diff --git a/cmake/externals/LibOVR/CMakeLists.txt b/cmake/externals/LibOVR/CMakeLists.txt index ae4cf6320e..481753f7e0 100644 --- a/cmake/externals/LibOVR/CMakeLists.txt +++ b/cmake/externals/LibOVR/CMakeLists.txt @@ -17,8 +17,8 @@ if (WIN32) ExternalProject_Add( ${EXTERNAL_NAME} - URL https://public.highfidelity.com/dependencies/ovr_sdk_win_1.26.0_public.zip - URL_MD5 06804ff9727b910dcd04a37c800053b5 + URL https://hifi-public.s3.amazonaws.com/dependencies/ovr_sdk_win_1.35.0.zip + URL_MD5 1e3e8b2101387af07ff9c841d0ea285e CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= PATCH_COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_SOURCE_DIR}/LibOVRCMakeLists.txt" /CMakeLists.txt LOG_DOWNLOAD 1 diff --git a/cmake/macros/AddCrashpad.cmake b/cmake/macros/AddCrashpad.cmake index 113ab53aae..bc070e057b 100644 --- a/cmake/macros/AddCrashpad.cmake +++ b/cmake/macros/AddCrashpad.cmake @@ -53,10 +53,5 @@ macro(add_crashpad) POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${CRASHPAD_HANDLER_EXE_PATH} "$/" ) - install( - PROGRAMS ${CRASHPAD_HANDLER_EXE_PATH} - DESTINATION ${INTERFACE_INSTALL_DIR} - COMPONENT ${CLIENT_COMPONENT} - ) endif () endmacro() diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 2950b8de75..3ae05b447f 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -678,12 +678,9 @@ $(document).ready(function(){ var errorEl = createDomainLoadingError("There was an error retrieving your places."); $("#" + Settings.PLACES_TABLE_ID).after(errorEl); - // do we have a domain ID? - if (!domainIDIsSet()) { - // we don't have a domain ID - add a button to offer the user a chance to get a temporary one - var temporaryPlaceButton = dynamicButton(Settings.GET_TEMPORARY_NAME_BTN_ID, 'Get a temporary place name'); - $('#' + Settings.PLACES_TABLE_ID).after(temporaryPlaceButton); - } + var temporaryPlaceButton = dynamicButton(Settings.GET_TEMPORARY_NAME_BTN_ID, 'Get a temporary place name'); + temporaryPlaceButton.hide(); + $('#' + Settings.PLACES_TABLE_ID).after(temporaryPlaceButton); if (accessTokenIsSet()) { appendAddButtonToPlacesTable(); } @@ -774,8 +771,9 @@ $(document).ready(function(){ // check if we have owner_places (for a real domain) or a name (for a temporary domain) if (data.status == "success") { + $('#' + Settings.GET_TEMPORARY_NAME_BTN_ID).hide(); $('.domain-loading-hide').show(); - if (data.domain.owner_places) { + if (data.domain.owner_places && data.domain.owner_places.length > 0) { // add a table row for each of these names _.each(data.domain.owner_places, function(place){ $('#' + Settings.PLACES_TABLE_ID + " tbody").append(placeTableRowForPlaceObject(place)); @@ -783,8 +781,9 @@ $(document).ready(function(){ } else if (data.domain.name) { // add a table row for this temporary domain name $('#' + Settings.PLACES_TABLE_ID + " tbody").append(placeTableRow(data.domain.name, '/', true)); + } else { + $('#' + Settings.GET_TEMPORARY_NAME_BTN_ID).show(); } - // Update label if (showOrHideLabel()) { var label = data.domain.label; diff --git a/interface/resources/controllers/oculus_touch.json b/interface/resources/controllers/oculus_touch.json index b818d371e3..86f559d964 100644 --- a/interface/resources/controllers/oculus_touch.json +++ b/interface/resources/controllers/oculus_touch.json @@ -13,11 +13,11 @@ { "from": "OculusTouch.LY", "to": "Standard.LY", "filters": [ - { "type": "deadZone", "min": 0.7 }, + { "type": "deadZone", "min": 0.15 }, "invert" ] }, - { "from": "OculusTouch.LX", "filters": { "type": "deadZone", "min": 0.7 }, "to": "Standard.LX" }, + { "from": "OculusTouch.LX", "filters": { "type": "deadZone", "min": 0.15 }, "to": "Standard.LX" }, { "from": "OculusTouch.LT", "to": "Standard.LTClick", "peek": true, "filters": [ { "type": "hysteresis", "min": 0.85, "max": 0.9 } ] @@ -29,11 +29,11 @@ { "from": "OculusTouch.RY", "to": "Standard.RY", "filters": [ - { "type": "deadZone", "min": 0.7 }, + { "type": "deadZone", "min": 0.15 }, "invert" ] }, - { "from": "OculusTouch.RX", "filters": { "type": "deadZone", "min": 0.7 }, "to": "Standard.RX" }, + { "from": "OculusTouch.RX", "filters": { "type": "deadZone", "min": 0.15 }, "to": "Standard.RX" }, { "from": "OculusTouch.RT", "to": "Standard.RTClick", "peek": true, "filters": [ { "type": "hysteresis", "min": 0.85, "max": 0.9 } ] diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json index 28f15605e0..0a5bd12460 100644 --- a/interface/resources/controllers/standard.json +++ b/interface/resources/controllers/standard.json @@ -1,11 +1,14 @@ { "name": "Standard to Action", "channels": [ - { "from": "Standard.LY", "to": "Actions.TranslateZ" }, + { "from": "Standard.LY", + "when": ["Application.RightHandDominant", "!Standard.RY"], + "to": "Actions.TranslateZ" + }, { "from": "Standard.LX", "when": [ - "Application.InHMD", "!Application.AdvancedMovement", + "Application.InHMD", "!Application.AdvancedMovement", "Application.RightHandDominant", "Application.SnapTurn", "!Standard.RX" ], "to": "Actions.StepYaw", @@ -18,14 +21,14 @@ ] }, { "from": "Standard.LX", "to": "Actions.TranslateX", - "when": [ "Application.AdvancedMovement" ] + "when": [ "Application.AdvancedMovement", "Application.StrafeEnabled", "Application.RightHandDominant" ] }, { "from": "Standard.LX", "to": "Actions.Yaw", - "when": [ "!Application.AdvancedMovement", "!Application.SnapTurn" ] + "when": [ "!Application.AdvancedMovement", "!Application.SnapTurn", "Application.RightHandDominant" ] }, { "from": "Standard.RX", - "when": [ "Application.SnapTurn" ], + "when": [ "Application.SnapTurn", "Application.RightHandDominant" ], "to": "Actions.StepYaw", "filters": [ @@ -36,20 +39,69 @@ ] }, { "from": "Standard.RX", "to": "Actions.Yaw", - "when": [ "!Application.SnapTurn" ] + "when": [ "!Application.SnapTurn", "Application.RightHandDominant" ] }, + { "from": "Standard.LeftSecondaryThumb", + "when": [ "Application.Grounded", "Application.LeftHandDominant" ], + "to": "Actions.Up" + }, + + { "from": "Standard.LeftSecondaryThumb", + "when": "Application.LeftHandDominant", + "to": "Actions.Up" + }, + { "from": "Standard.RY", - "when": "Application.Grounded", - "to": "Actions.Up", + "when": ["Application.LeftHandDominant", "!Standard.LY"], + "to": "Actions.TranslateZ" + }, + + { "from": "Standard.RX", + "when": [ + "Application.InHMD", "!Application.AdvancedMovement", "Application.LeftHandDominant", + "Application.SnapTurn", "!Standard.RX" + ], + "to": "Actions.StepYaw", "filters": [ - { "type": "deadZone", "min": 0.6 }, - "invert" + { "type": "deadZone", "min": 0.15 }, + "constrainToInteger", + { "type": "pulse", "interval": 0.25 }, + { "type": "scale", "scale": 22.5 } ] }, + { "from": "Standard.RX", "to": "Actions.TranslateX", + "when": [ "Application.AdvancedMovement", "Application.StrafeEnabled", "Application.LeftHandDominant" ] + }, + { "from": "Standard.RX", "to": "Actions.Yaw", + "when": [ "!Application.AdvancedMovement", "!Application.SnapTurn", "Application.LeftHandDominant" ] + }, - { "from": "Standard.RY", "to": "Actions.Up", "filters": "invert"}, + { "from": "Standard.LX", + "when": [ "Application.SnapTurn", "Application.LeftHandDominant" ], + "to": "Actions.StepYaw", + "filters": + [ + { "type": "deadZone", "min": 0.15 }, + "constrainToInteger", + { "type": "pulse", "interval": 0.25 }, + { "type": "scale", "scale": 22.5 } + ] + }, + { "from": "Standard.LX", "to": "Actions.Yaw", + "when": [ "!Application.SnapTurn", "Application.LeftHandDominant" ] + }, + + { "from": "Standard.RightSecondaryThumb", + "when": [ "Application.Grounded", "Application.RightHandDominant" ], + "to": "Actions.Up" + }, + + { "from": "Standard.RightSecondaryThumb", + "when": "Application.RightHandDominant", + "to": "Actions.Up" + }, { "from": "Standard.Back", "to": "Actions.CycleCamera" }, { "from": "Standard.Start", "to": "Actions.ContextMenu" }, @@ -128,4 +180,4 @@ { "from": "Standard.TrackedObject14", "to" : "Actions.TrackedObject14" }, { "from": "Standard.TrackedObject15", "to" : "Actions.TrackedObject15" } ] -} \ No newline at end of file +} diff --git a/interface/resources/controllers/vive.json b/interface/resources/controllers/vive.json index 24b1587691..730e1bcb58 100644 --- a/interface/resources/controllers/vive.json +++ b/interface/resources/controllers/vive.json @@ -10,8 +10,9 @@ "filters": [ { "type": "hysteresis", "min": 0.7, "max": 0.75 } ] }, - { "from": "Vive.LY", "when": "Vive.LSY", "filters": ["invert"], "to": "Standard.LY" }, - { "from": "Vive.LX", "when": "Vive.LSX", "to": "Standard.LX" }, + { "from": "Vive.LY", "when": "Vive.LS", "filters": [ { "type": "deadZone", "min": 0.15 }, "invert" ], "to": "Standard.LY" }, + { "from": "Vive.LX", "when": ["Vive.LS", "Application.RightHandDominant"], "filters": { "type": "deadZone", "min": 0.15 }, "to": "Standard.LX" }, + { "from": "Vive.LX", "when": ["Vive.LS", "Vive.LSX", "!Vive.LSY", "Application.LeftHandDominant"], "filters": { "type": "deadZone", "min": 0.15 }, "to": "Standard.LX" }, { "from": "Vive.LT", "to": "Standard.LT", "filters": [ @@ -28,8 +29,9 @@ }, { "from": "Vive.LSTouch", "to": "Standard.LSTouch" }, - { "from": "Vive.RY", "when": "Vive.RSY", "filters": ["invert"], "to": "Standard.RY" }, - { "from": "Vive.RX", "when": "Vive.RSX", "to": "Standard.RX" }, + { "from": "Vive.RY", "when": "Vive.RS", "filters": [ { "type": "deadZone", "min": 0.15 }, "invert" ], "to": "Standard.RY" }, + { "from": "Vive.RX", "when": ["Vive.RS", "Application.LeftHandDominant"], "filters": { "type": "deadZone", "min": 0.15 }, "to": "Standard.RX" }, + { "from": "Vive.RX", "when": ["Vive.RS", "Vive.RSX", "!Vive.RSY", "Application.RightHandDominant"], "filters": { "type": "deadZone", "min": 0.15 }, "to": "Standard.RX" }, { "from": "Vive.RT", "to": "Standard.RT", "filters": [ diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 147b5b79a6..e959f87a46 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -680,6 +680,8 @@ private: * InHMDnumbernumberThe user is in HMD mode. * AdvancedMovementnumbernumberAdvanced movement controls are enabled. * + * LeftHandDominantnumbernumberDominant hand set to left. + * RightHandDominantnumbernumberDominant hand set to right. * SnapTurnnumbernumberSnap turn is enabled. * GroundednumbernumberThe user's avatar is on the ground. * NavigationFocusednumbernumberNot used. @@ -701,6 +703,9 @@ static const QString STATE_NAV_FOCUSED = "NavigationFocused"; static const QString STATE_PLATFORM_WINDOWS = "PlatformWindows"; static const QString STATE_PLATFORM_MAC = "PlatformMac"; static const QString STATE_PLATFORM_ANDROID = "PlatformAndroid"; +static const QString STATE_LEFT_HAND_DOMINANT = "LeftHandDominant"; +static const QString STATE_RIGHT_HAND_DOMINANT = "RightHandDominant"; +static const QString STATE_STRAFE_ENABLED = "StrafeEnabled"; // Statically provided display and input plugins extern DisplayPluginList getDisplayPlugins(); @@ -902,7 +907,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { controller::StateController::setStateVariables({ { STATE_IN_HMD, STATE_CAMERA_FULL_SCREEN_MIRROR, STATE_CAMERA_FIRST_PERSON, STATE_CAMERA_THIRD_PERSON, STATE_CAMERA_ENTITY, STATE_CAMERA_INDEPENDENT, STATE_SNAP_TURN, STATE_ADVANCED_MOVEMENT_CONTROLS, STATE_GROUNDED, STATE_NAV_FOCUSED, - STATE_PLATFORM_WINDOWS, STATE_PLATFORM_MAC, STATE_PLATFORM_ANDROID } }); + STATE_PLATFORM_WINDOWS, STATE_PLATFORM_MAC, STATE_PLATFORM_ANDROID, STATE_LEFT_HAND_DOMINANT, STATE_RIGHT_HAND_DOMINANT, STATE_STRAFE_ENABLED } }); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -1740,6 +1745,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _applicationStateDevice->setInputVariant(STATE_ADVANCED_MOVEMENT_CONTROLS, []() -> float { return qApp->getMyAvatar()->useAdvancedMovementControls() ? 1 : 0; }); + _applicationStateDevice->setInputVariant(STATE_LEFT_HAND_DOMINANT, []() -> float { + return qApp->getMyAvatar()->getDominantHand() == "left" ? 1 : 0; + }); + _applicationStateDevice->setInputVariant(STATE_RIGHT_HAND_DOMINANT, []() -> float { + return qApp->getMyAvatar()->getDominantHand() == "right" ? 1 : 0; + }); + _applicationStateDevice->setInputVariant(STATE_STRAFE_ENABLED, []() -> float { + return qApp->getMyAvatar()->getStrafeEnabled() ? 1 : 0; + }); _applicationStateDevice->setInputVariant(STATE_GROUNDED, []() -> float { return qApp->getMyAvatar()->getCharacterController()->onGround() ? 1 : 0; @@ -6709,6 +6723,11 @@ void Application::updateRenderArgs(float deltaTime) { // Configure the type of display / stereo appRenderArgs._renderArgs._displayMode = (isHMDMode() ? RenderArgs::STEREO_HMD : RenderArgs::STEREO_MONITOR); } + + appRenderArgs._renderArgs._stencilMode = getActiveDisplayPlugin()->getStencilMaskMode(); + if (appRenderArgs._renderArgs._stencilMode == StencilMode::MESH) { + appRenderArgs._renderArgs._stencilMaskOperator = getActiveDisplayPlugin()->getStencilMaskMeshOperator(); + } } { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9ffcd0184e..568b492b46 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -155,6 +155,7 @@ MyAvatar::MyAvatar(QThread* thread) : _prevShouldDrawHead(true), _audioListenerMode(FROM_HEAD), _dominantHandSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "dominantHand", DOMINANT_RIGHT_HAND), + _strafeEnabledSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "strafeEnabled", DEFAULT_STRAFE_ENABLED), _hmdAvatarAlignmentTypeSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "hmdAvatarAlignmentType", DEFAULT_HMD_AVATAR_ALIGNMENT_TYPE), _headPitchSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "", 0.0f), _scaleSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "scale", _targetScale), @@ -169,7 +170,16 @@ MyAvatar::MyAvatar(QThread* thread) : _useSnapTurnSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "useSnapTurn", _useSnapTurn), _userHeightSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "userHeight", DEFAULT_AVATAR_HEIGHT), _flyingHMDSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "flyingHMD", _flyingPrefHMD), + _movementReferenceSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "movementReference", _movementReference), _avatarEntityCountSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "avatarEntityData" << "size", 0), + _driveGear1Setting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "driveGear1", _driveGear1), + _driveGear2Setting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "driveGear2", _driveGear2), + _driveGear3Setting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "driveGear3", _driveGear3), + _driveGear4Setting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "driveGear4", _driveGear4), + _driveGear5Setting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "driveGear5", _driveGear5), + _analogWalkSpeedSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "analogWalkSpeed", _analogWalkSpeed.get()), + _analogPlusWalkSpeedSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "analogPlusWalkSpeed", _analogPlusWalkSpeed.get()), + _controlSchemeIndexSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "controlSchemeIndex", _controlSchemeIndex), _userRecenterModelSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "userRecenterModel", USER_RECENTER_MODEL_AUTO) { _clientTraitsHandler.reset(new ClientTraitsHandler(this)); @@ -322,6 +332,14 @@ QString MyAvatar::getDominantHand() const { return _dominantHand.get(); } +void MyAvatar::setStrafeEnabled(bool enabled) { + _strafeEnabled.set(enabled); +} + +bool MyAvatar::getStrafeEnabled() const { + return _strafeEnabled.get(); +} + void MyAvatar::setDominantHand(const QString& hand) { if (hand == DOMINANT_LEFT_HAND || hand == DOMINANT_RIGHT_HAND) { bool changed = (hand != _dominantHand.get()); @@ -1256,6 +1274,7 @@ void MyAvatar::resizeAvatarEntitySettingHandles(uint32_t maxIndex) { void MyAvatar::saveData() { _dominantHandSetting.set(getDominantHand()); + _strafeEnabledSetting.set(getStrafeEnabled()); _hmdAvatarAlignmentTypeSetting.set(getHmdAvatarAlignmentType()); _headPitchSetting.set(getHead()->getBasePitch()); _scaleSetting.set(_targetScale); @@ -1279,6 +1298,15 @@ void MyAvatar::saveData() { _useSnapTurnSetting.set(_useSnapTurn); _userHeightSetting.set(getUserHeight()); _flyingHMDSetting.set(getFlyingHMDPref()); + _movementReferenceSetting.set(getMovementReference()); + _driveGear1Setting.set(getDriveGear1()); + _driveGear2Setting.set(getDriveGear2()); + _driveGear3Setting.set(getDriveGear3()); + _driveGear4Setting.set(getDriveGear4()); + _driveGear5Setting.set(getDriveGear5()); + _analogWalkSpeedSetting.set(getAnalogWalkSpeed()); + _analogPlusWalkSpeedSetting.set(getAnalogPlusWalkSpeed()); + _controlSchemeIndexSetting.set(getControlSchemeIndex()); _userRecenterModelSetting.set(userRecenterModelToString(getUserRecenterModel())); auto hmdInterface = DependencyManager::get(); @@ -1856,12 +1884,22 @@ void MyAvatar::loadData() { // Flying preferences must be loaded before calling setFlyingEnabled() Setting::Handle firstRunVal { Settings::firstRun, true }; setFlyingHMDPref(firstRunVal.get() ? false : _flyingHMDSetting.get()); + setMovementReference(firstRunVal.get() ? false : _movementReferenceSetting.get()); + setDriveGear1(firstRunVal.get() ? DEFAULT_GEAR_1 : _driveGear1Setting.get()); + setDriveGear2(firstRunVal.get() ? DEFAULT_GEAR_2 : _driveGear2Setting.get()); + setDriveGear3(firstRunVal.get() ? DEFAULT_GEAR_3 : _driveGear3Setting.get()); + setDriveGear4(firstRunVal.get() ? DEFAULT_GEAR_4 : _driveGear4Setting.get()); + setDriveGear5(firstRunVal.get() ? DEFAULT_GEAR_5 : _driveGear5Setting.get()); + setControlSchemeIndex(firstRunVal.get() ? LocomotionControlsMode::CONTROLS_DEFAULT : _controlSchemeIndexSetting.get()); + setAnalogWalkSpeed(firstRunVal.get() ? ANALOG_AVATAR_MAX_WALKING_SPEED : _analogWalkSpeedSetting.get()); + setAnalogPlusWalkSpeed(firstRunVal.get() ? ANALOG_PLUS_AVATAR_MAX_WALKING_SPEED : _analogPlusWalkSpeedSetting.get()); setFlyingEnabled(getFlyingEnabled()); setDisplayName(_displayNameSetting.get()); setCollisionSoundURL(_collisionSoundURLSetting.get(QUrl(DEFAULT_AVATAR_COLLISION_SOUND_URL)).toString()); setSnapTurn(_useSnapTurnSetting.get()); setDominantHand(_dominantHandSetting.get(DOMINANT_RIGHT_HAND).toLower()); + setStrafeEnabled(_strafeEnabledSetting.get(DEFAULT_STRAFE_ENABLED)); setHmdAvatarAlignmentType(_hmdAvatarAlignmentTypeSetting.get(DEFAULT_HMD_AVATAR_ALIGNMENT_TYPE).toLower()); setUserHeight(_userHeightSetting.get(DEFAULT_AVATAR_HEIGHT)); setTargetScale(_scaleSetting.get()); @@ -2519,6 +2557,12 @@ controller::Pose MyAvatar::getControllerPoseInAvatarFrame(controller::Action act } } +glm::quat MyAvatar::getOffHandRotation() const { + auto hand = (getDominantHand() == DOMINANT_RIGHT_HAND) ? controller::Action::LEFT_HAND : controller::Action::RIGHT_HAND; + auto pose = getControllerPoseInAvatarFrame(hand); + return pose.rotation; +} + void MyAvatar::updateMotors() { _characterController.clearMotors(); glm::quat motorRotation; @@ -3285,21 +3329,131 @@ void MyAvatar::updateOrientation(float deltaTime) { } } -static float scaleSpeedByDirection(const glm::vec2 velocityDirection, const float forwardSpeed, const float backwardSpeed) { - // for the elipse function --> (x^2)/(backwardSpeed*backwardSpeed) + y^2/(forwardSpeed*forwardSpeed) = 1, scale == y^2 when x is 0 - float fwdScale = forwardSpeed * forwardSpeed; - float backScale = backwardSpeed * backwardSpeed; - float scaledX = velocityDirection.x * backwardSpeed; - float scaledSpeed = forwardSpeed; - if (velocityDirection.y < 0.0f) { - if (backScale > 0.0f) { - float yValue = sqrtf(fwdScale * (1.0f - ((scaledX * scaledX) / backScale))); - scaledSpeed = sqrtf((scaledX * scaledX) + (yValue * yValue)); +float MyAvatar::calculateGearedSpeed(const float driveKey) { + float absDriveKey = abs(driveKey); + float sign = (driveKey < 0.0f) ? -1.0f : 1.0f; + if (absDriveKey > getDriveGear5()) { + return sign * 1.0f; + } + else if (absDriveKey > getDriveGear4()) { + return sign * 0.8f; + } + else if (absDriveKey > getDriveGear3()) { + return sign * 0.6f; + } + else if (absDriveKey > getDriveGear2()) { + return sign * 0.4f; + } + else if (absDriveKey > getDriveGear1()) { + return sign * 0.2f; + } + else { + return sign * 0.0f; + } +} + +glm::vec3 MyAvatar::scaleMotorSpeed(const glm::vec3 forward, const glm::vec3 right) { + float stickFullOn = 0.85f; + auto zSpeed = getDriveKey(TRANSLATE_Z); + auto xSpeed = getDriveKey(TRANSLATE_X); + glm::vec3 direction; + if (!useAdvancedMovementControls() && qApp->isHMDMode()) { + // Walking disabled in settings. + return Vectors::ZERO; + } else if (qApp->isHMDMode()) { + // HMD advanced movement controls. + switch (_controlSchemeIndex) { + case LocomotionControlsMode::CONTROLS_DEFAULT: + // No acceleration curve for this one, constant speed. + if (zSpeed || xSpeed) { + direction = (zSpeed * forward) + (xSpeed * right); + // Normalize direction. + auto length = glm::length(direction); + if (length > EPSILON) { + direction /= length; + } + return getSensorToWorldScale() * direction * getSprintSpeed() * _walkSpeedScalar; + } else { + return Vectors::ZERO; + } + case LocomotionControlsMode::CONTROLS_ANALOG: + case LocomotionControlsMode::CONTROLS_ANALOG_PLUS: + if (zSpeed || xSpeed) { + glm::vec3 scaledForward = getSensorToWorldScale() * calculateGearedSpeed(zSpeed) * _walkSpeedScalar * ((zSpeed >= stickFullOn) ? getSprintSpeed() : getWalkSpeed()) * forward; + glm::vec3 scaledRight = getSensorToWorldScale() * calculateGearedSpeed(xSpeed) * _walkSpeedScalar * ((xSpeed > stickFullOn) ? getSprintSpeed() : getWalkSpeed()) * right; + direction = scaledForward + scaledRight; + return direction; + } else { + return Vectors::ZERO; + } + default: + qDebug() << "Invalid control scheme index."; + return Vectors::ZERO; } } else { - scaledSpeed = backwardSpeed; + // Desktop mode. + direction = (zSpeed * forward) + (xSpeed * right); + auto length = glm::length(direction); + if (length > EPSILON) { + direction /= length; + } + direction *= getWalkSpeed() * _walkSpeedScalar; + return direction; } - return scaledSpeed; +} + +glm::vec3 MyAvatar::calculateScaledDirection(){ + CharacterController::State state = _characterController.getState(); + + // compute action input + // Determine if we're head or controller relative... + glm::vec3 forward, right; + + if (qApp->isHMDMode()) { + auto handRotation = getOffHandRotation(); + glm::vec3 controllerForward(0.0f, 1.0f, 0.0f); + glm::vec3 controllerRight(0.0f, 0.0f, (getDominantHand() == DOMINANT_RIGHT_HAND ? 1.0f : -1.0f)); + glm::vec3 transform; + switch (getMovementReference()) { + case LocomotionRelativeMovementMode::MOVEMENT_HAND_RELATIVE: + forward = (handRotation * controllerForward); + right = (handRotation * controllerRight); + break; + case LocomotionRelativeMovementMode::MOVEMENT_HAND_RELATIVE_LEVELED: + forward = (handRotation * controllerForward); + transform = forward - (glm::dot(forward, Vectors::UNIT_Y) * Vectors::UNIT_Y); + if (glm::length(transform) > EPSILON) { + forward = glm::normalize(transform); + } else { + forward = Vectors::ZERO; + } + right = (handRotation * controllerRight); + transform = right - (glm::dot(right, Vectors::UNIT_Y) * Vectors::UNIT_Y); + if (glm::length(transform) > EPSILON) { + right = glm::normalize(transform); + } else { + right = Vectors::ZERO; + } + break; + case LocomotionRelativeMovementMode::MOVEMENT_HMD_RELATIVE: + default: + forward = IDENTITY_FORWARD; + right = IDENTITY_RIGHT; + } + } else { + forward = IDENTITY_FORWARD; + right = IDENTITY_RIGHT; + } + + glm::vec3 direction = scaleMotorSpeed(forward, right); + + if (state == CharacterController::State::Hover || + _characterController.computeCollisionMask() == BULLET_COLLISION_MASK_COLLISIONLESS) { + glm::vec3 up = (getDriveKey(TRANSLATE_Y)) * IDENTITY_UP; + direction += up; + } + + return direction; } void MyAvatar::updateActionMotor(float deltaTime) { @@ -3319,25 +3473,13 @@ void MyAvatar::updateActionMotor(float deltaTime) { CharacterController::State state = _characterController.getState(); - // compute action input - glm::vec3 forward = (getDriveKey(TRANSLATE_Z)) * IDENTITY_FORWARD; - glm::vec3 right = (getDriveKey(TRANSLATE_X)) * IDENTITY_RIGHT; - - glm::vec3 direction = forward + right; - if (state == CharacterController::State::Hover || - _characterController.computeCollisionMask() == BULLET_COLLISION_MASK_COLLISIONLESS) { - glm::vec3 up = (getDriveKey(TRANSLATE_Y)) * IDENTITY_UP; - direction += up; - } + glm::vec3 direction = calculateScaledDirection(); _wasPushing = _isPushing; float directionLength = glm::length(direction); _isPushing = directionLength > EPSILON; - // normalize direction - if (_isPushing) { - direction /= directionLength; - } else { + if (!_isPushing) { direction = Vectors::ZERO; } @@ -3353,6 +3495,7 @@ void MyAvatar::updateActionMotor(float deltaTime) { const float maxBoostSpeed = sensorToWorldScale * MAX_BOOST_SPEED; if (_isPushing) { + direction /= directionLength; if (motorSpeed < maxBoostSpeed) { // an active action motor should never be slower than this float boostCoefficient = (maxBoostSpeed - motorSpeed) / maxBoostSpeed; @@ -3363,11 +3506,17 @@ void MyAvatar::updateActionMotor(float deltaTime) { } _actionMotorVelocity = motorSpeed * direction; } else { - // we're interacting with a floor --> simple horizontal speed and exponential decay - const glm::vec2 currentVel = { direction.x, direction.z }; - float scaledSpeed = scaleSpeedByDirection(currentVel, _walkSpeed.get(), _walkBackwardSpeed.get()); - // _walkSpeedScalar is a multiplier if we are in sprint mode, otherwise 1.0 - _actionMotorVelocity = sensorToWorldScale * (scaledSpeed * _walkSpeedScalar) * direction; + _actionMotorVelocity = direction; + } + + float previousBoomLength = _boomLength; + float boomChange = getDriveKey(ZOOM); + _boomLength += 2.0f * _boomLength * boomChange + boomChange * boomChange; + _boomLength = glm::clamp(_boomLength, ZOOM_MIN, ZOOM_MAX); + + // May need to change view if boom length has changed + if (previousBoomLength != _boomLength) { + qApp->changeViewAsNeeded(_boomLength); } } @@ -3880,6 +4029,136 @@ void MyAvatar::setFlyingHMDPref(bool enabled) { _flyingPrefHMD = enabled; } +void MyAvatar::setMovementReference(int enabled) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setMovementReference", Q_ARG(bool, enabled)); + return; + } + _movementReference = enabled; +} + +int MyAvatar::getMovementReference() { + return _movementReference; +} + +void MyAvatar::setControlSchemeIndex(int index){ + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setControlSchemeIndex", Q_ARG(int, index)); + return; + } + // Need to add checks for valid indices. + _controlSchemeIndex = index; +} + +int MyAvatar::getControlSchemeIndex() { + return _controlSchemeIndex; +} + +void MyAvatar::setDriveGear1(float shiftPoint) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setDriveGear1", Q_ARG(float, shiftPoint)); + return; + } + if (shiftPoint > 1.0f || shiftPoint < 0.0f) return; + _driveGear1 = (shiftPoint < _driveGear2) ? shiftPoint : _driveGear1; +} + +float MyAvatar::getDriveGear1() { + switch (_controlSchemeIndex) { + case LocomotionControlsMode::CONTROLS_ANALOG: + return ANALOG_AVATAR_GEAR_1; + case LocomotionControlsMode::CONTROLS_ANALOG_PLUS: + return _driveGear1; + case LocomotionControlsMode::CONTROLS_DEFAULT: + default: + return 1.0f; + } +} + +void MyAvatar::setDriveGear2(float shiftPoint) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setDriveGear2", Q_ARG(float, shiftPoint)); + return; + } + if (shiftPoint > 1.0f || shiftPoint < 0.0f) return; + _driveGear2 = (shiftPoint < _driveGear3 && shiftPoint >= _driveGear1) ? shiftPoint : _driveGear2; +} + +float MyAvatar::getDriveGear2() { + switch (_controlSchemeIndex) { + case LocomotionControlsMode::CONTROLS_ANALOG: + return ANALOG_AVATAR_GEAR_2; + case LocomotionControlsMode::CONTROLS_ANALOG_PLUS: + return _driveGear2; + case LocomotionControlsMode::CONTROLS_DEFAULT: + default: + return 1.0f; + } +} + +void MyAvatar::setDriveGear3(float shiftPoint) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setDriveGear3", Q_ARG(float, shiftPoint)); + return; + } + if (shiftPoint > 1.0f || shiftPoint < 0.0f) return; + _driveGear3 = (shiftPoint < _driveGear4 && shiftPoint >= _driveGear2) ? shiftPoint : _driveGear3; +} + +float MyAvatar::getDriveGear3() { + switch (_controlSchemeIndex) { + case LocomotionControlsMode::CONTROLS_ANALOG: + return ANALOG_AVATAR_GEAR_3; + case LocomotionControlsMode::CONTROLS_ANALOG_PLUS: + return _driveGear3; + case LocomotionControlsMode::CONTROLS_DEFAULT: + default: + return 1.0f; + } +} + +void MyAvatar::setDriveGear4(float shiftPoint) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setDriveGear4", Q_ARG(float, shiftPoint)); + return; + } + if (shiftPoint > 1.0f || shiftPoint < 0.0f) return; + _driveGear4 = (shiftPoint < _driveGear5 && shiftPoint >= _driveGear3) ? shiftPoint : _driveGear4; +} + +float MyAvatar::getDriveGear4() { + switch (_controlSchemeIndex) { + case LocomotionControlsMode::CONTROLS_ANALOG: + return ANALOG_AVATAR_GEAR_4; + case LocomotionControlsMode::CONTROLS_ANALOG_PLUS: + return _driveGear4; + case LocomotionControlsMode::CONTROLS_DEFAULT: + default: + return 1.0f; + } +} + +void MyAvatar::setDriveGear5(float shiftPoint) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setDriveGear5", Q_ARG(float, shiftPoint)); + return; + } + if (shiftPoint > 1.0f || shiftPoint < 0.0f) return; + _driveGear5 = (shiftPoint > _driveGear4) ? shiftPoint : _driveGear5; +} + +float MyAvatar::getDriveGear5() { + switch (_controlSchemeIndex) { + case LocomotionControlsMode::CONTROLS_ANALOG: + return ANALOG_AVATAR_GEAR_5; + case LocomotionControlsMode::CONTROLS_ANALOG_PLUS: + return _driveGear5; + case LocomotionControlsMode::CONTROLS_DEFAULT: + default: + return 1.0f; + } +} + bool MyAvatar::getFlyingHMDPref() { return _flyingPrefHMD; } @@ -4488,11 +4767,37 @@ bool MyAvatar::getIsSitStandStateLocked() const { } float MyAvatar::getWalkSpeed() const { - return _walkSpeed.get() * _walkSpeedScalar; + if (qApp->isHMDMode()) { + switch (_controlSchemeIndex) { + case LocomotionControlsMode::CONTROLS_ANALOG: + return _analogWalkSpeed.get(); + case LocomotionControlsMode::CONTROLS_ANALOG_PLUS: + return _analogPlusWalkSpeed.get(); + case LocomotionControlsMode::CONTROLS_DEFAULT: + default: + return _defaultWalkSpeed.get(); + } + } else { + return _defaultWalkSpeed.get(); + } + } float MyAvatar::getWalkBackwardSpeed() const { - return _walkSpeed.get() * _walkSpeedScalar; + if (qApp->isHMDMode()) { + switch (_controlSchemeIndex) { + case LocomotionControlsMode::CONTROLS_ANALOG: + return _analogWalkBackwardSpeed.get(); + case LocomotionControlsMode::CONTROLS_ANALOG_PLUS: + return _analogPlusWalkBackwardSpeed.get(); + case LocomotionControlsMode::CONTROLS_DEFAULT: + default: + return _defaultWalkBackwardSpeed.get(); + } + } else { + return _defaultWalkBackwardSpeed.get(); + } + } bool MyAvatar::isReadyForPhysics() const { @@ -4500,7 +4805,7 @@ bool MyAvatar::isReadyForPhysics() const { } void MyAvatar::setSprintMode(bool sprint) { - _walkSpeedScalar = sprint ? _sprintSpeed.get() : AVATAR_WALK_SPEED_SCALAR; + _walkSpeedScalar = sprint ? AVATAR_SPRINT_SPEED_SCALAR : AVATAR_WALK_SPEED_SCALAR; } void MyAvatar::setIsInWalkingState(bool isWalking) { @@ -4563,19 +4868,103 @@ void MyAvatar::setIsSitStandStateLocked(bool isLocked) { } void MyAvatar::setWalkSpeed(float value) { - _walkSpeed.set(value); + switch (_controlSchemeIndex) { + case LocomotionControlsMode::CONTROLS_DEFAULT: + _defaultWalkSpeed.set(value); + break; + case LocomotionControlsMode::CONTROLS_ANALOG: + _analogWalkSpeed.set(value); + break; + case LocomotionControlsMode::CONTROLS_ANALOG_PLUS: + _analogPlusWalkSpeed.set(value); + break; + default: + break; + } } void MyAvatar::setWalkBackwardSpeed(float value) { - _walkBackwardSpeed.set(value); + switch (_controlSchemeIndex) { + case LocomotionControlsMode::CONTROLS_DEFAULT: + _defaultWalkBackwardSpeed.set(value); + break; + case LocomotionControlsMode::CONTROLS_ANALOG: + _analogWalkBackwardSpeed.set(value); + break; + case LocomotionControlsMode::CONTROLS_ANALOG_PLUS: + _analogPlusWalkBackwardSpeed.set(value); + break; + default: + break; + } } void MyAvatar::setSprintSpeed(float value) { - _sprintSpeed.set(value); + switch (_controlSchemeIndex) { + case LocomotionControlsMode::CONTROLS_DEFAULT: + _defaultSprintSpeed.set(value); + break; + case LocomotionControlsMode::CONTROLS_ANALOG: + _analogSprintSpeed.set(value); + break; + case LocomotionControlsMode::CONTROLS_ANALOG_PLUS: + _analogPlusSprintSpeed.set(value); + break; + default: + break; + } } float MyAvatar::getSprintSpeed() const { - return _sprintSpeed.get(); + if (qApp->isHMDMode()) { + switch (_controlSchemeIndex) { + case LocomotionControlsMode::CONTROLS_ANALOG: + return _analogSprintSpeed.get(); + case LocomotionControlsMode::CONTROLS_ANALOG_PLUS: + return _analogPlusSprintSpeed.get(); + case LocomotionControlsMode::CONTROLS_DEFAULT: + default: + return _defaultSprintSpeed.get(); + } + } else { + return _defaultSprintSpeed.get(); + } +} + +void MyAvatar::setAnalogWalkSpeed(float value) { + _analogWalkSpeed.set(value); + // Sprint speed for Analog should be double walk speed. + _analogSprintSpeed.set(value * 2.0f); +} + +float MyAvatar::getAnalogWalkSpeed() const { + return _analogWalkSpeed.get(); +} + +void MyAvatar::setAnalogSprintSpeed(float value) { + _analogSprintSpeed.set(value); +} + +float MyAvatar::getAnalogSprintSpeed() const { + return _analogSprintSpeed.get(); +} + +void MyAvatar::setAnalogPlusWalkSpeed(float value) { + _analogPlusWalkSpeed.set(value); + // Sprint speed for Analog Plus should be double walk speed. + _analogPlusSprintSpeed.set(value * 2.0f); +} + +float MyAvatar::getAnalogPlusWalkSpeed() const { + return _analogPlusWalkSpeed.get(); +} + +void MyAvatar::setAnalogPlusSprintSpeed(float value) { + _analogPlusSprintSpeed.set(value); +} + +float MyAvatar::getAnalogPlusSprintSpeed() const { + return _analogPlusSprintSpeed.get(); } void MyAvatar::setSitStandStateChange(bool stateChanged) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 0859c20153..804e2687e7 100755 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -39,6 +39,18 @@ class ModelItemID; class MyHead; class DetailedMotionState; +enum LocomotionControlsMode { + CONTROLS_DEFAULT = 0, + CONTROLS_ANALOG, + CONTROLS_ANALOG_PLUS +}; + +enum LocomotionRelativeMovementMode { + MOVEMENT_HMD_RELATIVE = 0, + MOVEMENT_HAND_RELATIVE, + MOVEMENT_HAND_RELATIVE_LEVELED +}; + enum eyeContactTarget { LEFT_EYE, RIGHT_EYE, @@ -371,6 +383,13 @@ class MyAvatar : public Avatar { using Clock = std::chrono::system_clock; using TimePoint = Clock::time_point; + const float DEFAULT_GEAR_1 = 0.2f; + const float DEFAULT_GEAR_2 = 0.4f; + const float DEFAULT_GEAR_3 = 0.8f; + const float DEFAULT_GEAR_4 = 0.9f; + const float DEFAULT_GEAR_5 = 1.0f; + + const bool DEFAULT_STRAFE_ENABLED = true; public: /**jsdoc @@ -729,7 +748,17 @@ public: */ Q_INVOKABLE void setSnapTurn(bool on) { _useSnapTurn = on; } + /** + * @function MyAvatar.getControlScheme + * @returns {number} + */ + Q_INVOKABLE int getControlScheme() const { return _controlSchemeIndex; } + /** + * @function MyAvatar.setControlScheme + * @param {number} index + */ + Q_INVOKABLE void setControlScheme(int index) { _controlSchemeIndex = (index >= 0 && index <= 2) ? index : 0; } /**jsdoc * Sets the avatar's dominant hand. * @function MyAvatar.setDominantHand @@ -744,7 +773,16 @@ public: * @returns {string} "left" for the left hand, "right" for the right hand. */ Q_INVOKABLE QString getDominantHand() const; - + /**jsdoc + * @function MyAVatar.setStrafeEnabled + * @param {bool} enabled + */ + Q_INVOKABLE void setStrafeEnabled(bool enabled); + /**jsdoc + * @function MyAvatar.getStrafeEnabled + * @returns {bool} + */ + Q_INVOKABLE bool getStrafeEnabled() const; /**jsdoc * @function MyAvatar.setHmdAvatarAlignmentType * @param {string} type - "head" to align your head and your avatar's head, "eyes" to align your @@ -1235,6 +1273,7 @@ public: controller::Pose getControllerPoseInSensorFrame(controller::Action action) const; controller::Pose getControllerPoseInWorldFrame(controller::Action action) const; controller::Pose getControllerPoseInAvatarFrame(controller::Action action) const; + glm::quat getOffHandRotation() const; bool hasDriveInput() const; @@ -1317,6 +1356,106 @@ public: */ Q_INVOKABLE bool getFlyingHMDPref(); + /**jsdoc + * Set your preference for hand-relative movement. + * @function MyAvatar.setHandRelativeMovement + * @param {number} enabled - Set true if you want to enable hand-relative movement, otherwise set to false. + * + */ + Q_INVOKABLE void setMovementReference(int enabled); + + /**jsdoc + * Get your preference for hand-relative movement. + * @function MyAvatar.getHandRelativeMovement + * @returns {number} true if your preference is for user locomotion to be relative to the direction your + * controller is pointing, otherwise false. + */ + Q_INVOKABLE int getMovementReference(); + + /**jsdoc + * Set the first 'shifting point' for acceleration step function. + * @function MyAvatar.setDriveGear1 + * @param {number} shiftPoint - Set the first shift point for analog movement acceleration step function, between [0.0, 1.0]. Must be less than or equal to Gear 2. + */ + Q_INVOKABLE void setDriveGear1(float shiftPoint); + + /**jsdoc + * Get the first 'shifting point' for acceleration step function. + * @function MyAvatar.getDriveGear1 + * @returns {number} Value between [0.0, 1.0]. + */ + Q_INVOKABLE float getDriveGear1(); + + /**jsdoc + * Set the second 'shifting point' for acceleration step function. + * @function MyAvatar.setDriveGear2 + * @param {number} shiftPoint - Defines the second shift point for analog movement acceleration step function, between [0, 1]. Must be greater than or equal to Gear 1 and less than or equal to Gear 2. + */ + Q_INVOKABLE void setDriveGear2(float shiftPoint); + + /**jsdoc + * Get the second 'shifting point' for acceleration step function. + * @function MyAvatar.getDriveGear2 + * @returns {number} Value between [0.0, 1.0]. + */ + Q_INVOKABLE float getDriveGear2(); + + /**jsdoc + * Set the third 'shifting point' for acceleration step function. + * @function MyAvatar.setDriveGear3 + * @param {number} shiftPoint - Defines the third shift point for analog movement acceleration step function, between [0, 1]. Must be greater than or equal to Gear 2 and less than or equal to Gear 4. + */ + Q_INVOKABLE void setDriveGear3(float shiftPoint); + + /**jsdoc + * Get the third 'shifting point' for acceleration step function. + * @function MyAvatar.getDriveGear3 + * @returns {number} Value between [0.0, 1.0]. + */ + Q_INVOKABLE float getDriveGear3(); + + /**jsdoc + * Set the fourth 'shifting point' for acceleration step function. + * @function MyAvatar.setDriveGear4 + * @param {number} shiftPoint - Defines the fourth shift point for analog movement acceleration step function, between [0, 1]. Must be greater than Gear 3 and less than Gear 5. + */ + Q_INVOKABLE void setDriveGear4(float shiftPoint); + + /**jsdoc + * Get the fourth 'shifting point' for acceleration step function. + * @function MyAvatar.getDriveGear4 + * @returns {number} Value between [0.0, 1.0]. + */ + Q_INVOKABLE float getDriveGear4(); + + /**jsdoc + * Set the fifth 'shifting point' for acceleration step function. + * @function MyAvatar.setDriveGear5 + * @param {number} shiftPoint - Defines the fifth shift point for analog movement acceleration step function, between [0, 1]. Must be greater than or equal to Gear 4. + */ + Q_INVOKABLE void setDriveGear5(float shiftPoint); + + /**jsdoc + * Get the fifth 'shifting point' for acceleration step function. + * @function MyAvatar.getDriveGear5 + * @returns {number} Value between [0.0, 1.0]. + */ + Q_INVOKABLE float getDriveGear5(); + + /**jsdoc + * Choose the control scheme. + * @function MyAvatar.setControlSchemeIndex + * @param {number} Choose the control scheme to be used. + */ + void setControlSchemeIndex(int index); + + /**jsdoc + * Check what control scheme is in use. + * @function MyAvatar.getControlSchemeIndex + * @returns {number} Returns the index associated with a given control scheme. + */ + int getControlSchemeIndex(); + /**jsdoc * Gets the target scale of the avatar. The target scale is the desired scale of the avatar without any restrictions on * permissible scale values imposed by the domain. @@ -1490,6 +1629,14 @@ public: float getWalkBackwardSpeed() const; void setSprintSpeed(float value); float getSprintSpeed() const; + void setAnalogWalkSpeed(float value); + float getAnalogWalkSpeed() const; + void setAnalogSprintSpeed(float value); + float getAnalogSprintSpeed() const; + void setAnalogPlusWalkSpeed(float value); + float getAnalogPlusWalkSpeed() const; + void setAnalogPlusSprintSpeed(float value); + float getAnalogPlusSprintSpeed() const; void setSitStandStateChange(bool stateChanged); float getSitStandStateChange() const; void updateSitStandState(float newHeightReading, float dt); @@ -2230,6 +2377,13 @@ private: float _boomLength { ZOOM_DEFAULT }; float _yawSpeed; // degrees/sec float _pitchSpeed; // degrees/sec + float _driveGear1 { DEFAULT_GEAR_1 }; + float _driveGear2 { DEFAULT_GEAR_2 }; + float _driveGear3 { DEFAULT_GEAR_3 }; + float _driveGear4 { DEFAULT_GEAR_4 }; + float _driveGear5 { DEFAULT_GEAR_5 }; + int _controlSchemeIndex { CONTROLS_DEFAULT }; + int _movementReference{ 0 }; glm::vec3 _thrust { 0.0f }; // impulse accumulator for outside sources @@ -2270,6 +2424,9 @@ private: // private methods void updateOrientation(float deltaTime); + glm::vec3 calculateScaledDirection(); + float calculateGearedSpeed(const float driveKey); + glm::vec3 scaleMotorSpeed(const glm::vec3 forward, const glm::vec3 right); void updateActionMotor(float deltaTime); void updatePosition(float deltaTime); void updateViewBoom(); @@ -2287,6 +2444,7 @@ private: bool _useSnapTurn { true }; ThreadSafeValueCache _dominantHand { DOMINANT_RIGHT_HAND }; ThreadSafeValueCache _hmdAvatarAlignmentType { DEFAULT_HMD_AVATAR_ALIGNMENT_TYPE }; + ThreadSafeValueCache _strafeEnabled{ DEFAULT_STRAFE_ENABLED }; const float ROLL_CONTROL_DEAD_ZONE_DEFAULT = 8.0f; // degrees const float ROLL_CONTROL_RATE_DEFAULT = 114.0f; // degrees / sec @@ -2438,9 +2596,16 @@ private: ThreadSafeValueCache _lockSitStandState { false }; // max unscaled forward movement speed - ThreadSafeValueCache _walkSpeed { DEFAULT_AVATAR_MAX_WALKING_SPEED }; - ThreadSafeValueCache _walkBackwardSpeed { DEFAULT_AVATAR_MAX_WALKING_BACKWARD_SPEED }; - ThreadSafeValueCache _sprintSpeed { AVATAR_SPRINT_SPEED_SCALAR }; + ThreadSafeValueCache _defaultWalkSpeed { DEFAULT_AVATAR_MAX_WALKING_SPEED }; + ThreadSafeValueCache _defaultWalkBackwardSpeed { DEFAULT_AVATAR_MAX_WALKING_BACKWARD_SPEED }; + ThreadSafeValueCache _defaultSprintSpeed { DEFAULT_AVATAR_MAX_SPRINT_SPEED }; + ThreadSafeValueCache _analogWalkSpeed { ANALOG_AVATAR_MAX_WALKING_SPEED }; + ThreadSafeValueCache _analogWalkBackwardSpeed { ANALOG_AVATAR_MAX_WALKING_BACKWARD_SPEED }; + ThreadSafeValueCache _analogSprintSpeed { ANALOG_AVATAR_MAX_SPRINT_SPEED }; + ThreadSafeValueCache _analogPlusWalkSpeed { ANALOG_PLUS_AVATAR_MAX_WALKING_SPEED }; + ThreadSafeValueCache _analogPlusWalkBackwardSpeed { ANALOG_PLUS_AVATAR_MAX_WALKING_BACKWARD_SPEED }; + ThreadSafeValueCache _analogPlusSprintSpeed { ANALOG_PLUS_AVATAR_MAX_SPRINT_SPEED }; + float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR }; bool _isInWalkingState { false }; ThreadSafeValueCache _isInSittingState { false }; @@ -2460,6 +2625,7 @@ private: TimePoint _nextTraitsSendWindow; Setting::Handle _dominantHandSetting; + Setting::Handle _strafeEnabledSetting; Setting::Handle _hmdAvatarAlignmentTypeSetting; Setting::Handle _headPitchSetting; Setting::Handle _scaleSetting; @@ -2473,8 +2639,17 @@ private: Setting::Handle _useSnapTurnSetting; Setting::Handle _userHeightSetting; Setting::Handle _flyingHMDSetting; + Setting::Handle _movementReferenceSetting; Setting::Handle _avatarEntityCountSetting; Setting::Handle _allowTeleportingSetting { "allowTeleporting", true }; + Setting::Handle _driveGear1Setting; + Setting::Handle _driveGear2Setting; + Setting::Handle _driveGear3Setting; + Setting::Handle _driveGear4Setting; + Setting::Handle _driveGear5Setting; + Setting::Handle _analogWalkSpeedSetting; + Setting::Handle _analogPlusWalkSpeedSetting; + Setting::Handle _controlSchemeIndexSetting; std::vector> _avatarEntityIDSettings; std::vector> _avatarEntityDataSettings; Setting::Handle _userRecenterModelSetting; diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index dbd24573ee..75279ef889 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -266,6 +266,11 @@ void setupPreferences() { auto preference = new CheckPreference(VR_MOVEMENT, "Walking", getter, setter); preferences->addPreference(preference); } + { + auto getter = [myAvatar]()->bool { return myAvatar->getStrafeEnabled(); }; + auto setter = [myAvatar](bool value) { myAvatar->setStrafeEnabled(value); }; + preferences->addPreference(new CheckPreference(VR_MOVEMENT, "Strafing", getter, setter)); + } { auto getter = [myAvatar]()->bool { return myAvatar->getFlyingHMDPref(); }; auto setter = [myAvatar](bool value) { myAvatar->setFlyingHMDPref(value); }; @@ -273,6 +278,22 @@ void setupPreferences() { preference->setIndented(true); preferences->addPreference(preference); } + { + auto getter = [myAvatar]()->int { return myAvatar->getMovementReference(); }; + auto setter = [myAvatar](int value) { myAvatar->setMovementReference(value); }; + //auto preference = new CheckPreference(VR_MOVEMENT, "Hand-Relative Movement", getter, setter); + auto preference = new RadioButtonsPreference(VR_MOVEMENT, "Movement Direction", getter, setter); + QStringList items; + items << "HMD-Relative" << "Hand-Relative" << "Hand-Relative (Leveled)"; + preference->setHeading("Movement Direction"); + preference->setItems(items); + preferences->addPreference(preference); + } + { + auto getter = [myAvatar]()->QString { return myAvatar->getDominantHand(); }; + auto setter = [myAvatar](const QString& value) { myAvatar->setDominantHand(value); }; + preferences->addPreference(new PrimaryHandPreference(VR_MOVEMENT, "Dominant Hand", getter, setter)); + } { auto getter = [myAvatar]()->int { return myAvatar->getSnapTurn() ? 0 : 1; }; auto setter = [myAvatar](int value) { myAvatar->setSnapTurn(value == 0); }; @@ -283,6 +304,26 @@ void setupPreferences() { preference->setItems(items); preferences->addPreference(preference); } + { + auto getter = [myAvatar]()->int { return myAvatar->getControlScheme(); }; + auto setter = [myAvatar](int index) { myAvatar->setControlScheme(index); }; + auto preference = new RadioButtonsPreference(VR_MOVEMENT, "Control Scheme", getter, setter); + QStringList items; + items << "Default" << "Analog" << "Analog++"; + preference->setHeading("Control Scheme Selection"); + preference->setItems(items); + preferences->addPreference(preference); + } + { + auto getter = [myAvatar]()->float { return myAvatar->getAnalogPlusWalkSpeed(); }; + auto setter = [myAvatar](float value) { myAvatar->setAnalogPlusWalkSpeed(value); }; + auto preference = new SpinnerSliderPreference(VR_MOVEMENT, "Analog++ Walk Speed", getter, setter); + preference->setMin(6.0f); + preference->setMax(30.0f); + preference->setStep(1); + preference->setDecimals(2); + preferences->addPreference(preference); + } { auto getter = [myAvatar]()->bool { return myAvatar->getShowPlayArea(); }; auto setter = [myAvatar](bool value) { myAvatar->setShowPlayArea(value); }; diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h index d8c0ce8e1d..4d2f1018a7 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h @@ -48,6 +48,8 @@ public: void pluginUpdate() override {}; + virtual StencilMode getStencilMaskMode() const override { return StencilMode::PAINT; } + signals: void hmdMountedChanged(); void hmdVisibleChanged(bool visible); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 1ccf3fcfa2..b3dd78ae92 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -1459,7 +1459,7 @@ void EntityTree::startDynamicDomainVerificationOnServer(float minimumAgeToRemove QNetworkReply* networkReply = networkAccessManager.put(networkRequest, QJsonDocument(request).toJson()); - connect(networkReply, &QNetworkReply::finished, this, [this, entityIDs, networkReply, minimumAgeToRemove, &certificateID] { + connect(networkReply, &QNetworkReply::finished, this, [this, entityIDs, networkReply, minimumAgeToRemove, certificateID] { QJsonObject jsonObject = QJsonDocument::fromJson(networkReply->readAll()).object(); jsonObject = jsonObject["data"].toObject(); diff --git a/libraries/graphics/src/graphics/Geometry.cpp b/libraries/graphics/src/graphics/Geometry.cpp index a983ba07b4..cee2b0e3c9 100755 --- a/libraries/graphics/src/graphics/Geometry.cpp +++ b/libraries/graphics/src/graphics/Geometry.cpp @@ -362,7 +362,6 @@ MeshPointer Mesh::createIndexedTriangles_P3F(uint32_t numVertices, uint32_t numI mesh->setIndexBuffer(gpu::BufferView(new gpu::Buffer(numIndices * sizeof(uint32_t), (gpu::Byte*) indices), gpu::Element::INDEX_INT32)); } - std::vector parts; parts.push_back(graphics::Mesh::Part(0, numIndices, 0, graphics::Mesh::TRIANGLES)); mesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(parts.size() * sizeof(graphics::Mesh::Part), (gpu::Byte*) parts.data()), gpu::Element::PART_DRAWCALL)); diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h index aa52e57c3f..48887d66b5 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.h +++ b/libraries/plugins/src/plugins/DisplayPlugin.h @@ -27,6 +27,7 @@ #include #include #include "Plugin.h" +#include "StencilMode.h" class QOpenGLFramebufferObject; @@ -221,6 +222,10 @@ public: // for updating plugin-related commands. Mimics the input plugin. virtual void pluginUpdate() = 0; + virtual StencilMode getStencilMaskMode() const { return StencilMode::NONE; } + using StencilMaskMeshOperator = std::function; + virtual StencilMaskMeshOperator getStencilMaskMeshOperator() { return nullptr; } + signals: void recommendedFramebufferSizeChanged(const QSize& size); void resetSensorsRequested(); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 89a9c7cf47..4cceb5ccb3 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1289,6 +1289,8 @@ void Model::scaleToFit() { // size is our "target size in world space" // we need to set our model scale so that the extents of the mesh, fit in a box that size... glm::vec3 meshDimensions = modelMeshExtents.maximum - modelMeshExtents.minimum; + const glm::vec3 MIN_MESH_DIMENSIONS { 1.0e-6f }; // one micrometer + meshDimensions = glm::max(meshDimensions, MIN_MESH_DIMENSIONS); glm::vec3 rescaleDimensions = _scaleToFitDimensions / meshDimensions; setScaleInternal(rescaleDimensions); _scaledToFit = true; diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index d1d4a7d3d1..3c207c982c 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -397,7 +397,7 @@ protected: glm::vec3 _translation; // this is the translation in world coordinates to the model's registration point glm::quat _rotation; - glm::vec3 _scale; + glm::vec3 _scale { 1.0f }; glm::vec3 _overrideTranslation; glm::quat _overrideRotation; diff --git a/libraries/render-utils/src/StencilMaskPass.cpp b/libraries/render-utils/src/StencilMaskPass.cpp index 7217a3e5eb..6dfc1e50fd 100644 --- a/libraries/render-utils/src/StencilMaskPass.cpp +++ b/libraries/render-utils/src/StencilMaskPass.cpp @@ -19,7 +19,6 @@ using namespace render; void PrepareStencil::configure(const Config& config) { _maskMode = config.maskMode; - _forceDraw = config.forceDraw; } graphics::MeshPointer PrepareStencil::getMesh() { @@ -43,6 +42,7 @@ gpu::PipelinePointer PrepareStencil::getMeshStencilPipeline() { auto state = std::make_shared(); drawMask(*state); state->setColorWriteMask(gpu::State::WRITE_NONE); + state->setCullMode(gpu::State::CullMode::CULL_NONE); _meshStencilPipeline = gpu::Pipeline::create(program, state); } @@ -64,30 +64,37 @@ gpu::PipelinePointer PrepareStencil::getPaintStencilPipeline() { void PrepareStencil::run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& srcFramebuffer) { RenderArgs* args = renderContext->args; - // Only draw the stencil mask if in HMD mode or not forced. - if (!_forceDraw && (args->_displayMode != RenderArgs::STEREO_HMD)) { + StencilMode maskMode = _maskMode; + std::function maskOperator = [this](gpu::Batch& batch) { + auto mesh = getMesh(); + batch.setIndexBuffer(mesh->getIndexBuffer()); + batch.setInputFormat((mesh->getVertexFormat())); + batch.setInputStream(0, mesh->getVertexStream()); + + // Draw + auto part = mesh->getPartBuffer().get(0); + batch.drawIndexed(gpu::TRIANGLES, part._numIndices, part._startIndex); + }; + + if (maskMode == StencilMode::NONE) { + maskMode = args->_stencilMode; + maskOperator = args->_stencilMaskOperator; + } + + if (maskMode == StencilMode::NONE || (maskMode == StencilMode::MESH && !maskOperator)) { return; } doInBatch("PrepareStencil::run", args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); - batch.setViewportTransform(args->_viewport); - if (_maskMode < 0) { - batch.setPipeline(getMeshStencilPipeline()); - - auto mesh = getMesh(); - batch.setIndexBuffer(mesh->getIndexBuffer()); - batch.setInputFormat((mesh->getVertexFormat())); - batch.setInputStream(0, mesh->getVertexStream()); - - // Draw - auto part = mesh->getPartBuffer().get(0); - batch.drawIndexed(gpu::TRIANGLES, part._numIndices, part._startIndex); - } else { + if (maskMode == StencilMode::PAINT) { batch.setPipeline(getPaintStencilPipeline()); batch.draw(gpu::TRIANGLE_STRIP, 4); + } else if (maskMode == StencilMode::MESH) { + batch.setPipeline(getMeshStencilPipeline()); + maskOperator(batch); } }); } diff --git a/libraries/render-utils/src/StencilMaskPass.h b/libraries/render-utils/src/StencilMaskPass.h index a8e4d1e1f2..410b7a5e0a 100644 --- a/libraries/render-utils/src/StencilMaskPass.h +++ b/libraries/render-utils/src/StencilMaskPass.h @@ -15,17 +15,19 @@ #include #include #include +#include class PrepareStencilConfig : public render::Job::Config { Q_OBJECT - Q_PROPERTY(int maskMode MEMBER maskMode NOTIFY dirty) - Q_PROPERTY(bool forceDraw MEMBER forceDraw NOTIFY dirty) + Q_PROPERTY(StencilMode maskMode MEMBER maskMode NOTIFY dirty) public: PrepareStencilConfig(bool enabled = true) : JobConfig(enabled) {} - int maskMode { 0 }; - bool forceDraw { false }; + // -1 -> don't force drawing (fallback to render args mode) + // 0 -> force draw without mesh + // 1 -> force draw with mesh + StencilMode maskMode { StencilMode::NONE }; signals: void dirty(); @@ -66,8 +68,7 @@ private: graphics::MeshPointer _mesh; graphics::MeshPointer getMesh(); - int _maskMode { 0 }; - bool _forceDraw { false }; + StencilMode _maskMode { StencilMode::NONE }; }; diff --git a/libraries/render/src/render/Args.h b/libraries/render/src/render/Args.h index b5c98e3428..d2354561e0 100644 --- a/libraries/render/src/render/Args.h +++ b/libraries/render/src/render/Args.h @@ -16,11 +16,11 @@ #include #include +#include #include #include "Forward.h" - class AABox; namespace render { @@ -133,6 +133,9 @@ namespace render { std::function _hudOperator; gpu::TexturePointer _hudTexture; + + StencilMode _stencilMode { StencilMode::NONE }; + std::function _stencilMaskOperator; }; } diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index a4fd2540d4..873e04dd0a 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -163,7 +163,7 @@ ScriptEnginePointer scriptEngineFactory(ScriptEngine::Context context, const QString& scriptContents, const QString& fileNameString) { ScriptEngine* engine = new ScriptEngine(context, scriptContents, fileNameString); - ScriptEnginePointer engineSP = ScriptEnginePointer(engine); + ScriptEnginePointer engineSP = ScriptEnginePointer(engine, &QObject::deleteLater); auto scriptEngines = DependencyManager::get(); scriptEngines->addScriptEngine(qSharedPointerCast(engineSP)); engine->setScriptEngines(scriptEngines); @@ -267,7 +267,7 @@ void ScriptEngine::disconnectNonEssentialSignals() { QThread* workerThread; // Ensure the thread should be running, and does exist if (_isRunning && _isThreaded && (workerThread = thread())) { - connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit); + connect(this, &QObject::destroyed, workerThread, &QThread::quit); connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater); } } @@ -381,7 +381,7 @@ void ScriptEngine::runInThread() { // the script engine, make sure to add code to "reconnect" them to the // disconnectNonEssentialSignals() method connect(workerThread, &QThread::started, this, &ScriptEngine::run); - connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit); + connect(this, &QObject::destroyed, workerThread, &QThread::quit); connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater); workerThread->start(); diff --git a/libraries/shared/src/AvatarConstants.h b/libraries/shared/src/AvatarConstants.h index d55a63b960..5166cb7a0b 100644 --- a/libraries/shared/src/AvatarConstants.h +++ b/libraries/shared/src/AvatarConstants.h @@ -69,7 +69,23 @@ const glm::quat DEFAULT_AVATAR_RIGHTFOOT_ROT { -0.4016716778278351f, 0.915461599 const float DEFAULT_AVATAR_MAX_WALKING_SPEED = 2.6f; // meters / second const float DEFAULT_AVATAR_MAX_WALKING_BACKWARD_SPEED = 2.2f; // meters / second const float DEFAULT_AVATAR_MAX_FLYING_SPEED = 30.0f; // meters / second -const float DEFAULT_AVATAR_WALK_SPEED_THRESHOLD = 0.15f; +const float DEFAULT_AVATAR_MAX_SPRINT_SPEED = 3.4f; // meters / second +const float DEFAULT_AVATAR_WALK_SPEED_THRESHOLD = 0.15f; // meters / second + +const float ANALOG_AVATAR_MAX_WALKING_SPEED = 6.0f; // meters / second +const float ANALOG_AVATAR_MAX_WALKING_BACKWARD_SPEED = 2.2f; // meters / second +const float ANALOG_AVATAR_MAX_FLYING_SPEED = 30.0f; // meters / second +const float ANALOG_AVATAR_MAX_SPRINT_SPEED = 8.0f; // meters / second +const float ANALOG_AVATAR_GEAR_1 = 0.2f; // meters / second +const float ANALOG_AVATAR_GEAR_2 = 0.4f; // meters / second +const float ANALOG_AVATAR_GEAR_3 = 0.6f; // meters / second +const float ANALOG_AVATAR_GEAR_4 = 0.8f; // meters / second +const float ANALOG_AVATAR_GEAR_5 = 1.0f; // meters / second + +const float ANALOG_PLUS_AVATAR_MAX_WALKING_SPEED = 10.0f; // meters / second +const float ANALOG_PLUS_AVATAR_MAX_WALKING_BACKWARD_SPEED = 2.42f; // meters / second +const float ANALOG_PLUS_AVATAR_MAX_FLYING_SPEED = 30.0f; // meters / second +const float ANALOG_PLUS_AVATAR_MAX_SPRINT_SPEED = 20.0f; // meters / second const float DEFAULT_AVATAR_GRAVITY = -5.0f; // meters / second^2 (world) const float DEFAULT_AVATAR_JUMP_SPEED = 3.5f; // meters / second (sensor) @@ -86,6 +102,6 @@ static const float MAX_AVATAR_HEIGHT = 1000.0f * DEFAULT_AVATAR_HEIGHT; // meter static const float MIN_AVATAR_HEIGHT = 0.005f * DEFAULT_AVATAR_HEIGHT; // meters static const float MIN_AVATAR_RADIUS = 0.5f * MIN_AVATAR_HEIGHT; static const float AVATAR_WALK_SPEED_SCALAR = 1.0f; -static const float AVATAR_SPRINT_SPEED_SCALAR = 3.0f; +static const float AVATAR_SPRINT_SPEED_SCALAR = 2.0f; #endif // hifi_AvatarConstants_h diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index 597e537d8d..bb89ce306e 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -40,6 +40,7 @@ int qMapURLStringMetaTypeId = qRegisterMetaType>(); int socketErrorMetaTypeId = qRegisterMetaType(); int voidLambdaType = qRegisterMetaType>(); int variantLambdaType = qRegisterMetaType>(); +int stencilModeMetaTypeId = qRegisterMetaType(); void registerMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, vec2ToScriptValue, vec2FromScriptValue); @@ -64,6 +65,8 @@ void registerMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, collisionToScriptValue, collisionFromScriptValue); qScriptRegisterMetaType(engine, quuidToScriptValue, quuidFromScriptValue); qScriptRegisterMetaType(engine, aaCubeToScriptValue, aaCubeFromScriptValue); + + qScriptRegisterMetaType(engine, stencilModeToScriptValue, stencilModeFromScriptValue); } QScriptValue vec2ToScriptValue(QScriptEngine* engine, const glm::vec2& vec2) { @@ -1283,4 +1286,12 @@ QVariantMap parseTexturesToMap(QString newTextures, const QVariantMap& defaultTe } return toReturn; +} + +QScriptValue stencilModeToScriptValue(QScriptEngine* engine, const StencilMode& stencilMode) { + return engine->newVariant((int)stencilMode); +} + +void stencilModeFromScriptValue(const QScriptValue& object, StencilMode& stencilMode) { + stencilMode = StencilMode(object.toVariant().toInt()); } \ No newline at end of file diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index ea2c5b8354..13d7f81a2e 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -25,6 +25,7 @@ #include "shared/Bilateral.h" #include "Transform.h" #include "PhysicsCollisionGroups.h" +#include "StencilMode.h" class QColor; class QUrl; @@ -729,5 +730,8 @@ void qVectorMeshFaceFromScriptValue(const QScriptValue& array, QVector QVariantMap parseTexturesToMap(QString textures, const QVariantMap& defaultTextures); +Q_DECLARE_METATYPE(StencilMode) +QScriptValue stencilModeToScriptValue(QScriptEngine* engine, const StencilMode& stencilMode); +void stencilModeFromScriptValue(const QScriptValue &object, StencilMode& stencilMode); #endif // hifi_RegisteredMetaTypes_h diff --git a/libraries/shared/src/StencilMode.h b/libraries/shared/src/StencilMode.h new file mode 100644 index 0000000000..412d33b319 --- /dev/null +++ b/libraries/shared/src/StencilMode.h @@ -0,0 +1,19 @@ +// +// Created by Sam Gondelman on 3/26/19. +// Copyright 2019 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_StencilMode_h +#define hifi_StencilMode_h + +enum class StencilMode { + NONE = -1, // for legacy reasons, this is -1 + PAINT = 0, + MESH = 1 +}; + +#endif // hifi_StencilMode_h + diff --git a/plugins/oculus/CMakeLists.txt b/plugins/oculus/CMakeLists.txt index abce753b4d..6ddc75e1e5 100644 --- a/plugins/oculus/CMakeLists.txt +++ b/plugins/oculus/CMakeLists.txt @@ -18,7 +18,7 @@ if (WIN32 AND (NOT USE_GLES)) link_hifi_libraries( shared task gl shaders gpu ${PLATFORM_GL_BACKEND} controllers ui qml plugins ui-plugins display-plugins input-plugins - audio-client networking render-utils + audio-client networking render-utils graphics ${PLATFORM_GL_BACKEND} ) include_hifi_library_headers(octree) diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index a67e3127e5..db26537a19 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -227,3 +227,66 @@ QVector OculusBaseDisplayPlugin::getSensorPositions() { return result; } + +DisplayPlugin::StencilMaskMeshOperator OculusBaseDisplayPlugin::getStencilMaskMeshOperator() { + if (_session) { + if (!_stencilMeshesInitialized) { + _stencilMeshesInitialized = true; + ovr::for_each_eye([&](ovrEyeType eye) { + ovrFovStencilDesc stencilDesc = { + ovrFovStencil_HiddenArea, 0, eye, + _eyeRenderDescs[eye].Fov, _eyeRenderDescs[eye].HmdToEyePose.Orientation + }; + // First we get the size of the buffer we need + ovrFovStencilMeshBuffer buffer = { 0, 0, nullptr, 0, 0, nullptr }; + ovrResult result = ovr_GetFovStencil(_session, &stencilDesc, &buffer); + if (!OVR_SUCCESS(result)) { + _stencilMeshesInitialized = false; + return; + } + + std::vector ovrVertices(buffer.UsedVertexCount); + std::vector ovrIndices(buffer.UsedIndexCount); + + // Now we populate the actual buffer + buffer = { (int)ovrVertices.size(), 0, ovrVertices.data(), (int)ovrIndices.size(), 0, ovrIndices.data() }; + result = ovr_GetFovStencil(_session, &stencilDesc, &buffer); + + if (!OVR_SUCCESS(result)) { + _stencilMeshesInitialized = false; + return; + } + + std::vector vertices; + vertices.reserve(ovrVertices.size()); + for (auto& ovrVertex : ovrVertices) { + // We need the vertices in clip space + vertices.emplace_back(ovrVertex.x - (1.0f - (float)eye), 2.0f * ovrVertex.y - 1.0f, 0.0f); + } + + std::vector indices; + indices.reserve(ovrIndices.size()); + for (auto& ovrIndex : ovrIndices) { + indices.push_back(ovrIndex); + } + + _stencilMeshes[eye] = graphics::Mesh::createIndexedTriangles_P3F((uint32_t)vertices.size(), (uint32_t)indices.size(), vertices.data(), indices.data()); + }); + } + + if (_stencilMeshesInitialized) { + return [&](gpu::Batch& batch) { + for (auto& mesh : _stencilMeshes) { + batch.setIndexBuffer(mesh->getIndexBuffer()); + batch.setInputFormat((mesh->getVertexFormat())); + batch.setInputStream(0, mesh->getVertexStream()); + + // Draw + auto part = mesh->getPartBuffer().get(0); + batch.drawIndexed(gpu::TRIANGLES, part._numIndices, part._startIndex); + } + }; + } + } + return nullptr; +} \ No newline at end of file diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.h b/plugins/oculus/src/OculusBaseDisplayPlugin.h index 1abb7cdad7..42aa02a18f 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.h +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.h @@ -16,6 +16,8 @@ #define OVRPL_DISABLED #include +#include + class OculusBaseDisplayPlugin : public HmdDisplayPlugin { using Parent = HmdDisplayPlugin; public: @@ -34,6 +36,9 @@ public: QRectF getPlayAreaRect() override; QVector getSensorPositions() override; + virtual StencilMode getStencilMaskMode() const override { return StencilMode::MESH; } + virtual StencilMaskMeshOperator getStencilMaskMeshOperator() override; + protected: void customizeContext() override; void uncustomizeContext() override; @@ -52,4 +57,7 @@ protected: // ovrLayerEyeFovDepth _depthLayer; bool _hmdMounted { false }; bool _visible { true }; + + std::array _stencilMeshes; + bool _stencilMeshesInitialized { false }; }; diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index 11d941dcd0..b102722aea 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -784,3 +784,49 @@ QRectF OpenVrDisplayPlugin::getPlayAreaRect() { return QRectF(center.x, center.y, dimensions.x, dimensions.y); } + + +DisplayPlugin::StencilMaskMeshOperator OpenVrDisplayPlugin::getStencilMaskMeshOperator() { + if (_system) { + if (!_stencilMeshesInitialized) { + _stencilMeshesInitialized = true; + for (auto eye : VR_EYES) { + vr::HiddenAreaMesh_t stencilMesh = _system->GetHiddenAreaMesh(eye); + if (stencilMesh.pVertexData && stencilMesh.unTriangleCount > 0) { + std::vector vertices; + std::vector indices; + + const int NUM_INDICES_PER_TRIANGLE = 3; + int numIndices = stencilMesh.unTriangleCount * NUM_INDICES_PER_TRIANGLE; + vertices.reserve(numIndices); + indices.reserve(numIndices); + for (int i = 0; i < numIndices; i++) { + vr::HmdVector2_t vertex2D = stencilMesh.pVertexData[i]; + // We need the vertices in clip space + vertices.emplace_back(vertex2D.v[0] - (1.0f - (float)eye), 2.0f * vertex2D.v[1] - 1.0f, 0.0f); + indices.push_back(i); + } + + _stencilMeshes[eye] = graphics::Mesh::createIndexedTriangles_P3F((uint32_t)vertices.size(), (uint32_t)indices.size(), vertices.data(), indices.data()); + } else { + _stencilMeshesInitialized = false; + } + } + } + + if (_stencilMeshesInitialized) { + return [&](gpu::Batch& batch) { + for (auto& mesh : _stencilMeshes) { + batch.setIndexBuffer(mesh->getIndexBuffer()); + batch.setInputFormat((mesh->getVertexFormat())); + batch.setInputStream(0, mesh->getVertexStream()); + + // Draw + auto part = mesh->getPartBuffer().get(0); + batch.drawIndexed(gpu::TRIANGLES, part._numIndices, part._startIndex); + } + }; + } + } + return nullptr; +} \ No newline at end of file diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.h b/plugins/openvr/src/OpenVrDisplayPlugin.h index 265f328920..aaec787893 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.h +++ b/plugins/openvr/src/OpenVrDisplayPlugin.h @@ -13,6 +13,8 @@ #include +#include + const float TARGET_RATE_OpenVr = 90.0f; // FIXME: get from sdk tracked device property? This number is vive-only. namespace gl { @@ -67,6 +69,9 @@ public: QRectF getPlayAreaRect() override; + virtual StencilMode getStencilMaskMode() const override{ return StencilMode::MESH; } + virtual StencilMaskMeshOperator getStencilMaskMeshOperator() override; + protected: bool internalActivate() override; void internalDeactivate() override; @@ -94,4 +99,7 @@ private: bool _asyncReprojectionActive { false }; bool _hmdMounted { false }; + + std::array _stencilMeshes; + bool _stencilMeshesInitialized { false }; }; diff --git a/scripts/system/controllers/controllerModules/farGrabEntity.js b/scripts/system/controllers/controllerModules/farGrabEntity.js index 65a3671cae..ecafa3cb26 100644 --- a/scripts/system/controllers/controllerModules/farGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farGrabEntity.js @@ -18,7 +18,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Script.include("/~/system/libraries/controllers.js"); -(function() { +(function () { var MARGIN = 25; function TargetObject(entityID, entityProps) { @@ -27,12 +27,13 @@ Script.include("/~/system/libraries/controllers.js"); this.targetEntityID = null; this.targetEntityProps = null; - this.getTargetEntity = function() { + this.getTargetEntity = function () { var parentPropsLength = this.parentProps.length; if (parentPropsLength !== 0) { var targetEntity = { id: this.parentProps[parentPropsLength - 1].id, - props: this.parentProps[parentPropsLength - 1]}; + props: this.parentProps[parentPropsLength - 1] + }; this.targetEntityID = targetEntity.id; this.targetEntityProps = targetEntity.props; return targetEntity; @@ -41,7 +42,8 @@ Script.include("/~/system/libraries/controllers.js"); this.targetEntityProps = this.entityProps; return { id: this.entityID, - props: this.entityProps}; + props: this.entityProps + }; }; } @@ -62,8 +64,6 @@ Script.include("/~/system/libraries/controllers.js"); this.MIN_HAPTIC_PULSE_INTERVAL = 500; // ms this.disabled = false; var _this = this; - this.leftTrigger = 0.0; - this.rightTrigger = 0.0; this.initialControllerRotation = Quat.IDENTITY; this.currentControllerRotation = Quat.IDENTITY; this.manipulating = false; @@ -101,13 +101,9 @@ Script.include("/~/system/libraries/controllers.js"); return (this.hand === RIGHT_HAND ? LEFT_HAND : RIGHT_HAND); } - this.getOffhandTrigger = function () { - return (_this.hand === RIGHT_HAND ? _this.leftTrigger : _this.rightTrigger); - } - // Activation criteria for rotating a fargrabbed entity. If we're changing the mapping, this is where to do it. - this.shouldManipulateTarget = function () { - return (_this.getOffhandTrigger() > TRIGGER_ON_VALUE) ? true : false; + this.shouldManipulateTarget = function (controllerData) { + return (controllerData.triggerValues[this.getOffhand()] > TRIGGER_ON_VALUE || controllerData.secondaryValues[this.getOffhand()] > TRIGGER_ON_VALUE) ? true : false; }; // Get the delta between the current rotation and where the controller was when manipulation started. @@ -123,11 +119,15 @@ Script.include("/~/system/libraries/controllers.js"); MyAvatar.setJointRotation(FAR_GRAB_JOINTS[this.hand], newTargetRotLocal); }; - this.handToController = function() { + this.setJointRotation = function (newTargetRotLocal) { + MyAvatar.setJointRotation(FAR_GRAB_JOINTS[this.hand], newTargetRotLocal); + }; + + this.handToController = function () { return (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; }; - this.distanceGrabTimescale = function(mass, distance) { + this.distanceGrabTimescale = function (mass, distance) { var timeScale = DISTANCE_HOLDING_ACTION_TIMEFRAME * mass / DISTANCE_HOLDING_UNITY_MASS * distance / DISTANCE_HOLDING_UNITY_DISTANCE; @@ -137,7 +137,7 @@ Script.include("/~/system/libraries/controllers.js"); return timeScale; }; - this.getMass = function(dimensions, density) { + this.getMass = function (dimensions, density) { return (dimensions.x * dimensions.y * dimensions.z) * density; }; @@ -204,8 +204,8 @@ Script.include("/~/system/libraries/controllers.js"); } var farJointIndex = FAR_GRAB_JOINTS[this.hand]; this.grabID = MyAvatar.grab(targetProps.id, farJointIndex, - Entities.worldToLocalPosition(targetProps.position, MyAvatar.SELF_ID, farJointIndex), - Entities.worldToLocalRotation(targetProps.rotation, MyAvatar.SELF_ID, farJointIndex)); + Entities.worldToLocalPosition(targetProps.position, MyAvatar.SELF_ID, farJointIndex), + Entities.worldToLocalRotation(targetProps.rotation, MyAvatar.SELF_ID, farJointIndex)); Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ action: 'grab', @@ -217,7 +217,7 @@ Script.include("/~/system/libraries/controllers.js"); this.previousRoomControllerPosition = roomControllerPosition; }; - this.continueDistanceHolding = function(controllerData) { + this.continueDistanceHolding = function (controllerData) { var controllerLocation = controllerData.controllerLocations[this.hand]; var worldControllerPosition = controllerLocation.position; var worldControllerRotation = controllerLocation.orientation; @@ -263,7 +263,7 @@ Script.include("/~/system/libraries/controllers.js"); var RADIAL_GRAB_AMPLIFIER = 10.0; if (Math.abs(this.grabRadialVelocity) > 0.0) { this.grabRadius = this.grabRadius + (this.grabRadialVelocity * deltaObjectTime * - this.grabRadius * RADIAL_GRAB_AMPLIFIER); + this.grabRadius * RADIAL_GRAB_AMPLIFIER); } // don't let grabRadius go all the way to zero, because it can't come back from that @@ -278,7 +278,7 @@ Script.include("/~/system/libraries/controllers.js"); var newTargetPosLocal = MyAvatar.worldToJointPoint(newTargetPosition); // This block handles the user's ability to rotate the object they're FarGrabbing - if (this.shouldManipulateTarget()) { + if (this.shouldManipulateTarget(controllerData)) { // Get the pose of the controller that is not grabbing. var pose = Controller.getPoseValue((this.getOffhand() ? Controller.Standard.RightHand : Controller.Standard.LeftHand)); if (pose.valid) { @@ -345,13 +345,13 @@ Script.include("/~/system/libraries/controllers.js"); otherModule.disabled = false; }; - this.updateRecommendedArea = function() { + this.updateRecommendedArea = function () { var dims = Controller.getViewportDimensions(); this.reticleMaxX = dims.x - MARGIN; this.reticleMaxY = dims.y - MARGIN; }; - this.calculateNewReticlePosition = function(intersection) { + this.calculateNewReticlePosition = function (intersection) { this.updateRecommendedArea(); var point2d = HMD.overlayFromWorldPoint(intersection); point2d.x = Math.max(this.reticleMinX, Math.min(point2d.x, this.reticleMaxX)); @@ -359,7 +359,7 @@ Script.include("/~/system/libraries/controllers.js"); return point2d; }; - this.notPointingAtEntity = function(controllerData) { + this.notPointingAtEntity = function (controllerData) { var intersection = controllerData.rayPicks[this.hand]; var entityProperty = Entities.getEntityProperties(intersection.objectID, DISPATCHER_PROPERTIES); var entityType = entityProperty.type; @@ -372,7 +372,7 @@ Script.include("/~/system/libraries/controllers.js"); return false; }; - this.destroyContextOverlay = function(controllerData) { + this.destroyContextOverlay = function (controllerData) { if (this.entityWithContextOverlay) { ContextOverlay.destroyContextOverlay(this.entityWithContextOverlay); this.entityWithContextOverlay = false; @@ -380,7 +380,7 @@ Script.include("/~/system/libraries/controllers.js"); } }; - this.targetIsNull = function() { + this.targetIsNull = function () { var properties = Entities.getEntityProperties(this.targetEntityID, DISPATCHER_PROPERTIES); if (Object.keys(properties).length === 0 && this.distanceHolding) { return true; @@ -424,8 +424,6 @@ Script.include("/~/system/libraries/controllers.js"); }; this.run = function (controllerData) { - this.leftTrigger = controllerData.triggerValues[LEFT_HAND]; - this.rightTrigger = controllerData.triggerValues[RIGHT_HAND]; if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE || this.targetIsNull()) { this.endFarGrabEntity(controllerData); return makeRunningValues(false, [], []); @@ -522,12 +520,12 @@ Script.include("/~/system/libraries/controllers.js"); _this.contextOverlayTimer && _this.potentialEntityWithContextOverlay === rayPickInfo.objectID) { var cotProps = Entities.getEntityProperties(rayPickInfo.objectID, - DISPATCHER_PROPERTIES); + DISPATCHER_PROPERTIES); var pointerEvent = { type: "Move", id: _this.hand + 1, // 0 is reserved for hardware mouse pos2D: projectOntoEntityXYPlane(rayPickInfo.objectID, - rayPickInfo.intersection, cotProps), + rayPickInfo.intersection, cotProps), pos3D: rayPickInfo.intersection, normal: rayPickInfo.surfaceNormal, direction: Vec3.subtract(ZERO_VEC, rayPickInfo.surfaceNormal), @@ -546,7 +544,7 @@ Script.include("/~/system/libraries/controllers.js"); return this.exitIfDisabled(controllerData); }; - this.exitIfDisabled = function(controllerData) { + this.exitIfDisabled = function (controllerData) { var moduleName = this.hand === RIGHT_HAND ? "RightDisableModules" : "LeftDisableModules"; var disableModule = getEnabledModuleByName(moduleName); if (disableModule) { @@ -563,10 +561,10 @@ Script.include("/~/system/libraries/controllers.js"); return makeRunningValues(true, [], [], laserLockInfo); }; - this.calculateOffset = function(controllerData) { + this.calculateOffset = function (controllerData) { if (this.distanceHolding) { var targetProps = Entities.getEntityProperties(this.targetObject.entityID, - [ "position", "rotation", "registrationPoint", "dimensions" ]); + ["position", "rotation", "registrationPoint", "dimensions"]); return worldPositionToRegistrationFrameMatrix(targetProps, controllerData.rayPicks[this.hand].intersection); } return undefined; diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index 23457cdd85..5a51773930 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -129,6 +129,8 @@ Script.include("/~/system/libraries/controllers.js"); this.init = false; this.hand = hand; this.buttonValue = 0; + this.standardAxisLY = 0.0; + this.standardAxisRY = 0.0; this.disabled = false; // used by the 'Hifi-Teleport-Disabler' message handler this.active = false; this.state = TELEPORTER_STATES.IDLE; @@ -690,6 +692,44 @@ Script.include("/~/system/libraries/controllers.js"); } }; + this.getStandardLY = function (value) { + _this.standardAxisLY = value; + }; + + this.getStandardRY = function (value) { + _this.standardAxisRY = value; + }; + + // Return value for the getDominantY and getOffhandY functions has to be inverted. + this.getDominantY = function () { + return (MyAvatar.getDominantHand() === "left") ? -(_this.standardAxisLY) : -(_this.standardAxisRY); + }; + + this.getOffhandY = function () { + return (MyAvatar.getDominantHand() === "left") ? -(_this.standardAxisRY) : -(_this.standardAxisLY); + }; + + this.getDominantHand = function () { + return (MyAvatar.getDominantHand() === "left") ? LEFT_HAND : RIGHT_HAND; + } + + this.getOffHand = function () { + return (MyAvatar.getDominantHand() === "left") ? RIGHT_HAND : LEFT_HAND; + } + + this.showReticle = function () { + return (_this.getDominantY() > TELEPORT_DEADZONE) ? true : false; + }; + + this.shouldTeleport = function () { + return (_this.getDominantY() > TELEPORT_DEADZONE && _this.getOffhandY() > TELEPORT_DEADZONE) ? true : false; + }; + + this.shouldCancel = function () { + //return (_this.getDominantY() < -TELEPORT_DEADZONE || _this.getOffhandY() < -TELEPORT_DEADZONE) ? true : false; + return (_this.getDominantY() <= TELEPORT_DEADZONE) ? true : false; + }; + this.parameters = makeDispatcherModuleParameters( 80, this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], @@ -706,7 +746,7 @@ Script.include("/~/system/libraries/controllers.js"); } var otherModule = this.getOtherModule(); - if (!this.disabled && this.buttonValue !== 0 && !otherModule.active) { + if (!this.disabled && this.showReticle() && !otherModule.active && this.hand === this.getDominantHand()) { this.active = true; this.enterTeleport(); return makeRunningValues(true, [], []); @@ -715,6 +755,12 @@ Script.include("/~/system/libraries/controllers.js"); }; this.run = function(controllerData, deltaTime) { + // Kill condition: + if (_this.shouldCancel()) { + _this.disableLasers(); + this.active = false; + return makeRunningValues(false, [], []); + } // Get current hand pose information to see if the pose is valid var pose = Controller.getPoseValue(handInfo[(_this.hand === RIGHT_HAND) ? 'right' : 'left'].controllerInput); @@ -778,7 +824,7 @@ Script.include("/~/system/libraries/controllers.js"); this.teleport = function(newResult, target) { var result = newResult; _this.teleportedPosition = newResult.intersection; - if (_this.buttonValue !== 0) { + if (!_this.shouldTeleport()) { return makeRunningValues(true, [], []); } @@ -801,8 +847,8 @@ Script.include("/~/system/libraries/controllers.js"); }; this.disableLasers = function() { - _this.setPlayAreaVisible(false, null, true); - _this.setTeleportVisible(false, null, true); + _this.setPlayAreaVisible(false, null, false); + _this.setTeleportVisible(false, null, false); Pointers.disablePointer(_this.teleportParabolaHandVisuals); Pointers.disablePointer(_this.teleportParabolaHandCollisions); Pointers.disablePointer(_this.teleportParabolaHeadVisuals); @@ -982,6 +1028,10 @@ Script.include("/~/system/libraries/controllers.js"); // Teleport actions. teleportMapping.from(Controller.Standard.LeftPrimaryThumb).peek().to(leftTeleporter.buttonPress); teleportMapping.from(Controller.Standard.RightPrimaryThumb).peek().to(rightTeleporter.buttonPress); + teleportMapping.from(Controller.Standard.LY).peek().to(leftTeleporter.getStandardLY); + teleportMapping.from(Controller.Standard.RY).peek().to(leftTeleporter.getStandardRY); + teleportMapping.from(Controller.Standard.LY).peek().to(rightTeleporter.getStandardLY); + teleportMapping.from(Controller.Standard.RY).peek().to(rightTeleporter.getStandardRY); } var leftTeleporter = new Teleporter(LEFT_HAND); diff --git a/scripts/system/controllers/controllerScripts.js b/scripts/system/controllers/controllerScripts.js index ca7d041792..c9cb61b5f5 100644 --- a/scripts/system/controllers/controllerScripts.js +++ b/scripts/system/controllers/controllerScripts.js @@ -15,7 +15,7 @@ var CONTOLLER_SCRIPTS = [ "squeezeHands.js", "controllerDisplayManager.js", "grab.js", - "toggleAdvancedMovementForHandControllers.js", + //"toggleAdvancedMovementForHandControllers.js", "handTouch.js", "controllerDispatcher.js", "controllerModules/nearParentGrabOverlay.js", diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js index 51645e5502..3b81e17473 100644 --- a/scripts/system/libraries/controllerDispatcherUtils.js +++ b/scripts/system/libraries/controllerDispatcherUtils.js @@ -103,6 +103,8 @@ TEAR_AWAY_DISTANCE = 0.15; // ungrab an entity if its bounding-box moves this fa TEAR_AWAY_COUNT = 2; // multiply by TEAR_AWAY_CHECK_TIME to know how long the item must be away TEAR_AWAY_CHECK_TIME = 0.15; // seconds, duration between checks +TELEPORT_DEADZONE = 0.15; + NEAR_GRAB_DISTANCE = 0.14; // Grab an entity if its bounding box is within this distance. // Smaller than TEAR_AWAY_DISTANCE for hysteresis. diff --git a/scripts/system/tablet-ui/tabletUI.js b/scripts/system/tablet-ui/tabletUI.js index 60848224bb..a38febaa77 100644 --- a/scripts/system/tablet-ui/tabletUI.js +++ b/scripts/system/tablet-ui/tabletUI.js @@ -291,7 +291,7 @@ var clickMapping = Controller.newMapping('tabletToggle-click'); var wantsMenu = 0; clickMapping.from(function () { return wantsMenu; }).to(Controller.Actions.ContextMenu); - clickMapping.from(Controller.Standard.RightSecondaryThumb).peek().to(function (clicked) { + clickMapping.from(Controller.Standard.RightSecondaryThumb).peek().when(Controller.Hardware.Application.LeftHandDominant).to(function (clicked) { if (clicked) { //activeHudPoint2d(Controller.Standard.RightHand); Messages.sendLocalMessage("toggleHand", Controller.Standard.RightHand); @@ -299,7 +299,7 @@ wantsMenu = clicked; }); - clickMapping.from(Controller.Standard.LeftSecondaryThumb).peek().to(function (clicked) { + clickMapping.from(Controller.Standard.LeftSecondaryThumb).peek().when(Controller.Hardware.Application.RightHandDominant).to(function (clicked) { if (clicked) { //activeHudPoint2d(Controller.Standard.LeftHand); Messages.sendLocalMessage("toggleHand", Controller.Standard.LeftHand); diff --git a/tools/jsdoc/README.md b/tools/jsdoc/README.md index f3dda84291..8526bccc4e 100644 --- a/tools/jsdoc/README.md +++ b/tools/jsdoc/README.md @@ -11,7 +11,7 @@ If you would like the extra functionality for gravPrep: To generate html documentation for the High Fidelity JavaScript API: * `cd tools/jsdoc` -* `jsdoc root.js -c config.json` +* `jsdoc root.js -r api-mainpage.md -c config.json` The out folder should contain index.html. diff --git a/tools/jsdoc/api-mainpage.md b/tools/jsdoc/api-mainpage.md new file mode 100644 index 0000000000..e1ec140af3 --- /dev/null +++ b/tools/jsdoc/api-mainpage.md @@ -0,0 +1,9 @@ +The High Fidelity JavaScript API lets content creators and developers create new experiences and transform virtual worlds within the High Fidelity metaverse. With it, you can build great content, customize avatars, play audio and so much more. + +You are most likely to interact with these APIs: + +* The **[Entities](Entities.html)** namespace lets you add, remove, and edit entities around you to build an interactive environment. In addition, you can use this namespace to find entities in range, direction, collision, or raytrace. +* The **[AvatarList](AvatarList.html)**, **[MyAvatar](MyAvatar.html)**, and **[Avatar](Avatar.html)** namespaces affect your personal avatars, and lets you get information on other people's avatars. +* The **[Script](Script.html)** namespace lets you to connect callbacks from your client to script, such as functionality that is dependent on time (`Script.update`, `Script.setTimeout`, `Script.setInterval`, etc), connect paths relatively to assets (`Script.resolvePath`), refer to other scripts (`Script.require`, `Script.include`), or connect functions to events which occur when the script is turned off (`Script.scriptEnding`). + +To learn more about using High Fidelity and exploring the metaverse, visit the [High Fidelity Documentation](https://docs.highfidelity.com). \ No newline at end of file diff --git a/tools/jsdoc/hifi-jsdoc-template/publish.js b/tools/jsdoc/hifi-jsdoc-template/publish.js index 9cd428bbbb..7d0ded5a0b 100644 --- a/tools/jsdoc/hifi-jsdoc-template/publish.js +++ b/tools/jsdoc/hifi-jsdoc-template/publish.js @@ -420,7 +420,7 @@ function linktoExternal(longName, name) { */ function buildNav(members) { - var nav = '

Home

'; + var nav = '

API Reference Home

'; var seen = {}; var seenTutorials = {}; var docdash = env && env.conf && env.conf.docdash || {}; diff --git a/tools/jsdoc/hifi-jsdoc-template/static/fonts/Cairo-Bold.ttf b/tools/jsdoc/hifi-jsdoc-template/static/fonts/Cairo-Bold.ttf deleted file mode 100644 index ad884391d7..0000000000 Binary files a/tools/jsdoc/hifi-jsdoc-template/static/fonts/Cairo-Bold.ttf and /dev/null differ diff --git a/tools/jsdoc/hifi-jsdoc-template/static/fonts/Graphik-Regular.otf b/tools/jsdoc/hifi-jsdoc-template/static/fonts/Graphik-Regular.otf new file mode 100644 index 0000000000..8100438827 Binary files /dev/null and b/tools/jsdoc/hifi-jsdoc-template/static/fonts/Graphik-Regular.otf differ diff --git a/tools/jsdoc/hifi-jsdoc-template/static/fonts/Graphik-Semibold.otf b/tools/jsdoc/hifi-jsdoc-template/static/fonts/Graphik-Semibold.otf new file mode 100644 index 0000000000..45cf6bc865 Binary files /dev/null and b/tools/jsdoc/hifi-jsdoc-template/static/fonts/Graphik-Semibold.otf differ diff --git a/tools/jsdoc/hifi-jsdoc-template/static/images/fav-icon.ico b/tools/jsdoc/hifi-jsdoc-template/static/images/fav-icon.ico new file mode 100644 index 0000000000..2bacaf1083 Binary files /dev/null and b/tools/jsdoc/hifi-jsdoc-template/static/images/fav-icon.ico differ diff --git a/tools/jsdoc/hifi-jsdoc-template/static/images/white-logo.png b/tools/jsdoc/hifi-jsdoc-template/static/images/white-logo.png index 18cd2d88dd..b23aa64e94 100644 Binary files a/tools/jsdoc/hifi-jsdoc-template/static/images/white-logo.png and b/tools/jsdoc/hifi-jsdoc-template/static/images/white-logo.png differ diff --git a/tools/jsdoc/hifi-jsdoc-template/static/styles/jsdoc.css b/tools/jsdoc/hifi-jsdoc-template/static/styles/jsdoc.css index 2ba9c84954..2232491d04 100644 --- a/tools/jsdoc/hifi-jsdoc-template/static/styles/jsdoc.css +++ b/tools/jsdoc/hifi-jsdoc-template/static/styles/jsdoc.css @@ -4,8 +4,13 @@ ********************************************************************/ @font-face{ - font-family: 'Cairo'; - src: url('../fonts/Cairo-Bold.ttf') format('truetype'); + font-family: 'Graphik Semibold'; + src: url('../fonts/Graphik-SemiBold.otf') format('opentype'); +} + +@font-face{ + font-family: 'Graphik Regular'; + src: url('../fonts/Graphik-Regular.otf') format('opentype'); } @font-face{ @@ -29,12 +34,15 @@ html body { - font-family: 'Proxima Nova', sans-serif; - font-size: 1rem; - line-height: 1.5; - letter-spacing: 0.5px; - margin: 1.5rem; - color: #555; + font-family: 'Graphik Regular', 'Proxima Nova', arial, sans-serif; + font-weight: 400; + color: #000000; + letter-spacing: 0.5px; +} + +#main p { + line-height: 24px; + margin-bottom: 24px; } section @@ -50,14 +58,13 @@ section ********************************************************************/ h1, h2, h3, h4 { - font-family: "Cairo", Helvetica, sans-serif; + font-family: "Graphik Semibold", Helvetica, sans-serif; } h1 { font-size: 3.25rem; text-align: center; - letter-spacing: 1.5px; margin: 50px 25px 25px; } @@ -69,15 +76,13 @@ h2 h3 { - font-size: 1.5rem; + font-size: 28px; } h4 { - font-size: 18px; - letter-spacing: -0.33px; - margin-bottom: 12px; - color: #4d4e53; + font-family: 'Graphik Regular'; + font-size: 1.03rem; } h6 @@ -119,7 +124,7 @@ table background-color: #fff; border-collapse: collapse; border-spacing: 0; - border: 1px solid #ccc; + border: solid #d8e1d9 1px; text-align: left; overflow: auto; font-size: 0.9rem; @@ -128,18 +133,19 @@ table } table > thead { - background-color: #ddd; - border-bottom: 1px solid #ccc; + border-color: #d8e1d9; + background: #d8e1d9; font-weight: 400; } table th, table td { padding: 0.5rem; - border-left: 1px solid #ccc; + border-left: 1px solid #d8e1d9; + font-size: .95em; } table tr { - border-bottom: 1px solid #ccc; + border-bottom: 1px solid #d8e1d9; } table tr:nth-child(even) { @@ -150,18 +156,14 @@ table tr:nth-child(even) { ****************************** Link styles ************************* ********************************************************************/ -a, a:visited, a:active { - color: #1694CA; - text-decoration: none; +a, a:hover, a:active, a:visited { + text-decoration: none; } -article a:hover { - color: #0e6185; - text-decoration: none; - font-weight: bold; +#main a, #main a:visited, #main a:active, #main a:hover { + color: #009ee0; } - /******************************************************************* ***************************** List styles ************************** ********************************************************************/ @@ -171,20 +173,29 @@ article ul { } article li { + font-size: .95rem; padding-bottom: 5px; } +.readme ul { + font-size: 0.95rem; + line-height: 24px; + margin-bottom: 24px; + +} + /******************************************************************* ********************** Navigation sidebar styles ******************* ********************************************************************/ nav { position: fixed; - top: 165px; + top: 260px; bottom: 0; left: 0; right: 0; - width: 305px; + width: 300px; + background-color: #000000; border-right: 1px solid #ccc; overflow-y: scroll; padding-left: 20px; @@ -192,6 +203,11 @@ nav { box-sizing: border-box; } +nav::-webkit-scrollbar { + width: 0; + height: 0; +} + nav #nav-search { width: 210px; height: 30px; @@ -207,21 +223,28 @@ nav #nav-search { position: fixed; top: 0; left: 0; - height: 165px; - width: 305px; - background-color: #00B4EF; - vertical-align: middle; + height: 260px; + width: 300px; + background-color: #000000; + color: #FFFFFF; text-align: center; margin-top: 0px; } .nav-header p { - padding-top: 15px; + padding-top: 8px; +} + +.nav-header a { + color: #FFFFFF; + font-size: .9rem; + line-height: 1.5; } nav h3 { - font-family: "Proxima Nova", sans-serif; + font-family: "Graphik Regular", sans-serif; font-size: 0.9rem; + color: #FFFFFF; text-transform: uppercase; letter-spacing: 0.5px; } @@ -233,8 +256,16 @@ nav ul { list-style: none; } +nav h3 a { + color: #FFFFFF; +} + nav ul a, nav ul a:visited, nav ul a:active { - color: #a1a1a1; + color: #FFFFFF; +} + +nav ul a:hover { + font-weight: bold; } nav ul ul { @@ -250,7 +281,7 @@ nav ul ul li:first-child nav li { - margin-top: 3px; + margin-top: 14px; } @@ -333,14 +364,14 @@ nav > h2 > a { .search-input { - font-family: 'Proxima Nova', sans-serif; - font-size: 0.9rem; + font-family: 'Graphik Regular', sans-serif; + font-size: 80%; border: 1px solid #ddd; box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.06); - border-radius: 0.1875rem; + border-radius: 0; color: #3A3F3E; - width: 75%; - padding: 0.425rem; + width: 70%; + padding: 10px; } /******************************************************************** @@ -349,23 +380,20 @@ nav > h2 > a { tt, code, kbd, samp { font-family: Consolas, Monaco, 'Andale Mono', monospace; - font-size: 0.8rem; + font-size: 0.9rem; } .name, .signature { font-family: Consolas, Monaco, 'Andale Mono', monospace; - font-size: 0.8rem; + font-size: 0.9rem; } - - - - - img { + display: block; max-width: 100%; + margin: auto; } p, ul, ol, blockquote { @@ -427,7 +455,7 @@ header { color: #999 !important; } -.availableIn +#main p.availableIn { font-size: 0.8rem; } @@ -517,7 +545,7 @@ header { .prettyprint code { - font-size: 0.65rem; + font-size: 0.7rem; line-height: 18px; display: block; padding: 4px 12px; @@ -580,13 +608,8 @@ header { padding-top: 0; } -.params td.description > p:last-child, .props td.description > p:last-child { - margin-bottom: 0; - padding-bottom: 0; -} - span.param-type, .params td .param-type, .param-type dd { - color: #606; + color: #606; font-family: Consolas, Monaco, 'Andale Mono', monospace } diff --git a/tools/jsdoc/hifi-jsdoc-template/tmpl/layout.tmpl b/tools/jsdoc/hifi-jsdoc-template/tmpl/layout.tmpl index 6f267587c0..41a324fdaf 100644 --- a/tools/jsdoc/hifi-jsdoc-template/tmpl/layout.tmpl +++ b/tools/jsdoc/hifi-jsdoc-template/tmpl/layout.tmpl @@ -16,10 +16,11 @@