Merge branch 'instancing' of github.com:highfidelity/hifi into instancing_gltf

This commit is contained in:
sabrina-shanman 2019-10-16 14:03:01 -07:00
commit 0c3e81f52f
59 changed files with 1687 additions and 471 deletions

View file

@ -0,0 +1,36 @@
From 7638b7c5a659dceb4e580ae87d4d60b00847ef94 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emil=20Nord=C3=A9n?= <emilnorden@yahoo.se>
Date: Sat, 4 May 2019 08:38:53 +0200
Subject: [PATCH] fixed build on latest version of clang
---
src/Bullet3Common/b3Vector3.h | 2 +-
src/LinearMath/btVector3.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/Bullet3Common/b3Vector3.h b/src/Bullet3Common/b3Vector3.h
index 56e6c13311..a70d68d6e1 100644
--- a/src/Bullet3Common/b3Vector3.h
+++ b/src/Bullet3Common/b3Vector3.h
@@ -36,7 +36,7 @@ subject to the following restrictions:
#pragma warning(disable : 4556) // value of intrinsic immediate argument '4294967239' is out of range '0 - 255'
#endif
-#define B3_SHUFFLE(x, y, z, w) ((w) << 6 | (z) << 4 | (y) << 2 | (x))
+#define B3_SHUFFLE(x, y, z, w) (((w) << 6 | (z) << 4 | (y) << 2 | (x)) & 0xff)
//#define b3_pshufd_ps( _a, _mask ) (__m128) _mm_shuffle_epi32((__m128i)(_a), (_mask) )
#define b3_pshufd_ps(_a, _mask) _mm_shuffle_ps((_a), (_a), (_mask))
#define b3_splat3_ps(_a, _i) b3_pshufd_ps((_a), B3_SHUFFLE(_i, _i, _i, 3))
diff --git a/src/LinearMath/btVector3.h b/src/LinearMath/btVector3.h
index 61fd8d1e46..d65ed9808d 100644
--- a/src/LinearMath/btVector3.h
+++ b/src/LinearMath/btVector3.h
@@ -36,7 +36,7 @@ subject to the following restrictions:
#pragma warning(disable : 4556) // value of intrinsic immediate argument '4294967239' is out of range '0 - 255'
#endif
-#define BT_SHUFFLE(x, y, z, w) ((w) << 6 | (z) << 4 | (y) << 2 | (x))
+#define BT_SHUFFLE(x, y, z, w) (((w) << 6 | (z) << 4 | (y) << 2 | (x)) & 0xff)
//#define bt_pshufd_ps( _a, _mask ) (__m128) _mm_shuffle_epi32((__m128i)(_a), (_mask) )
#define bt_pshufd_ps(_a, _mask) _mm_shuffle_ps((_a), (_a), (_mask))
#define bt_splat3_ps(_a, _i) bt_pshufd_ps((_a), BT_SHUFFLE(_i, _i, _i, 3))

View file

@ -27,6 +27,7 @@ vcpkg_from_github(
REF ab8f16961e19a86ee20c6a1d61f662392524cc77 REF ab8f16961e19a86ee20c6a1d61f662392524cc77
SHA512 927742db29867517283d45e475f0c534a9a57e165cae221f26e08e88057253a1682ac9919b2dc547b9cf388ba0b931b175623461d44f28c9184796ba90b1ed55 SHA512 927742db29867517283d45e475f0c534a9a57e165cae221f26e08e88057253a1682ac9919b2dc547b9cf388ba0b931b175623461d44f28c9184796ba90b1ed55
HEAD_REF master HEAD_REF master
PATCHES "bullet-git-fix-build-clang-8.patch"
) )
vcpkg_configure_cmake( vcpkg_configure_cmake(

View file

@ -5251,7 +5251,7 @@
{ {
"easingType": "easeInOutQuad", "easingType": "easeInOutQuad",
"id": "idle", "id": "idle",
"interpDuration": 20, "interpDuration": 15,
"interpTarget": 20, "interpTarget": 20,
"interpType": "evaluateBoth", "interpType": "evaluateBoth",
"transitions": [ "transitions": [
@ -5383,8 +5383,8 @@
{ {
"easingType": "easeInOutQuad", "easingType": "easeInOutQuad",
"id": "idleSettle", "id": "idleSettle",
"interpDuration": 15, "interpDuration": 13,
"interpTarget": 15, "interpTarget": 14,
"interpType": "snapshotPrev", "interpType": "snapshotPrev",
"transitions": [ "transitions": [
{ {
@ -5477,7 +5477,7 @@
"transitions": [ "transitions": [
{ {
"state": "idleSettle", "state": "idleSettle",
"var": "isNotInput" "var": "isNotInputSlow"
}, },
{ {
"state": "WALKBWD", "state": "WALKBWD",
@ -5541,7 +5541,7 @@
"transitions": [ "transitions": [
{ {
"state": "idleSettle", "state": "idleSettle",
"var": "isNotInput" "var": "isNotInputSlow"
}, },
{ {
"state": "WALKFWD", "state": "WALKFWD",
@ -5605,7 +5605,7 @@
"transitions": [ "transitions": [
{ {
"state": "idleSettle", "state": "idleSettle",
"var": "isNotInput" "var": "isNotInputSlow"
}, },
{ {
"state": "WALKFWD", "state": "WALKFWD",
@ -5669,7 +5669,7 @@
"transitions": [ "transitions": [
{ {
"state": "idleSettle", "state": "idleSettle",
"var": "isNotInput" "var": "isNotInputSlow"
}, },
{ {
"state": "WALKFWD", "state": "WALKFWD",

View file

@ -9,6 +9,7 @@
// //
import QtQuick 2.10 import QtQuick 2.10
import QtQuick.Layouts 1.3
import "../simplifiedConstants" as SimplifiedConstants import "../simplifiedConstants" as SimplifiedConstants
import "../simplifiedControls" as SimplifiedControls import "../simplifiedControls" as SimplifiedControls
import "./components" as AvatarAppComponents import "./components" as AvatarAppComponents
@ -79,7 +80,11 @@ Rectangle {
errorText.text = "There was a problem while retrieving your inventory. " + errorText.text = "There was a problem while retrieving your inventory. " +
"Please try closing and re-opening the Avatar app.\n\nInventory status: " + result.status + "\nMessage: " + result.message; "Please try closing and re-opening the Avatar app.\n\nInventory status: " + result.status + "\nMessage: " + result.message;
} else if (result.data && result.data.assets && result.data.assets.length === 0 && avatarAppInventoryModel.count === 0) { } else if (result.data && result.data.assets && result.data.assets.length === 0 && avatarAppInventoryModel.count === 0) {
errorText.text = "You have not created any avatars yet! Create an avatar with the Avatar Creator, then close and re-open the Avatar App." emptyInventoryContainer.visible = true;
}
if (Settings.getValue("simplifiedUI/debugFTUE", 0) === 4) {
emptyInventoryContainer.visible = true;
} }
avatarAppInventoryModel.handlePage(result.status !== "success" && result.message, result); avatarAppInventoryModel.handlePage(result.status !== "success" && result.message, result);
@ -140,8 +145,95 @@ Rectangle {
anchors.rightMargin: 24 anchors.rightMargin: 24
} }
Item {
id: emptyInventoryContainer
visible: false
anchors.top: displayNameHeader.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
Flickable {
id: emptyInventoryFlickable
anchors.fill: parent
contentWidth: parent.width
contentHeight: emptyInventoryLayout.height
clip: true
ColumnLayout {
id: emptyInventoryLayout
anchors.top: parent.top
anchors.left: parent.left
anchors.leftMargin: 26
anchors.right: parent.right
anchors.rightMargin: 26
spacing: 0
HifiStylesUit.GraphikSemiBold {
text: "Stand out from the crowd!"
Layout.preferredWidth: parent.width
Layout.preferredHeight: paintedHeight
Layout.topMargin: 16
size: 28
color: simplifiedUI.colors.text.white
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.Wrap
}
HifiStylesUit.GraphikRegular {
text: "Create your custom avatar."
Layout.preferredWidth: parent.width
Layout.preferredHeight: paintedHeight
Layout.topMargin: 2
size: 18
wrapMode: Text.Wrap
color: simplifiedUI.colors.text.white
horizontalAlignment: Text.AlignHCenter
}
Image {
id: avatarImage;
source: "images/avatarProfilePic.png"
Layout.preferredWidth: parent.width
Layout.preferredHeight: 450
Layout.alignment: Qt.AlignHCenter
mipmap: true
fillMode: Image.PreserveAspectFit
}
Image {
source: "images/qrCode.jpg"
Layout.preferredWidth: 190
Layout.preferredHeight: 190
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: -160
mipmap: true
fillMode: Image.PreserveAspectFit
}
HifiStylesUit.GraphikSemiBold {
text: "Scan for Mobile App"
Layout.preferredWidth: parent.width
Layout.preferredHeight: paintedHeight
Layout.topMargin: 12
size: 28
color: simplifiedUI.colors.text.white
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.Wrap
}
}
}
SimplifiedControls.VerticalScrollBar {
parent: emptyInventoryFlickable
}
}
Item { Item {
id: avatarInfoTextContainer id: avatarInfoTextContainer
visible: !emptyInventoryContainer.visible
width: parent.implicitWidth width: parent.implicitWidth
height: childrenRect.height height: childrenRect.height
anchors.top: displayNameHeader.bottom anchors.top: displayNameHeader.bottom
@ -164,7 +256,7 @@ Rectangle {
id: yourAvatarsSubtitle id: yourAvatarsSubtitle
text: "These are the avatars that you've created and uploaded via the Avatar Creator." text: "These are the avatars that you've created and uploaded via the Avatar Creator."
width: parent.width width: parent.width
wrapMode: Text.WordWrap wrapMode: Text.Wrap
anchors.top: yourAvatarsTitle.bottom anchors.top: yourAvatarsTitle.bottom
anchors.topMargin: 6 anchors.topMargin: 6
verticalAlignment: TextInput.AlignVCenter verticalAlignment: TextInput.AlignVCenter
@ -208,9 +300,10 @@ Rectangle {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
visible: !emptyInventoryContainer.visible
AnimatedImage { AnimatedImage {
visible: !inventoryContentsList.visible && !errorText.visible visible: !(inventoryContentsList.visible || errorText.visible)
anchors.centerIn: parent anchors.centerIn: parent
width: 72 width: 72
height: width height: width
@ -271,6 +364,8 @@ Rectangle {
return; return;
} }
} }
root.avatarPreviewUrl = "../../images/defaultAvatar.svg";
} }
function fromScript(message) { function fromScript(message) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

View file

@ -54,8 +54,8 @@ Rectangle {
if ((MyAvatar.skeletonModelURL.indexOf("defaultAvatar") > -1 || MyAvatar.skeletonModelURL.indexOf("fst") === -1) && if ((MyAvatar.skeletonModelURL.indexOf("defaultAvatar") > -1 || MyAvatar.skeletonModelURL.indexOf("fst") === -1) &&
topBarInventoryModel.count > 0) { topBarInventoryModel.count > 0) {
Settings.setValue("simplifiedUI/alreadyAutoSelectedAvatar", true); Settings.setValue("simplifiedUI/alreadyAutoSelectedAvatarFromInventory", true);
MyAvatar.useFullAvatarURL = topBarInventoryModel.get(0).download_url; MyAvatar.useFullAvatarURL(topBarInventoryModel.get(0).download_url);
} }
} }
} }
@ -71,7 +71,7 @@ Rectangle {
if (isLoggedIn) { if (isLoggedIn) {
Commerce.getWalletStatus(); Commerce.getWalletStatus();
} else { } else {
// Show some error to the user // Show some error to the user in the UI?
} }
} }
@ -113,12 +113,68 @@ Rectangle {
topBarInventoryModel.getNextPage(); topBarInventoryModel.getNextPage();
} else { } else {
inventoryFullyReceived = true; inventoryFullyReceived = true;
var scriptExecutionCount = Settings.getValue("simplifiedUI/SUIScriptExecutionCount");
var currentAvatarURL = MyAvatar.skeletonModelURL;
var currentAvatarURLContainsDefaultAvatar = currentAvatarURL.indexOf("defaultAvatar") > -1;
var currentAvatarURLContainsFST = currentAvatarURL.indexOf("fst") > -1;
var currentAvatarURLContainsSimplifiedAvatar = currentAvatarURL.indexOf("simplifiedAvatar") > -1;
var alreadyAutoSelectedAvatarFromInventory = Settings.getValue("simplifiedUI/alreadyAutoSelectedAvatarFromInventory", false);
var userHasValidAvatarInInventory = topBarInventoryModel.count > 0 &&
topBarInventoryModel.get(0).download_url.indexOf(".fst") > -1;
var simplifiedAvatarPrefix = "https://content.highfidelity.com/Experiences/Releases/simplifiedUI/simplifiedFTUE/avatars/simplifiedAvatar_";
var simplifiedAvatarColors = ["Blue", "Cyan", "Green", "Magenta", "Red"];
var simplifiedAvatarSuffix = "/avatar.fst";
// If we have an avatar in our inventory AND we haven't already auto-selected an avatar... // Use `Settings.setValue("simplifiedUI/debugFTUE", 0);` to turn off FTUE Debug Mode.
if ((!Settings.getValue("simplifiedUI/alreadyAutoSelectedAvatar", false) || // Use `Settings.setValue("simplifiedUI/debugFTUE", 1);` to debug FTUE Screen 1.
MyAvatar.skeletonModelURL.indexOf("defaultAvatar") > -1 || MyAvatar.skeletonModelURL.indexOf("fst") === -1) && topBarInventoryModel.count > 0) { // Use `Settings.setValue("simplifiedUI/debugFTUE", 2);` to debug FTUE Screen 2.
Settings.setValue("simplifiedUI/alreadyAutoSelectedAvatar", true); // Use `Settings.setValue("simplifiedUI/debugFTUE", 3);` to debug FTUE Screen 3.
MyAvatar.skeletonModelURL = topBarInventoryModel.get(0).download_url; // Use `Settings.setValue("simplifiedUI/debugFTUE", 4);` to force the UI to show what would happen if the user had an empty Inventory.
var debugFTUE = Settings.getValue("simplifiedUI/debugFTUE", 0);
if (debugFTUE === 1 || debugFTUE === 2) {
scriptExecutionCount = 1;
currentAvatarURLContainsDefaultAvatar = true;
if (debugFTUE === 1) {
userHasValidAvatarInInventory = false;
currentAvatarURLContainsSimplifiedAvatar = false;
}
} else if (debugFTUE === 3) {
scriptExecutionCount = 2;
currentAvatarURLContainsDefaultAvatar = false;
currentAvatarURLContainsSimplifiedAvatar = true;
}
// If we have never auto-selected and the user is still using a default avatar or if the current avatar is not valid (fst), or if
// the current avatar is the old default (Woody), use top avatar from inventory or one of the new defaults.
// If the current avatar URL is invalid, OR the user is using the "default avatar" (Woody)...
if (!currentAvatarURLContainsFST || currentAvatarURLContainsDefaultAvatar) {
// If the user has a valid avatar in their inventory...
if (userHasValidAvatarInInventory) {
// ...use the first avatar in the user's inventory.
MyAvatar.useFullAvatarURL(topBarInventoryModel.get(0).download_url);
Settings.setValue("simplifiedUI/alreadyAutoSelectedAvatarFromInventory", true);
// Else if the user isn't wearing a "Simplified Avatar"
} else if (!currentAvatarURLContainsSimplifiedAvatar) {
// ...assign to the user a new "Simplified Avatar" (i.e. a simple avatar of random color)
var avatarColor = simplifiedAvatarColors[Math.floor(Math.random() * simplifiedAvatarColors.length)];
var simplifiedAvatarModelURL = simplifiedAvatarPrefix + avatarColor + simplifiedAvatarSuffix;
MyAvatar.useFullAvatarURL(simplifiedAvatarModelURL);
currentAvatarURLContainsSimplifiedAvatar = true;
}
}
if (scriptExecutionCount === 1) {
sendToScript({
"source": "SimplifiedTopBar.qml",
"method": "displayInitialLaunchWindow"
});
} else if (scriptExecutionCount === 2 && currentAvatarURLContainsSimplifiedAvatar) {
sendToScript({
"source": "SimplifiedTopBar.qml",
"method": "displaySecondLaunchWindow"
});
} }
} }
} }
@ -556,7 +612,7 @@ Rectangle {
} }
function updatePreviewUrl() { function updatePreviewUrl() {
var previewUrl = ""; var previewUrl = "";
var downloadUrl = ""; var downloadUrl = "";
for (var i = 0; i < topBarInventoryModel.count; ++i) { for (var i = 0; i < topBarInventoryModel.count; ++i) {
@ -570,6 +626,8 @@ Rectangle {
return; return;
} }
} }
avatarButtonImage.source = "../images/defaultAvatar.svg";
} }

View file

@ -3618,7 +3618,7 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) {
_myCamera.setPosition(extractTranslation(camMat)); _myCamera.setPosition(extractTranslation(camMat));
_myCamera.setOrientation(glmExtractRotation(camMat)); _myCamera.setOrientation(glmExtractRotation(camMat));
} else { } else {
_myCamera.setPosition(myAvatar->getLookAtPivotPoint()); _myCamera.setPosition(myAvatar->getCameraEyesPosition(deltaTime));
_myCamera.setOrientation(myAvatar->getLookAtRotation()); _myCamera.setOrientation(myAvatar->getLookAtRotation());
} }
} else if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) { } else if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) {

View file

@ -152,7 +152,7 @@ static int triggerReactionNameToIndex(const QString& reactionName) {
} }
static int beginEndReactionNameToIndex(const QString& reactionName) { static int beginEndReactionNameToIndex(const QString& reactionName) {
assert(NUM_AVATAR_BEGIN_END_REACTIONS == TRIGGER_REACTION_NAMES.size()); assert(NUM_AVATAR_BEGIN_END_REACTIONS == BEGIN_END_REACTION_NAMES.size());
return BEGIN_END_REACTION_NAMES.indexOf(reactionName); return BEGIN_END_REACTION_NAMES.indexOf(reactionName);
} }
@ -2719,7 +2719,7 @@ void MyAvatar::updateMotors() {
if (_characterController.getState() == CharacterController::State::Hover || if (_characterController.getState() == CharacterController::State::Hover ||
_characterController.computeCollisionMask() == BULLET_COLLISION_MASK_COLLISIONLESS) { _characterController.computeCollisionMask() == BULLET_COLLISION_MASK_COLLISIONLESS) {
CameraMode mode = qApp->getCamera().getMode(); CameraMode mode = qApp->getCamera().getMode();
if (mode == CAMERA_MODE_FIRST_PERSON || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) { if (!qApp->isHMDMode() && (mode == CAMERA_MODE_FIRST_PERSON || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE)) {
motorRotation = getLookAtRotation(); motorRotation = getLookAtRotation();
} else { } else {
motorRotation = getMyHead()->getHeadOrientation(); motorRotation = getMyHead()->getHeadOrientation();
@ -6812,6 +6812,50 @@ glm::vec3 MyAvatar::getLookAtPivotPoint() {
return yAxisEyePosition; return yAxisEyePosition;
} }
glm::vec3 MyAvatar::getCameraEyesPosition(float deltaTime) {
glm::vec3 defaultEyesPosition = getLookAtPivotPoint();
if (isFlying()) {
return defaultEyesPosition;
}
glm::vec3 avatarFrontVector = getWorldOrientation() * Vectors::FRONT;
glm::vec3 avatarUpVector = getWorldOrientation() * Vectors::UP;
// Compute the offset between the default and real eye positions.
glm::vec3 defaultEyesToEyesVector = getHead()->getEyePosition() - defaultEyesPosition;
float FRONT_OFFSET_IDLE_MULTIPLIER = 2.0f;
float FRONT_OFFSET_JUMP_MULTIPLIER = 1.5f;
float frontOffset = FRONT_OFFSET_IDLE_MULTIPLIER * glm::length(defaultEyesPosition - getDefaultEyePosition());
// Looking down will aproximate move the camera forward to meet the real eye position
float mixAlpha = glm::dot(_lookAtPitch * Vectors::FRONT, -avatarUpVector);
// When jumping the camera should follow the real eye on the Y coordenate
float upOffset = 0.0f;
if (isJumping() || _characterController.getState() == CharacterController::State::Takeoff) {
upOffset = glm::dot(defaultEyesToEyesVector, avatarUpVector);
frontOffset = glm::dot(defaultEyesToEyesVector, avatarFrontVector) * FRONT_OFFSET_JUMP_MULTIPLIER;
mixAlpha = 1.0f;
} else {
// Limit the range effect from 45 to 90 degrees
const float HEAD_OFFSET_DOT_THRESHOLD = 0.7f; // 45 degrees aprox
mixAlpha = mixAlpha < HEAD_OFFSET_DOT_THRESHOLD ? 0.0f : (mixAlpha - HEAD_OFFSET_DOT_THRESHOLD) /
(1.0f - HEAD_OFFSET_DOT_THRESHOLD);
}
const float FPS = 60.0f;
float timeScale = deltaTime * FPS;
frontOffset = frontOffset < 0.0f ? 0.0f : mixAlpha * frontOffset;
glm::vec3 cameraOffset = upOffset * Vectors::UP + frontOffset * Vectors::FRONT;
const float TAU = 0.1f;
_cameraEyesOffset = _cameraEyesOffset + (cameraOffset - _cameraEyesOffset) * min(1.0f, TAU * timeScale);
glm::vec3 estimatedCameraPosition = defaultEyesPosition + getWorldOrientation() * _cameraEyesOffset;
return estimatedCameraPosition;
}
bool MyAvatar::isJumping() {
return (_characterController.getState() == CharacterController::State::InAir ||
_characterController.getState() == CharacterController::State::Takeoff) && !isFlying();
}
bool MyAvatar::setPointAt(const glm::vec3& pointAtTarget) { bool MyAvatar::setPointAt(const glm::vec3& pointAtTarget) {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
bool result = false; bool result = false;

View file

@ -1919,6 +1919,8 @@ public:
bool getIsJointOverridden(int jointIndex) const; bool getIsJointOverridden(int jointIndex) const;
glm::vec3 getLookAtPivotPoint(); glm::vec3 getLookAtPivotPoint();
glm::vec3 getCameraEyesPosition(float deltaTime);
bool isJumping();
public slots: public slots:
@ -2973,6 +2975,8 @@ private:
// used to prevent character from jumping after endSit is called. // used to prevent character from jumping after endSit is called.
bool _endSitKeyPressComplete { false }; bool _endSitKeyPressComplete { false };
glm::vec3 _cameraEyesOffset;
}; };
QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode); QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);

View file

@ -52,6 +52,21 @@ static const QVariantMap DOCK_AREA {
{ "RIGHT", DockArea::RIGHT } { "RIGHT", DockArea::RIGHT }
}; };
/**jsdoc
* The possible "relative position anchors" of an <code>InteractiveWindow</code>. Used when defining the `relativePosition` property of an `InteractiveWindow`.
* @typedef {object} InteractiveWindow.RelativePositionAnchors
* @property {InteractiveWindow.RelativePositionAnchor} TOP_LEFT - Specifies that the `relativePosition` of the `InteractiveWindow` will be offset from the top left of the Interface window.
* @property {InteractiveWindow.RelativePositionAnchor} TOP_RIGHT - Specifies that the `relativePosition` of the `InteractiveWindow` will be offset from the top right of the Interface window.
* @property {InteractiveWindow.RelativePositionAnchor} BOTTOM_RIGHT - Specifies that the `relativePosition` of the `InteractiveWindow` will be offset from the bottom right of the Interface window.
* @property {InteractiveWindow.RelativePositionAnchor} BOTTOM_LEFT - Specifies that the `relativePosition` of the `InteractiveWindow` will be offset from the bottom left of the Interface window.
*/
static const QVariantMap RELATIVE_POSITION_ANCHOR {
{ "TOP_LEFT", RelativePositionAnchor::TOP_LEFT },
{ "TOP_RIGHT", RelativePositionAnchor::TOP_RIGHT },
{ "BOTTOM_RIGHT", RelativePositionAnchor::BOTTOM_RIGHT },
{ "BOTTOM_LEFT", RelativePositionAnchor::BOTTOM_LEFT }
};
DesktopScriptingInterface::DesktopScriptingInterface(QObject* parent, bool restricted) DesktopScriptingInterface::DesktopScriptingInterface(QObject* parent, bool restricted)
: QObject(parent), _restricted(restricted) { } : QObject(parent), _restricted(restricted) { }
@ -99,6 +114,10 @@ QVariantMap DesktopScriptingInterface::getDockArea() {
return DOCK_AREA; return DOCK_AREA;
} }
QVariantMap DesktopScriptingInterface::getRelativePositionAnchor() {
return RELATIVE_POSITION_ANCHOR;
}
void DesktopScriptingInterface::setHUDAlpha(float alpha) { void DesktopScriptingInterface::setHUDAlpha(float alpha) {
qApp->getApplicationCompositor().setAlpha(alpha); qApp->getApplicationCompositor().setAlpha(alpha);
} }

View file

@ -42,6 +42,9 @@
* @property {InteractiveWindow.DockAreas} DockArea - The possible docking locations of an {@link InteractiveWindow}: top, * @property {InteractiveWindow.DockAreas} DockArea - The possible docking locations of an {@link InteractiveWindow}: top,
* bottom, left, or right of the Interface window. * bottom, left, or right of the Interface window.
* <em>Read-only.</em> * <em>Read-only.</em>
* @property {InteractiveWindow.RelativePositionAnchors} RelativePositionAnchor - The possible "relative position anchors" for an {@link InteractiveWindow}: top left,
* top right, bottom right, or bottom left of the Interface window.
* <em>Read-only.</em>
*/ */
class DesktopScriptingInterface : public QObject, public Dependency { class DesktopScriptingInterface : public QObject, public Dependency {
Q_OBJECT Q_OBJECT
@ -50,6 +53,7 @@ class DesktopScriptingInterface : public QObject, public Dependency {
Q_PROPERTY(QVariantMap PresentationMode READ getPresentationMode CONSTANT FINAL) Q_PROPERTY(QVariantMap PresentationMode READ getPresentationMode CONSTANT FINAL)
Q_PROPERTY(QVariantMap DockArea READ getDockArea CONSTANT FINAL) Q_PROPERTY(QVariantMap DockArea READ getDockArea CONSTANT FINAL)
Q_PROPERTY(QVariantMap RelativePositionAnchor READ getRelativePositionAnchor CONSTANT FINAL)
Q_PROPERTY(int ALWAYS_ON_TOP READ flagAlwaysOnTop CONSTANT FINAL) Q_PROPERTY(int ALWAYS_ON_TOP READ flagAlwaysOnTop CONSTANT FINAL)
Q_PROPERTY(int CLOSE_BUTTON_HIDES READ flagCloseButtonHides CONSTANT FINAL) Q_PROPERTY(int CLOSE_BUTTON_HIDES READ flagCloseButtonHides CONSTANT FINAL)
@ -106,7 +110,7 @@ private:
Q_INVOKABLE InteractiveWindowPointer createWindowOnThread(const QString& sourceUrl, const QVariantMap& properties, QThread* targetThread); Q_INVOKABLE InteractiveWindowPointer createWindowOnThread(const QString& sourceUrl, const QVariantMap& properties, QThread* targetThread);
static QVariantMap getDockArea(); static QVariantMap getDockArea();
static QVariantMap getRelativePositionAnchor();
Q_INVOKABLE static QVariantMap getPresentationMode(); Q_INVOKABLE static QVariantMap getPresentationMode();
const bool _restricted; const bool _restricted;
}; };

View file

@ -39,6 +39,9 @@ static const char* const ADDITIONAL_FLAGS_PROPERTY = "additionalFlags";
static const char* const OVERRIDE_FLAGS_PROPERTY = "overrideFlags"; static const char* const OVERRIDE_FLAGS_PROPERTY = "overrideFlags";
static const char* const SOURCE_PROPERTY = "source"; static const char* const SOURCE_PROPERTY = "source";
static const char* const TITLE_PROPERTY = "title"; static const char* const TITLE_PROPERTY = "title";
static const char* const RELATIVE_POSITION_ANCHOR_PROPERTY = "relativePositionAnchor";
static const char* const RELATIVE_POSITION_PROPERTY = "relativePosition";
static const char* const IS_FULL_SCREEN_WINDOW = "isFullScreenWindow";
static const char* const POSITION_PROPERTY = "position"; static const char* const POSITION_PROPERTY = "position";
static const char* const INTERACTIVE_WINDOW_POSITION_PROPERTY = "interactiveWindowPosition"; static const char* const INTERACTIVE_WINDOW_POSITION_PROPERTY = "interactiveWindowPosition";
static const char* const SIZE_PROPERTY = "size"; static const char* const SIZE_PROPERTY = "size";
@ -112,6 +115,14 @@ void InteractiveWindow::forwardKeyReleaseEvent(int key, int modifiers) {
QCoreApplication::postEvent(QCoreApplication::instance(), event); QCoreApplication::postEvent(QCoreApplication::instance(), event);
} }
void InteractiveWindow::onMainWindowGeometryChanged(QRect geometry) {
if (_isFullScreenWindow) {
repositionAndResizeFullScreenWindow();
} else {
setPositionUsingRelativePositionAndAnchor(geometry);
}
}
void InteractiveWindow::emitMainWindowResizeEvent() { void InteractiveWindow::emitMainWindowResizeEvent() {
emit qApp->getWindow()->windowGeometryChanged(qApp->getWindow()->geometry()); emit qApp->getWindow()->windowGeometryChanged(qApp->getWindow()->geometry());
} }
@ -184,22 +195,32 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
*/ */
if (nativeWindowInfo.contains(DOCK_AREA_PROPERTY)) { if (nativeWindowInfo.contains(DOCK_AREA_PROPERTY)) {
DockArea dockedArea = (DockArea) nativeWindowInfo[DOCK_AREA_PROPERTY].toInt(); DockArea dockedArea = (DockArea) nativeWindowInfo[DOCK_AREA_PROPERTY].toInt();
int tempWidth = 0;
int tempHeight = 0;
switch (dockedArea) { switch (dockedArea) {
case DockArea::TOP: case DockArea::TOP:
dockArea = Qt::TopDockWidgetArea; dockArea = Qt::TopDockWidgetArea;
_dockWidget->setFixedHeight(windowSize.height()); tempHeight = windowSize.height();
_dockWidget->setFixedHeight(tempHeight);
qApp->getWindow()->setDockedWidgetRelativePositionOffset(QSize(0, -tempHeight));
break; break;
case DockArea::BOTTOM: case DockArea::BOTTOM:
dockArea = Qt::BottomDockWidgetArea; dockArea = Qt::BottomDockWidgetArea;
_dockWidget->setFixedHeight(windowSize.height()); tempHeight = windowSize.height();
_dockWidget->setFixedHeight(tempHeight);
qApp->getWindow()->setDockedWidgetRelativePositionOffset(QSize(0, tempHeight));
break; break;
case DockArea::LEFT: case DockArea::LEFT:
dockArea = Qt::LeftDockWidgetArea; dockArea = Qt::LeftDockWidgetArea;
_dockWidget->setFixedWidth(windowSize.width()); tempWidth = windowSize.width();
_dockWidget->setFixedWidth(tempWidth);
qApp->getWindow()->setDockedWidgetRelativePositionOffset(QSize(-tempWidth, 0));
break; break;
case DockArea::RIGHT: case DockArea::RIGHT:
dockArea = Qt::RightDockWidgetArea; dockArea = Qt::RightDockWidgetArea;
_dockWidget->setFixedWidth(windowSize.width()); tempWidth = windowSize.width();
_dockWidget->setFixedWidth(tempWidth);
qApp->getWindow()->setDockedWidgetRelativePositionOffset(QSize(tempWidth, 0));
break; break;
default: default:
@ -255,6 +276,9 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
if (properties.contains(TITLE_PROPERTY)) { if (properties.contains(TITLE_PROPERTY)) {
object->setProperty(TITLE_PROPERTY, properties[TITLE_PROPERTY].toString()); object->setProperty(TITLE_PROPERTY, properties[TITLE_PROPERTY].toString());
} }
if (properties.contains(VISIBLE_PROPERTY)) {
object->setProperty(VISIBLE_PROPERTY, properties[INTERACTIVE_WINDOW_VISIBLE_PROPERTY].toBool());
}
if (properties.contains(SIZE_PROPERTY)) { if (properties.contains(SIZE_PROPERTY)) {
const auto size = vec2FromVariant(properties[SIZE_PROPERTY]); const auto size = vec2FromVariant(properties[SIZE_PROPERTY]);
object->setProperty(INTERACTIVE_WINDOW_SIZE_PROPERTY, QSize(size.x, size.y)); object->setProperty(INTERACTIVE_WINDOW_SIZE_PROPERTY, QSize(size.x, size.y));
@ -263,8 +287,21 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
const auto position = vec2FromVariant(properties[POSITION_PROPERTY]); const auto position = vec2FromVariant(properties[POSITION_PROPERTY]);
object->setProperty(INTERACTIVE_WINDOW_POSITION_PROPERTY, QPointF(position.x, position.y)); object->setProperty(INTERACTIVE_WINDOW_POSITION_PROPERTY, QPointF(position.x, position.y));
} }
if (properties.contains(VISIBLE_PROPERTY)) { if (properties.contains(RELATIVE_POSITION_ANCHOR_PROPERTY)) {
object->setProperty(VISIBLE_PROPERTY, properties[INTERACTIVE_WINDOW_VISIBLE_PROPERTY].toBool()); _relativePositionAnchor = static_cast<RelativePositionAnchor>(properties[RELATIVE_POSITION_ANCHOR_PROPERTY].toInt());
}
if (properties.contains(RELATIVE_POSITION_PROPERTY)) {
_relativePosition = vec2FromVariant(properties[RELATIVE_POSITION_PROPERTY]);
setPositionUsingRelativePositionAndAnchor(qApp->getWindow()->geometry());
}
if (properties.contains(IS_FULL_SCREEN_WINDOW)) {
_isFullScreenWindow = properties[IS_FULL_SCREEN_WINDOW].toBool();
}
if (_isFullScreenWindow) {
QRect geo = qApp->getWindow()->geometry();
object->setProperty(INTERACTIVE_WINDOW_POSITION_PROPERTY, QPointF(geo.x(), geo.y()));
object->setProperty(INTERACTIVE_WINDOW_SIZE_PROPERTY, QSize(geo.width(), geo.height()));
} }
// The qmlToScript method handles the thread-safety of this call. Because the QVariant argument // The qmlToScript method handles the thread-safety of this call. Because the QVariant argument
@ -288,6 +325,8 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap
connect(object, SIGNAL(interactiveWindowVisibleChanged()), this, SLOT(parentNativeWindowToMainWindow()), Qt::QueuedConnection); connect(object, SIGNAL(interactiveWindowVisibleChanged()), this, SLOT(parentNativeWindowToMainWindow()), Qt::QueuedConnection);
connect(object, SIGNAL(presentationModeChanged()), this, SLOT(parentNativeWindowToMainWindow()), Qt::QueuedConnection); connect(object, SIGNAL(presentationModeChanged()), this, SLOT(parentNativeWindowToMainWindow()), Qt::QueuedConnection);
#endif #endif
connect(qApp->getWindow(), &MainWindow::windowGeometryChanged, this, &InteractiveWindow::onMainWindowGeometryChanged, Qt::QueuedConnection);
QUrl sourceURL{ sourceUrl }; QUrl sourceURL{ sourceUrl };
// If the passed URL doesn't correspond to a known scheme, assume it's a local file path // If the passed URL doesn't correspond to a known scheme, assume it's a local file path
@ -414,6 +453,68 @@ void InteractiveWindow::setPosition(const glm::vec2& position) {
} }
} }
RelativePositionAnchor InteractiveWindow::getRelativePositionAnchor() const {
return _relativePositionAnchor;
}
void InteractiveWindow::setRelativePositionAnchor(const RelativePositionAnchor& relativePositionAnchor) {
_relativePositionAnchor = relativePositionAnchor;
setPositionUsingRelativePositionAndAnchor(qApp->getWindow()->geometry());
}
glm::vec2 InteractiveWindow::getRelativePosition() const {
return _relativePosition;
}
void InteractiveWindow::setRelativePosition(const glm::vec2& relativePosition) {
_relativePosition = relativePosition;
setPositionUsingRelativePositionAndAnchor(qApp->getWindow()->geometry());
}
void InteractiveWindow::setPositionUsingRelativePositionAndAnchor(const QRect& mainWindowGeometry) {
RelativePositionAnchor relativePositionAnchor = getRelativePositionAnchor();
glm::vec2 relativePosition = getRelativePosition();
glm::vec2 newPosition;
switch (relativePositionAnchor) {
case RelativePositionAnchor::TOP_LEFT:
newPosition.x = mainWindowGeometry.x() + relativePosition.x;
newPosition.y = mainWindowGeometry.y() + relativePosition.y;
break;
case RelativePositionAnchor::TOP_RIGHT:
newPosition.x = mainWindowGeometry.x() + mainWindowGeometry.width() - relativePosition.x;
newPosition.y = mainWindowGeometry.y() + relativePosition.y;
break;
case RelativePositionAnchor::BOTTOM_RIGHT:
newPosition.x = mainWindowGeometry.x() + mainWindowGeometry.width() - relativePosition.x;
newPosition.y = mainWindowGeometry.y() + mainWindowGeometry.height() - relativePosition.y;
break;
case RelativePositionAnchor::BOTTOM_LEFT:
newPosition.x = mainWindowGeometry.x() + relativePosition.x;
newPosition.y = mainWindowGeometry.y() + mainWindowGeometry.height() - relativePosition.y;
break;
}
// Make sure we include the dimensions of the docked widget!
QSize dockedWidgetRelativePositionOffset = qApp->getWindow()->getDockedWidgetRelativePositionOffset();
newPosition.x = newPosition.x + dockedWidgetRelativePositionOffset.width();
newPosition.y = newPosition.y + dockedWidgetRelativePositionOffset.height();
if (_qmlWindowProxy) {
QMetaObject::invokeMethod(_qmlWindowProxy.get(), "writeProperty", Q_ARG(QString, INTERACTIVE_WINDOW_POSITION_PROPERTY),
Q_ARG(QVariant, QPointF(newPosition.x, newPosition.y)));
}
setPosition(newPosition);
}
void InteractiveWindow::repositionAndResizeFullScreenWindow() {
QRect windowGeometry = qApp->getWindow()->geometry();
setPosition(glm::vec2(windowGeometry.x(), windowGeometry.y()));
setSize(glm::vec2(windowGeometry.width(), windowGeometry.height()));
}
glm::vec2 InteractiveWindow::getSize() const { glm::vec2 InteractiveWindow::getSize() const {
if (!_qmlWindowProxy) { if (!_qmlWindowProxy) {
return {}; return {};

View file

@ -89,6 +89,14 @@ namespace InteractiveWindowEnums {
RIGHT RIGHT
}; };
Q_ENUM_NS(DockArea); Q_ENUM_NS(DockArea);
enum RelativePositionAnchor {
TOP_LEFT,
TOP_RIGHT,
BOTTOM_RIGHT,
BOTTOM_LEFT
};
Q_ENUM_NS(RelativePositionAnchor);
} }
using namespace InteractiveWindowEnums; using namespace InteractiveWindowEnums;
@ -121,6 +129,8 @@ class InteractiveWindow : public QObject {
Q_PROPERTY(QString title READ getTitle WRITE setTitle) Q_PROPERTY(QString title READ getTitle WRITE setTitle)
Q_PROPERTY(glm::vec2 position READ getPosition WRITE setPosition) Q_PROPERTY(glm::vec2 position READ getPosition WRITE setPosition)
Q_PROPERTY(RelativePositionAnchor relativePositionAnchor READ getRelativePositionAnchor WRITE setRelativePositionAnchor)
Q_PROPERTY(glm::vec2 relativePosition READ getRelativePosition WRITE setRelativePosition)
Q_PROPERTY(glm::vec2 size READ getSize WRITE setSize) Q_PROPERTY(glm::vec2 size READ getSize WRITE setSize)
Q_PROPERTY(bool visible READ isVisible WRITE setVisible) Q_PROPERTY(bool visible READ isVisible WRITE setVisible)
Q_PROPERTY(int presentationMode READ getPresentationMode WRITE setPresentationMode) Q_PROPERTY(int presentationMode READ getPresentationMode WRITE setPresentationMode)
@ -136,6 +146,21 @@ private:
Q_INVOKABLE glm::vec2 getPosition() const; Q_INVOKABLE glm::vec2 getPosition() const;
Q_INVOKABLE void setPosition(const glm::vec2& position); Q_INVOKABLE void setPosition(const glm::vec2& position);
RelativePositionAnchor _relativePositionAnchor{ RelativePositionAnchor::TOP_LEFT };
Q_INVOKABLE RelativePositionAnchor getRelativePositionAnchor() const;
Q_INVOKABLE void setRelativePositionAnchor(const RelativePositionAnchor& position);
// This "relative position" is relative to the "relative position anchor" and excludes the window frame.
// This position will ALWAYS include the geometry of a docked widget, if one is present.
glm::vec2 _relativePosition{ 0.0f, 0.0f };
Q_INVOKABLE glm::vec2 getRelativePosition() const;
Q_INVOKABLE void setRelativePosition(const glm::vec2& position);
Q_INVOKABLE void setPositionUsingRelativePositionAndAnchor(const QRect& mainWindowGeometry);
bool _isFullScreenWindow{ false };
Q_INVOKABLE void repositionAndResizeFullScreenWindow();
Q_INVOKABLE glm::vec2 getSize() const; Q_INVOKABLE glm::vec2 getSize() const;
Q_INVOKABLE void setSize(const glm::vec2& size); Q_INVOKABLE void setSize(const glm::vec2& size);
@ -320,6 +345,7 @@ protected slots:
void forwardKeyPressEvent(int key, int modifiers); void forwardKeyPressEvent(int key, int modifiers);
void forwardKeyReleaseEvent(int key, int modifiers); void forwardKeyReleaseEvent(int key, int modifiers);
void emitMainWindowResizeEvent(); void emitMainWindowResizeEvent();
void onMainWindowGeometryChanged(QRect geometry);
private: private:
std::shared_ptr<QmlWindowProxy> _qmlWindowProxy; std::shared_ptr<QmlWindowProxy> _qmlWindowProxy;

View file

@ -55,6 +55,8 @@ public:
float getFrame() const { return _frame; } float getFrame() const { return _frame; }
void loadURL(const QString& url); void loadURL(const QString& url);
AnimBlendType getBlendType() const { return _blendType; };
protected: protected:
virtual void setCurrentFrameInternal(float frame) override; virtual void setCurrentFrameInternal(float frame) override;

View file

@ -30,6 +30,34 @@ AnimSkeleton::AnimSkeleton(const HFMModel& hfmModel) {
// we make a copy of the inverseBindMatrices in order to prevent mutating the model bind pose // we make a copy of the inverseBindMatrices in order to prevent mutating the model bind pose
// when we are dealing with a joint offset in the model // when we are dealing with a joint offset in the model
for (int i = 0; i < (int)hfmModel.skinDeformers.size(); i++) {
const auto& defor = hfmModel.skinDeformers[i];
std::vector<HFMCluster> dummyClustersList;
for (int j = 0; j < defor.clusters.size(); j++) {
std::vector<glm::mat4> bindMatrices;
// cast into a non-const reference, so we can mutate the FBXCluster
HFMCluster& cluster = const_cast<HFMCluster&>(defor.clusters.at(j));
HFMCluster localCluster;
localCluster.jointIndex = cluster.jointIndex;
localCluster.inverseBindMatrix = cluster.inverseBindMatrix;
localCluster.inverseBindTransform.evalFromRawMatrix(localCluster.inverseBindMatrix);
// if we have a joint offset in the fst file then multiply its inverse by the
// model cluster inverse bind matrix
if (hfmModel.jointRotationOffsets.contains(cluster.jointIndex)) {
AnimPose localOffset(hfmModel.jointRotationOffsets[cluster.jointIndex], glm::vec3());
localCluster.inverseBindMatrix = (glm::mat4)localOffset.inverse() * cluster.inverseBindMatrix;
localCluster.inverseBindTransform.evalFromRawMatrix(localCluster.inverseBindMatrix);
}
dummyClustersList.push_back(localCluster);
}
_clusterBindMatrixOriginalValues.push_back(dummyClustersList);
}
/*
for (int i = 0; i < (int)hfmModel.meshes.size(); i++) { for (int i = 0; i < (int)hfmModel.meshes.size(); i++) {
const HFMMesh& mesh = hfmModel.meshes.at(i); const HFMMesh& mesh = hfmModel.meshes.at(i);
std::vector<HFMCluster> dummyClustersList; std::vector<HFMCluster> dummyClustersList;
@ -55,6 +83,7 @@ AnimSkeleton::AnimSkeleton(const HFMModel& hfmModel) {
} }
_clusterBindMatrixOriginalValues.push_back(dummyClustersList); _clusterBindMatrixOriginalValues.push_back(dummyClustersList);
} }
*/
} }
AnimSkeleton::AnimSkeleton(const std::vector<HFMJoint>& joints, const QMap<int, glm::quat> jointOffsets) { AnimSkeleton::AnimSkeleton(const std::vector<HFMJoint>& joints, const QMap<int, glm::quat> jointOffsets) {

View file

@ -70,6 +70,8 @@ public:
std::vector<int> lookUpJointIndices(const std::vector<QString>& jointNames) const; std::vector<int> lookUpJointIndices(const std::vector<QString>& jointNames) const;
const HFMCluster getClusterBindMatricesOriginalValues(const int meshIndex, const int clusterIndex) const { return _clusterBindMatrixOriginalValues[meshIndex][clusterIndex]; } const HFMCluster getClusterBindMatricesOriginalValues(const int meshIndex, const int clusterIndex) const { return _clusterBindMatrixOriginalValues[meshIndex][clusterIndex]; }
// const HFMCluster getClusterBindMatricesOriginalValues(const int meshIndex, const int clusterIndex) const { return _clusterBindMatrixOriginalValues[meshIndex][clusterIndex]; }
protected: protected:
void buildSkeletonFromJoints(const std::vector<HFMJoint>& joints, const QMap<int, glm::quat> jointOffsets); void buildSkeletonFromJoints(const std::vector<HFMJoint>& joints, const QMap<int, glm::quat> jointOffsets);

View file

@ -545,7 +545,8 @@ QStringList Rig::getAnimationRoles() const {
auto clipNode = std::dynamic_pointer_cast<AnimClip>(node); auto clipNode = std::dynamic_pointer_cast<AnimClip>(node);
if (clipNode) { if (clipNode) {
// filter out the userAnims, they are for internal use only. // filter out the userAnims, they are for internal use only.
if (!clipNode->getID().startsWith("userAnim")) { // also don't return additive blend node clips as valid roles.
if (!clipNode->getID().startsWith("userAnim") && clipNode->getBlendType() == AnimBlendType_Normal) {
list.append(node->getID()); list.append(node->getID());
} }
} }
@ -1432,6 +1433,69 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
} }
_lastEnableInverseKinematics = _enableInverseKinematics; _lastEnableInverseKinematics = _enableInverseKinematics;
//stategraph vars based on input
const float INPUT_DEADZONE_THRESHOLD = 0.05f;
const float SLOW_SPEED_THRESHOLD = 1.5f;
if (fabsf(_previousControllerParameters.inputX) <= INPUT_DEADZONE_THRESHOLD &&
fabsf(_previousControllerParameters.inputZ) <= INPUT_DEADZONE_THRESHOLD) {
// no WASD input
if (fabsf(forwardSpeed) <= SLOW_SPEED_THRESHOLD && fabsf(lateralSpeed) <= SLOW_SPEED_THRESHOLD) {
_animVars.set("isInputForward", false);
_animVars.set("isInputBackward", false);
_animVars.set("isInputRight", false);
_animVars.set("isInputLeft", false);
_animVars.set("isNotInput", true);
_animVars.set("isNotInputSlow", true);
} else {
_animVars.set("isInputForward", false);
_animVars.set("isInputBackward", false);
_animVars.set("isInputRight", false);
_animVars.set("isInputLeft", false);
_animVars.set("isNotInput", true);
_animVars.set("isNotInputSlow", false);
}
} else if (fabsf(_previousControllerParameters.inputZ) >= fabsf(_previousControllerParameters.inputX)) {
if (_previousControllerParameters.inputZ > 0.0f) {
// forward
_animVars.set("isInputForward", true);
_animVars.set("isInputBackward", false);
_animVars.set("isInputRight", false);
_animVars.set("isInputLeft", false);
_animVars.set("isNotInput", false);
_animVars.set("isNotInputSlow", false);
} else {
// backward
_animVars.set("isInputForward", false);
_animVars.set("isInputBackward", true);
_animVars.set("isInputRight", false);
_animVars.set("isInputLeft", false);
_animVars.set("isNotInput", false);
_animVars.set("isNotInputSlow", false);
}
} else {
if (_previousControllerParameters.inputX > 0.0f) {
// right
_animVars.set("isInputForward", false);
_animVars.set("isInputBackward", false);
_animVars.set("isInputRight", true);
_animVars.set("isInputLeft", false);
_animVars.set("isNotInput", false);
_animVars.set("isNotInputSlow", false);
} else {
// left
_animVars.set("isInputForward", false);
_animVars.set("isInputBackward", false);
_animVars.set("isInputRight", false);
_animVars.set("isInputLeft", true);
_animVars.set("isNotInput", false);
_animVars.set("isNotInputSlow", false);
}
}
} }
_lastForward = forward; _lastForward = forward;
_lastPosition = worldPosition; _lastPosition = worldPosition;
@ -2160,50 +2224,6 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo
} }
} }
//deadzone constant
const float INPUT_DEADZONE_THRESHOLD = 0.05f;
if (fabsf(params.inputX) <= INPUT_DEADZONE_THRESHOLD && fabsf(params.inputZ) <= INPUT_DEADZONE_THRESHOLD) {
// no WASD input
_animVars.set("isInputForward", false);
_animVars.set("isInputBackward", false);
_animVars.set("isInputRight", false);
_animVars.set("isInputLeft", false);
_animVars.set("isNotInput", true);
} else if (fabsf(params.inputZ) >= fabsf(params.inputX)) {
if (params.inputZ > 0.0f) {
// forward
_animVars.set("isInputForward", true);
_animVars.set("isInputBackward", false);
_animVars.set("isInputRight", false);
_animVars.set("isInputLeft", false);
_animVars.set("isNotInput", false);
} else {
// backward
_animVars.set("isInputForward", false);
_animVars.set("isInputBackward", true);
_animVars.set("isInputRight", false);
_animVars.set("isInputLeft", false);
_animVars.set("isNotInput", false);
}
} else {
if (params.inputX > 0.0f) {
// right
_animVars.set("isInputForward", false);
_animVars.set("isInputBackward", false);
_animVars.set("isInputRight", true);
_animVars.set("isInputLeft", false);
_animVars.set("isNotInput", false);
} else {
// left
_animVars.set("isInputForward", false);
_animVars.set("isInputBackward", false);
_animVars.set("isInputRight", false);
_animVars.set("isInputLeft", true);
_animVars.set("isNotInput", false);
}
}
_headEnabled = params.primaryControllerFlags[PrimaryControllerType_Head] & (uint8_t)ControllerFlags::Enabled; _headEnabled = params.primaryControllerFlags[PrimaryControllerType_Head] & (uint8_t)ControllerFlags::Enabled;
bool leftHandEnabled = params.primaryControllerFlags[PrimaryControllerType_LeftHand] & (uint8_t)ControllerFlags::Enabled; bool leftHandEnabled = params.primaryControllerFlags[PrimaryControllerType_LeftHand] & (uint8_t)ControllerFlags::Enabled;

View file

@ -88,8 +88,8 @@ public:
AnimPose secondaryControllerPoses[NumSecondaryControllerTypes]; // rig space AnimPose secondaryControllerPoses[NumSecondaryControllerTypes]; // rig space
uint8_t secondaryControllerFlags[NumSecondaryControllerTypes]; uint8_t secondaryControllerFlags[NumSecondaryControllerTypes];
bool isTalking; bool isTalking;
float inputX; float inputX = 0.0f;
float inputZ; float inputZ = 0.0f;
bool reactionEnabledFlags[NUM_AVATAR_BEGIN_END_REACTIONS]; bool reactionEnabledFlags[NUM_AVATAR_BEGIN_END_REACTIONS];
bool reactionTriggers[NUM_AVATAR_TRIGGER_REACTIONS]; bool reactionTriggers[NUM_AVATAR_TRIGGER_REACTIONS];
HFMJointShapeInfo hipsShapeInfo; HFMJointShapeInfo hipsShapeInfo;

View file

@ -335,8 +335,8 @@ namespace controller {
makeAxisPair(Action::STEP_PITCH, "StepPitch"), makeAxisPair(Action::STEP_PITCH, "StepPitch"),
makeAxisPair(Action::STEP_ROLL, "StepRoll"), makeAxisPair(Action::STEP_ROLL, "StepRoll"),
makeAxisPair(Action::STEP_TRANSLATE_X, "StepTranslateX"), makeAxisPair(Action::STEP_TRANSLATE_X, "StepTranslateX"),
makeAxisPair(Action::STEP_TRANSLATE_X, "StepTranslateY"), makeAxisPair(Action::STEP_TRANSLATE_Y, "StepTranslateY"),
makeAxisPair(Action::STEP_TRANSLATE_X, "StepTranslateZ"), makeAxisPair(Action::STEP_TRANSLATE_Z, "StepTranslateZ"),
makePosePair(Action::LEFT_HAND, "LeftHand"), makePosePair(Action::LEFT_HAND, "LeftHand"),
makePosePair(Action::RIGHT_HAND, "RightHand"), makePosePair(Action::RIGHT_HAND, "RightHand"),

View file

@ -1463,9 +1463,6 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
// see if any materials have texture children // see if any materials have texture children
bool materialsHaveTextures = checkMaterialsHaveTextures(_hfmMaterials, _textureFilenames, _connectionChildMap); bool materialsHaveTextures = checkMaterialsHaveTextures(_hfmMaterials, _textureFilenames, _connectionChildMap);
// Note that the transforms in the TransformNodes are initially in world-space, and need to be converted to parent-space
std::vector<hfm::TransformNode> transformNodes;
for (QMap<QString, ExtractedMesh>::iterator it = meshes.begin(); it != meshes.end(); it++) { for (QMap<QString, ExtractedMesh>::iterator it = meshes.begin(); it != meshes.end(); it++) {
const QString& meshID = it.key(); const QString& meshID = it.key();
const ExtractedMesh& extracted = it.value(); const ExtractedMesh& extracted = it.value();
@ -1509,7 +1506,7 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
hfm::Shape& shape = partShapes[i]; hfm::Shape& shape = partShapes[i];
shape.mesh = meshIndex; shape.mesh = meshIndex;
shape.meshPart = i; shape.meshPart = i;
shape.transform = transformIndex; shape.joint = transformIndex;
auto matName = mesh.parts[i].materialID; auto matName = mesh.parts[i].materialID;
auto materialIt = materialNameToID.find(matName.toStdString()); auto materialIt = materialNameToID.find(matName.toStdString());
@ -1593,10 +1590,10 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
} }
// whether we're skinned depends on how many clusters are attached // whether we're skinned depends on how many clusters are attached
if (clusterIDs.size() > 1) { if (clusterIDs.size() > 0) {
hfm::DynamicTransform dynamicTransform; hfm::SkinDeformer skinDeformer;
auto& clusters = dynamicTransform.clusters; auto& clusters = skinDeformer.clusters;
std::vector<hfm::Deformer> deformers; std::vector<hfm::SkinCluster> skinClusters;
for (const auto& clusterID : clusterIDs) { for (const auto& clusterID : clusterIDs) {
HFMCluster hfmCluster; HFMCluster hfmCluster;
const Cluster& fbxCluster = fbxClusters[clusterID]; const Cluster& fbxCluster = fbxClusters[clusterID];
@ -1642,38 +1639,43 @@ HFMModel* FBXSerializer::extractHFMModel(const hifi::VariantHash& mapping, const
clusters.push_back(cluster); clusters.push_back(cluster);
// Skinned mesh instances have a dynamic transform // Skinned mesh instances have a dynamic transform
dynamicTransform.deformers.reserve(clusterIDs.size()); skinDeformer.skinClusterIndices.reserve(clusterIDs.size());
clusters.reserve(clusterIDs.size());
for (const auto& clusterID : clusterIDs) { for (const auto& clusterID : clusterIDs) {
const Cluster& fbxCluster = fbxClusters[clusterID]; const Cluster& fbxCluster = fbxClusters[clusterID];
dynamicTransform.deformers.emplace_back(); skinDeformer.skinClusterIndices.emplace_back();
deformers.emplace_back(); skinClusters.emplace_back();
hfm::Deformer& deformer = deformers.back(); hfm::SkinCluster& skinCluster = skinClusters.back();
size_t indexWeightPairs = (size_t)std::min(fbxCluster.indices.size(), fbxCluster.weights.size()); size_t indexWeightPairs = (size_t)std::min(fbxCluster.indices.size(), fbxCluster.weights.size());
deformer.indices.reserve(indexWeightPairs); skinCluster.indices.reserve(indexWeightPairs);
deformer.weights.reserve(indexWeightPairs); skinCluster.weights.reserve(indexWeightPairs);
for (int i = 0; i < (int)indexWeightPairs; i++) {
int oldIndex = fbxCluster.indices[i]; for (int j = 0; j < fbxCluster.indices.size(); j++) {
uint32_t newIndex = (uint32_t)extracted.newIndices.value(oldIndex); int oldIndex = fbxCluster.indices.at(j);
deformer.indices.push_back(newIndex); float weight = fbxCluster.weights.at(j);
deformer.indices.push_back((float)fbxCluster.weights[i]); for (QMultiHash<int, int>::const_iterator it = extracted.newIndices.constFind(oldIndex);
it != extracted.newIndices.end() && it.key() == oldIndex; it++) {
int newIndex = it.value();
skinCluster.indices.push_back(newIndex);
skinCluster.weights.push_back(weight);
}
} }
} }
// Store this model's deformers, this dynamic transform's deformer IDs // Store this model's deformers, this dynamic transform's deformer IDs
uint32_t deformerMinID = (uint32_t)hfmModel.deformers.size(); uint32_t deformerMinID = (uint32_t)hfmModel.skinClusters.size();
hfmModel.deformers.insert(hfmModel.deformers.end(), deformers.cbegin(), deformers.cend()); hfmModel.skinClusters.insert(hfmModel.skinClusters.end(), skinClusters.cbegin(), skinClusters.cend());
dynamicTransform.deformers.resize(deformers.size()); skinDeformer.skinClusterIndices.resize(skinClusters.size());
std::iota(dynamicTransform.deformers.begin(), dynamicTransform.deformers.end(), deformerMinID); std::iota(skinDeformer.skinClusterIndices.begin(), skinDeformer.skinClusterIndices.end(), deformerMinID);
// Store the model's dynamic transform, and put its ID in the shapes // Store the model's dynamic transform, and put its ID in the shapes
hfmModel.dynamicTransforms.push_back(dynamicTransform); hfmModel.skinDeformers.push_back(skinDeformer);
uint32_t dynamicTransformID = (uint32_t)(hfmModel.dynamicTransforms.size() - 1); uint32_t skinDeformerID = (uint32_t)(hfmModel.skinDeformers.size() - 1);
for (hfm::Shape& shape : partShapes) { for (hfm::Shape& shape : partShapes) {
shape.dynamicTransform = dynamicTransformID; shape.skinDeformer = skinDeformerID;
} }
} else { } else {
// this is a single-joint mesh // this is a no cluster mesh
HFMJoint& joint = hfmModel.joints[transformIndex]; HFMJoint& joint = hfmModel.joints[transformIndex];
// Apply geometric offset, if present, by transforming the vertices directly // Apply geometric offset, if present, by transforming the vertices directly

View file

@ -242,17 +242,20 @@ public:
QVector<glm::vec3> colors; QVector<glm::vec3> colors;
QVector<glm::vec2> texCoords; QVector<glm::vec2> texCoords;
QVector<glm::vec2> texCoords1; QVector<glm::vec2> texCoords1;
QVector<uint16_t> clusterIndices; // DEPRECATED (see hfm::Shape::dynamicTransform, hfm::DynamicTransform::deformers, hfm::Deformer)
QVector<uint16_t> clusterWeights; // DEPRECATED (see hfm::Shape::dynamicTransform, hfm::DynamicTransform::deformers, hfm::Deformer)
QVector<int32_t> originalIndices;
QVector<Cluster> clusters; // DEPRECATED (see hfm::Shape::dynamicTransform, hfm::DynamicTransform::clusters) QVector<Cluster> clusters; // DEPRECATED (see hfm::Shape::dynamicTransform, hfm::DynamicTransform::clusters)
Extents meshExtents; // DEPRECATED (see hfm::Shape::transformedExtents) Extents meshExtents; // DEPRECATED (see hfm::Shape::transformedExtents)
glm::mat4 modelTransform; // DEPRECATED (see hfm::Joint::globalTransform, hfm::Shape::transform, hfm::Model::joints) glm::mat4 modelTransform; // DEPRECATED (see hfm::Joint::globalTransform, hfm::Shape::transform, hfm::Model::joints)
// Skinning cluster attributes
QVector<uint16_t> clusterIndices;
QVector<uint16_t> clusterWeights;
// Blendshape attributes
QVector<Blendshape> blendshapes; QVector<Blendshape> blendshapes;
QVector<int32_t> originalIndices; // Original indices of the vertices
unsigned int meshIndex; // the order the meshes appeared in the object file unsigned int meshIndex; // the order the meshes appeared in the object file
graphics::MeshPointer _mesh; graphics::MeshPointer _mesh;
@ -293,27 +296,17 @@ public:
bool shouldInitCollisions() const { return _collisionsConfig.size() > 0; } bool shouldInitCollisions() const { return _collisionsConfig.size() > 0; }
}; };
// DEPRECATED in favor of using hfm::Joint
class TransformNode {
public:
static const uint32_t INVALID_PARENT_INDEX{ (uint32_t)-1 };
uint32_t parent { INVALID_PARENT_INDEX };
Transform transform;
};
// Formerly contained in hfm::Mesh // Formerly contained in hfm::Mesh
class Deformer { class SkinCluster {
public: public:
std::vector<uint32_t> indices; std::vector<uint32_t> indices;
std::vector<float> weights; std::vector<float> weights;
}; };
class DynamicTransform { class SkinDeformer {
public: public:
std::vector<uint16_t> deformers; std::vector<uint16_t> skinClusterIndices;
std::vector<Cluster> clusters; // affect the deformer of the same index std::vector<Cluster> clusters;
std::vector<uint32_t> blendshapes;
// There are also the meshExtents and modelTransform, which for now are left in hfm::Mesh
}; };
// The lightweight model part description. // The lightweight model part description.
@ -322,10 +315,10 @@ public:
uint32_t mesh { UNDEFINED_KEY }; uint32_t mesh { UNDEFINED_KEY };
uint32_t meshPart { UNDEFINED_KEY }; uint32_t meshPart { UNDEFINED_KEY };
uint32_t material { UNDEFINED_KEY }; uint32_t material { UNDEFINED_KEY };
uint32_t transform { UNDEFINED_KEY }; // The hfm::Joint associated with this shape, containing transform information uint32_t joint { UNDEFINED_KEY }; // The hfm::Joint associated with this shape, containing transform information
// TODO: Have all serializers calculate hfm::Shape::transformedExtents in world space where they previously calculated hfm::Mesh::meshExtents. Change all code that uses hfm::Mesh::meshExtents to use this instead. // TODO: Have all serializers calculate hfm::Shape::transformedExtents in world space where they previously calculated hfm::Mesh::meshExtents. Change all code that uses hfm::Mesh::meshExtents to use this instead.
Extents transformedExtents; // The precise extents of the meshPart vertices in world space, after transform information is applied, while not taking into account rigging/skinning Extents transformedExtents; // The precise extents of the meshPart vertices in world space, after transform information is applied, while not taking into account rigging/skinning
uint32_t dynamicTransform { UNDEFINED_KEY }; uint32_t skinDeformer { UNDEFINED_KEY };
}; };
/// The runtime model format. /// The runtime model format.
@ -342,10 +335,9 @@ public:
std::vector<Mesh> meshes; std::vector<Mesh> meshes;
std::vector<Material> materials; std::vector<Material> materials;
std::vector<Deformer> deformers;
std::vector<TransformNode> transforms; std::vector<SkinDeformer> skinDeformers;
std::vector<DynamicTransform> dynamicTransforms; std::vector<SkinCluster> skinClusters;
std::vector<Joint> joints; std::vector<Joint> joints;
QHash<QString, int> jointIndices; ///< 1-based, so as to more easily detect missing indices QHash<QString, int> jointIndices; ///< 1-based, so as to more easily detect missing indices

View file

@ -30,7 +30,7 @@ namespace baker {
class GetModelPartsTask { class GetModelPartsTask {
public: public:
using Input = hfm::Model::Pointer; using Input = hfm::Model::Pointer;
using Output = VaryingSet9<std::vector<hfm::Mesh>, hifi::URL, baker::MeshIndicesToModelNames, baker::BlendshapesPerMesh, std::vector<hfm::Joint>, std::vector<hfm::Shape>, std::vector<hfm::DynamicTransform>, std::vector<hfm::Deformer>, Extents>; using Output = VaryingSet9<std::vector<hfm::Mesh>, hifi::URL, baker::MeshIndicesToModelNames, baker::BlendshapesPerMesh, std::vector<hfm::Joint>, std::vector<hfm::Shape>, std::vector<hfm::SkinDeformer>, std::vector<hfm::SkinCluster>, Extents>;
using JobModel = Job::ModelIO<GetModelPartsTask, Input, Output>; using JobModel = Job::ModelIO<GetModelPartsTask, Input, Output>;
void run(const BakeContextPointer& context, const Input& input, Output& output) { void run(const BakeContextPointer& context, const Input& input, Output& output) {
@ -45,8 +45,8 @@ namespace baker {
} }
output.edit4() = hfmModelIn->joints; output.edit4() = hfmModelIn->joints;
output.edit5() = hfmModelIn->shapes; output.edit5() = hfmModelIn->shapes;
output.edit6() = hfmModelIn->dynamicTransforms; output.edit6() = hfmModelIn->skinDeformers;
output.edit7() = hfmModelIn->deformers; output.edit7() = hfmModelIn->skinClusters;
output.edit8() = hfmModelIn->meshExtents; output.edit8() = hfmModelIn->meshExtents;
} }
}; };
@ -147,8 +147,8 @@ namespace baker {
const auto blendshapesPerMeshIn = modelPartsIn.getN<GetModelPartsTask::Output>(3); const auto blendshapesPerMeshIn = modelPartsIn.getN<GetModelPartsTask::Output>(3);
const auto jointsIn = modelPartsIn.getN<GetModelPartsTask::Output>(4); const auto jointsIn = modelPartsIn.getN<GetModelPartsTask::Output>(4);
const auto shapesIn = modelPartsIn.getN<GetModelPartsTask::Output>(5); const auto shapesIn = modelPartsIn.getN<GetModelPartsTask::Output>(5);
const auto dynamicTransformsIn = modelPartsIn.getN<GetModelPartsTask::Output>(6); const auto skinDeformersIn = modelPartsIn.getN<GetModelPartsTask::Output>(6);
const auto deformersIn = modelPartsIn.getN<GetModelPartsTask::Output>(7); const auto skinClustersIn = modelPartsIn.getN<GetModelPartsTask::Output>(7);
const auto modelExtentsIn = modelPartsIn.getN<GetModelPartsTask::Output>(8); const auto modelExtentsIn = modelPartsIn.getN<GetModelPartsTask::Output>(8);
// Calculate normals and tangents for meshes and blendshapes if they do not exist // Calculate normals and tangents for meshes and blendshapes if they do not exist
@ -163,14 +163,14 @@ namespace baker {
// Skinning weight calculations // Skinning weight calculations
// NOTE: Due to limitations in the current graphics::MeshPointer representation, the output list of ReweightedDeformers is per-mesh. An element is empty if there are no deformers for the mesh of the same index. // NOTE: Due to limitations in the current graphics::MeshPointer representation, the output list of ReweightedDeformers is per-mesh. An element is empty if there are no deformers for the mesh of the same index.
const auto reweightDeformersInputs = ReweightDeformersTask::Input(meshesIn, shapesIn, dynamicTransformsIn, deformersIn).asVarying(); const auto reweightDeformersInputs = ReweightDeformersTask::Input(meshesIn, shapesIn, skinDeformersIn, skinClustersIn).asVarying();
const auto reweightedDeformers = model.addJob<ReweightDeformersTask>("ReweightDeformers", reweightDeformersInputs); const auto reweightedDeformers = model.addJob<ReweightDeformersTask>("ReweightDeformers", reweightDeformersInputs);
// Shape vertices are included/rejected based on skinning weight, and thus must use the reweighted deformers. // Shape vertices are included/rejected based on skinning weight, and thus must use the reweighted deformers.
const auto collectShapeVerticesInputs = CollectShapeVerticesTask::Input(meshesIn, shapesIn, jointsIn, dynamicTransformsIn, reweightedDeformers).asVarying(); const auto collectShapeVerticesInputs = CollectShapeVerticesTask::Input(meshesIn, shapesIn, jointsIn, skinDeformersIn, reweightedDeformers).asVarying();
const auto shapeVerticesPerJoint = model.addJob<CollectShapeVerticesTask>("CollectShapeVertices", collectShapeVerticesInputs); const auto shapeVerticesPerJoint = model.addJob<CollectShapeVerticesTask>("CollectShapeVertices", collectShapeVerticesInputs);
// Build the graphics::MeshPointer for each hfm::Mesh // Build the graphics::MeshPointer for each hfm::Mesh
const auto buildGraphicsMeshInputs = BuildGraphicsMeshTask::Input(meshesIn, url, meshIndicesToModelNames, normalsPerMesh, tangentsPerMesh, shapesIn, dynamicTransformsIn, reweightedDeformers).asVarying(); const auto buildGraphicsMeshInputs = BuildGraphicsMeshTask::Input(meshesIn, url, meshIndicesToModelNames, normalsPerMesh, tangentsPerMesh, shapesIn, skinDeformersIn, reweightedDeformers).asVarying();
const auto graphicsMeshes = model.addJob<BuildGraphicsMeshTask>("BuildGraphicsMesh", buildGraphicsMeshInputs); const auto graphicsMeshes = model.addJob<BuildGraphicsMeshTask>("BuildGraphicsMesh", buildGraphicsMeshInputs);
// Prepare joint information // Prepare joint information

View file

@ -95,7 +95,7 @@ void buildGraphicsMesh(const hfm::Mesh& hfmMesh, graphics::MeshPointer& graphics
HIFI_FCDEBUG_ID(model_baker(), repeatMessageID, "BuildGraphicsMeshTask -- The number of indices and weights for a deformer had different sizes and have been trimmed to match"); HIFI_FCDEBUG_ID(model_baker(), repeatMessageID, "BuildGraphicsMeshTask -- The number of indices and weights for a deformer had different sizes and have been trimmed to match");
} }
// Record cluster sizes // Record cluster sizes
const size_t numVertClusters = (reweightedDeformers.weightsPerVertex ? hfmMesh.clusterIndices.size() / reweightedDeformers.weightsPerVertex : 0); const size_t numVertClusters = (reweightedDeformers.weightsPerVertex ? reweightedDeformers.indices.size() / reweightedDeformers.weightsPerVertex : 0);
const size_t clusterIndicesSize = numVertClusters * clusterIndiceElement.getSize(); const size_t clusterIndicesSize = numVertClusters * clusterIndiceElement.getSize();
const size_t clusterWeightsSize = numVertClusters * clusterWeightElement.getSize(); const size_t clusterWeightsSize = numVertClusters * clusterWeightElement.getSize();
@ -381,16 +381,16 @@ void BuildGraphicsMeshTask::run(const baker::BakeContextPointer& context, const
const auto& normalsPerMesh = input.get3(); const auto& normalsPerMesh = input.get3();
const auto& tangentsPerMesh = input.get4(); const auto& tangentsPerMesh = input.get4();
const auto& shapes = input.get5(); const auto& shapes = input.get5();
const auto& dynamicTransforms = input.get6(); const auto& skinDeformers = input.get6();
const auto& reweightedDeformersPerMesh = input.get7(); const auto& reweightedDeformersPerMesh = input.get7();
// Currently, there is only (at most) one dynamicTransform per mesh // Currently, there is only (at most) one skinDeformer per mesh
// An undefined shape.dynamicTransform has the value hfm::UNDEFINED_KEY // An undefined shape.skinDeformer has the value hfm::UNDEFINED_KEY
std::vector<uint32_t> dynamicTransformPerMesh; std::vector<uint32_t> skinDeformerPerMesh;
dynamicTransformPerMesh.resize(meshes.size(), hfm::UNDEFINED_KEY); skinDeformerPerMesh.resize(meshes.size(), hfm::UNDEFINED_KEY);
for (const auto& shape : shapes) { for (const auto& shape : shapes) {
uint32_t dynamicTransformIndex = shape.dynamicTransform; uint32_t skinDeformerIndex = shape.skinDeformer;
dynamicTransformPerMesh[shape.mesh] = dynamicTransformIndex; skinDeformerPerMesh[shape.mesh] = skinDeformerIndex;
} }
auto& graphicsMeshes = output; auto& graphicsMeshes = output;
@ -403,10 +403,10 @@ void BuildGraphicsMeshTask::run(const baker::BakeContextPointer& context, const
uint16_t numDeformerControllers = 0; uint16_t numDeformerControllers = 0;
if (reweightedDeformers.weightsPerVertex != 0) { if (reweightedDeformers.weightsPerVertex != 0) {
uint32_t dynamicTransformIndex = dynamicTransformPerMesh[i]; uint32_t skinDeformerIndex = skinDeformerPerMesh[i];
if (dynamicTransformIndex != hfm::UNDEFINED_KEY) { if (skinDeformerIndex != hfm::UNDEFINED_KEY) {
const hfm::DynamicTransform& dynamicTransform = dynamicTransforms[dynamicTransformIndex]; const hfm::SkinDeformer& skinDeformer = skinDeformers[skinDeformerIndex];
numDeformerControllers = (uint16_t)dynamicTransform.deformers.size(); numDeformerControllers = (uint16_t)skinDeformer.skinClusterIndices.size();
} }
} }

View file

@ -20,7 +20,7 @@
class BuildGraphicsMeshTask { class BuildGraphicsMeshTask {
public: public:
using Input = baker::VaryingSet8<std::vector<hfm::Mesh>, hifi::URL, baker::MeshIndicesToModelNames, baker::NormalsPerMesh, baker::TangentsPerMesh, std::vector<hfm::Shape>, std::vector<hfm::DynamicTransform>, std::vector<baker::ReweightedDeformers>>; using Input = baker::VaryingSet8<std::vector<hfm::Mesh>, hifi::URL, baker::MeshIndicesToModelNames, baker::NormalsPerMesh, baker::TangentsPerMesh, std::vector<hfm::Shape>, std::vector<hfm::SkinDeformer>, std::vector<baker::ReweightedDeformers>>;
using Output = std::vector<graphics::MeshPointer>; using Output = std::vector<graphics::MeshPointer>;
using JobModel = baker::Job::ModelIO<BuildGraphicsMeshTask, Input, Output>; using JobModel = baker::Job::ModelIO<BuildGraphicsMeshTask, Input, Output>;

View file

@ -13,15 +13,15 @@
#include <glm/gtx/transform.hpp> #include <glm/gtx/transform.hpp>
// Used to track and avoid duplicate shape vertices, as multiple shapes can have the same mesh and dynamicTransform // Used to track and avoid duplicate shape vertices, as multiple shapes can have the same mesh and skinDeformer
class VertexSource { class VertexSource {
public: public:
uint32_t mesh; uint32_t mesh;
uint32_t dynamicTransform; uint32_t skinDeformer;
bool operator==(const VertexSource& other) const { bool operator==(const VertexSource& other) const {
return mesh == other.mesh && return mesh == other.mesh &&
dynamicTransform == other.dynamicTransform; skinDeformer == other.skinDeformer;
} }
}; };
@ -29,7 +29,7 @@ void CollectShapeVerticesTask::run(const baker::BakeContextPointer& context, con
const auto& meshes = input.get0(); const auto& meshes = input.get0();
const auto& shapes = input.get1(); const auto& shapes = input.get1();
const auto& joints = input.get2(); const auto& joints = input.get2();
const auto& dynamicTransforms = input.get3(); const auto& skinDeformers = input.get3();
const auto& reweightedDeformers = input.get4(); const auto& reweightedDeformers = input.get4();
auto& shapeVerticesPerJoint = output; auto& shapeVerticesPerJoint = output;
@ -38,18 +38,18 @@ void CollectShapeVerticesTask::run(const baker::BakeContextPointer& context, con
vertexSourcesPerJoint.resize(joints.size()); vertexSourcesPerJoint.resize(joints.size());
for (size_t i = 0; i < shapes.size(); ++i) { for (size_t i = 0; i < shapes.size(); ++i) {
const auto& shape = shapes[i]; const auto& shape = shapes[i];
const uint32_t dynamicTransformKey = shape.dynamicTransform; const uint32_t skinDeformerKey = shape.skinDeformer;
if (dynamicTransformKey == hfm::UNDEFINED_KEY) { if (skinDeformerKey == hfm::UNDEFINED_KEY) {
continue; continue;
} }
VertexSource vertexSource; VertexSource vertexSource;
vertexSource.mesh = shape.mesh; vertexSource.mesh = shape.mesh;
vertexSource.dynamicTransform = dynamicTransformKey; vertexSource.skinDeformer = skinDeformerKey;
const auto& dynamicTransform = dynamicTransforms[dynamicTransformKey]; const auto& skinDeformer = skinDeformers[skinDeformerKey];
for (size_t j = 0; j < dynamicTransform.clusters.size(); ++j) { for (size_t j = 0; j < skinDeformer.clusters.size(); ++j) {
const auto& cluster = dynamicTransform.clusters[j]; const auto& cluster = skinDeformer.clusters[j];
const uint32_t jointIndex = cluster.jointIndex; const uint32_t jointIndex = cluster.jointIndex;
auto& vertexSources = vertexSourcesPerJoint[jointIndex]; auto& vertexSources = vertexSourcesPerJoint[jointIndex];

View file

@ -19,7 +19,7 @@
class CollectShapeVerticesTask { class CollectShapeVerticesTask {
public: public:
using Input = baker::VaryingSet5<std::vector<hfm::Mesh>, std::vector<hfm::Shape>, std::vector<hfm::Joint>, std::vector<hfm::DynamicTransform>, std::vector<baker::ReweightedDeformers>>; using Input = baker::VaryingSet5<std::vector<hfm::Mesh>, std::vector<hfm::Shape>, std::vector<hfm::Joint>, std::vector<hfm::SkinDeformer>, std::vector<baker::ReweightedDeformers>>;
using Output = std::vector<ShapeVertices>; using Output = std::vector<ShapeVertices>;
using JobModel = baker::Job::ModelIO<CollectShapeVerticesTask, Input, Output>; using JobModel = baker::Job::ModelIO<CollectShapeVerticesTask, Input, Output>;

View file

@ -11,30 +11,30 @@
#include "ReweightDeformersTask.h" #include "ReweightDeformersTask.h"
baker::ReweightedDeformers getReweightedDeformers(size_t numMeshVertices, const std::vector<const hfm::Deformer*> deformers, const uint16_t weightsPerVertex) { baker::ReweightedDeformers getReweightedDeformers(size_t numMeshVertices, const std::vector<const hfm::SkinCluster*> skinClusters, const uint16_t weightsPerVertex) {
baker::ReweightedDeformers reweightedDeformers; baker::ReweightedDeformers reweightedDeformers;
if (deformers.size() == 0) { if (skinClusters.size() == 0) {
return reweightedDeformers; return reweightedDeformers;
} }
size_t numClusterIndices = numMeshVertices * weightsPerVertex; size_t numClusterIndices = numMeshVertices * weightsPerVertex;
reweightedDeformers.weightsPerVertex = weightsPerVertex; reweightedDeformers.weightsPerVertex = weightsPerVertex;
// TODO: Consider having a rootCluster property in the DynamicTransform rather than appending the root to the end of the cluster list. // TODO: Consider having a rootCluster property in the DynamicTransform rather than appending the root to the end of the cluster list.
reweightedDeformers.indices.resize(numClusterIndices, (uint16_t)(deformers.size() - 1)); reweightedDeformers.indices.resize(numClusterIndices, (uint16_t)(skinClusters.size() - 1));
reweightedDeformers.weights.resize(numClusterIndices, 0); reweightedDeformers.weights.resize(numClusterIndices, 0);
std::vector<float> weightAccumulators; std::vector<float> weightAccumulators;
weightAccumulators.resize(numClusterIndices, 0.0f); weightAccumulators.resize(numClusterIndices, 0.0f);
for (uint16_t i = 0; i < (uint16_t)deformers.size(); ++i) { for (uint16_t i = 0; i < (uint16_t)skinClusters.size(); ++i) {
const hfm::Deformer& deformer = *deformers[i]; const hfm::SkinCluster& skinCluster = *skinClusters[i];
if (deformer.indices.size() != deformer.weights.size()) { if (skinCluster.indices.size() != skinCluster.weights.size()) {
reweightedDeformers.trimmedToMatch = true; reweightedDeformers.trimmedToMatch = true;
} }
size_t numIndicesOrWeights = std::min(deformer.indices.size(), deformer.weights.size()); size_t numIndicesOrWeights = std::min(skinCluster.indices.size(), skinCluster.weights.size());
for (size_t j = 0; j < numIndicesOrWeights; ++j) { for (size_t j = 0; j < numIndicesOrWeights; ++j) {
uint32_t index = deformer.indices[j]; uint32_t index = skinCluster.indices[j];
float weight = deformer.weights[j]; float weight = skinCluster.weights[j];
// look for an unused slot in the weights vector // look for an unused slot in the weights vector
uint32_t weightIndex = index * weightsPerVertex; uint32_t weightIndex = index * weightsPerVertex;
@ -90,34 +90,34 @@ void ReweightDeformersTask::run(const baker::BakeContextPointer& context, const
const auto& meshes = input.get0(); const auto& meshes = input.get0();
const auto& shapes = input.get1(); const auto& shapes = input.get1();
const auto& dynamicTransforms = input.get2(); const auto& skinDeformers = input.get2();
const auto& deformers = input.get3(); const auto& skinClusters = input.get3();
auto& reweightedDeformers = output; auto& reweightedDeformers = output;
// Currently, there is only (at most) one dynamicTransform per mesh // Currently, there is only (at most) one skinDeformer per mesh
// An undefined shape.dynamicTransform has the value hfm::UNDEFINED_KEY // An undefined shape.skinDeformer has the value hfm::UNDEFINED_KEY
std::vector<uint32_t> dynamicTransformPerMesh; std::vector<uint32_t> skinDeformerPerMesh;
dynamicTransformPerMesh.resize(meshes.size(), hfm::UNDEFINED_KEY); skinDeformerPerMesh.resize(meshes.size(), hfm::UNDEFINED_KEY);
for (const auto& shape : shapes) { for (const auto& shape : shapes) {
uint32_t dynamicTransformIndex = shape.dynamicTransform; uint32_t skinDeformerIndex = shape.skinDeformer;
dynamicTransformPerMesh[shape.mesh] = dynamicTransformIndex; skinDeformerPerMesh[shape.mesh] = skinDeformerIndex;
} }
reweightedDeformers.reserve(meshes.size()); reweightedDeformers.reserve(meshes.size());
for (size_t i = 0; i < meshes.size(); ++i) { for (size_t i = 0; i < meshes.size(); ++i) {
const auto& mesh = meshes[i]; const auto& mesh = meshes[i];
uint32_t dynamicTransformIndex = dynamicTransformPerMesh[i]; uint32_t skinDeformerIndex = skinDeformerPerMesh[i];
const hfm::DynamicTransform* dynamicTransform = nullptr; const hfm::SkinDeformer* skinDeformer = nullptr;
std::vector<const hfm::Deformer*> meshDeformers; std::vector<const hfm::SkinCluster*> meshSkinClusters;
if (dynamicTransformIndex != hfm::UNDEFINED_KEY) { if (skinDeformerIndex != hfm::UNDEFINED_KEY) {
dynamicTransform = &dynamicTransforms[dynamicTransformIndex]; skinDeformer = &skinDeformers[skinDeformerIndex];
for (const auto& deformerIndex : dynamicTransform->deformers) { for (const auto& skinClusterIndex : skinDeformer->skinClusterIndices) {
const auto& deformer = deformers[deformerIndex]; const auto& skinCluster = skinClusters[skinClusterIndex];
meshDeformers.push_back(&deformer); meshSkinClusters.push_back(&skinCluster);
} }
} }
reweightedDeformers.push_back(getReweightedDeformers((size_t)mesh.vertices.size(), meshDeformers, NUM_WEIGHTS_PER_VERTEX)); reweightedDeformers.push_back(getReweightedDeformers((size_t)mesh.vertices.size(), meshSkinClusters, NUM_WEIGHTS_PER_VERTEX));
} }
} }

View file

@ -19,7 +19,7 @@
class ReweightDeformersTask { class ReweightDeformersTask {
public: public:
using Input = baker::VaryingSet4<std::vector<hfm::Mesh>, std::vector<hfm::Shape>, std::vector<hfm::DynamicTransform>, std::vector<hfm::Deformer>>; using Input = baker::VaryingSet4<std::vector<hfm::Mesh>, std::vector<hfm::Shape>, std::vector<hfm::SkinDeformer>, std::vector<hfm::SkinCluster>>;
using Output = std::vector<baker::ReweightedDeformers>; using Output = std::vector<baker::ReweightedDeformers>;
using JobModel = baker::Job::ModelIO<ReweightDeformersTask, Input, Output>; using JobModel = baker::Job::ModelIO<ReweightDeformersTask, Input, Output>;

View file

@ -295,7 +295,6 @@ void ModelResource::onGeometryMappingLoaded(bool success) {
if (success && _modelResource) { if (success && _modelResource) {
_hfmModel = _modelResource->_hfmModel; _hfmModel = _modelResource->_hfmModel;
_materialMapping = _modelResource->_materialMapping; _materialMapping = _modelResource->_materialMapping;
// _meshParts = _modelResource->_meshParts;
_meshes = _modelResource->_meshes; _meshes = _modelResource->_meshes;
_materials = _modelResource->_materials; _materials = _modelResource->_materials;

View file

@ -18,8 +18,8 @@
using namespace render; using namespace render;
CauterizedMeshPartPayload::CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) CauterizedMeshPartPayload::CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform)
: ModelMeshPartPayload(model, meshIndex, partIndex, shapeIndex, transform, offsetTransform) {} : ModelMeshPartPayload(model, meshIndex, partIndex, shapeIndex, transform) {}
void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices, void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices,
const std::vector<glm::mat4>& cauterizedClusterMatrices) { const std::vector<glm::mat4>& cauterizedClusterMatrices) {

View file

@ -13,7 +13,7 @@
class CauterizedMeshPartPayload : public ModelMeshPartPayload { class CauterizedMeshPartPayload : public ModelMeshPartPayload {
public: public:
CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform); CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform);
// matrix palette skinning // matrix palette skinning
void updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices, void updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices,

View file

@ -32,8 +32,40 @@ bool CauterizedModel::updateGeometry() {
bool needsFullUpdate = Model::updateGeometry(); bool needsFullUpdate = Model::updateGeometry();
if (_isCauterized && needsFullUpdate) { if (_isCauterized && needsFullUpdate) {
assert(_cauterizeMeshStates.empty()); assert(_cauterizeMeshStates.empty());
/* const HFMModel& hfmModel = getHFMModel();
const auto& hfmDynamicTransforms = hfmModel.skinDeformers;
for (int i = 0; i < hfmDynamicTransforms.size(); i++) {
const auto& dynT = hfmDynamicTransforms[i];
MeshState state;
if (_useDualQuaternionSkinning) {
state.clusterDualQuaternions.resize(dynT.clusters.size());
} else {
state.clusterMatrices.resize(dynT.clusters.size());
}
_cauterizeMeshStates.append(state);
_meshStates.push_back(state);
}*/
const HFMModel& hfmModel = getHFMModel(); const HFMModel& hfmModel = getHFMModel();
foreach (const HFMMesh& mesh, hfmModel.meshes) { const auto& hfmDynamicTransforms = hfmModel.skinDeformers;
int i = 0;
/* for (const auto& mesh: hfmModel.meshes) {
MeshState state;
state.clusterDualQuaternions.resize(mesh.clusters.size());
state.clusterMatrices.resize(mesh.clusters.size());
_meshStates.push_back(state);
i++;
}
*/
for (int i = 0; i < hfmDynamicTransforms.size(); i++) {
const auto& dynT = hfmDynamicTransforms[i];
MeshState state;
state.clusterDualQuaternions.resize(dynT.clusters.size());
state.clusterMatrices.resize(dynT.clusters.size());
_cauterizeMeshStates.push_back(state);
}
/* foreach (const HFMMesh& mesh, hfmModel.meshes) {
Model::MeshState state; Model::MeshState state;
if (_useDualQuaternionSkinning) { if (_useDualQuaternionSkinning) {
state.clusterDualQuaternions.resize(mesh.clusters.size()); state.clusterDualQuaternions.resize(mesh.clusters.size());
@ -42,7 +74,7 @@ bool CauterizedModel::updateGeometry() {
state.clusterMatrices.resize(mesh.clusters.size()); state.clusterMatrices.resize(mesh.clusters.size());
_cauterizeMeshStates.append(state); _cauterizeMeshStates.append(state);
} }
} }*/
} }
return needsFullUpdate; return needsFullUpdate;
} }
@ -52,11 +84,6 @@ void CauterizedModel::createRenderItemSet() {
assert(isLoaded()); assert(isLoaded());
const auto& meshes = _renderGeometry->getMeshes(); const auto& meshes = _renderGeometry->getMeshes();
// all of our mesh vectors must match in size
if (meshes.size() != _meshStates.size()) {
qCDebug(renderutils) << "WARNING!!!! Mesh Sizes don't match! We will not segregate mesh groups yet.";
return;
}
// We should not have any existing renderItems if we enter this section of code // We should not have any existing renderItems if we enter this section of code
Q_ASSERT(_modelMeshRenderItems.isEmpty()); Q_ASSERT(_modelMeshRenderItems.isEmpty());
@ -73,8 +100,23 @@ void CauterizedModel::createRenderItemSet() {
offset.setScale(_scale); offset.setScale(_scale);
offset.postTranslate(_offset); offset.postTranslate(_offset);
Transform::mult(transform, transform, offset);
// Run through all of the meshes, and place them into their segregated, but unsorted buckets // Run through all of the meshes, and place them into their segregated, but unsorted buckets
// Run through all of the meshes, and place them into their segregated, but unsorted buckets
int shapeID = 0; int shapeID = 0;
const auto& shapes = _renderGeometry->getHFMModel().shapes;
for (shapeID; shapeID < shapes.size(); shapeID++) {
const auto& shape = shapes[shapeID];
_modelMeshRenderItems << std::make_shared<CauterizedMeshPartPayload>(shared_from_this(), shape.mesh, shape.meshPart, shapeID, transform);
auto material = getNetworkModel()->getShapeMaterial(shapeID);
_modelMeshMaterialNames.push_back(material ? material->getName() : "");
_modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)shape.mesh, shape.skinDeformer });
}
/* int shapeID = 0;
uint32_t numMeshes = (uint32_t)meshes.size(); uint32_t numMeshes = (uint32_t)meshes.size();
for (uint32_t i = 0; i < numMeshes; i++) { for (uint32_t i = 0; i < numMeshes; i++) {
const auto& mesh = meshes.at(i); const auto& mesh = meshes.at(i);
@ -85,14 +127,14 @@ void CauterizedModel::createRenderItemSet() {
// Create the render payloads // Create the render payloads
int numParts = (int)mesh->getNumParts(); int numParts = (int)mesh->getNumParts();
for (int partIndex = 0; partIndex < numParts; partIndex++) { for (int partIndex = 0; partIndex < numParts; partIndex++) {
auto ptr = std::make_shared<CauterizedMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset); auto ptr = std::make_shared<CauterizedMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform);
_modelMeshRenderItems << std::static_pointer_cast<ModelMeshPartPayload>(ptr); _modelMeshRenderItems << std::static_pointer_cast<ModelMeshPartPayload>(ptr);
auto material = getNetworkModel()->getShapeMaterial(shapeID); auto material = getNetworkModel()->getShapeMaterial(shapeID);
_modelMeshMaterialNames.push_back(material ? material->getName() : ""); _modelMeshMaterialNames.push_back(material ? material->getName() : "");
_modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i }); _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i });
shapeID++; shapeID++;
} }
} }*/
} else { } else {
Model::createRenderItemSet(); Model::createRenderItemSet();
} }
@ -108,6 +150,38 @@ void CauterizedModel::updateClusterMatrices() {
updateShapeStatesFromRig(); updateShapeStatesFromRig();
_needsUpdateClusterMatrices = false; _needsUpdateClusterMatrices = false;
const HFMModel& hfmModel = getHFMModel();
const auto& hfmDynamicTransforms = hfmModel.skinDeformers;
for (int i = 0; i < (int)_meshStates.size(); i++) {
MeshState& state = _meshStates[i];
const auto& deformer = hfmDynamicTransforms[i];
int meshIndex = i;
int clusterIndex = 0;
for (int d = 0; d < deformer.clusters.size(); d++) {
const auto& cluster = deformer.clusters[d];
clusterIndex = d;
const auto& cbmov = _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex);
if (_useDualQuaternionSkinning) {
auto jointPose = _rig.getJointPose(cluster.jointIndex);
Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans());
Transform clusterTransform;
Transform::mult(clusterTransform, jointTransform, cbmov.inverseBindTransform);
state.clusterDualQuaternions[d] = Model::TransformDualQuaternion(clusterTransform);
}
else {
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
glm_mat4u_mul(jointMatrix, cbmov.inverseBindMatrix, state.clusterMatrices[d]);
}
}
}
/*
const HFMModel& hfmModel = getHFMModel(); const HFMModel& hfmModel = getHFMModel();
for (int i = 0; i < (int)_meshStates.size(); i++) { for (int i = 0; i < (int)_meshStates.size(); i++) {
Model::MeshState& state = _meshStates[i]; Model::MeshState& state = _meshStates[i];
@ -131,7 +205,7 @@ void CauterizedModel::updateClusterMatrices() {
} }
} }
} }
*/
// as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty. // as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty.
if (!_cauterizeBoneSet.empty()) { if (!_cauterizeBoneSet.empty()) {
@ -224,64 +298,69 @@ void CauterizedModel::updateRenderItems() {
auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex; auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex;
const auto& shapeState = self->getShapeState(i); const auto& shapeState = self->getShapeState(i);
const auto& meshState = self->getMeshState(meshIndex);
const auto& cauterizedMeshState = self->getCauterizeMeshState(meshIndex); auto deformerIndex = self->_modelMeshRenderItemShapes[i].deformerIndex;
bool isDeformed = (deformerIndex != hfm::UNDEFINED_KEY);
// auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex;
// auto deformerIndex = self->_modelMeshRenderItemShapes[i].meshIndex;
// const auto& shapeState = self->getShapeState(i);
bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, shapeState, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey,
primitiveMode, renderItemKeyGlobalFlags, enableCauterization](ModelMeshPartPayload& mmppData) {
CauterizedMeshPartPayload& data = static_cast<CauterizedMeshPartPayload&>(mmppData);
if (useDualQuaternionSkinning) {
data.updateClusterBuffer(meshState.clusterDualQuaternions,
cauterizedMeshState.clusterDualQuaternions);
data.computeAdjustedLocalBound(meshState.clusterDualQuaternions);
} else {
data.updateClusterBuffer(meshState.clusterMatrices,
cauterizedMeshState.clusterMatrices);
data.computeAdjustedLocalBound(meshState.clusterMatrices);
}
Transform renderTransform = modelTransform;
/*if (useDualQuaternionSkinning) { if (isDeformed) {
if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) {
const auto& dq = meshState.clusterDualQuaternions[0]; const auto& meshState = self->getMeshState(deformerIndex);
Transform transform(dq.getRotation(), const auto& cauterizedMeshState = self->getCauterizeMeshState(deformerIndex);
dq.getScale(),
dq.getTranslation()); transaction.updateItem<ModelMeshPartPayload>(itemID,
renderTransform = modelTransform.worldTransform(transform); [modelTransform, shapeState, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey,
} primitiveMode, renderItemKeyGlobalFlags, enableCauterization](ModelMeshPartPayload& mmppData) {
} else { CauterizedMeshPartPayload& data = static_cast<CauterizedMeshPartPayload&>(mmppData);
if (meshState.clusterMatrices.size() == 1 || meshState.clusterMatrices.size() == 2) { if (useDualQuaternionSkinning) {
renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0])); data.updateClusterBuffer(meshState.clusterDualQuaternions,
} cauterizedMeshState.clusterDualQuaternions);
}*/ } else {
if (meshState.clusterMatrices.size() <= 1) { data.updateClusterBuffer(meshState.clusterMatrices,
cauterizedMeshState.clusterMatrices);
}
Transform renderTransform = modelTransform;
// if (meshState.clusterMatrices.size() <= 2) {
// renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform);
// }
data.updateTransform(renderTransform);
data.updateTransformForCauterizedMesh(renderTransform);
data.updateTransformAndBound(modelTransform.worldTransform(shapeState._rootFromJointTransform));
data.setEnableCauterization(enableCauterization);
data.updateKey(renderItemKeyGlobalFlags);
data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning);
});
} else {
transaction.updateItem<ModelMeshPartPayload>(itemID,
[modelTransform, shapeState, invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, enableCauterization]
(ModelMeshPartPayload& mmppData) {
CauterizedMeshPartPayload& data = static_cast<CauterizedMeshPartPayload&>(mmppData);
Transform renderTransform = modelTransform;
renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform); renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform);
} data.updateTransform(renderTransform);
data.updateTransformForSkinnedMesh(renderTransform, modelTransform); data.updateTransformForCauterizedMesh(renderTransform);
renderTransform = modelTransform; data.setEnableCauterization(enableCauterization);
if (useDualQuaternionSkinning) { data.updateKey(renderItemKeyGlobalFlags);
if (cauterizedMeshState.clusterDualQuaternions.size() == 1 || cauterizedMeshState.clusterDualQuaternions.size() == 2) { data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, false);
const auto& dq = cauterizedMeshState.clusterDualQuaternions[0]; });
Transform transform(dq.getRotation(),
dq.getScale(), }
dq.getTranslation());
renderTransform = modelTransform.worldTransform(Transform(transform));
}
} else {
if (cauterizedMeshState.clusterMatrices.size() == 1 || cauterizedMeshState.clusterMatrices.size() == 2) {
renderTransform = modelTransform.worldTransform(Transform(cauterizedMeshState.clusterMatrices[0]));
}
}
data.updateTransformForCauterizedMesh(renderTransform);
data.setEnableCauterization(enableCauterization);
data.updateKey(renderItemKeyGlobalFlags);
data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning);
});
} }
scene->enqueueTransaction(transaction); scene->enqueueTransaction(transaction);

View file

@ -64,11 +64,15 @@ void MeshPartPayload::updateMeshPart(const std::shared_ptr<const graphics::Mesh>
} }
} }
void MeshPartPayload::updateTransform(const Transform& transform, const Transform& offsetTransform) { void MeshPartPayload::updateTransform(const Transform& transform) {
_transform = transform; _worldFromLocalTransform = transform;
Transform::mult(_drawTransform, _transform, offsetTransform);
_worldBound = _localBound; _worldBound = _localBound;
_worldBound.transform(_drawTransform); _worldBound.transform(_worldFromLocalTransform);
}
void MeshPartPayload::updateTransformAndBound(const Transform& transform) {
_worldBound = _localBound;
_worldBound.transform(transform);
} }
void MeshPartPayload::addMaterial(graphics::MaterialLayer material) { void MeshPartPayload::addMaterial(graphics::MaterialLayer material) {
@ -134,7 +138,7 @@ void MeshPartPayload::bindMesh(gpu::Batch& batch) {
} }
void MeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const { void MeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const {
batch.setModelTransform(_drawTransform); batch.setModelTransform(_worldFromLocalTransform);
} }
@ -196,7 +200,7 @@ template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, Ren
} }
ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) : ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform) :
_meshIndex(meshIndex), _meshIndex(meshIndex),
_shapeID(shapeIndex) { _shapeID(shapeIndex) {
@ -210,38 +214,16 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in
auto& modelMesh = model->getNetworkModel()->getMeshes().at(_meshIndex); auto& modelMesh = model->getNetworkModel()->getMeshes().at(_meshIndex);
_meshNumVertices = (int)modelMesh->getNumVertices(); _meshNumVertices = (int)modelMesh->getNumVertices();
const Model::MeshState& state = model->getMeshState(_meshIndex); // const Model::MeshState& state = model->getMeshState(_meshIndex);
updateMeshPart(modelMesh, partIndex); updateMeshPart(modelMesh, partIndex);
if (useDualQuaternionSkinning) { Transform renderTransform = transform;
computeAdjustedLocalBound(state.clusterDualQuaternions);
} else {
computeAdjustedLocalBound(state.clusterMatrices);
}
updateTransform(transform, offsetTransform);
Transform renderTransform = transform;
/* if (useDualQuaternionSkinning) {
if (state.clusterDualQuaternions.size() == 1) {
const auto& dq = state.clusterDualQuaternions[0];
Transform transform(dq.getRotation(),
dq.getScale(),
dq.getTranslation());
renderTransform = transform.worldTransform(Transform(transform));
}
} else {
if (state.clusterMatrices.size() == 1) {
renderTransform = transform.worldTransform(Transform(state.clusterMatrices[0]));
}
}
*/
const Model::ShapeState& shapeState = model->getShapeState(shapeIndex); const Model::ShapeState& shapeState = model->getShapeState(shapeIndex);
renderTransform = transform.worldTransform(shapeState._rootFromJointTransform); renderTransform = transform.worldTransform(shapeState._rootFromJointTransform);
updateTransformForSkinnedMesh(renderTransform, transform); updateTransform(renderTransform);
_deformerIndex = shape.skinDeformer;
initCache(model); initCache(model);
@ -264,7 +246,9 @@ void ModelMeshPartPayload::initCache(const ModelPointer& model) {
if (_drawMesh) { if (_drawMesh) {
auto vertexFormat = _drawMesh->getVertexFormat(); auto vertexFormat = _drawMesh->getVertexFormat();
_hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR); _hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR);
_isSkinned = vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT) && vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_INDEX); if (_deformerIndex != hfm::UNDEFINED_KEY) {
_isSkinned = vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT) && vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_INDEX);
}
const HFMModel& hfmModel = model->getHFMModel(); const HFMModel& hfmModel = model->getHFMModel();
const HFMMesh& mesh = hfmModel.meshes.at(_meshIndex); const HFMMesh& mesh = hfmModel.meshes.at(_meshIndex);
@ -323,13 +307,6 @@ void ModelMeshPartPayload::updateClusterBuffer(const std::vector<Model::Transfor
} }
} }
void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform) {
_transform = renderTransform;
_worldBound = _adjustedLocalBound;
// _worldBound.transform(boundTransform);
_worldBound.transform(renderTransform);
}
// Note that this method is called for models but not for shapes // Note that this method is called for models but not for shapes
void ModelMeshPartPayload::updateKey(const render::ItemKey& key) { void ModelMeshPartPayload::updateKey(const render::ItemKey& key) {
ItemKey::Builder builder(key); ItemKey::Builder builder(key);
@ -420,7 +397,7 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMo
if (_clusterBuffer) { if (_clusterBuffer) {
batch.setUniformBuffer(graphics::slot::buffer::Skinning, _clusterBuffer); batch.setUniformBuffer(graphics::slot::buffer::Skinning, _clusterBuffer);
} }
batch.setModelTransform(_transform); batch.setModelTransform(_worldFromLocalTransform);
} }
void ModelMeshPartPayload::render(RenderArgs* args) { void ModelMeshPartPayload::render(RenderArgs* args) {
@ -458,38 +435,6 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE; args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE;
} }
void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<glm::mat4>& clusterMatrices) {
_adjustedLocalBound = _localBound;
if (clusterMatrices.size() > 0) {
_adjustedLocalBound.transform(clusterMatrices.back());
for (int i = 0; i < (int)clusterMatrices.size() - 1; ++i) {
AABox clusterBound = _localBound;
clusterBound.transform(clusterMatrices[i]);
_adjustedLocalBound += clusterBound;
}
}
}
void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions) {
_adjustedLocalBound = _localBound;
if (clusterDualQuaternions.size() > 0) {
Transform rootTransform(clusterDualQuaternions.back().getRotation(),
clusterDualQuaternions.back().getScale(),
clusterDualQuaternions.back().getTranslation());
_adjustedLocalBound.transform(rootTransform);
for (int i = 0; i < (int)clusterDualQuaternions.size() - 1; ++i) {
AABox clusterBound = _localBound;
Transform transform(clusterDualQuaternions[i].getRotation(),
clusterDualQuaternions[i].getScale(),
clusterDualQuaternions[i].getTranslation());
clusterBound.transform(transform);
_adjustedLocalBound += clusterBound;
}
}
}
void ModelMeshPartPayload::setBlendshapeBuffer(const std::unordered_map<int, gpu::BufferPointer>& blendshapeBuffers, const QVector<int>& blendedMeshSizes) { void ModelMeshPartPayload::setBlendshapeBuffer(const std::unordered_map<int, gpu::BufferPointer>& blendshapeBuffers, const QVector<int>& blendedMeshSizes) {
if (_meshIndex < blendedMeshSizes.length() && blendedMeshSizes.at(_meshIndex) == _meshNumVertices) { if (_meshIndex < blendedMeshSizes.length() && blendedMeshSizes.at(_meshIndex) == _meshNumVertices) {
auto blendshapeBuffer = blendshapeBuffers.find(_meshIndex); auto blendshapeBuffer = blendshapeBuffers.find(_meshIndex);

View file

@ -38,7 +38,8 @@ public:
virtual void updateMeshPart(const std::shared_ptr<const graphics::Mesh>& drawMesh, int partIndex); virtual void updateMeshPart(const std::shared_ptr<const graphics::Mesh>& drawMesh, int partIndex);
virtual void notifyLocationChanged() {} virtual void notifyLocationChanged() {}
void updateTransform(const Transform& transform, const Transform& offsetTransform); void updateTransform(const Transform& transform);
void updateTransformAndBound(const Transform& transform );
// Render Item interface // Render Item interface
virtual render::ItemKey getKey() const; virtual render::ItemKey getKey() const;
@ -52,13 +53,11 @@ public:
virtual void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const; virtual void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const;
// Payload resource cached values // Payload resource cached values
Transform _drawTransform; Transform _worldFromLocalTransform;
Transform _transform;
int _partIndex = 0; int _partIndex = 0;
bool _hasColorAttrib { false }; bool _hasColorAttrib { false };
graphics::Box _localBound; graphics::Box _localBound;
graphics::Box _adjustedLocalBound;
mutable graphics::Box _worldBound; mutable graphics::Box _worldBound;
std::shared_ptr<const graphics::Mesh> _drawMesh; std::shared_ptr<const graphics::Mesh> _drawMesh;
@ -86,7 +85,7 @@ namespace render {
class ModelMeshPartPayload : public MeshPartPayload { class ModelMeshPartPayload : public MeshPartPayload {
public: public:
ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform); ModelMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform);
typedef render::Payload<ModelMeshPartPayload> Payload; typedef render::Payload<ModelMeshPartPayload> Payload;
typedef Payload::DataPointer Pointer; typedef Payload::DataPointer Pointer;
@ -100,7 +99,6 @@ public:
// dual quaternion skinning // dual quaternion skinning
void updateClusterBuffer(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions); void updateClusterBuffer(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions);
void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform);
// Render Item interface // Render Item interface
render::ShapeKey getShapeKey() const override; // shape interface render::ShapeKey getShapeKey() const override; // shape interface
@ -113,12 +111,6 @@ public:
void bindMesh(gpu::Batch& batch) override; void bindMesh(gpu::Batch& batch) override;
void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const override; void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const override;
// matrix palette skinning
void computeAdjustedLocalBound(const std::vector<glm::mat4>& clusterMatrices);
// dual quaternion skinning
void computeAdjustedLocalBound(const std::vector<Model::TransformDualQuaternion>& clusterDualQuaternions);
gpu::BufferPointer _clusterBuffer; gpu::BufferPointer _clusterBuffer;
enum class ClusterBufferType { Matrices, DualQuaternions }; enum class ClusterBufferType { Matrices, DualQuaternions };
@ -126,6 +118,7 @@ public:
int _meshIndex; int _meshIndex;
int _shapeID; int _shapeID;
int _deformerIndex;
bool _isSkinned{ false }; bool _isSkinned{ false };
bool _isBlendShaped { false }; bool _isBlendShaped { false };

View file

@ -186,7 +186,7 @@ bool Model::shouldInvalidatePayloadShapeKey(int meshIndex) {
const auto& networkMeshes = getNetworkModel()->getMeshes(); const auto& networkMeshes = getNetworkModel()->getMeshes();
// if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown
// to false to rebuild out mesh groups. // to false to rebuild out mesh groups.
if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)hfmModel.meshes.size() || meshIndex >= (int)_meshStates.size()) { if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)hfmModel.meshes.size() /* || meshIndex >= (int)_meshStates.size()*/) {
_needsFixupInScene = true; // trigger remove/add cycle _needsFixupInScene = true; // trigger remove/add cycle
invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid
return true; return true;
@ -233,45 +233,52 @@ void Model::updateRenderItems() {
auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex; auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex;
const auto& shapeState = self->getShapeState(i); const auto& shapeState = self->getShapeState(i);
const auto& meshState = self->getMeshState(meshIndex);
auto deformerIndex = self->_modelMeshRenderItemShapes[i].deformerIndex;
bool isDeformed = (deformerIndex != hfm::UNDEFINED_KEY);
bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex); bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, shapeState, meshState, useDualQuaternionSkinning,
invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, cauterized](ModelMeshPartPayload& data) { if (isDeformed) {
if (useDualQuaternionSkinning) {
data.updateClusterBuffer(meshState.clusterDualQuaternions);
data.computeAdjustedLocalBound(meshState.clusterDualQuaternions);
} else {
data.updateClusterBuffer(meshState.clusterMatrices);
data.computeAdjustedLocalBound(meshState.clusterMatrices);
}
Transform renderTransform = modelTransform; const auto& meshState = self->getMeshState(deformerIndex);
// MeshState meshState;
bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
/*if (useDualQuaternionSkinning) {
if (meshState.clusterDualQuaternions.size() == 1 || meshState.clusterDualQuaternions.size() == 2) { transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, shapeState, meshState, useDualQuaternionSkinning,
const auto& dq = meshState.clusterDualQuaternions[0]; invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags, cauterized](ModelMeshPartPayload& data) {
Transform transform(dq.getRotation(), if (useDualQuaternionSkinning) {
dq.getScale(), data.updateClusterBuffer(meshState.clusterDualQuaternions);
dq.getTranslation()); } else {
renderTransform = modelTransform.worldTransform(Transform(transform)); data.updateClusterBuffer(meshState.clusterMatrices);
} }
} else {
if (meshState.clusterMatrices.size() == 1 || meshState.clusterMatrices.size() == 2) { Transform renderTransform = modelTransform;
renderTransform = modelTransform.worldTransform(Transform(meshState.clusterMatrices[0])); // if (meshState.clusterMatrices.size() <= 1) {
} // renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform);
}*/ // }
if (meshState.clusterMatrices.size() <= 1) { data.updateTransform(renderTransform);
data.updateTransformAndBound(modelTransform.worldTransform(shapeState._rootFromJointTransform));
data.setCauterized(cauterized);
data.updateKey(renderItemKeyGlobalFlags);
data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning);
});
} else {
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, shapeState, invalidatePayloadShapeKey, primitiveMode, renderItemKeyGlobalFlags](ModelMeshPartPayload& data) {
Transform renderTransform = modelTransform;
// if (meshState.clusterMatrices.size() <= 1) {
renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform); renderTransform = modelTransform.worldTransform(shapeState._rootFromJointTransform);
} // }
data.updateTransformForSkinnedMesh(renderTransform, modelTransform); data.updateTransform(renderTransform);
data.setCauterized(cauterized); data.updateKey(renderItemKeyGlobalFlags);
data.updateKey(renderItemKeyGlobalFlags); data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, false);
data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning); });
}); }
} }
AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction);
@ -304,9 +311,9 @@ void Model::updateShapeStatesFromRig() {
const auto& shapes = hfmModel.shapes; const auto& shapes = hfmModel.shapes;
_shapeStates.resize(shapes.size()); _shapeStates.resize(shapes.size());
for (int s = 0; s < shapes.size(); ++s) { for (int s = 0; s < shapes.size(); ++s) {
uint32_t jointId = shapes[s].transform; uint32_t jointId = shapes[s].joint;
if (jointId < _rig.getJointStateCount()) { if (jointId < (uint32_t) _rig.getJointStateCount()) {
_shapeStates[s]._rootFromJointTransform = _rig.getJointTransform(shapes[s].transform); _shapeStates[s]._rootFromJointTransform = _rig.getJointTransform(jointId);
} }
} }
} }
@ -329,14 +336,24 @@ bool Model::updateGeometry() {
updateShapeStatesFromRig(); updateShapeStatesFromRig();
const HFMModel& hfmModel = getHFMModel(); const HFMModel& hfmModel = getHFMModel();
const auto& hfmSkinDeformers = hfmModel.skinDeformers;
int i = 0; int i = 0;
foreach (const HFMMesh& mesh, hfmModel.meshes) { /* for (const auto& mesh: hfmModel.meshes) {
MeshState state; MeshState state;
state.clusterDualQuaternions.resize(mesh.clusters.size()); state.clusterDualQuaternions.resize(mesh.clusters.size());
state.clusterMatrices.resize(mesh.clusters.size()); state.clusterMatrices.resize(mesh.clusters.size());
_meshStates.push_back(state); _meshStates.push_back(state);
i++; i++;
} }
*/
for (int i = 0; i < hfmSkinDeformers.size(); i++) {
const auto& dynT = hfmSkinDeformers[i];
MeshState state;
state.clusterDualQuaternions.resize(dynT.clusters.size());
state.clusterMatrices.resize(dynT.clusters.size());
_meshStates.push_back(state);
}
needFullUpdate = true; needFullUpdate = true;
emit rigReady(); emit rigReady();
} }
@ -1410,8 +1427,34 @@ void Model::updateClusterMatrices() {
_needsUpdateClusterMatrices = false; _needsUpdateClusterMatrices = false;
const HFMModel& hfmModel = getHFMModel(); const HFMModel& hfmModel = getHFMModel();
const auto& hfmSkinDeformers = hfmModel.skinDeformers;
for (int i = 0; i < (int) _meshStates.size(); i++) { for (int i = 0; i < (int) _meshStates.size(); i++) {
MeshState& state = _meshStates[i]; MeshState& state = _meshStates[i];
const auto& deformer = hfmSkinDeformers[i];
int meshIndex = i;
int clusterIndex = 0;
for (int d = 0; d < deformer.clusters.size(); d++) {
const auto& cluster = deformer.clusters[d];
clusterIndex = d;
const auto& cbmov = _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex);
if (_useDualQuaternionSkinning) {
auto jointPose = _rig.getJointPose(cluster.jointIndex);
Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans());
Transform clusterTransform;
Transform::mult(clusterTransform, jointTransform, cbmov.inverseBindTransform);
state.clusterDualQuaternions[d] = Model::TransformDualQuaternion(clusterTransform);
}
else {
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
glm_mat4u_mul(jointMatrix, cbmov.inverseBindMatrix, state.clusterMatrices[d]);
}
}
/*
int meshIndex = i; int meshIndex = i;
const HFMMesh& mesh = hfmModel.meshes.at(i); const HFMMesh& mesh = hfmModel.meshes.at(i);
for (int j = 0; j < mesh.clusters.size(); j++) { for (int j = 0; j < mesh.clusters.size(); j++) {
@ -1428,7 +1471,7 @@ void Model::updateClusterMatrices() {
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex); auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
glm_mat4u_mul(jointMatrix, _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex).inverseBindMatrix, state.clusterMatrices[j]); glm_mat4u_mul(jointMatrix, _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex).inverseBindMatrix, state.clusterMatrices[j]);
} }
} }*/
} }
// post the blender if we're not currently waiting for one to finish // post the blender if we're not currently waiting for one to finish
@ -1477,12 +1520,6 @@ void Model::createRenderItemSet() {
assert(isLoaded()); assert(isLoaded());
const auto& meshes = _renderGeometry->getMeshes(); const auto& meshes = _renderGeometry->getMeshes();
// all of our mesh vectors must match in size
if (meshes.size() != _meshStates.size()) {
qCDebug(renderutils) << "WARNING!!!! Mesh Sizes don't match! " << meshes.size() << _meshStates.size() << " We will not segregate mesh groups yet.";
return;
}
// We should not have any existing renderItems if we enter this section of code // We should not have any existing renderItems if we enter this section of code
Q_ASSERT(_modelMeshRenderItems.isEmpty()); Q_ASSERT(_modelMeshRenderItems.isEmpty());
@ -1500,6 +1537,17 @@ void Model::createRenderItemSet() {
// Run through all of the meshes, and place them into their segregated, but unsorted buckets // Run through all of the meshes, and place them into their segregated, but unsorted buckets
int shapeID = 0; int shapeID = 0;
const auto& shapes = _renderGeometry->getHFMModel().shapes;
for (shapeID; shapeID < shapes.size(); shapeID++) {
const auto& shape = shapes[shapeID];
_modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), shape.mesh, shape.meshPart, shapeID, transform);
auto material = getNetworkModel()->getShapeMaterial(shapeID);
_modelMeshMaterialNames.push_back(material ? material->getName() : "");
_modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)shape.mesh, shape.skinDeformer });
}
/*
uint32_t numMeshes = (uint32_t)meshes.size(); uint32_t numMeshes = (uint32_t)meshes.size();
for (uint32_t i = 0; i < numMeshes; i++) { for (uint32_t i = 0; i < numMeshes; i++) {
const auto& mesh = meshes.at(i); const auto& mesh = meshes.at(i);
@ -1510,17 +1558,17 @@ void Model::createRenderItemSet() {
// Create the render payloads // Create the render payloads
int numParts = (int)mesh->getNumParts(); int numParts = (int)mesh->getNumParts();
for (int partIndex = 0; partIndex < numParts; partIndex++) { for (int partIndex = 0; partIndex < numParts; partIndex++) {
_modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset); _modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform);
auto material = getNetworkModel()->getShapeMaterial(shapeID); auto material = getNetworkModel()->getShapeMaterial(shapeID);
_modelMeshMaterialNames.push_back(material ? material->getName() : ""); _modelMeshMaterialNames.push_back(material ? material->getName() : "");
_modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i }); _modelMeshRenderItemShapes.emplace_back(ShapeInfo{ (int)i });
shapeID++; shapeID++;
} }
} }*/
} }
bool Model::isRenderable() const { bool Model::isRenderable() const {
return (!_shapeStates.empty() && !_meshStates.empty()) || (isLoaded() && _renderGeometry->getMeshes().empty()); return (!_shapeStates.empty() /* && !_meshStates.empty()*/) || (isLoaded() && _renderGeometry->getMeshes().empty());
} }
std::set<unsigned int> Model::getMeshIDsFromMaterialID(QString parentMaterialName) { std::set<unsigned int> Model::getMeshIDsFromMaterialID(QString parentMaterialName) {

View file

@ -473,7 +473,7 @@ protected:
QVector<std::shared_ptr<ModelMeshPartPayload>> _modelMeshRenderItems; QVector<std::shared_ptr<ModelMeshPartPayload>> _modelMeshRenderItems;
QMap<render::ItemID, render::PayloadPointer> _modelMeshRenderItemsMap; QMap<render::ItemID, render::PayloadPointer> _modelMeshRenderItemsMap;
render::ItemIDs _modelMeshRenderItemIDs; render::ItemIDs _modelMeshRenderItemIDs;
using ShapeInfo = struct { int meshIndex; }; using ShapeInfo = struct { int meshIndex; uint32_t deformerIndex{ hfm::UNDEFINED_KEY }; };
std::vector<ShapeInfo> _modelMeshRenderItemShapes; std::vector<ShapeInfo> _modelMeshRenderItemShapes;
std::vector<std::string> _modelMeshMaterialNames; std::vector<std::string> _modelMeshMaterialNames;

View file

@ -24,6 +24,10 @@ public:
~MainWindow(); ~MainWindow();
static QWindow* findMainWindow(); static QWindow* findMainWindow();
// This offset is used for positioning children window relative to the main window.
void setDockedWidgetRelativePositionOffset(const QSize& newOffset) { _dockedWidgetRelativePositionOffset.setWidth(newOffset.width()); _dockedWidgetRelativePositionOffset.setHeight(newOffset.height()); }
QSize getDockedWidgetRelativePositionOffset() { return _dockedWidgetRelativePositionOffset; }
public slots: public slots:
void restoreGeometry(); void restoreGeometry();
void saveGeometry(); void saveGeometry();
@ -46,6 +50,7 @@ protected:
private: private:
Setting::Handle<QRect> _windowGeometry; Setting::Handle<QRect> _windowGeometry;
Setting::Handle<int> _windowState; Setting::Handle<int> _windowState;
QSize _dockedWidgetRelativePositionOffset{ 0, 0 };
}; };
#endif /* defined(__hifi__MainWindow__) */ #endif /* defined(__hifi__MainWindow__) */

View file

@ -444,17 +444,9 @@ function updateEmoteIndicatorIcon(iconURL) {
} }
function onGeometryChanged(rect) {
updateEmoteAppBarPosition();
}
function onWindowMinimizedChanged(isMinimized) { function onWindowMinimizedChanged(isMinimized) {
if (isMinimized) { isWindowMinimized = isMinimized;
handleEmoteIndicatorVisibleChanged(false); maybeChangeEmoteIndicatorVisibility(!isMinimized);
} else if (!HMD.active) {
handleEmoteIndicatorVisibleChanged(true);
}
} }
@ -539,10 +531,11 @@ function showEmoteAppBar() {
x: EMOTE_APP_BAR_WIDTH_PX, x: EMOTE_APP_BAR_WIDTH_PX,
y: EMOTE_APP_BAR_HEIGHT_PX y: EMOTE_APP_BAR_HEIGHT_PX
}, },
position: { relativePosition: {
x: Window.x + EMOTE_APP_BAR_LEFT_MARGIN, x: EMOTE_APP_BAR_LEFT_MARGIN,
y: Window.y + Window.innerHeight - EMOTE_APP_BAR_BOTTOM_MARGIN y: EMOTE_APP_BAR_BOTTOM_MARGIN
}, },
relativePositionAnchor: Desktop.RelativePositionAnchor.BOTTOM_LEFT,
overrideFlags: EMOTE_APP_BAR_WINDOW_FLAGS overrideFlags: EMOTE_APP_BAR_WINDOW_FLAGS
}); });
@ -550,10 +543,18 @@ function showEmoteAppBar() {
} }
function handleEmoteIndicatorVisibleChanged(shouldBeVisible) { // There is currently no property in the Window Scripting Interface to determine
if (shouldBeVisible && !emoteAppBarWindow) { // whether the Interface window is currently minimized. This feels like an oversight.
// We should add that functionality to the Window Scripting Interface, and remove `isWindowMinimized` below.
var isWindowMinimized = false;
function maybeChangeEmoteIndicatorVisibility(desiredVisibility) {
if (isWindowMinimized || HMD.active) {
desiredVisibility = false;
}
if (desiredVisibility && !emoteAppBarWindow) {
showEmoteAppBar(); showEmoteAppBar();
} else if (emoteAppBarWindow) { } else if (!desiredVisibility && emoteAppBarWindow) {
emoteAppBarWindow.fromQml.disconnect(onMessageFromEmoteAppBar); emoteAppBarWindow.fromQml.disconnect(onMessageFromEmoteAppBar);
emoteAppBarWindow.close(); emoteAppBarWindow.close();
emoteAppBarWindow = false; emoteAppBarWindow = false;
@ -561,23 +562,25 @@ function handleEmoteIndicatorVisibleChanged(shouldBeVisible) {
} }
function handleFTUEScreensVisibilityChanged(ftueScreenVisible) {
maybeChangeEmoteIndicatorVisibility(!ftueScreenVisible);
}
function onDisplayModeChanged(isHMDMode) { function onDisplayModeChanged(isHMDMode) {
reactionsBegun.forEach(function(react) { reactionsBegun.forEach(function(react) {
endReactionWrapper(react); endReactionWrapper(react);
}); });
if (isHMDMode) { maybeChangeEmoteIndicatorVisibility(!isHMDMode);
handleEmoteIndicatorVisibleChanged(false);
} else {
handleEmoteIndicatorVisibleChanged(true);
}
} }
var emojiAPI = Script.require("./emojiApp/simplifiedEmoji.js?" + Date.now()); var emojiAPI = Script.require("./emojiApp/simplifiedEmoji.js");
var keyPressSignalsConnected = false; var keyPressSignalsConnected = false;
var emojiCodeMap; var emojiCodeMap;
var customEmojiCodeMap; var customEmojiCodeMap;
var _this;
function setup() { function setup() {
deleteOldReticles(); deleteOldReticles();
@ -605,16 +608,25 @@ function setup() {
}, {}); }, {});
Window.minimizedChanged.connect(onWindowMinimizedChanged); Window.minimizedChanged.connect(onWindowMinimizedChanged);
Window.geometryChanged.connect(onGeometryChanged);
HMD.displayModeChanged.connect(onDisplayModeChanged); HMD.displayModeChanged.connect(onDisplayModeChanged);
getSounds(); getSounds();
handleEmoteIndicatorVisibleChanged(true); maybeChangeEmoteIndicatorVisibility(true);
Controller.keyPressEvent.connect(keyPressHandler); Controller.keyPressEvent.connect(keyPressHandler);
Controller.keyReleaseEvent.connect(keyReleaseHandler); Controller.keyReleaseEvent.connect(keyReleaseHandler);
keyPressSignalsConnected = true; keyPressSignalsConnected = true;
Script.scriptEnding.connect(unload); Script.scriptEnding.connect(unload);
function Emote() {
_this = this;
}
Emote.prototype = {
handleFTUEScreensVisibilityChanged: handleFTUEScreensVisibilityChanged
};
return new Emote();
} }
@ -638,7 +650,6 @@ function unload() {
maybeDeleteRemoteIndicatorTimeout(); maybeDeleteRemoteIndicatorTimeout();
Window.minimizedChanged.disconnect(onWindowMinimizedChanged); Window.minimizedChanged.disconnect(onWindowMinimizedChanged);
Window.geometryChanged.disconnect(onGeometryChanged);
HMD.displayModeChanged.disconnect(onDisplayModeChanged); HMD.displayModeChanged.disconnect(onDisplayModeChanged);
if (keyPressSignalsConnected) { if (keyPressSignalsConnected) {
@ -671,7 +682,6 @@ function unload() {
// #region EMOJI_UTILITY // #region EMOJI_UTILITY
var EMOJI_52_BASE_URL = "../../resources/images/emojis/52px/";
function selectedEmoji(code) { function selectedEmoji(code) {
emojiAPI.addEmoji(code); emojiAPI.addEmoji(code);
// this URL needs to be relative to SimplifiedEmoteIndicator.qml // this URL needs to be relative to SimplifiedEmoteIndicator.qml
@ -786,4 +796,6 @@ function toggleEmojiApp() {
// END EMOJI // END EMOJI
// ************************************* // *************************************
setup(); var emote = setup();
module.exports = emote;

View file

@ -1,15 +1,40 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.6, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!-- Generator: Adobe Illustrator 23.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
viewBox="0 0 93.7 127.8" style="enable-background:new 0 0 93.7 127.8;" xml:space="preserve"> <!ENTITY ns_extend "http://ns.adobe.com/Extensibility/1.0/">
<path d="M91.9,97c-7.6,9.6-17.8,16.7-29.3,20.3h-0.1c-0.4,0.1-0.8,0.3-1.3,0.4c-4.6,1.3-9.5,2-14.4,2c-4.9,0-9.8-0.7-14.4-2 <!ENTITY ns_ai "http://ns.adobe.com/AdobeIllustrator/10.0/">
c-0.4-0.1-0.8-0.3-1.3-0.4h-0.1C19.6,113.8,9.4,106.6,1.8,97c0,0-0.5-0.5-0.9,0.1C0.6,97.6,1,98.5,1,98.5 <!ENTITY ns_graphs "http://ns.adobe.com/Graphs/1.0/">
C9.9,116,27,127.8,46.8,127.8l0,0c0,0,0.1,0,0.1,0c0,0,0.1,0,0.1,0l0,0c19.7-0.1,36.8-11.8,45.8-29.3c0,0,0.4-0.9,0.1-1.4 <!ENTITY ns_vars "http://ns.adobe.com/Variables/1.0/">
C92.4,96.6,91.9,97,91.9,97z M91.9,78.8C84.3,88.4,74.1,95.5,62.6,99h-0.1c-0.4,0.1-0.8,0.3-1.3,0.4c-4.6,1.3-9.5,2-14.4,2 <!ENTITY ns_imrep "http://ns.adobe.com/ImageReplacement/1.0/">
c-4.9,0-9.8-0.7-14.4-2c-0.4-0.1-0.8-0.3-1.3-0.4h-0.1C19.6,95.5,9.4,88.4,1.8,78.8c0,0-0.5-0.5-0.9,0.1C0.6,79.3,1,80.2,1,80.2 <!ENTITY ns_sfw "http://ns.adobe.com/SaveForWeb/1.0/">
c8.9,17.5,26.1,29.2,45.8,29.3l0,0c0,0,0.1,0,0.1,0c0,0,0.1,0,0.1,0l0,0c19.7-0.1,36.8-11.8,45.8-29.3c0,0,0.4-0.9,0.1-1.4 <!ENTITY ns_custom "http://ns.adobe.com/GenericCustomNamespace/1.0/">
C92.4,78.3,91.9,78.8,91.9,78.8z M46.9,92.7c25.8,0,46.9-20.7,46.9-46.4S72.7,0,46.9,0S0,20.7,0,46.4S20.9,92.7,46.9,92.7z <!ENTITY ns_adobe_xpath "http://ns.adobe.com/XPath/1.0/">
M65.5,30.8c2.8,0,5,2.2,5,5s-2.2,5-5,5c-2.8,0-5-2.2-5-5S62.8,30.8,65.5,30.8z M36,54.3c2.7,3.2,6.6,5,10.8,5s8.2-1.9,10.8-5 ]>
c0.9-1.1,2.7-1.2,3.8-0.4c1.1,0.9,1.3,2.6,0.3,3.7c-3.7,4.4-9.1,6.9-14.9,6.9c-5.8,0-11.2-2.5-14.9-6.9c-0.9-1.1-0.8-2.7,0.3-3.7 <svg version="1.1" id="Layer_1" xmlns:x="&ns_extend;" xmlns:i="&ns_ai;" xmlns:graph="&ns_graphs;"
C33.4,53.1,35,53.2,36,54.3z M28.1,30.8c2.8,0,5,2.2,5,5s-2.2,5-5,5c-2.8,0-5-2.2-5-5S25.3,30.8,28.1,30.8z"/> xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 52.8 49"
style="enable-background:new 0 0 52.8 49;" xml:space="preserve">
<style type="text/css">
.st0{opacity:0.7;}
.st1{fill:#FFFFFF;}
</style>
<metadata>
<sfw xmlns="&ns_sfw;">
<slices></slices>
<sliceSourceBounds bottomLeftOrigin="true" height="49" width="52.8" x="8.3" y="11.1"></sliceSourceBounds>
</sfw>
</metadata>
<g class="st0">
<path class="st1" d="M10.3,47.8c5.1,0.8,10.3,1.2,15.3,1.2c0.3,0,0.6,0,0.8,0c5.4-0.1,10.8-0.6,16.2-1.5c4-0.8,7.8-4.5,8.7-8.5
c1-4.8,1.5-9.8,1.5-14.6s-0.5-9.8-1.5-14.6c-0.8-3.9-4.7-7.6-8.7-8.4C37.3,0.6,31.8,0,26.4,0c-5.3-0.1-10.8,0.3-16.2,1.2
c-4,0.7-7.9,4.5-8.7,8.5c-1,5-1.5,9.9-1.5,14.9s0.5,9.9,1.5,14.9C2.4,43.3,6.2,47.1,10.3,47.8z M6.2,10.6C6.7,8.6,9,6.3,11,5.9
c4.9-0.8,9.7-1.2,14.6-1.2c0.3,0,0.6,0,0.8,0c5.1,0.1,10.3,0.6,15.3,1.4c2,0.4,4.4,2.7,4.8,4.6c0.9,4.5,1.3,9.1,1.3,13.7
s-0.4,9.1-1.3,13.6c-0.4,1.9-2.8,4.3-4.8,4.7c-5.1,0.9-10.3,1.4-15.3,1.4c-5.1,0.1-10.3-0.3-15.3-1.2c-2-0.3-4.4-2.7-4.8-4.6
c-0.9-4.6-1.4-9.3-1.4-14C4.9,19.9,5.3,15.1,6.2,10.6z"/>
<path class="st1" d="M14.1,32.3c-0.3,0.9-0.1,1.9,0.6,2.6c0.2,0.2,5,4.5,11,4.5c0.6,0,1.2-0.1,1.8-0.1c6.8-1,10.7-7.6,11-7.9
c0.5-0.8,0.4-1.9-0.1-2.7c-0.6-0.8-1.6-1.1-2.6-0.9c-6.4,1.7-12.9,2.7-19.5,2.9C15.3,30.8,14.5,31.4,14.1,32.3z"/>
<path class="st1" d="M17.1,25.7c3.4,0,6.2-2.8,6.2-6.2c0-3.4-2.8-6.2-6.2-6.2c-3.4,0-6.2,2.8-6.2,6.2C10.8,23,13.6,25.7,17.1,25.7z
"/>
<path class="st1" d="M34.3,20.4h4.2c1.3,0,2.3-1,2.3-2.3c0-1.3-1-2.3-2.3-2.3h-4.2c-1.3,0-2.3,1-2.3,2.3
C32,19.5,33.1,20.4,34.3,20.4z"/>
</g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -0,0 +1,350 @@
//
// InitialLaunchWindow.qml
//
// 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
//
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtGraphicalEffects 1.0
import QtQuick.Layouts 1.3
import stylesUit 1.0 as HifiStylesUit
import TabletScriptingInterface 1.0
import hifi.simplifiedUI.simplifiedConstants 1.0 as SimplifiedConstants
import hifi.simplifiedUI.simplifiedControls 1.0 as SimplifiedControls
Rectangle {
id: root
color: simplifiedUI.colors.white
anchors.fill: parent
property bool landscapeOrientation: root.width > root.height
SimplifiedConstants.SimplifiedConstants {
id: simplifiedUI
}
Component.onCompleted: {
var debugFTUE = Settings.getValue("simplifiedUI/debugFTUE", 0);
if ((debugFTUE !== 1 &&
(Settings.getValue("simplifiedUI/alreadyAutoSelectedAvatarFromInventory", false) ||
Settings.getValue("simplifiedUI/closedAvatarPageOfInitialLaunchWindow", false))) ||
debugFTUE === 2) {
tempAvatarPageContainer.visible = false;
controlsContainer.visible = true;
}
}
Item {
id: tempAvatarPageContainer
anchors.fill: parent
Item {
id: contentContainer
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: firstPageBottomBarContainer.top
Image {
id: avatarImage
anchors.verticalCenter: parent.verticalCenter
height: Math.max(parent.height - 48, 350)
anchors.left: parent.left
anchors.leftMargin: 12
source: resourceDirectoryUrl + "qml/hifi/simplifiedUI/avatarApp/images/" +
MyAvatar.skeletonModelURL.substring(MyAvatar.skeletonModelURL.indexOf("simplifiedAvatar"), MyAvatar.skeletonModelURL.lastIndexOf("/")) + ".png"
mipmap: true
fillMode: Image.PreserveAspectFit
}
Flickable {
id: textContainer
clip: true
anchors.top: parent.top
anchors.topMargin: 128
anchors.bottom: qrAndInstructionsContainer.top
anchors.bottomMargin: 32
anchors.left: avatarImage.right
anchors.leftMargin: 48
anchors.right: parent.right
contentWidth: width
contentHeight: contentItem.childrenRect.height
interactive: contentHeight > height
HifiStylesUit.RalewayBold {
id: headerText
text: "We know this isn't you..."
color: simplifiedUI.colors.text.black
size: 48
height: paintedHeight
wrapMode: Text.Wrap
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
}
HifiStylesUit.RalewayRegular {
id: descriptionText
anchors.top: headerText.bottom
anchors.topMargin: 10
anchors.left: parent.left
width: Math.min(700, parent.width) - headerText.anchors.rightMargin
height: paintedHeight
text: "...but we've given you this <b>temporary avatar</b> to use " +
"for today. If you see this avatar in-world, walk up and " +
"say hello to other new users!<br><br>" +
"<b>We want you to be you</b> so we've built " +
'<a href="https://www.highfidelity.com/knowledge/virtual-you/">Virtual You</a>, an Avatar Creator ' +
"App. Creating an avatar is as easy as taking a selfie and picking your " +
"outfits! Available now on iOS and Android."
color: simplifiedUI.colors.text.black
size: 22
wrapMode: Text.Wrap
onLinkActivated: {
Qt.openUrlExternally(link);
}
}
}
Item {
id: qrAndInstructionsContainer
anchors.left: avatarImage.right
anchors.leftMargin: 48
anchors.right: parent.right
anchors.rightMargin: 16
anchors.bottom: parent.bottom
height: 130
Image {
id: avatarAppQRCodeImage
source: resourceDirectoryUrl + "qml/hifi/simplifiedUI/avatarApp/images/qrCode.jpg"
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
width: 130
mipmap: true
fillMode: Image.PreserveAspectFit
}
HifiStylesUit.RalewayBold {
id: instructionText
anchors.top: avatarAppQRCodeImage.top
anchors.bottom: avatarAppQRCodeImage.bottom
anchors.left: avatarAppQRCodeImage.right
anchors.leftMargin: 30
anchors.right: parent.right
text: "Use your mobile phone to scan this QR code."
color: simplifiedUI.colors.text.black
size: 22
wrapMode: Text.Wrap
}
}
SimplifiedControls.VerticalScrollBar {
parent: textContainer
visible: parent.contentHeight > parent.height
size: parent.height / parent.contentHeight
}
}
Item {
id: firstPageBottomBarContainer
anchors.left: parent.left
anchors.leftMargin: 32
anchors.right: parent.right
anchors.rightMargin: 32
anchors.bottom: parent.bottom
height: continueLink.height + 48
HifiStylesUit.RalewayBold {
id: continueLink
anchors.centerIn: parent
text: "Continue >"
width: parent.width
height: paintedHeight
color: simplifiedUI.colors.text.lightBlue
opacity: continueMouseArea.containsMouse ? 1.0 : 0.7
size: 36
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
MouseArea {
id: continueMouseArea
hoverEnabled: true
anchors.fill: parent
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
tempAvatarPageContainer.visible = false;
Settings.setValue("simplifiedUI/closedAvatarPageOfInitialLaunchWindow", true);
controlsContainer.visible = true;
}
}
}
}
}
Item {
id: controlsContainer
visible: false
anchors.fill: parent
HifiStylesUit.RalewayRegular {
id: controlsDescriptionText
text: "Use these avatar controls to<br><b>interact with and move around in your new HQ.</b>"
anchors.top: parent.top
anchors.topMargin: 48
anchors.left: parent.left
anchors.leftMargin: 32
anchors.right: parent.right
anchors.rightMargin: 32
horizontalAlignment: Text.AlignHCenter
height: paintedHeight
color: simplifiedUI.colors.text.black
size: 36
wrapMode: Text.Wrap
}
Item {
anchors.top: controlsDescriptionText.bottom
anchors.topMargin: 16
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: bottomBarContainer.top
GridView {
id: controlsGrid
property int maxColumns: 2
property int idealCellWidth: 361
anchors.fill: parent
clip: true
cellWidth: width / Math.min(Math.floor(width / idealCellWidth), maxColumns)
cellHeight: 225
model: ListModel {
ListElement {
imageHeight: 198
imageSource: "images/walkingControls.png"
}
ListElement {
imageHeight: 193
imageSource: "images/mouseControls.png"
}
ListElement {
imageHeight: 146
imageSource: "images/runJumpControls.png"
}
ListElement {
imageHeight: 96
imageSource: "images/cameraControls.png"
}
}
delegate: Rectangle {
height: GridView.view.cellHeight
width: GridView.view.cellWidth
Image {
anchors.centerIn: parent
width: parent.GridView.view.idealCellWidth
height: model.imageHeight
source: model.imageSource
fillMode: Image.PreserveAspectFit
}
}
}
SimplifiedControls.VerticalScrollBar {
parent: controlsGrid
anchors.topMargin: 96
anchors.bottomMargin: anchors.topMargin
}
}
Item {
id: bottomBarContainer
anchors.left: parent.left
anchors.leftMargin: 32
anchors.right: parent.right
anchors.rightMargin: 32
anchors.bottom: parent.bottom
height: iHaveAGoodGrip.height + learnMoreLink.height + 48
HifiStylesUit.RalewayBold {
id: iHaveAGoodGrip
anchors.centerIn: parent
text: "I've got a good grip on the controls."
width: parent.width
height: paintedHeight
color: simplifiedUI.colors.text.lightBlue
opacity: goodGripMouseArea.containsMouse ? 1.0 : 0.7
size: 36
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
MouseArea {
id: goodGripMouseArea
hoverEnabled: true
anchors.fill: parent
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
sendToScript({
"source": "InitialLaunchWindow.qml",
"method": "closeInitialLaunchWindow"
});
}
}
}
HifiStylesUit.RalewayBold {
id: learnMoreLink
anchors.left: parent.left
anchors.leftMargin: 16
anchors.top: iHaveAGoodGrip.bottom
anchors.topMargin: 8
text: "Learn more about our controls."
width: paintedWidth
height: paintedHeight
color: simplifiedUI.colors.text.lightBlue
opacity: learnMoreAboutControlsMouseArea.containsMouse ? 1.0 : 0.7
size: 14
wrapMode: Text.Wrap
MouseArea {
id: learnMoreAboutControlsMouseArea
hoverEnabled: true
anchors.fill: parent
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
Qt.openUrlExternally("https://www.highfidelity.com/knowledge/get-around");
}
}
}
}
}
Image {
id: topLeftAccentImage
width: 400
height: 180
anchors.left: parent.left
anchors.top: parent.top
source: "images/defaultTopLeft.png"
}
Image {
id: bottomRightAccentImage
width: 80
height: 250
anchors.right: parent.right
anchors.bottom: parent.bottom
source: "images/defaultBottomRight.png"
}
signal sendToScript(var message);
}

View file

@ -0,0 +1,186 @@
//
// SecondLaunchWindow.qml
//
// 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
//
import QtQuick 2.10
import QtQuick.Controls 2.3
import QtGraphicalEffects 1.0
import QtQuick.Layouts 1.3
import stylesUit 1.0 as HifiStylesUit
import TabletScriptingInterface 1.0
import hifi.simplifiedUI.simplifiedConstants 1.0 as SimplifiedConstants
import hifi.simplifiedUI.simplifiedControls 1.0 as SimplifiedControls
Rectangle {
id: root
color: simplifiedUI.colors.white
anchors.fill: parent
SimplifiedConstants.SimplifiedConstants {
id: simplifiedUI
}
Item {
id: contentContainer
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: continueLink.top
Image {
id: avatarImage
anchors.verticalCenter: parent.verticalCenter
height: Math.max(parent.height - 48, 350)
anchors.left: parent.left
anchors.leftMargin: 12
source: resourceDirectoryUrl + "qml/hifi/simplifiedUI/avatarApp/images/hero.png"
mipmap: true
fillMode: Image.PreserveAspectFit
}
Item {
anchors.top: parent.top
anchors.topMargin: 196
anchors.bottom: parent.bottom
anchors.bottomMargin: 32
anchors.left: avatarImage.right
anchors.leftMargin: 48
anchors.right: parent.right
Flickable {
id: textContainer
clip: true
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
width: Math.min(700, parent.width)
contentWidth: width
contentHeight: contentItem.childrenRect.height
interactive: contentHeight > height
HifiStylesUit.RalewayBold {
id: headerText
text: "Stand out from the crowd!"
color: simplifiedUI.colors.text.black
size: 48
height: paintedHeight
wrapMode: Text.Wrap
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
}
HifiStylesUit.RalewayRegular {
id: descriptionText
anchors.top: headerText.bottom
anchors.topMargin: 10
anchors.left: parent.left
width: parent.width - headerText.anchors.rightMargin
height: paintedHeight
text: "You can create and upload custom avatars from our Avatar Creator App. " +
"It's as easy as taking a selfie.<br>Available now on iOS and Android Platforms."
color: simplifiedUI.colors.text.black
size: 22
wrapMode: Text.Wrap
}
Item {
id: qrAndInstructionsContainer
anchors.top: descriptionText.bottom
anchors.topMargin: 24
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: 16
height: avatarAppQRCodeImage.height
Image {
id: avatarAppQRCodeImage
source: resourceDirectoryUrl + "qml/hifi/simplifiedUI/avatarApp/images/qrCode.jpg"
anchors.top: parent.top
anchors.left: parent.left
width: 130
height: width
mipmap: true
fillMode: Image.PreserveAspectFit
}
HifiStylesUit.RalewayBold {
id: instructionText
anchors.top: avatarAppQRCodeImage.top
anchors.bottom: avatarAppQRCodeImage.bottom
anchors.left: avatarAppQRCodeImage.right
anchors.leftMargin: 30
anchors.right: parent.right
text: "Use your mobile phone to scan this QR code."
color: simplifiedUI.colors.text.black
size: 22
wrapMode: Text.Wrap
}
}
}
}
SimplifiedControls.VerticalScrollBar {
parent: textContainer
visible: parent.contentHeight > parent.height
size: parent.height / parent.contentHeight
}
}
HifiStylesUit.RalewayBold {
id: continueLink
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.leftMargin: 16
anchors.right: parent.right
anchors.rightMargin: 16
height: 96
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: "No thanks, I'll keep using my default avatar."
color: simplifiedUI.colors.text.lightBlue
opacity: continueMouseArea.containsMouse ? 1.0 : 0.7
size: 24
MouseArea {
id: continueMouseArea
hoverEnabled: true
anchors.fill: parent
onClicked: {
Tablet.playSound(TabletEnums.ButtonClick);
sendToScript({
"source": "SecondLaunchWindow.qml",
"method": "closeSecondLaunchWindow"
});
}
}
}
Image {
id: topLeftAccentImage
width: 130
height: 320
anchors.left: parent.left
anchors.top: parent.top
source: "images/standOutTopLeft.png"
}
Image {
id: bottomRightAccentImage
width: 250
height: 80
anchors.right: parent.right
anchors.bottom: parent.bottom
source: "images/standOutBottomRight.png"
}
signal sendToScript(var message);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

View file

@ -14,7 +14,6 @@
// START CONFIG OPTIONS // START CONFIG OPTIONS
var DOCKED_QML_SUPPORTED = true;
var TOOLBAR_NAME = "com.highfidelity.interface.toolbar.system"; var TOOLBAR_NAME = "com.highfidelity.interface.toolbar.system";
var DEFAULT_SCRIPTS_PATH_PREFIX = ScriptDiscoveryService.defaultScriptsPath + "/"; var DEFAULT_SCRIPTS_PATH_PREFIX = ScriptDiscoveryService.defaultScriptsPath + "/";
// END CONFIG OPTIONS // END CONFIG OPTIONS
@ -284,28 +283,21 @@ function maybeDeleteOutputDeviceMutedOverlay() {
var outputDeviceMutedOverlay = false; var outputDeviceMutedOverlay = false;
var OUTPUT_DEVICE_MUTED_OVERLAY_DEFAULT_DIMS_PX = 300; var OUTPUT_DEVICE_MUTED_OVERLAY_DEFAULT_DIMS_PX = 300;
var OUTPUT_DEVICE_MUTED_MARGIN_BOTTOM_PX = 20; var OUTPUT_DEVICE_MUTED_OVERLAY_DEFAULT_MARGINS_PX = 20;
var OUTPUT_DEVICE_MUTED_MARGIN_LEFT_RIGHT_PX = 20; var OUTPUT_DEVICE_MUTED_DIMS_RATIO_TO_WINDOW_SIZE = 0.8;
function updateOutputDeviceMutedOverlay(isMuted) { function updateOutputDeviceMutedOverlay(isMuted) {
if (isMuted) { if (isMuted) {
var props = { var props = {
imageURL: Script.resolvePath("images/outputDeviceMuted.svg"), imageURL: Script.resolvePath("images/outputDeviceMuted.svg"),
alpha: 0.5 alpha: 0.5
}; };
var overlayDims = OUTPUT_DEVICE_MUTED_OVERLAY_DEFAULT_DIMS_PX; var overlayDims = OUTPUT_DEVICE_MUTED_OVERLAY_DEFAULT_DIMS_PX;
props.x = Window.innerWidth / 2 - overlayDims / 2; var overlayWithMarginsDims = overlayDims + 2 * OUTPUT_DEVICE_MUTED_OVERLAY_DEFAULT_MARGINS_PX;
props.y = Window.innerHeight / 2 - overlayDims / 2;
var outputDeviceMutedOverlayBottomY = props.y + overlayDims; if (overlayWithMarginsDims > Window.innerHeight || overlayWithMarginsDims > Window.innerWidth) {
var inputDeviceMutedOverlayTopY = INPUT_DEVICE_MUTED_MARGIN_TOP_PX; var minWindowDims = Math.min(Window.innerHeight, Window.innerWidth);
if (outputDeviceMutedOverlayBottomY + OUTPUT_DEVICE_MUTED_MARGIN_BOTTOM_PX > inputDeviceMutedOverlayTopY) { overlayDims = Math.round(minWindowDims * OUTPUT_DEVICE_MUTED_DIMS_RATIO_TO_WINDOW_SIZE);
overlayDims = 2 * (inputDeviceMutedOverlayTopY - Window.innerHeight / 2 - OUTPUT_DEVICE_MUTED_MARGIN_BOTTOM_PX);
}
if (overlayDims + OUTPUT_DEVICE_MUTED_MARGIN_LEFT_RIGHT_PX > Window.innerWidth) {
overlayDims = Math.min(Window.innerWidth - OUTPUT_DEVICE_MUTED_MARGIN_LEFT_RIGHT_PX, overlayDims);
} else {
overlayDims = Math.min(OUTPUT_DEVICE_MUTED_OVERLAY_DEFAULT_DIMS_PX, overlayDims);
} }
props.width = overlayDims; props.width = overlayDims;
@ -359,6 +351,124 @@ function setOutputMuted(outputMuted) {
} }
} }
var TOP_BAR_HEIGHT_PX = 48;
var INITIAL_LAUNCH_QML_PATH = Script.resolvePath("./simplifiedFTUE/InitialLaunchWindow.qml");
var INITIAL_LAUNCH_WINDOW_TITLE = "Initial Launch";
var INITIAL_LAUNCH_PRESENTATION_MODE = Desktop.PresentationMode.NATIVE;
var INITIAL_WINDOW_FLAGS = 0x00000001 | // Qt::Window
0x00000008 | // Qt::Popup
0x00000002 | // Qt::Tool
0x00000800 | // Qt::FramelessWindowHint
0x40000000; // Qt::NoDropShadowWindowHint
var initialLaunchWindow = false;
function displayInitialLaunchWindow() {
if (initialLaunchWindow) {
return;
}
simplifiedEmote.handleFTUEScreensVisibilityChanged(true);
initialLaunchWindow = Desktop.createWindow(INITIAL_LAUNCH_QML_PATH, {
title: INITIAL_LAUNCH_WINDOW_TITLE,
presentationMode: INITIAL_LAUNCH_PRESENTATION_MODE,
isFullScreenWindow: true,
overrideFlags: INITIAL_WINDOW_FLAGS
});
initialLaunchWindow.fromQml.connect(onMessageFromInitialLaunchWindow);
Window.location = "file:///~/serverless/tutorial.json";
}
var SECOND_LAUNCH_QML_PATH = Script.resolvePath("simplifiedFTUE/SecondLaunchWindow.qml");
var SECOND_LAUNCH_WINDOW_TITLE = "Second Launch";
var SECOND_LAUNCH_PRESENTATION_MODE = Desktop.PresentationMode.NATIVE;
var SECOND_WINDOW_FLAGS = 0x00000001 | // Qt::Window
0x00000008 | // Qt::Popup
0x00000002 | // Qt::Tool
0x00000800 | // Qt::FramelessWindowHint
0x40000000; // Qt::NoDropShadowWindowHint
var secondLaunchWindow = false;
function displaySecondLaunchWindow() {
if (secondLaunchWindow) {
return;
}
simplifiedEmote.handleFTUEScreensVisibilityChanged(true);
secondLaunchWindow = Desktop.createWindow(SECOND_LAUNCH_QML_PATH, {
title: SECOND_LAUNCH_WINDOW_TITLE,
presentationMode: SECOND_LAUNCH_PRESENTATION_MODE,
isFullScreenWindow: true,
overrideFlags: SECOND_WINDOW_FLAGS
});
secondLaunchWindow.fromQml.connect(onMessageFromSecondLaunchWindow);
Window.location = "file:///~/serverless/tutorial.json";
}
function closeInitialLaunchWindow() {
if (initialLaunchWindow) {
initialLaunchWindow.fromQml.disconnect(onMessageFromInitialLaunchWindow);
initialLaunchWindow.close();
initialLaunchWindow = null;
}
simplifiedEmote.handleFTUEScreensVisibilityChanged(false);
}
function closeSecondLaunchWindow() {
if (secondLaunchWindow) {
secondLaunchWindow.fromQml.disconnect(onMessageFromSecondLaunchWindow);
secondLaunchWindow.close();
secondLaunchWindow = null;
}
simplifiedEmote.handleFTUEScreensVisibilityChanged(false);
}
var INITIAL_LAUNCH_WINDOW_MESSAGE_SOURCE = "InitialLaunchWindow.qml";
function onMessageFromInitialLaunchWindow(message) {
if (message.source !== INITIAL_LAUNCH_WINDOW_MESSAGE_SOURCE) {
return;
}
switch (message.method) {
case "closeInitialLaunchWindow":
closeInitialLaunchWindow();
var homeLocation = LocationBookmarks.getAddress("hqhome");
if (homeLocation) {
Window.location = homeLocation;
}
break;
default:
console.log("Unrecognized message from " + INITIAL_LAUNCH_WINDOW_MESSAGE_SOURCE + ": " + JSON.stringify(message));
break;
}
}
var SECOND_LAUNCH_WINDOW_MESSAGE_SOURCE = "SecondLaunchWindow.qml";
function onMessageFromSecondLaunchWindow(message) {
if (message.source !== SECOND_LAUNCH_WINDOW_MESSAGE_SOURCE) {
return;
}
switch (message.method) {
case "closeSecondLaunchWindow":
closeSecondLaunchWindow();
var homeLocation = LocationBookmarks.getAddress("hqhome");
if (homeLocation) {
Window.location = homeLocation;
}
break;
default:
console.log("Unrecognized message from " + SECOND_LAUNCH_WINDOW_MESSAGE_SOURCE + ": " + JSON.stringify(message));
break;
}
}
var WAIT_FOR_TOP_BAR_MS = 1000; var WAIT_FOR_TOP_BAR_MS = 1000;
function sendLocalStatusToQml() { function sendLocalStatusToQml() {
@ -404,6 +514,14 @@ function onMessageFromTopBar(message) {
si.toggleStatus(); si.toggleStatus();
break; break;
case "displayInitialLaunchWindow":
displayInitialLaunchWindow();
break;
case "displaySecondLaunchWindow":
displaySecondLaunchWindow();
break;
default: default:
console.log("Unrecognized message from " + TOP_BAR_MESSAGE_SOURCE + ": " + JSON.stringify(message)); console.log("Unrecognized message from " + TOP_BAR_MESSAGE_SOURCE + ": " + JSON.stringify(message));
break; break;
@ -432,7 +550,6 @@ var TOP_BAR_QML_PATH = Script.resourcesPath() + "qml/hifi/simplifiedUI/topBar/Si
var TOP_BAR_WINDOW_TITLE = "Simplified Top Bar"; var TOP_BAR_WINDOW_TITLE = "Simplified Top Bar";
var TOP_BAR_PRESENTATION_MODE = Desktop.PresentationMode.NATIVE; var TOP_BAR_PRESENTATION_MODE = Desktop.PresentationMode.NATIVE;
var TOP_BAR_WIDTH_PX = Window.innerWidth; var TOP_BAR_WIDTH_PX = Window.innerWidth;
var TOP_BAR_HEIGHT_PX = 48;
var topBarWindow = false; var topBarWindow = false;
function loadSimplifiedTopBar() { function loadSimplifiedTopBar() {
var windowProps = { var windowProps = {
@ -443,16 +560,9 @@ function loadSimplifiedTopBar() {
y: TOP_BAR_HEIGHT_PX y: TOP_BAR_HEIGHT_PX
} }
}; };
if (DOCKED_QML_SUPPORTED) { windowProps.presentationWindowInfo = {
windowProps.presentationWindowInfo = { dockArea: Desktop.DockArea.TOP
dockArea: Desktop.DockArea.TOP };
};
} else {
windowProps.position = {
x: Window.x,
y: Window.y
};
}
topBarWindow = Desktop.createWindow(TOP_BAR_QML_PATH, windowProps); topBarWindow = Desktop.createWindow(TOP_BAR_QML_PATH, windowProps);
topBarWindow.fromQml.connect(onMessageFromTopBar); topBarWindow.fromQml.connect(onMessageFromTopBar);
@ -517,21 +627,38 @@ function onHMDInputDeviceMutedChanged(isMuted) {
function onGeometryChanged(rect) { function onGeometryChanged(rect) {
updateInputDeviceMutedOverlay(Audio.muted); updateInputDeviceMutedOverlay(Audio.muted);
updateOutputDeviceMutedOverlay(isOutputMuted()); updateOutputDeviceMutedOverlay(isOutputMuted());
if (topBarWindow && !DOCKED_QML_SUPPORTED) { }
topBarWindow.size = {
"x": rect.width, var initialLaunchWindowIsMinimized = false;
"y": TOP_BAR_HEIGHT_PX var secondLaunchWindowIsMinimized = false;
}; function onWindowMinimizedChanged(isMinimized) {
topBarWindow.position = { if (isMinimized) {
"x": rect.x, handleInitialLaunchWindowVisibleChanged(false);
"y": rect.y handleSecondLaunchWindowVisibleChanged(false);
}; } else if (!HMD.active) {
handleInitialLaunchWindowVisibleChanged(true);
handleSecondLaunchWindowVisibleChanged(true);
} }
} }
function onWindowMinimizedChanged() { function handleInitialLaunchWindowVisibleChanged(shouldBeVisible) {
// prerequisite placeholder for Reduce Friction of Customer Acquisition sub task: https://highfidelity.atlassian.net/browse/DEV-585 if (shouldBeVisible && !initialLaunchWindow && initialLaunchWindowIsMinimized) {
print("WINDOW MINIMIZED CHANGED SIGNAL"); displayInitialLaunchWindow();
initialLaunchWindowIsMinimized = false;
} else if (!shouldBeVisible && initialLaunchWindow) {
closeInitialLaunchWindow();
initialLaunchWindowIsMinimized = true;
}
}
function handleSecondLaunchWindowVisibleChanged(shouldBeVisible) {
if (shouldBeVisible && !secondLaunchWindow && secondLaunchWindowIsMinimized) {
displaySecondLaunchWindow();
secondLaunchWindowIsMinimized = false;
} else if (!shouldBeVisible && secondLaunchWindow) {
closeSecondLaunchWindow();
secondLaunchWindowIsMinimized = true;
}
} }
function onDisplayModeChanged(isHMDMode) { function onDisplayModeChanged(isHMDMode) {
@ -541,8 +668,12 @@ function onDisplayModeChanged(isHMDMode) {
if (isHMDMode) { if (isHMDMode) {
onHMDInputDeviceMutedChanged(Audio.mutedHMD); onHMDInputDeviceMutedChanged(Audio.mutedHMD);
handleInitialLaunchWindowVisibleChanged(false);
handleSecondLaunchWindowVisibleChanged(false);
} else { } else {
onDesktopInputDeviceMutedChanged(Audio.mutedDesktop); onDesktopInputDeviceMutedChanged(Audio.mutedDesktop);
handleInitialLaunchWindowVisibleChanged(true);
handleSecondLaunchWindowVisibleChanged(true);
} }
} }
@ -585,9 +716,9 @@ function restoreLODSettings() {
} }
var nametag = Script.require("./simplifiedNametag/simplifiedNametag.js?" + Date.now()); var nametag = Script.require("./simplifiedNametag/simplifiedNametag.js");
var si = Script.require("./simplifiedStatusIndicator/simplifiedStatusIndicator.js?" + Date.now()); var si = Script.require("./simplifiedStatusIndicator/simplifiedStatusIndicator.js");
var emote = Script.require("../simplifiedEmote/simplifiedEmote.js?" + Date.now()); var simplifiedEmote = Script.require("../simplifiedEmote/simplifiedEmote.js");
var oldShowAudioTools; var oldShowAudioTools;
var oldShowBubbleTools; var oldShowBubbleTools;
var keepExistingUIAndScriptsSetting = Settings.getValue("simplifiedUI/keepExistingUIAndScripts", false); var keepExistingUIAndScriptsSetting = Settings.getValue("simplifiedUI/keepExistingUIAndScripts", false);
@ -654,6 +785,14 @@ function shutdown() {
settingsAppWindow.close(); settingsAppWindow.close();
} }
if (initialLaunchWindow) {
closeInitialLaunchWindow();
}
if (secondLaunchWindow) {
closeSecondLaunchWindow();
}
maybeDeleteInputDeviceMutedOverlay(); maybeDeleteInputDeviceMutedOverlay();
maybeDeleteOutputDeviceMutedOverlay(); maybeDeleteOutputDeviceMutedOverlay();

View file

@ -50,11 +50,11 @@ var OVERLAY_DATA_HMD = {
}; };
var AWAY_INTRO = { var AWAY_INTRO = {
url: "http://hifi-content.s3.amazonaws.com/ozan/dev/anim/standard_anims_160127/kneel.fbx", url: "https://hifi-content.s3.amazonaws.com/doug/animation/fbx/afk_texting.fbx",
playbackRate: 30.0, playbackRate: 30.0,
loopFlag: false, loopFlag: true,
startFrame: 0.0, startFrame: 1.0,
endFrame: 83.0 endFrame: 489.0
}; };
// MAIN CONTROL // MAIN CONTROL