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

This commit is contained in:
Sam Gateau 2019-09-21 08:52:13 -07:00
commit 3c2809b9ed
28 changed files with 5069 additions and 4389 deletions

View file

@ -240,6 +240,9 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
QThread::currentThread()->setObjectName("main thread"); QThread::currentThread()->setObjectName("main thread");
LogHandler::getInstance().setParent(this);
LogHandler::getInstance().setupRepeatedMessageFlusher();
DependencyManager::registerInheritance<LimitedNodeList, NodeList>(); DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
DependencyManager::set<ScriptInitializers>(); DependencyManager::set<ScriptInitializers>();

View file

@ -174,6 +174,9 @@ DomainServer::DomainServer(int argc, char* argv[]) :
LogUtils::init(); LogUtils::init();
LogHandler::getInstance().setParent(this);
LogHandler::getInstance().setupRepeatedMessageFlusher();
qDebug() << "Setting up domain-server"; qDebug() << "Setting up domain-server";
qDebug() << "[VERSION] Build sequence:" << qPrintable(applicationVersion()); qDebug() << "[VERSION] Build sequence:" << qPrintable(applicationVersion());
qDebug() << "[VERSION] MODIFIED_ORGANIZATION:" << BuildInfo::MODIFIED_ORGANIZATION; qDebug() << "[VERSION] MODIFIED_ORGANIZATION:" << BuildInfo::MODIFIED_ORGANIZATION;
@ -320,7 +323,7 @@ DomainServer::DomainServer(int argc, char* argv[]) :
connect(_contentManager.get(), &DomainContentBackupManager::recoveryCompleted, this, &DomainServer::restart); connect(_contentManager.get(), &DomainContentBackupManager::recoveryCompleted, this, &DomainServer::restart);
static const int NODE_PING_MONITOR_INTERVAL_MSECS = 1 * MSECS_PER_SECOND; static const int NODE_PING_MONITOR_INTERVAL_MSECS = 1 * MSECS_PER_SECOND;
_nodePingMonitorTimer = new QTimer{ this }; _nodePingMonitorTimer = new QTimer{ this };
connect(_nodePingMonitorTimer, &QTimer::timeout, this, &DomainServer::nodePingMonitor); connect(_nodePingMonitorTimer, &QTimer::timeout, this, &DomainServer::nodePingMonitor);
_nodePingMonitorTimer->start(NODE_PING_MONITOR_INTERVAL_MSECS); _nodePingMonitorTimer->start(NODE_PING_MONITOR_INTERVAL_MSECS);

File diff suppressed because it is too large Load diff

View file

@ -3,8 +3,8 @@
"channels": [ "channels": [
{ "from": "Keyboard.A", "when": ["Keyboard.RightMouseButton", "!Keyboard.Control"], "to": "Actions.LATERAL_LEFT" }, { "from": "Keyboard.A", "when": ["Keyboard.RightMouseButton", "!Keyboard.Control"], "to": "Actions.LATERAL_LEFT" },
{ "from": "Keyboard.D", "when": ["Keyboard.RightMouseButton", "!Keyboard.Control"], "to": "Actions.LATERAL_RIGHT" }, { "from": "Keyboard.D", "when": ["Keyboard.RightMouseButton", "!Keyboard.Control"], "to": "Actions.LATERAL_RIGHT" },
{ "from": "Keyboard.E", "when": "!Keyboard.Control", "to": "Actions.LATERAL_RIGHT" }, { "from": "Keyboard.E", "when": ["!Application.CameraSelfie", "!Application.CameraLookAt", "!Keyboard.Control"], "to": "Actions.LATERAL_RIGHT" },
{ "from": "Keyboard.Q", "when": "!Keyboard.Control", "to": "Actions.LATERAL_LEFT" }, { "from": "Keyboard.Q", "when": ["!Application.CameraSelfie"," !Application.CameraLookAt", "!Keyboard.Control"], "to": "Actions.LATERAL_LEFT" },
{ "from": "Keyboard.T", "when": "!Keyboard.Control", "to": "Actions.TogglePushToTalk" }, { "from": "Keyboard.T", "when": "!Keyboard.Control", "to": "Actions.TogglePushToTalk" },
{ "comment" : "Mouse turn need to be small continuous increments", { "comment" : "Mouse turn need to be small continuous increments",
@ -39,7 +39,6 @@
] ]
}, },
{ "from": { "makeAxis" : [ { "from": { "makeAxis" : [
["Keyboard.Left" ], ["Keyboard.Left" ],
["Keyboard.Right"] ["Keyboard.Right"]
@ -85,6 +84,24 @@
"when": ["Application.CameraThirdPerson", "!Keyboard.Shift"], "when": ["Application.CameraThirdPerson", "!Keyboard.Shift"],
"to": "Actions.Yaw" "to": "Actions.Yaw"
}, },
{ "from": { "makeAxis" : [
["Keyboard.Left"],
["Keyboard.Right"]
]
},
"when": ["Application.CameraLookAt", "!Keyboard.Shift"],
"to": "Actions.Yaw"
},
{ "from": { "makeAxis" : [
["Keyboard.Left"],
["Keyboard.Right"]
]
},
"when": ["Application.CameraSelfie", "!Keyboard.Shift"],
"to": "Actions.Yaw"
},
{ "from": { "makeAxis" : [ { "from": { "makeAxis" : [
["Keyboard.A"], ["Keyboard.A"],
@ -104,6 +121,24 @@
"to": "Actions.Yaw" "to": "Actions.Yaw"
}, },
{ "from": { "makeAxis" : [
["Keyboard.Q"],
["Keyboard.E"]
]
},
"when": ["Application.CameraLookAt", "!Keyboard.Control"],
"to": "Actions.Yaw"
},
{ "from": { "makeAxis" : [
["Keyboard.E"],
["Keyboard.Q"]
]
},
"when": ["Application.CameraSelfie", "!Keyboard.Control"],
"to": "Actions.Yaw"
},
{ "from": { "makeAxis" : [ { "from": { "makeAxis" : [
["Keyboard.TouchpadLeft"], ["Keyboard.TouchpadLeft"],
["Keyboard.TouchpadRight"] ["Keyboard.TouchpadRight"]
@ -122,6 +157,24 @@
"to": "Actions.Yaw" "to": "Actions.Yaw"
}, },
{ "from": { "makeAxis" : [
["Keyboard.TouchpadLeft"],
["Keyboard.TouchpadRight"]
]
},
"when": "Application.CameraLookAt",
"to": "Actions.Yaw"
},
{ "from": { "makeAxis" : [
["Keyboard.TouchpadLeft"],
["Keyboard.TouchpadRight"]
]
},
"when": "Application.CameraSelfie",
"to": "Actions.Yaw"
},
{ "from": { "makeAxis" : ["Keyboard.MouseMoveLeft", "Keyboard.MouseMoveRight"] }, { "from": { "makeAxis" : ["Keyboard.MouseMoveLeft", "Keyboard.MouseMoveRight"] },
"when": "Keyboard.RightMouseButton", "when": "Keyboard.RightMouseButton",
"to": "Actions.DeltaYaw", "to": "Actions.DeltaYaw",
@ -132,7 +185,7 @@
}, },
{ "from": { "makeAxis" : ["Keyboard.MouseMoveUp", "Keyboard.MouseMoveDown"] }, { "from": { "makeAxis" : ["Keyboard.MouseMoveUp", "Keyboard.MouseMoveDown"] },
"when": "Keyboard.RightMouseButton", "when": ["!Application.CameraSelfie", "!Application.CameraLookAt", "Keyboard.RightMouseButton"],
"to": "Actions.DeltaPitch", "to": "Actions.DeltaPitch",
"filters": "filters":
[ [
@ -140,16 +193,44 @@
] ]
}, },
{ "from": "Keyboard.W", "when": "!Keyboard.Control", "to": "Actions.LONGITUDINAL_FORWARD" }, { "from": { "makeAxis" : ["Keyboard.MouseMoveUp", "Keyboard.MouseMoveDown"] },
{ "from": "Keyboard.S", "when": "!Keyboard.Control", "to": "Actions.LONGITUDINAL_BACKWARD" }, "when": ["Application.CameraLookAt", "Keyboard.RightMouseButton"],
"to": "Actions.DeltaPitch",
"filters":
[
{ "type": "scale", "scale": 0.3 }
]
},
{ "from": { "makeAxis" : ["Keyboard.MouseMoveDown", "Keyboard.MouseMoveUp"] },
"when": ["Application.CameraSelfie", "Keyboard.RightMouseButton"],
"to": "Actions.DeltaPitch",
"filters":
[
{ "type": "scale", "scale": 0.3 }
]
},
{ "from": "Keyboard.W", "when": ["!Application.CameraSelfie", "!Keyboard.Control"], "to": "Actions.LONGITUDINAL_FORWARD" },
{ "from": "Keyboard.S", "when": ["!Application.CameraSelfie", "!Keyboard.Control"], "to": "Actions.LONGITUDINAL_BACKWARD" },
{ "from": "Keyboard.S", "when": ["Application.CameraSelfie", "!Keyboard.Control"], "to": "Actions.LONGITUDINAL_FORWARD" },
{ "from": "Keyboard.W", "when": ["Application.CameraSelfie", "!Keyboard.Control"], "to": "Actions.LONGITUDINAL_BACKWARD" },
{ "from": "Keyboard.A", "when": "Application.CameraLookAt", "to": "Actions.LATERAL_LEFT" },
{ "from": "Keyboard.D", "when": "Application.CameraLookAt", "to": "Actions.LATERAL_RIGHT" },
{ "from": "Keyboard.A", "when": "Application.CameraSelfie", "to": "Actions.LATERAL_RIGHT" },
{ "from": "Keyboard.D", "when": "Application.CameraSelfie", "to": "Actions.LATERAL_LEFT" },
{ "from": "Keyboard.Shift", "when": ["!Keyboard.Left", "!Keyboard.Right"], "to": "Actions.SPRINT" }, { "from": "Keyboard.Shift", "when": ["!Keyboard.Left", "!Keyboard.Right"], "to": "Actions.SPRINT" },
{ "from": "Keyboard.C", "when": "!Keyboard.Control", "to": "Actions.VERTICAL_DOWN" }, { "from": "Keyboard.C", "when": "!Keyboard.Control", "to": "Actions.VERTICAL_DOWN" },
{ "from": "Keyboard.Left", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" }, { "from": "Keyboard.Left", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" },
{ "from": "Keyboard.Right", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" }, { "from": "Keyboard.Right", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" },
{ "from": "Keyboard.Up", "when": "Application.CameraFirstPerson", "to": "Actions.LONGITUDINAL_FORWARD" }, { "from": "Keyboard.Up", "when": "Application.CameraFirstPerson", "to": "Actions.LONGITUDINAL_FORWARD" },
{ "from": "Keyboard.Up", "when": "Application.CameraThirdPerson", "to": "Actions.LONGITUDINAL_FORWARD" }, { "from": "Keyboard.Up", "when": "Application.CameraThirdPerson", "to": "Actions.LONGITUDINAL_FORWARD" },
{ "from": "Keyboard.Up", "when": "Application.CameraLookAt", "to": "Actions.LONGITUDINAL_FORWARD" },
{ "from": "Keyboard.Up", "when": "Application.CameraSelfie", "to": "Actions.LONGITUDINAL_BACKWARD" },
{ "from": "Keyboard.Down", "when": "Application.CameraFirstPerson", "to": "Actions.LONGITUDINAL_BACKWARD" }, { "from": "Keyboard.Down", "when": "Application.CameraFirstPerson", "to": "Actions.LONGITUDINAL_BACKWARD" },
{ "from": "Keyboard.Down", "when": "Application.CameraThirdPerson", "to": "Actions.LONGITUDINAL_BACKWARD" }, { "from": "Keyboard.Down", "when": "Application.CameraThirdPerson", "to": "Actions.LONGITUDINAL_BACKWARD" },
{ "from": "Keyboard.Down", "when": "Application.CameraLookAt", "to": "Actions.LONGITUDINAL_BACKWARD" },
{ "from": "Keyboard.Down", "when": "Application.CameraSelfie", "to": "Actions.LONGITUDINAL_FORWARD" },
{ "from": "Keyboard.PgDown", "to": "Actions.VERTICAL_DOWN" }, { "from": "Keyboard.PgDown", "to": "Actions.VERTICAL_DOWN" },
{ "from": "Keyboard.PgUp", "to": "Actions.VERTICAL_UP" }, { "from": "Keyboard.PgUp", "to": "Actions.VERTICAL_UP" },

View file

@ -71,7 +71,7 @@ Flickable {
ColumnLayout { ColumnLayout {
id: controlsContainer id: controlsContainer
Layout.preferredWidth: parent.width Layout.preferredWidth: parent.width
Layout.topMargin: 24 Layout.topMargin: 24
spacing: 0 spacing: 0
HifiStylesUit.GraphikSemiBold { HifiStylesUit.GraphikSemiBold {
@ -154,6 +154,45 @@ Flickable {
} }
} }
} }
ColumnLayout {
Layout.preferredWidth: parent.width
spacing: 0
HifiStylesUit.GraphikSemiBold {
text: "VR Rotation Mode"
Layout.preferredWidth: parent.width
height: paintedHeight
size: 22
color: simplifiedUI.colors.text.white
}
ColumnLayout {
width: parent.width
Layout.topMargin: simplifiedUI.margins.settings.settingsGroupTopMargin
spacing: simplifiedUI.margins.settings.spacingBetweenRadiobuttons
ButtonGroup { id: rotationButtonGroup }
SimplifiedControls.RadioButton {
text: "Snap Turn"
ButtonGroup.group: rotationButtonGroup
checked: MyAvatar.getSnapTurn() === true
onClicked: {
MyAvatar.setSnapTurn(true);
}
}
SimplifiedControls.RadioButton {
text: "Smooth Turn"
ButtonGroup.group: rotationButtonGroup
checked: MyAvatar.getSnapTurn() === false
onClicked: {
MyAvatar.setSnapTurn(false);
}
}
}
}
ColumnLayout { ColumnLayout {
id: micControlsContainer id: micControlsContainer

View file

@ -24,6 +24,8 @@ TextField {
property string rightGlyph: "" property string rightGlyph: ""
property alias bottomBorderVisible: bottomRectangle.visible property alias bottomBorderVisible: bottomRectangle.visible
property alias backgroundColor: textFieldBackground.color property alias backgroundColor: textFieldBackground.color
property string unfocusedPlaceholderText
property bool blankPlaceholderTextOnFocus: true
color: simplifiedUI.colors.text.white color: simplifiedUI.colors.text.white
font.family: "Graphik Medium" font.family: "Graphik Medium"
@ -47,6 +49,19 @@ TextField {
} }
} }
onFocusChanged: {
if (!root.blankPlaceholderTextOnFocus) {
return;
}
if (focus) {
root.unfocusedPlaceholderText = root.placeholderText;
root.placeholderText = "";
} else {
root.placeholderText = root.unfocusedPlaceholderText;
}
}
background: Rectangle { background: Rectangle {
id: textFieldBackground id: textFieldBackground
color: Qt.rgba(0, 0, 0, 0); color: Qt.rgba(0, 0, 0, 0);

View file

@ -372,12 +372,14 @@ Rectangle {
readonly property string shortPlaceholderText: "Jump to..." readonly property string shortPlaceholderText: "Jump to..."
readonly property string longPlaceholderText: "Type the name of a location to quickly jump there..." readonly property string longPlaceholderText: "Type the name of a location to quickly jump there..."
anchors.centerIn: parent anchors.centerIn: parent
width: Math.min(parent.width, 600) width: Math.min(parent.width, 445)
height: parent.height - 11 height: 35
leftPadding: 8 leftPadding: 8
rightPadding: 8 rightPadding: 8
bottomBorderVisible: false bottomBorderVisible: false
backgroundColor: "#313131" backgroundColor: "#1D1D1D"
placeholderTextColor: "#8E8E8E"
font.pixelSize: 14
placeholderText: width - leftPadding - rightPadding < goToTextFieldMetrics.width ? shortPlaceholderText : longPlaceholderText placeholderText: width - leftPadding - rightPadding < goToTextFieldMetrics.width ? shortPlaceholderText : longPlaceholderText
clip: true clip: true
selectByMouse: true selectByMouse: true
@ -386,8 +388,8 @@ Rectangle {
if (goToTextField.length > 0) { if (goToTextField.length > 0) {
AddressManager.handleLookupString(goToTextField.text); AddressManager.handleLookupString(goToTextField.text);
goToTextField.text = ""; goToTextField.text = "";
parent.forceActiveFocus();
} }
parent.forceActiveFocus();
} }
} }
} }

View file

@ -19,6 +19,7 @@ StackView {
objectName: "stack" objectName: "stack"
property string title: "General Settings" property string title: "General Settings"
property alias gotoPreviousApp: root.gotoPreviousApp; property alias gotoPreviousApp: root.gotoPreviousApp;
property alias gotoPreviousAppFromScript: root.gotoPreviousAppFromScript;
signal sendToScript(var message); signal sendToScript(var message);
function pushSource(path) { function pushSource(path) {
@ -30,6 +31,10 @@ StackView {
profileRoot.pop(); profileRoot.pop();
} }
function emitSendToScript(message) {
profileRoot.sendToScript(message);
}
TabletPreferencesDialog { TabletPreferencesDialog {
id: root id: root
objectName: "TabletGeneralPreferences" objectName: "TabletGeneralPreferences"

View file

@ -104,6 +104,10 @@ Rectangle {
if (loader.item.hasOwnProperty("gotoPreviousApp")) { if (loader.item.hasOwnProperty("gotoPreviousApp")) {
loader.item.gotoPreviousApp = true; loader.item.gotoPreviousApp = true;
} }
if (loader.item.hasOwnProperty("gotoPreviousAppFromScript")) {
loader.item.gotoPreviousAppFromScript = true;
}
}); });
} }
} }
@ -276,7 +280,7 @@ Rectangle {
} else { } else {
console.log("newSource is of unknown type!"); console.log("newSource is of unknown type!");
} }
screenChanged(type, newSource); screenChanged(type, newSource);
}); });
} }

View file

@ -30,6 +30,7 @@ Item {
property bool keyboardRaised: false property bool keyboardRaised: false
property bool punctuationMode: false property bool punctuationMode: false
property bool gotoPreviousApp: false property bool gotoPreviousApp: false
property bool gotoPreviousAppFromScript: false
property var tablet; property var tablet;
@ -72,7 +73,9 @@ Item {
function closeDialog() { function closeDialog() {
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
if (gotoPreviousApp) { if (gotoPreviousAppFromScript) {
dialog.parent.sendToScript("returnToPreviousApp");
} else if (gotoPreviousApp) {
tablet.returnToPreviousApp(); tablet.returnToPreviousApp();
} else { } else {
tablet.gotoHomeScreen(); tablet.gotoHomeScreen();

View file

@ -709,6 +709,8 @@ static const QString STATE_CAMERA_FIRST_PERSON = "CameraFirstPerson";
static const QString STATE_CAMERA_THIRD_PERSON = "CameraThirdPerson"; static const QString STATE_CAMERA_THIRD_PERSON = "CameraThirdPerson";
static const QString STATE_CAMERA_ENTITY = "CameraEntity"; static const QString STATE_CAMERA_ENTITY = "CameraEntity";
static const QString STATE_CAMERA_INDEPENDENT = "CameraIndependent"; static const QString STATE_CAMERA_INDEPENDENT = "CameraIndependent";
static const QString STATE_CAMERA_LOOK_AT = "CameraLookAt";
static const QString STATE_CAMERA_SELFIE = "CameraSelfie";
static const QString STATE_SNAP_TURN = "SnapTurn"; static const QString STATE_SNAP_TURN = "SnapTurn";
static const QString STATE_ADVANCED_MOVEMENT_CONTROLS = "AdvancedMovement"; static const QString STATE_ADVANCED_MOVEMENT_CONTROLS = "AdvancedMovement";
static const QString STATE_GROUNDED = "Grounded"; static const QString STATE_GROUNDED = "Grounded";
@ -925,7 +927,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
DependencyManager::set<AudioInjectorManager>(); DependencyManager::set<AudioInjectorManager>();
DependencyManager::set<MessagesClient>(); DependencyManager::set<MessagesClient>();
controller::StateController::setStateVariables({ { STATE_IN_HMD, STATE_CAMERA_FULL_SCREEN_MIRROR, 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_CAMERA_FIRST_PERSON, STATE_CAMERA_THIRD_PERSON, STATE_CAMERA_ENTITY, STATE_CAMERA_INDEPENDENT, STATE_CAMERA_LOOK_AT, STATE_CAMERA_SELFIE,
STATE_SNAP_TURN, STATE_ADVANCED_MOVEMENT_CONTROLS, STATE_GROUNDED, STATE_NAV_FOCUSED, STATE_SNAP_TURN, STATE_ADVANCED_MOVEMENT_CONTROLS, STATE_GROUNDED, STATE_NAV_FOCUSED,
STATE_PLATFORM_WINDOWS, STATE_PLATFORM_MAC, STATE_PLATFORM_ANDROID, STATE_LEFT_HAND_DOMINANT, STATE_RIGHT_HAND_DOMINANT, STATE_STRAFE_ENABLED } }); STATE_PLATFORM_WINDOWS, STATE_PLATFORM_MAC, STATE_PLATFORM_ANDROID, STATE_LEFT_HAND_DOMINANT, STATE_RIGHT_HAND_DOMINANT, STATE_STRAFE_ENABLED } });
DependencyManager::set<UserInputMapper>(); DependencyManager::set<UserInputMapper>();
@ -1061,6 +1063,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning())); setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning()));
setProperty(hifi::properties::CRASHED, _previousSessionCrashed); setProperty(hifi::properties::CRASHED, _previousSessionCrashed);
LogHandler::getInstance().setParent(this);
LogHandler::getInstance().setupRepeatedMessageFlusher();
{ {
const QStringList args = arguments(); const QStringList args = arguments();
@ -1872,6 +1877,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
_applicationStateDevice->setInputVariant(STATE_CAMERA_THIRD_PERSON, []() -> float { _applicationStateDevice->setInputVariant(STATE_CAMERA_THIRD_PERSON, []() -> float {
return qApp->getCamera().getMode() == CAMERA_MODE_THIRD_PERSON ? 1 : 0; return qApp->getCamera().getMode() == CAMERA_MODE_THIRD_PERSON ? 1 : 0;
}); });
_applicationStateDevice->setInputVariant(STATE_CAMERA_LOOK_AT, []() -> float {
return qApp->getCamera().getMode() == CAMERA_MODE_LOOK_AT ? 1 : 0;
});
_applicationStateDevice->setInputVariant(STATE_CAMERA_SELFIE, []() -> float {
return qApp->getCamera().getMode() == CAMERA_MODE_SELFIE ? 1 : 0;
});
_applicationStateDevice->setInputVariant(STATE_CAMERA_ENTITY, []() -> float { _applicationStateDevice->setInputVariant(STATE_CAMERA_ENTITY, []() -> float {
return qApp->getCamera().getMode() == CAMERA_MODE_ENTITY ? 1 : 0; return qApp->getCamera().getMode() == CAMERA_MODE_ENTITY ? 1 : 0;
}); });
@ -3586,7 +3597,8 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) {
// Always use the default eye position, not the actual head eye position. // Always use the default eye position, not the actual head eye position.
// Using the latter will cause the camera to wobble with idle animations, // Using the latter will cause the camera to wobble with idle animations,
// or with changes from the face tracker // or with changes from the face tracker
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { CameraMode mode = _myCamera.getMode();
if (mode == CAMERA_MODE_FIRST_PERSON) {
_thirdPersonHMDCameraBoomValid= false; _thirdPersonHMDCameraBoomValid= false;
if (isHMDMode()) { if (isHMDMode()) {
mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
@ -3597,10 +3609,8 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) {
_myCamera.setPosition(myAvatar->getDefaultEyePosition()); _myCamera.setPosition(myAvatar->getDefaultEyePosition());
_myCamera.setOrientation(myAvatar->getMyHead()->getHeadOrientation()); _myCamera.setOrientation(myAvatar->getMyHead()->getHeadOrientation());
} }
} } else if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) {
else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
if (isHMDMode()) { if (isHMDMode()) {
if (!_thirdPersonHMDCameraBoomValid) { if (!_thirdPersonHMDCameraBoomValid) {
const glm::vec3 CAMERA_OFFSET = glm::vec3(0.0f, 0.0f, 0.7f); const glm::vec3 CAMERA_OFFSET = glm::vec3(0.0f, 0.0f, 0.7f);
_thirdPersonHMDCameraBoom = cancelOutRollAndPitch(myAvatar->getHMDSensorOrientation()) * CAMERA_OFFSET; _thirdPersonHMDCameraBoom = cancelOutRollAndPitch(myAvatar->getHMDSensorOrientation()) * CAMERA_OFFSET;
@ -3615,22 +3625,28 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) {
_myCamera.setOrientation(glm::normalize(glmExtractRotation(worldCameraMat))); _myCamera.setOrientation(glm::normalize(glmExtractRotation(worldCameraMat)));
_myCamera.setPosition(extractTranslation(worldCameraMat)); _myCamera.setPosition(extractTranslation(worldCameraMat));
} } else {
else {
_thirdPersonHMDCameraBoomValid = false; _thirdPersonHMDCameraBoomValid = false;
if (mode == CAMERA_MODE_THIRD_PERSON) {
_myCamera.setOrientation(myAvatar->getHead()->getOrientation()); _myCamera.setOrientation(myAvatar->getHead()->getOrientation());
if (isOptionChecked(MenuOption::CenterPlayerInView)) { if (isOptionChecked(MenuOption::CenterPlayerInView)) {
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
+ _myCamera.getOrientation() * boomOffset);
} else {
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
+ myAvatar->getWorldOrientation() * boomOffset);
}
} else {
glm::quat lookAtRotation = myAvatar->getLookAtRotation();
if (mode == CAMERA_MODE_SELFIE) {
lookAtRotation = lookAtRotation * glm::angleAxis(PI, myAvatar->getWorldOrientation() * Vectors::UP);
}
_myCamera.setPosition(myAvatar->getDefaultEyePosition() _myCamera.setPosition(myAvatar->getDefaultEyePosition()
+ _myCamera.getOrientation() * boomOffset); + lookAtRotation * boomOffset);
} _myCamera.lookAt(myAvatar->getDefaultEyePosition());
else {
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
+ myAvatar->getWorldOrientation() * boomOffset);
} }
} }
} } else if (mode == CAMERA_MODE_MIRROR) {
else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
_thirdPersonHMDCameraBoomValid= false; _thirdPersonHMDCameraBoomValid= false;
if (isHMDMode()) { if (isHMDMode()) {
@ -3668,8 +3684,7 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) {
glm::vec3(0.0f, 0.0f, -1.0f) * myAvatar->getBoomLength() * _scaleMirror); glm::vec3(0.0f, 0.0f, -1.0f) * myAvatar->getBoomLength() * _scaleMirror);
} }
renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE;
} } else if (mode == CAMERA_MODE_ENTITY) {
else if (_myCamera.getMode() == CAMERA_MODE_ENTITY) {
_thirdPersonHMDCameraBoomValid= false; _thirdPersonHMDCameraBoomValid= false;
EntityItemPointer cameraEntity = _myCamera.getCameraEntityPointer(); EntityItemPointer cameraEntity = _myCamera.getCameraEntityPointer();
if (cameraEntity != nullptr) { if (cameraEntity != nullptr) {
@ -4387,12 +4402,12 @@ void Application::keyPressEvent(QKeyEvent* event) {
} }
case Qt::Key_2: { case Qt::Key_2: {
Menu* menu = Menu::getInstance(); Menu* menu = Menu::getInstance();
menu->triggerOption(MenuOption::FullscreenMirror); menu->triggerOption(MenuOption::SelfieCamera);
break; break;
} }
case Qt::Key_3: { case Qt::Key_3: {
Menu* menu = Menu::getInstance(); Menu* menu = Menu::getInstance();
menu->triggerOption(MenuOption::ThirdPerson); menu->triggerOption(MenuOption::LookAtCamera);
break; break;
} }
case Qt::Key_4: case Qt::Key_4:
@ -5484,7 +5499,7 @@ void Application::loadSettings() {
// dictated that we should be in first person // dictated that we should be in first person
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, isFirstPerson); Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, isFirstPerson);
Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !isFirstPerson); Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !isFirstPerson);
_myCamera.setMode((isFirstPerson) ? CAMERA_MODE_FIRST_PERSON : CAMERA_MODE_THIRD_PERSON); _myCamera.setMode((isFirstPerson) ? CAMERA_MODE_FIRST_PERSON : CAMERA_MODE_LOOK_AT);
cameraMenuChanged(); cameraMenuChanged();
auto inputs = pluginManager->getInputPlugins(); auto inputs = pluginManager->getInputPlugins();
@ -5842,11 +5857,16 @@ void Application::cycleCamera() {
} else if (menu->isOptionChecked(MenuOption::FirstPerson)) { } else if (menu->isOptionChecked(MenuOption::FirstPerson)) {
menu->setIsOptionChecked(MenuOption::FirstPerson, false); menu->setIsOptionChecked(MenuOption::FirstPerson, false);
menu->setIsOptionChecked(MenuOption::ThirdPerson, true); menu->setIsOptionChecked(MenuOption::LookAtCamera, true);
} else if (menu->isOptionChecked(MenuOption::ThirdPerson)) { } else if (menu->isOptionChecked(MenuOption::LookAtCamera)) {
menu->setIsOptionChecked(MenuOption::ThirdPerson, false); menu->setIsOptionChecked(MenuOption::LookAtCamera, false);
menu->setIsOptionChecked(MenuOption::SelfieCamera, true);
} else if (menu->isOptionChecked(MenuOption::SelfieCamera)) {
menu->setIsOptionChecked(MenuOption::SelfieCamera, false);
menu->setIsOptionChecked(MenuOption::FullscreenMirror, true); menu->setIsOptionChecked(MenuOption::FullscreenMirror, true);
} }
@ -5858,11 +5878,11 @@ void Application::cameraModeChanged() {
case CAMERA_MODE_FIRST_PERSON: case CAMERA_MODE_FIRST_PERSON:
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, true); Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, true);
break; break;
case CAMERA_MODE_THIRD_PERSON: case CAMERA_MODE_LOOK_AT:
Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, true); Menu::getInstance()->setIsOptionChecked(MenuOption::LookAtCamera, true);
break; break;
case CAMERA_MODE_MIRROR: case CAMERA_MODE_SELFIE:
Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, true); Menu::getInstance()->setIsOptionChecked(MenuOption::SelfieCamera, true);
break; break;
default: default:
// we don't have menu items for the others, so just leave it alone. // we don't have menu items for the others, so just leave it alone.
@ -5878,32 +5898,32 @@ void Application::changeViewAsNeeded(float boomLength) {
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON && boomLengthGreaterThanMinimum) { if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON && boomLengthGreaterThanMinimum) {
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, false); Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, false);
Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, true); Menu::getInstance()->setIsOptionChecked(MenuOption::LookAtCamera, true);
cameraMenuChanged(); cameraMenuChanged();
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON && !boomLengthGreaterThanMinimum) { } else if (_myCamera.getMode() == CAMERA_MODE_LOOK_AT && !boomLengthGreaterThanMinimum) {
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, true); Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, true);
Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, false); Menu::getInstance()->setIsOptionChecked(MenuOption::LookAtCamera, false);
cameraMenuChanged(); cameraMenuChanged();
} }
} }
void Application::cameraMenuChanged() { void Application::cameraMenuChanged() {
auto menu = Menu::getInstance(); auto menu = Menu::getInstance();
if (menu->isOptionChecked(MenuOption::FullscreenMirror)) { if (menu->isOptionChecked(MenuOption::FirstPerson)) {
if (!isHMDMode() && _myCamera.getMode() != CAMERA_MODE_MIRROR) {
_mirrorYawOffset = 0.0f;
_myCamera.setMode(CAMERA_MODE_MIRROR);
getMyAvatar()->reset(false, false, false); // to reset any active MyAvatar::FollowHelpers
getMyAvatar()->setBoomLength(MyAvatar::ZOOM_DEFAULT);
}
} else if (menu->isOptionChecked(MenuOption::FirstPerson)) {
if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON) { if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON) {
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON); _myCamera.setMode(CAMERA_MODE_FIRST_PERSON);
getMyAvatar()->setBoomLength(MyAvatar::ZOOM_MIN); getMyAvatar()->setBoomLength(MyAvatar::ZOOM_MIN);
} }
} else if (menu->isOptionChecked(MenuOption::ThirdPerson)) { } else if (menu->isOptionChecked(MenuOption::LookAtCamera)) {
if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) { if (_myCamera.getMode() != CAMERA_MODE_LOOK_AT) {
_myCamera.setMode(CAMERA_MODE_THIRD_PERSON); _myCamera.setMode(CAMERA_MODE_LOOK_AT);
if (getMyAvatar()->getBoomLength() == MyAvatar::ZOOM_MIN) {
getMyAvatar()->setBoomLength(MyAvatar::ZOOM_DEFAULT);
}
}
} else if (menu->isOptionChecked(MenuOption::SelfieCamera)) {
if (_myCamera.getMode() != CAMERA_MODE_SELFIE) {
_myCamera.setMode(CAMERA_MODE_SELFIE);
if (getMyAvatar()->getBoomLength() == MyAvatar::ZOOM_MIN) { if (getMyAvatar()->getBoomLength() == MyAvatar::ZOOM_MIN) {
getMyAvatar()->setBoomLength(MyAvatar::ZOOM_DEFAULT); getMyAvatar()->setBoomLength(MyAvatar::ZOOM_DEFAULT);
} }
@ -8994,9 +9014,9 @@ void Application::setDisplayPlugin(DisplayPluginPointer newDisplayPlugin) {
cameraMenuChanged(); cameraMenuChanged();
} }
// Remove the mirror camera option from menu if in HMD mode // Remove the selfie camera options from menu if in HMD mode
auto mirrorAction = menu->getActionForOption(MenuOption::FullscreenMirror); auto selfieAction = menu->getActionForOption(MenuOption::SelfieCamera);
mirrorAction->setVisible(!isHmd); selfieAction->setVisible(!isHmd);
} }
Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin"); Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin");

View file

@ -177,19 +177,19 @@ Menu::Menu() {
firstPersonAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup)); firstPersonAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup));
// View > Third Person // View > Look At
auto thirdPersonAction = cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash( auto lookAtAction = cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(
viewMenu, MenuOption::ThirdPerson, 0, viewMenu, MenuOption::LookAtCamera, 0,
false, qApp, SLOT(cameraMenuChanged()))); false, qApp, SLOT(cameraMenuChanged())));
thirdPersonAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup)); lookAtAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup));
// View > Mirror // View > Selfie
auto viewMirrorAction = cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash( auto selfieAction = cameraModeGroup->addAction(addCheckableActionToQMenuAndActionHash(
viewMenu, MenuOption::FullscreenMirror, 0, viewMenu, MenuOption::SelfieCamera, 0,
false, qApp, SLOT(cameraMenuChanged()))); false, qApp, SLOT(cameraMenuChanged())));
viewMirrorAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup)); selfieAction->setProperty(EXCLUSION_GROUP_KEY, QVariant::fromValue(cameraModeGroup));
viewMenu->addSeparator(); viewMenu->addSeparator();

View file

@ -129,6 +129,7 @@ namespace MenuOption {
const QString Login = "Login/Sign Up"; const QString Login = "Login/Sign Up";
const QString Log = "Log"; const QString Log = "Log";
const QString LogExtraTimings = "Log Extra Timing Details"; const QString LogExtraTimings = "Log Extra Timing Details";
const QString LookAtCamera = "Third Person";
const QString LowVelocityFilter = "Low Velocity Filter"; const QString LowVelocityFilter = "Low Velocity Filter";
const QString MeshVisible = "Draw Mesh"; const QString MeshVisible = "Draw Mesh";
const QString MuteEnvironment = "Mute Environment"; const QString MuteEnvironment = "Mute Environment";
@ -181,6 +182,7 @@ namespace MenuOption {
const QString RunTimingTests = "Run Timing Tests"; const QString RunTimingTests = "Run Timing Tests";
const QString ScriptedMotorControl = "Enable Scripted Motor Control"; const QString ScriptedMotorControl = "Enable Scripted Motor Control";
const QString ShowTrackedObjects = "Show Tracked Objects"; const QString ShowTrackedObjects = "Show Tracked Objects";
const QString SelfieCamera = "Selfie";
const QString SendWrongDSConnectVersion = "Send wrong DS connect version"; const QString SendWrongDSConnectVersion = "Send wrong DS connect version";
const QString SendWrongProtocolVersion = "Send wrong protocol version"; const QString SendWrongProtocolVersion = "Send wrong protocol version";
const QString SetHomeLocation = "Set Home Location"; const QString SetHomeLocation = "Set Home Location";
@ -201,7 +203,7 @@ namespace MenuOption {
const QString AnimStats = "Show Animation Stats"; const QString AnimStats = "Show Animation Stats";
const QString StopAllScripts = "Stop All Scripts"; const QString StopAllScripts = "Stop All Scripts";
const QString SuppressShortTimings = "Suppress Timings Less than 10ms"; const QString SuppressShortTimings = "Suppress Timings Less than 10ms";
const QString ThirdPerson = "Third Person"; const QString ThirdPerson = "Third Person Legacy";
const QString ThreePointCalibration = "3 Point Calibration"; const QString ThreePointCalibration = "3 Point Calibration";
const QString ThrottleFPSIfNotFocus = "Throttle FPS If Not Focus"; // FIXME - this value duplicated in Basic2DWindowOpenGLDisplayPlugin.cpp const QString ThrottleFPSIfNotFocus = "Throttle FPS If Not Focus"; // FIXME - this value duplicated in Basic2DWindowOpenGLDisplayPlugin.cpp
const QString ToggleHipsFollowing = "Toggle Hips Following"; const QString ToggleHipsFollowing = "Toggle Hips Following";

View file

@ -99,6 +99,10 @@ static const QString USER_RECENTER_MODEL_FORCE_STAND = QStringLiteral("ForceStan
static const QString USER_RECENTER_MODEL_AUTO = QStringLiteral("Auto"); static const QString USER_RECENTER_MODEL_AUTO = QStringLiteral("Auto");
static const QString USER_RECENTER_MODEL_DISABLE_HMD_LEAN = QStringLiteral("DisableHMDLean"); static const QString USER_RECENTER_MODEL_DISABLE_HMD_LEAN = QStringLiteral("DisableHMDLean");
const QString HEAD_BLENDING_NAME = "lookAroundAlpha";
const QString HEAD_ALPHA_NAME = "additiveBlendAlpha";
const float HEAD_ALPHA_BLENDING = 1.0f;
MyAvatar::SitStandModelType stringToUserRecenterModel(const QString& str) { MyAvatar::SitStandModelType stringToUserRecenterModel(const QString& str) {
if (str == USER_RECENTER_MODEL_FORCE_SIT) { if (str == USER_RECENTER_MODEL_FORCE_SIT) {
return MyAvatar::ForceSit; return MyAvatar::ForceSit;
@ -451,7 +455,7 @@ QByteArray MyAvatar::toByteArrayStateful(AvatarDataDetail dataDetail, bool dropF
_globalBoundingBoxDimensions.y = _characterController.getCapsuleHalfHeight(); _globalBoundingBoxDimensions.y = _characterController.getCapsuleHalfHeight();
_globalBoundingBoxDimensions.z = _characterController.getCapsuleRadius(); _globalBoundingBoxDimensions.z = _characterController.getCapsuleRadius();
_globalBoundingBoxOffset = _characterController.getCapsuleLocalOffset(); _globalBoundingBoxOffset = _characterController.getCapsuleLocalOffset();
if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) { if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) {
// fake the avatar position that is sent up to the AvatarMixer // fake the avatar position that is sent up to the AvatarMixer
glm::vec3 oldPosition = getWorldPosition(); glm::vec3 oldPosition = getWorldPosition();
setWorldPosition(getSkeletonPosition()); setWorldPosition(getSkeletonPosition());
@ -948,6 +952,13 @@ void MyAvatar::simulate(float deltaTime, bool inView) {
head->setPosition(headPosition); head->setPosition(headPosition);
head->setScale(getModelScale()); head->setScale(getModelScale());
head->simulate(deltaTime); head->simulate(deltaTime);
CameraMode mode = qApp->getCamera().getMode();
if (_scriptControlsHeadLookAt || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) {
updateHeadLookAt(deltaTime);
} else if (_headLookAtActive){
resetHeadLookAt();
_headLookAtActive = false;
}
} }
// Record avatars movements. // Record avatars movements.
@ -2610,7 +2621,7 @@ void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelN
glm::vec3 MyAvatar::getSkeletonPosition() const { glm::vec3 MyAvatar::getSkeletonPosition() const {
CameraMode mode = qApp->getCamera().getMode(); CameraMode mode = qApp->getCamera().getMode();
if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) { if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) {
// The avatar is rotated PI about the yAxis, so we have to correct for it // The avatar is rotated PI about the yAxis, so we have to correct for it
// to get the skeleton offset contribution in the world-frame. // to get the skeleton offset contribution in the world-frame.
const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f));
@ -3133,7 +3144,6 @@ void MyAvatar::initAnimGraph() {
} }
emit animGraphUrlChanged(graphUrl); emit animGraphUrlChanged(graphUrl);
_skeletonModel->getRig().initAnimGraph(graphUrl); _skeletonModel->getRig().initAnimGraph(graphUrl);
_currentAnimGraphUrl.set(graphUrl); _currentAnimGraphUrl.set(graphUrl);
connect(&(_skeletonModel->getRig()), SIGNAL(onLoadComplete()), this, SLOT(animGraphLoaded())); connect(&(_skeletonModel->getRig()), SIGNAL(onLoadComplete()), this, SLOT(animGraphLoaded()));
@ -3416,11 +3426,19 @@ void MyAvatar::setRotationThreshold(float angleRadians) {
} }
void MyAvatar::updateOrientation(float deltaTime) { void MyAvatar::updateOrientation(float deltaTime) {
// Smoothly rotate body with arrow keys // Smoothly rotate body with arrow keys
float targetSpeed = getDriveKey(YAW) * _yawSpeed; float targetSpeed = getDriveKey(YAW) * _yawSpeed;
CameraMode mode = qApp->getCamera().getMode();
bool computeLookAt = (mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) && isReadyForPhysics() && !qApp->isHMDMode();
if (computeLookAt) {
// For "Look At" and "Selfie" camera modes we also smooth the yaw rotation from right-click mouse movement.
float speedFromDeltaYaw = deltaTime > FLT_EPSILON ? getDriveKey(DELTA_YAW) / deltaTime : 0.0f;
speedFromDeltaYaw *= _yawSpeed / YAW_SPEED_DEFAULT;
targetSpeed += speedFromDeltaYaw;
}
if (targetSpeed != 0.0f) { if (targetSpeed != 0.0f) {
const float ROTATION_RAMP_TIMESCALE = 0.1f; const float ROTATION_RAMP_TIMESCALE = 0.5f;
float blend = deltaTime / ROTATION_RAMP_TIMESCALE; float blend = deltaTime / ROTATION_RAMP_TIMESCALE;
if (blend > 1.0f) { if (blend > 1.0f) {
blend = 1.0f; blend = 1.0f;
@ -3441,10 +3459,10 @@ void MyAvatar::updateOrientation(float deltaTime) {
} }
} }
float totalBodyYaw = _bodyYawDelta * deltaTime; float totalBodyYaw = _bodyYawDelta * deltaTime;
if (!computeLookAt) {
// Rotate directly proportional to delta yaw and delta pitch from right-click mouse movement. // Rotate directly proportional to delta yaw and delta pitch from right-click mouse movement.
totalBodyYaw += getDriveKey(DELTA_YAW) * _yawSpeed / YAW_SPEED_DEFAULT; totalBodyYaw += getDriveKey(DELTA_YAW) * _yawSpeed / YAW_SPEED_DEFAULT;
}
// Comfort Mode: If you press any of the left/right rotation drive keys or input, you'll // Comfort Mode: If you press any of the left/right rotation drive keys or input, you'll
// get an instantaneous 15 degree turn. If you keep holding the key down you'll get another // get an instantaneous 15 degree turn. If you keep holding the key down you'll get another
// snap turn every half second. // snap turn every half second.
@ -3453,7 +3471,6 @@ void MyAvatar::updateOrientation(float deltaTime) {
totalBodyYaw += getDriveKey(STEP_YAW); totalBodyYaw += getDriveKey(STEP_YAW);
snapTurn = true; snapTurn = true;
} }
// Use head/HMD roll to turn while flying, but not when standing still. // Use head/HMD roll to turn while flying, but not when standing still.
if (qApp->isHMDMode() && getCharacterController()->getState() == CharacterController::State::Hover && _hmdRollControlEnabled && hasDriveInput()) { if (qApp->isHMDMode() && getCharacterController()->getState() == CharacterController::State::Hover && _hmdRollControlEnabled && hasDriveInput()) {
@ -3488,7 +3505,60 @@ void MyAvatar::updateOrientation(float deltaTime) {
// update body orientation by movement inputs // update body orientation by movement inputs
glm::quat initialOrientation = getOrientationOutbound(); glm::quat initialOrientation = getOrientationOutbound();
setWorldOrientation(getWorldOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, totalBodyYaw, 0.0f)))); glm::vec3 eyesPosition = getDefaultEyePosition();
const float FPS = 60.0f;
float timeScale = deltaTime * FPS;
bool faceForward = false;
if (!computeLookAt) {
setWorldOrientation(getWorldOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, totalBodyYaw, 0.0f))));
_lookAtCameraTarget = eyesPosition + getWorldOrientation() * Vectors::FRONT;
_lookAtYaw = getWorldOrientation();
_lookAtPitch = Quaternions::IDENTITY;
} else {
// Compute new look at vectors
if (totalBodyYaw != 0.0f) {
_lookAtYaw = _lookAtYaw * glm::quat(glm::radians(glm::vec3(0.0f, totalBodyYaw, 0.0f)));
}
float pitchIncrement = getDriveKey(PITCH) * _pitchSpeed * deltaTime
+ getDriveKey(DELTA_PITCH) * _pitchSpeed / PITCH_SPEED_DEFAULT;
if (pitchIncrement != 0.0f) {
glm::quat _previousLookAtPitch = _lookAtPitch;
_lookAtPitch = _lookAtPitch * glm::quat(glm::radians(glm::vec3(pitchIncrement, 0.0f, 0.0f)));
// Limit the camera horizontal pitch
float MAX_LOOK_AT_PITCH_DEGREES = 80.0f;
float pitchFromHorizont = glm::degrees(angleBetween(getLookAtRotation() * Vectors::FRONT, _lookAtYaw * Vectors::FRONT));
if (pitchFromHorizont > MAX_LOOK_AT_PITCH_DEGREES) {
_lookAtPitch = _previousLookAtPitch;
}
}
bool isMovingFwdBwd = getDriveKey(TRANSLATE_Z) != 0.0f;
bool isMovingSideways = getDriveKey(TRANSLATE_X) != 0.0f;
bool isRotatingWhileSeated = isMovingSideways && _characterController.getSeated();
faceForward = isMovingFwdBwd || (isMovingSideways && !isRotatingWhileSeated);
// Blend the avatar orientation with the camera look at if moving forward.
if (faceForward || _shouldTurnToFaceCamera) {
const float REORIENT_FORWARD_BLEND = 0.25f;
const float REORIENT_TURN_BLEND = 0.03f;
const float DIAGONAL_TURN_BLEND = 0.02f;
float blend = (_shouldTurnToFaceCamera ? REORIENT_TURN_BLEND : REORIENT_FORWARD_BLEND) * timeScale;
if (blend > 1.0f) {
blend = 1.0f;
}
glm::quat faceRotation = _lookAtYaw;
if (isMovingFwdBwd && isMovingSideways) {
// Reorient avatar to face camera diagonal
blend = DIAGONAL_TURN_BLEND;
float turnSign = getDriveKey(TRANSLATE_Z) < 0.0f ? -1.0f : 1.0f;
turnSign = getDriveKey(TRANSLATE_X) > 0.0f ? -turnSign : turnSign;
faceRotation = _lookAtYaw * glm::angleAxis(turnSign * 0.25f * PI, Vectors::UP);
}
setWorldOrientation(glm::slerp(getWorldOrientation(), faceRotation, blend));
} else if (isRotatingWhileSeated) {
float rotatingWhileSeatedYaw = -getDriveKey(TRANSLATE_X) * _yawSpeed * deltaTime;
setWorldOrientation(getWorldOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, rotatingWhileSeatedYaw, 0.0f))));
}
}
if (snapTurn) { if (snapTurn) {
// Whether or not there is an existing smoothing going on, just reset the smoothing timer and set the starting position as the avatar's current position, then smooth to the new position. // Whether or not there is an existing smoothing going on, just reset the smoothing timer and set the starting position as the avatar's current position, then smooth to the new position.
@ -3509,9 +3579,74 @@ void MyAvatar::updateOrientation(float deltaTime) {
head->setBaseYaw(YAW(euler)); head->setBaseYaw(YAW(euler));
head->setBasePitch(PITCH(euler)); head->setBasePitch(PITCH(euler));
head->setBaseRoll(ROLL(euler)); head->setBaseRoll(ROLL(euler));
} else if (computeLookAt) {
// Reset head orientation before applying the blending offset
head->setBaseYaw(0.0f);
head->setBasePitch(0.0f);
head->setBaseRoll(0.0f);
glm::vec3 cameraVector = (faceForward ? _lookAtPitch * getWorldOrientation() : getLookAtRotation()) * Vectors::FRONT;
glm::vec3 cameraYawVector = _lookAtYaw * Vectors::FRONT;
// Cap and attenuate head's lookat pitch angle
const float START_LOOKING_UP_DEGREES = 5.0f;
const float START_LOOKING_DOWN_DEGREES = 15.0f;
const float MAX_UP_DOWN_DEGREES = 90.0f;
glm::vec3 avatarVectorUp = getWorldOrientation() * Vectors::UP;
float upDownDot = glm::dot(cameraVector, avatarVectorUp);
float upDownDegrees = MAX_UP_DOWN_DEGREES - glm::degrees(acosf(abs(upDownDot)));
float lookAttenuation = 0.0f;
if (upDownDot <= 0.0f) {
if (upDownDegrees > START_LOOKING_DOWN_DEGREES) {
lookAttenuation = (upDownDegrees - START_LOOKING_DOWN_DEGREES) / (MAX_UP_DOWN_DEGREES - START_LOOKING_DOWN_DEGREES);
}
} else {
if (upDownDegrees > START_LOOKING_UP_DEGREES) {
lookAttenuation = (upDownDegrees - START_LOOKING_UP_DEGREES) / (MAX_UP_DOWN_DEGREES - START_LOOKING_UP_DEGREES);
}
}
glm::vec3 avatarVectorFront = getWorldOrientation() * Vectors::FRONT;
float frontBackDot = glm::dot(cameraYawVector, avatarVectorFront);
glm::vec3 avatarVectorRight = getWorldOrientation() * Vectors::RIGHT;
float leftRightDot = glm::dot(cameraYawVector, avatarVectorRight);
const float REORIENT_ANGLE = 65.0f;
const float TRIGGER_REORIENT_ANGLE = 45.0f;
glm::vec3 ajustedYawVector = cameraYawVector;
if (frontBackDot < 0.0f) {
ajustedYawVector = (leftRightDot < 0.0f ? -avatarVectorRight : avatarVectorRight);
cameraVector = (ajustedYawVector * _lookAtPitch) * Vectors::FRONT;
if (frontBackDot < -glm::sin(glm::radians(TRIGGER_REORIENT_ANGLE))) {
_shouldTurnToFaceCamera = true;
}
} else if (frontBackDot > glm::sin(glm::radians(REORIENT_ANGLE))) {
_shouldTurnToFaceCamera = false;
}
cameraVector = glm::mix(cameraVector, ajustedYawVector, 1.0f - lookAttenuation);
// Calculate the camera target point.
glm::vec3 targetPoint = eyesPosition + glm::normalize(cameraVector);
const float LOOKAT_MIX_ALPHA = 0.25f;
if (getDriveKey(TRANSLATE_Y) == 0.0f) {
// Approximate the head's look at vector to the camera look at vector with some delay.
float mixAlpha = LOOKAT_MIX_ALPHA * timeScale;
if (mixAlpha > 1.0f) {
mixAlpha = 1.0f;
}
_lookAtCameraTarget = glm::mix(_lookAtCameraTarget, targetPoint, mixAlpha);
} else {
_lookAtCameraTarget = targetPoint;
}
_headLookAtActive = true;
} else { } else {
head->setBaseYaw(0.0f); head->setBaseYaw(0.0f);
head->setBasePitch(getHead()->getBasePitch() + getDriveKey(PITCH) * _pitchSpeed * deltaTime head->setBasePitch(getHead()->getBasePitch() + getDriveKey(PITCH) * _pitchSpeed * deltaTime
+ getDriveKey(DELTA_PITCH) * _pitchSpeed / PITCH_SPEED_DEFAULT); + getDriveKey(DELTA_PITCH) * _pitchSpeed / PITCH_SPEED_DEFAULT);
head->setBaseRoll(0.0f); head->setBaseRoll(0.0f);
} }
@ -3543,7 +3678,7 @@ float MyAvatar::calculateGearedSpeed(const float driveKey) {
glm::vec3 MyAvatar::scaleMotorSpeed(const glm::vec3 forward, const glm::vec3 right) { glm::vec3 MyAvatar::scaleMotorSpeed(const glm::vec3 forward, const glm::vec3 right) {
float stickFullOn = 0.85f; float stickFullOn = 0.85f;
auto zSpeed = getDriveKey(TRANSLATE_Z); auto zSpeed = getDriveKey(TRANSLATE_Z);
auto xSpeed = getDriveKey(TRANSLATE_X); auto xSpeed = !_characterController.getSeated() ? getDriveKey(TRANSLATE_X) : 0.0f;
glm::vec3 direction; glm::vec3 direction;
if (!useAdvancedMovementControls() && qApp->isHMDMode()) { if (!useAdvancedMovementControls() && qApp->isHMDMode()) {
// Walking disabled in settings. // Walking disabled in settings.
@ -3581,6 +3716,10 @@ glm::vec3 MyAvatar::scaleMotorSpeed(const glm::vec3 forward, const glm::vec3 rig
} else { } else {
// Desktop mode. // Desktop mode.
direction = (zSpeed * forward) + (xSpeed * right); direction = (zSpeed * forward) + (xSpeed * right);
if (qApp->getCamera().getMode() == CAMERA_MODE_LOOK_AT && zSpeed != 0.0f && xSpeed != 0.0f){
direction = (zSpeed * forward);
}
auto length = glm::length(direction); auto length = glm::length(direction);
if (length > EPSILON) { if (length > EPSILON) {
direction /= length; direction /= length;
@ -5236,9 +5375,13 @@ glm::quat MyAvatar::getOrientationForAudio() {
glm::quat result; glm::quat result;
switch (_audioListenerMode) { switch (_audioListenerMode) {
case AudioListenerMode::FROM_HEAD: case AudioListenerMode::FROM_HEAD: {
result = getHead()->getFinalOrientationInWorldFrame(); // Using the camera's orientation instead, when the current mode is controlling the avatar's head.
CameraMode mode = qApp->getCamera().getMode();
bool headFollowsCamera = mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE;
result = headFollowsCamera ? qApp->getCamera().getOrientation() : getHead()->getFinalOrientationInWorldFrame();
break; break;
}
case AudioListenerMode::FROM_CAMERA: case AudioListenerMode::FROM_CAMERA:
result = qApp->getCamera().getOrientation(); result = qApp->getCamera().getOrientation();
break; break;
@ -6334,7 +6477,6 @@ void MyAvatar::sendPacket(const QUuid& entityID) const {
void MyAvatar::setSitDriveKeysStatus(bool enabled) { void MyAvatar::setSitDriveKeysStatus(bool enabled) {
const std::vector<DriveKeys> DISABLED_DRIVE_KEYS_DURING_SIT = { const std::vector<DriveKeys> DISABLED_DRIVE_KEYS_DURING_SIT = {
DriveKeys::TRANSLATE_X,
DriveKeys::TRANSLATE_Y, DriveKeys::TRANSLATE_Y,
DriveKeys::TRANSLATE_Z, DriveKeys::TRANSLATE_Z,
DriveKeys::STEP_TRANSLATE_X, DriveKeys::STEP_TRANSLATE_X,
@ -6512,3 +6654,70 @@ void MyAvatar::updateLookAtPosition(FaceTracker* faceTracker, Camera& myCamera)
getHead()->setLookAtPosition(lookAtSpot); getHead()->setLookAtPosition(lookAtSpot);
} }
void MyAvatar::resetHeadLookAt() {
if (_skeletonModelLoaded) {
_skeletonModel->getRig().setDirectionalBlending(HEAD_BLENDING_NAME, glm::vec3(),
HEAD_ALPHA_NAME, HEAD_ALPHA_BLENDING);
}
}
void MyAvatar::updateHeadLookAt(float deltaTime) {
if (_skeletonModelLoaded) {
glm::vec3 lookAtTarget = _scriptControlsHeadLookAt ? _lookAtScriptTarget : _lookAtCameraTarget;
glm::vec3 avatarXVector = glm::normalize(getWorldOrientation() * Vectors::UNIT_X);
glm::vec3 avatarYVector = glm::normalize(getWorldOrientation() * Vectors::UNIT_Y);
glm::vec3 avatarZVector = glm::normalize(getWorldOrientation() * Vectors::UNIT_Z);
glm::vec3 headToTargetVector = lookAtTarget - getDefaultEyePosition();
if (glm::length(headToTargetVector) > EPSILON) {
headToTargetVector = glm::normalize(headToTargetVector);
} else {
// The target point is the avatar head
return;
}
float xDot = glm::dot(avatarXVector, headToTargetVector);
float yDot = glm::dot(avatarYVector, headToTargetVector);
float zDot = glm::dot(avatarZVector, headToTargetVector);
// Force the head to look at one of the sides when the look at point is behind the avatar
if (zDot > 0.0f && xDot != 0.0f) {
//xDot /= fabsf(xDot);
}
// Make sure dot products are in range to avoid acosf returning NaN
xDot = glm::min(glm::max(xDot, -1.0f), 1.0f);
yDot = glm::min(glm::max(yDot, -1.0f), 1.0f);
float xAngle = acosf(xDot);
float yAngle = acosf(yDot);
// xBlend and yBlend are the values from -1.0 to 1.0 that set the directional blending.
// We compute them using the angles (0 to PI/2) => (1.0 to 0.0) and (PI/2 to PI) => (0.0 to -1.0)
float xBlend = -(xAngle - 0.5f * PI) / (0.5f * PI);
float yBlend = -(yAngle - 0.5f * PI) / (0.5f * PI);
glm::vec3 lookAtBlend = glm::vec3(xBlend, yBlend, 0.0f);
_skeletonModel->getRig().setDirectionalBlending(HEAD_BLENDING_NAME, lookAtBlend,
HEAD_ALPHA_NAME, HEAD_ALPHA_BLENDING);
if (_scriptControlsHeadLookAt) {
_scriptHeadControlTimer += deltaTime;
if (_scriptHeadControlTimer > MAX_LOOK_AT_TIME_SCRIPT_CONTROL) {
_scriptHeadControlTimer = 0.0f;
_scriptControlsHeadLookAt = false;
_lookAtCameraTarget = _lookAtScriptTarget;
}
}
}
}
void MyAvatar::setHeadLookAt(const glm::vec3& lookAtTarget) {
if (QThread::currentThread() != thread()) {
BLOCKING_INVOKE_METHOD(this, "setHeadLookAt",
Q_ARG(const glm::vec3&, lookAtTarget));
return;
}
_headLookAtActive = true;
_scriptControlsHeadLookAt = true;
_scriptHeadControlTimer = 0.0f;
_lookAtScriptTarget = lookAtTarget;
}

View file

@ -1749,6 +1749,24 @@ public:
glm::vec3 getNextPosition() { return _goToPending ? _goToPosition : getWorldPosition(); } glm::vec3 getNextPosition() { return _goToPending ? _goToPosition : getWorldPosition(); }
void prepareAvatarEntityDataForReload(); void prepareAvatarEntityDataForReload();
/**jsdoc
* Turn the avatar's head until it faces the target point within the 90/-90 degree range.
* Once this method is called, API calls will have full control of the head for a limited time.
* If this method is not called for two seconds, the engine will regain control of the head.
* @function MyAvatar.setHeadLookAt
* @param {Vec3} lookAtTarget - The target point in world coordinates.
*/
Q_INVOKABLE void setHeadLookAt(const glm::vec3& lookAtTarget);
/**jsdoc
* Returns the current head look at target point in world coordinates.
* @function MyAvatar.getHeadLookAt
* @returns {Vec3} Default position between your avatar's eyes in world coordinates.
*/
Q_INVOKABLE glm::vec3 getHeadLookAt() { return _lookAtCameraTarget; }
glm::quat getLookAtRotation() { return _lookAtYaw * _lookAtPitch; }
/**jsdoc /**jsdoc
* Creates a new grab that grabs an entity. * Creates a new grab that grabs an entity.
* @function MyAvatar.grab * @function MyAvatar.grab
@ -2626,6 +2644,21 @@ private:
glm::vec3 _trackedHeadPosition; glm::vec3 _trackedHeadPosition;
const float MAX_LOOK_AT_TIME_SCRIPT_CONTROL = 2.0f;
glm::quat _lookAtPitch;
glm::quat _lookAtYaw;
glm::vec3 _lookAtCameraTarget;
glm::vec3 _lookAtScriptTarget;
bool _headLookAtActive { false };
bool _shouldTurnToFaceCamera { false };
bool _scriptControlsHeadLookAt { false };
float _scriptHeadControlTimer { 0.0f };
// LookAt camera data
float _selfieTriggerAngle { 55.0f };
float _frontLookAtSpeed { 0.15f };
float _backLookAtSpeed { 0.25f };
Setting::Handle<float> _realWorldFieldOfView; Setting::Handle<float> _realWorldFieldOfView;
Setting::Handle<bool> _useAdvancedMovementControls; Setting::Handle<bool> _useAdvancedMovementControls;
Setting::Handle<bool> _showPlayArea; Setting::Handle<bool> _showPlayArea;
@ -2650,6 +2683,8 @@ private:
void initHeadBones(); void initHeadBones();
void initAnimGraph(); void initAnimGraph();
void initFlowFromFST(); void initFlowFromFST();
void updateHeadLookAt(float deltaTime);
void resetHeadLookAt();
// Avatar Preferences // Avatar Preferences
QUrl _fullAvatarURLFromPreferences; QUrl _fullAvatarURLFromPreferences;

View file

@ -1658,7 +1658,7 @@ void Rig::updateHead(bool headEnabled, bool hipsEnabled, const AnimPose& headPos
_animVars.set("splineIKEnabled", false); _animVars.set("splineIKEnabled", false);
_animVars.unset("headPosition"); _animVars.unset("headPosition");
_animVars.set("headRotation", headPose.rot()); _animVars.set("headRotation", headPose.rot());
_animVars.set("headType", (int)IKTarget::Type::RotationOnly); _animVars.set("headType", (int)IKTarget::Type::Unknown);
} }
} }
} }
@ -2645,3 +2645,8 @@ float Rig::getUnscaledEyeHeight() const {
return DEFAULT_AVATAR_EYE_HEIGHT; return DEFAULT_AVATAR_EYE_HEIGHT;
} }
} }
void Rig::setDirectionalBlending(const QString& targetName, const glm::vec3& blendingTarget, const QString& alphaName, float alpha) {
_animVars.set(targetName, blendingTarget);
_animVars.set(alphaName, alpha);
}

View file

@ -254,6 +254,7 @@ public:
int getOverrideJointCount() const; int getOverrideJointCount() const;
bool getFlowActive() const; bool getFlowActive() const;
bool getNetworkGraphActive() const; bool getNetworkGraphActive() const;
void setDirectionalBlending(const QString& targetName, const glm::vec3& blendingTarget, const QString& alphaName, float alpha);
signals: signals:
void onLoadComplete(); void onLoadComplete();

View file

@ -210,7 +210,6 @@ qint64 writeStringToStream(const QString& string, QDataStream& stream) {
int64_t AudioInjector::injectNextFrame() { int64_t AudioInjector::injectNextFrame() {
if (stateHas(AudioInjectorState::NetworkInjectionFinished)) { if (stateHas(AudioInjectorState::NetworkInjectionFinished)) {
qCDebug(audio) << "AudioInjector::injectNextFrame called but AudioInjector has finished and was not restarted. Returning.";
return NEXT_FRAME_DELTA_ERROR_OR_FINISHED; return NEXT_FRAME_DELTA_ERROR_OR_FINISHED;
} }

View file

@ -481,11 +481,15 @@ QUuid EntityScriptingInterface::addEntityInternal(const EntityItemProperties& pr
_activityTracking.addedEntityCount++; _activityTracking.addedEntityCount++;
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
const auto sessionID = nodeList->getSessionUUID(); auto sessionID = nodeList->getSessionUUID();
EntityItemProperties propertiesWithSimID = properties; EntityItemProperties propertiesWithSimID = properties;
propertiesWithSimID.setEntityHostType(entityHostType); propertiesWithSimID.setEntityHostType(entityHostType);
if (entityHostType == entity::HostType::AVATAR) { if (entityHostType == entity::HostType::AVATAR) {
if (sessionID.isNull()) {
// null sessionID is unacceptable in this case
sessionID = AVATAR_SELF_ID;
}
propertiesWithSimID.setOwningAvatarID(sessionID); propertiesWithSimID.setOwningAvatarID(sessionID);
} else if (entityHostType == entity::HostType::LOCAL) { } else if (entityHostType == entity::HostType::LOCAL) {
// For now, local entities are always collisionless // For now, local entities are always collisionless
@ -801,7 +805,7 @@ QUuid EntityScriptingInterface::editEntity(const QUuid& id, const EntityItemProp
return; return;
} }
if (entity->isAvatarEntity() && entity->getOwningAvatarID() != sessionID) { if (entity->isAvatarEntity() && entity->getOwningAvatarID() != sessionID && entity->getOwningAvatarID() != AVATAR_SELF_ID) {
// don't edit other avatar's avatarEntities // don't edit other avatar's avatarEntities
properties = EntityItemProperties(); properties = EntityItemProperties();
return; return;

View file

@ -32,14 +32,6 @@ LogHandler& LogHandler::getInstance() {
return staticInstance; return staticInstance;
} }
LogHandler::LogHandler() {
// make sure we setup the repeated message flusher, but do it on the LogHandler thread
QMetaObject::invokeMethod(this, "setupRepeatedMessageFlusher");
}
LogHandler::~LogHandler() {
}
const char* stringForLogType(LogMsgType msgType) { const char* stringForLogType(LogMsgType msgType) {
switch (msgType) { switch (msgType) {
case LogInfo: case LogInfo:

View file

@ -54,12 +54,11 @@ public:
int newRepeatedMessageID(); int newRepeatedMessageID();
void printRepeatedMessage(int messageID, LogMsgType type, const QMessageLogContext& context, const QString &message); void printRepeatedMessage(int messageID, LogMsgType type, const QMessageLogContext& context, const QString &message);
private slots:
void setupRepeatedMessageFlusher(); void setupRepeatedMessageFlusher();
private: private:
LogHandler(); LogHandler() = default;
~LogHandler(); ~LogHandler() = default;
void flushRepeatedMessages(); void flushRepeatedMessages();

View file

@ -35,6 +35,18 @@
* your avatar.</td> * your avatar.</td>
* </tr> * </tr>
* <tr> * <tr>
* <td><strong>Look&nbsp;At</strong></td>
* <td><code>"look&nbsp;at"</code></td>
* <td>The camera is positioned behind your avatar. The camera moves and rotates independently from your avatar.
* The avatar's head always faces the camera look at point.</td>
* </tr>
* <tr>
* <td><strong>Selfie</strong></td>
* <td><code>"selfie"</code></td>
* <td>The camera is positioned in front of your avatar. The camera moves and rotates independently from your avatar.
* Your avatar's head is always facing the camera.</td>
* </tr>
* <tr>
* <td><strong>Mirror</strong></td> * <td><strong>Mirror</strong></td>
* <td><code>"mirror"</code></td> * <td><code>"mirror"</code></td>
* <td>The camera is positioned such that you are looking directly at your avatar. The camera moves and rotates with your * <td>The camera is positioned such that you are looking directly at your avatar. The camera moves and rotates with your
@ -67,6 +79,10 @@ CameraMode stringToMode(const QString& mode) {
return CAMERA_MODE_INDEPENDENT; return CAMERA_MODE_INDEPENDENT;
} else if (mode == "entity") { } else if (mode == "entity") {
return CAMERA_MODE_ENTITY; return CAMERA_MODE_ENTITY;
} else if (mode == "look at") {
return CAMERA_MODE_LOOK_AT;
} else if (mode == "selfie") {
return CAMERA_MODE_SELFIE;
} }
return CAMERA_MODE_NULL; return CAMERA_MODE_NULL;
} }
@ -82,6 +98,10 @@ QString modeToString(CameraMode mode) {
return "independent"; return "independent";
} else if (mode == CAMERA_MODE_ENTITY) { } else if (mode == CAMERA_MODE_ENTITY) {
return "entity"; return "entity";
} else if (mode == CAMERA_MODE_LOOK_AT) {
return "look at";
} else if (mode == CAMERA_MODE_SELFIE) {
return "selfie";
} }
return "unknown"; return "unknown";
} }

View file

@ -23,6 +23,8 @@ enum CameraMode
CAMERA_MODE_MIRROR, CAMERA_MODE_MIRROR,
CAMERA_MODE_INDEPENDENT, CAMERA_MODE_INDEPENDENT,
CAMERA_MODE_ENTITY, CAMERA_MODE_ENTITY,
CAMERA_MODE_LOOK_AT,
CAMERA_MODE_SELFIE,
NUM_CAMERA_MODES NUM_CAMERA_MODES
}; };
@ -182,7 +184,7 @@ private:
void recompose(); void recompose();
void decompose(); void decompose();
CameraMode _mode{ CAMERA_MODE_THIRD_PERSON }; CameraMode _mode{ CAMERA_MODE_LOOK_AT };
glm::mat4 _transform; glm::mat4 _transform;
glm::mat4 _projection; glm::mat4 _projection;

View file

@ -592,12 +592,51 @@ void TabletProxy::gotoMenuScreen(const QString& submenu) {
} }
} }
void TabletProxy::loadQMLOnTop(const QVariant& path) { void TabletProxy::loadQMLOnTopImpl(const QVariant& path, bool localSafeContext) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "loadQMLOnTop", Q_ARG(QVariant, path)); qCWarning(uiLogging) << __FUNCTION__ << "may not be called directly by scripts";
return; return;
} }
QObject* root = nullptr;
if (!_toolbarMode && _qmlTabletRoot) {
root = _qmlTabletRoot;
} else if (_toolbarMode && _desktopWindow) {
root = _desktopWindow->asQuickItem();
}
if (root) {
if (localSafeContext) {
hifi::scripting::setLocalAccessSafeThread(true);
}
QMetaObject::invokeMethod(root, "loadQMLOnTop", Q_ARG(const QVariant&, path));
QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true)));
if (_toolbarMode && _desktopWindow) {
QMetaObject::invokeMethod(root, "setResizable", Q_ARG(const QVariant&, QVariant(false)));
}
hifi::scripting::setLocalAccessSafeThread(false);
} else {
qCDebug(uiLogging) << "tablet cannot load QML because _qmlTabletRoot is null";
}
}
void TabletProxy::loadQMLOnTop(const QVariant& path) {
bool localSafeContext = hifi::scripting::isLocalAccessSafeThread();
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "loadQMLOnTopImpl", Q_ARG(QVariant, path), Q_ARG(bool, localSafeContext));
return;
}
loadQMLOnTopImpl(path, localSafeContext);
}
void TabletProxy::returnToPreviousAppImpl(bool localSafeContext) {
if (QThread::currentThread() != thread()) {
qCWarning(uiLogging) << __FUNCTION__ << "may not be called directly by scripts";
return;
}
QObject* root = nullptr; QObject* root = nullptr;
if (!_toolbarMode && _qmlTabletRoot) { if (!_toolbarMode && _qmlTabletRoot) {
root = _qmlTabletRoot; root = _qmlTabletRoot;
@ -606,35 +645,26 @@ void TabletProxy::loadQMLOnTop(const QVariant& path) {
} }
if (root) { if (root) {
QMetaObject::invokeMethod(root, "loadQMLOnTop", Q_ARG(const QVariant&, path)); if (localSafeContext) {
QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true))); hifi::scripting::setLocalAccessSafeThread(true);
if (_toolbarMode && _desktopWindow) {
QMetaObject::invokeMethod(root, "setResizable", Q_ARG(const QVariant&, QVariant(false)));
} }
QMetaObject::invokeMethod(root, "returnToPreviousApp");
QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true)));
hifi::scripting::setLocalAccessSafeThread(false);
} else { } else {
qCDebug(uiLogging) << "tablet cannot load QML because _qmlTabletRoot is null"; qCDebug(uiLogging) << "tablet cannot load QML because _qmlTabletRoot is null";
} }
} }
void TabletProxy::returnToPreviousApp() { void TabletProxy::returnToPreviousApp() {
bool localSafeContext = hifi::scripting::isLocalAccessSafeThread();
qDebug() << "TabletProxy::returnToPreviousApp -> localSafeContext: " << localSafeContext;
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "returnToPreviousApp"); QMetaObject::invokeMethod(this, "returnToPreviousAppImpl", Q_ARG(bool, localSafeContext));
return; return;
} }
QObject* root = nullptr; returnToPreviousAppImpl(localSafeContext);
if (!_toolbarMode && _qmlTabletRoot) {
root = _qmlTabletRoot;
} else if (_toolbarMode && _desktopWindow) {
root = _desktopWindow->asQuickItem();
}
if (root) {
QMetaObject::invokeMethod(root, "returnToPreviousApp");
QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true)));
} else {
qCDebug(uiLogging) << "tablet cannot load QML because _qmlTabletRoot is null";
}
} }
void TabletProxy::loadQMLSource(const QVariant& path, bool resizable) { void TabletProxy::loadQMLSource(const QVariant& path, bool resizable) {
@ -940,8 +970,6 @@ void TabletProxy::sendToQml(const QVariant& msg) {
} }
} }
OffscreenQmlSurface* TabletProxy::getTabletSurface() { OffscreenQmlSurface* TabletProxy::getTabletSurface() {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
OffscreenQmlSurface* result = nullptr; OffscreenQmlSurface* result = nullptr;

View file

@ -298,10 +298,26 @@ public:
*/ */
Q_INVOKABLE void loadQMLSourceImpl(const QVariant& path, bool resizable, bool localSafeContext); Q_INVOKABLE void loadQMLSourceImpl(const QVariant& path, bool resizable, bool localSafeContext);
/**jsdoc
* Internal function, do not call from scripts
* @function TabletProxy#loadHTMLSourceImpl
*/
Q_INVOKABLE void loadHTMLSourceImpl(const QVariant& url, const QString& injectJavaScriptUrl, bool localSafeContext); Q_INVOKABLE void loadHTMLSourceImpl(const QVariant& url, const QString& injectJavaScriptUrl, bool localSafeContext);
/**jsdoc
* Internal function, do not call from scripts
* @function TabletProxy#loadHTMLSourceImpl
*/
Q_INVOKABLE void loadHTMLSourceImpl(const QString& url, const QString& injectedJavaScriptUrl, bool loadOtherBase, bool localSafeContext); Q_INVOKABLE void loadHTMLSourceImpl(const QString& url, const QString& injectedJavaScriptUrl, bool loadOtherBase, bool localSafeContext);
/**jsdoc
* Internal function, do not call from scripts
* @function TabletProxy#returnToPreviousAppImpl
*/
Q_INVOKABLE void returnToPreviousAppImpl(bool localSafeContext);
Q_INVOKABLE void loadQMLOnTopImpl(const QVariant& path, bool localSafeContext);
// FIXME: This currently relies on a script initializing the tablet (hence the bool denoting success); // FIXME: This currently relies on a script initializing the tablet (hence the bool denoting success);
// it should be initialized internally so it cannot fail // it should be initialized internally so it cannot fail

View file

@ -10,6 +10,8 @@
// //
#include "ViewTask.h" #include "ViewTask.h"
#include <Profile.h>
using namespace workload; using namespace workload;
@ -181,8 +183,11 @@ void ControlViews::regulateViews(workload::Views& outViews, const workload::Timi
auto loopDuration = timings[5]; auto loopDuration = timings[5];
regionBackFronts[workload::Region::R1] = regionRegulators[workload::Region::R1].run(loopDuration, timings[2] + timings[3], regionBackFronts[workload::Region::R1]); regionBackFronts[workload::Region::R1] = regionRegulators[workload::Region::R1].run(loopDuration, timings[2] + timings[3], regionBackFronts[workload::Region::R1]);
PROFILE_COUNTER(workload, "R1Front", { { "R1", regionBackFronts[workload::Region::R1].y} } );
regionBackFronts[workload::Region::R2] = regionRegulators[workload::Region::R2].run(loopDuration, timings[2] + timings[3], regionBackFronts[workload::Region::R2]); regionBackFronts[workload::Region::R2] = regionRegulators[workload::Region::R2].run(loopDuration, timings[2] + timings[3], regionBackFronts[workload::Region::R2]);
PROFILE_COUNTER(workload, "R2Front", { { "R2", regionBackFronts[workload::Region::R2].y } } );
regionBackFronts[workload::Region::R3] = regionRegulators[workload::Region::R3].run(loopDuration, timings[4], regionBackFronts[workload::Region::R3]); regionBackFronts[workload::Region::R3] = regionRegulators[workload::Region::R3].run(loopDuration, timings[4], regionBackFronts[workload::Region::R3]);
PROFILE_COUNTER(workload, "R3Front", { { "R3", regionBackFronts[workload::Region::R3].y } } );
enforceRegionContainment(); enforceRegionContainment();
for (auto& outView : outViews) { for (auto& outView : outViews) {

View file

@ -65,6 +65,7 @@ function onMessage(message) {
// 2. Although we currently use a single image, we would like to take snapshot, a selfie, a 360 etc. all at the // 2. Although we currently use a single image, we would like to take snapshot, a selfie, a 360 etc. all at the
// same time, show the user all of them, and have the user deselect any that they do not want to share. // same time, show the user all of them, and have the user deselect any that they do not want to share.
// So we'll ultimately be receiving a set of objects, perhaps with different post processing for each. // So we'll ultimately be receiving a set of objects, perhaps with different post processing for each.
if (message.type !== "snapshot") { if (message.type !== "snapshot") {
return; return;
} }
@ -85,7 +86,7 @@ function onMessage(message) {
image_data: imageData, image_data: imageData,
canShare: canShare canShare: canShare
}); });
}); });
} else { } else {
ui.sendMessage({ ui.sendMessage({
type: "snapshot", type: "snapshot",
@ -274,6 +275,14 @@ var POLAROID_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/alan/dev/Test/sna
var POLAROID_RATE_LIMIT_MS = 1000; var POLAROID_RATE_LIMIT_MS = 1000;
var polaroidPrintingIsRateLimited = false; var polaroidPrintingIsRateLimited = false;
// force call the gotoPreviousApp on script thead to load snapshot html page.
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
tablet.fromQml.connect(function(message) {
if (message === 'returnToPreviousApp') {
tablet.returnToPreviousApp();
}
});
function printToPolaroid(image_url) { function printToPolaroid(image_url) {
// Rate-limit printing // Rate-limit printing
if (polaroidPrintingIsRateLimited) { if (polaroidPrintingIsRateLimited) {