Merge branch 'master' of https://github.com/highfidelity/hifi into loginInitiative2
|
@ -84,7 +84,7 @@ void ScriptableAvatar::update(float deltatime) {
|
|||
// Run animation
|
||||
if (_animation && _animation->isLoaded() && _animation->getFrames().size() > 0 && !_bind.isNull() && _bind->isLoaded()) {
|
||||
if (!_animSkeleton) {
|
||||
_animSkeleton = std::make_shared<AnimSkeleton>(_bind->getGeometry());
|
||||
_animSkeleton = std::make_shared<AnimSkeleton>(_bind->getHFMModel());
|
||||
}
|
||||
float currentFrame = _animationDetails.currentFrame + deltatime * _animationDetails.fps;
|
||||
if (_animationDetails.loop || currentFrame < _animationDetails.lastFrame) {
|
||||
|
@ -93,7 +93,7 @@ void ScriptableAvatar::update(float deltatime) {
|
|||
}
|
||||
_animationDetails.currentFrame = currentFrame;
|
||||
|
||||
const QVector<HFMJoint>& modelJoints = _bind->getGeometry().joints;
|
||||
const QVector<HFMJoint>& modelJoints = _bind->getHFMModel().joints;
|
||||
QStringList animationJointNames = _animation->getJointNames();
|
||||
|
||||
const int nJoints = modelJoints.size();
|
||||
|
@ -113,7 +113,7 @@ void ScriptableAvatar::update(float deltatime) {
|
|||
const QString& name = animationJointNames[i];
|
||||
// As long as we need the model preRotations anyway, let's get the jointIndex from the bind skeleton rather than
|
||||
// trusting the .fst (which is sometimes not updated to match changes to .fbx).
|
||||
int mapping = _bind->getGeometry().getJointIndex(name);
|
||||
int mapping = _bind->getHFMModel().getJointIndex(name);
|
||||
if (mapping != -1 && !_maskedJoints.contains(name)) {
|
||||
|
||||
AnimPose floorPose = composeAnimPose(modelJoints[mapping], floorFrame.rotations[i], floorFrame.translations[i] * UNIT_SCALE);
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
<svg width="22" height="26" fill="none" version="1.1" viewBox="0 0 22 26" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1 7L11 1L21 7M1 7L11 13M1 7V19L11 25M11 13L21 7M11 13V25M21 7V19L11 25" stroke="#000" stroke-linejoin="round" stroke-width="2"/>
|
||||
<circle class="st1" cx="19.407" cy="2.5881" r="2.5846" fill="#ef3b4e" stroke-width=".24043"/>
|
||||
</svg>
|
After Width: | Height: | Size: 356 B |
3
interface/resources/icons/tablet-icons/inventory-a.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="22" height="26" viewBox="0 0 22 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1 7L11 1L21 7M1 7L11 13M1 7V19L11 25M11 13L21 7M11 13V25M21 7V19L11 25" stroke="black" stroke-width="2" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 243 B |
|
@ -0,0 +1,4 @@
|
|||
<svg width="22" height="26" fill="none" version="1.1" viewBox="0 0 22 26" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1 7L11 1L21 7M1 7L11 13M1 7V19L11 25M11 13L21 7M11 13V25M21 7V19L11 25" stroke="#fff" stroke-linejoin="round" stroke-width="2"/>
|
||||
<circle class="st1" cx="19.41" cy="2.5828" r="2.5846" fill="#ef3b4e" stroke-width=".24043"/>
|
||||
</svg>
|
After Width: | Height: | Size: 355 B |
3
interface/resources/icons/tablet-icons/inventory-i.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg width="22" height="26" viewBox="0 0 22 26" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1 7L11 1L21 7M1 7L11 13M1 7V19L11 25M11 13L21 7M11 13V25M21 7V19L11 25" stroke="white" stroke-width="2" stroke-linejoin="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 243 B |
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 96 96" style="enable-background:new 0 0 96 96;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st1{fill:#EF3B4E;}
|
||||
</style>
|
||||
<circle class="st1" cx="84.6" cy="11.5" r="10.75"/>
|
||||
<g><path d="M2.4,70.5c0,6.1,4.9,11,11,11H76c6.1,0,11-4.9,11-11V59.6c3.7-0.7,6.6-3.9,6.6-7.9v-7.5c0-3.9-2.8-7.2-6.6-7.9V25.5 c0-6.1-4.9-11-11-11H13.4c-6.1,0-11,4.9-11,11V70.5z M87.6,51.8c0,1.1-0.9,2-2,2H72.2c-2.8,0-5-2.2-5-5v-1.5c0-2.8,2.2-5,5-5h13.3 c1.1,0,2,0.9,2,2V51.8z M8.4,25.5c0-2.8,2.2-5,5-5H76c2.8,0,5,2.2,5,5v10.7h-8.7c-6.1,0-11,4.9-11,11v1.5c0,6.1,4.9,11,11,11H81 v10.7c0,2.8-2.2,5-5,5H13.4c-2.8,0-5-2.2-5-5V25.5z"></path></g></svg>
|
Before Width: | Height: | Size: 755 B |
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 96 96" style="enable-background:new 0 0 96 96;" xml:space="preserve"><g><path d="M2.4,70.5c0,6.1,4.9,11,11,11H76c6.1,0,11-4.9,11-11V59.6c3.7-0.7,6.6-3.9,6.6-7.9v-7.5c0-3.9-2.8-7.2-6.6-7.9V25.5 c0-6.1-4.9-11-11-11H13.4c-6.1,0-11,4.9-11,11V70.5z M87.6,51.8c0,1.1-0.9,2-2,2H72.2c-2.8,0-5-2.2-5-5v-1.5c0-2.8,2.2-5,5-5h13.3 c1.1,0,2,0.9,2,2V51.8z M8.4,25.5c0-2.8,2.2-5,5-5H76c2.8,0,5,2.2,5,5v10.7h-8.7c-6.1,0-11,4.9-11,11v1.5c0,6.1,4.9,11,11,11H81 v10.7c0,2.8-2.2,5-5,5H13.4c-2.8,0-5-2.2-5-5V25.5z"></path></g></svg>
|
Before Width: | Height: | Size: 643 B |
|
@ -1,16 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 21.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"
|
||||
viewBox="0 0 96 96" style="enable-background:new 0 0 96 96;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
.st1{fill:#EF3B4E;}
|
||||
</style>
|
||||
<circle class="st1" cx="84.6" cy="11.5" r="10.75"/>
|
||||
<g>
|
||||
<path class="st0" d="M2.4,70.5c0,6.1,4.9,11,11,11H76c6.1,0,11-4.9,11-11V59.6c3.7-0.7,6.6-3.9,6.6-7.9v-7.5c0-3.9-2.8-7.2-6.6-7.9
|
||||
V25.5c0-6.1-4.9-11-11-11H13.4c-6.1,0-11,4.9-11,11C2.4,25.5,2.4,70.5,2.4,70.5z M87.6,51.8c0,1.1-0.9,2-2,2H72.2c-2.8,0-5-2.2-5-5
|
||||
v-1.5c0-2.8,2.2-5,5-5h13.3c1.1,0,2,0.9,2,2L87.6,51.8L87.6,51.8z M8.4,25.5c0-2.8,2.2-5,5-5H76c2.8,0,5,2.2,5,5v10.7h-8.7
|
||||
c-6.1,0-11,4.9-11,11v1.5c0,6.1,4.9,11,11,11H81v10.7c0,2.8-2.2,5-5,5H13.4c-2.8,0-5-2.2-5-5V25.5z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 984 B |
|
@ -1,14 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 21.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"
|
||||
viewBox="0 0 96 96" style="enable-background:new 0 0 96 96;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M2.4,70.5c0,6.1,4.9,11,11,11H76c6.1,0,11-4.9,11-11V59.6c3.7-0.7,6.6-3.9,6.6-7.9v-7.5c0-3.9-2.8-7.2-6.6-7.9
|
||||
V25.5c0-6.1-4.9-11-11-11H13.4c-6.1,0-11,4.9-11,11C2.4,25.5,2.4,70.5,2.4,70.5z M87.6,51.8c0,1.1-0.9,2-2,2H72.2c-2.8,0-5-2.2-5-5
|
||||
v-1.5c0-2.8,2.2-5,5-5h13.3c1.1,0,2,0.9,2,2L87.6,51.8L87.6,51.8z M8.4,25.5c0-2.8,2.2-5,5-5H76c2.8,0,5,2.2,5,5v10.7h-8.7
|
||||
c-6.1,0-11,4.9-11,11v1.5c0,6.1,4.9,11,11,11H81v10.7c0,2.8-2.2,5-5,5H13.4c-2.8,0-5-2.2-5-5V25.5z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 909 B |
|
@ -260,38 +260,50 @@ Item {
|
|||
interactive: false;
|
||||
anchors.fill: parent;
|
||||
model: filterBarModel;
|
||||
delegate: Rectangle {
|
||||
id: dropDownButton;
|
||||
color: hifi.colors.white;
|
||||
delegate: Item {
|
||||
width: parent.width;
|
||||
height: 50;
|
||||
Rectangle {
|
||||
id: dropDownButton;
|
||||
color: hifi.colors.white;
|
||||
width: parent.width;
|
||||
height: 50;
|
||||
visible: true;
|
||||
|
||||
RalewaySemiBold {
|
||||
id: dropDownButtonText;
|
||||
text: model.displayName;
|
||||
anchors.fill: parent;
|
||||
anchors.leftMargin: 12;
|
||||
color: hifi.colors.baseGray;
|
||||
horizontalAlignment: Text.AlignLeft;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
size: 18;
|
||||
RalewaySemiBold {
|
||||
id: dropDownButtonText;
|
||||
text: model.displayName;
|
||||
anchors.fill: parent;
|
||||
anchors.topMargin: 2;
|
||||
anchors.leftMargin: 12;
|
||||
color: hifi.colors.baseGray;
|
||||
horizontalAlignment: Text.AlignLeft;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
size: 18;
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
hoverEnabled: true;
|
||||
propagateComposedEvents: false;
|
||||
onEntered: {
|
||||
dropDownButton.color = hifi.colors.blueHighlight;
|
||||
}
|
||||
onExited: {
|
||||
dropDownButton.color = hifi.colors.white;
|
||||
}
|
||||
onClicked: {
|
||||
textField.forceActiveFocus();
|
||||
root.primaryFilter_index = index;
|
||||
dropdownContainer.visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
hoverEnabled: true;
|
||||
propagateComposedEvents: false;
|
||||
onEntered: {
|
||||
dropDownButton.color = hifi.colors.blueHighlight;
|
||||
}
|
||||
onExited: {
|
||||
dropDownButton.color = hifi.colors.white;
|
||||
}
|
||||
onClicked: {
|
||||
textField.forceActiveFocus();
|
||||
root.primaryFilter_index = index;
|
||||
dropdownContainer.visible = false;
|
||||
}
|
||||
Rectangle {
|
||||
height: 2;
|
||||
width: parent.width;
|
||||
color: hifi.colors.lightGray;
|
||||
visible: model.separator
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,8 +63,8 @@ MessageBox {
|
|||
popup.dialogButtons.yesButton.fontCapitalization = Font.MixedCase;
|
||||
popup.button1text = 'CANCEL'
|
||||
popup.titleText = 'Get Wearables'
|
||||
popup.bodyText = 'Buy wearables from <b><a href="app://marketplace">Marketplace.</a></b>' + '<br/>' +
|
||||
'Wear wearable from <b><a href="app://purchases">My Purchases.</a></b>' + '<br/>' + '<br/>' +
|
||||
popup.bodyText = 'Get wearables from <b><a href="app://marketplace">Marketplace.</a></b>' + '<br/>' +
|
||||
'Wear wearable from <b><a href="app://purchases">Inventory.</a></b>' + '<br/>' + '<br/>' +
|
||||
'Visit “AvatarIsland” to get wearables'
|
||||
|
||||
popup.imageSource = getWearablesUrl;
|
||||
|
@ -89,7 +89,7 @@ MessageBox {
|
|||
|
||||
function showDeleteFavorite(favoriteName, callback) {
|
||||
popup.titleText = 'Delete Favorite: {AvatarName}'.replace('{AvatarName}', favoriteName)
|
||||
popup.bodyText = 'This will delete your favorite. You will retain access to the wearables and avatar that made up the favorite from My Purchases.'
|
||||
popup.bodyText = 'This will delete your favorite. You will retain access to the wearables and avatar that made up the favorite from Inventory.'
|
||||
popup.imageSource = null;
|
||||
popup.button1text = 'CANCEL'
|
||||
popup.button2text = 'DELETE'
|
||||
|
@ -128,8 +128,8 @@ MessageBox {
|
|||
popup.button1text = 'CANCEL'
|
||||
popup.titleText = 'Get Avatars'
|
||||
|
||||
popup.bodyText = 'Buy avatars from <b><a href="app://marketplace">Marketplace.</a></b>' + '<br/>' +
|
||||
'Wear avatars in <b><a href="app://purchases">My Purchases.</a></b>' + '<br/>' + '<br/>' +
|
||||
popup.bodyText = 'Get avatars from <b><a href="app://marketplace">Marketplace.</a></b>' + '<br/>' +
|
||||
'Wear avatars in <b><a href="app://purchases">Inventory.</a></b>' + '<br/>' + '<br/>' +
|
||||
'Visit “BodyMart” to get free avatars.'
|
||||
|
||||
popup.imageSource = getAvatarsUrl;
|
||||
|
|
|
@ -240,11 +240,6 @@ Rectangle {
|
|||
lightboxPopup.button1method = function() {
|
||||
lightboxPopup.visible = false;
|
||||
}
|
||||
lightboxPopup.button2text = "GO TO WALLET";
|
||||
lightboxPopup.button2method = function() {
|
||||
lightboxPopup.visible = false;
|
||||
sendToScript({method: 'checkout_openWallet'});
|
||||
};
|
||||
lightboxPopup.visible = true;
|
||||
} else {
|
||||
sendToScript(msg);
|
||||
|
@ -383,7 +378,7 @@ Rectangle {
|
|||
anchors.leftMargin: 16;
|
||||
width: paintedWidth;
|
||||
height: paintedHeight;
|
||||
text: "Review Purchase:";
|
||||
text: "Review:";
|
||||
color: hifi.colors.black;
|
||||
size: 28;
|
||||
}
|
||||
|
@ -448,7 +443,7 @@ Rectangle {
|
|||
// "HFC" balance label
|
||||
HiFiGlyphs {
|
||||
id: itemPriceTextLabel;
|
||||
visible: !(root.isUpdating && root.itemEdition > 0);
|
||||
visible: !(root.isUpdating && root.itemEdition > 0) && (root.itemPrice > 0);
|
||||
text: hifi.glyphs.hfc;
|
||||
// Size
|
||||
size: 30;
|
||||
|
@ -464,7 +459,7 @@ Rectangle {
|
|||
}
|
||||
FiraSansSemiBold {
|
||||
id: itemPriceText;
|
||||
text: (root.isUpdating && root.itemEdition > 0) ? "FREE\nUPDATE" : ((root.itemPrice === -1) ? "--" : root.itemPrice);
|
||||
text: (root.isUpdating && root.itemEdition > 0) ? "FREE\nUPDATE" : ((root.itemPrice === -1) ? "--" : ((root.itemPrice > 0) ? root.itemPrice : "FREE"));
|
||||
// Text size
|
||||
size: (root.isUpdating && root.itemEdition > 0) ? 20 : 26;
|
||||
// Anchors
|
||||
|
@ -559,7 +554,7 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
// "View in My Purchases" button
|
||||
// "View in Inventory" button
|
||||
HifiControlsUit.Button {
|
||||
id: viewInMyPurchasesButton;
|
||||
visible: false;
|
||||
|
@ -570,7 +565,7 @@ Rectangle {
|
|||
height: 50;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
text: root.isUpdating ? "UPDATE TO THIS ITEM FOR FREE" : "VIEW THIS ITEM IN MY PURCHASES";
|
||||
text: root.isUpdating ? "UPDATE TO THIS ITEM FOR FREE" : "VIEW THIS ITEM IN YOUR INVENTORY";
|
||||
onClicked: {
|
||||
if (root.isUpdating) {
|
||||
sendToScript({method: 'checkout_goToPurchases', filterText: root.baseItemName});
|
||||
|
@ -594,7 +589,7 @@ Rectangle {
|
|||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
text: (root.isUpdating && root.itemEdition > 0) ? "CONFIRM UPDATE" : (((root.isCertified) ? ((ownershipStatusReceived && balanceReceived && availableUpdatesReceived) ?
|
||||
((viewInMyPurchasesButton.visible && !root.isUpdating) ? "Buy It Again" : "Confirm Purchase") : "--") : "Get Item"));
|
||||
((viewInMyPurchasesButton.visible && !root.isUpdating) ? "Get It Again" : "Confirm") : "--") : "Get Item"));
|
||||
onClicked: {
|
||||
if (root.isUpdating && root.itemEdition > 0) {
|
||||
// If we're updating an app, the existing app needs to be uninstalled.
|
||||
|
@ -608,9 +603,9 @@ Rectangle {
|
|||
} else if (root.isCertified) {
|
||||
if (!root.shouldBuyWithControlledFailure) {
|
||||
if (root.itemType === "contentSet" && !Entities.canReplaceContent()) {
|
||||
lightboxPopup.titleText = "Purchase Content Set";
|
||||
lightboxPopup.titleText = "Get Content Set";
|
||||
lightboxPopup.bodyText = "You will not be able to replace this domain's content with <b>" + root.itemName +
|
||||
" </b>until the server owner gives you 'Replace Content' permissions.<br><br>Are you sure you want to purchase this content set?";
|
||||
" </b>until the server owner gives you 'Replace Content' permissions.<br><br>Are you sure you want to get this content set?";
|
||||
lightboxPopup.button1text = "CANCEL";
|
||||
lightboxPopup.button1method = function() {
|
||||
lightboxPopup.visible = false;
|
||||
|
@ -694,7 +689,7 @@ Rectangle {
|
|||
id: completeText2;
|
||||
text: "The " + (root.itemTypesText)[itemTypesArray.indexOf(root.itemType)] +
|
||||
' <font color="' + hifi.colors.blueAccent + '"><a href="#">' + root.itemName + '</a></font>' +
|
||||
" has been added to your Purchases and a receipt will appear in your Wallet's transaction history.";
|
||||
" has been added to your Inventory.";
|
||||
// Text size
|
||||
size: 18;
|
||||
// Anchors
|
||||
|
@ -833,7 +828,7 @@ Rectangle {
|
|||
}
|
||||
lightboxPopup.button2text = "OPEN GOTO";
|
||||
lightboxPopup.button2method = function() {
|
||||
sendToScript({method: 'purchases_openGoTo'});
|
||||
sendToScript({method: 'checkout_openGoTo'});
|
||||
lightboxPopup.visible = false;
|
||||
};
|
||||
lightboxPopup.visible = true;
|
||||
|
@ -864,7 +859,7 @@ Rectangle {
|
|||
|
||||
RalewaySemiBold {
|
||||
id: myPurchasesLink;
|
||||
text: '<font color="' + hifi.colors.primaryHighlight + '"><a href="#">View this item in My Purchases</a></font>';
|
||||
text: '<font color="' + hifi.colors.primaryHighlight + '"><a href="#">View this item in your Inventory</a></font>';
|
||||
// Text size
|
||||
size: 18;
|
||||
// Anchors
|
||||
|
@ -886,7 +881,8 @@ Rectangle {
|
|||
|
||||
RalewaySemiBold {
|
||||
id: walletLink;
|
||||
text: '<font color="' + hifi.colors.primaryHighlight + '"><a href="#">View receipt in Wallet</a></font>';
|
||||
visible: !WalletScriptingInterface.limitedCommerce;
|
||||
text: '<font color="' + hifi.colors.primaryHighlight + '"><a href="#">View receipt in Recent Activity</a></font>';
|
||||
// Text size
|
||||
size: 18;
|
||||
// Anchors
|
||||
|
@ -902,18 +898,18 @@ Rectangle {
|
|||
horizontalAlignment: Text.AlignLeft;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
onLinkActivated: {
|
||||
sendToScript({method: 'purchases_openWallet'});
|
||||
sendToScript({method: 'checkout_openRecentActivity'});
|
||||
}
|
||||
}
|
||||
|
||||
RalewayRegular {
|
||||
id: pendingText;
|
||||
text: 'Your item is marked "pending" while your purchase is being confirmed. ' +
|
||||
text: 'Your item is marked "pending" while the transfer is being confirmed. ' +
|
||||
'<b><font color="' + hifi.colors.primaryHighlight + '"><a href="#">Learn More</a></font></b>';
|
||||
// Text size
|
||||
size: 18;
|
||||
// Anchors
|
||||
anchors.top: walletLink.bottom;
|
||||
anchors.top: walletLink.visible ? walletLink.bottom : myPurchasesLink.bottom;
|
||||
anchors.topMargin: 32;
|
||||
height: paintedHeight;
|
||||
anchors.left: parent.left;
|
||||
|
@ -925,8 +921,8 @@ Rectangle {
|
|||
horizontalAlignment: Text.AlignLeft;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
onLinkActivated: {
|
||||
lightboxPopup.titleText = "Purchase Confirmations";
|
||||
lightboxPopup.bodyText = 'Your item is marked "pending" while your purchase is being confirmed.<br><br>' +
|
||||
lightboxPopup.titleText = "Confirmations";
|
||||
lightboxPopup.bodyText = 'Your item is marked "pending" while the transfer is being confirmed.<br><br>' +
|
||||
'Confirmations usually take about 90 seconds.';
|
||||
lightboxPopup.button1text = "CLOSE";
|
||||
lightboxPopup.button1method = function() {
|
||||
|
@ -936,9 +932,9 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
// "Continue Shopping" button
|
||||
// "Continue" button
|
||||
HifiControlsUit.Button {
|
||||
id: continueShoppingButton;
|
||||
id: continueButton;
|
||||
color: hifi.buttons.noneBorderlessGray;
|
||||
colorScheme: hifi.colorSchemes.light;
|
||||
anchors.bottom: parent.bottom;
|
||||
|
@ -946,9 +942,9 @@ Rectangle {
|
|||
anchors.right: parent.right;
|
||||
width: 193;
|
||||
height: 44;
|
||||
text: "Continue Shopping";
|
||||
text: "Continue";
|
||||
onClicked: {
|
||||
sendToScript({method: 'checkout_continueShopping', itemId: itemId});
|
||||
sendToScript({method: 'checkout_continue', itemId: itemId});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -971,7 +967,7 @@ Rectangle {
|
|||
|
||||
RalewayRegular {
|
||||
id: failureHeaderText;
|
||||
text: "<b>Purchase Failed.</b><br>Your Purchases and HFC balance haven't changed.";
|
||||
text: "<b>Purchase Failed.</b><br>Your Inventory and HFC balance haven't changed.";
|
||||
// Text size
|
||||
size: 24;
|
||||
// Anchors
|
||||
|
@ -1037,7 +1033,7 @@ Rectangle {
|
|||
width: parent.width/2 - anchors.leftMargin*2;
|
||||
text: "Back to Marketplace";
|
||||
onClicked: {
|
||||
sendToScript({method: 'checkout_continueShopping', itemId: itemId});
|
||||
sendToScript({method: 'checkout_continue', itemId: itemId});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1122,10 +1118,10 @@ Rectangle {
|
|||
if (root.balanceAfterPurchase < 0) {
|
||||
// If you already own the item...
|
||||
if (!root.alreadyOwned) {
|
||||
buyText.text = "<b>Your Wallet does not have sufficient funds to purchase this item.</b>";
|
||||
buyText.text = "<b>You do not have sufficient funds to purchase this item.</b>";
|
||||
// Else if you don't already own the item...
|
||||
} else if (canBuyAgain()) {
|
||||
buyText.text = "<b>Your Wallet does not have sufficient funds to purchase this item again.</b>";
|
||||
buyText.text = "<b>You do not have sufficient funds to purchase this item again.</b>";
|
||||
} else {
|
||||
buyText.text = "<b>While you do not have sufficient funds to buy this, you already have this item.</b>"
|
||||
}
|
||||
|
@ -1171,7 +1167,7 @@ Rectangle {
|
|||
buyText.text = "";
|
||||
}
|
||||
} else {
|
||||
buyText.text = '<i>This type of item cannot currently be certified, so it will not show up in "My Purchases". You can access it again for free from the Marketplace.</i>';
|
||||
buyText.text = '<i>This type of item cannot currently be certified, so it will not show up in "Inventory". You can access it again for free from the Marketplace.</i>';
|
||||
buyTextContainer.color = hifi.colors.white;
|
||||
buyTextContainer.border.color = hifi.colors.white;
|
||||
buyGlyph.text = "";
|
||||
|
|
|
@ -27,7 +27,6 @@ Item {
|
|||
property string referrerURL: (Account.metaverseServerURL + "/marketplace?");
|
||||
readonly property int additionalDropdownHeight: usernameDropdown.height - myUsernameButton.anchors.bottomMargin;
|
||||
property alias usernameDropdownVisible: usernameDropdown.visible;
|
||||
property bool messagesWaiting: false;
|
||||
|
||||
height: mainContainer.height + additionalDropdownHeight;
|
||||
|
||||
|
@ -38,7 +37,6 @@ Item {
|
|||
if (walletStatus === 0) {
|
||||
sendToParent({method: "needsLogIn"});
|
||||
} else if (walletStatus === 5) {
|
||||
Commerce.getAvailableUpdates();
|
||||
Commerce.getSecurityImage();
|
||||
} else if (walletStatus > 5) {
|
||||
console.log("ERROR in EmulatedMarketplaceHeader.qml: Unknown wallet status: " + walletStatus);
|
||||
|
@ -59,14 +57,6 @@ Item {
|
|||
securityImage.source = "image://security/securityImage";
|
||||
}
|
||||
}
|
||||
|
||||
onAvailableUpdatesResult: {
|
||||
if (result.status !== 'success') {
|
||||
console.log("Failed to get Available Updates", result.data.message);
|
||||
} else {
|
||||
root.messagesWaiting = result.data.updates.length > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
|
@ -118,50 +108,6 @@ Item {
|
|||
anchors.right: securityImage.left;
|
||||
anchors.rightMargin: 6;
|
||||
|
||||
Rectangle {
|
||||
id: myPurchasesLink;
|
||||
anchors.right: myUsernameButton.left;
|
||||
anchors.rightMargin: 8;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
height: 40;
|
||||
width: myPurchasesText.paintedWidth + 10;
|
||||
|
||||
RalewaySemiBold {
|
||||
id: myPurchasesText;
|
||||
text: "My Purchases";
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.blueAccent;
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
// Anchors
|
||||
anchors.centerIn: parent;
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
hoverEnabled: enabled;
|
||||
onClicked: {
|
||||
sendToParent({ method: 'header_goToPurchases', hasUpdates: root.messagesWaiting });
|
||||
}
|
||||
onEntered: myPurchasesText.color = hifi.colors.blueHighlight;
|
||||
onExited: myPurchasesText.color = hifi.colors.blueAccent;
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: messagesWaitingLight;
|
||||
visible: root.messagesWaiting;
|
||||
anchors.right: myPurchasesLink.left;
|
||||
anchors.rightMargin: -2;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
height: 10;
|
||||
width: height;
|
||||
radius: height/2;
|
||||
color: "red";
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: textMetrics;
|
||||
font.family: "Raleway"
|
||||
|
@ -267,7 +213,7 @@ Item {
|
|||
anchors.topMargin: -buttonAndUsernameContainer.anchors.bottomMargin;
|
||||
anchors.right: buttonAndUsernameContainer.right;
|
||||
height: childrenRect.height;
|
||||
width: 100;
|
||||
width: 150;
|
||||
|
||||
Rectangle {
|
||||
id: myItemsButton;
|
||||
|
@ -279,7 +225,7 @@ Item {
|
|||
|
||||
RalewaySemiBold {
|
||||
anchors.fill: parent;
|
||||
text: "My Items"
|
||||
text: "My Submissions"
|
||||
color: hifi.colors.baseGray;
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
|
|
|
@ -87,7 +87,7 @@ Rectangle {
|
|||
}
|
||||
RalewayRegular {
|
||||
id: introText2;
|
||||
text: "My Purchases";
|
||||
text: "Inventory";
|
||||
// Text size
|
||||
size: 22;
|
||||
// Anchors
|
||||
|
@ -116,7 +116,7 @@ Rectangle {
|
|||
|
||||
RalewayRegular {
|
||||
id: step1text;
|
||||
text: "The <b>'REZ IT'</b> button makes your purchase appear in front of you.";
|
||||
text: "The <b>'REZ IT'</b> button makes your item appear in front of you.";
|
||||
// Text size
|
||||
size: 20;
|
||||
// Anchors
|
||||
|
|
|
@ -73,6 +73,10 @@ Item {
|
|||
}
|
||||
|
||||
onTransferAssetToNodeResult: {
|
||||
if (!root.visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
root.isCurrentlySendingAsset = false;
|
||||
|
||||
if (result.status === 'success') {
|
||||
|
@ -92,6 +96,10 @@ Item {
|
|||
}
|
||||
|
||||
onTransferAssetToUsernameResult: {
|
||||
if (!root.visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
root.isCurrentlySendingAsset = false;
|
||||
|
||||
if (result.status === 'success') {
|
||||
|
@ -1309,13 +1317,13 @@ Item {
|
|||
|
||||
Rectangle {
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: root.assetName === "" ? 15 : 150;
|
||||
anchors.topMargin: root.assetName === "" ? 15 : 125;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: root.assetName === "" ? 15 : 50;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: root.assetName === "" ? 15 : 50;
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.bottomMargin: root.assetName === "" ? 15 : 240;
|
||||
anchors.bottomMargin: root.assetName === "" ? 15 : 125;
|
||||
color: "#FFFFFF";
|
||||
|
||||
RalewaySemiBold {
|
||||
|
|
|
@ -28,7 +28,7 @@ Rectangle {
|
|||
property string itemName: "--";
|
||||
property string itemOwner: "--";
|
||||
property string itemEdition: "--";
|
||||
property string dateOfPurchase: "--";
|
||||
property string dateAcquired: "--";
|
||||
property string itemCost: "--";
|
||||
property string certTitleTextColor: hifi.colors.darkGray;
|
||||
property string certTextColor: hifi.colors.white;
|
||||
|
@ -64,7 +64,7 @@ Rectangle {
|
|||
root.itemName = "";
|
||||
root.itemEdition = "";
|
||||
root.itemOwner = "";
|
||||
root.dateOfPurchase = "";
|
||||
root.dateAcquired = "";
|
||||
root.itemCost = "";
|
||||
errorText.text = "Information about this certificate is currently unavailable. Please try again later.";
|
||||
}
|
||||
|
@ -77,8 +77,9 @@ Rectangle {
|
|||
// "\u2022" is the Unicode character 'BULLET' - it's what's used in password fields on the web, etc
|
||||
root.itemOwner = root.isMyCert ? Account.username :
|
||||
"\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
|
||||
root.dateOfPurchase = root.isMyCert ? getFormattedDate(result.data.transfer_created_at * 1000) : "Undisclosed";
|
||||
root.itemCost = (root.isMyCert && result.data.cost !== undefined) ? result.data.cost : "Undisclosed";
|
||||
root.dateAcquired = root.isMyCert ? getFormattedDate(result.data.transfer_created_at * 1000) : "Undisclosed";
|
||||
root.itemCost = (root.isMyCert && result.data.cost !== undefined) ?
|
||||
(parseInt(result.data.cost) > 0 ? result.data.cost : "Free") : "Undisclosed";
|
||||
}
|
||||
if (root.certInfoReplaceMode > 4) {
|
||||
root.itemEdition = result.data.edition_number + "/" + (result.data.limited_run === -1 ? "\u221e" : result.data.limited_run);
|
||||
|
@ -86,7 +87,7 @@ Rectangle {
|
|||
|
||||
if (root.certificateStatus === 4) { // CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED
|
||||
if (root.isMyCert) {
|
||||
errorText.text = "This item is an uncertified copy of an item you purchased.";
|
||||
errorText.text = "This item is an uncertified copy of an item you acquired.";
|
||||
} else {
|
||||
errorText.text = "The person who placed this item doesn't own it.";
|
||||
}
|
||||
|
@ -102,8 +103,8 @@ Rectangle {
|
|||
showInMarketplaceButton.visible = false;
|
||||
// "Edition" text previously set above in this function
|
||||
// "Owner" text previously set above in this function
|
||||
// "Purchase Date" text previously set above in this function
|
||||
// "Purchase Price" text previously set above in this function
|
||||
// "Acquisition Date" text previously set above in this function
|
||||
// "Acquisition Price" text previously set above in this function
|
||||
if (result.data.invalid_reason) {
|
||||
errorText.text = result.data.invalid_reason;
|
||||
}
|
||||
|
@ -117,8 +118,8 @@ Rectangle {
|
|||
showInMarketplaceButton.visible = true;
|
||||
// "Edition" text previously set above in this function
|
||||
// "Owner" text previously set above in this function
|
||||
// "Purchase Date" text previously set above in this function
|
||||
// "Purchase Price" text previously set above in this function
|
||||
// "Acquisition Date" text previously set above in this function
|
||||
// "Acquisition Price" text previously set above in this function
|
||||
errorText.text = "The status of this item is still pending confirmation. If the purchase is not confirmed, " +
|
||||
"this entity will be cleaned up by the domain.";
|
||||
}
|
||||
|
@ -145,8 +146,8 @@ Rectangle {
|
|||
// "Item Name" text will be set in "onCertificateInfoResult()"
|
||||
// "Edition" text will be set in "onCertificateInfoResult()"
|
||||
// "Owner" text will be set in "onCertificateInfoResult()"
|
||||
// "Purchase Date" text will be set in "onCertificateInfoResult()"
|
||||
// "Purchase Price" text will be set in "onCertificateInfoResult()"
|
||||
// "Acquisition Date" text will be set in "onCertificateInfoResult()"
|
||||
// "Acquisition Price" text will be set in "onCertificateInfoResult()"
|
||||
errorText.text = "";
|
||||
} else if (root.certificateStatus === 2) { // CERTIFICATE_STATUS_VERIFICATION_TIMEOUT
|
||||
root.useGoldCert = false;
|
||||
|
@ -160,7 +161,7 @@ Rectangle {
|
|||
root.itemName = "";
|
||||
root.itemEdition = "";
|
||||
root.itemOwner = "";
|
||||
root.dateOfPurchase = "";
|
||||
root.dateAcquired = "";
|
||||
root.itemCost = "";
|
||||
errorText.text = "Your request to inspect this item timed out. Please try again later.";
|
||||
} else if (root.certificateStatus === 3) { // CERTIFICATE_STATUS_STATIC_VERIFICATION_FAILED
|
||||
|
@ -175,8 +176,8 @@ Rectangle {
|
|||
// "Item Name" text will be set in "onCertificateInfoResult()"
|
||||
// "Edition" text will be set in "onCertificateInfoResult()"
|
||||
// "Owner" text will be set in "onCertificateInfoResult()"
|
||||
// "Purchase Date" text will be set in "onCertificateInfoResult()"
|
||||
// "Purchase Price" text will be set in "onCertificateInfoResult()"
|
||||
// "Acquisition Date" text will be set in "onCertificateInfoResult()"
|
||||
// "Acquisition Price" text will be set in "onCertificateInfoResult()"
|
||||
errorText.text = "The information associated with this item has been modified and it no longer matches the original certified item.";
|
||||
} else if (root.certificateStatus === 4) { // CERTIFICATE_STATUS_OWNER_VERIFICATION_FAILED
|
||||
root.useGoldCert = false;
|
||||
|
@ -190,8 +191,8 @@ Rectangle {
|
|||
// "Item Name" text will be set in "onCertificateInfoResult()"
|
||||
root.itemEdition = "Uncertified Copy"
|
||||
// "Owner" text will be set in "onCertificateInfoResult()"
|
||||
// "Purchase Date" text will be set in "onCertificateInfoResult()"
|
||||
// "Purchase Price" text will be set in "onCertificateInfoResult()"
|
||||
// "Acquisition Date" text will be set in "onCertificateInfoResult()"
|
||||
// "Acquisition Price" text will be set in "onCertificateInfoResult()"
|
||||
// "Error Text" text will be set in "onCertificateInfoResult()"
|
||||
} else {
|
||||
console.log("Unknown certificate status received from ledger signal!");
|
||||
|
@ -485,8 +486,8 @@ Rectangle {
|
|||
}
|
||||
|
||||
RalewayRegular {
|
||||
id: dateOfPurchaseHeader;
|
||||
text: "PURCHASE DATE";
|
||||
id: dateAcquiredHeader;
|
||||
text: "ACQUISITION DATE";
|
||||
// Text size
|
||||
size: 16;
|
||||
// Anchors
|
||||
|
@ -500,15 +501,15 @@ Rectangle {
|
|||
color: hifi.colors.darkGray;
|
||||
}
|
||||
AnonymousProRegular {
|
||||
id: dateOfPurchase;
|
||||
text: root.dateOfPurchase;
|
||||
id: dateAcquired;
|
||||
text: root.dateAcquired;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Anchors
|
||||
anchors.top: dateOfPurchaseHeader.bottom;
|
||||
anchors.top: dateAcquiredHeader.bottom;
|
||||
anchors.topMargin: 8;
|
||||
anchors.left: dateOfPurchaseHeader.left;
|
||||
anchors.right: dateOfPurchaseHeader.right;
|
||||
anchors.left: dateAcquiredHeader.left;
|
||||
anchors.right: dateAcquiredHeader.right;
|
||||
height: paintedHeight;
|
||||
// Style
|
||||
color: root.infoTextColor;
|
||||
|
@ -516,7 +517,7 @@ Rectangle {
|
|||
|
||||
RalewayRegular {
|
||||
id: priceHeader;
|
||||
text: "PURCHASE PRICE";
|
||||
text: "ACQUISITION PRICE";
|
||||
// Text size
|
||||
size: 16;
|
||||
// Anchors
|
||||
|
@ -530,7 +531,7 @@ Rectangle {
|
|||
}
|
||||
HiFiGlyphs {
|
||||
id: hfcGlyph;
|
||||
visible: priceText.text !== "Undisclosed" && priceText.text !== "";
|
||||
visible: priceText.text !== "Undisclosed" && priceText.text !== "" && priceText.text !== "Free";
|
||||
text: hifi.glyphs.hfc;
|
||||
// Size
|
||||
size: 24;
|
||||
|
@ -618,7 +619,7 @@ Rectangle {
|
|||
root.itemName = "--";
|
||||
root.itemOwner = "--";
|
||||
root.itemEdition = "--";
|
||||
root.dateOfPurchase = "--";
|
||||
root.dateAcquired = "--";
|
||||
root.marketplaceUrl = "";
|
||||
root.itemCost = "--";
|
||||
root.isMyCert = false;
|
||||
|
|
|
@ -47,8 +47,7 @@ Item {
|
|||
property string wornEntityID;
|
||||
property string upgradeUrl;
|
||||
property string upgradeTitle;
|
||||
property bool updateAvailable: root.upgradeUrl !== "" && !root.isShowingMyItems;
|
||||
property bool isShowingMyItems;
|
||||
property bool updateAvailable: root.upgradeUrl !== "";
|
||||
property bool valid;
|
||||
|
||||
property string originalStatusText;
|
||||
|
@ -231,7 +230,7 @@ Item {
|
|||
|
||||
Loader {
|
||||
id: giftButton;
|
||||
visible: !root.isShowingMyItems;
|
||||
visible: root.itemEdition > 0;
|
||||
sourceComponent: contextCardButton;
|
||||
anchors.right: parent.right;
|
||||
anchors.top: parent.top;
|
||||
|
@ -345,6 +344,7 @@ Item {
|
|||
|
||||
Rectangle {
|
||||
id: permissionExplanationCard;
|
||||
visible: false;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 30;
|
||||
anchors.top: parent.top;
|
||||
|
|
|
@ -19,7 +19,6 @@ import "../../../controls" as HifiControls
|
|||
import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere.
|
||||
import "../wallet" as HifiWallet
|
||||
import "../common" as HifiCommerceCommon
|
||||
import "../inspectionCertificate" as HifiInspectionCertificate
|
||||
import "../common/sendAsset" as HifiSendAsset
|
||||
import "../.." as HifiCommon
|
||||
|
||||
|
@ -34,7 +33,6 @@ Rectangle {
|
|||
property bool securityImageResultReceived: false;
|
||||
property bool purchasesReceived: false;
|
||||
property bool punctuationMode: false;
|
||||
property bool isShowingMyItems: false;
|
||||
property bool isDebuggingFirstUseTutorial: false;
|
||||
property string installedApps;
|
||||
property bool keyboardRaised: false;
|
||||
|
@ -92,7 +90,6 @@ Rectangle {
|
|||
if (result.status !== 'success') {
|
||||
console.log("Failed to get Available Updates", result.data.message);
|
||||
} else {
|
||||
sendToScript({method: 'purchases_availableUpdatesReceived', numUpdates: result.data.updates.length });
|
||||
root.numUpdatesAvailable = result.total_entries;
|
||||
}
|
||||
}
|
||||
|
@ -106,10 +103,6 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
onIsShowingMyItemsChanged: {
|
||||
getPurchases();
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: notSetUpTimer;
|
||||
interval: 200;
|
||||
|
@ -118,19 +111,6 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
HifiInspectionCertificate.InspectionCertificate {
|
||||
id: inspectionCertificate;
|
||||
z: 998;
|
||||
visible: false;
|
||||
anchors.fill: parent;
|
||||
|
||||
Connections {
|
||||
onSendToScript: {
|
||||
sendToScript(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HifiCommerceCommon.CommerceLightbox {
|
||||
id: lightboxPopup;
|
||||
z: 999;
|
||||
|
@ -180,7 +160,8 @@ Rectangle {
|
|||
HifiCommerceCommon.EmulatedMarketplaceHeader {
|
||||
id: titleBarContainer;
|
||||
z: 997;
|
||||
visible: !needsLogIn.visible;
|
||||
visible: false;
|
||||
height: 100;
|
||||
// Size
|
||||
width: parent.width;
|
||||
// Anchors
|
||||
|
@ -199,11 +180,6 @@ Rectangle {
|
|||
lightboxPopup.button1method = function() {
|
||||
lightboxPopup.visible = false;
|
||||
}
|
||||
lightboxPopup.button2text = "GO TO WALLET";
|
||||
lightboxPopup.button2method = function() {
|
||||
sendToScript({method: 'purchases_openWallet'});
|
||||
lightboxPopup.visible = false;
|
||||
};
|
||||
lightboxPopup.visible = true;
|
||||
} else {
|
||||
sendToScript(msg);
|
||||
|
@ -475,7 +451,7 @@ Rectangle {
|
|||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 16;
|
||||
width: paintedWidth;
|
||||
text: isShowingMyItems ? "My Items" : "My Purchases";
|
||||
text: "Items";
|
||||
color: hifi.colors.black;
|
||||
size: 22;
|
||||
}
|
||||
|
@ -517,8 +493,13 @@ Rectangle {
|
|||
"filterName": "wearable"
|
||||
},
|
||||
{
|
||||
"separator" : true,
|
||||
"displayName": "Updatable",
|
||||
"filterName": "updated"
|
||||
},
|
||||
{
|
||||
"displayName": "My Submissions",
|
||||
"filterName": "proofs"
|
||||
}
|
||||
]
|
||||
filterBar.primaryFilterChoices.clear();
|
||||
|
@ -533,6 +514,7 @@ Rectangle {
|
|||
onTextChanged: {
|
||||
purchasesModel.searchFilter = filterBar.text;
|
||||
filterBar.previousText = filterBar.text;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -556,10 +538,18 @@ Rectangle {
|
|||
listModelName: 'purchases';
|
||||
listView: purchasesContentsList;
|
||||
getPage: function () {
|
||||
console.debug('getPage', purchasesModel.listModelName, root.isShowingMyItems, filterBar.primaryFilter_filterName, purchasesModel.currentPageToRetrieve, purchasesModel.itemsPerPage);
|
||||
console.debug('getPage', purchasesModel.listModelName, filterBar.primaryFilter_filterName, purchasesModel.currentPageToRetrieve, purchasesModel.itemsPerPage);
|
||||
var editionFilter = "";
|
||||
var primaryFilter = "";
|
||||
|
||||
if (filterBar.primaryFilter_filterName === "proofs") {
|
||||
editionFilter = "proofs";
|
||||
} else {
|
||||
primaryFilter = filterBar.primaryFilter_filterName;
|
||||
}
|
||||
Commerce.inventory(
|
||||
root.isShowingMyItems ? "proofs" : "purchased",
|
||||
filterBar.primaryFilter_filterName,
|
||||
editionFilter,
|
||||
primaryFilter,
|
||||
filterBar.text,
|
||||
purchasesModel.currentPageToRetrieve,
|
||||
purchasesModel.itemsPerPage
|
||||
|
@ -609,7 +599,6 @@ Rectangle {
|
|||
upgradeUrl: model.upgrade_url;
|
||||
upgradeTitle: model.upgrade_title;
|
||||
itemType: model.item_type;
|
||||
isShowingMyItems: root.isShowingMyItems;
|
||||
valid: model.valid;
|
||||
anchors.topMargin: 10;
|
||||
anchors.bottomMargin: 10;
|
||||
|
@ -626,8 +615,6 @@ Rectangle {
|
|||
sendToScript({ method: 'purchases_updateWearables' });
|
||||
}
|
||||
} else if (msg.method === 'purchases_itemCertificateClicked') {
|
||||
inspectionCertificate.visible = true;
|
||||
inspectionCertificate.isLightbox = true;
|
||||
sendToScript(msg);
|
||||
} else if (msg.method === "showInvalidatedLightbox") {
|
||||
lightboxPopup.titleText = "Item Invalidated";
|
||||
|
@ -640,7 +627,7 @@ Rectangle {
|
|||
lightboxPopup.visible = true;
|
||||
} else if (msg.method === "showPendingLightbox") {
|
||||
lightboxPopup.titleText = "Item Pending";
|
||||
lightboxPopup.bodyText = 'Your item is marked "pending" while your purchase is being confirmed. ' +
|
||||
lightboxPopup.bodyText = 'Your item is marked "pending" while the transfer is being confirmed. ' +
|
||||
"Usually, purchases take about 90 seconds to confirm.";
|
||||
lightboxPopup.button1text = "CLOSE";
|
||||
lightboxPopup.button1method = function() {
|
||||
|
@ -822,7 +809,8 @@ Rectangle {
|
|||
|
||||
Rectangle {
|
||||
id: updatesAvailableBanner;
|
||||
visible: root.numUpdatesAvailable > 0 && !root.isShowingMyItems;
|
||||
visible: root.numUpdatesAvailable > 0 &&
|
||||
filterBar.primaryFilter_filterName !== "proofs";
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
|
@ -883,9 +871,8 @@ Rectangle {
|
|||
id: noItemsAlertContainer;
|
||||
visible: !purchasesContentsList.visible &&
|
||||
root.purchasesReceived &&
|
||||
root.isShowingMyItems &&
|
||||
filterBar.text === "" &&
|
||||
filterBar.primaryFilter_displayName === "";
|
||||
filterBar.primaryFilter_filterName === "proofs";
|
||||
anchors.top: filterBarContainer.bottom;
|
||||
anchors.topMargin: 12;
|
||||
anchors.left: parent.left;
|
||||
|
@ -895,7 +882,7 @@ Rectangle {
|
|||
// Explanitory text
|
||||
RalewayRegular {
|
||||
id: noItemsYet;
|
||||
text: "<b>You haven't submitted anything to the Marketplace yet!</b><br><br>Submit an item to the Marketplace to add it to My Items.";
|
||||
text: "<b>You haven't submitted anything to the Marketplace yet!</b><br><br>Submit an item to the Marketplace to add it to My Submissions.";
|
||||
// Text size
|
||||
size: 22;
|
||||
// Anchors
|
||||
|
@ -933,7 +920,6 @@ Rectangle {
|
|||
id: noPurchasesAlertContainer;
|
||||
visible: !purchasesContentsList.visible &&
|
||||
root.purchasesReceived &&
|
||||
!root.isShowingMyItems &&
|
||||
filterBar.text === "" &&
|
||||
filterBar.primaryFilter_displayName === "";
|
||||
anchors.top: filterBarContainer.bottom;
|
||||
|
@ -945,7 +931,7 @@ Rectangle {
|
|||
// Explanitory text
|
||||
RalewayRegular {
|
||||
id: haventPurchasedYet;
|
||||
text: "<b>You haven't purchased anything yet!</b><br><br>Get an item from <b>Marketplace</b> to add it to My Purchases.";
|
||||
text: "<b>You haven't gotten anything yet!</b><br><br>Get an item from <b>Marketplace</b> to add it to your Inventory.";
|
||||
// Text size
|
||||
size: 22;
|
||||
// Anchors
|
||||
|
@ -1065,11 +1051,10 @@ Rectangle {
|
|||
titleBarContainer.referrerURL = message.referrerURL || "";
|
||||
filterBar.text = message.filterText ? message.filterText : "";
|
||||
break;
|
||||
case 'inspectionCertificate_setCertificateId':
|
||||
inspectionCertificate.fromScript(message);
|
||||
break;
|
||||
case 'purchases_showMyItems':
|
||||
root.isShowingMyItems = true;
|
||||
filterBar.primaryFilter_filterName = "proofs";
|
||||
filterBar.primaryFilter_displayName = "Proofs";
|
||||
filterBar.primaryFilter_index = 6;
|
||||
break;
|
||||
case 'updateConnections':
|
||||
sendAsset.updateConnections(message.connections);
|
||||
|
|
|
@ -62,7 +62,7 @@ Item {
|
|||
isExpanded: false;
|
||||
question: "How can I get HFC?";
|
||||
answer: "High Fidelity commerce is in open beta right now. Want more HFC? \
|
||||
Get it by going to <br><br><b><font color='#0093C5'><a href='#bank'>BankOfHighFidelity.</a></font></b> and meeting with the banker!";
|
||||
Get it by going to <b><font color='#0093C5'><a href='#bank'>BankOfHighFidelity</a></font></b> and meeting with the banker!";
|
||||
}
|
||||
ListElement {
|
||||
isExpanded: false;
|
||||
|
|
|
@ -93,7 +93,7 @@ Item {
|
|||
// Text below helper text
|
||||
RalewayRegular {
|
||||
id: loginDetailText;
|
||||
text: "To buy/sell items on the <b>Marketplace</b>, or to use your <b>Wallet</b>, you must first log in to High Fidelity.";
|
||||
text: "To get items on the <b>Marketplace</b>, or to use your <b>Assets</b>, you must first log in to High Fidelity.";
|
||||
// Text size
|
||||
size: 18;
|
||||
// Anchors
|
||||
|
|
|
@ -20,6 +20,8 @@ import "../../../controls" as HifiControls
|
|||
import "../common" as HifiCommerceCommon
|
||||
import "../common/sendAsset"
|
||||
import "../.." as HifiCommon
|
||||
import "../purchases" as HifiPurchases
|
||||
import "../inspectionCertificate" as HifiInspectionCertificate
|
||||
|
||||
Rectangle {
|
||||
HifiConstants { id: hifi; }
|
||||
|
@ -27,6 +29,7 @@ Rectangle {
|
|||
id: root;
|
||||
|
||||
property string activeView: "initialize";
|
||||
property string initialActiveViewAfterStatus5: "walletInventory";
|
||||
property bool keyboardRaised: false;
|
||||
property bool isPassword: false;
|
||||
|
||||
|
@ -64,7 +67,8 @@ Rectangle {
|
|||
}
|
||||
} else if (walletStatus === 5) {
|
||||
if (root.activeView !== "walletSetup") {
|
||||
root.activeView = "walletHome";
|
||||
root.activeView = root.initialActiveViewAfterStatus5;
|
||||
Commerce.getAvailableUpdates();
|
||||
Commerce.getSecurityImage();
|
||||
}
|
||||
} else {
|
||||
|
@ -86,6 +90,21 @@ Rectangle {
|
|||
titleBarSecurityImage.source = "image://security/securityImage";
|
||||
}
|
||||
}
|
||||
|
||||
onAvailableUpdatesResult: {
|
||||
if (result.status !== 'success') {
|
||||
console.log("Failed to get Available Updates", result.data.message);
|
||||
} else {
|
||||
exchangeMoneyButtonContainer.messagesWaiting = result.data.updates.length > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onActiveViewChanged: {
|
||||
if (activeView === "walletHome") {
|
||||
walletHomeButtonContainer.messagesWaiting = false;
|
||||
sendToScript({method: 'clearShouldShowDotHistory'});
|
||||
}
|
||||
}
|
||||
|
||||
HifiCommerceCommon.CommerceLightbox {
|
||||
|
@ -108,29 +127,32 @@ Rectangle {
|
|||
anchors.top: parent.top;
|
||||
|
||||
// Wallet icon
|
||||
HiFiGlyphs {
|
||||
Image {
|
||||
id: walletIcon;
|
||||
text: hifi.glyphs.wallet;
|
||||
// Size
|
||||
size: parent.height * 0.8;
|
||||
// Anchors
|
||||
source: "../../../../icons/tablet-icons/inventory-a.svg";
|
||||
height: parent.height * 0.5;
|
||||
width: walletIcon.height;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 8;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
// Style
|
||||
visible: false; // When we use a white .svg instead of a glyph with color property, we set to invisible and use the following ColorOverlay.
|
||||
}
|
||||
ColorOverlay {
|
||||
anchors.fill: walletIcon;
|
||||
source: walletIcon;
|
||||
color: hifi.colors.blueHighlight;
|
||||
}
|
||||
|
||||
// Title Bar text
|
||||
RalewaySemiBold {
|
||||
id: titleBarText;
|
||||
text: "WALLET";
|
||||
text: "INVENTORY";
|
||||
// Text size
|
||||
size: hifi.fontSizes.overlayTitle;
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.left: walletIcon.right;
|
||||
anchors.leftMargin: 4;
|
||||
anchors.leftMargin: 6;
|
||||
anchors.bottom: parent.bottom;
|
||||
width: paintedWidth;
|
||||
// Style
|
||||
|
@ -319,6 +341,39 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
HifiInspectionCertificate.InspectionCertificate {
|
||||
id: inspectionCertificate;
|
||||
z: 998;
|
||||
visible: false;
|
||||
anchors.fill: parent;
|
||||
|
||||
Connections {
|
||||
onSendToScript: {
|
||||
sendToScript(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HifiPurchases.Purchases {
|
||||
id: walletInventory;
|
||||
visible: root.activeView === "walletInventory";
|
||||
anchors.top: titleBarContainer.bottom;
|
||||
anchors.bottom: !WalletScriptingInterface.limitedCommerce ? tabButtonsContainer.top : parent.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
Connections {
|
||||
onSendToScript: {
|
||||
if (message.method === 'purchases_itemCertificateClicked') {
|
||||
inspectionCertificate.visible = true;
|
||||
inspectionCertificate.isLightbox = true;
|
||||
sendToScript(message);
|
||||
} else {
|
||||
sendToScript(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HifiCommon.RootHttpRequest {
|
||||
id: http;
|
||||
}
|
||||
|
@ -361,7 +416,7 @@ Rectangle {
|
|||
//
|
||||
Item {
|
||||
id: tabButtonsContainer;
|
||||
visible: !needsLogIn.visible && root.activeView !== "passphraseChange" && sendMoney.currentActiveView !== "sendAssetStep";
|
||||
visible: !needsLogIn.visible && root.activeView !== "passphraseChange" && sendMoney.currentActiveView !== "sendAssetStep" && !WalletScriptingInterface.limitedCommerce;
|
||||
property int numTabs: 4;
|
||||
// Size
|
||||
width: root.width;
|
||||
|
@ -380,16 +435,17 @@ Rectangle {
|
|||
// "WALLET HOME" tab button
|
||||
Rectangle {
|
||||
id: walletHomeButtonContainer;
|
||||
property bool messagesWaiting: false;
|
||||
visible: !walletSetup.visible;
|
||||
color: root.activeView === "walletHome" ? hifi.colors.blueAccent : hifi.colors.black;
|
||||
anchors.top: parent.top;
|
||||
anchors.left: parent.left;
|
||||
anchors.left: exchangeMoneyButtonContainer.right;
|
||||
anchors.bottom: parent.bottom;
|
||||
width: parent.width / tabButtonsContainer.numTabs;
|
||||
|
||||
|
||||
HiFiGlyphs {
|
||||
id: homeTabIcon;
|
||||
text: hifi.glyphs.home2;
|
||||
text: hifi.glyphs.leftRightArrows;
|
||||
// Size
|
||||
size: 50;
|
||||
// Anchors
|
||||
|
@ -397,11 +453,24 @@ Rectangle {
|
|||
anchors.top: parent.top;
|
||||
anchors.topMargin: -2;
|
||||
// Style
|
||||
color: root.activeView === "walletHome" || walletHomeTabMouseArea.containsMouse ? hifi.colors.white : hifi.colors.blueHighlight;
|
||||
color: WalletScriptingInterface.limitedCommerce ? hifi.colors.lightGray50 : ((root.activeView === "walletHome" || walletHomeTabMouseArea.containsMouse) ? hifi.colors.white : hifi.colors.blueHighlight);
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: recentActivityMessagesWaitingLight;
|
||||
visible: parent.messagesWaiting;
|
||||
anchors.right: homeTabIcon.left;
|
||||
anchors.rightMargin: -4;
|
||||
anchors.top: homeTabIcon.top;
|
||||
anchors.topMargin: 16;
|
||||
height: 10;
|
||||
width: height;
|
||||
radius: height/2;
|
||||
color: "red";
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
text: "WALLET HOME";
|
||||
text: "RECENT ACTIVITY";
|
||||
// Text size
|
||||
size: 16;
|
||||
// Anchors
|
||||
|
@ -412,7 +481,7 @@ Rectangle {
|
|||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 4;
|
||||
// Style
|
||||
color: root.activeView === "walletHome" || walletHomeTabMouseArea.containsMouse ? hifi.colors.white : hifi.colors.blueHighlight;
|
||||
color: WalletScriptingInterface.limitedCommerce ? hifi.colors.lightGray50 : ((root.activeView === "walletHome" || walletHomeTabMouseArea.containsMouse) ? hifi.colors.white : hifi.colors.blueHighlight);
|
||||
wrapMode: Text.WordWrap;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
|
@ -421,6 +490,7 @@ Rectangle {
|
|||
MouseArea {
|
||||
id: walletHomeTabMouseArea;
|
||||
anchors.fill: parent;
|
||||
enabled: !WalletScriptingInterface.limitedCommerce;
|
||||
hoverEnabled: enabled;
|
||||
onClicked: {
|
||||
root.activeView = "walletHome";
|
||||
|
@ -434,28 +504,46 @@ Rectangle {
|
|||
// "EXCHANGE MONEY" tab button
|
||||
Rectangle {
|
||||
id: exchangeMoneyButtonContainer;
|
||||
property bool messagesWaiting: false;
|
||||
|
||||
visible: !walletSetup.visible;
|
||||
color: hifi.colors.black;
|
||||
color: root.activeView === "walletInventory" ? hifi.colors.blueAccent : hifi.colors.black;
|
||||
anchors.top: parent.top;
|
||||
anchors.left: walletHomeButtonContainer.right;
|
||||
anchors.left: parent.left;
|
||||
anchors.bottom: parent.bottom;
|
||||
width: parent.width / tabButtonsContainer.numTabs;
|
||||
|
||||
HiFiGlyphs {
|
||||
|
||||
Image {
|
||||
id: exchangeMoneyTabIcon;
|
||||
text: hifi.glyphs.leftRightArrows;
|
||||
// Size
|
||||
size: 50;
|
||||
// Anchors
|
||||
source: "images/items-tab-a.svg";
|
||||
height: 25;
|
||||
width: exchangeMoneyTabIcon.height;
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: -2;
|
||||
// Style
|
||||
color: hifi.colors.lightGray50;
|
||||
anchors.topMargin: 10;
|
||||
visible: false; // When we use a white .svg instead of a glyph with color property, we set to invisible and use the following ColorOverlay.
|
||||
}
|
||||
ColorOverlay {
|
||||
anchors.fill: exchangeMoneyTabIcon;
|
||||
source: exchangeMoneyTabIcon;
|
||||
color: root.activeView === "walletInventory" || inventoryTabMouseArea.containsMouse ? hifi.colors.white : hifi.colors.blueHighlight;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: exchangeMoneyMessagesWaitingLight;
|
||||
visible: parent.messagesWaiting;
|
||||
anchors.right: exchangeMoneyTabIcon.left;
|
||||
anchors.rightMargin: 9;
|
||||
anchors.top: exchangeMoneyTabIcon.top;
|
||||
anchors.topMargin: 4;
|
||||
height: 10;
|
||||
width: height;
|
||||
radius: height/2;
|
||||
color: "red";
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
text: "EXCHANGE MONEY";
|
||||
text: "ITEMS";
|
||||
// Text size
|
||||
size: 16;
|
||||
// Anchors
|
||||
|
@ -466,12 +554,24 @@ Rectangle {
|
|||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 4;
|
||||
// Style
|
||||
color: hifi.colors.lightGray50;
|
||||
color: root.activeView === "walletInventory" || inventoryTabMouseArea.containsMouse ? hifi.colors.white : hifi.colors.blueHighlight;
|
||||
wrapMode: Text.WordWrap;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
verticalAlignment: Text.AlignTop;
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: inventoryTabMouseArea;
|
||||
anchors.fill: parent;
|
||||
hoverEnabled: enabled;
|
||||
onClicked: {
|
||||
root.activeView = "walletInventory";
|
||||
tabButtonsContainer.resetTabButtonColors();
|
||||
}
|
||||
onEntered: parent.color = hifi.colors.blueHighlight;
|
||||
onExited: parent.color = root.activeView === "walletInventory" ? hifi.colors.blueAccent : hifi.colors.black;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -481,10 +581,10 @@ Rectangle {
|
|||
visible: !walletSetup.visible;
|
||||
color: root.activeView === "sendMoney" ? hifi.colors.blueAccent : hifi.colors.black;
|
||||
anchors.top: parent.top;
|
||||
anchors.left: exchangeMoneyButtonContainer.right;
|
||||
anchors.left: walletHomeButtonContainer.right;
|
||||
anchors.bottom: parent.bottom;
|
||||
width: parent.width / tabButtonsContainer.numTabs;
|
||||
|
||||
|
||||
HiFiGlyphs {
|
||||
id: sendMoneyTabIcon;
|
||||
text: hifi.glyphs.paperPlane;
|
||||
|
@ -495,7 +595,7 @@ Rectangle {
|
|||
anchors.top: parent.top;
|
||||
anchors.topMargin: -2;
|
||||
// Style
|
||||
color: root.activeView === "sendMoney" || sendMoneyTabMouseArea.containsMouse ? hifi.colors.white : hifi.colors.blueHighlight;
|
||||
color: WalletScriptingInterface.limitedCommerce ? hifi.colors.lightGray50 : ((root.activeView === "sendMoney" || sendMoneyTabMouseArea.containsMouse) ? hifi.colors.white : hifi.colors.blueHighlight);
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
|
@ -510,7 +610,7 @@ Rectangle {
|
|||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 4;
|
||||
// Style
|
||||
color: root.activeView === "sendMoney" || sendMoneyTabMouseArea.containsMouse ? hifi.colors.white : hifi.colors.blueHighlight;
|
||||
color: WalletScriptingInterface.limitedCommerce ? hifi.colors.lightGray50 : ((root.activeView === "sendMoney" || sendMoneyTabMouseArea.containsMouse) ? hifi.colors.white : hifi.colors.blueHighlight);
|
||||
wrapMode: Text.WordWrap;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
|
@ -520,6 +620,7 @@ Rectangle {
|
|||
MouseArea {
|
||||
id: sendMoneyTabMouseArea;
|
||||
anchors.fill: parent;
|
||||
enabled: !WalletScriptingInterface.limitedCommerce;
|
||||
hoverEnabled: enabled;
|
||||
onClicked: {
|
||||
root.activeView = "sendMoney";
|
||||
|
@ -539,7 +640,7 @@ Rectangle {
|
|||
anchors.left: sendMoneyButtonContainer.right;
|
||||
anchors.bottom: parent.bottom;
|
||||
width: parent.width / tabButtonsContainer.numTabs;
|
||||
|
||||
|
||||
HiFiGlyphs {
|
||||
id: helpTabIcon;
|
||||
text: hifi.glyphs.question;
|
||||
|
@ -588,16 +689,16 @@ Rectangle {
|
|||
function resetTabButtonColors() {
|
||||
walletHomeButtonContainer.color = hifi.colors.black;
|
||||
sendMoneyButtonContainer.color = hifi.colors.black;
|
||||
securityButtonContainer.color = hifi.colors.black;
|
||||
helpButtonContainer.color = hifi.colors.black;
|
||||
exchangeMoneyButtonContainer.color = hifi.colors.black;
|
||||
if (root.activeView === "walletHome") {
|
||||
walletHomeButtonContainer.color = hifi.colors.blueAccent;
|
||||
} else if (root.activeView === "sendMoney") {
|
||||
sendMoneyButtonContainer.color = hifi.colors.blueAccent;
|
||||
} else if (root.activeView === "security") {
|
||||
securityButtonContainer.color = hifi.colors.blueAccent;
|
||||
} else if (root.activeView === "help") {
|
||||
helpButtonContainer.color = hifi.colors.blueAccent;
|
||||
} else if (root.activeView == "walletInventory") {
|
||||
exchangeMoneyButtonContainer.color = hifi.colors.blueAccent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -663,18 +764,40 @@ Rectangle {
|
|||
break;
|
||||
case 'updateConnections':
|
||||
sendMoney.updateConnections(message.connections);
|
||||
walletInventory.fromScript(message);
|
||||
break;
|
||||
case 'selectRecipient':
|
||||
case 'updateSelectedRecipientUsername':
|
||||
sendMoney.fromScript(message);
|
||||
walletInventory.fromScript(message);
|
||||
break;
|
||||
case 'http.response':
|
||||
http.handleHttpResponse(message);
|
||||
// Duplicate handler is required because we don't track referrer for `http`
|
||||
walletInventory.fromScript(message);
|
||||
break;
|
||||
case 'palIsStale':
|
||||
case 'avatarDisconnected':
|
||||
// Because we don't have "channels" for sending messages to a specific QML object, the messages are broadcast to all QML Items. If an Item of yours happens to be visible when some script sends a message with a method you don't expect, you'll get "Unrecognized message..." logs.
|
||||
break;
|
||||
case 'inspectionCertificate_setCertificateId':
|
||||
inspectionCertificate.fromScript(message);
|
||||
break;
|
||||
case 'updatePurchases':
|
||||
case 'purchases_showMyItems':
|
||||
case 'updateWearables':
|
||||
walletInventory.fromScript(message);
|
||||
break;
|
||||
case 'updateRecentActivityMessageLight':
|
||||
walletHomeButtonContainer.messagesWaiting = message.messagesWaiting;
|
||||
break;
|
||||
case 'checkout_openRecentActivity':
|
||||
if (root.activeView === "initialize") {
|
||||
root.initialActiveViewAfterStatus5 = "walletHome";
|
||||
} else {
|
||||
root.activeView = "walletHome";
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.log('Unrecognized message from wallet.js:', JSON.stringify(message));
|
||||
}
|
||||
|
@ -722,7 +845,8 @@ Rectangle {
|
|||
root.activeView = "initialize";
|
||||
Commerce.getWalletStatus();
|
||||
} else if (msg.referrer === 'purchases') {
|
||||
sendToScript({method: 'goToPurchases'});
|
||||
root.activeView = "walletInventory";
|
||||
tabButtonsContainer.resetTabButtonColors();
|
||||
} else if (msg.referrer === 'marketplace cta' || msg.referrer === 'mainPage') {
|
||||
sendToScript({method: 'goToMarketplaceMainPage', itemId: msg.referrer});
|
||||
} else {
|
||||
|
|
|
@ -179,28 +179,6 @@ Item {
|
|||
color: hifi.colors.baseGrayHighlight;
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
id: myPurchasesLink;
|
||||
text: '<font color="#0093C5"><a href="#myPurchases">My Purchases</a></font>';
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: 26;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 20;
|
||||
width: paintedWidth;
|
||||
height: 30;
|
||||
y: 4;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.baseGrayHighlight;
|
||||
horizontalAlignment: Text.AlignRight;
|
||||
|
||||
onLinkActivated: {
|
||||
sendSignalToWallet({method: 'goToPurchases_fromWalletHome'});
|
||||
}
|
||||
}
|
||||
|
||||
HifiModels.PSFListModel {
|
||||
id: transactionHistoryModel;
|
||||
property int lastPendingCount: 0;
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<svg width="26" height="24" viewBox="0 0 26 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<line x1="6" y1="2" x2="26" y2="2" stroke="white" stroke-width="4"/>
|
||||
<line x1="1.74846e-07" y1="2" x2="4" y2="2" stroke="white" stroke-width="4"/>
|
||||
<line x1="6" y1="12" x2="26" y2="12" stroke="white" stroke-width="4"/>
|
||||
<line x1="1.74846e-07" y1="12" x2="4" y2="12" stroke="white" stroke-width="4"/>
|
||||
<line x1="6" y1="22" x2="26" y2="22" stroke="white" stroke-width="4"/>
|
||||
<line x1="1.74846e-07" y1="22" x2="4" y2="22" stroke="white" stroke-width="4"/>
|
||||
</svg>
|
After Width: | Height: | Size: 552 B |
|
@ -328,7 +328,7 @@ Rectangle {
|
|||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
text: "Your wallet is not set up.\n" +
|
||||
"Open the WALLET app to get started.";
|
||||
"Open the ASSETS app to get started.";
|
||||
// Anchors
|
||||
anchors.fill: parent;
|
||||
// Text size
|
||||
|
|
|
@ -1152,7 +1152,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
|
||||
// set the OCULUS_STORE property so the oculus plugin can know if we ran from the Oculus Store
|
||||
static const QString OCULUS_STORE_ARG = "--oculus-store";
|
||||
setProperty(hifi::properties::OCULUS_STORE, arguments().indexOf(OCULUS_STORE_ARG) != -1);
|
||||
bool isStore = arguments().indexOf(OCULUS_STORE_ARG) != -1;
|
||||
setProperty(hifi::properties::OCULUS_STORE, isStore);
|
||||
DependencyManager::get<WalletScriptingInterface>()->setLimitedCommerce(isStore); // Or we could make it a separate arg, or if either arg is set, etc. And should this instead by a hifi::properties?
|
||||
|
||||
updateHeartbeat();
|
||||
|
||||
|
@ -3130,7 +3132,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) {
|
|||
surfaceContext->setContextProperty("AvatarInputs", AvatarInputs::getInstance());
|
||||
surfaceContext->setContextProperty("Selection", DependencyManager::get<SelectionScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data());
|
||||
surfaceContext->setContextProperty("Wallet", DependencyManager::get<WalletScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("WalletScriptingInterface", DependencyManager::get<WalletScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("HiFiAbout", AboutUtil::getInstance());
|
||||
surfaceContext->setContextProperty("ResourceRequestObserver", DependencyManager::get<ResourceRequestObserver>().data());
|
||||
|
||||
|
@ -6990,7 +6992,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe
|
|||
scriptEngine->registerGlobalObject("AvatarInputs", AvatarInputs::getInstance());
|
||||
scriptEngine->registerGlobalObject("Selection", DependencyManager::get<SelectionScriptingInterface>().data());
|
||||
scriptEngine->registerGlobalObject("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data());
|
||||
scriptEngine->registerGlobalObject("Wallet", DependencyManager::get<WalletScriptingInterface>().data());
|
||||
scriptEngine->registerGlobalObject("WalletScriptingInterface", DependencyManager::get<WalletScriptingInterface>().data());
|
||||
scriptEngine->registerGlobalObject("AddressManager", DependencyManager::get<AddressManager>().data());
|
||||
scriptEngine->registerGlobalObject("HifiAbout", AboutUtil::getInstance());
|
||||
scriptEngine->registerGlobalObject("ResourceRequestObserver", DependencyManager::get<ResourceRequestObserver>().data());
|
||||
|
@ -7998,6 +8000,7 @@ void Application::loadAvatarBrowser() const {
|
|||
auto tablet = dynamic_cast<TabletProxy*>(DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system"));
|
||||
// construct the url to the marketplace item
|
||||
QString url = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/marketplace?category=avatars";
|
||||
|
||||
QString MARKETPLACES_INJECT_SCRIPT_PATH = "file:///" + qApp->applicationDirPath() + "/scripts/system/html/js/marketplacesInject.js";
|
||||
tablet->gotoWebScreen(url, MARKETPLACES_INJECT_SCRIPT_PATH);
|
||||
DependencyManager::get<HMDScriptingInterface>()->openTablet();
|
||||
|
|
|
@ -109,10 +109,10 @@ bool ModelPackager::loadModel() {
|
|||
qCDebug(interfaceapp) << "Reading FBX file : " << _fbxInfo.filePath();
|
||||
QByteArray fbxContents = fbx.readAll();
|
||||
|
||||
_geometry.reset(readFBX(fbxContents, QVariantHash(), _fbxInfo.filePath()));
|
||||
_hfmModel.reset(readFBX(fbxContents, QVariantHash(), _fbxInfo.filePath()));
|
||||
|
||||
// make sure we have some basic mappings
|
||||
populateBasicMapping(_mapping, _fbxInfo.filePath(), *_geometry);
|
||||
populateBasicMapping(_mapping, _fbxInfo.filePath(), *_hfmModel);
|
||||
} catch (const QString& error) {
|
||||
qCDebug(interfaceapp) << "Error reading " << _fbxInfo.filePath() << ": " << error;
|
||||
return false;
|
||||
|
@ -122,7 +122,7 @@ bool ModelPackager::loadModel() {
|
|||
|
||||
bool ModelPackager::editProperties() {
|
||||
// open the dialog to configure the rest
|
||||
ModelPropertiesDialog properties(_modelType, _mapping, _modelFile.path(), *_geometry);
|
||||
ModelPropertiesDialog properties(_modelType, _mapping, _modelFile.path(), *_hfmModel);
|
||||
if (properties.exec() == QDialog::Rejected) {
|
||||
return false;
|
||||
}
|
||||
|
@ -235,18 +235,18 @@ bool ModelPackager::zipModel() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename, const HFMGeometry& geometry) {
|
||||
void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename, const HFMModel& hfmModel) {
|
||||
|
||||
bool isBodyType = _modelType == FSTReader::BODY_ONLY_MODEL || _modelType == FSTReader::HEAD_AND_BODY_MODEL;
|
||||
|
||||
// mixamo files - in the event that a mixamo file was edited by some other tool, it's likely the applicationName will
|
||||
// be rewritten, so we detect the existence of several different blendshapes which indicate we're likely a mixamo file
|
||||
bool likelyMixamoFile = geometry.applicationName == "mixamo.com" ||
|
||||
(geometry.blendshapeChannelNames.contains("BrowsDown_Right") &&
|
||||
geometry.blendshapeChannelNames.contains("MouthOpen") &&
|
||||
geometry.blendshapeChannelNames.contains("Blink_Left") &&
|
||||
geometry.blendshapeChannelNames.contains("Blink_Right") &&
|
||||
geometry.blendshapeChannelNames.contains("Squint_Right"));
|
||||
bool likelyMixamoFile = hfmModel.applicationName == "mixamo.com" ||
|
||||
(hfmModel.blendshapeChannelNames.contains("BrowsDown_Right") &&
|
||||
hfmModel.blendshapeChannelNames.contains("MouthOpen") &&
|
||||
hfmModel.blendshapeChannelNames.contains("Blink_Left") &&
|
||||
hfmModel.blendshapeChannelNames.contains("Blink_Right") &&
|
||||
hfmModel.blendshapeChannelNames.contains("Squint_Right"));
|
||||
|
||||
if (!mapping.contains(NAME_FIELD)) {
|
||||
mapping.insert(NAME_FIELD, QFileInfo(filename).baseName());
|
||||
|
@ -268,15 +268,15 @@ void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename
|
|||
}
|
||||
QVariantHash joints = mapping.value(JOINT_FIELD).toHash();
|
||||
if (!joints.contains("jointEyeLeft")) {
|
||||
joints.insert("jointEyeLeft", geometry.jointIndices.contains("jointEyeLeft") ? "jointEyeLeft" :
|
||||
(geometry.jointIndices.contains("EyeLeft") ? "EyeLeft" : "LeftEye"));
|
||||
joints.insert("jointEyeLeft", hfmModel.jointIndices.contains("jointEyeLeft") ? "jointEyeLeft" :
|
||||
(hfmModel.jointIndices.contains("EyeLeft") ? "EyeLeft" : "LeftEye"));
|
||||
}
|
||||
if (!joints.contains("jointEyeRight")) {
|
||||
joints.insert("jointEyeRight", geometry.jointIndices.contains("jointEyeRight") ? "jointEyeRight" :
|
||||
geometry.jointIndices.contains("EyeRight") ? "EyeRight" : "RightEye");
|
||||
joints.insert("jointEyeRight", hfmModel.jointIndices.contains("jointEyeRight") ? "jointEyeRight" :
|
||||
hfmModel.jointIndices.contains("EyeRight") ? "EyeRight" : "RightEye");
|
||||
}
|
||||
if (!joints.contains("jointNeck")) {
|
||||
joints.insert("jointNeck", geometry.jointIndices.contains("jointNeck") ? "jointNeck" : "Neck");
|
||||
joints.insert("jointNeck", hfmModel.jointIndices.contains("jointNeck") ? "jointNeck" : "Neck");
|
||||
}
|
||||
|
||||
if (isBodyType) {
|
||||
|
@ -296,7 +296,7 @@ void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename
|
|||
|
||||
if (!joints.contains("jointHead")) {
|
||||
const char* topName = likelyMixamoFile ? "HeadTop_End" : "HeadEnd";
|
||||
joints.insert("jointHead", geometry.jointIndices.contains(topName) ? topName : "Head");
|
||||
joints.insert("jointHead", hfmModel.jointIndices.contains(topName) ? topName : "Head");
|
||||
}
|
||||
|
||||
mapping.insert(JOINT_FIELD, joints);
|
||||
|
@ -370,7 +370,7 @@ void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename
|
|||
|
||||
void ModelPackager::listTextures() {
|
||||
_textures.clear();
|
||||
foreach (const HFMMaterial mat, _geometry->materials) {
|
||||
foreach (const HFMMaterial mat, _hfmModel->materials) {
|
||||
if (!mat.albedoTexture.filename.isEmpty() && mat.albedoTexture.content.isEmpty() &&
|
||||
!_textures.contains(mat.albedoTexture.filename)) {
|
||||
_textures << mat.albedoTexture.filename;
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#include "ui/ModelsBrowser.h"
|
||||
|
||||
class HFMGeometry;
|
||||
class HFMModel;
|
||||
|
||||
class ModelPackager : public QObject {
|
||||
public:
|
||||
|
@ -32,7 +32,7 @@ private:
|
|||
bool editProperties();
|
||||
bool zipModel();
|
||||
|
||||
void populateBasicMapping(QVariantHash& mapping, QString filename, const HFMGeometry& geometry);
|
||||
void populateBasicMapping(QVariantHash& mapping, QString filename, const HFMModel& hfmModel);
|
||||
|
||||
void listTextures();
|
||||
bool copyTextures(const QString& oldDir, const QDir& newDir);
|
||||
|
@ -44,7 +44,7 @@ private:
|
|||
QString _scriptDir;
|
||||
|
||||
QVariantHash _mapping;
|
||||
std::unique_ptr<HFMGeometry> _geometry;
|
||||
std::unique_ptr<HFMModel> _hfmModel;
|
||||
QStringList _textures;
|
||||
QStringList _scripts;
|
||||
};
|
||||
|
|
|
@ -27,11 +27,11 @@
|
|||
|
||||
|
||||
ModelPropertiesDialog::ModelPropertiesDialog(FSTReader::ModelType modelType, const QVariantHash& originalMapping,
|
||||
const QString& basePath, const HFMGeometry& geometry) :
|
||||
const QString& basePath, const HFMModel& hfmModel) :
|
||||
_modelType(modelType),
|
||||
_originalMapping(originalMapping),
|
||||
_basePath(basePath),
|
||||
_geometry(geometry)
|
||||
_hfmModel(hfmModel)
|
||||
{
|
||||
setWindowTitle("Set Model Properties");
|
||||
|
||||
|
@ -108,8 +108,8 @@ QVariantHash ModelPropertiesDialog::getMapping() const {
|
|||
|
||||
// update the joint indices
|
||||
QVariantHash jointIndices;
|
||||
for (int i = 0; i < _geometry.joints.size(); i++) {
|
||||
jointIndices.insert(_geometry.joints.at(i).name, QString::number(i));
|
||||
for (int i = 0; i < _hfmModel.joints.size(); i++) {
|
||||
jointIndices.insert(_hfmModel.joints.at(i).name, QString::number(i));
|
||||
}
|
||||
mapping.insert(JOINT_INDEX_FIELD, jointIndices);
|
||||
|
||||
|
@ -118,10 +118,10 @@ QVariantHash ModelPropertiesDialog::getMapping() const {
|
|||
if (_modelType == FSTReader::ATTACHMENT_MODEL) {
|
||||
glm::vec3 pivot;
|
||||
if (_pivotAboutCenter->isChecked()) {
|
||||
pivot = (_geometry.meshExtents.minimum + _geometry.meshExtents.maximum) * 0.5f;
|
||||
pivot = (_hfmModel.meshExtents.minimum + _hfmModel.meshExtents.maximum) * 0.5f;
|
||||
|
||||
} else if (_pivotJoint->currentIndex() != 0) {
|
||||
pivot = extractTranslation(_geometry.joints.at(_pivotJoint->currentIndex() - 1).transform);
|
||||
pivot = extractTranslation(_hfmModel.joints.at(_pivotJoint->currentIndex() - 1).transform);
|
||||
}
|
||||
mapping.insert(TRANSLATION_X_FIELD, -pivot.x * (float)_scale->value() + (float)_translationX->value());
|
||||
mapping.insert(TRANSLATION_Y_FIELD, -pivot.y * (float)_scale->value() + (float)_translationY->value());
|
||||
|
@ -191,7 +191,7 @@ void ModelPropertiesDialog::reset() {
|
|||
}
|
||||
foreach (const QVariant& joint, _originalMapping.values(FREE_JOINT_FIELD)) {
|
||||
QString jointName = joint.toString();
|
||||
if (_geometry.jointIndices.contains(jointName)) {
|
||||
if (_hfmModel.jointIndices.contains(jointName)) {
|
||||
createNewFreeJoint(jointName);
|
||||
}
|
||||
}
|
||||
|
@ -249,8 +249,8 @@ QComboBox* ModelPropertiesDialog::createJointBox(bool withNone) const {
|
|||
if (withNone) {
|
||||
box->addItem("(none)");
|
||||
}
|
||||
foreach (const HFMJoint& joint, _geometry.joints) {
|
||||
if (joint.isSkeletonJoint || !_geometry.hasSkeletonJoints) {
|
||||
foreach (const HFMJoint& joint, _hfmModel.joints) {
|
||||
if (joint.isSkeletonJoint || !_hfmModel.hasSkeletonJoints) {
|
||||
box->addItem(joint.name);
|
||||
}
|
||||
}
|
||||
|
@ -266,7 +266,7 @@ QDoubleSpinBox* ModelPropertiesDialog::createTranslationBox() const {
|
|||
}
|
||||
|
||||
void ModelPropertiesDialog::insertJointMapping(QVariantHash& joints, const QString& joint, const QString& name) const {
|
||||
if (_geometry.jointIndices.contains(name)) {
|
||||
if (_hfmModel.jointIndices.contains(name)) {
|
||||
joints.insert(joint, name);
|
||||
} else {
|
||||
joints.remove(joint);
|
||||
|
|
|
@ -30,7 +30,7 @@ class ModelPropertiesDialog : public QDialog {
|
|||
|
||||
public:
|
||||
ModelPropertiesDialog(FSTReader::ModelType modelType, const QVariantHash& originalMapping,
|
||||
const QString& basePath, const HFMGeometry& geometry);
|
||||
const QString& basePath, const HFMModel& hfmModel);
|
||||
|
||||
QVariantHash getMapping() const;
|
||||
|
||||
|
@ -50,7 +50,7 @@ private:
|
|||
FSTReader::ModelType _modelType;
|
||||
QVariantHash _originalMapping;
|
||||
QString _basePath;
|
||||
HFMGeometry _geometry;
|
||||
HFMModel _hfmModel;
|
||||
QLineEdit* _name = nullptr;
|
||||
QPushButton* _textureDirectory = nullptr;
|
||||
QPushButton* _scriptDirectory = nullptr;
|
||||
|
|
|
@ -155,8 +155,8 @@ MyAvatar::MyAvatar(QThread* thread) :
|
|||
});
|
||||
connect(_skeletonModel.get(), &Model::rigReady, this, [this]() {
|
||||
if (_shouldLoadScripts) {
|
||||
auto geometry = getSkeletonModel()->getHFMGeometry();
|
||||
qApp->loadAvatarScripts(geometry.scripts);
|
||||
auto hfmModel = getSkeletonModel()->getHFMModel();
|
||||
qApp->loadAvatarScripts(hfmModel.scripts);
|
||||
_shouldLoadScripts = false;
|
||||
}
|
||||
// Load and convert old attachments to avatar entities
|
||||
|
@ -2429,10 +2429,10 @@ void MyAvatar::attachmentDataToEntityProperties(const AttachmentData& data, Enti
|
|||
void MyAvatar::initHeadBones() {
|
||||
int neckJointIndex = -1;
|
||||
if (_skeletonModel->isLoaded()) {
|
||||
neckJointIndex = _skeletonModel->getHFMGeometry().neckJointIndex;
|
||||
neckJointIndex = _skeletonModel->getHFMModel().neckJointIndex;
|
||||
}
|
||||
if (neckJointIndex == -1) {
|
||||
neckJointIndex = (_skeletonModel->getHFMGeometry().headJointIndex - 1);
|
||||
neckJointIndex = (_skeletonModel->getHFMModel().headJointIndex - 1);
|
||||
if (neckJointIndex < 0) {
|
||||
// return if the head is not even there. can't cauterize!!
|
||||
return;
|
||||
|
@ -2592,11 +2592,11 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
|
|||
|
||||
if (_skeletonModel && _skeletonModel->isLoaded()) {
|
||||
const Rig& rig = _skeletonModel->getRig();
|
||||
const HFMGeometry& geometry = _skeletonModel->getHFMGeometry();
|
||||
const HFMModel& hfmModel = _skeletonModel->getHFMModel();
|
||||
for (int i = 0; i < rig.getJointStateCount(); i++) {
|
||||
AnimPose jointPose;
|
||||
rig.getAbsoluteJointPoseInRigFrame(i, jointPose);
|
||||
const HFMJointShapeInfo& shapeInfo = geometry.joints[i].shapeInfo;
|
||||
const HFMJointShapeInfo& shapeInfo = hfmModel.joints[i].shapeInfo;
|
||||
const AnimPose pose = rigToWorldPose * jointPose;
|
||||
for (size_t j = 0; j < shapeInfo.debugLines.size() / 2; j++) {
|
||||
glm::vec3 pointA = pose.xformPoint(shapeInfo.debugLines[2 * j]);
|
||||
|
@ -4012,7 +4012,7 @@ float MyAvatar::getSitStandStateChange() const {
|
|||
}
|
||||
|
||||
QVector<QString> MyAvatar::getScriptUrls() {
|
||||
QVector<QString> scripts = _skeletonModel->isLoaded() ? _skeletonModel->getHFMGeometry().scripts : QVector<QString>();
|
||||
QVector<QString> scripts = _skeletonModel->isLoaded() ? _skeletonModel->getHFMModel().scripts : QVector<QString>();
|
||||
return scripts;
|
||||
}
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) {
|
|||
|
||||
// Called within Model::simulate call, below.
|
||||
void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
const HFMModel& hfmModel = getHFMModel();
|
||||
|
||||
Head* head = _owningAvatar->getHead();
|
||||
|
||||
|
@ -268,19 +268,19 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
// pass detailed torso k-dops to rig.
|
||||
int hipsJoint = _rig.indexOfJoint("Hips");
|
||||
if (hipsJoint >= 0) {
|
||||
params.hipsShapeInfo = geometry.joints[hipsJoint].shapeInfo;
|
||||
params.hipsShapeInfo = hfmModel.joints[hipsJoint].shapeInfo;
|
||||
}
|
||||
int spineJoint = _rig.indexOfJoint("Spine");
|
||||
if (spineJoint >= 0) {
|
||||
params.spineShapeInfo = geometry.joints[spineJoint].shapeInfo;
|
||||
params.spineShapeInfo = hfmModel.joints[spineJoint].shapeInfo;
|
||||
}
|
||||
int spine1Joint = _rig.indexOfJoint("Spine1");
|
||||
if (spine1Joint >= 0) {
|
||||
params.spine1ShapeInfo = geometry.joints[spine1Joint].shapeInfo;
|
||||
params.spine1ShapeInfo = hfmModel.joints[spine1Joint].shapeInfo;
|
||||
}
|
||||
int spine2Joint = _rig.indexOfJoint("Spine2");
|
||||
if (spine2Joint >= 0) {
|
||||
params.spine2ShapeInfo = geometry.joints[spine2Joint].shapeInfo;
|
||||
params.spine2ShapeInfo = hfmModel.joints[spine2Joint].shapeInfo;
|
||||
}
|
||||
|
||||
_rig.updateFromControllerParameters(params, deltaTime);
|
||||
|
@ -300,8 +300,8 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
eyeParams.eyeSaccade = head->getSaccade();
|
||||
eyeParams.modelRotation = getRotation();
|
||||
eyeParams.modelTranslation = getTranslation();
|
||||
eyeParams.leftEyeJointIndex = geometry.leftEyeJointIndex;
|
||||
eyeParams.rightEyeJointIndex = geometry.rightEyeJointIndex;
|
||||
eyeParams.leftEyeJointIndex = hfmModel.leftEyeJointIndex;
|
||||
eyeParams.rightEyeJointIndex = hfmModel.rightEyeJointIndex;
|
||||
|
||||
_rig.updateFromEyeParameters(eyeParams);
|
||||
|
||||
|
|
|
@ -244,7 +244,6 @@ QString transactionString(const QJsonObject& valueObject) {
|
|||
return result;
|
||||
}
|
||||
|
||||
static const QString MARKETPLACE_ITEMS_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/marketplace/items/";
|
||||
void Ledger::historySuccess(QNetworkReply* reply) {
|
||||
// here we send a historyResult with some extra stuff in it
|
||||
// Namely, the styled text we'd like to show. The issue is the
|
||||
|
|
|
@ -131,7 +131,7 @@ void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& sha
|
|||
// should never fall in here when collision model not fully loaded
|
||||
// TODO: assert that all geometries exist and are loaded
|
||||
//assert(_model && _model->isLoaded() && _compoundShapeResource && _compoundShapeResource->isLoaded());
|
||||
const HFMGeometry& collisionGeometry = resource->getHFMGeometry();
|
||||
const HFMModel& collisionModel = resource->getHFMModel();
|
||||
|
||||
ShapeInfo::PointCollection& pointCollection = shapeInfo.getPointCollection();
|
||||
pointCollection.clear();
|
||||
|
@ -139,7 +139,7 @@ void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& sha
|
|||
|
||||
// the way OBJ files get read, each section under a "g" line is its own meshPart. We only expect
|
||||
// to find one actual "mesh" (with one or more meshParts in it), but we loop over the meshes, just in case.
|
||||
foreach (const HFMMesh& mesh, collisionGeometry.meshes) {
|
||||
foreach (const HFMMesh& mesh, collisionModel.meshes) {
|
||||
// each meshPart is a convex hull
|
||||
foreach (const HFMMeshPart &meshPart, mesh.parts) {
|
||||
pointCollection.push_back(QVector<glm::vec3>());
|
||||
|
@ -206,7 +206,7 @@ void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& sha
|
|||
// to the visual model and apply them to the collision model (without regard for the
|
||||
// collision model's extents).
|
||||
|
||||
glm::vec3 scaleToFit = dimensions / resource->getHFMGeometry().getUnscaledMeshExtents().size();
|
||||
glm::vec3 scaleToFit = dimensions / resource->getHFMModel().getUnscaledMeshExtents().size();
|
||||
// multiply each point by scale
|
||||
for (int32_t i = 0; i < pointCollection.size(); i++) {
|
||||
for (int32_t j = 0; j < pointCollection[i].size(); j++) {
|
||||
|
@ -216,11 +216,11 @@ void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& sha
|
|||
}
|
||||
shapeInfo.setParams(type, dimensions, resource->getURL().toString());
|
||||
} else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) {
|
||||
const HFMGeometry& hfmGeometry = resource->getHFMGeometry();
|
||||
int numHFMMeshes = hfmGeometry.meshes.size();
|
||||
const HFMModel& hfmModel = resource->getHFMModel();
|
||||
int numHFMMeshes = hfmModel.meshes.size();
|
||||
int totalNumVertices = 0;
|
||||
for (int i = 0; i < numHFMMeshes; i++) {
|
||||
const HFMMesh& mesh = hfmGeometry.meshes.at(i);
|
||||
const HFMMesh& mesh = hfmModel.meshes.at(i);
|
||||
totalNumVertices += mesh.vertices.size();
|
||||
}
|
||||
const int32_t MAX_VERTICES_PER_STATIC_MESH = 1e6;
|
||||
|
@ -230,7 +230,7 @@ void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& sha
|
|||
return;
|
||||
}
|
||||
|
||||
auto& meshes = resource->getHFMGeometry().meshes;
|
||||
auto& meshes = resource->getHFMModel().meshes;
|
||||
int32_t numMeshes = (int32_t)(meshes.size());
|
||||
|
||||
const int MAX_ALLOWED_MESH_COUNT = 1000;
|
||||
|
|
|
@ -10,13 +10,15 @@
|
|||
//
|
||||
|
||||
#include "WalletScriptingInterface.h"
|
||||
#include <SettingHandle.h>
|
||||
|
||||
CheckoutProxy::CheckoutProxy(QObject* qmlObject, QObject* parent) : QmlWrapper(qmlObject, parent) {
|
||||
Q_ASSERT(QThread::currentThread() == qApp->thread());
|
||||
}
|
||||
|
||||
WalletScriptingInterface::WalletScriptingInterface() {
|
||||
|
||||
connect(DependencyManager::get<AccountManager>().data(),
|
||||
&AccountManager::limitedCommerceChanged, this, &WalletScriptingInterface::limitedCommerceChanged);
|
||||
}
|
||||
|
||||
void WalletScriptingInterface::refreshWalletStatus() {
|
||||
|
@ -42,4 +44,4 @@ void WalletScriptingInterface::proveAvatarEntityOwnershipVerification(const QUui
|
|||
} else {
|
||||
qCDebug(entities) << "Failed to prove ownership of:" << entityID << "is not an avatar entity";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@
|
|||
#include <QtCore/QObject>
|
||||
#include <DependencyManager.h>
|
||||
|
||||
#include "scripting/HMDScriptingInterface.h"
|
||||
#include <ui/TabletScriptingInterface.h>
|
||||
#include <ui/QmlWrapper.h>
|
||||
#include <OffscreenUi.h>
|
||||
#include "Application.h"
|
||||
#include "commerce/Wallet.h"
|
||||
#include "ui/overlays/ContextOverlayInterface.h"
|
||||
#include <AccountManager.h>
|
||||
|
||||
class CheckoutProxy : public QmlWrapper {
|
||||
Q_OBJECT
|
||||
|
@ -29,7 +29,6 @@ public:
|
|||
CheckoutProxy(QObject* qmlObject, QObject* parent = nullptr);
|
||||
};
|
||||
|
||||
|
||||
/**jsdoc
|
||||
* @namespace Wallet
|
||||
*
|
||||
|
@ -37,28 +36,31 @@ public:
|
|||
* @hifi-client-entity
|
||||
*
|
||||
* @property {number} walletStatus
|
||||
* @property {bool} limitedCommerce
|
||||
*/
|
||||
class WalletScriptingInterface : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
|
||||
SINGLETON_DEPENDENCY
|
||||
Q_PROPERTY(uint walletStatus READ getWalletStatus WRITE setWalletStatus NOTIFY walletStatusChanged)
|
||||
Q_PROPERTY(bool limitedCommerce READ getLimitedCommerce WRITE setLimitedCommerce NOTIFY limitedCommerceChanged)
|
||||
|
||||
public:
|
||||
|
||||
WalletScriptingInterface();
|
||||
|
||||
/**jsdoc
|
||||
* @function Wallet.refreshWalletStatus
|
||||
* @function WalletScriptingInterface.refreshWalletStatus
|
||||
*/
|
||||
Q_INVOKABLE void refreshWalletStatus();
|
||||
|
||||
/**jsdoc
|
||||
* @function Wallet.getWalletStatus
|
||||
* @function WalletScriptingInterface.getWalletStatus
|
||||
* @returns {number}
|
||||
*/
|
||||
Q_INVOKABLE uint getWalletStatus() { return _walletStatus; }
|
||||
|
||||
/**jsdoc
|
||||
* @function Wallet.proveAvatarEntityOwnershipVerification
|
||||
* @function WalletScriptingInterface.proveAvatarEntityOwnershipVerification
|
||||
* @param {Uuid} entityID
|
||||
*/
|
||||
Q_INVOKABLE void proveAvatarEntityOwnershipVerification(const QUuid& entityID);
|
||||
|
@ -67,29 +69,38 @@ public:
|
|||
// scripts could cause the Wallet to incorrectly report its status.
|
||||
void setWalletStatus(const uint& status);
|
||||
|
||||
bool getLimitedCommerce() { return DependencyManager::get<AccountManager>()->getLimitedCommerce(); }
|
||||
void setLimitedCommerce(bool isLimited) { DependencyManager::get<AccountManager>()->setLimitedCommerce(isLimited); };
|
||||
|
||||
signals:
|
||||
|
||||
/**jsdoc
|
||||
* @function Wallet.walletStatusChanged
|
||||
* @function WalletScriptingInterface.walletStatusChanged
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void walletStatusChanged();
|
||||
|
||||
/**jsdoc
|
||||
* @function Wallet.walletNotSetup
|
||||
* @function WalletScriptingInterface.limitedCommerceChanged
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void limitedCommerceChanged();
|
||||
|
||||
/**jsdoc
|
||||
* @function WalletScriptingInterface.walletNotSetup
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void walletNotSetup();
|
||||
|
||||
/**jsdoc
|
||||
* @function Wallet.ownershipVerificationSuccess
|
||||
* @function WalletScriptingInterface.ownershipVerificationSuccess
|
||||
* @param {Uuid} entityID
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void ownershipVerificationSuccess(const QUuid& entityID);
|
||||
|
||||
/**jsdoc
|
||||
* @function Wallet.ownershipVerificationFailed
|
||||
* @function WalletScriptingInterface.ownershipVerificationFailed
|
||||
* @param {Uuid} entityID
|
||||
* @returns {Signal}
|
||||
*/
|
||||
|
|
|
@ -223,12 +223,7 @@ bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID&
|
|||
|
||||
bool ContextOverlayInterface::contextOverlayFilterPassed(const EntityItemID& entityItemID) {
|
||||
EntityItemProperties entityProperties = _entityScriptingInterface->getEntityProperties(entityItemID, _entityPropertyFlags);
|
||||
Setting::Handle<bool> _settingSwitch{ "commerce", true };
|
||||
if (_settingSwitch.get()) {
|
||||
return (entityProperties.getCertificateID().length() != 0);
|
||||
} else {
|
||||
return (entityProperties.getMarketplaceID().length() != 0);
|
||||
}
|
||||
return (entityProperties.getCertificateID().length() != 0);
|
||||
}
|
||||
|
||||
bool ContextOverlayInterface::destroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event) {
|
||||
|
|
|
@ -446,7 +446,7 @@ QVariant ModelOverlay::getProperty(const QString& property) {
|
|||
|
||||
if (property == "jointNames") {
|
||||
if (_model && _model->isActive()) {
|
||||
// note: going through Rig because Model::getJointNames() (which proxies to HFMGeometry) was always empty
|
||||
// note: going through Rig because Model::getJointNames() (which proxies to HFMModel) was always empty
|
||||
const Rig* rig = &(_model->getRig());
|
||||
return mapJoints<QStringList, QString>([rig](int jointIndex) -> QString {
|
||||
return rig->nameOfJoint(jointIndex);
|
||||
|
@ -605,11 +605,11 @@ void ModelOverlay::animate() {
|
|||
return;
|
||||
}
|
||||
|
||||
QStringList animationJointNames = _animation->getGeometry().getJointNames();
|
||||
auto& hfmJoints = _animation->getGeometry().joints;
|
||||
QStringList animationJointNames = _animation->getHFMModel().getJointNames();
|
||||
auto& hfmJoints = _animation->getHFMModel().joints;
|
||||
|
||||
auto& originalHFMJoints = _model->getHFMGeometry().joints;
|
||||
auto& originalFbxIndices = _model->getHFMGeometry().jointIndices;
|
||||
auto& originalHFMJoints = _model->getHFMModel().joints;
|
||||
auto& originalHFMIndices = _model->getHFMModel().jointIndices;
|
||||
|
||||
const QVector<glm::quat>& rotations = frames[_lastKnownCurrentFrame].rotations;
|
||||
const QVector<glm::vec3>& translations = frames[_lastKnownCurrentFrame].translations;
|
||||
|
@ -628,9 +628,9 @@ void ModelOverlay::animate() {
|
|||
} else if (index < animationJointNames.size()) {
|
||||
QString jointName = hfmJoints[index].name;
|
||||
|
||||
if (originalFbxIndices.contains(jointName)) {
|
||||
if (originalHFMIndices.contains(jointName)) {
|
||||
// Making sure the joint names exist in the original model the animation is trying to apply onto. If they do, then remap and get its translation.
|
||||
int remappedIndex = originalFbxIndices[jointName] - 1; // JointIndeces seem to always start from 1 and the found index is always 1 higher than actual.
|
||||
int remappedIndex = originalHFMIndices[jointName] - 1; // JointIndeces seem to always start from 1 and the found index is always 1 higher than actual.
|
||||
translationMat = glm::translate(originalHFMJoints[remappedIndex].translation);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include "ui/AvatarInputs.h"
|
||||
#include "avatar/AvatarManager.h"
|
||||
#include "scripting/AccountServicesScriptingInterface.h"
|
||||
#include "scripting/WalletScriptingInterface.h"
|
||||
#include <plugins/InputConfiguration.h>
|
||||
#include "ui/Snapshot.h"
|
||||
#include "SoundCacheScriptingInterface.h"
|
||||
|
@ -270,6 +271,7 @@ void Web3DOverlay::setupQmlSurface(bool isTablet) {
|
|||
_webSurface->getSurfaceContext()->setContextProperty("Window", DependencyManager::get<WindowScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("Reticle", qApp->getApplicationCompositor().getReticleInterface());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("HiFiAbout", AboutUtil::getInstance());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("WalletScriptingInterface", DependencyManager::get<WalletScriptingInterface>().data());
|
||||
_webSurface->getSurfaceContext()->setContextProperty("ResourceRequestObserver", DependencyManager::get<ResourceRequestObserver>().data());
|
||||
|
||||
// Override min fps for tablet UI, for silky smooth scrolling
|
||||
|
|
|
@ -101,8 +101,8 @@ void AnimClip::copyFromNetworkAnim() {
|
|||
|
||||
// build a mapping from animation joint indices to skeleton joint indices.
|
||||
// by matching joints with the same name.
|
||||
const HFMGeometry& geom = _networkAnim->getGeometry();
|
||||
AnimSkeleton animSkeleton(geom);
|
||||
const HFMModel& hfmModel = _networkAnim->getHFMModel();
|
||||
AnimSkeleton animSkeleton(hfmModel);
|
||||
const auto animJointCount = animSkeleton.getNumJoints();
|
||||
const auto skeletonJointCount = _skeleton->getNumJoints();
|
||||
std::vector<int> jointMap;
|
||||
|
@ -115,12 +115,12 @@ void AnimClip::copyFromNetworkAnim() {
|
|||
jointMap.push_back(skeletonJoint);
|
||||
}
|
||||
|
||||
const int frameCount = geom.animationFrames.size();
|
||||
const int frameCount = hfmModel.animationFrames.size();
|
||||
_anim.resize(frameCount);
|
||||
|
||||
for (int frame = 0; frame < frameCount; frame++) {
|
||||
|
||||
const HFMAnimationFrame& hfmAnimFrame = geom.animationFrames[frame];
|
||||
const HFMAnimationFrame& hfmAnimFrame = hfmModel.animationFrames[frame];
|
||||
|
||||
// init all joints in animation to default pose
|
||||
// this will give us a resonable result for bones in the model skeleton but not in the animation.
|
||||
|
@ -150,7 +150,7 @@ void AnimClip::copyFromNetworkAnim() {
|
|||
|
||||
// adjust translation offsets, so large translation animatons on the reference skeleton
|
||||
// will be adjusted when played on a skeleton with short limbs.
|
||||
const glm::vec3& hfmZeroTrans = geom.animationFrames[0].translations[animJoint];
|
||||
const glm::vec3& hfmZeroTrans = hfmModel.animationFrames[0].translations[animJoint];
|
||||
const AnimPose& relDefaultPose = _skeleton->getRelativeDefaultPose(skeletonJoint);
|
||||
float boneLengthScale = 1.0f;
|
||||
const float EPSILON = 0.0001f;
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
|
||||
#include "AnimationLogging.h"
|
||||
|
||||
AnimSkeleton::AnimSkeleton(const HFMGeometry& geometry) {
|
||||
AnimSkeleton::AnimSkeleton(const HFMModel& hfmModel) {
|
||||
// convert to std::vector of joints
|
||||
std::vector<HFMJoint> joints;
|
||||
joints.reserve(geometry.joints.size());
|
||||
for (auto& joint : geometry.joints) {
|
||||
joints.reserve(hfmModel.joints.size());
|
||||
for (auto& joint : hfmModel.joints) {
|
||||
joints.push_back(joint);
|
||||
}
|
||||
buildSkeletonFromJoints(joints);
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
using Pointer = std::shared_ptr<AnimSkeleton>;
|
||||
using ConstPointer = std::shared_ptr<const AnimSkeleton>;
|
||||
|
||||
explicit AnimSkeleton(const HFMGeometry& geometry);
|
||||
explicit AnimSkeleton(const HFMModel& hfmModel);
|
||||
explicit AnimSkeleton(const std::vector<HFMJoint>& joints);
|
||||
int nameToJointIndex(const QString& jointName) const;
|
||||
const QString& getJointName(int jointIndex) const;
|
||||
|
|
|
@ -69,14 +69,14 @@ void AnimationReader::run() {
|
|||
|
||||
if (urlValid) {
|
||||
// Parse the FBX directly from the QNetworkReply
|
||||
HFMGeometry::Pointer fbxgeo;
|
||||
HFMModel::Pointer hfmModel;
|
||||
if (_url.path().toLower().endsWith(".fbx")) {
|
||||
fbxgeo.reset(readFBX(_data, QVariantHash(), _url.path()));
|
||||
hfmModel.reset(readFBX(_data, QVariantHash(), _url.path()));
|
||||
} else {
|
||||
QString errorStr("usupported format");
|
||||
emit onError(299, errorStr);
|
||||
}
|
||||
emit onSuccess(fbxgeo);
|
||||
emit onSuccess(hfmModel);
|
||||
} else {
|
||||
throw QString("url is invalid");
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ void AnimationReader::run() {
|
|||
}
|
||||
|
||||
bool Animation::isLoaded() const {
|
||||
return _loaded && _geometry;
|
||||
return _loaded && _hfmModel;
|
||||
}
|
||||
|
||||
QStringList Animation::getJointNames() const {
|
||||
|
@ -99,8 +99,8 @@ QStringList Animation::getJointNames() const {
|
|||
return result;
|
||||
}
|
||||
QStringList names;
|
||||
if (_geometry) {
|
||||
foreach (const HFMJoint& joint, _geometry->joints) {
|
||||
if (_hfmModel) {
|
||||
foreach (const HFMJoint& joint, _hfmModel->joints) {
|
||||
names.append(joint.name);
|
||||
}
|
||||
}
|
||||
|
@ -114,30 +114,30 @@ QVector<HFMAnimationFrame> Animation::getFrames() const {
|
|||
Q_RETURN_ARG(QVector<HFMAnimationFrame>, result));
|
||||
return result;
|
||||
}
|
||||
if (_geometry) {
|
||||
return _geometry->animationFrames;
|
||||
if (_hfmModel) {
|
||||
return _hfmModel->animationFrames;
|
||||
} else {
|
||||
return QVector<HFMAnimationFrame>();
|
||||
}
|
||||
}
|
||||
|
||||
const QVector<HFMAnimationFrame>& Animation::getFramesReference() const {
|
||||
return _geometry->animationFrames;
|
||||
return _hfmModel->animationFrames;
|
||||
}
|
||||
|
||||
void Animation::downloadFinished(const QByteArray& data) {
|
||||
// parse the animation/fbx file on a background thread.
|
||||
AnimationReader* animationReader = new AnimationReader(_url, data);
|
||||
connect(animationReader, SIGNAL(onSuccess(HFMGeometry::Pointer)), SLOT(animationParseSuccess(HFMGeometry::Pointer)));
|
||||
connect(animationReader, SIGNAL(onSuccess(HFMModel::Pointer)), SLOT(animationParseSuccess(HFMModel::Pointer)));
|
||||
connect(animationReader, SIGNAL(onError(int, QString)), SLOT(animationParseError(int, QString)));
|
||||
QThreadPool::globalInstance()->start(animationReader);
|
||||
}
|
||||
|
||||
void Animation::animationParseSuccess(HFMGeometry::Pointer geometry) {
|
||||
void Animation::animationParseSuccess(HFMModel::Pointer hfmModel) {
|
||||
|
||||
qCDebug(animation) << "Animation parse success" << _url.toDisplayString();
|
||||
|
||||
_geometry = geometry;
|
||||
_hfmModel = hfmModel;
|
||||
finishedLoading(true);
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ public:
|
|||
|
||||
QString getType() const override { return "Animation"; }
|
||||
|
||||
const HFMGeometry& getGeometry() const { return *_geometry; }
|
||||
const HFMModel& getHFMModel() const { return *_hfmModel; }
|
||||
|
||||
virtual bool isLoaded() const override;
|
||||
|
||||
|
@ -88,12 +88,12 @@ protected:
|
|||
virtual void downloadFinished(const QByteArray& data) override;
|
||||
|
||||
protected slots:
|
||||
void animationParseSuccess(HFMGeometry::Pointer geometry);
|
||||
void animationParseSuccess(HFMModel::Pointer hfmModel);
|
||||
void animationParseError(int error, QString str);
|
||||
|
||||
private:
|
||||
|
||||
HFMGeometry::Pointer _geometry;
|
||||
HFMModel::Pointer _hfmModel;
|
||||
};
|
||||
|
||||
/// Reads geometry in a worker thread.
|
||||
|
@ -105,7 +105,7 @@ public:
|
|||
virtual void run() override;
|
||||
|
||||
signals:
|
||||
void onSuccess(HFMGeometry::Pointer geometry);
|
||||
void onSuccess(HFMModel::Pointer hfmModel);
|
||||
void onError(int error, QString str);
|
||||
|
||||
private:
|
||||
|
|
|
@ -260,14 +260,14 @@ void Rig::destroyAnimGraph() {
|
|||
_rightEyeJointChildren.clear();
|
||||
}
|
||||
|
||||
void Rig::initJointStates(const HFMGeometry& geometry, const glm::mat4& modelOffset) {
|
||||
_geometryOffset = AnimPose(geometry.offset);
|
||||
void Rig::initJointStates(const HFMModel& hfmModel, const glm::mat4& modelOffset) {
|
||||
_geometryOffset = AnimPose(hfmModel.offset);
|
||||
_invGeometryOffset = _geometryOffset.inverse();
|
||||
_geometryToRigTransform = modelOffset * geometry.offset;
|
||||
_geometryToRigTransform = modelOffset * hfmModel.offset;
|
||||
_rigToGeometryTransform = glm::inverse(_geometryToRigTransform);
|
||||
setModelOffset(modelOffset);
|
||||
|
||||
_animSkeleton = std::make_shared<AnimSkeleton>(geometry);
|
||||
_animSkeleton = std::make_shared<AnimSkeleton>(hfmModel);
|
||||
|
||||
_internalPoseSet._relativePoses.clear();
|
||||
_internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||
|
@ -293,24 +293,24 @@ void Rig::initJointStates(const HFMGeometry& geometry, const glm::mat4& modelOff
|
|||
|
||||
buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses);
|
||||
|
||||
_rootJointIndex = geometry.rootJointIndex;
|
||||
_leftEyeJointIndex = geometry.leftEyeJointIndex;
|
||||
_rightEyeJointIndex = geometry.rightEyeJointIndex;
|
||||
_leftHandJointIndex = geometry.leftHandJointIndex;
|
||||
_leftElbowJointIndex = _leftHandJointIndex >= 0 ? geometry.joints.at(_leftHandJointIndex).parentIndex : -1;
|
||||
_leftShoulderJointIndex = _leftElbowJointIndex >= 0 ? geometry.joints.at(_leftElbowJointIndex).parentIndex : -1;
|
||||
_rightHandJointIndex = geometry.rightHandJointIndex;
|
||||
_rightElbowJointIndex = _rightHandJointIndex >= 0 ? geometry.joints.at(_rightHandJointIndex).parentIndex : -1;
|
||||
_rightShoulderJointIndex = _rightElbowJointIndex >= 0 ? geometry.joints.at(_rightElbowJointIndex).parentIndex : -1;
|
||||
_rootJointIndex = hfmModel.rootJointIndex;
|
||||
_leftEyeJointIndex = hfmModel.leftEyeJointIndex;
|
||||
_rightEyeJointIndex = hfmModel.rightEyeJointIndex;
|
||||
_leftHandJointIndex = hfmModel.leftHandJointIndex;
|
||||
_leftElbowJointIndex = _leftHandJointIndex >= 0 ? hfmModel.joints.at(_leftHandJointIndex).parentIndex : -1;
|
||||
_leftShoulderJointIndex = _leftElbowJointIndex >= 0 ? hfmModel.joints.at(_leftElbowJointIndex).parentIndex : -1;
|
||||
_rightHandJointIndex = hfmModel.rightHandJointIndex;
|
||||
_rightElbowJointIndex = _rightHandJointIndex >= 0 ? hfmModel.joints.at(_rightHandJointIndex).parentIndex : -1;
|
||||
_rightShoulderJointIndex = _rightElbowJointIndex >= 0 ? hfmModel.joints.at(_rightElbowJointIndex).parentIndex : -1;
|
||||
|
||||
_leftEyeJointChildren = _animSkeleton->getChildrenOfJoint(geometry.leftEyeJointIndex);
|
||||
_rightEyeJointChildren = _animSkeleton->getChildrenOfJoint(geometry.rightEyeJointIndex);
|
||||
_leftEyeJointChildren = _animSkeleton->getChildrenOfJoint(hfmModel.leftEyeJointIndex);
|
||||
_rightEyeJointChildren = _animSkeleton->getChildrenOfJoint(hfmModel.rightEyeJointIndex);
|
||||
}
|
||||
|
||||
void Rig::reset(const HFMGeometry& geometry) {
|
||||
_geometryOffset = AnimPose(geometry.offset);
|
||||
void Rig::reset(const HFMModel& hfmModel) {
|
||||
_geometryOffset = AnimPose(hfmModel.offset);
|
||||
_invGeometryOffset = _geometryOffset.inverse();
|
||||
_animSkeleton = std::make_shared<AnimSkeleton>(geometry);
|
||||
_animSkeleton = std::make_shared<AnimSkeleton>(hfmModel);
|
||||
|
||||
_internalPoseSet._relativePoses.clear();
|
||||
_internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||
|
@ -338,18 +338,18 @@ void Rig::reset(const HFMGeometry& geometry) {
|
|||
|
||||
buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses);
|
||||
|
||||
_rootJointIndex = geometry.rootJointIndex;
|
||||
_leftEyeJointIndex = geometry.leftEyeJointIndex;
|
||||
_rightEyeJointIndex = geometry.rightEyeJointIndex;
|
||||
_leftHandJointIndex = geometry.leftHandJointIndex;
|
||||
_leftElbowJointIndex = _leftHandJointIndex >= 0 ? geometry.joints.at(_leftHandJointIndex).parentIndex : -1;
|
||||
_leftShoulderJointIndex = _leftElbowJointIndex >= 0 ? geometry.joints.at(_leftElbowJointIndex).parentIndex : -1;
|
||||
_rightHandJointIndex = geometry.rightHandJointIndex;
|
||||
_rightElbowJointIndex = _rightHandJointIndex >= 0 ? geometry.joints.at(_rightHandJointIndex).parentIndex : -1;
|
||||
_rightShoulderJointIndex = _rightElbowJointIndex >= 0 ? geometry.joints.at(_rightElbowJointIndex).parentIndex : -1;
|
||||
_rootJointIndex = hfmModel.rootJointIndex;
|
||||
_leftEyeJointIndex = hfmModel.leftEyeJointIndex;
|
||||
_rightEyeJointIndex = hfmModel.rightEyeJointIndex;
|
||||
_leftHandJointIndex = hfmModel.leftHandJointIndex;
|
||||
_leftElbowJointIndex = _leftHandJointIndex >= 0 ? hfmModel.joints.at(_leftHandJointIndex).parentIndex : -1;
|
||||
_leftShoulderJointIndex = _leftElbowJointIndex >= 0 ? hfmModel.joints.at(_leftElbowJointIndex).parentIndex : -1;
|
||||
_rightHandJointIndex = hfmModel.rightHandJointIndex;
|
||||
_rightElbowJointIndex = _rightHandJointIndex >= 0 ? hfmModel.joints.at(_rightHandJointIndex).parentIndex : -1;
|
||||
_rightShoulderJointIndex = _rightElbowJointIndex >= 0 ? hfmModel.joints.at(_rightElbowJointIndex).parentIndex : -1;
|
||||
|
||||
_leftEyeJointChildren = _animSkeleton->getChildrenOfJoint(geometry.leftEyeJointIndex);
|
||||
_rightEyeJointChildren = _animSkeleton->getChildrenOfJoint(geometry.rightEyeJointIndex);
|
||||
_leftEyeJointChildren = _animSkeleton->getChildrenOfJoint(hfmModel.leftEyeJointIndex);
|
||||
_rightEyeJointChildren = _animSkeleton->getChildrenOfJoint(hfmModel.rightEyeJointIndex);
|
||||
|
||||
if (!_animGraphURL.isEmpty()) {
|
||||
_animNode.reset();
|
||||
|
@ -1938,7 +1938,7 @@ void Rig::copyJointsIntoJointData(QVector<JointData>& jointDataVec) const {
|
|||
data.rotationIsDefaultPose = isEqual(data.rotation, defaultAbsRot);
|
||||
|
||||
// translations are in relative frame but scaled so that they are in meters,
|
||||
// instead of geometry units.
|
||||
// instead of model units.
|
||||
glm::vec3 defaultRelTrans = _geometryOffset.scale() * _animSkeleton->getRelativeDefaultPose(i).trans();
|
||||
data.translation = _geometryOffset.scale() * (!_sendNetworkNode ? _internalPoseSet._relativePoses[i].trans() : _networkPoseSet._relativePoses[i].trans());
|
||||
data.translationIsDefaultPose = isEqual(data.translation, defaultRelTrans);
|
||||
|
@ -1963,7 +1963,7 @@ void Rig::copyJointsFromJointData(const QVector<JointData>& jointDataVec) {
|
|||
return;
|
||||
}
|
||||
|
||||
// make a vector of rotations in absolute-geometry-frame
|
||||
// make a vector of rotations in absolute-model-frame
|
||||
std::vector<glm::quat> rotations;
|
||||
rotations.reserve(numJoints);
|
||||
const glm::quat rigToGeometryRot(glmExtractRotation(_rigToGeometryTransform));
|
||||
|
@ -1972,7 +1972,7 @@ void Rig::copyJointsFromJointData(const QVector<JointData>& jointDataVec) {
|
|||
if (data.rotationIsDefaultPose) {
|
||||
rotations.push_back(absoluteDefaultPoses[i].rot());
|
||||
} else {
|
||||
// JointData rotations are in absolute rig-frame so we rotate them to absolute geometry-frame
|
||||
// JointData rotations are in absolute rig-frame so we rotate them to absolute model-frame
|
||||
rotations.push_back(rigToGeometryRot * data.rotation);
|
||||
}
|
||||
}
|
||||
|
@ -2008,7 +2008,7 @@ void Rig::computeExternalPoses(const glm::mat4& modelOffsetMat) {
|
|||
}
|
||||
|
||||
void Rig::computeAvatarBoundingCapsule(
|
||||
const HFMGeometry& geometry,
|
||||
const HFMModel& hfmModel,
|
||||
float& radiusOut,
|
||||
float& heightOut,
|
||||
glm::vec3& localOffsetOut) const {
|
||||
|
@ -2041,7 +2041,7 @@ void Rig::computeAvatarBoundingCapsule(
|
|||
// from the head to the hips when computing the rest of the bounding capsule.
|
||||
int index = indexOfJoint("Head");
|
||||
while (index != -1) {
|
||||
const HFMJointShapeInfo& shapeInfo = geometry.joints.at(index).shapeInfo;
|
||||
const HFMJointShapeInfo& shapeInfo = hfmModel.joints.at(index).shapeInfo;
|
||||
AnimPose pose = _animSkeleton->getAbsoluteDefaultPose(index);
|
||||
if (shapeInfo.points.size() > 0) {
|
||||
for (auto& point : shapeInfo.points) {
|
||||
|
|
|
@ -122,8 +122,8 @@ public:
|
|||
void overrideRoleAnimation(const QString& role, const QString& url, float fps, bool loop, float firstFrame, float lastFrame);
|
||||
void restoreRoleAnimation(const QString& role);
|
||||
|
||||
void initJointStates(const HFMGeometry& geometry, const glm::mat4& modelOffset);
|
||||
void reset(const HFMGeometry& geometry);
|
||||
void initJointStates(const HFMModel& hfmModel, const glm::mat4& modelOffset);
|
||||
void reset(const HFMModel& hfmModel);
|
||||
bool jointStatesEmpty();
|
||||
int getJointStateCount() const;
|
||||
int indexOfJoint(const QString& jointName) const;
|
||||
|
@ -210,7 +210,7 @@ public:
|
|||
void copyJointsFromJointData(const QVector<JointData>& jointDataVec);
|
||||
void computeExternalPoses(const glm::mat4& modelOffsetMat);
|
||||
|
||||
void computeAvatarBoundingCapsule(const HFMGeometry& geometry, float& radiusOut, float& heightOut, glm::vec3& offsetOut) const;
|
||||
void computeAvatarBoundingCapsule(const HFMModel& hfmModel, float& radiusOut, float& heightOut, glm::vec3& offsetOut) const;
|
||||
|
||||
void setEnableInverseKinematics(bool enable);
|
||||
void setEnableAnimations(bool enable);
|
||||
|
|
|
@ -1311,7 +1311,7 @@ glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const {
|
|||
case CAMERA_MATRIX_INDEX: {
|
||||
glm::quat rotation;
|
||||
if (_skeletonModel && _skeletonModel->isActive()) {
|
||||
int headJointIndex = _skeletonModel->getHFMGeometry().headJointIndex;
|
||||
int headJointIndex = _skeletonModel->getHFMModel().headJointIndex;
|
||||
if (headJointIndex >= 0) {
|
||||
_skeletonModel->getAbsoluteJointRotationInRigFrame(headJointIndex, rotation);
|
||||
}
|
||||
|
@ -1360,7 +1360,7 @@ glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
|
|||
case CAMERA_MATRIX_INDEX: {
|
||||
glm::vec3 translation;
|
||||
if (_skeletonModel && _skeletonModel->isActive()) {
|
||||
int headJointIndex = _skeletonModel->getHFMGeometry().headJointIndex;
|
||||
int headJointIndex = _skeletonModel->getHFMModel().headJointIndex;
|
||||
if (headJointIndex >= 0) {
|
||||
_skeletonModel->getAbsoluteJointTranslationInRigFrame(headJointIndex, translation);
|
||||
}
|
||||
|
@ -1416,7 +1416,7 @@ void Avatar::withValidJointIndicesCache(std::function<void()> const& worker) con
|
|||
if (!_modelJointsCached) {
|
||||
_modelJointIndicesCache.clear();
|
||||
if (_skeletonModel && _skeletonModel->isActive()) {
|
||||
_modelJointIndicesCache = _skeletonModel->getHFMGeometry().jointIndices;
|
||||
_modelJointIndicesCache = _skeletonModel->getHFMModel().jointIndices;
|
||||
_modelJointsCached = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,9 +54,9 @@ void SkeletonModel::setTextures(const QVariantMap& textures) {
|
|||
}
|
||||
|
||||
void SkeletonModel::initJointStates() {
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
const HFMModel& hfmModel = getHFMModel();
|
||||
glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset);
|
||||
_rig.initJointStates(geometry, modelOffset);
|
||||
_rig.initJointStates(hfmModel, modelOffset);
|
||||
|
||||
{
|
||||
// initialize _jointData with proper values for default joints
|
||||
|
@ -66,7 +66,7 @@ void SkeletonModel::initJointStates() {
|
|||
}
|
||||
|
||||
// Determine the default eye position for avatar scale = 1.0
|
||||
int headJointIndex = geometry.headJointIndex;
|
||||
int headJointIndex = hfmModel.headJointIndex;
|
||||
if (0 > headJointIndex || headJointIndex >= _rig.getJointStateCount()) {
|
||||
qCWarning(avatars_renderer) << "Bad head joint! Got:" << headJointIndex << "jointCount:" << _rig.getJointStateCount();
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ void SkeletonModel::initJointStates() {
|
|||
getEyeModelPositions(leftEyePosition, rightEyePosition);
|
||||
glm::vec3 midEyePosition = (leftEyePosition + rightEyePosition) / 2.0f;
|
||||
|
||||
int rootJointIndex = geometry.rootJointIndex;
|
||||
int rootJointIndex = hfmModel.rootJointIndex;
|
||||
glm::vec3 rootModelPosition;
|
||||
getJointPosition(rootJointIndex, rootModelPosition);
|
||||
|
||||
|
@ -96,7 +96,7 @@ void SkeletonModel::initJointStates() {
|
|||
// Called within Model::simulate call, below.
|
||||
void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
||||
assert(!_owningAvatar->isMyAvatar());
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
const HFMModel& hfmModel = getHFMModel();
|
||||
|
||||
Head* head = _owningAvatar->getHead();
|
||||
|
||||
|
@ -124,7 +124,7 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
|
||||
// If the head is not positioned, updateEyeJoints won't get the math right
|
||||
glm::quat headOrientation;
|
||||
_rig.getJointRotation(geometry.headJointIndex, headOrientation);
|
||||
_rig.getJointRotation(hfmModel.headJointIndex, headOrientation);
|
||||
glm::vec3 eulers = safeEulerAngles(headOrientation);
|
||||
head->setBasePitch(glm::degrees(-eulers.x));
|
||||
head->setBaseYaw(glm::degrees(eulers.y));
|
||||
|
@ -135,8 +135,8 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
eyeParams.eyeSaccade = glm::vec3(0.0f);
|
||||
eyeParams.modelRotation = getRotation();
|
||||
eyeParams.modelTranslation = getTranslation();
|
||||
eyeParams.leftEyeJointIndex = geometry.leftEyeJointIndex;
|
||||
eyeParams.rightEyeJointIndex = geometry.rightEyeJointIndex;
|
||||
eyeParams.leftEyeJointIndex = hfmModel.leftEyeJointIndex;
|
||||
eyeParams.rightEyeJointIndex = hfmModel.rightEyeJointIndex;
|
||||
|
||||
_rig.updateFromEyeParameters(eyeParams);
|
||||
}
|
||||
|
@ -259,45 +259,45 @@ bool SkeletonModel::getRightShoulderPosition(glm::vec3& position) const {
|
|||
}
|
||||
|
||||
bool SkeletonModel::getHeadPosition(glm::vec3& headPosition) const {
|
||||
return isActive() && getJointPositionInWorldFrame(getHFMGeometry().headJointIndex, headPosition);
|
||||
return isActive() && getJointPositionInWorldFrame(getHFMModel().headJointIndex, headPosition);
|
||||
}
|
||||
|
||||
bool SkeletonModel::getNeckPosition(glm::vec3& neckPosition) const {
|
||||
return isActive() && getJointPositionInWorldFrame(getHFMGeometry().neckJointIndex, neckPosition);
|
||||
return isActive() && getJointPositionInWorldFrame(getHFMModel().neckJointIndex, neckPosition);
|
||||
}
|
||||
|
||||
bool SkeletonModel::getLocalNeckPosition(glm::vec3& neckPosition) const {
|
||||
return isActive() && getJointPosition(getHFMGeometry().neckJointIndex, neckPosition);
|
||||
return isActive() && getJointPosition(getHFMModel().neckJointIndex, neckPosition);
|
||||
}
|
||||
|
||||
bool SkeletonModel::getEyeModelPositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const {
|
||||
if (!isActive()) {
|
||||
return false;
|
||||
}
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
const HFMModel& hfmModel = getHFMModel();
|
||||
|
||||
if (getJointPosition(geometry.leftEyeJointIndex, firstEyePosition) &&
|
||||
getJointPosition(geometry.rightEyeJointIndex, secondEyePosition)) {
|
||||
if (getJointPosition(hfmModel.leftEyeJointIndex, firstEyePosition) &&
|
||||
getJointPosition(hfmModel.rightEyeJointIndex, secondEyePosition)) {
|
||||
return true;
|
||||
}
|
||||
// no eye joints; try to estimate based on head/neck joints
|
||||
glm::vec3 neckPosition, headPosition;
|
||||
if (getJointPosition(geometry.neckJointIndex, neckPosition) &&
|
||||
getJointPosition(geometry.headJointIndex, headPosition)) {
|
||||
if (getJointPosition(hfmModel.neckJointIndex, neckPosition) &&
|
||||
getJointPosition(hfmModel.headJointIndex, headPosition)) {
|
||||
const float EYE_PROPORTION = 0.6f;
|
||||
glm::vec3 baseEyePosition = glm::mix(neckPosition, headPosition, EYE_PROPORTION);
|
||||
glm::quat headRotation;
|
||||
getJointRotation(geometry.headJointIndex, headRotation);
|
||||
getJointRotation(hfmModel.headJointIndex, headRotation);
|
||||
const float EYES_FORWARD = 0.25f;
|
||||
const float EYE_SEPARATION = 0.1f;
|
||||
float headHeight = glm::distance(neckPosition, headPosition);
|
||||
firstEyePosition = baseEyePosition + headRotation * glm::vec3(EYE_SEPARATION, 0.0f, EYES_FORWARD) * headHeight;
|
||||
secondEyePosition = baseEyePosition + headRotation * glm::vec3(-EYE_SEPARATION, 0.0f, EYES_FORWARD) * headHeight;
|
||||
return true;
|
||||
} else if (getJointPosition(geometry.headJointIndex, headPosition)) {
|
||||
} else if (getJointPosition(hfmModel.headJointIndex, headPosition)) {
|
||||
glm::vec3 baseEyePosition = headPosition;
|
||||
glm::quat headRotation;
|
||||
getJointRotation(geometry.headJointIndex, headRotation);
|
||||
getJointRotation(hfmModel.headJointIndex, headRotation);
|
||||
const float EYES_FORWARD_HEAD_ONLY = 0.30f;
|
||||
const float EYE_SEPARATION = 0.1f;
|
||||
firstEyePosition = baseEyePosition + headRotation * glm::vec3(EYE_SEPARATION, 0.0f, EYES_FORWARD_HEAD_ONLY);
|
||||
|
@ -330,15 +330,15 @@ void SkeletonModel::computeBoundingShape() {
|
|||
return;
|
||||
}
|
||||
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
if (geometry.joints.isEmpty() || geometry.rootJointIndex == -1) {
|
||||
const HFMModel& hfmModel = getHFMModel();
|
||||
if (hfmModel.joints.isEmpty() || hfmModel.rootJointIndex == -1) {
|
||||
// rootJointIndex == -1 if the avatar model has no skeleton
|
||||
return;
|
||||
}
|
||||
|
||||
float radius, height;
|
||||
glm::vec3 offset;
|
||||
_rig.computeAvatarBoundingCapsule(geometry, radius, height, offset);
|
||||
_rig.computeAvatarBoundingCapsule(hfmModel, radius, height, offset);
|
||||
float invScale = 1.0f / _owningAvatar->getModelScale();
|
||||
_boundingCapsuleRadius = invScale * radius;
|
||||
_boundingCapsuleHeight = invScale * height;
|
||||
|
@ -369,7 +369,7 @@ void SkeletonModel::renderBoundingCollisionShapes(RenderArgs* args, gpu::Batch&
|
|||
}
|
||||
|
||||
bool SkeletonModel::hasSkeleton() {
|
||||
return isActive() ? getHFMGeometry().rootJointIndex != -1 : false;
|
||||
return isActive() ? getHFMModel().rootJointIndex != -1 : false;
|
||||
}
|
||||
|
||||
void SkeletonModel::onInvalidate() {
|
||||
|
|
|
@ -41,10 +41,10 @@ public:
|
|||
void updateAttitude(const glm::quat& orientation);
|
||||
|
||||
/// Returns the index of the left hand joint, or -1 if not found.
|
||||
int getLeftHandJointIndex() const { return isActive() ? getHFMGeometry().leftHandJointIndex : -1; }
|
||||
int getLeftHandJointIndex() const { return isActive() ? getHFMModel().leftHandJointIndex : -1; }
|
||||
|
||||
/// Returns the index of the right hand joint, or -1 if not found.
|
||||
int getRightHandJointIndex() const { return isActive() ? getHFMGeometry().rightHandJointIndex : -1; }
|
||||
int getRightHandJointIndex() const { return isActive() ? getHFMModel().rightHandJointIndex : -1; }
|
||||
|
||||
bool getLeftGrabPosition(glm::vec3& position) const;
|
||||
bool getRightGrabPosition(glm::vec3& position) const;
|
||||
|
|
|
@ -206,7 +206,7 @@ void FBXBaker::importScene() {
|
|||
}
|
||||
#endif
|
||||
|
||||
_geometry = reader.extractHFMGeometry({}, _modelURL.toString());
|
||||
_hfmModel = reader.extractHFMModel({}, _modelURL.toString());
|
||||
_textureContentMap = reader._textureContent;
|
||||
}
|
||||
|
||||
|
@ -231,7 +231,7 @@ void FBXBaker::rewriteAndBakeSceneModels() {
|
|||
for (FBXNode& objectChild : rootChild.children) {
|
||||
if (objectChild.name == "Geometry") {
|
||||
|
||||
// TODO Pull this out of _geometry instead so we don't have to reprocess it
|
||||
// TODO Pull this out of _hfmModel instead so we don't have to reprocess it
|
||||
auto extractedMesh = FBXReader::extractMesh(objectChild, meshIndex, false);
|
||||
|
||||
// Callback to get MaterialID
|
||||
|
@ -293,7 +293,7 @@ void FBXBaker::rewriteAndBakeSceneTextures() {
|
|||
QHash<QString, image::TextureUsage::Type> textureTypes;
|
||||
|
||||
// enumerate the materials in the extracted geometry so we can determine the texture type for each texture ID
|
||||
for (const auto& material : _geometry->materials) {
|
||||
for (const auto& material : _hfmModel->materials) {
|
||||
if (material.normalTexture.isBumpmap) {
|
||||
textureTypes[material.normalTexture.id] = BUMP_TEXTURE;
|
||||
} else {
|
||||
|
|
|
@ -53,7 +53,7 @@ private:
|
|||
void rewriteAndBakeSceneModels();
|
||||
void rewriteAndBakeSceneTextures();
|
||||
|
||||
HFMGeometry* _geometry;
|
||||
HFMModel* _hfmModel;
|
||||
QHash<QString, int> _textureNameMatchCount;
|
||||
QHash<QUrl, QString> _remappedTexturePaths;
|
||||
|
||||
|
|
|
@ -153,7 +153,7 @@ void OBJBaker::bakeOBJ() {
|
|||
checkIfTexturesFinished();
|
||||
}
|
||||
|
||||
void OBJBaker::createFBXNodeTree(FBXNode& rootNode, HFMGeometry& geometry) {
|
||||
void OBJBaker::createFBXNodeTree(FBXNode& rootNode, HFMModel& hfmModel) {
|
||||
// Generating FBX Header Node
|
||||
FBXNode headerNode;
|
||||
headerNode.name = FBX_HEADER_EXTENSION;
|
||||
|
@ -199,7 +199,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, HFMGeometry& geometry) {
|
|||
// Compress the mesh information and store in dracoNode
|
||||
bool hasDeformers = false; // No concept of deformers for an OBJ
|
||||
FBXNode dracoNode;
|
||||
compressMesh(geometry.meshes[0], hasDeformers, dracoNode);
|
||||
compressMesh(hfmModel.meshes[0], hasDeformers, dracoNode);
|
||||
geometryNode.children.append(dracoNode);
|
||||
|
||||
// Generating Object node's child - Model node
|
||||
|
@ -214,17 +214,17 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, HFMGeometry& geometry) {
|
|||
objectNode.children = { geometryNode, modelNode };
|
||||
|
||||
// Generating Objects node's child - Material node
|
||||
auto& meshParts = geometry.meshes[0].parts;
|
||||
auto& meshParts = hfmModel.meshes[0].parts;
|
||||
for (auto& meshPart : meshParts) {
|
||||
FBXNode materialNode;
|
||||
materialNode.name = MATERIAL_NODE_NAME;
|
||||
if (geometry.materials.size() == 1) {
|
||||
if (hfmModel.materials.size() == 1) {
|
||||
// case when no material information is provided, OBJReader considers it as a single default material
|
||||
for (auto& materialID : geometry.materials.keys()) {
|
||||
setMaterialNodeProperties(materialNode, materialID, geometry);
|
||||
for (auto& materialID : hfmModel.materials.keys()) {
|
||||
setMaterialNodeProperties(materialNode, materialID, hfmModel);
|
||||
}
|
||||
} else {
|
||||
setMaterialNodeProperties(materialNode, meshPart.materialID, geometry);
|
||||
setMaterialNodeProperties(materialNode, meshPart.materialID, hfmModel);
|
||||
}
|
||||
|
||||
objectNode.children.append(materialNode);
|
||||
|
@ -235,7 +235,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, HFMGeometry& geometry) {
|
|||
auto size = meshParts.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
QString material = meshParts[i].materialID;
|
||||
HFMMaterial currentMaterial = geometry.materials[material];
|
||||
HFMMaterial currentMaterial = hfmModel.materials[material];
|
||||
if (!currentMaterial.albedoTexture.filename.isEmpty() || !currentMaterial.specularTexture.filename.isEmpty()) {
|
||||
auto textureID = nextNodeID();
|
||||
_mapTextureMaterial.emplace_back(textureID, i);
|
||||
|
@ -325,12 +325,12 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, HFMGeometry& geometry) {
|
|||
}
|
||||
|
||||
// Set properties for material nodes
|
||||
void OBJBaker::setMaterialNodeProperties(FBXNode& materialNode, QString material, HFMGeometry& geometry) {
|
||||
void OBJBaker::setMaterialNodeProperties(FBXNode& materialNode, QString material, HFMModel& hfmModel) {
|
||||
auto materialID = nextNodeID();
|
||||
_materialIDs.push_back(materialID);
|
||||
materialNode.properties = { materialID, material, MESH };
|
||||
|
||||
HFMMaterial currentMaterial = geometry.materials[material];
|
||||
HFMMaterial currentMaterial = hfmModel.materials[material];
|
||||
|
||||
// Setting the hierarchy: Material -> Properties70 -> P -> Properties
|
||||
FBXNode properties70Node;
|
||||
|
|
|
@ -39,8 +39,8 @@ private slots:
|
|||
|
||||
private:
|
||||
void loadOBJ();
|
||||
void createFBXNodeTree(FBXNode& rootNode, HFMGeometry& geometry);
|
||||
void setMaterialNodeProperties(FBXNode& materialNode, QString material, HFMGeometry& geometry);
|
||||
void createFBXNodeTree(FBXNode& rootNode, HFMModel& hfmModel);
|
||||
void setMaterialNodeProperties(FBXNode& materialNode, QString material, HFMModel& hfmModel);
|
||||
NodeID nextNodeID() { return _nodeID++; }
|
||||
|
||||
|
||||
|
|
|
@ -268,7 +268,7 @@ EntityItemProperties RenderableModelEntityItem::getProperties(const EntityProper
|
|||
if (model->isLoaded()) {
|
||||
// TODO: improve naturalDimensions in the future,
|
||||
// for now we've added this hack for setting natural dimensions of models
|
||||
Extents meshExtents = model->getHFMGeometry().getUnscaledMeshExtents();
|
||||
Extents meshExtents = model->getHFMModel().getUnscaledMeshExtents();
|
||||
properties.setNaturalDimensions(meshExtents.maximum - meshExtents.minimum);
|
||||
properties.calculateNaturalPosition(meshExtents.minimum, meshExtents.maximum);
|
||||
}
|
||||
|
@ -403,7 +403,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
// should never fall in here when collision model not fully loaded
|
||||
// TODO: assert that all geometries exist and are loaded
|
||||
//assert(_model && _model->isLoaded() && _compoundShapeResource && _compoundShapeResource->isLoaded());
|
||||
const HFMGeometry& collisionGeometry = _compoundShapeResource->getHFMGeometry();
|
||||
const HFMModel& collisionGeometry = _compoundShapeResource->getHFMModel();
|
||||
|
||||
ShapeInfo::PointCollection& pointCollection = shapeInfo.getPointCollection();
|
||||
pointCollection.clear();
|
||||
|
@ -478,7 +478,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
// to the visual model and apply them to the collision model (without regard for the
|
||||
// collision model's extents).
|
||||
|
||||
glm::vec3 scaleToFit = dimensions / model->getHFMGeometry().getUnscaledMeshExtents().size();
|
||||
glm::vec3 scaleToFit = dimensions / model->getHFMModel().getUnscaledMeshExtents().size();
|
||||
// multiply each point by scale before handing the point-set off to the physics engine.
|
||||
// also determine the extents of the collision model.
|
||||
glm::vec3 registrationOffset = dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint());
|
||||
|
@ -498,12 +498,12 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
|
||||
// compute meshPart local transforms
|
||||
QVector<glm::mat4> localTransforms;
|
||||
const HFMGeometry& hfmGeometry = model->getHFMGeometry();
|
||||
int numHFMMeshes = hfmGeometry.meshes.size();
|
||||
const HFMModel& hfmModel = model->getHFMModel();
|
||||
int numHFMMeshes = hfmModel.meshes.size();
|
||||
int totalNumVertices = 0;
|
||||
glm::mat4 invRegistraionOffset = glm::translate(dimensions * (getRegistrationPoint() - ENTITY_ITEM_DEFAULT_REGISTRATION_POINT));
|
||||
for (int i = 0; i < numHFMMeshes; i++) {
|
||||
const HFMMesh& mesh = hfmGeometry.meshes.at(i);
|
||||
const HFMMesh& mesh = hfmModel.meshes.at(i);
|
||||
if (mesh.clusters.size() > 0) {
|
||||
const HFMCluster& cluster = mesh.clusters.at(0);
|
||||
auto jointMatrix = model->getRig().getJointTransform(cluster.jointIndex);
|
||||
|
@ -524,7 +524,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
|
||||
std::vector<std::shared_ptr<const graphics::Mesh>> meshes;
|
||||
if (type == SHAPE_TYPE_SIMPLE_COMPOUND) {
|
||||
auto& hfmMeshes = _compoundShapeResource->getHFMGeometry().meshes;
|
||||
auto& hfmMeshes = _compoundShapeResource->getHFMModel().meshes;
|
||||
meshes.reserve(hfmMeshes.size());
|
||||
for (auto& hfmMesh : hfmMeshes) {
|
||||
meshes.push_back(hfmMesh._mesh);
|
||||
|
@ -755,7 +755,7 @@ int RenderableModelEntityItem::avatarJointIndex(int modelJointIndex) {
|
|||
bool RenderableModelEntityItem::contains(const glm::vec3& point) const {
|
||||
auto model = getModel();
|
||||
if (EntityItem::contains(point) && model && _compoundShapeResource && _compoundShapeResource->isLoaded()) {
|
||||
return _compoundShapeResource->getHFMGeometry().convexHullContains(worldToEntity(point));
|
||||
return _compoundShapeResource->getHFMModel().convexHullContains(worldToEntity(point));
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -1159,11 +1159,11 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
|
|||
return;
|
||||
}
|
||||
|
||||
QStringList animationJointNames = _animation->getGeometry().getJointNames();
|
||||
auto& hfmJoints = _animation->getGeometry().joints;
|
||||
QStringList animationJointNames = _animation->getHFMModel().getJointNames();
|
||||
auto& hfmJoints = _animation->getHFMModel().joints;
|
||||
|
||||
auto& originalHFMJoints = _model->getHFMGeometry().joints;
|
||||
auto& originalHFMIndices = _model->getHFMGeometry().jointIndices;
|
||||
auto& originalHFMJoints = _model->getHFMModel().joints;
|
||||
auto& originalHFMIndices = _model->getHFMModel().jointIndices;
|
||||
|
||||
bool allowTranslation = entity->getAnimationAllowTranslation();
|
||||
|
||||
|
|
|
@ -231,7 +231,7 @@ public:
|
|||
bool needTangentSpace() const;
|
||||
};
|
||||
|
||||
/// A single mesh (with optional blendshapes) extracted from an FBX document.
|
||||
/// A single mesh (with optional blendshapes).
|
||||
class HFMMesh {
|
||||
public:
|
||||
|
||||
|
@ -277,7 +277,7 @@ public:
|
|||
* @property {Quat[]} rotations
|
||||
* @property {Vec3[]} translations
|
||||
*/
|
||||
/// A single animation frame extracted from an FBX document.
|
||||
/// A single animation frame.
|
||||
class HFMAnimationFrame {
|
||||
public:
|
||||
QVector<glm::quat> rotations;
|
||||
|
@ -305,10 +305,10 @@ public:
|
|||
Q_DECLARE_METATYPE(HFMAnimationFrame)
|
||||
Q_DECLARE_METATYPE(QVector<HFMAnimationFrame>)
|
||||
|
||||
/// A set of meshes extracted from an FBX document.
|
||||
class HFMGeometry {
|
||||
/// The runtime model format.
|
||||
class HFMModel {
|
||||
public:
|
||||
using Pointer = std::shared_ptr<HFMGeometry>;
|
||||
using Pointer = std::shared_ptr<HFMModel>;
|
||||
|
||||
QString originalURL;
|
||||
QString author;
|
||||
|
@ -368,7 +368,7 @@ public:
|
|||
QList<QString> blendshapeChannelNames;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(HFMGeometry)
|
||||
Q_DECLARE_METATYPE(HFMGeometry::Pointer)
|
||||
Q_DECLARE_METATYPE(HFMModel)
|
||||
Q_DECLARE_METATYPE(HFMModel::Pointer)
|
||||
|
||||
#endif // hifi_FBX_h_
|
||||
|
|
|
@ -40,9 +40,9 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
int HFMGeometryPointerMetaTypeId = qRegisterMetaType<HFMGeometry::Pointer>();
|
||||
int HFMModelPointerMetaTypeId = qRegisterMetaType<HFMModel::Pointer>();
|
||||
|
||||
QStringList HFMGeometry::getJointNames() const {
|
||||
QStringList HFMModel::getJointNames() const {
|
||||
QStringList names;
|
||||
foreach (const HFMJoint& joint, joints) {
|
||||
names.append(joint.name);
|
||||
|
@ -50,7 +50,7 @@ QStringList HFMGeometry::getJointNames() const {
|
|||
return names;
|
||||
}
|
||||
|
||||
bool HFMGeometry::hasBlendedMeshes() const {
|
||||
bool HFMModel::hasBlendedMeshes() const {
|
||||
if (!meshes.isEmpty()) {
|
||||
foreach (const HFMMesh& mesh, meshes) {
|
||||
if (!mesh.blendshapes.isEmpty()) {
|
||||
|
@ -61,7 +61,7 @@ bool HFMGeometry::hasBlendedMeshes() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
Extents HFMGeometry::getUnscaledMeshExtents() const {
|
||||
Extents HFMModel::getUnscaledMeshExtents() const {
|
||||
const Extents& extents = meshExtents;
|
||||
|
||||
// even though our caller asked for "unscaled" we need to include any fst scaling, translation, and rotation, which
|
||||
|
@ -74,7 +74,7 @@ Extents HFMGeometry::getUnscaledMeshExtents() const {
|
|||
}
|
||||
|
||||
// TODO: Move to graphics::Mesh when Sam's ready
|
||||
bool HFMGeometry::convexHullContains(const glm::vec3& point) const {
|
||||
bool HFMModel::convexHullContains(const glm::vec3& point) const {
|
||||
if (!getUnscaledMeshExtents().containsPoint(point)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -124,16 +124,16 @@ bool HFMGeometry::convexHullContains(const glm::vec3& point) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
QString HFMGeometry::getModelNameOfMesh(int meshIndex) const {
|
||||
QString HFMModel::getModelNameOfMesh(int meshIndex) const {
|
||||
if (meshIndicesToModelNames.contains(meshIndex)) {
|
||||
return meshIndicesToModelNames.value(meshIndex);
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
int hfmGeometryMetaTypeId = qRegisterMetaType<HFMGeometry>();
|
||||
int hfmModelMetaTypeId = qRegisterMetaType<HFMModel>();
|
||||
int hfmAnimationFrameMetaTypeId = qRegisterMetaType<HFMAnimationFrame>();
|
||||
int hfmAnimationFrameVectorMetaTypeId = qRegisterMetaType<QVector<HFMAnimationFrame> >();
|
||||
int hfmAnimationFrameVectorMetaTypeId = qRegisterMetaType<QVector<HFMAnimationFrame>>();
|
||||
|
||||
|
||||
glm::vec3 parseVec3(const QString& string) {
|
||||
|
@ -264,17 +264,17 @@ public:
|
|||
};
|
||||
|
||||
glm::mat4 getGlobalTransform(const QMultiMap<QString, QString>& _connectionParentMap,
|
||||
const QHash<QString, FBXModel>& models, QString nodeID, bool mixamoHack, const QString& url) {
|
||||
const QHash<QString, FBXModel>& fbxModels, QString nodeID, bool mixamoHack, const QString& url) {
|
||||
glm::mat4 globalTransform;
|
||||
QVector<QString> visitedNodes; // Used to prevent following a cycle
|
||||
while (!nodeID.isNull()) {
|
||||
visitedNodes.append(nodeID); // Append each node we visit
|
||||
|
||||
const FBXModel& model = models.value(nodeID);
|
||||
globalTransform = glm::translate(model.translation) * model.preTransform * glm::mat4_cast(model.preRotation *
|
||||
model.rotation * model.postRotation) * model.postTransform * globalTransform;
|
||||
if (model.hasGeometricOffset) {
|
||||
glm::mat4 geometricOffset = createMatFromScaleQuatAndPos(model.geometricScaling, model.geometricRotation, model.geometricTranslation);
|
||||
const FBXModel& fbxModel = fbxModels.value(nodeID);
|
||||
globalTransform = glm::translate(fbxModel.translation) * fbxModel.preTransform * glm::mat4_cast(fbxModel.preRotation *
|
||||
fbxModel.rotation * fbxModel.postRotation) * fbxModel.postTransform * globalTransform;
|
||||
if (fbxModel.hasGeometricOffset) {
|
||||
glm::mat4 geometricOffset = createMatFromScaleQuatAndPos(fbxModel.geometricScaling, fbxModel.geometricRotation, fbxModel.geometricTranslation);
|
||||
globalTransform = globalTransform * geometricOffset;
|
||||
}
|
||||
|
||||
|
@ -290,7 +290,7 @@ glm::mat4 getGlobalTransform(const QMultiMap<QString, QString>& _connectionParen
|
|||
continue;
|
||||
}
|
||||
|
||||
if (models.contains(parentID)) {
|
||||
if (fbxModels.contains(parentID)) {
|
||||
nodeID = parentID;
|
||||
break;
|
||||
}
|
||||
|
@ -329,7 +329,7 @@ public:
|
|||
};
|
||||
|
||||
void appendModelIDs(const QString& parentID, const QMultiMap<QString, QString>& connectionChildMap,
|
||||
QHash<QString, FBXModel>& models, QSet<QString>& remainingModels, QVector<QString>& modelIDs, bool isRootNode = false) {
|
||||
QHash<QString, FBXModel>& fbxModels, QSet<QString>& remainingModels, QVector<QString>& modelIDs, bool isRootNode = false) {
|
||||
if (remainingModels.contains(parentID)) {
|
||||
modelIDs.append(parentID);
|
||||
remainingModels.remove(parentID);
|
||||
|
@ -337,10 +337,10 @@ void appendModelIDs(const QString& parentID, const QMultiMap<QString, QString>&
|
|||
int parentIndex = isRootNode ? -1 : modelIDs.size() - 1;
|
||||
foreach (const QString& childID, connectionChildMap.values(parentID)) {
|
||||
if (remainingModels.contains(childID)) {
|
||||
FBXModel& model = models[childID];
|
||||
if (model.parentIndex == -1) {
|
||||
model.parentIndex = parentIndex;
|
||||
appendModelIDs(childID, connectionChildMap, models, remainingModels, modelIDs);
|
||||
FBXModel& fbxModel = fbxModels[childID];
|
||||
if (fbxModel.parentIndex == -1) {
|
||||
fbxModel.parentIndex = parentIndex;
|
||||
appendModelIDs(childID, connectionChildMap, fbxModels, remainingModels, modelIDs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -403,7 +403,7 @@ static void createTangents(const HFMMesh& mesh, bool generateFromTexCoords,
|
|||
setTangents(mesh, accessor, part.triangleIndices.at(i + 2), part.triangleIndices.at(i), vertices, normals, tangents);
|
||||
}
|
||||
if ((part.triangleIndices.size() % 3) != 0) {
|
||||
qCDebug(modelformat) << "Error in extractHFMGeometry part.triangleIndices.size() is not divisible by three ";
|
||||
qCDebug(modelformat) << "Error in extractHFMModel part.triangleIndices.size() is not divisible by three ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -503,7 +503,7 @@ void addBlendshapes(const ExtractedBlendshape& extracted, const QList<WeightedIn
|
|||
}
|
||||
|
||||
QString getTopModelID(const QMultiMap<QString, QString>& connectionParentMap,
|
||||
const QHash<QString, FBXModel>& models, const QString& modelID, const QString& url) {
|
||||
const QHash<QString, FBXModel>& fbxModels, const QString& modelID, const QString& url) {
|
||||
QString topID = modelID;
|
||||
QVector<QString> visitedNodes; // Used to prevent following a cycle
|
||||
forever {
|
||||
|
@ -515,7 +515,7 @@ QString getTopModelID(const QMultiMap<QString, QString>& connectionParentMap,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (models.contains(parentID)) {
|
||||
if (fbxModels.contains(parentID)) {
|
||||
topID = parentID;
|
||||
goto outerContinue;
|
||||
}
|
||||
|
@ -615,7 +615,7 @@ QByteArray fileOnUrl(const QByteArray& filepath, const QString& url) {
|
|||
return filepath.mid(filepath.lastIndexOf('/') + 1);
|
||||
}
|
||||
|
||||
HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QString& url) {
|
||||
HFMModel* FBXReader::extractHFMModel(const QVariantHash& mapping, const QString& url) {
|
||||
const FBXNode& node = _rootNode;
|
||||
QMap<QString, ExtractedMesh> meshes;
|
||||
QHash<QString, QString> modelIDsToNames;
|
||||
|
@ -624,7 +624,7 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
|
||||
QVector<ExtractedBlendshape> blendshapes;
|
||||
|
||||
QHash<QString, FBXModel> models;
|
||||
QHash<QString, FBXModel> fbxModels;
|
||||
QHash<QString, Cluster> clusters;
|
||||
QHash<QString, AnimationCurve> animationCurves;
|
||||
|
||||
|
@ -689,10 +689,10 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
#if defined(DEBUG_FBXREADER)
|
||||
int unknown = 0;
|
||||
#endif
|
||||
HFMGeometry* geometryPtr = new HFMGeometry;
|
||||
HFMGeometry& geometry = *geometryPtr;
|
||||
HFMModel* hfmModelPtr = new HFMModel;
|
||||
HFMModel& hfmModel = *hfmModelPtr;
|
||||
|
||||
geometry.originalURL = url;
|
||||
hfmModel.originalURL = url;
|
||||
|
||||
float unitScaleFactor = 1.0f;
|
||||
glm::vec3 ambientColor;
|
||||
|
@ -708,7 +708,7 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
if (subobject.name == "MetaData") {
|
||||
foreach (const FBXNode& subsubobject, subobject.children) {
|
||||
if (subsubobject.name == "Author") {
|
||||
geometry.author = subsubobject.properties.at(0).toString();
|
||||
hfmModel.author = subsubobject.properties.at(0).toString();
|
||||
}
|
||||
}
|
||||
} else if (subobject.name == "Properties70") {
|
||||
|
@ -716,7 +716,7 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
static const QVariant APPLICATION_NAME = QVariant(QByteArray("Original|ApplicationName"));
|
||||
if (subsubobject.name == "P" && subsubobject.properties.size() >= 5 &&
|
||||
subsubobject.properties.at(0) == APPLICATION_NAME) {
|
||||
geometry.applicationName = subsubobject.properties.at(4).toString();
|
||||
hfmModel.applicationName = subsubobject.properties.at(4).toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -814,7 +814,7 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
glm::vec3 geometricRotation;
|
||||
|
||||
glm::vec3 rotationMin, rotationMax;
|
||||
FBXModel model = { name, -1, glm::vec3(), glm::mat4(), glm::quat(), glm::quat(), glm::quat(),
|
||||
FBXModel fbxModel = { name, -1, glm::vec3(), glm::mat4(), glm::quat(), glm::quat(), glm::quat(),
|
||||
glm::mat4(), glm::vec3(), glm::vec3(),
|
||||
false, glm::vec3(), glm::quat(), glm::vec3(1.0f) };
|
||||
ExtractedMesh* mesh = NULL;
|
||||
|
@ -963,27 +963,27 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
}
|
||||
|
||||
// see FBX documentation, http://download.autodesk.com/us/fbx/20112/FBX_SDK_HELP/index.html
|
||||
model.translation = translation;
|
||||
fbxModel.translation = translation;
|
||||
|
||||
model.preTransform = glm::translate(rotationOffset) * glm::translate(rotationPivot);
|
||||
model.preRotation = glm::quat(glm::radians(preRotation));
|
||||
model.rotation = glm::quat(glm::radians(rotation));
|
||||
model.postRotation = glm::inverse(glm::quat(glm::radians(postRotation)));
|
||||
model.postTransform = glm::translate(-rotationPivot) * glm::translate(scaleOffset) *
|
||||
fbxModel.preTransform = glm::translate(rotationOffset) * glm::translate(rotationPivot);
|
||||
fbxModel.preRotation = glm::quat(glm::radians(preRotation));
|
||||
fbxModel.rotation = glm::quat(glm::radians(rotation));
|
||||
fbxModel.postRotation = glm::inverse(glm::quat(glm::radians(postRotation)));
|
||||
fbxModel.postTransform = glm::translate(-rotationPivot) * glm::translate(scaleOffset) *
|
||||
glm::translate(scalePivot) * glm::scale(scale) * glm::translate(-scalePivot);
|
||||
// NOTE: angles from the FBX file are in degrees
|
||||
// so we convert them to radians for the FBXModel class
|
||||
model.rotationMin = glm::radians(glm::vec3(rotationMinX ? rotationMin.x : -180.0f,
|
||||
fbxModel.rotationMin = glm::radians(glm::vec3(rotationMinX ? rotationMin.x : -180.0f,
|
||||
rotationMinY ? rotationMin.y : -180.0f, rotationMinZ ? rotationMin.z : -180.0f));
|
||||
model.rotationMax = glm::radians(glm::vec3(rotationMaxX ? rotationMax.x : 180.0f,
|
||||
fbxModel.rotationMax = glm::radians(glm::vec3(rotationMaxX ? rotationMax.x : 180.0f,
|
||||
rotationMaxY ? rotationMax.y : 180.0f, rotationMaxZ ? rotationMax.z : 180.0f));
|
||||
|
||||
model.hasGeometricOffset = hasGeometricOffset;
|
||||
model.geometricTranslation = geometricTranslation;
|
||||
model.geometricRotation = glm::quat(glm::radians(geometricRotation));
|
||||
model.geometricScaling = geometricScaling;
|
||||
fbxModel.hasGeometricOffset = hasGeometricOffset;
|
||||
fbxModel.geometricTranslation = geometricTranslation;
|
||||
fbxModel.geometricRotation = glm::quat(glm::radians(geometricRotation));
|
||||
fbxModel.geometricScaling = geometricScaling;
|
||||
|
||||
models.insert(getID(object.properties), model);
|
||||
fbxModels.insert(getID(object.properties), fbxModel);
|
||||
} else if (object.name == "Texture") {
|
||||
TextureParam tex;
|
||||
foreach (const FBXNode& subobject, object.children) {
|
||||
|
@ -1307,7 +1307,7 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
name = name.mid(name.lastIndexOf('.') + 1);
|
||||
}
|
||||
QString id = getID(object.properties);
|
||||
geometry.blendshapeChannelNames << name;
|
||||
hfmModel.blendshapeChannelNames << name;
|
||||
foreach (const WeightedIndex& index, blendshapeIndices.values(name)) {
|
||||
blendshapeChannelIndices.insert(id, index);
|
||||
}
|
||||
|
@ -1454,26 +1454,26 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
float offsetScale = mapping.value("scale", 1.0f).toFloat() * unitScaleFactor * METERS_PER_CENTIMETER;
|
||||
glm::quat offsetRotation = glm::quat(glm::radians(glm::vec3(mapping.value("rx").toFloat(),
|
||||
mapping.value("ry").toFloat(), mapping.value("rz").toFloat())));
|
||||
geometry.offset = glm::translate(glm::vec3(mapping.value("tx").toFloat(), mapping.value("ty").toFloat(),
|
||||
hfmModel.offset = glm::translate(glm::vec3(mapping.value("tx").toFloat(), mapping.value("ty").toFloat(),
|
||||
mapping.value("tz").toFloat())) * glm::mat4_cast(offsetRotation) *
|
||||
glm::scale(glm::vec3(offsetScale, offsetScale, offsetScale));
|
||||
|
||||
// get the list of models in depth-first traversal order
|
||||
QVector<QString> modelIDs;
|
||||
QSet<QString> remainingModels;
|
||||
for (QHash<QString, FBXModel>::const_iterator model = models.constBegin(); model != models.constEnd(); model++) {
|
||||
QSet<QString> remainingFBXModels;
|
||||
for (QHash<QString, FBXModel>::const_iterator fbxModel = fbxModels.constBegin(); fbxModel != fbxModels.constEnd(); fbxModel++) {
|
||||
// models with clusters must be parented to the cluster top
|
||||
// Unless the model is a root node.
|
||||
bool isARootNode = !modelIDs.contains(_connectionParentMap.value(model.key()));
|
||||
bool isARootNode = !modelIDs.contains(_connectionParentMap.value(fbxModel.key()));
|
||||
if (!isARootNode) {
|
||||
foreach(const QString& deformerID, _connectionChildMap.values(model.key())) {
|
||||
foreach(const QString& deformerID, _connectionChildMap.values(fbxModel.key())) {
|
||||
foreach(const QString& clusterID, _connectionChildMap.values(deformerID)) {
|
||||
if (!clusters.contains(clusterID)) {
|
||||
continue;
|
||||
}
|
||||
QString topID = getTopModelID(_connectionParentMap, models, _connectionChildMap.value(clusterID), url);
|
||||
_connectionChildMap.remove(_connectionParentMap.take(model.key()), model.key());
|
||||
_connectionParentMap.insert(model.key(), topID);
|
||||
QString topID = getTopModelID(_connectionParentMap, fbxModels, _connectionChildMap.value(clusterID), url);
|
||||
_connectionChildMap.remove(_connectionParentMap.take(fbxModel.key()), fbxModel.key());
|
||||
_connectionParentMap.insert(fbxModel.key(), topID);
|
||||
goto outerBreak;
|
||||
}
|
||||
}
|
||||
|
@ -1481,21 +1481,21 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
}
|
||||
|
||||
// make sure the parent is in the child map
|
||||
QString parent = _connectionParentMap.value(model.key());
|
||||
if (!_connectionChildMap.contains(parent, model.key())) {
|
||||
_connectionChildMap.insert(parent, model.key());
|
||||
QString parent = _connectionParentMap.value(fbxModel.key());
|
||||
if (!_connectionChildMap.contains(parent, fbxModel.key())) {
|
||||
_connectionChildMap.insert(parent, fbxModel.key());
|
||||
}
|
||||
remainingModels.insert(model.key());
|
||||
remainingFBXModels.insert(fbxModel.key());
|
||||
}
|
||||
while (!remainingModels.isEmpty()) {
|
||||
QString first = *remainingModels.constBegin();
|
||||
foreach (const QString& id, remainingModels) {
|
||||
while (!remainingFBXModels.isEmpty()) {
|
||||
QString first = *remainingFBXModels.constBegin();
|
||||
foreach (const QString& id, remainingFBXModels) {
|
||||
if (id < first) {
|
||||
first = id;
|
||||
}
|
||||
}
|
||||
QString topID = getTopModelID(_connectionParentMap, models, first, url);
|
||||
appendModelIDs(_connectionParentMap.value(topID), _connectionChildMap, models, remainingModels, modelIDs, true);
|
||||
QString topID = getTopModelID(_connectionParentMap, fbxModels, first, url);
|
||||
appendModelIDs(_connectionParentMap.value(topID), _connectionChildMap, fbxModels, remainingFBXModels, modelIDs, true);
|
||||
}
|
||||
|
||||
// figure the number of animation frames from the curves
|
||||
|
@ -1507,53 +1507,53 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
HFMAnimationFrame frame;
|
||||
frame.rotations.resize(modelIDs.size());
|
||||
frame.translations.resize(modelIDs.size());
|
||||
geometry.animationFrames.append(frame);
|
||||
hfmModel.animationFrames.append(frame);
|
||||
}
|
||||
|
||||
// convert the models to joints
|
||||
QVariantList freeJoints = mapping.values("freeJoint");
|
||||
geometry.hasSkeletonJoints = false;
|
||||
hfmModel.hasSkeletonJoints = false;
|
||||
foreach (const QString& modelID, modelIDs) {
|
||||
const FBXModel& model = models[modelID];
|
||||
const FBXModel& fbxModel = fbxModels[modelID];
|
||||
HFMJoint joint;
|
||||
joint.isFree = freeJoints.contains(model.name);
|
||||
joint.parentIndex = model.parentIndex;
|
||||
joint.isFree = freeJoints.contains(fbxModel.name);
|
||||
joint.parentIndex = fbxModel.parentIndex;
|
||||
|
||||
// get the indices of all ancestors starting with the first free one (if any)
|
||||
int jointIndex = geometry.joints.size();
|
||||
int jointIndex = hfmModel.joints.size();
|
||||
joint.freeLineage.append(jointIndex);
|
||||
int lastFreeIndex = joint.isFree ? 0 : -1;
|
||||
for (int index = joint.parentIndex; index != -1; index = geometry.joints.at(index).parentIndex) {
|
||||
if (geometry.joints.at(index).isFree) {
|
||||
for (int index = joint.parentIndex; index != -1; index = hfmModel.joints.at(index).parentIndex) {
|
||||
if (hfmModel.joints.at(index).isFree) {
|
||||
lastFreeIndex = joint.freeLineage.size();
|
||||
}
|
||||
joint.freeLineage.append(index);
|
||||
}
|
||||
joint.freeLineage.remove(lastFreeIndex + 1, joint.freeLineage.size() - lastFreeIndex - 1);
|
||||
joint.translation = model.translation; // these are usually in centimeters
|
||||
joint.preTransform = model.preTransform;
|
||||
joint.preRotation = model.preRotation;
|
||||
joint.rotation = model.rotation;
|
||||
joint.postRotation = model.postRotation;
|
||||
joint.postTransform = model.postTransform;
|
||||
joint.rotationMin = model.rotationMin;
|
||||
joint.rotationMax = model.rotationMax;
|
||||
joint.translation = fbxModel.translation; // these are usually in centimeters
|
||||
joint.preTransform = fbxModel.preTransform;
|
||||
joint.preRotation = fbxModel.preRotation;
|
||||
joint.rotation = fbxModel.rotation;
|
||||
joint.postRotation = fbxModel.postRotation;
|
||||
joint.postTransform = fbxModel.postTransform;
|
||||
joint.rotationMin = fbxModel.rotationMin;
|
||||
joint.rotationMax = fbxModel.rotationMax;
|
||||
|
||||
joint.hasGeometricOffset = model.hasGeometricOffset;
|
||||
joint.geometricTranslation = model.geometricTranslation;
|
||||
joint.geometricRotation = model.geometricRotation;
|
||||
joint.geometricScaling = model.geometricScaling;
|
||||
joint.hasGeometricOffset = fbxModel.hasGeometricOffset;
|
||||
joint.geometricTranslation = fbxModel.geometricTranslation;
|
||||
joint.geometricRotation = fbxModel.geometricRotation;
|
||||
joint.geometricScaling = fbxModel.geometricScaling;
|
||||
|
||||
glm::quat combinedRotation = joint.preRotation * joint.rotation * joint.postRotation;
|
||||
|
||||
if (joint.parentIndex == -1) {
|
||||
joint.transform = geometry.offset * glm::translate(joint.translation) * joint.preTransform *
|
||||
joint.transform = hfmModel.offset * glm::translate(joint.translation) * joint.preTransform *
|
||||
glm::mat4_cast(combinedRotation) * joint.postTransform;
|
||||
joint.inverseDefaultRotation = glm::inverse(combinedRotation);
|
||||
joint.distanceToParent = 0.0f;
|
||||
|
||||
} else {
|
||||
const HFMJoint& parentJoint = geometry.joints.at(joint.parentIndex);
|
||||
const HFMJoint& parentJoint = hfmModel.joints.at(joint.parentIndex);
|
||||
joint.transform = parentJoint.transform * glm::translate(joint.translation) *
|
||||
joint.preTransform * glm::mat4_cast(combinedRotation) * joint.postTransform;
|
||||
joint.inverseDefaultRotation = glm::inverse(combinedRotation) * parentJoint.inverseDefaultRotation;
|
||||
|
@ -1561,20 +1561,20 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
extractTranslation(joint.transform));
|
||||
}
|
||||
joint.inverseBindRotation = joint.inverseDefaultRotation;
|
||||
joint.name = model.name;
|
||||
joint.name = fbxModel.name;
|
||||
|
||||
foreach (const QString& childID, _connectionChildMap.values(modelID)) {
|
||||
QString type = typeFlags.value(childID);
|
||||
if (!type.isEmpty()) {
|
||||
geometry.hasSkeletonJoints |= (joint.isSkeletonJoint = type.toLower().contains("Skeleton"));
|
||||
hfmModel.hasSkeletonJoints |= (joint.isSkeletonJoint = type.toLower().contains("Skeleton"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
joint.bindTransformFoundInCluster = false;
|
||||
|
||||
geometry.joints.append(joint);
|
||||
geometry.jointIndices.insert(model.name, geometry.joints.size());
|
||||
hfmModel.joints.append(joint);
|
||||
hfmModel.jointIndices.insert(fbxModel.name, hfmModel.joints.size());
|
||||
|
||||
QString rotationID = localRotations.value(modelID);
|
||||
AnimationCurve xRotCurve = animationCurves.value(xComponents.value(rotationID));
|
||||
|
@ -1590,11 +1590,11 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
glm::vec3 defaultPosValues = joint.translation;
|
||||
|
||||
for (int i = 0; i < frameCount; i++) {
|
||||
geometry.animationFrames[i].rotations[jointIndex] = glm::quat(glm::radians(glm::vec3(
|
||||
hfmModel.animationFrames[i].rotations[jointIndex] = glm::quat(glm::radians(glm::vec3(
|
||||
xRotCurve.values.isEmpty() ? defaultRotValues.x : xRotCurve.values.at(i % xRotCurve.values.size()),
|
||||
yRotCurve.values.isEmpty() ? defaultRotValues.y : yRotCurve.values.at(i % yRotCurve.values.size()),
|
||||
zRotCurve.values.isEmpty() ? defaultRotValues.z : zRotCurve.values.at(i % zRotCurve.values.size()))));
|
||||
geometry.animationFrames[i].translations[jointIndex] = glm::vec3(
|
||||
hfmModel.animationFrames[i].translations[jointIndex] = glm::vec3(
|
||||
xPosCurve.values.isEmpty() ? defaultPosValues.x : xPosCurve.values.at(i % xPosCurve.values.size()),
|
||||
yPosCurve.values.isEmpty() ? defaultPosValues.y : yPosCurve.values.at(i % yPosCurve.values.size()),
|
||||
zPosCurve.values.isEmpty() ? defaultPosValues.z : zPosCurve.values.at(i % zPosCurve.values.size()));
|
||||
|
@ -1603,32 +1603,32 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
|
||||
// NOTE: shapeVertices are in joint-frame
|
||||
std::vector<ShapeVertices> shapeVertices;
|
||||
shapeVertices.resize(std::max(1, geometry.joints.size()) );
|
||||
shapeVertices.resize(std::max(1, hfmModel.joints.size()) );
|
||||
|
||||
// find our special joints
|
||||
geometry.leftEyeJointIndex = modelIDs.indexOf(jointEyeLeftID);
|
||||
geometry.rightEyeJointIndex = modelIDs.indexOf(jointEyeRightID);
|
||||
geometry.neckJointIndex = modelIDs.indexOf(jointNeckID);
|
||||
geometry.rootJointIndex = modelIDs.indexOf(jointRootID);
|
||||
geometry.leanJointIndex = modelIDs.indexOf(jointLeanID);
|
||||
geometry.headJointIndex = modelIDs.indexOf(jointHeadID);
|
||||
geometry.leftHandJointIndex = modelIDs.indexOf(jointLeftHandID);
|
||||
geometry.rightHandJointIndex = modelIDs.indexOf(jointRightHandID);
|
||||
geometry.leftToeJointIndex = modelIDs.indexOf(jointLeftToeID);
|
||||
geometry.rightToeJointIndex = modelIDs.indexOf(jointRightToeID);
|
||||
hfmModel.leftEyeJointIndex = modelIDs.indexOf(jointEyeLeftID);
|
||||
hfmModel.rightEyeJointIndex = modelIDs.indexOf(jointEyeRightID);
|
||||
hfmModel.neckJointIndex = modelIDs.indexOf(jointNeckID);
|
||||
hfmModel.rootJointIndex = modelIDs.indexOf(jointRootID);
|
||||
hfmModel.leanJointIndex = modelIDs.indexOf(jointLeanID);
|
||||
hfmModel.headJointIndex = modelIDs.indexOf(jointHeadID);
|
||||
hfmModel.leftHandJointIndex = modelIDs.indexOf(jointLeftHandID);
|
||||
hfmModel.rightHandJointIndex = modelIDs.indexOf(jointRightHandID);
|
||||
hfmModel.leftToeJointIndex = modelIDs.indexOf(jointLeftToeID);
|
||||
hfmModel.rightToeJointIndex = modelIDs.indexOf(jointRightToeID);
|
||||
|
||||
foreach (const QString& id, humanIKJointIDs) {
|
||||
geometry.humanIKJointIndices.append(modelIDs.indexOf(id));
|
||||
hfmModel.humanIKJointIndices.append(modelIDs.indexOf(id));
|
||||
}
|
||||
|
||||
// extract the translation component of the neck transform
|
||||
if (geometry.neckJointIndex != -1) {
|
||||
const glm::mat4& transform = geometry.joints.at(geometry.neckJointIndex).transform;
|
||||
geometry.neckPivot = glm::vec3(transform[3][0], transform[3][1], transform[3][2]);
|
||||
if (hfmModel.neckJointIndex != -1) {
|
||||
const glm::mat4& transform = hfmModel.joints.at(hfmModel.neckJointIndex).transform;
|
||||
hfmModel.neckPivot = glm::vec3(transform[3][0], transform[3][1], transform[3][2]);
|
||||
}
|
||||
|
||||
geometry.bindExtents.reset();
|
||||
geometry.meshExtents.reset();
|
||||
hfmModel.bindExtents.reset();
|
||||
hfmModel.meshExtents.reset();
|
||||
|
||||
// Create the Material Library
|
||||
consolidateHFMMaterials(mapping);
|
||||
|
@ -1664,7 +1664,7 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
}
|
||||
}
|
||||
#endif
|
||||
geometry.materials = _hfmMaterials;
|
||||
hfmModel.materials = _hfmMaterials;
|
||||
|
||||
// see if any materials have texture children
|
||||
bool materialsHaveTextures = checkMaterialsHaveTextures(_hfmMaterials, _textureFilenames, _connectionChildMap);
|
||||
|
@ -1675,14 +1675,14 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
extracted.mesh.meshExtents.reset();
|
||||
|
||||
// accumulate local transforms
|
||||
QString modelID = models.contains(it.key()) ? it.key() : _connectionParentMap.value(it.key());
|
||||
glm::mat4 modelTransform = getGlobalTransform(_connectionParentMap, models, modelID, geometry.applicationName == "mixamo.com", url);
|
||||
QString modelID = fbxModels.contains(it.key()) ? it.key() : _connectionParentMap.value(it.key());
|
||||
glm::mat4 modelTransform = getGlobalTransform(_connectionParentMap, fbxModels, modelID, hfmModel.applicationName == "mixamo.com", url);
|
||||
|
||||
// compute the mesh extents from the transformed vertices
|
||||
foreach (const glm::vec3& vertex, extracted.mesh.vertices) {
|
||||
glm::vec3 transformedVertex = glm::vec3(modelTransform * glm::vec4(vertex, 1.0f));
|
||||
geometry.meshExtents.minimum = glm::min(geometry.meshExtents.minimum, transformedVertex);
|
||||
geometry.meshExtents.maximum = glm::max(geometry.meshExtents.maximum, transformedVertex);
|
||||
hfmModel.meshExtents.minimum = glm::min(hfmModel.meshExtents.minimum, transformedVertex);
|
||||
hfmModel.meshExtents.maximum = glm::max(hfmModel.meshExtents.maximum, transformedVertex);
|
||||
|
||||
extracted.mesh.meshExtents.minimum = glm::min(extracted.mesh.meshExtents.minimum, transformedVertex);
|
||||
extracted.mesh.meshExtents.maximum = glm::max(extracted.mesh.meshExtents.maximum, transformedVertex);
|
||||
|
@ -1763,14 +1763,14 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
extracted.mesh.clusters.append(hfmCluster);
|
||||
|
||||
// override the bind rotation with the transform link
|
||||
HFMJoint& joint = geometry.joints[hfmCluster.jointIndex];
|
||||
HFMJoint& joint = hfmModel.joints[hfmCluster.jointIndex];
|
||||
joint.inverseBindRotation = glm::inverse(extractRotation(cluster.transformLink));
|
||||
joint.bindTransform = cluster.transformLink;
|
||||
joint.bindTransformFoundInCluster = true;
|
||||
|
||||
// update the bind pose extents
|
||||
glm::vec3 bindTranslation = extractTranslation(geometry.offset * joint.bindTransform);
|
||||
geometry.bindExtents.addPoint(bindTranslation);
|
||||
glm::vec3 bindTranslation = extractTranslation(hfmModel.offset * joint.bindTransform);
|
||||
hfmModel.bindExtents.addPoint(bindTranslation);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1801,14 +1801,14 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
const Cluster& cluster = clusters[clusterID];
|
||||
const HFMCluster& hfmCluster = extracted.mesh.clusters.at(i);
|
||||
int jointIndex = hfmCluster.jointIndex;
|
||||
HFMJoint& joint = geometry.joints[jointIndex];
|
||||
HFMJoint& joint = hfmModel.joints[jointIndex];
|
||||
glm::mat4 transformJointToMesh = inverseModelTransform * joint.bindTransform;
|
||||
glm::vec3 boneEnd = extractTranslation(transformJointToMesh);
|
||||
glm::vec3 boneBegin = boneEnd;
|
||||
glm::vec3 boneDirection;
|
||||
float boneLength = 0.0f;
|
||||
if (joint.parentIndex != -1) {
|
||||
boneBegin = extractTranslation(inverseModelTransform * geometry.joints[joint.parentIndex].bindTransform);
|
||||
boneBegin = extractTranslation(inverseModelTransform * hfmModel.joints[joint.parentIndex].bindTransform);
|
||||
boneDirection = boneEnd - boneBegin;
|
||||
boneLength = glm::length(boneDirection);
|
||||
if (boneLength > EPSILON) {
|
||||
|
@ -1882,7 +1882,7 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
} else {
|
||||
// this is a single-mesh joint
|
||||
int jointIndex = firstHFMCluster.jointIndex;
|
||||
HFMJoint& joint = geometry.joints[jointIndex];
|
||||
HFMJoint& joint = hfmModel.joints[jointIndex];
|
||||
|
||||
// transform cluster vertices to joint-frame and save for later
|
||||
glm::mat4 meshToJoint = glm::inverse(joint.bindTransform) * modelTransform;
|
||||
|
@ -1902,8 +1902,8 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
}
|
||||
buildModelMesh(extracted.mesh, url);
|
||||
|
||||
geometry.meshes.append(extracted.mesh);
|
||||
int meshIndex = geometry.meshes.size() - 1;
|
||||
hfmModel.meshes.append(extracted.mesh);
|
||||
int meshIndex = hfmModel.meshes.size() - 1;
|
||||
if (extracted.mesh._mesh) {
|
||||
extracted.mesh._mesh->displayName = QString("%1#/mesh/%2").arg(url).arg(meshIndex).toStdString();
|
||||
extracted.mesh._mesh->modelName = modelIDsToNames.value(modelID).toStdString();
|
||||
|
@ -1923,8 +1923,8 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
};
|
||||
|
||||
// now that all joints have been scanned compute a k-Dop bounding volume of mesh
|
||||
for (int i = 0; i < geometry.joints.size(); ++i) {
|
||||
HFMJoint& joint = geometry.joints[i];
|
||||
for (int i = 0; i < hfmModel.joints.size(); ++i) {
|
||||
HFMJoint& joint = hfmModel.joints[i];
|
||||
|
||||
// NOTE: points are in joint-frame
|
||||
ShapeVertices& points = shapeVertices.at(i);
|
||||
|
@ -1958,7 +1958,7 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
generateBoundryLinesForDop14(joint.shapeInfo.dots, joint.shapeInfo.avgPoint, joint.shapeInfo.debugLines);
|
||||
}
|
||||
}
|
||||
geometry.palmDirection = parseVec3(mapping.value("palmDirection", "0, -1, 0").toString());
|
||||
hfmModel.palmDirection = parseVec3(mapping.value("palmDirection", "0, -1, 0").toString());
|
||||
|
||||
// attempt to map any meshes to a named model
|
||||
for (QHash<QString, int>::const_iterator m = meshIDsToMeshIndices.constBegin();
|
||||
|
@ -1971,14 +1971,14 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
const QString& modelID = ooChildToParent.value(meshID);
|
||||
if (modelIDsToNames.contains(modelID)) {
|
||||
const QString& modelName = modelIDsToNames.value(modelID);
|
||||
geometry.meshIndicesToModelNames.insert(meshIndex, modelName);
|
||||
hfmModel.meshIndicesToModelNames.insert(meshIndex, modelName);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
int i = 0;
|
||||
for (const auto& mesh : geometry.meshes) {
|
||||
auto name = geometry.getModelNameOfMesh(i++);
|
||||
for (const auto& mesh : hfmModel.meshes) {
|
||||
auto name = hfmModel.getModelNameOfMesh(i++);
|
||||
if (!name.isEmpty()) {
|
||||
if (mesh._mesh) {
|
||||
mesh._mesh->modelName = name.toStdString();
|
||||
|
@ -1991,16 +1991,16 @@ HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QS
|
|||
}
|
||||
}
|
||||
}
|
||||
return geometryPtr;
|
||||
return hfmModelPtr;
|
||||
}
|
||||
|
||||
HFMGeometry* readFBX(const QByteArray& model, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) {
|
||||
QBuffer buffer(const_cast<QByteArray*>(&model));
|
||||
HFMModel* readFBX(const QByteArray& data, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) {
|
||||
QBuffer buffer(const_cast<QByteArray*>(&data));
|
||||
buffer.open(QIODevice::ReadOnly);
|
||||
return readFBX(&buffer, mapping, url, loadLightmaps, lightmapLevel);
|
||||
}
|
||||
|
||||
HFMGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) {
|
||||
HFMModel* readFBX(QIODevice* device, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) {
|
||||
FBXReader reader;
|
||||
reader._rootNode = FBXReader::parseFBX(device);
|
||||
reader._loadLightmaps = loadLightmaps;
|
||||
|
@ -2008,5 +2008,5 @@ HFMGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QStri
|
|||
|
||||
qCDebug(modelformat) << "Reading FBX: " << url;
|
||||
|
||||
return reader.extractHFMGeometry(mapping, url);
|
||||
return reader.extractHFMModel(mapping, url);
|
||||
}
|
||||
|
|
|
@ -34,13 +34,13 @@
|
|||
class QIODevice;
|
||||
class FBXNode;
|
||||
|
||||
/// Reads FBX geometry from the supplied model and mapping data.
|
||||
/// Reads HFMModel from the supplied model and mapping data.
|
||||
/// \exception QString if an error occurs in parsing
|
||||
HFMGeometry* readFBX(const QByteArray& model, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f);
|
||||
HFMModel* readFBX(const QByteArray& data, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f);
|
||||
|
||||
/// Reads FBX geometry from the supplied model and mapping data.
|
||||
/// Reads HFMModel from the supplied model and mapping data.
|
||||
/// \exception QString if an error occurs in parsing
|
||||
HFMGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f);
|
||||
HFMModel* readFBX(QIODevice* device, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f);
|
||||
|
||||
class TextureParam {
|
||||
public:
|
||||
|
@ -103,12 +103,12 @@ class ExtractedMesh;
|
|||
|
||||
class FBXReader {
|
||||
public:
|
||||
HFMGeometry* _hfmGeometry;
|
||||
HFMModel* _hfmModel;
|
||||
|
||||
FBXNode _rootNode;
|
||||
static FBXNode parseFBX(QIODevice* device);
|
||||
|
||||
HFMGeometry* extractHFMGeometry(const QVariantHash& mapping, const QString& url);
|
||||
HFMModel* extractHFMModel(const QVariantHash& mapping, const QString& url);
|
||||
|
||||
static ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex, bool deduplicate = true);
|
||||
QHash<QString, ExtractedMesh> meshes;
|
||||
|
|
|
@ -533,10 +533,10 @@ bool GLTFReader::addTexture(const QJsonObject& object) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool GLTFReader::parseGLTF(const QByteArray& model) {
|
||||
bool GLTFReader::parseGLTF(const QByteArray& data) {
|
||||
PROFILE_RANGE_EX(resource_parse, __FUNCTION__, 0xffff0000, nullptr);
|
||||
|
||||
QJsonDocument d = QJsonDocument::fromJson(model);
|
||||
QJsonDocument d = QJsonDocument::fromJson(data);
|
||||
QJsonObject jsFile = d.object();
|
||||
|
||||
bool isvalid = setAsset(jsFile);
|
||||
|
@ -697,7 +697,7 @@ glm::mat4 GLTFReader::getModelTransform(const GLTFNode& node) {
|
|||
return tmat;
|
||||
}
|
||||
|
||||
bool GLTFReader::buildGeometry(HFMGeometry& geometry, const QUrl& url) {
|
||||
bool GLTFReader::buildGeometry(HFMModel& hfmModel, const QUrl& url) {
|
||||
|
||||
//Build dependencies
|
||||
QVector<QVector<int>> nodeDependencies(_file.nodes.size());
|
||||
|
@ -727,17 +727,17 @@ bool GLTFReader::buildGeometry(HFMGeometry& geometry, const QUrl& url) {
|
|||
}
|
||||
|
||||
//Build default joints
|
||||
geometry.joints.resize(1);
|
||||
geometry.joints[0].isFree = false;
|
||||
geometry.joints[0].parentIndex = -1;
|
||||
geometry.joints[0].distanceToParent = 0;
|
||||
geometry.joints[0].translation = glm::vec3(0, 0, 0);
|
||||
geometry.joints[0].rotationMin = glm::vec3(0, 0, 0);
|
||||
geometry.joints[0].rotationMax = glm::vec3(0, 0, 0);
|
||||
geometry.joints[0].name = "OBJ";
|
||||
geometry.joints[0].isSkeletonJoint = true;
|
||||
hfmModel.joints.resize(1);
|
||||
hfmModel.joints[0].isFree = false;
|
||||
hfmModel.joints[0].parentIndex = -1;
|
||||
hfmModel.joints[0].distanceToParent = 0;
|
||||
hfmModel.joints[0].translation = glm::vec3(0, 0, 0);
|
||||
hfmModel.joints[0].rotationMin = glm::vec3(0, 0, 0);
|
||||
hfmModel.joints[0].rotationMax = glm::vec3(0, 0, 0);
|
||||
hfmModel.joints[0].name = "OBJ";
|
||||
hfmModel.joints[0].isSkeletonJoint = true;
|
||||
|
||||
geometry.jointIndices["x"] = 1;
|
||||
hfmModel.jointIndices["x"] = 1;
|
||||
|
||||
//Build materials
|
||||
QVector<QString> materialIDs;
|
||||
|
@ -750,8 +750,8 @@ bool GLTFReader::buildGeometry(HFMGeometry& geometry, const QUrl& url) {
|
|||
|
||||
for (int i = 0; i < materialIDs.size(); i++) {
|
||||
QString& matid = materialIDs[i];
|
||||
geometry.materials[matid] = HFMMaterial();
|
||||
HFMMaterial& hfmMaterial = geometry.materials[matid];
|
||||
hfmModel.materials[matid] = HFMMaterial();
|
||||
HFMMaterial& hfmMaterial = hfmModel.materials[matid];
|
||||
hfmMaterial._material = std::make_shared<graphics::Material>();
|
||||
setHFMMaterial(hfmMaterial, _file.materials[i]);
|
||||
}
|
||||
|
@ -765,8 +765,8 @@ bool GLTFReader::buildGeometry(HFMGeometry& geometry, const QUrl& url) {
|
|||
if (node.defined["mesh"]) {
|
||||
qCDebug(modelformat) << "node_transforms" << node.transforms;
|
||||
foreach(auto &primitive, _file.meshes[node.mesh].primitives) {
|
||||
geometry.meshes.append(HFMMesh());
|
||||
HFMMesh& mesh = geometry.meshes[geometry.meshes.size() - 1];
|
||||
hfmModel.meshes.append(HFMMesh());
|
||||
HFMMesh& mesh = hfmModel.meshes[hfmModel.meshes.size() - 1];
|
||||
HFMCluster cluster;
|
||||
cluster.jointIndex = 0;
|
||||
cluster.inverseBindMatrix = glm::mat4(1, 0, 0, 0,
|
||||
|
@ -886,7 +886,7 @@ bool GLTFReader::buildGeometry(HFMGeometry& geometry, const QUrl& url) {
|
|||
mesh.meshExtents.reset();
|
||||
foreach(const glm::vec3& vertex, mesh.vertices) {
|
||||
mesh.meshExtents.addPoint(vertex);
|
||||
geometry.meshExtents.addPoint(vertex);
|
||||
hfmModel.meshExtents.addPoint(vertex);
|
||||
}
|
||||
|
||||
// since mesh.modelTransform seems to not have any effect I apply the transformation the model
|
||||
|
@ -898,7 +898,7 @@ bool GLTFReader::buildGeometry(HFMGeometry& geometry, const QUrl& url) {
|
|||
}
|
||||
}
|
||||
|
||||
mesh.meshIndex = geometry.meshes.size();
|
||||
mesh.meshIndex = hfmModel.meshes.size();
|
||||
FBXReader::buildModelMesh(mesh, url.toString());
|
||||
}
|
||||
|
||||
|
@ -910,7 +910,7 @@ bool GLTFReader::buildGeometry(HFMGeometry& geometry, const QUrl& url) {
|
|||
return true;
|
||||
}
|
||||
|
||||
HFMGeometry* GLTFReader::readGLTF(QByteArray& model, const QVariantHash& mapping,
|
||||
HFMModel* GLTFReader::readGLTF(QByteArray& data, const QVariantHash& mapping,
|
||||
const QUrl& url, bool loadLightmaps, float lightmapLevel) {
|
||||
|
||||
_url = url;
|
||||
|
@ -922,15 +922,15 @@ HFMGeometry* GLTFReader::readGLTF(QByteArray& model, const QVariantHash& mapping
|
|||
_url = QUrl(QFileInfo(localFileName).absoluteFilePath());
|
||||
}
|
||||
|
||||
parseGLTF(model);
|
||||
parseGLTF(data);
|
||||
//_file.dump();
|
||||
HFMGeometry* geometryPtr = new HFMGeometry();
|
||||
HFMGeometry& geometry = *geometryPtr;
|
||||
HFMModel* hfmModelPtr = new HFMModel();
|
||||
HFMModel& hfmModel = *hfmModelPtr;
|
||||
|
||||
buildGeometry(geometry, url);
|
||||
buildGeometry(hfmModel, url);
|
||||
|
||||
//hfmDebugDump(geometry);
|
||||
return geometryPtr;
|
||||
//hfmDebugDump(data);
|
||||
return hfmModelPtr;
|
||||
|
||||
}
|
||||
|
||||
|
@ -1181,37 +1181,37 @@ void GLTFReader::retriangulate(const QVector<int>& inIndices, const QVector<glm:
|
|||
}
|
||||
}
|
||||
|
||||
void GLTFReader::hfmDebugDump(const HFMGeometry& hfmgeo) {
|
||||
qCDebug(modelformat) << "---------------- hfmGeometry ----------------";
|
||||
qCDebug(modelformat) << " hasSkeletonJoints =" << hfmgeo.hasSkeletonJoints;
|
||||
qCDebug(modelformat) << " offset =" << hfmgeo.offset;
|
||||
void GLTFReader::hfmDebugDump(const HFMModel& hfmModel) {
|
||||
qCDebug(modelformat) << "---------------- hfmModel ----------------";
|
||||
qCDebug(modelformat) << " hasSkeletonJoints =" << hfmModel.hasSkeletonJoints;
|
||||
qCDebug(modelformat) << " offset =" << hfmModel.offset;
|
||||
|
||||
qCDebug(modelformat) << " leftEyeJointIndex =" << hfmgeo.leftEyeJointIndex;
|
||||
qCDebug(modelformat) << " rightEyeJointIndex =" << hfmgeo.rightEyeJointIndex;
|
||||
qCDebug(modelformat) << " neckJointIndex =" << hfmgeo.neckJointIndex;
|
||||
qCDebug(modelformat) << " rootJointIndex =" << hfmgeo.rootJointIndex;
|
||||
qCDebug(modelformat) << " leanJointIndex =" << hfmgeo.leanJointIndex;
|
||||
qCDebug(modelformat) << " headJointIndex =" << hfmgeo.headJointIndex;
|
||||
qCDebug(modelformat) << " leftHandJointIndex" << hfmgeo.leftHandJointIndex;
|
||||
qCDebug(modelformat) << " rightHandJointIndex" << hfmgeo.rightHandJointIndex;
|
||||
qCDebug(modelformat) << " leftToeJointIndex" << hfmgeo.leftToeJointIndex;
|
||||
qCDebug(modelformat) << " rightToeJointIndex" << hfmgeo.rightToeJointIndex;
|
||||
qCDebug(modelformat) << " leftEyeSize = " << hfmgeo.leftEyeSize;
|
||||
qCDebug(modelformat) << " rightEyeSize = " << hfmgeo.rightEyeSize;
|
||||
qCDebug(modelformat) << " leftEyeJointIndex =" << hfmModel.leftEyeJointIndex;
|
||||
qCDebug(modelformat) << " rightEyeJointIndex =" << hfmModel.rightEyeJointIndex;
|
||||
qCDebug(modelformat) << " neckJointIndex =" << hfmModel.neckJointIndex;
|
||||
qCDebug(modelformat) << " rootJointIndex =" << hfmModel.rootJointIndex;
|
||||
qCDebug(modelformat) << " leanJointIndex =" << hfmModel.leanJointIndex;
|
||||
qCDebug(modelformat) << " headJointIndex =" << hfmModel.headJointIndex;
|
||||
qCDebug(modelformat) << " leftHandJointIndex" << hfmModel.leftHandJointIndex;
|
||||
qCDebug(modelformat) << " rightHandJointIndex" << hfmModel.rightHandJointIndex;
|
||||
qCDebug(modelformat) << " leftToeJointIndex" << hfmModel.leftToeJointIndex;
|
||||
qCDebug(modelformat) << " rightToeJointIndex" << hfmModel.rightToeJointIndex;
|
||||
qCDebug(modelformat) << " leftEyeSize = " << hfmModel.leftEyeSize;
|
||||
qCDebug(modelformat) << " rightEyeSize = " << hfmModel.rightEyeSize;
|
||||
|
||||
qCDebug(modelformat) << " palmDirection = " << hfmgeo.palmDirection;
|
||||
qCDebug(modelformat) << " palmDirection = " << hfmModel.palmDirection;
|
||||
|
||||
qCDebug(modelformat) << " neckPivot = " << hfmgeo.neckPivot;
|
||||
qCDebug(modelformat) << " neckPivot = " << hfmModel.neckPivot;
|
||||
|
||||
qCDebug(modelformat) << " bindExtents.size() = " << hfmgeo.bindExtents.size();
|
||||
qCDebug(modelformat) << " meshExtents.size() = " << hfmgeo.meshExtents.size();
|
||||
qCDebug(modelformat) << " bindExtents.size() = " << hfmModel.bindExtents.size();
|
||||
qCDebug(modelformat) << " meshExtents.size() = " << hfmModel.meshExtents.size();
|
||||
|
||||
qCDebug(modelformat) << " jointIndices.size() =" << hfmgeo.jointIndices.size();
|
||||
qCDebug(modelformat) << " joints.count() =" << hfmgeo.joints.count();
|
||||
qCDebug(modelformat) << " jointIndices.size() =" << hfmModel.jointIndices.size();
|
||||
qCDebug(modelformat) << " joints.count() =" << hfmModel.joints.count();
|
||||
qCDebug(modelformat) << "---------------- Meshes ----------------";
|
||||
qCDebug(modelformat) << " meshes.count() =" << hfmgeo.meshes.count();
|
||||
qCDebug(modelformat) << " blendshapeChannelNames = " << hfmgeo.blendshapeChannelNames;
|
||||
foreach(HFMMesh mesh, hfmgeo.meshes) {
|
||||
qCDebug(modelformat) << " meshes.count() =" << hfmModel.meshes.count();
|
||||
qCDebug(modelformat) << " blendshapeChannelNames = " << hfmModel.blendshapeChannelNames;
|
||||
foreach(HFMMesh mesh, hfmModel.meshes) {
|
||||
qCDebug(modelformat) << "\n";
|
||||
qCDebug(modelformat) << " meshpointer =" << mesh._mesh.get();
|
||||
qCDebug(modelformat) << " meshindex =" << mesh.meshIndex;
|
||||
|
@ -1254,18 +1254,18 @@ void GLTFReader::hfmDebugDump(const HFMGeometry& hfmgeo) {
|
|||
qCDebug(modelformat) << "\n";
|
||||
}
|
||||
qCDebug(modelformat) << "---------------- AnimationFrames ----------------";
|
||||
foreach(HFMAnimationFrame anim, hfmgeo.animationFrames) {
|
||||
foreach(HFMAnimationFrame anim, hfmModel.animationFrames) {
|
||||
qCDebug(modelformat) << " anim.translations = " << anim.translations;
|
||||
qCDebug(modelformat) << " anim.rotations = " << anim.rotations;
|
||||
}
|
||||
QList<int> mitomona_keys = hfmgeo.meshIndicesToModelNames.keys();
|
||||
QList<int> mitomona_keys = hfmModel.meshIndicesToModelNames.keys();
|
||||
foreach(int key, mitomona_keys) {
|
||||
qCDebug(modelformat) << " meshIndicesToModelNames key =" << key << " val =" << hfmgeo.meshIndicesToModelNames[key];
|
||||
qCDebug(modelformat) << " meshIndicesToModelNames key =" << key << " val =" << hfmModel.meshIndicesToModelNames[key];
|
||||
}
|
||||
|
||||
qCDebug(modelformat) << "---------------- Materials ----------------";
|
||||
|
||||
foreach(HFMMaterial mat, hfmgeo.materials) {
|
||||
foreach(HFMMaterial mat, hfmModel.materials) {
|
||||
qCDebug(modelformat) << "\n";
|
||||
qCDebug(modelformat) << " mat.materialID =" << mat.materialID;
|
||||
qCDebug(modelformat) << " diffuseColor =" << mat.diffuseColor;
|
||||
|
@ -1314,7 +1314,7 @@ void GLTFReader::hfmDebugDump(const HFMGeometry& hfmgeo) {
|
|||
|
||||
qCDebug(modelformat) << "---------------- Joints ----------------";
|
||||
|
||||
foreach(HFMJoint joint, hfmgeo.joints) {
|
||||
foreach(HFMJoint joint, hfmModel.joints) {
|
||||
qCDebug(modelformat) << "\n";
|
||||
qCDebug(modelformat) << " shapeInfo.avgPoint =" << joint.shapeInfo.avgPoint;
|
||||
qCDebug(modelformat) << " shapeInfo.debugLines =" << joint.shapeInfo.debugLines;
|
||||
|
|
|
@ -706,7 +706,7 @@ class GLTFReader : public QObject {
|
|||
Q_OBJECT
|
||||
public:
|
||||
GLTFReader();
|
||||
HFMGeometry* readGLTF(QByteArray& model, const QVariantHash& mapping,
|
||||
HFMModel* readGLTF(QByteArray& data, const QVariantHash& mapping,
|
||||
const QUrl& url, bool loadLightmaps = true, float lightmapLevel = 1.0f);
|
||||
private:
|
||||
GLTFFile _file;
|
||||
|
@ -714,8 +714,8 @@ private:
|
|||
|
||||
glm::mat4 getModelTransform(const GLTFNode& node);
|
||||
|
||||
bool buildGeometry(HFMGeometry& geometry, const QUrl& url);
|
||||
bool parseGLTF(const QByteArray& model);
|
||||
bool buildGeometry(HFMModel& hfmModel, const QUrl& url);
|
||||
bool parseGLTF(const QByteArray& data);
|
||||
|
||||
bool getStringVal(const QJsonObject& object, const QString& fieldname,
|
||||
QString& value, QMap<QString, bool>& defined);
|
||||
|
@ -780,7 +780,7 @@ private:
|
|||
|
||||
void setHFMMaterial(HFMMaterial& fbxmat, const GLTFMaterial& material);
|
||||
HFMTexture getHFMTexture(const GLTFTexture& texture);
|
||||
void hfmDebugDump(const HFMGeometry& hfmgeo);
|
||||
void hfmDebugDump(const HFMModel& hfmModel);
|
||||
};
|
||||
|
||||
#endif // hifi_GLTFReader_h
|
|
@ -488,10 +488,10 @@ QNetworkReply* request(QUrl& url, bool isTest) {
|
|||
}
|
||||
|
||||
|
||||
bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, HFMGeometry& geometry,
|
||||
bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, HFMModel& hfmModel,
|
||||
float& scaleGuess, bool combineParts) {
|
||||
FaceGroup faces;
|
||||
HFMMesh& mesh = geometry.meshes[0];
|
||||
HFMMesh& mesh = hfmModel.meshes[0];
|
||||
mesh.parts.append(HFMMeshPart());
|
||||
HFMMeshPart& meshPart = mesh.parts.last();
|
||||
bool sawG = false;
|
||||
|
@ -652,41 +652,41 @@ done:
|
|||
}
|
||||
|
||||
|
||||
HFMGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, bool combineParts, const QUrl& url) {
|
||||
HFMModel::Pointer OBJReader::readOBJ(QByteArray& data, const QVariantHash& mapping, bool combineParts, const QUrl& url) {
|
||||
PROFILE_RANGE_EX(resource_parse, __FUNCTION__, 0xffff0000, nullptr);
|
||||
QBuffer buffer { &model };
|
||||
QBuffer buffer { &data };
|
||||
buffer.open(QIODevice::ReadOnly);
|
||||
|
||||
auto geometryPtr { std::make_shared<HFMGeometry>() };
|
||||
HFMGeometry& geometry { *geometryPtr };
|
||||
auto hfmModelPtr { std::make_shared<HFMModel>() };
|
||||
HFMModel& hfmModel { *hfmModelPtr };
|
||||
OBJTokenizer tokenizer { &buffer };
|
||||
float scaleGuess = 1.0f;
|
||||
|
||||
bool needsMaterialLibrary = false;
|
||||
|
||||
_url = url;
|
||||
geometry.meshExtents.reset();
|
||||
geometry.meshes.append(HFMMesh());
|
||||
hfmModel.meshExtents.reset();
|
||||
hfmModel.meshes.append(HFMMesh());
|
||||
|
||||
try {
|
||||
// call parseOBJGroup as long as it's returning true. Each successful call will
|
||||
// add a new meshPart to the geometry's single mesh.
|
||||
while (parseOBJGroup(tokenizer, mapping, geometry, scaleGuess, combineParts)) {}
|
||||
// add a new meshPart to the model's single mesh.
|
||||
while (parseOBJGroup(tokenizer, mapping, hfmModel, scaleGuess, combineParts)) {}
|
||||
|
||||
HFMMesh& mesh = geometry.meshes[0];
|
||||
HFMMesh& mesh = hfmModel.meshes[0];
|
||||
mesh.meshIndex = 0;
|
||||
|
||||
geometry.joints.resize(1);
|
||||
geometry.joints[0].isFree = false;
|
||||
geometry.joints[0].parentIndex = -1;
|
||||
geometry.joints[0].distanceToParent = 0;
|
||||
geometry.joints[0].translation = glm::vec3(0, 0, 0);
|
||||
geometry.joints[0].rotationMin = glm::vec3(0, 0, 0);
|
||||
geometry.joints[0].rotationMax = glm::vec3(0, 0, 0);
|
||||
geometry.joints[0].name = "OBJ";
|
||||
geometry.joints[0].isSkeletonJoint = true;
|
||||
hfmModel.joints.resize(1);
|
||||
hfmModel.joints[0].isFree = false;
|
||||
hfmModel.joints[0].parentIndex = -1;
|
||||
hfmModel.joints[0].distanceToParent = 0;
|
||||
hfmModel.joints[0].translation = glm::vec3(0, 0, 0);
|
||||
hfmModel.joints[0].rotationMin = glm::vec3(0, 0, 0);
|
||||
hfmModel.joints[0].rotationMax = glm::vec3(0, 0, 0);
|
||||
hfmModel.joints[0].name = "OBJ";
|
||||
hfmModel.joints[0].isSkeletonJoint = true;
|
||||
|
||||
geometry.jointIndices["x"] = 1;
|
||||
hfmModel.jointIndices["x"] = 1;
|
||||
|
||||
HFMCluster cluster;
|
||||
cluster.jointIndex = 0;
|
||||
|
@ -818,13 +818,13 @@ HFMGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& m
|
|||
mesh.meshExtents.reset();
|
||||
foreach(const glm::vec3& vertex, mesh.vertices) {
|
||||
mesh.meshExtents.addPoint(vertex);
|
||||
geometry.meshExtents.addPoint(vertex);
|
||||
hfmModel.meshExtents.addPoint(vertex);
|
||||
}
|
||||
|
||||
// Build the single mesh.
|
||||
FBXReader::buildModelMesh(mesh, url.toString());
|
||||
|
||||
// hfmDebugDump(geometry);
|
||||
// hfmDebugDump(hfmModel);
|
||||
} catch(const std::exception& e) {
|
||||
qCDebug(modelformat) << "OBJ reader fail: " << e.what();
|
||||
}
|
||||
|
@ -885,12 +885,12 @@ HFMGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& m
|
|||
if (!objMaterial.used) {
|
||||
continue;
|
||||
}
|
||||
geometry.materials[materialID] = HFMMaterial(objMaterial.diffuseColor,
|
||||
hfmModel.materials[materialID] = HFMMaterial(objMaterial.diffuseColor,
|
||||
objMaterial.specularColor,
|
||||
objMaterial.emissiveColor,
|
||||
objMaterial.shininess,
|
||||
objMaterial.opacity);
|
||||
HFMMaterial& hfmMaterial = geometry.materials[materialID];
|
||||
HFMMaterial& hfmMaterial = hfmModel.materials[materialID];
|
||||
hfmMaterial.materialID = materialID;
|
||||
hfmMaterial._material = std::make_shared<graphics::Material>();
|
||||
graphics::MaterialPointer modelMaterial = hfmMaterial._material;
|
||||
|
@ -988,15 +988,15 @@ HFMGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& m
|
|||
modelMaterial->setOpacity(hfmMaterial.opacity);
|
||||
}
|
||||
|
||||
return geometryPtr;
|
||||
return hfmModelPtr;
|
||||
}
|
||||
|
||||
void hfmDebugDump(const HFMGeometry& hfmgeo) {
|
||||
qCDebug(modelformat) << "---------------- hfmGeometry ----------------";
|
||||
qCDebug(modelformat) << " hasSkeletonJoints =" << hfmgeo.hasSkeletonJoints;
|
||||
qCDebug(modelformat) << " offset =" << hfmgeo.offset;
|
||||
qCDebug(modelformat) << " meshes.count() =" << hfmgeo.meshes.count();
|
||||
foreach (HFMMesh mesh, hfmgeo.meshes) {
|
||||
void hfmDebugDump(const HFMModel& hfmModel) {
|
||||
qCDebug(modelformat) << "---------------- hfmModel ----------------";
|
||||
qCDebug(modelformat) << " hasSkeletonJoints =" << hfmModel.hasSkeletonJoints;
|
||||
qCDebug(modelformat) << " offset =" << hfmModel.offset;
|
||||
qCDebug(modelformat) << " meshes.count() =" << hfmModel.meshes.count();
|
||||
foreach (HFMMesh mesh, hfmModel.meshes) {
|
||||
qCDebug(modelformat) << " vertices.count() =" << mesh.vertices.count();
|
||||
qCDebug(modelformat) << " colors.count() =" << mesh.colors.count();
|
||||
qCDebug(modelformat) << " normals.count() =" << mesh.normals.count();
|
||||
|
@ -1037,10 +1037,10 @@ void hfmDebugDump(const HFMGeometry& hfmgeo) {
|
|||
}
|
||||
}
|
||||
|
||||
qCDebug(modelformat) << " jointIndices =" << hfmgeo.jointIndices;
|
||||
qCDebug(modelformat) << " joints.count() =" << hfmgeo.joints.count();
|
||||
qCDebug(modelformat) << " jointIndices =" << hfmModel.jointIndices;
|
||||
qCDebug(modelformat) << " joints.count() =" << hfmModel.joints.count();
|
||||
|
||||
foreach (HFMJoint joint, hfmgeo.joints) {
|
||||
foreach (HFMJoint joint, hfmModel.joints) {
|
||||
qCDebug(modelformat) << " isFree =" << joint.isFree;
|
||||
qCDebug(modelformat) << " freeLineage" << joint.freeLineage;
|
||||
qCDebug(modelformat) << " parentIndex" << joint.parentIndex;
|
||||
|
|
|
@ -87,13 +87,13 @@ public:
|
|||
QString currentMaterialName;
|
||||
QHash<QString, OBJMaterial> materials;
|
||||
|
||||
HFMGeometry::Pointer readOBJ(QByteArray& model, const QVariantHash& mapping, bool combineParts, const QUrl& url = QUrl());
|
||||
HFMModel::Pointer readOBJ(QByteArray& data, const QVariantHash& mapping, bool combineParts, const QUrl& url = QUrl());
|
||||
|
||||
private:
|
||||
QUrl _url;
|
||||
|
||||
QHash<QByteArray, bool> librariesSeen;
|
||||
bool parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, HFMGeometry& geometry,
|
||||
bool parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, HFMModel& hfmModel,
|
||||
float& scaleGuess, bool combineParts);
|
||||
void parseMaterialLibrary(QIODevice* device);
|
||||
void parseTextureLine(const QByteArray& textureLine, QByteArray& filename, OBJMaterialTextureOptions& textureOptions);
|
||||
|
@ -104,4 +104,4 @@ private:
|
|||
|
||||
// What are these utilities doing here? One is used by fbx loading code in VHACD Utils, and the other a general debugging utility.
|
||||
void setMeshPartDefaults(HFMMeshPart& meshPart, QString materialID);
|
||||
void hfmDebugDump(const HFMGeometry& hfmgeo);
|
||||
void hfmDebugDump(const HFMModel& hfmModel);
|
||||
|
|
|
@ -128,7 +128,7 @@ void GeometryMappingResource::downloadFinished(const QByteArray& data) {
|
|||
|
||||
void GeometryMappingResource::onGeometryMappingLoaded(bool success) {
|
||||
if (success && _geometryResource) {
|
||||
_hfmGeometry = _geometryResource->_hfmGeometry;
|
||||
_hfmModel = _geometryResource->_hfmModel;
|
||||
_meshParts = _geometryResource->_meshParts;
|
||||
_meshes = _geometryResource->_meshes;
|
||||
_materials = _geometryResource->_materials;
|
||||
|
@ -193,38 +193,38 @@ void GeometryReader::run() {
|
|||
_url.path().toLower().endsWith(".obj.gz") ||
|
||||
_url.path().toLower().endsWith(".gltf"))) {
|
||||
|
||||
HFMGeometry::Pointer hfmGeometry;
|
||||
HFMModel::Pointer hfmModel;
|
||||
|
||||
if (_url.path().toLower().endsWith(".fbx")) {
|
||||
hfmGeometry.reset(readFBX(_data, _mapping, _url.path()));
|
||||
if (hfmGeometry->meshes.size() == 0 && hfmGeometry->joints.size() == 0) {
|
||||
hfmModel.reset(readFBX(_data, _mapping, _url.path()));
|
||||
if (hfmModel->meshes.size() == 0 && hfmModel->joints.size() == 0) {
|
||||
throw QString("empty geometry, possibly due to an unsupported FBX version");
|
||||
}
|
||||
} else if (_url.path().toLower().endsWith(".obj")) {
|
||||
hfmGeometry = OBJReader().readOBJ(_data, _mapping, _combineParts, _url);
|
||||
hfmModel = OBJReader().readOBJ(_data, _mapping, _combineParts, _url);
|
||||
} else if (_url.path().toLower().endsWith(".obj.gz")) {
|
||||
QByteArray uncompressedData;
|
||||
if (gunzip(_data, uncompressedData)){
|
||||
hfmGeometry = OBJReader().readOBJ(uncompressedData, _mapping, _combineParts, _url);
|
||||
hfmModel = OBJReader().readOBJ(uncompressedData, _mapping, _combineParts, _url);
|
||||
} else {
|
||||
throw QString("failed to decompress .obj.gz");
|
||||
}
|
||||
|
||||
} else if (_url.path().toLower().endsWith(".gltf")) {
|
||||
std::shared_ptr<GLTFReader> glreader = std::make_shared<GLTFReader>();
|
||||
hfmGeometry.reset(glreader->readGLTF(_data, _mapping, _url));
|
||||
if (hfmGeometry->meshes.size() == 0 && hfmGeometry->joints.size() == 0) {
|
||||
hfmModel.reset(glreader->readGLTF(_data, _mapping, _url));
|
||||
if (hfmModel->meshes.size() == 0 && hfmModel->joints.size() == 0) {
|
||||
throw QString("empty geometry, possibly due to an unsupported GLTF version");
|
||||
}
|
||||
} else {
|
||||
throw QString("unsupported format");
|
||||
}
|
||||
|
||||
// Add scripts to hfmGeometry
|
||||
// Add scripts to hfmModel
|
||||
if (!_mapping.value(SCRIPT_FIELD).isNull()) {
|
||||
QVariantList scripts = _mapping.values(SCRIPT_FIELD);
|
||||
for (auto &script : scripts) {
|
||||
hfmGeometry->scripts.push_back(script.toString());
|
||||
hfmModel->scripts.push_back(script.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -234,7 +234,7 @@ void GeometryReader::run() {
|
|||
qCWarning(modelnetworking) << "Abandoning load of" << _url << "; could not get strong ref";
|
||||
} else {
|
||||
QMetaObject::invokeMethod(resource.data(), "setGeometryDefinition",
|
||||
Q_ARG(HFMGeometry::Pointer, hfmGeometry));
|
||||
Q_ARG(HFMModel::Pointer, hfmModel));
|
||||
}
|
||||
} else {
|
||||
throw QString("url is invalid");
|
||||
|
@ -262,7 +262,7 @@ public:
|
|||
virtual void downloadFinished(const QByteArray& data) override;
|
||||
|
||||
protected:
|
||||
Q_INVOKABLE void setGeometryDefinition(HFMGeometry::Pointer hfmGeometry);
|
||||
Q_INVOKABLE void setGeometryDefinition(HFMModel::Pointer hfmModel);
|
||||
|
||||
private:
|
||||
QVariantHash _mapping;
|
||||
|
@ -277,13 +277,13 @@ void GeometryDefinitionResource::downloadFinished(const QByteArray& data) {
|
|||
QThreadPool::globalInstance()->start(new GeometryReader(_self, _effectiveBaseURL, _mapping, data, _combineParts));
|
||||
}
|
||||
|
||||
void GeometryDefinitionResource::setGeometryDefinition(HFMGeometry::Pointer hfmGeometry) {
|
||||
// Assume ownership of the geometry pointer
|
||||
_hfmGeometry = hfmGeometry;
|
||||
void GeometryDefinitionResource::setGeometryDefinition(HFMModel::Pointer hfmModel) {
|
||||
// Assume ownership of the HFMModel pointer
|
||||
_hfmModel = hfmModel;
|
||||
|
||||
// Copy materials
|
||||
QHash<QString, size_t> materialIDAtlas;
|
||||
for (const HFMMaterial& material : _hfmGeometry->materials) {
|
||||
for (const HFMMaterial& material : _hfmModel->materials) {
|
||||
materialIDAtlas[material.materialID] = _materials.size();
|
||||
_materials.push_back(std::make_shared<NetworkMaterial>(material, _textureBaseUrl));
|
||||
}
|
||||
|
@ -291,7 +291,7 @@ void GeometryDefinitionResource::setGeometryDefinition(HFMGeometry::Pointer hfmG
|
|||
std::shared_ptr<GeometryMeshes> meshes = std::make_shared<GeometryMeshes>();
|
||||
std::shared_ptr<GeometryMeshParts> parts = std::make_shared<GeometryMeshParts>();
|
||||
int meshID = 0;
|
||||
for (const HFMMesh& mesh : _hfmGeometry->meshes) {
|
||||
for (const HFMMesh& mesh : _hfmModel->meshes) {
|
||||
// Copy mesh pointers
|
||||
meshes->emplace_back(mesh._mesh);
|
||||
int partID = 0;
|
||||
|
@ -371,7 +371,7 @@ const QVariantMap Geometry::getTextures() const {
|
|||
|
||||
// FIXME: The materials should only be copied when modified, but the Model currently caches the original
|
||||
Geometry::Geometry(const Geometry& geometry) {
|
||||
_hfmGeometry = geometry._hfmGeometry;
|
||||
_hfmModel = geometry._hfmModel;
|
||||
_meshes = geometry._meshes;
|
||||
_meshParts = geometry._meshParts;
|
||||
|
||||
|
@ -444,8 +444,8 @@ void GeometryResource::deleter() {
|
|||
}
|
||||
|
||||
void GeometryResource::setTextures() {
|
||||
if (_hfmGeometry) {
|
||||
for (const HFMMaterial& material : _hfmGeometry->materials) {
|
||||
if (_hfmModel) {
|
||||
for (const HFMMaterial& material : _hfmModel->materials) {
|
||||
_materials.push_back(std::make_shared<NetworkMaterial>(material, _textureBaseUrl));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,9 +45,9 @@ public:
|
|||
// Mutable, but must retain structure of vector
|
||||
using NetworkMaterials = std::vector<std::shared_ptr<NetworkMaterial>>;
|
||||
|
||||
bool isGeometryLoaded() const { return (bool)_hfmGeometry; }
|
||||
bool isHFMModelLoaded() const { return (bool)_hfmModel; }
|
||||
|
||||
const HFMGeometry& getHFMGeometry() const { return *_hfmGeometry; }
|
||||
const HFMModel& getHFMModel() const { return *_hfmModel; }
|
||||
const GeometryMeshes& getMeshes() const { return *_meshes; }
|
||||
const std::shared_ptr<NetworkMaterial> getShapeMaterial(int shapeID) const;
|
||||
|
||||
|
@ -62,7 +62,7 @@ protected:
|
|||
friend class GeometryMappingResource;
|
||||
|
||||
// Shared across all geometries, constant throughout lifetime
|
||||
std::shared_ptr<const HFMGeometry> _hfmGeometry;
|
||||
std::shared_ptr<const HFMModel> _hfmModel;
|
||||
std::shared_ptr<const GeometryMeshes> _meshes;
|
||||
std::shared_ptr<const GeometryMeshParts> _meshParts;
|
||||
|
||||
|
@ -94,7 +94,7 @@ protected:
|
|||
|
||||
// Geometries may not hold onto textures while cached - that is for the texture cache
|
||||
// Instead, these methods clear and reset textures from the geometry when caching/loading
|
||||
bool shouldSetTextures() const { return _hfmGeometry && _materials.empty(); }
|
||||
bool shouldSetTextures() const { return _hfmModel && _materials.empty(); }
|
||||
void setTextures();
|
||||
void resetTextures();
|
||||
|
||||
|
|
|
@ -837,3 +837,7 @@ void AccountManager::handleKeypairGenerationError() {
|
|||
// reset our waiting state for keypair response
|
||||
_isWaitingForKeypairResponse = false;
|
||||
}
|
||||
|
||||
void AccountManager::setLimitedCommerce(bool isLimited) {
|
||||
_limitedCommerce = isLimited;
|
||||
}
|
||||
|
|
|
@ -98,6 +98,9 @@ public:
|
|||
|
||||
void removeAccountFromFile();
|
||||
|
||||
bool getLimitedCommerce() { return _limitedCommerce; }
|
||||
void setLimitedCommerce(bool isLimited);
|
||||
|
||||
public slots:
|
||||
void requestAccessToken(const QString& login, const QString& password);
|
||||
void requestAccessTokenWithSteam(QByteArray authSessionTicket);
|
||||
|
@ -121,6 +124,7 @@ signals:
|
|||
void loginFailed();
|
||||
void logoutComplete();
|
||||
void newKeypair();
|
||||
void limitedCommerceChanged();
|
||||
|
||||
private slots:
|
||||
void handleKeypairGenerationError();
|
||||
|
@ -150,6 +154,8 @@ private:
|
|||
QByteArray _pendingPrivateKey;
|
||||
|
||||
QUuid _sessionID { QUuid::createUuid() };
|
||||
|
||||
bool _limitedCommerce { false };
|
||||
};
|
||||
|
||||
#endif // hifi_AccountManager_h
|
||||
|
|
|
@ -32,8 +32,8 @@ bool CauterizedModel::updateGeometry() {
|
|||
bool needsFullUpdate = Model::updateGeometry();
|
||||
if (_isCauterized && needsFullUpdate) {
|
||||
assert(_cauterizeMeshStates.empty());
|
||||
const HFMGeometry& hfmGeometry = getHFMGeometry();
|
||||
foreach (const HFMMesh& mesh, hfmGeometry.meshes) {
|
||||
const HFMModel& hfmModel = getHFMModel();
|
||||
foreach (const HFMMesh& mesh, hfmModel.meshes) {
|
||||
Model::MeshState state;
|
||||
if (_useDualQuaternionSkinning) {
|
||||
state.clusterDualQuaternions.resize(mesh.clusters.size());
|
||||
|
@ -76,7 +76,7 @@ void CauterizedModel::createRenderItemSet() {
|
|||
// Run through all of the meshes, and place them into their segregated, but unsorted buckets
|
||||
int shapeID = 0;
|
||||
uint32_t numMeshes = (uint32_t)meshes.size();
|
||||
const HFMGeometry& hfmGeometry = getHFMGeometry();
|
||||
const HFMModel& hfmModel = getHFMModel();
|
||||
for (uint32_t i = 0; i < numMeshes; i++) {
|
||||
const auto& mesh = meshes.at(i);
|
||||
if (!mesh) {
|
||||
|
@ -86,7 +86,7 @@ void CauterizedModel::createRenderItemSet() {
|
|||
// Create the render payloads
|
||||
int numParts = (int)mesh->getNumParts();
|
||||
for (int partIndex = 0; partIndex < numParts; partIndex++) {
|
||||
initializeBlendshapes(hfmGeometry.meshes[i], i);
|
||||
initializeBlendshapes(hfmModel.meshes[i], i);
|
||||
|
||||
auto ptr = std::make_shared<CauterizedMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset);
|
||||
_modelMeshRenderItems << std::static_pointer_cast<ModelMeshPartPayload>(ptr);
|
||||
|
@ -109,11 +109,11 @@ void CauterizedModel::updateClusterMatrices() {
|
|||
return;
|
||||
}
|
||||
_needsUpdateClusterMatrices = false;
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
const HFMModel& hfmModel = getHFMModel();
|
||||
|
||||
for (int i = 0; i < (int)_meshStates.size(); i++) {
|
||||
Model::MeshState& state = _meshStates[i];
|
||||
const HFMMesh& mesh = geometry.meshes.at(i);
|
||||
const HFMMesh& mesh = hfmModel.meshes.at(i);
|
||||
for (int j = 0; j < mesh.clusters.size(); j++) {
|
||||
const HFMCluster& cluster = mesh.clusters.at(j);
|
||||
if (_useDualQuaternionSkinning) {
|
||||
|
@ -133,7 +133,7 @@ void CauterizedModel::updateClusterMatrices() {
|
|||
// as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty.
|
||||
if (!_cauterizeBoneSet.empty()) {
|
||||
|
||||
AnimPose cauterizePose = _rig.getJointPose(geometry.neckJointIndex);
|
||||
AnimPose cauterizePose = _rig.getJointPose(hfmModel.neckJointIndex);
|
||||
cauterizePose.scale() = glm::vec3(0.0001f, 0.0001f, 0.0001f);
|
||||
|
||||
static const glm::mat4 zeroScale(
|
||||
|
@ -141,11 +141,11 @@ void CauterizedModel::updateClusterMatrices() {
|
|||
glm::vec4(0.0f, 0.0001f, 0.0f, 0.0f),
|
||||
glm::vec4(0.0f, 0.0f, 0.0001f, 0.0f),
|
||||
glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
auto cauterizeMatrix = _rig.getJointTransform(geometry.neckJointIndex) * zeroScale;
|
||||
auto cauterizeMatrix = _rig.getJointTransform(hfmModel.neckJointIndex) * zeroScale;
|
||||
|
||||
for (int i = 0; i < _cauterizeMeshStates.size(); i++) {
|
||||
Model::MeshState& state = _cauterizeMeshStates[i];
|
||||
const HFMMesh& mesh = geometry.meshes.at(i);
|
||||
const HFMMesh& mesh = hfmModel.meshes.at(i);
|
||||
|
||||
for (int j = 0; j < mesh.clusters.size(); j++) {
|
||||
const HFMCluster& cluster = mesh.clusters.at(j);
|
||||
|
@ -175,7 +175,7 @@ void CauterizedModel::updateClusterMatrices() {
|
|||
|
||||
// post the blender if we're not currently waiting for one to finish
|
||||
auto modelBlender = DependencyManager::get<ModelBlender>();
|
||||
if (_blendshapeOffsetsInitialized && modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) {
|
||||
if (_blendshapeOffsetsInitialized && modelBlender->shouldComputeBlendshapes() && hfmModel.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) {
|
||||
_blendedBlendshapeCoefficients = _blendshapeCoefficients;
|
||||
modelBlender->noteRequiresBlend(getThisPointer());
|
||||
}
|
||||
|
|
|
@ -260,8 +260,8 @@ void ModelMeshPartPayload::initCache(const ModelPointer& model) {
|
|||
_hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR);
|
||||
_isSkinned = vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT) && vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_INDEX);
|
||||
|
||||
const HFMGeometry& geometry = model->getHFMGeometry();
|
||||
const HFMMesh& mesh = geometry.meshes.at(_meshIndex);
|
||||
const HFMModel& hfmModel = model->getHFMModel();
|
||||
const HFMMesh& mesh = hfmModel.meshes.at(_meshIndex);
|
||||
|
||||
_isBlendShaped = !mesh.blendshapes.isEmpty();
|
||||
_hasTangents = !mesh.tangents.isEmpty();
|
||||
|
|
|
@ -183,11 +183,11 @@ bool Model::shouldInvalidatePayloadShapeKey(int meshIndex) {
|
|||
return true;
|
||||
}
|
||||
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
const HFMModel& hfmModel = getHFMModel();
|
||||
const auto& networkMeshes = getGeometry()->getMeshes();
|
||||
// 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.
|
||||
if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)geometry.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
|
||||
invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid
|
||||
return true;
|
||||
|
@ -278,8 +278,8 @@ void Model::setRenderItemsNeedUpdate() {
|
|||
|
||||
void Model::reset() {
|
||||
if (isLoaded()) {
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
_rig.reset(geometry);
|
||||
const HFMModel& hfmModel = getHFMModel();
|
||||
_rig.reset(hfmModel);
|
||||
emit rigReset();
|
||||
emit rigReady();
|
||||
}
|
||||
|
@ -295,13 +295,13 @@ bool Model::updateGeometry() {
|
|||
_needsReload = false;
|
||||
|
||||
// TODO: should all Models have a valid _rig?
|
||||
if (_rig.jointStatesEmpty() && getHFMGeometry().joints.size() > 0) {
|
||||
if (_rig.jointStatesEmpty() && getHFMModel().joints.size() > 0) {
|
||||
initJointStates();
|
||||
assert(_meshStates.empty());
|
||||
|
||||
const HFMGeometry& hfmGeometry = getHFMGeometry();
|
||||
const HFMModel& hfmModel = getHFMModel();
|
||||
int i = 0;
|
||||
foreach (const HFMMesh& mesh, hfmGeometry.meshes) {
|
||||
foreach (const HFMMesh& mesh, hfmModel.meshes) {
|
||||
MeshState state;
|
||||
state.clusterDualQuaternions.resize(mesh.clusters.size());
|
||||
state.clusterMatrices.resize(mesh.clusters.size());
|
||||
|
@ -319,10 +319,10 @@ bool Model::updateGeometry() {
|
|||
|
||||
// virtual
|
||||
void Model::initJointStates() {
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
const HFMModel& hfmModel = getHFMModel();
|
||||
glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset);
|
||||
|
||||
_rig.initJointStates(geometry, modelOffset);
|
||||
_rig.initJointStates(hfmModel, modelOffset);
|
||||
}
|
||||
|
||||
bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
|
@ -363,9 +363,9 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
|
|||
int bestShapeID = 0;
|
||||
int bestSubMeshIndex = 0;
|
||||
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
const HFMModel& hfmModel = getHFMModel();
|
||||
if (!_triangleSetsValid) {
|
||||
calculateTriangleSets(geometry);
|
||||
calculateTriangleSets(hfmModel);
|
||||
}
|
||||
|
||||
glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset);
|
||||
|
@ -448,7 +448,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
|
|||
extraInfo["shapeID"] = bestShapeID;
|
||||
if (pickAgainstTriangles) {
|
||||
extraInfo["subMeshIndex"] = bestSubMeshIndex;
|
||||
extraInfo["subMeshName"] = geometry.getModelNameOfMesh(bestSubMeshIndex);
|
||||
extraInfo["subMeshName"] = hfmModel.getModelNameOfMesh(bestSubMeshIndex);
|
||||
extraInfo["subMeshTriangleWorld"] = QVariantMap{
|
||||
{ "v0", vec3toVariant(bestWorldTriangle.v0) },
|
||||
{ "v1", vec3toVariant(bestWorldTriangle.v1) },
|
||||
|
@ -506,9 +506,9 @@ bool Model::findParabolaIntersectionAgainstSubMeshes(const glm::vec3& origin, co
|
|||
int bestShapeID = 0;
|
||||
int bestSubMeshIndex = 0;
|
||||
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
const HFMModel& hfmModel = getHFMModel();
|
||||
if (!_triangleSetsValid) {
|
||||
calculateTriangleSets(geometry);
|
||||
calculateTriangleSets(hfmModel);
|
||||
}
|
||||
|
||||
glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset);
|
||||
|
@ -595,7 +595,7 @@ bool Model::findParabolaIntersectionAgainstSubMeshes(const glm::vec3& origin, co
|
|||
extraInfo["shapeID"] = bestShapeID;
|
||||
if (pickAgainstTriangles) {
|
||||
extraInfo["subMeshIndex"] = bestSubMeshIndex;
|
||||
extraInfo["subMeshName"] = geometry.getModelNameOfMesh(bestSubMeshIndex);
|
||||
extraInfo["subMeshName"] = hfmModel.getModelNameOfMesh(bestSubMeshIndex);
|
||||
extraInfo["subMeshTriangleWorld"] = QVariantMap{
|
||||
{ "v0", vec3toVariant(bestWorldTriangle.v0) },
|
||||
{ "v1", vec3toVariant(bestWorldTriangle.v1) },
|
||||
|
@ -641,7 +641,7 @@ bool Model::convexHullContains(glm::vec3 point) {
|
|||
QMutexLocker locker(&_mutex);
|
||||
|
||||
if (!_triangleSetsValid) {
|
||||
calculateTriangleSets(getHFMGeometry());
|
||||
calculateTriangleSets(getHFMModel());
|
||||
}
|
||||
|
||||
// If we are inside the models box, then consider the submeshes...
|
||||
|
@ -753,7 +753,7 @@ bool Model::replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointe
|
|||
}
|
||||
// update triangles for picking
|
||||
{
|
||||
HFMGeometry geometry;
|
||||
HFMModel hfmModel;
|
||||
for (const auto& newMesh : meshes) {
|
||||
HFMMesh mesh;
|
||||
mesh._mesh = newMesh.getMeshPointer();
|
||||
|
@ -767,15 +767,15 @@ bool Model::replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointe
|
|||
{
|
||||
foreach (const glm::vec3& vertex, mesh.vertices) {
|
||||
glm::vec3 transformedVertex = glm::vec3(mesh.modelTransform * glm::vec4(vertex, 1.0f));
|
||||
geometry.meshExtents.minimum = glm::min(geometry.meshExtents.minimum, transformedVertex);
|
||||
geometry.meshExtents.maximum = glm::max(geometry.meshExtents.maximum, transformedVertex);
|
||||
hfmModel.meshExtents.minimum = glm::min(hfmModel.meshExtents.minimum, transformedVertex);
|
||||
hfmModel.meshExtents.maximum = glm::max(hfmModel.meshExtents.maximum, transformedVertex);
|
||||
mesh.meshExtents.minimum = glm::min(mesh.meshExtents.minimum, transformedVertex);
|
||||
mesh.meshExtents.maximum = glm::max(mesh.meshExtents.maximum, transformedVertex);
|
||||
}
|
||||
}
|
||||
geometry.meshes << mesh;
|
||||
hfmModel.meshes << mesh;
|
||||
}
|
||||
calculateTriangleSets(geometry);
|
||||
calculateTriangleSets(hfmModel);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -789,11 +789,11 @@ scriptable::ScriptableModelBase Model::getScriptableModel() {
|
|||
return result;
|
||||
}
|
||||
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
int numberOfMeshes = geometry.meshes.size();
|
||||
const HFMModel& hfmModel = getHFMModel();
|
||||
int numberOfMeshes = hfmModel.meshes.size();
|
||||
int shapeID = 0;
|
||||
for (int i = 0; i < numberOfMeshes; i++) {
|
||||
const HFMMesh& hfmMesh = geometry.meshes.at(i);
|
||||
const HFMMesh& hfmMesh = hfmModel.meshes.at(i);
|
||||
if (auto mesh = hfmMesh._mesh) {
|
||||
result.append(mesh);
|
||||
|
||||
|
@ -808,17 +808,17 @@ scriptable::ScriptableModelBase Model::getScriptableModel() {
|
|||
return result;
|
||||
}
|
||||
|
||||
void Model::calculateTriangleSets(const HFMGeometry& geometry) {
|
||||
void Model::calculateTriangleSets(const HFMModel& hfmModel) {
|
||||
PROFILE_RANGE(render, __FUNCTION__);
|
||||
|
||||
int numberOfMeshes = geometry.meshes.size();
|
||||
int numberOfMeshes = hfmModel.meshes.size();
|
||||
|
||||
_triangleSetsValid = true;
|
||||
_modelSpaceMeshTriangleSets.clear();
|
||||
_modelSpaceMeshTriangleSets.resize(numberOfMeshes);
|
||||
|
||||
for (int i = 0; i < numberOfMeshes; i++) {
|
||||
const HFMMesh& mesh = geometry.meshes.at(i);
|
||||
const HFMMesh& mesh = hfmModel.meshes.at(i);
|
||||
|
||||
const int numberOfParts = mesh.parts.size();
|
||||
auto& meshTriangleSets = _modelSpaceMeshTriangleSets[i];
|
||||
|
@ -839,7 +839,7 @@ void Model::calculateTriangleSets(const HFMGeometry& geometry) {
|
|||
int totalTriangles = (numberOfQuads * TRIANGLES_PER_QUAD) + numberOfTris;
|
||||
partTriangleSet.reserve(totalTriangles);
|
||||
|
||||
auto meshTransform = geometry.offset * mesh.modelTransform;
|
||||
auto meshTransform = hfmModel.offset * mesh.modelTransform;
|
||||
|
||||
if (part.quadIndices.size() > 0) {
|
||||
int vIndex = 0;
|
||||
|
@ -1114,7 +1114,7 @@ Extents Model::getBindExtents() const {
|
|||
if (!isActive()) {
|
||||
return Extents();
|
||||
}
|
||||
const Extents& bindExtents = getHFMGeometry().bindExtents;
|
||||
const Extents& bindExtents = getHFMModel().bindExtents;
|
||||
Extents scaledExtents = { bindExtents.minimum * _scale, bindExtents.maximum * _scale };
|
||||
return scaledExtents;
|
||||
}
|
||||
|
@ -1128,12 +1128,12 @@ Extents Model::getMeshExtents() const {
|
|||
if (!isActive()) {
|
||||
return Extents();
|
||||
}
|
||||
const Extents& extents = getHFMGeometry().meshExtents;
|
||||
const Extents& extents = getHFMModel().meshExtents;
|
||||
|
||||
// even though our caller asked for "unscaled" we need to include any fst scaling, translation, and rotation, which
|
||||
// is captured in the offset matrix
|
||||
glm::vec3 minimum = glm::vec3(getHFMGeometry().offset * glm::vec4(extents.minimum, 1.0f));
|
||||
glm::vec3 maximum = glm::vec3(getHFMGeometry().offset * glm::vec4(extents.maximum, 1.0f));
|
||||
glm::vec3 minimum = glm::vec3(getHFMModel().offset * glm::vec4(extents.minimum, 1.0f));
|
||||
glm::vec3 maximum = glm::vec3(getHFMModel().offset * glm::vec4(extents.maximum, 1.0f));
|
||||
Extents scaledExtents = { minimum * _scale, maximum * _scale };
|
||||
return scaledExtents;
|
||||
}
|
||||
|
@ -1143,12 +1143,12 @@ Extents Model::getUnscaledMeshExtents() const {
|
|||
return Extents();
|
||||
}
|
||||
|
||||
const Extents& extents = getHFMGeometry().meshExtents;
|
||||
const Extents& extents = getHFMModel().meshExtents;
|
||||
|
||||
// even though our caller asked for "unscaled" we need to include any fst scaling, translation, and rotation, which
|
||||
// is captured in the offset matrix
|
||||
glm::vec3 minimum = glm::vec3(getHFMGeometry().offset * glm::vec4(extents.minimum, 1.0f));
|
||||
glm::vec3 maximum = glm::vec3(getHFMGeometry().offset * glm::vec4(extents.maximum, 1.0f));
|
||||
glm::vec3 minimum = glm::vec3(getHFMModel().offset * glm::vec4(extents.minimum, 1.0f));
|
||||
glm::vec3 maximum = glm::vec3(getHFMModel().offset * glm::vec4(extents.maximum, 1.0f));
|
||||
Extents scaledExtents = { minimum, maximum };
|
||||
|
||||
return scaledExtents;
|
||||
|
@ -1171,11 +1171,11 @@ void Model::setJointTranslation(int index, bool valid, const glm::vec3& translat
|
|||
}
|
||||
|
||||
int Model::getParentJointIndex(int jointIndex) const {
|
||||
return (isActive() && jointIndex != -1) ? getHFMGeometry().joints.at(jointIndex).parentIndex : -1;
|
||||
return (isActive() && jointIndex != -1) ? getHFMModel().joints.at(jointIndex).parentIndex : -1;
|
||||
}
|
||||
|
||||
int Model::getLastFreeJointIndex(int jointIndex) const {
|
||||
return (isActive() && jointIndex != -1) ? getHFMGeometry().joints.at(jointIndex).freeLineage.last() : -1;
|
||||
return (isActive() && jointIndex != -1) ? getHFMModel().joints.at(jointIndex).freeLineage.last() : -1;
|
||||
}
|
||||
|
||||
void Model::setTextures(const QVariantMap& textures) {
|
||||
|
@ -1275,7 +1275,7 @@ QStringList Model::getJointNames() const {
|
|||
Q_RETURN_ARG(QStringList, result));
|
||||
return result;
|
||||
}
|
||||
return isActive() ? getHFMGeometry().getJointNames() : QStringList();
|
||||
return isActive() ? getHFMModel().getJointNames() : QStringList();
|
||||
}
|
||||
|
||||
void Model::setScaleToFit(bool scaleToFit, const glm::vec3& dimensions, bool forceRescale) {
|
||||
|
@ -1415,10 +1415,10 @@ void Model::updateClusterMatrices() {
|
|||
}
|
||||
|
||||
_needsUpdateClusterMatrices = false;
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
const HFMModel& hfmModel = getHFMModel();
|
||||
for (int i = 0; i < (int) _meshStates.size(); i++) {
|
||||
MeshState& state = _meshStates[i];
|
||||
const HFMMesh& mesh = geometry.meshes.at(i);
|
||||
const HFMMesh& mesh = hfmModel.meshes.at(i);
|
||||
for (int j = 0; j < mesh.clusters.size(); j++) {
|
||||
const HFMCluster& cluster = mesh.clusters.at(j);
|
||||
if (_useDualQuaternionSkinning) {
|
||||
|
@ -1436,7 +1436,7 @@ void Model::updateClusterMatrices() {
|
|||
|
||||
// post the blender if we're not currently waiting for one to finish
|
||||
auto modelBlender = DependencyManager::get<ModelBlender>();
|
||||
if (_blendshapeOffsetsInitialized && modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) {
|
||||
if (_blendshapeOffsetsInitialized && modelBlender->shouldComputeBlendshapes() && hfmModel.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) {
|
||||
_blendedBlendshapeCoefficients = _blendshapeCoefficients;
|
||||
modelBlender->noteRequiresBlend(getThisPointer());
|
||||
}
|
||||
|
@ -1505,7 +1505,7 @@ void Model::createRenderItemSet() {
|
|||
// Run through all of the meshes, and place them into their segregated, but unsorted buckets
|
||||
int shapeID = 0;
|
||||
uint32_t numMeshes = (uint32_t)meshes.size();
|
||||
auto& hfmGeometry = getHFMGeometry();
|
||||
auto& hfmModel = getHFMModel();
|
||||
for (uint32_t i = 0; i < numMeshes; i++) {
|
||||
const auto& mesh = meshes.at(i);
|
||||
if (!mesh) {
|
||||
|
@ -1515,7 +1515,7 @@ void Model::createRenderItemSet() {
|
|||
// Create the render payloads
|
||||
int numParts = (int)mesh->getNumParts();
|
||||
for (int partIndex = 0; partIndex < numParts; partIndex++) {
|
||||
initializeBlendshapes(hfmGeometry.meshes[i], i);
|
||||
initializeBlendshapes(hfmModel.meshes[i], i);
|
||||
_modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset);
|
||||
auto material = getGeometry()->getShapeMaterial(shapeID);
|
||||
_modelMeshMaterialNames.push_back(material ? material->getName() : "");
|
||||
|
@ -1600,7 +1600,7 @@ void Model::removeMaterial(graphics::MaterialPointer material, const std::string
|
|||
class CollisionRenderGeometry : public Geometry {
|
||||
public:
|
||||
CollisionRenderGeometry(graphics::MeshPointer mesh) {
|
||||
_hfmGeometry = std::make_shared<HFMGeometry>();
|
||||
_hfmModel = std::make_shared<HFMModel>();
|
||||
std::shared_ptr<GeometryMeshes> meshes = std::make_shared<GeometryMeshes>();
|
||||
meshes->push_back(mesh);
|
||||
_meshes = meshes;
|
||||
|
@ -1656,7 +1656,7 @@ void Blender::run() {
|
|||
if (_model && _model->isLoaded()) {
|
||||
DETAILED_PROFILE_RANGE_EX(simulation_animation, __FUNCTION__, 0xFFFF0000, 0, { { "url", _model->getURL().toString() } });
|
||||
int offset = 0;
|
||||
auto meshes = _model->getHFMGeometry().meshes;
|
||||
auto meshes = _model->getHFMModel().meshes;
|
||||
int meshIndex = 0;
|
||||
foreach(const HFMMesh& mesh, meshes) {
|
||||
auto modelMeshBlendshapeOffsets = _model->_blendshapeOffsets.find(meshIndex++);
|
||||
|
|
|
@ -163,7 +163,7 @@ public:
|
|||
|
||||
bool maybeStartBlender();
|
||||
|
||||
bool isLoaded() const { return (bool)_renderGeometry && _renderGeometry->isGeometryLoaded(); }
|
||||
bool isLoaded() const { return (bool)_renderGeometry && _renderGeometry->isHFMModelLoaded(); }
|
||||
bool isAddedToScene() const { return _addedToScene; }
|
||||
|
||||
void setIsWireframe(bool isWireframe) { _isWireframe = isWireframe; }
|
||||
|
@ -184,8 +184,8 @@ public:
|
|||
Q_INVOKABLE virtual void setTextures(const QVariantMap& textures);
|
||||
|
||||
/// Provided as a convenience, will crash if !isLoaded()
|
||||
// And so that getGeometry() isn't chained everywhere
|
||||
const HFMGeometry& getHFMGeometry() const { assert(isLoaded()); return _renderGeometry->getHFMGeometry(); }
|
||||
// And so that getHFMModel() isn't chained everywhere
|
||||
const HFMModel& getHFMModel() const { assert(isLoaded()); return _renderGeometry->getHFMModel(); }
|
||||
|
||||
bool isActive() const { return isLoaded(); }
|
||||
|
||||
|
@ -450,7 +450,7 @@ protected:
|
|||
|
||||
bool _overrideModelTransform { false };
|
||||
bool _triangleSetsValid { false };
|
||||
void calculateTriangleSets(const HFMGeometry& geometry);
|
||||
void calculateTriangleSets(const HFMModel& hfmModel);
|
||||
std::vector<std::vector<TriangleSet>> _modelSpaceMeshTriangleSets; // model space triangles for all sub meshes
|
||||
|
||||
virtual void createRenderItemSet();
|
||||
|
|
|
@ -41,11 +41,11 @@ void SoftAttachmentModel::updateClusterMatrices() {
|
|||
|
||||
_needsUpdateClusterMatrices = false;
|
||||
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
const HFMModel& hfmModel = getHFMModel();
|
||||
|
||||
for (int i = 0; i < (int) _meshStates.size(); i++) {
|
||||
MeshState& state = _meshStates[i];
|
||||
const HFMMesh& mesh = geometry.meshes.at(i);
|
||||
const HFMMesh& mesh = hfmModel.meshes.at(i);
|
||||
|
||||
for (int j = 0; j < mesh.clusters.size(); j++) {
|
||||
const HFMCluster& cluster = mesh.clusters.at(j);
|
||||
|
@ -78,7 +78,7 @@ void SoftAttachmentModel::updateClusterMatrices() {
|
|||
|
||||
// post the blender if we're not currently waiting for one to finish
|
||||
auto modelBlender = DependencyManager::get<ModelBlender>();
|
||||
if (_blendshapeOffsetsInitialized && modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) {
|
||||
if (_blendshapeOffsetsInitialized && modelBlender->shouldComputeBlendshapes() && hfmModel.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) {
|
||||
_blendedBlendshapeCoefficients = _blendshapeCoefficients;
|
||||
modelBlender->noteRequiresBlend(getThisPointer());
|
||||
}
|
||||
|
|
|
@ -70,9 +70,9 @@ void RequestFilters::interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info,
|
|||
|
||||
// check if this is a request to a highfidelity URL
|
||||
bool isAuthable = isAuthableHighFidelityURL(info.requestUrl());
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
if (isAuthable) {
|
||||
// if we have an access token, add it to the right HTTP header for authorization
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
||||
if (accountManager->hasValidAccessToken()) {
|
||||
static const QString OAUTH_AUTHORIZATION_HEADER = "Authorization";
|
||||
|
@ -84,13 +84,9 @@ void RequestFilters::interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info,
|
|||
static const QString USER_AGENT = "User-Agent";
|
||||
const QString tokenStringMobile{ "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36" };
|
||||
const QString tokenStringMetaverse{ "Chrome/48.0 (HighFidelityInterface)" };
|
||||
const QString tokenStringLimitedCommerce{ "Chrome/48.0 (HighFidelityInterface limitedCommerce)" };
|
||||
|
||||
// During the period in which we have HFC commerce in the system, but not applied everywhere:
|
||||
const QString tokenStringCommerce{ "Chrome/48.0 (HighFidelityInterface WithHFC)" };
|
||||
Setting::Handle<bool> _settingSwitch{ "commerce", true };
|
||||
bool isMoney = _settingSwitch.get();
|
||||
|
||||
const QString tokenString = !isAuthable ? tokenStringMobile : (isMoney ? tokenStringCommerce : tokenStringMetaverse);
|
||||
const QString tokenString = !isAuthable ? tokenStringMobile : (accountManager->getLimitedCommerce() ? tokenStringLimitedCommerce : tokenStringMetaverse);
|
||||
info.setHttpHeader(USER_AGENT.toLocal8Bit(), tokenString.toLocal8Bit());
|
||||
}
|
||||
|
||||
|
|
|
@ -95,16 +95,16 @@ function AppUi(properties) {
|
|||
activeIcon: isWaiting ? that.activeMessagesButton : that.activeButton
|
||||
});
|
||||
};
|
||||
that.notificationPollTimeout = false;
|
||||
that.notificationPollTimeoutMs = 60000;
|
||||
that.notificationPollEndpoint = false;
|
||||
that.notificationPollStopPaginatingConditionMet = false;
|
||||
that.notificationPollTimeout = [false];
|
||||
that.notificationPollTimeoutMs = [60000];
|
||||
that.notificationPollEndpoint = [false];
|
||||
that.notificationPollStopPaginatingConditionMet = [false];
|
||||
that.notificationDataProcessPage = function (data) {
|
||||
return data;
|
||||
};
|
||||
that.notificationPollCallback = that.ignore;
|
||||
that.notificationPollCaresAboutSince = false;
|
||||
that.notificationInitialCallbackMade = false;
|
||||
that.notificationPollCallback = [that.ignore];
|
||||
that.notificationPollCaresAboutSince = [false];
|
||||
that.notificationInitialCallbackMade = [false];
|
||||
that.notificationDisplayBanner = function (message) {
|
||||
if (!that.isOpen) {
|
||||
Window.displayAnnouncement(message);
|
||||
|
@ -129,7 +129,9 @@ function AppUi(properties) {
|
|||
}
|
||||
that.isOpen = true;
|
||||
}
|
||||
} else { // Not us. Should we do something for type Home, Menu, and particularly Closed (meaning tablet hidden?
|
||||
} else {
|
||||
// A different screen is now visible, or the tablet has been closed.
|
||||
// Tablet visibility is controlled separately by `tabletShownChanged()`
|
||||
that.wireEventBridge(false);
|
||||
if (that.isOpen) {
|
||||
that.buttonActive(false);
|
||||
|
@ -139,83 +141,124 @@ function AppUi(properties) {
|
|||
that.isOpen = false;
|
||||
}
|
||||
}
|
||||
// console.debug(that.buttonName + " app reports: Tablet screen changed.\nNew screen type: " + type +
|
||||
// "\nNew screen URL: " + url + "\nCurrent app open status: " + that.isOpen + "\n");
|
||||
};
|
||||
|
||||
// Overwrite with the given properties:
|
||||
Object.keys(properties).forEach(function (key) { that[key] = properties[key]; });
|
||||
Object.keys(properties).forEach(function (key) {
|
||||
that[key] = properties[key];
|
||||
});
|
||||
|
||||
//
|
||||
// START Notification Handling
|
||||
//
|
||||
|
||||
var currentDataPageToRetrieve = [];
|
||||
var concatenatedServerResponse = [];
|
||||
for (var i = 0; i < that.notificationPollEndpoint.length; i++) {
|
||||
currentDataPageToRetrieve[i] = 1;
|
||||
concatenatedServerResponse[i] = new Array();
|
||||
}
|
||||
|
||||
var MAX_LOG_LENGTH_CHARACTERS = 300;
|
||||
function requestCallback(error, response, optionalParams) {
|
||||
var indexOfRequest = optionalParams.indexOfRequest;
|
||||
var urlOfRequest = optionalParams.urlOfRequest;
|
||||
|
||||
if (error || (response.status !== 'success')) {
|
||||
print("Error: unable to get", urlOfRequest, error || response.status);
|
||||
startNotificationTimer(indexOfRequest);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!that.notificationPollStopPaginatingConditionMet[indexOfRequest] ||
|
||||
that.notificationPollStopPaginatingConditionMet[indexOfRequest](response)) {
|
||||
startNotificationTimer(indexOfRequest);
|
||||
|
||||
var notificationData;
|
||||
if (concatenatedServerResponse[indexOfRequest].length) {
|
||||
notificationData = concatenatedServerResponse[indexOfRequest];
|
||||
} else {
|
||||
notificationData = that.notificationDataProcessPage[indexOfRequest](response);
|
||||
}
|
||||
console.debug(that.buttonName, that.notificationPollEndpoint[indexOfRequest],
|
||||
'truncated notification data for processing:',
|
||||
JSON.stringify(notificationData).substring(0, MAX_LOG_LENGTH_CHARACTERS));
|
||||
that.notificationPollCallback[indexOfRequest](notificationData);
|
||||
that.notificationInitialCallbackMade[indexOfRequest] = true;
|
||||
currentDataPageToRetrieve[indexOfRequest] = 1;
|
||||
concatenatedServerResponse[indexOfRequest] = new Array();
|
||||
} else {
|
||||
concatenatedServerResponse[indexOfRequest] =
|
||||
concatenatedServerResponse[indexOfRequest].concat(that.notificationDataProcessPage[indexOfRequest](response));
|
||||
currentDataPageToRetrieve[indexOfRequest]++;
|
||||
request({
|
||||
json: true,
|
||||
uri: (urlOfRequest + "&page=" + currentDataPageToRetrieve[indexOfRequest])
|
||||
}, requestCallback, optionalParams);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var METAVERSE_BASE = Account.metaverseServerURL;
|
||||
var currentDataPageToRetrieve = 1;
|
||||
var concatenatedServerResponse = new Array();
|
||||
that.notificationPoll = function () {
|
||||
if (!that.notificationPollEndpoint) {
|
||||
var MS_IN_SEC = 1000;
|
||||
that.notificationPoll = function (i) {
|
||||
if (!that.notificationPollEndpoint[i]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// User is "appearing offline" or is offline
|
||||
if (GlobalServices.findableBy === "none" || Account.username === "") {
|
||||
that.notificationPollTimeout = Script.setTimeout(that.notificationPoll, that.notificationPollTimeoutMs);
|
||||
// User is "appearing offline" or is not logged in
|
||||
if (GlobalServices.findableBy === "none" || Account.username === "Unknown user") {
|
||||
// The notification polling will restart when the user changes their availability
|
||||
// or when they log in, so it's not necessary to restart a timer here.
|
||||
console.debug(that.buttonName + " Notifications: User is appearing offline or not logged in. " +
|
||||
that.buttonName + " will poll for notifications when user logs in and has their availability " +
|
||||
"set to not appear offline.");
|
||||
return;
|
||||
}
|
||||
|
||||
var url = METAVERSE_BASE + that.notificationPollEndpoint;
|
||||
var url = METAVERSE_BASE + that.notificationPollEndpoint[i];
|
||||
|
||||
var settingsKey = "notifications/" + that.buttonName + "/lastPoll";
|
||||
var settingsKey = "notifications/" + that.notificationPollEndpoint[i] + "/lastPoll";
|
||||
var currentTimestamp = new Date().getTime();
|
||||
var lastPollTimestamp = Settings.getValue(settingsKey, currentTimestamp);
|
||||
if (that.notificationPollCaresAboutSince) {
|
||||
url = url + "&since=" + lastPollTimestamp/1000;
|
||||
if (that.notificationPollCaresAboutSince[i]) {
|
||||
url = url + "&since=" + lastPollTimestamp / MS_IN_SEC;
|
||||
}
|
||||
Settings.setValue(settingsKey, currentTimestamp);
|
||||
|
||||
console.debug(that.buttonName, 'polling for notifications at endpoint', url);
|
||||
|
||||
function requestCallback(error, response) {
|
||||
if (error || (response.status !== 'success')) {
|
||||
print("Error: unable to get", url, error || response.status);
|
||||
that.notificationPollTimeout = Script.setTimeout(that.notificationPoll, that.notificationPollTimeoutMs);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!that.notificationPollStopPaginatingConditionMet || that.notificationPollStopPaginatingConditionMet(response)) {
|
||||
that.notificationPollTimeout = Script.setTimeout(that.notificationPoll, that.notificationPollTimeoutMs);
|
||||
|
||||
var notificationData;
|
||||
if (concatenatedServerResponse.length) {
|
||||
notificationData = concatenatedServerResponse;
|
||||
} else {
|
||||
notificationData = that.notificationDataProcessPage(response);
|
||||
}
|
||||
console.debug(that.buttonName, 'notification data for processing:', JSON.stringify(notificationData));
|
||||
that.notificationPollCallback(notificationData);
|
||||
that.notificationInitialCallbackMade = true;
|
||||
currentDataPageToRetrieve = 1;
|
||||
concatenatedServerResponse = new Array();
|
||||
} else {
|
||||
concatenatedServerResponse = concatenatedServerResponse.concat(that.notificationDataProcessPage(response));
|
||||
currentDataPageToRetrieve++;
|
||||
request({ json: true, uri: (url + "&page=" + currentDataPageToRetrieve) }, requestCallback);
|
||||
}
|
||||
}
|
||||
|
||||
request({ json: true, uri: url }, requestCallback);
|
||||
request({
|
||||
json: true,
|
||||
uri: url
|
||||
},
|
||||
requestCallback,
|
||||
{
|
||||
indexOfRequest: i,
|
||||
urlOfRequest: url
|
||||
});
|
||||
};
|
||||
|
||||
// This won't do anything if there isn't a notification endpoint set
|
||||
that.notificationPoll();
|
||||
for (i = 0; i < that.notificationPollEndpoint.length; i++) {
|
||||
that.notificationPoll(i);
|
||||
}
|
||||
|
||||
function startNotificationTimer(indexOfRequest) {
|
||||
that.notificationPollTimeout[indexOfRequest] = Script.setTimeout(function () {
|
||||
that.notificationPoll(indexOfRequest);
|
||||
}, that.notificationPollTimeoutMs[indexOfRequest]);
|
||||
}
|
||||
|
||||
function restartNotificationPoll() {
|
||||
that.notificationInitialCallbackMade = false;
|
||||
if (that.notificationPollTimeout) {
|
||||
Script.clearTimeout(that.notificationPollTimeout);
|
||||
that.notificationPollTimeout = false;
|
||||
for (var j = 0; j < that.notificationPollEndpoint.length; j++) {
|
||||
that.notificationInitialCallbackMade[j] = false;
|
||||
if (that.notificationPollTimeout[j]) {
|
||||
Script.clearTimeout(that.notificationPollTimeout[j]);
|
||||
that.notificationPollTimeout[j] = false;
|
||||
}
|
||||
that.notificationPoll(j);
|
||||
}
|
||||
that.notificationPoll();
|
||||
}
|
||||
//
|
||||
// END Notification Handling
|
||||
|
@ -322,9 +365,11 @@ function AppUi(properties) {
|
|||
}
|
||||
that.tablet.removeButton(that.button);
|
||||
}
|
||||
if (that.notificationPollTimeout) {
|
||||
Script.clearInterval(that.notificationPollTimeout);
|
||||
that.notificationPollTimeout = false;
|
||||
for (var i = 0; i < that.notificationPollTimeout.length; i++) {
|
||||
if (that.notificationPollTimeout[i]) {
|
||||
Script.clearInterval(that.notificationPollTimeout[i]);
|
||||
that.notificationPollTimeout[i] = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
// Set up the handlers.
|
||||
|
@ -333,7 +378,7 @@ function AppUi(properties) {
|
|||
Script.scriptEnding.connect(that.onScriptEnding);
|
||||
GlobalServices.findableByChanged.connect(restartNotificationPoll);
|
||||
GlobalServices.myUsernameChanged.connect(restartNotificationPoll);
|
||||
if (that.buttonName == Settings.getValue("startUpApp")) {
|
||||
if (that.buttonName === Settings.getValue("startUpApp")) {
|
||||
Settings.setValue("startUpApp", "");
|
||||
Script.setTimeout(function () {
|
||||
that.open();
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
module.exports = {
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
request: function (options, callback) { // cb(error, responseOfCorrectContentType) of url. A subset of npm request.
|
||||
// cb(error, responseOfCorrectContentType, optionalCallbackParameter) of url. A subset of npm request.
|
||||
request: function (options, callback, optionalCallbackParameter) {
|
||||
var httpRequest = new XMLHttpRequest(), key;
|
||||
// QT bug: apparently doesn't handle onload. Workaround using readyState.
|
||||
httpRequest.onreadystatechange = function () {
|
||||
|
@ -38,7 +39,7 @@ module.exports = {
|
|||
if (error) {
|
||||
response = { statusCode: httpRequest.status };
|
||||
}
|
||||
callback(error, response);
|
||||
callback(error, response, optionalCallbackParameter);
|
||||
}
|
||||
};
|
||||
if (typeof options === 'string') {
|
||||
|
|
|
@ -159,7 +159,7 @@ var selectedAvatarEntityGrabbable = false;
|
|||
var selectedAvatarEntityID = null;
|
||||
var grabbedAvatarEntityChangeNotifier = null;
|
||||
|
||||
var MARKETPLACE_PURCHASES_QML_PATH = "hifi/commerce/purchases/Purchases.qml";
|
||||
var MARKETPLACE_PURCHASES_QML_PATH = "hifi/commerce/wallet/Wallet.qml";
|
||||
var MARKETPLACE_URL = Account.metaverseServerURL + "/marketplace";
|
||||
var MARKETPLACES_INJECT_SCRIPT_URL = Script.resolvePath("html/js/marketplacesInject.js");
|
||||
|
||||
|
@ -285,9 +285,9 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See
|
|||
case 'navigate':
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system")
|
||||
if(message.url.indexOf('app://') === 0) {
|
||||
if(message.url === 'app://marketplace') {
|
||||
if (message.url === 'app://marketplace') {
|
||||
tablet.gotoWebScreen(MARKETPLACE_URL, MARKETPLACES_INJECT_SCRIPT_URL);
|
||||
} else if(message.url === 'app://purchases') {
|
||||
} else if (message.url === 'app://purchases') {
|
||||
tablet.pushOntoStack(MARKETPLACE_PURCHASES_QML_PATH);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
/* global getConnectionData */
|
||||
/* global getConnectionData getControllerWorldLocation openLoginWindow WalletScriptingInterface */
|
||||
|
||||
(function () { // BEGIN LOCAL_SCOPE
|
||||
Script.include("/~/system/libraries/accountUtils.js");
|
||||
|
@ -20,7 +20,6 @@ var AppUi = Script.require('appUi');
|
|||
|
||||
var MARKETPLACE_URL = Account.metaverseServerURL + "/marketplace";
|
||||
|
||||
|
||||
// BEGIN AVATAR SELECTOR LOGIC
|
||||
var UNSELECTED_COLOR = { red: 0x1F, green: 0xC6, blue: 0xA6 };
|
||||
var SELECTED_COLOR = { red: 0xF3, green: 0x91, blue: 0x29 };
|
||||
|
@ -48,7 +47,6 @@ ExtendedOverlay.prototype.editOverlay = function (properties) { // change displa
|
|||
function color(selected, hovering) {
|
||||
var base = hovering ? HOVER_COLOR : selected ? SELECTED_COLOR : UNSELECTED_COLOR;
|
||||
function scale(component) {
|
||||
var delta = 0xFF - component;
|
||||
return component;
|
||||
}
|
||||
return { red: scale(base.red), green: scale(base.green), blue: scale(base.blue) };
|
||||
|
@ -105,7 +103,8 @@ ExtendedOverlay.unHover = function () { // calls hover(false) on lastHoveringId
|
|||
// hit(overlay) on the one overlay intersected by pickRay, if any.
|
||||
// noHit() if no ExtendedOverlay was intersected (helps with hover)
|
||||
ExtendedOverlay.applyPickRay = function (pickRay, hit, noHit) {
|
||||
var pickedOverlay = Overlays.findRayIntersection(pickRay); // Depends on nearer coverOverlays to extend closer to us than farther ones.
|
||||
// Depends on nearer coverOverlays to extend closer to us than farther ones.
|
||||
var pickedOverlay = Overlays.findRayIntersection(pickRay);
|
||||
if (!pickedOverlay.intersects) {
|
||||
if (noHit) {
|
||||
return noHit();
|
||||
|
@ -131,6 +130,7 @@ function addAvatarNode(id) {
|
|||
}
|
||||
|
||||
var pingPong = true;
|
||||
var OVERLAY_SCALE = 0.032;
|
||||
function updateOverlays() {
|
||||
var eye = Camera.position;
|
||||
AvatarList.getAvatarIdentifiers().forEach(function (id) {
|
||||
|
@ -148,7 +148,8 @@ function updateOverlays() {
|
|||
var target = avatar.position;
|
||||
var distance = Vec3.distance(target, eye);
|
||||
var offset = 0.2;
|
||||
var diff = Vec3.subtract(target, eye); // get diff between target and eye (a vector pointing to the eye from avatar position)
|
||||
// get diff between target and eye (a vector pointing to the eye from avatar position)
|
||||
var diff = Vec3.subtract(target, eye);
|
||||
var headIndex = avatar.getJointIndex("Head"); // base offset on 1/2 distance from hips to head if we can
|
||||
if (headIndex > 0) {
|
||||
offset = avatar.getAbsoluteJointTranslationInObjectFrame(headIndex).y / 2;
|
||||
|
@ -164,7 +165,7 @@ function updateOverlays() {
|
|||
overlay.editOverlay({
|
||||
color: color(ExtendedOverlay.isSelected(id), overlay.hovering),
|
||||
position: target,
|
||||
dimensions: 0.032 * distance
|
||||
dimensions: OVERLAY_SCALE * distance
|
||||
});
|
||||
});
|
||||
pingPong = !pingPong;
|
||||
|
@ -380,6 +381,31 @@ function onUsernameChanged() {
|
|||
Settings.setValue("keepMeLoggedIn", false);
|
||||
Settings.setValue("keepMeLoggedIn/savedUsername", "");
|
||||
}
|
||||
}
|
||||
|
||||
var MARKETPLACES_INJECT_SCRIPT_URL = Script.resolvePath("../html/js/marketplacesInject.js");
|
||||
var METAVERSE_SERVER_URL = Account.metaverseServerURL;
|
||||
var MARKETPLACE_URL_INITIAL = MARKETPLACE_URL + "?"; // Append "?" to signal injected script that it's the initial page.
|
||||
function openMarketplace(optionalItemOrUrl) {
|
||||
// This is a bit of a kluge, but so is the whole file.
|
||||
// If given a whole path, use it with no cta.
|
||||
// If given an id, build the appropriate url and use the id as the cta.
|
||||
// Otherwise, use home and 'marketplace cta'.
|
||||
// AND... if call onMarketplaceOpen to setupWallet if we need to.
|
||||
var url = optionalItemOrUrl || MARKETPLACE_URL_INITIAL;
|
||||
// If optionalItemOrUrl contains the metaverse base, then it's a url, not an item id.
|
||||
if (optionalItemOrUrl && optionalItemOrUrl.indexOf(METAVERSE_SERVER_URL) === -1) {
|
||||
url = MARKETPLACE_URL + '/items/' + optionalItemOrUrl;
|
||||
}
|
||||
ui.open(url, MARKETPLACES_INJECT_SCRIPT_URL);
|
||||
}
|
||||
|
||||
function setCertificateInfo(itemCertificateId) {
|
||||
ui.tablet.sendToQml({
|
||||
method: 'inspectionCertificate_setCertificateId',
|
||||
entityId: "",
|
||||
certificateId: itemCertificateId
|
||||
});
|
||||
}
|
||||
|
||||
// Function Name: fromQml()
|
||||
|
@ -387,8 +413,6 @@ function onUsernameChanged() {
|
|||
// Description:
|
||||
// -Called when a message is received from SpectatorCamera.qml. The "message" argument is what is sent from the QML
|
||||
// in the format "{method, params}", like json-rpc. See also sendToQml().
|
||||
var MARKETPLACE_PURCHASES_QML_PATH = "hifi/commerce/purchases/Purchases.qml";
|
||||
var MARKETPLACES_INJECT_SCRIPT_URL = Script.resolvePath("../html/js/marketplacesInject.js");
|
||||
function fromQml(message) {
|
||||
switch (message.method) {
|
||||
case 'passphrasePopup_cancelClicked':
|
||||
|
@ -413,6 +437,7 @@ function fromQml(message) {
|
|||
}
|
||||
break;
|
||||
case 'needsLogIn_loginClicked':
|
||||
ui.close();
|
||||
openLoginWindow();
|
||||
break;
|
||||
case 'disableHmdPreview':
|
||||
|
@ -422,10 +447,6 @@ function fromQml(message) {
|
|||
case 'transactionHistory_linkClicked':
|
||||
ui.open(message.marketplaceLink, MARKETPLACES_INJECT_SCRIPT_URL);
|
||||
break;
|
||||
case 'goToPurchases_fromWalletHome':
|
||||
case 'goToPurchases':
|
||||
ui.open(MARKETPLACE_PURCHASES_QML_PATH);
|
||||
break;
|
||||
case 'goToMarketplaceMainPage':
|
||||
ui.open(MARKETPLACE_URL, MARKETPLACES_INJECT_SCRIPT_URL);
|
||||
break;
|
||||
|
@ -450,22 +471,20 @@ function fromQml(message) {
|
|||
removeOverlays();
|
||||
break;
|
||||
case 'sendAsset_sendPublicly':
|
||||
if (message.assetName === "") {
|
||||
deleteSendMoneyParticleEffect();
|
||||
sendMoneyRecipient = message.recipient;
|
||||
var amount = message.amount;
|
||||
var props = SEND_MONEY_PARTICLE_PROPERTIES;
|
||||
props.parentID = MyAvatar.sessionUUID;
|
||||
props.position = MyAvatar.position;
|
||||
props.position.y += 0.2;
|
||||
if (message.effectImage) {
|
||||
props.textures = message.effectImage;
|
||||
}
|
||||
sendMoneyParticleEffect = Entities.addEntity(props, true);
|
||||
particleEffectTimestamp = Date.now();
|
||||
updateSendMoneyParticleEffect();
|
||||
sendMoneyParticleEffectUpdateTimer = Script.setInterval(updateSendMoneyParticleEffect, SEND_MONEY_PARTICLE_TIMER_UPDATE);
|
||||
deleteSendMoneyParticleEffect();
|
||||
sendMoneyRecipient = message.recipient;
|
||||
var props = SEND_MONEY_PARTICLE_PROPERTIES;
|
||||
props.parentID = MyAvatar.sessionUUID;
|
||||
props.position = MyAvatar.position;
|
||||
props.position.y += 0.2;
|
||||
if (message.effectImage) {
|
||||
props.textures = message.effectImage;
|
||||
}
|
||||
sendMoneyParticleEffect = Entities.addEntity(props, true);
|
||||
particleEffectTimestamp = Date.now();
|
||||
updateSendMoneyParticleEffect();
|
||||
sendMoneyParticleEffectUpdateTimer =
|
||||
Script.setInterval(updateSendMoneyParticleEffect, SEND_MONEY_PARTICLE_TIMER_UPDATE);
|
||||
break;
|
||||
case 'transactionHistory_goToBank':
|
||||
if (Account.metaverseServerURL.indexOf("staging") >= 0) {
|
||||
|
@ -474,6 +493,49 @@ function fromQml(message) {
|
|||
Window.location = "hifi://BankOfHighFidelity";
|
||||
}
|
||||
break;
|
||||
case 'purchases_updateWearables':
|
||||
var currentlyWornWearables = [];
|
||||
var ATTACHMENT_SEARCH_RADIUS = 100; // meters (just in case)
|
||||
|
||||
var nearbyEntities = Entities.findEntitiesByType('Model', MyAvatar.position, ATTACHMENT_SEARCH_RADIUS);
|
||||
|
||||
for (var i = 0; i < nearbyEntities.length; i++) {
|
||||
var currentProperties = Entities.getEntityProperties(
|
||||
nearbyEntities[i], ['certificateID', 'editionNumber', 'parentID']
|
||||
);
|
||||
if (currentProperties.parentID === MyAvatar.sessionUUID) {
|
||||
currentlyWornWearables.push({
|
||||
entityID: nearbyEntities[i],
|
||||
entityCertID: currentProperties.certificateID,
|
||||
entityEdition: currentProperties.editionNumber
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ui.tablet.sendToQml({ method: 'updateWearables', wornWearables: currentlyWornWearables });
|
||||
break;
|
||||
case 'purchases_walletNotSetUp':
|
||||
ui.tablet.sendToQml({
|
||||
method: 'updateWalletReferrer',
|
||||
referrer: "purchases"
|
||||
});
|
||||
break;
|
||||
case 'purchases_openGoTo':
|
||||
ui.open("hifi/tablet/TabletAddressDialog.qml");
|
||||
break;
|
||||
case 'purchases_itemInfoClicked':
|
||||
var itemId = message.itemId;
|
||||
if (itemId && itemId !== "") {
|
||||
openMarketplace(itemId);
|
||||
}
|
||||
break;
|
||||
case 'purchases_itemCertificateClicked':
|
||||
setCertificateInfo(message.itemCertificateId);
|
||||
break;
|
||||
case 'clearShouldShowDotHistory':
|
||||
shouldShowDotHistory = false;
|
||||
ui.messagesWaiting(shouldShowDotUpdates || shouldShowDotHistory);
|
||||
break;
|
||||
case 'http.request':
|
||||
// Handled elsewhere, don't log.
|
||||
break;
|
||||
|
@ -482,41 +544,76 @@ function fromQml(message) {
|
|||
}
|
||||
}
|
||||
|
||||
var isWired = false;
|
||||
function walletOpened() {
|
||||
Users.usernameFromIDReply.connect(usernameFromIDReply);
|
||||
Controller.mousePressEvent.connect(handleMouseEvent);
|
||||
Controller.mouseMoveEvent.connect(handleMouseMoveEvent);
|
||||
triggerMapping.enable();
|
||||
triggerPressMapping.enable();
|
||||
shouldShowDot = false;
|
||||
ui.messagesWaiting(shouldShowDot);
|
||||
isWired = true;
|
||||
|
||||
if (shouldShowDotHistory) {
|
||||
ui.sendMessage({
|
||||
method: 'updateRecentActivityMessageLight',
|
||||
messagesWaiting: shouldShowDotHistory
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function walletClosed() {
|
||||
off();
|
||||
}
|
||||
|
||||
function notificationDataProcessPage(data) {
|
||||
function notificationDataProcessPageUpdates(data) {
|
||||
return data.data.updates;
|
||||
}
|
||||
|
||||
function notificationDataProcessPageHistory(data) {
|
||||
return data.data.history;
|
||||
}
|
||||
|
||||
var shouldShowDot = false;
|
||||
function notificationPollCallback(historyArray) {
|
||||
var shouldShowDotUpdates = false;
|
||||
function notificationPollCallbackUpdates(updatesArray) {
|
||||
shouldShowDotUpdates = shouldShowDotUpdates || updatesArray.length > 0;
|
||||
ui.messagesWaiting(shouldShowDotUpdates || shouldShowDotHistory);
|
||||
|
||||
if (updatesArray.length > 0) {
|
||||
var message;
|
||||
if (!ui.notificationInitialCallbackMade[0]) {
|
||||
message = updatesArray.length + " of your purchased items " +
|
||||
(updatesArray.length === 1 ? "has an update " : "have updates ") +
|
||||
"available. Open INVENTORY to update.";
|
||||
ui.notificationDisplayBanner(message);
|
||||
|
||||
ui.notificationPollCaresAboutSince[0] = true;
|
||||
} else {
|
||||
for (var i = 0; i < updatesArray.length; i++) {
|
||||
message = "Update available for \"" +
|
||||
updatesArray[i].base_item_title + "\"." +
|
||||
"Open INVENTORY to update.";
|
||||
ui.notificationDisplayBanner(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var shouldShowDotHistory = false;
|
||||
function notificationPollCallbackHistory(historyArray) {
|
||||
if (!ui.isOpen) {
|
||||
var notificationCount = historyArray.length;
|
||||
shouldShowDot = shouldShowDot || notificationCount > 0;
|
||||
ui.messagesWaiting(shouldShowDot);
|
||||
shouldShowDotHistory = shouldShowDotHistory || notificationCount > 0;
|
||||
ui.messagesWaiting(shouldShowDotUpdates || shouldShowDotHistory);
|
||||
|
||||
if (notificationCount > 0) {
|
||||
var message;
|
||||
if (!ui.notificationInitialCallbackMade) {
|
||||
message = "You have " + notificationCount + " unread wallet " +
|
||||
"transaction" + (notificationCount === 1 ? "" : "s") + ". Open WALLET to see all activity.";
|
||||
if (!ui.notificationInitialCallbackMade[1]) {
|
||||
message = "You have " + notificationCount + " unread recent " +
|
||||
"transaction" + (notificationCount === 1 ? "" : "s") + ". Open INVENTORY to see all activity.";
|
||||
ui.notificationDisplayBanner(message);
|
||||
} else {
|
||||
for (var i = 0; i < notificationCount; i++) {
|
||||
message = '"' + (historyArray[i].message) + '" ' +
|
||||
"Open WALLET to see all activity.";
|
||||
"Open INVENTORY to see all activity.";
|
||||
ui.notificationDisplayBanner(message);
|
||||
}
|
||||
}
|
||||
|
@ -524,7 +621,12 @@ function notificationPollCallback(historyArray) {
|
|||
}
|
||||
}
|
||||
|
||||
function isReturnedDataEmpty(data) {
|
||||
function isReturnedDataEmptyUpdates(data) {
|
||||
var updatesArray = data.data.updates;
|
||||
return updatesArray.length === 0;
|
||||
}
|
||||
|
||||
function isReturnedDataEmptyHistory(data) {
|
||||
var historyArray = data.data.history;
|
||||
return historyArray.length === 0;
|
||||
}
|
||||
|
@ -559,10 +661,27 @@ function uninstallMarketplaceItemTester() {
|
|||
}
|
||||
}
|
||||
|
||||
var BUTTON_NAME = "WALLET";
|
||||
var BUTTON_NAME = "INVENTORY";
|
||||
var WALLET_QML_SOURCE = "hifi/commerce/wallet/Wallet.qml";
|
||||
var NOTIFICATION_POLL_TIMEOUT = 300000;
|
||||
var ui;
|
||||
function startup() {
|
||||
var notificationPollEndpointArray = ["/api/v1/commerce/available_updates?per_page=10"];
|
||||
var notificationPollTimeoutMsArray = [NOTIFICATION_POLL_TIMEOUT];
|
||||
var notificationDataProcessPageArray = [notificationDataProcessPageUpdates];
|
||||
var notificationPollCallbackArray = [notificationPollCallbackUpdates];
|
||||
var notificationPollStopPaginatingConditionMetArray = [isReturnedDataEmptyUpdates];
|
||||
var notificationPollCaresAboutSinceArray = [false];
|
||||
|
||||
if (!WalletScriptingInterface.limitedCommerce) {
|
||||
notificationPollEndpointArray[1] = "/api/v1/commerce/history?per_page=10";
|
||||
notificationPollTimeoutMsArray[1] = NOTIFICATION_POLL_TIMEOUT;
|
||||
notificationDataProcessPageArray[1] = notificationDataProcessPageHistory;
|
||||
notificationPollCallbackArray[1] = notificationPollCallbackHistory;
|
||||
notificationPollStopPaginatingConditionMetArray[1] = isReturnedDataEmptyHistory;
|
||||
notificationPollCaresAboutSinceArray[1] = true;
|
||||
}
|
||||
|
||||
ui = new AppUi({
|
||||
buttonName: BUTTON_NAME,
|
||||
sortOrder: 10,
|
||||
|
@ -570,12 +689,12 @@ function startup() {
|
|||
onOpened: walletOpened,
|
||||
onClosed: walletClosed,
|
||||
onMessage: fromQml,
|
||||
notificationPollEndpoint: "/api/v1/commerce/history?per_page=10",
|
||||
notificationPollTimeoutMs: 300000,
|
||||
notificationDataProcessPage: notificationDataProcessPage,
|
||||
notificationPollCallback: notificationPollCallback,
|
||||
notificationPollStopPaginatingConditionMet: isReturnedDataEmpty,
|
||||
notificationPollCaresAboutSince: true
|
||||
notificationPollEndpoint: notificationPollEndpointArray,
|
||||
notificationPollTimeoutMs: notificationPollTimeoutMsArray,
|
||||
notificationDataProcessPage: notificationDataProcessPageArray,
|
||||
notificationPollCallback: notificationPollCallbackArray,
|
||||
notificationPollStopPaginatingConditionMet: notificationPollStopPaginatingConditionMetArray,
|
||||
notificationPollCaresAboutSince: notificationPollCaresAboutSinceArray
|
||||
});
|
||||
GlobalServices.myUsernameChanged.connect(onUsernameChanged);
|
||||
installMarketplaceItemTester();
|
||||
|
@ -583,11 +702,14 @@ function startup() {
|
|||
|
||||
var isUpdateOverlaysWired = false;
|
||||
function off() {
|
||||
Users.usernameFromIDReply.disconnect(usernameFromIDReply);
|
||||
Controller.mousePressEvent.disconnect(handleMouseEvent);
|
||||
Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent);
|
||||
triggerMapping.disable();
|
||||
triggerPressMapping.disable();
|
||||
if (isWired) {
|
||||
Users.usernameFromIDReply.disconnect(usernameFromIDReply);
|
||||
Controller.mousePressEvent.disconnect(handleMouseEvent);
|
||||
Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent);
|
||||
triggerMapping.disable();
|
||||
triggerPressMapping.disable();
|
||||
isWired = false;
|
||||
}
|
||||
|
||||
if (isUpdateOverlaysWired) {
|
||||
Script.update.disconnect(updateOverlays);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
var xmlHttpRequest = null;
|
||||
var isPreparing = false; // Explicitly track download request status.
|
||||
|
||||
var limitedCommerce = false;
|
||||
var commerceMode = false;
|
||||
var userIsLoggedIn = false;
|
||||
var walletNeedsSetup = false;
|
||||
|
@ -59,7 +60,7 @@
|
|||
);
|
||||
|
||||
// Footer.
|
||||
var isInitialHiFiPage = location.href === marketplaceBaseURL + "/marketplace?";
|
||||
var isInitialHiFiPage = location.href === (marketplaceBaseURL + "/marketplace?");
|
||||
$("body").append(
|
||||
'<div id="marketplace-navigation">' +
|
||||
(!isInitialHiFiPage ? '<input id="back-button" type="button" class="white" value="< Back" />' : '') +
|
||||
|
@ -92,7 +93,7 @@
|
|||
window.location = "https://clara.io/library?gameCheck=true&public=true";
|
||||
});
|
||||
$('#exploreHifiMarketplace').on('click', function () {
|
||||
window.location = marketplaceBaseURL + "/marketplace";
|
||||
window.location = marketplaceBaseURL + "/marketplace?";
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -169,7 +170,7 @@
|
|||
|
||||
var span = document.createElement('span');
|
||||
span.style = "margin:10px;color:#1b6420;font-size:15px;";
|
||||
span.innerHTML = "to purchase items from the Marketplace.";
|
||||
span.innerHTML = "to get items from the Marketplace.";
|
||||
|
||||
var xButton = document.createElement('a');
|
||||
xButton.id = "xButton";
|
||||
|
@ -195,40 +196,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
function maybeAddPurchasesButton() {
|
||||
if (userIsLoggedIn) {
|
||||
// Why isn't this an id?! This really shouldn't be a class on the website, but it is.
|
||||
var navbarBrandElement = document.getElementsByClassName('navbar-brand')[0];
|
||||
var purchasesElement = document.createElement('a');
|
||||
var dropDownElement = document.getElementById('user-dropdown');
|
||||
|
||||
$('#user-dropdown').find('.username')[0].style = "max-width:80px;white-space:nowrap;overflow:hidden;" +
|
||||
"text-overflow:ellipsis;display:inline-block;position:relative;top:4px;";
|
||||
$('#user-dropdown').find('.caret')[0].style = "position:relative;top:-3px;";
|
||||
|
||||
purchasesElement.id = "purchasesButton";
|
||||
purchasesElement.setAttribute('href', "#");
|
||||
purchasesElement.innerHTML = "";
|
||||
if (messagesWaiting) {
|
||||
purchasesElement.innerHTML += "<span style='width:10px;height:10px;background-color:red;border-radius:50%;display:inline-block;'></span> ";
|
||||
}
|
||||
purchasesElement.innerHTML += "My Purchases";
|
||||
// FRONTEND WEBDEV RANT: The username dropdown should REALLY not be programmed to be on the same
|
||||
// line as the search bar, overlaid on top of the search bar, floated right, and then relatively bumped up using "top:-50px".
|
||||
$('.navbar-brand').css('margin-right', '10px');
|
||||
purchasesElement.style = "height:100%;margin-top:18px;font-weight:bold;float:right;margin-right:" + (dropDownElement.offsetWidth + 30) +
|
||||
"px;position:relative;z-index:999;";
|
||||
navbarBrandElement.parentNode.insertAdjacentElement('beforeend', purchasesElement);
|
||||
$('#purchasesButton').on('click', function () {
|
||||
EventBridge.emitWebEvent(JSON.stringify({
|
||||
type: "PURCHASES",
|
||||
referrerURL: window.location.href,
|
||||
hasUpdates: messagesWaiting
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function changeDropdownMenu() {
|
||||
var logInOrOutButton = document.createElement('a');
|
||||
logInOrOutButton.id = "logInOrOutButton";
|
||||
|
@ -283,6 +250,7 @@
|
|||
$(this).attr('href', '#');
|
||||
}
|
||||
cost = $(this).closest('.col-xs-3').find('.item-cost').text();
|
||||
var costInt = parseInt(cost, 10);
|
||||
|
||||
$(this).closest('.col-xs-3').prev().attr("class", 'col-xs-6');
|
||||
$(this).closest('.col-xs-3').attr("class", 'col-xs-6');
|
||||
|
@ -312,11 +280,12 @@
|
|||
var getString = "GET";
|
||||
// Protection against the button getting stuck in the "BUY"/"GET" state.
|
||||
// That happens when the browser gets two MOUSEENTER events before getting a
|
||||
// MOUSELEAVE event.
|
||||
if ($this.text() === buyString || $this.text() === getString) {
|
||||
return;
|
||||
}
|
||||
if ($this.text() === 'invalidated') {
|
||||
// MOUSELEAVE event. Also, if not available for sale, just return.
|
||||
if ($this.text() === buyString ||
|
||||
$this.text() === getString ||
|
||||
$this.text() === 'invalidated' ||
|
||||
$this.text() === 'sold out' ||
|
||||
$this.text() === 'not for sale' ) {
|
||||
return;
|
||||
}
|
||||
$this.data('initialHtml', $this.html());
|
||||
|
@ -337,7 +306,10 @@
|
|||
|
||||
|
||||
$('.grid-item').find('#price-or-edit').find('a').on('click', function () {
|
||||
if ($(this).closest('.grid-item').find('.price').text() === 'invalidated') {
|
||||
var price = $(this).closest('.grid-item').find('.price').text();
|
||||
if (price === 'invalidated' ||
|
||||
price === 'sold out' ||
|
||||
price === 'not for sale') {
|
||||
return false;
|
||||
}
|
||||
buyButtonClicked($(this).closest('.grid-item').attr('data-item-id'),
|
||||
|
@ -398,7 +370,6 @@
|
|||
// Try this here in case it works (it will if the user just pressed the "back" button,
|
||||
// since that doesn't trigger another AJAX request.
|
||||
injectBuyButtonOnMainPage();
|
||||
maybeAddPurchasesButton();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -419,7 +390,12 @@
|
|||
|
||||
var href = purchaseButton.attr('href');
|
||||
purchaseButton.attr('href', '#');
|
||||
var cost = $('.item-cost').text();
|
||||
var costInt = parseInt(cost, 10);
|
||||
var availability = $.trim($('.item-availability').text());
|
||||
if (limitedCommerce && (costInt > 0)) {
|
||||
availability = '';
|
||||
}
|
||||
if (availability === 'available') {
|
||||
purchaseButton.css({
|
||||
"background": "linear-gradient(#00b4ef, #0093C5)",
|
||||
|
@ -436,14 +412,13 @@
|
|||
});
|
||||
}
|
||||
|
||||
var cost = $('.item-cost').text();
|
||||
var type = $('.item-type').text();
|
||||
var isUpdating = window.location.href.indexOf('edition=') > -1;
|
||||
var urlParams = new URLSearchParams(window.location.search);
|
||||
if (isUpdating) {
|
||||
purchaseButton.html('UPDATE FOR FREE');
|
||||
} else if (availability !== 'available') {
|
||||
purchaseButton.html('UNAVAILABLE (' + availability + ')');
|
||||
purchaseButton.html('UNAVAILABLE ' + (availability ? ('(' + availability + ')') : ''));
|
||||
} else if (parseInt(cost) > 0 && $('#side-info').find('#buyItemButton').size() === 0) {
|
||||
purchaseButton.html('PURCHASE <span class="hifi-glyph hifi-glyph-hfc" style="filter:invert(1);background-size:20px;' +
|
||||
'width:20px;height:20px;position:relative;top:5px;"></span> ' + cost);
|
||||
|
@ -461,7 +436,6 @@
|
|||
type);
|
||||
}
|
||||
});
|
||||
maybeAddPurchasesButton();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -742,6 +716,7 @@
|
|||
cancelClaraDownload();
|
||||
} else if (message.type === "marketplaces") {
|
||||
if (message.action === "commerceSetting") {
|
||||
limitedCommerce = !!message.data.limitedCommerce;
|
||||
commerceMode = !!message.data.commerceMode;
|
||||
userIsLoggedIn = !!message.data.userIsLoggedIn;
|
||||
walletNeedsSetup = !!message.data.walletNeedsSetup;
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
/* global Tablet, Script, HMD, UserActivityLogger, Entities, Account, Wallet, ContextOverlay, Settings, Camera, Vec3,
|
||||
Quat, MyAvatar, Clipboard, Menu, Grid, Uuid, GlobalServices, openLoginWindow, getConnectionData, Overlays, SoundCache,
|
||||
DesktopPreviewProvider */
|
||||
DesktopPreviewProvider, ResourceRequestObserver */
|
||||
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
|
||||
|
||||
var selectionDisplay = null; // for gridTool.js to ignore
|
||||
|
@ -23,7 +23,7 @@ Script.include("/~/system/libraries/connectionUtils.js");
|
|||
var MARKETPLACE_CHECKOUT_QML_PATH = "hifi/commerce/checkout/Checkout.qml";
|
||||
var MARKETPLACE_INSPECTIONCERTIFICATE_QML_PATH = "hifi/commerce/inspectionCertificate/InspectionCertificate.qml";
|
||||
var MARKETPLACE_ITEM_TESTER_QML_PATH = "hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml";
|
||||
var MARKETPLACE_PURCHASES_QML_PATH = "hifi/commerce/purchases/Purchases.qml";
|
||||
var MARKETPLACE_PURCHASES_QML_PATH = "hifi/commerce/wallet/Wallet.qml"; // HRS FIXME "hifi/commerce/purchases/Purchases.qml";
|
||||
var MARKETPLACE_WALLET_QML_PATH = "hifi/commerce/wallet/Wallet.qml";
|
||||
var MARKETPLACES_INJECT_SCRIPT_URL = Script.resolvePath("../html/js/marketplacesInject.js");
|
||||
var MARKETPLACES_URL = Script.resolvePath("../html/marketplaces.html");
|
||||
|
@ -115,10 +115,10 @@ function setTabletVisibleInSecondaryCamera(visibleInSecondaryCam) {
|
|||
tabletShouldBeVisibleInSecondaryCamera = Overlays.getProperty(HMD.tabletID, "isVisibleInSecondaryCamera");
|
||||
}
|
||||
|
||||
Overlays.editOverlay(HMD.tabletID, { isVisibleInSecondaryCamera : visibleInSecondaryCam });
|
||||
Overlays.editOverlay(HMD.homeButtonID, { isVisibleInSecondaryCamera : visibleInSecondaryCam });
|
||||
Overlays.editOverlay(HMD.homeButtonHighlightID, { isVisibleInSecondaryCamera : visibleInSecondaryCam });
|
||||
Overlays.editOverlay(HMD.tabletScreenID, { isVisibleInSecondaryCamera : visibleInSecondaryCam });
|
||||
Overlays.editOverlay(HMD.tabletID, { isVisibleInSecondaryCamera: visibleInSecondaryCam });
|
||||
Overlays.editOverlay(HMD.homeButtonID, { isVisibleInSecondaryCamera: visibleInSecondaryCam });
|
||||
Overlays.editOverlay(HMD.homeButtonHighlightID, { isVisibleInSecondaryCamera: visibleInSecondaryCam });
|
||||
Overlays.editOverlay(HMD.tabletScreenID, { isVisibleInSecondaryCamera: visibleInSecondaryCam });
|
||||
}
|
||||
|
||||
function openWallet() {
|
||||
|
@ -137,7 +137,7 @@ function setupWallet(referrer) {
|
|||
}
|
||||
|
||||
function onMarketplaceOpen(referrer) {
|
||||
var cta = referrer, match;
|
||||
var match;
|
||||
if (Account.loggedIn && walletNeedsSetup()) {
|
||||
if (referrer === MARKETPLACE_URL_INITIAL) {
|
||||
setupWallet('marketplace cta');
|
||||
|
@ -218,7 +218,7 @@ function onUsernameChanged() {
|
|||
}
|
||||
|
||||
function walletNeedsSetup() {
|
||||
return Wallet.walletStatus === 1;
|
||||
return WalletScriptingInterface.walletStatus === 1;
|
||||
}
|
||||
|
||||
function sendCommerceSettings() {
|
||||
|
@ -230,289 +230,11 @@ function sendCommerceSettings() {
|
|||
userIsLoggedIn: Account.loggedIn,
|
||||
walletNeedsSetup: walletNeedsSetup(),
|
||||
metaverseServerURL: Account.metaverseServerURL,
|
||||
messagesWaiting: shouldShowDot
|
||||
limitedCommerce: WalletScriptingInterface.limitedCommerce
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// BEGIN AVATAR SELECTOR LOGIC
|
||||
var UNSELECTED_COLOR = { red: 0x1F, green: 0xC6, blue: 0xA6 };
|
||||
var SELECTED_COLOR = { red: 0xF3, green: 0x91, blue: 0x29 };
|
||||
var HOVER_COLOR = { red: 0xD0, green: 0xD0, blue: 0xD0 };
|
||||
|
||||
var overlays = {}; // Keeps track of all our extended overlay data objects, keyed by target identifier.
|
||||
|
||||
function ExtendedOverlay(key, type, properties) { // A wrapper around overlays to store the key it is associated with.
|
||||
overlays[key] = this;
|
||||
this.key = key;
|
||||
this.selected = false;
|
||||
this.hovering = false;
|
||||
this.activeOverlay = Overlays.addOverlay(type, properties); // We could use different overlays for (un)selected...
|
||||
}
|
||||
// Instance methods:
|
||||
ExtendedOverlay.prototype.deleteOverlay = function () { // remove display and data of this overlay
|
||||
Overlays.deleteOverlay(this.activeOverlay);
|
||||
delete overlays[this.key];
|
||||
};
|
||||
|
||||
ExtendedOverlay.prototype.editOverlay = function (properties) { // change display of this overlay
|
||||
Overlays.editOverlay(this.activeOverlay, properties);
|
||||
};
|
||||
|
||||
function color(selected, hovering) {
|
||||
var base = hovering ? HOVER_COLOR : selected ? SELECTED_COLOR : UNSELECTED_COLOR;
|
||||
function scale(component) {
|
||||
return component;
|
||||
}
|
||||
return { red: scale(base.red), green: scale(base.green), blue: scale(base.blue) };
|
||||
}
|
||||
// so we don't have to traverse the overlays to get the last one
|
||||
var lastHoveringId = 0;
|
||||
ExtendedOverlay.prototype.hover = function (hovering) {
|
||||
this.hovering = hovering;
|
||||
if (this.key === lastHoveringId) {
|
||||
if (hovering) {
|
||||
return;
|
||||
}
|
||||
lastHoveringId = 0;
|
||||
}
|
||||
this.editOverlay({ color: color(this.selected, hovering) });
|
||||
if (hovering) {
|
||||
// un-hover the last hovering overlay
|
||||
if (lastHoveringId && lastHoveringId !== this.key) {
|
||||
ExtendedOverlay.get(lastHoveringId).hover(false);
|
||||
}
|
||||
lastHoveringId = this.key;
|
||||
}
|
||||
};
|
||||
ExtendedOverlay.prototype.select = function (selected) {
|
||||
if (this.selected === selected) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.editOverlay({ color: color(selected, this.hovering) });
|
||||
this.selected = selected;
|
||||
};
|
||||
// Class methods:
|
||||
var selectedId = false;
|
||||
ExtendedOverlay.isSelected = function (id) {
|
||||
return selectedId === id;
|
||||
};
|
||||
ExtendedOverlay.get = function (key) { // answer the extended overlay data object associated with the given avatar identifier
|
||||
return overlays[key];
|
||||
};
|
||||
ExtendedOverlay.some = function (iterator) { // Bails early as soon as iterator returns truthy.
|
||||
var key;
|
||||
for (key in overlays) {
|
||||
if (iterator(ExtendedOverlay.get(key))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
ExtendedOverlay.unHover = function () { // calls hover(false) on lastHoveringId (if any)
|
||||
if (lastHoveringId) {
|
||||
ExtendedOverlay.get(lastHoveringId).hover(false);
|
||||
}
|
||||
};
|
||||
|
||||
// hit(overlay) on the one overlay intersected by pickRay, if any.
|
||||
// noHit() if no ExtendedOverlay was intersected (helps with hover)
|
||||
ExtendedOverlay.applyPickRay = function (pickRay, hit, noHit) {
|
||||
var pickedOverlay = Overlays.findRayIntersection(pickRay); // Depends on nearer coverOverlays to extend closer to us than farther ones.
|
||||
if (!pickedOverlay.intersects) {
|
||||
if (noHit) {
|
||||
return noHit();
|
||||
}
|
||||
return;
|
||||
}
|
||||
ExtendedOverlay.some(function (overlay) { // See if pickedOverlay is one of ours.
|
||||
if ((overlay.activeOverlay) === pickedOverlay.overlayID) {
|
||||
hit(overlay);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function addAvatarNode(id) {
|
||||
return new ExtendedOverlay(id, "sphere", {
|
||||
drawInFront: true,
|
||||
solid: true,
|
||||
alpha: 0.8,
|
||||
color: color(false, false),
|
||||
ignoreRayIntersection: false
|
||||
});
|
||||
}
|
||||
|
||||
var pingPong = true;
|
||||
function updateOverlays() {
|
||||
var eye = Camera.position;
|
||||
AvatarList.getAvatarIdentifiers().forEach(function (id) {
|
||||
if (!id) {
|
||||
return; // don't update ourself, or avatars we're not interested in
|
||||
}
|
||||
var avatar = AvatarList.getAvatar(id);
|
||||
if (!avatar) {
|
||||
return; // will be deleted below if there had been an overlay.
|
||||
}
|
||||
var overlay = ExtendedOverlay.get(id);
|
||||
if (!overlay) { // For now, we're treating this as a temporary loss, as from the personal space bubble. Add it back.
|
||||
overlay = addAvatarNode(id);
|
||||
}
|
||||
var target = avatar.position;
|
||||
var distance = Vec3.distance(target, eye);
|
||||
var offset = 0.2;
|
||||
var diff = Vec3.subtract(target, eye); // get diff between target and eye (a vector pointing to the eye from avatar position)
|
||||
var headIndex = avatar.getJointIndex("Head"); // base offset on 1/2 distance from hips to head if we can
|
||||
if (headIndex > 0) {
|
||||
offset = avatar.getAbsoluteJointTranslationInObjectFrame(headIndex).y / 2;
|
||||
}
|
||||
|
||||
// move a bit in front, towards the camera
|
||||
target = Vec3.subtract(target, Vec3.multiply(Vec3.normalize(diff), offset));
|
||||
|
||||
// now bump it up a bit
|
||||
target.y = target.y + offset;
|
||||
|
||||
overlay.ping = pingPong;
|
||||
overlay.editOverlay({
|
||||
color: color(ExtendedOverlay.isSelected(id), overlay.hovering),
|
||||
position: target,
|
||||
dimensions: 0.032 * distance
|
||||
});
|
||||
});
|
||||
pingPong = !pingPong;
|
||||
ExtendedOverlay.some(function (overlay) { // Remove any that weren't updated. (User is gone.)
|
||||
if (overlay.ping === pingPong) {
|
||||
overlay.deleteOverlay();
|
||||
}
|
||||
});
|
||||
}
|
||||
function removeOverlays() {
|
||||
selectedId = false;
|
||||
lastHoveringId = 0;
|
||||
ExtendedOverlay.some(function (overlay) {
|
||||
overlay.deleteOverlay();
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// Clicks.
|
||||
//
|
||||
function usernameFromIDReply(id, username, machineFingerprint, isAdmin) {
|
||||
if (selectedId === id) {
|
||||
var message = {
|
||||
method: 'updateSelectedRecipientUsername',
|
||||
userName: username === "" ? "unknown username" : username
|
||||
};
|
||||
ui.tablet.sendToQml(message);
|
||||
}
|
||||
}
|
||||
function handleClick(pickRay) {
|
||||
ExtendedOverlay.applyPickRay(pickRay, function (overlay) {
|
||||
var nextSelectedStatus = !overlay.selected;
|
||||
var avatarId = overlay.key;
|
||||
selectedId = nextSelectedStatus ? avatarId : false;
|
||||
if (nextSelectedStatus) {
|
||||
Users.requestUsernameFromID(avatarId);
|
||||
}
|
||||
var message = {
|
||||
method: 'selectRecipient',
|
||||
id: avatarId,
|
||||
isSelected: nextSelectedStatus,
|
||||
displayName: '"' + AvatarList.getAvatar(avatarId).sessionDisplayName + '"',
|
||||
userName: ''
|
||||
};
|
||||
ui.tablet.sendToQml(message);
|
||||
|
||||
ExtendedOverlay.some(function (overlay) {
|
||||
var id = overlay.key;
|
||||
var selected = ExtendedOverlay.isSelected(id);
|
||||
overlay.select(selected);
|
||||
});
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
function handleMouseEvent(mousePressEvent) { // handleClick if we get one.
|
||||
if (!mousePressEvent.isLeftButton) {
|
||||
return;
|
||||
}
|
||||
handleClick(Camera.computePickRay(mousePressEvent.x, mousePressEvent.y));
|
||||
}
|
||||
function handleMouseMove(pickRay) { // given the pickRay, just do the hover logic
|
||||
ExtendedOverlay.applyPickRay(pickRay, function (overlay) {
|
||||
overlay.hover(true);
|
||||
}, function () {
|
||||
ExtendedOverlay.unHover();
|
||||
});
|
||||
}
|
||||
|
||||
// handy global to keep track of which hand is the mouse (if any)
|
||||
var currentHandPressed = 0;
|
||||
var TRIGGER_CLICK_THRESHOLD = 0.85;
|
||||
var TRIGGER_PRESS_THRESHOLD = 0.05;
|
||||
|
||||
function handleMouseMoveEvent(event) { // find out which overlay (if any) is over the mouse position
|
||||
var pickRay;
|
||||
if (HMD.active) {
|
||||
if (currentHandPressed !== 0) {
|
||||
pickRay = controllerComputePickRay(currentHandPressed);
|
||||
} else {
|
||||
// nothing should hover, so
|
||||
ExtendedOverlay.unHover();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
pickRay = Camera.computePickRay(event.x, event.y);
|
||||
}
|
||||
handleMouseMove(pickRay);
|
||||
}
|
||||
function handleTriggerPressed(hand, value) {
|
||||
// The idea is if you press one trigger, it is the one
|
||||
// we will consider the mouse. Even if the other is pressed,
|
||||
// we ignore it until this one is no longer pressed.
|
||||
var isPressed = value > TRIGGER_PRESS_THRESHOLD;
|
||||
if (currentHandPressed === 0) {
|
||||
currentHandPressed = isPressed ? hand : 0;
|
||||
return;
|
||||
}
|
||||
if (currentHandPressed === hand) {
|
||||
currentHandPressed = isPressed ? hand : 0;
|
||||
return;
|
||||
}
|
||||
// otherwise, the other hand is still triggered
|
||||
// so do nothing.
|
||||
}
|
||||
|
||||
// We get mouseMoveEvents from the handControllers, via handControllerPointer.
|
||||
// But we don't get mousePressEvents.
|
||||
var triggerMapping = Controller.newMapping(Script.resolvePath('') + '-click');
|
||||
var triggerPressMapping = Controller.newMapping(Script.resolvePath('') + '-press');
|
||||
function controllerComputePickRay(hand) {
|
||||
var controllerPose = getControllerWorldLocation(hand, true);
|
||||
if (controllerPose.valid) {
|
||||
return { origin: controllerPose.position, direction: Quat.getUp(controllerPose.orientation) };
|
||||
}
|
||||
}
|
||||
function makeClickHandler(hand) {
|
||||
return function (clicked) {
|
||||
if (clicked > TRIGGER_CLICK_THRESHOLD) {
|
||||
var pickRay = controllerComputePickRay(hand);
|
||||
handleClick(pickRay);
|
||||
}
|
||||
};
|
||||
}
|
||||
function makePressHandler(hand) {
|
||||
return function (value) {
|
||||
handleTriggerPressed(hand, value);
|
||||
};
|
||||
}
|
||||
triggerMapping.from(Controller.Standard.RTClick).peek().to(makeClickHandler(Controller.Standard.RightHand));
|
||||
triggerMapping.from(Controller.Standard.LTClick).peek().to(makeClickHandler(Controller.Standard.LeftHand));
|
||||
triggerPressMapping.from(Controller.Standard.RT).peek().to(makePressHandler(Controller.Standard.RightHand));
|
||||
triggerPressMapping.from(Controller.Standard.LT).peek().to(makePressHandler(Controller.Standard.LeftHand));
|
||||
// END AVATAR SELECTOR LOGIC
|
||||
|
||||
var grid = new Grid();
|
||||
function adjustPositionPerBoundingBox(position, direction, registration, dimensions, orientation) {
|
||||
// Adjust the position such that the bounding box (registration, dimenions, and orientation) lies behind the original
|
||||
|
@ -562,6 +284,7 @@ function defaultFor(arg, val) {
|
|||
return typeof arg !== 'undefined' ? arg : val;
|
||||
}
|
||||
|
||||
var CERT_ID_URLPARAM_LENGTH = 15; // length of "certificate_id="
|
||||
function rezEntity(itemHref, itemType, marketplaceItemTesterId) {
|
||||
var isWearable = itemType === "wearable";
|
||||
var success = Clipboard.importEntities(itemHref, true, marketplaceItemTesterId);
|
||||
|
@ -584,7 +307,7 @@ function rezEntity(itemHref, itemType, marketplaceItemTesterId) {
|
|||
}
|
||||
var certPos = itemHref.search("certificate_id="); // TODO how do I parse a URL from here?
|
||||
if (certPos >= 0) {
|
||||
certPos += 15; // length of "certificate_id="
|
||||
certPos += CERT_ID_URLPARAM_LENGTH;
|
||||
var certURLEncoded = itemHref.substring(certPos);
|
||||
var certB64Encoded = decodeURIComponent(certURLEncoded);
|
||||
for (var key in wearableTransforms) {
|
||||
|
@ -593,7 +316,7 @@ function rezEntity(itemHref, itemType, marketplaceItemTesterId) {
|
|||
if (certificateTransforms) {
|
||||
for (var certID in certificateTransforms) {
|
||||
if (certificateTransforms.hasOwnProperty(certID) &&
|
||||
certID == certB64Encoded) {
|
||||
certID === certB64Encoded) {
|
||||
var certificateTransform = certificateTransforms[certID];
|
||||
wearableLocalPosition = certificateTransform.localPosition;
|
||||
wearableLocalRotation = certificateTransform.localRotation;
|
||||
|
@ -636,8 +359,10 @@ function rezEntity(itemHref, itemType, marketplaceItemTesterId) {
|
|||
targetDirection = Vec3.multiplyQbyV(targetDirection, Vec3.UNIT_Z);
|
||||
|
||||
var targetPosition = getPositionToCreateEntity();
|
||||
var deltaParallel = HALF_TREE_SCALE; // Distance to move entities parallel to targetDirection.
|
||||
var deltaPerpendicular = Vec3.ZERO; // Distance to move entities perpendicular to targetDirection.
|
||||
// Distance to move entities parallel to targetDirection.
|
||||
var deltaParallel = HALF_TREE_SCALE;
|
||||
// Distance to move entities perpendicular to targetDirection.
|
||||
var deltaPerpendicular = Vec3.ZERO;
|
||||
for (var i = 0, length = pastedEntityIDs.length; i < length; i++) {
|
||||
var curLoopEntityProps = Entities.getEntityProperties(pastedEntityIDs[i], ["position", "dimensions",
|
||||
"registrationPoint", "rotation", "parentID"]);
|
||||
|
@ -665,7 +390,8 @@ function rezEntity(itemHref, itemType, marketplaceItemTesterId) {
|
|||
}
|
||||
|
||||
if (!Vec3.equal(deltaPosition, Vec3.ZERO)) {
|
||||
for (var editEntityIndex = 0, numEntities = pastedEntityIDs.length; editEntityIndex < numEntities; editEntityIndex++) {
|
||||
for (var editEntityIndex = 0,
|
||||
numEntities = pastedEntityIDs.length; editEntityIndex < numEntities; editEntityIndex++) {
|
||||
if (Uuid.isNull(entityParentIDs[editEntityIndex])) {
|
||||
Entities.editEntity(pastedEntityIDs[editEntityIndex], {
|
||||
position: Vec3.sum(deltaPosition, entityPositions[editEntityIndex])
|
||||
|
@ -768,79 +494,6 @@ function onWebEventReceived(message) {
|
|||
});
|
||||
}
|
||||
}
|
||||
var sendAssetRecipient;
|
||||
var sendAssetParticleEffectUpdateTimer;
|
||||
var particleEffectTimestamp;
|
||||
var sendAssetParticleEffect;
|
||||
var SEND_ASSET_PARTICLE_TIMER_UPDATE = 250;
|
||||
var SEND_ASSET_PARTICLE_EMITTING_DURATION = 3000;
|
||||
var SEND_ASSET_PARTICLE_LIFETIME_SECONDS = 8;
|
||||
var SEND_ASSET_PARTICLE_PROPERTIES = {
|
||||
accelerationSpread: { x: 0, y: 0, z: 0 },
|
||||
alpha: 1,
|
||||
alphaFinish: 1,
|
||||
alphaSpread: 0,
|
||||
alphaStart: 1,
|
||||
azimuthFinish: 0,
|
||||
azimuthStart: -6,
|
||||
color: { red: 255, green: 222, blue: 255 },
|
||||
colorFinish: { red: 255, green: 229, blue: 225 },
|
||||
colorSpread: { red: 0, green: 0, blue: 0 },
|
||||
colorStart: { red: 243, green: 255, blue: 255 },
|
||||
emitAcceleration: { x: 0, y: 0, z: 0 }, // Immediately gets updated to be accurate
|
||||
emitDimensions: { x: 0, y: 0, z: 0 },
|
||||
emitOrientation: { x: 0, y: 0, z: 0 },
|
||||
emitRate: 4,
|
||||
emitSpeed: 2.1,
|
||||
emitterShouldTrail: true,
|
||||
isEmitting: 1,
|
||||
lifespan: SEND_ASSET_PARTICLE_LIFETIME_SECONDS + 1, // Immediately gets updated to be accurate
|
||||
lifetime: SEND_ASSET_PARTICLE_LIFETIME_SECONDS + 1,
|
||||
maxParticles: 20,
|
||||
name: 'asset-particles',
|
||||
particleRadius: 0.2,
|
||||
polarFinish: 0,
|
||||
polarStart: 0,
|
||||
radiusFinish: 0.05,
|
||||
radiusSpread: 0,
|
||||
radiusStart: 0.2,
|
||||
speedSpread: 0,
|
||||
textures: "http://hifi-content.s3.amazonaws.com/alan/dev/Particles/Bokeh-Particle-HFC.png",
|
||||
type: 'ParticleEffect'
|
||||
};
|
||||
|
||||
function updateSendAssetParticleEffect() {
|
||||
var timestampNow = Date.now();
|
||||
if ((timestampNow - particleEffectTimestamp) > (SEND_ASSET_PARTICLE_LIFETIME_SECONDS * 1000)) {
|
||||
deleteSendAssetParticleEffect();
|
||||
return;
|
||||
} else if ((timestampNow - particleEffectTimestamp) > SEND_ASSET_PARTICLE_EMITTING_DURATION) {
|
||||
Entities.editEntity(sendAssetParticleEffect, {
|
||||
isEmitting: 0
|
||||
});
|
||||
} else if (sendAssetParticleEffect) {
|
||||
var recipientPosition = AvatarList.getAvatar(sendAssetRecipient).position;
|
||||
var distance = Vec3.distance(recipientPosition, MyAvatar.position);
|
||||
var accel = Vec3.subtract(recipientPosition, MyAvatar.position);
|
||||
accel.y -= 3.0;
|
||||
var life = Math.sqrt(2 * distance / Vec3.length(accel));
|
||||
Entities.editEntity(sendAssetParticleEffect, {
|
||||
emitAcceleration: accel,
|
||||
lifespan: life
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function deleteSendAssetParticleEffect() {
|
||||
if (sendAssetParticleEffectUpdateTimer) {
|
||||
Script.clearInterval(sendAssetParticleEffectUpdateTimer);
|
||||
sendAssetParticleEffectUpdateTimer = null;
|
||||
}
|
||||
if (sendAssetParticleEffect) {
|
||||
sendAssetParticleEffect = Entities.deleteEntity(sendAssetParticleEffect);
|
||||
}
|
||||
sendAssetRecipient = null;
|
||||
}
|
||||
|
||||
var savedDisablePreviewOption = Menu.isOptionChecked("Disable Preview");
|
||||
var UI_FADE_TIMEOUT_MS = 150;
|
||||
|
@ -867,24 +520,21 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) {
|
|||
}
|
||||
switch (message.method) {
|
||||
case 'gotoBank':
|
||||
ui.close();
|
||||
ui.close();
|
||||
if (Account.metaverseServerURL.indexOf("staging") >= 0) {
|
||||
Window.location = "hifi://hifiqa-master-metaverse-staging"; // So that we can test in staging.
|
||||
} else {
|
||||
Window.location = "hifi://BankOfHighFidelity";
|
||||
}
|
||||
break;
|
||||
case 'purchases_openWallet':
|
||||
case 'checkout_openWallet':
|
||||
case 'checkout_setUpClicked':
|
||||
openWallet();
|
||||
break;
|
||||
case 'purchases_walletNotSetUp':
|
||||
case 'checkout_openRecentActivity':
|
||||
ui.open(MARKETPLACE_WALLET_QML_PATH);
|
||||
wireQmlEventBridge(true);
|
||||
ui.tablet.sendToQml({
|
||||
method: 'updateWalletReferrer',
|
||||
referrer: "purchases"
|
||||
method: 'checkout_openRecentActivity'
|
||||
});
|
||||
break;
|
||||
case 'checkout_setUpClicked':
|
||||
openWallet();
|
||||
break;
|
||||
case 'checkout_walletNotSetUp':
|
||||
|
@ -907,15 +557,9 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) {
|
|||
case 'checkout_itemLinkClicked':
|
||||
openMarketplace(message.itemId);
|
||||
break;
|
||||
case 'checkout_continueShopping':
|
||||
case 'checkout_continue':
|
||||
openMarketplace();
|
||||
break;
|
||||
case 'purchases_itemInfoClicked':
|
||||
var itemId = message.itemId;
|
||||
if (itemId && itemId !== "") {
|
||||
openMarketplace(itemId);
|
||||
}
|
||||
break;
|
||||
case 'checkout_rezClicked':
|
||||
case 'purchases_rezClicked':
|
||||
case 'tester_rezClicked':
|
||||
|
@ -944,7 +588,6 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) {
|
|||
}
|
||||
break;
|
||||
case 'header_marketplaceImageClicked':
|
||||
case 'purchases_backClicked':
|
||||
openMarketplace(message.referrerURL);
|
||||
break;
|
||||
case 'purchases_goToMarketplaceClicked':
|
||||
|
@ -952,9 +595,6 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) {
|
|||
break;
|
||||
case 'updateItemClicked':
|
||||
openMarketplace(message.upgradeUrl + "?edition=" + message.itemEdition);
|
||||
break;
|
||||
case 'giftAsset':
|
||||
|
||||
break;
|
||||
case 'passphrasePopup_cancelClicked':
|
||||
case 'needsLogIn_cancelClicked':
|
||||
|
@ -970,18 +610,13 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) {
|
|||
Menu.setIsOptionChecked("Disable Preview", true);
|
||||
setTabletVisibleInSecondaryCamera(false);
|
||||
}
|
||||
<<<<<<< Updated upstream
|
||||
break;
|
||||
case 'maybeEnableHmdPreview':
|
||||
maybeEnableHMDPreview();
|
||||
break;
|
||||
case 'purchases_openGoTo':
|
||||
case 'checkout_openGoTo':
|
||||
ui.open("hifi/tablet/TabletAddressDialog.qml");
|
||||
break;
|
||||
case 'purchases_itemCertificateClicked':
|
||||
contextOverlayEntity = "";
|
||||
setCertificateInfo(contextOverlayEntity, message.itemCertificateId);
|
||||
break;
|
||||
case 'inspectionCertificate_closeClicked':
|
||||
ui.close();
|
||||
break;
|
||||
|
@ -1000,126 +635,25 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) {
|
|||
method: 'purchases_showMyItems'
|
||||
});
|
||||
break;
|
||||
case 'refreshConnections':
|
||||
// Guard to prevent this code from being executed while sending money --
|
||||
// we only want to execute this while sending non-HFC gifts
|
||||
if (!onWalletScreen) {
|
||||
print('Refreshing Connections...');
|
||||
getConnectionData(false);
|
||||
}
|
||||
break;
|
||||
case 'enable_ChooseRecipientNearbyMode':
|
||||
// Guard to prevent this code from being executed while sending money --
|
||||
// we only want to execute this while sending non-HFC gifts
|
||||
if (!onWalletScreen) {
|
||||
if (!isUpdateOverlaysWired) {
|
||||
Script.update.connect(updateOverlays);
|
||||
isUpdateOverlaysWired = true;
|
||||
}
|
||||
=======
|
||||
}
|
||||
|
||||
<<<<<<< Updated upstream
|
||||
// Function Name: onTabletScreenChanged()
|
||||
//
|
||||
// Description:
|
||||
// -Called when the TabletScriptingInterface::screenChanged() signal is emitted. The "type" argument can be either the string
|
||||
// value of "Home", "Web", "Menu", "QML", or "Closed". The "url" argument is only valid for Web and QML.
|
||||
var onWalletScreen = false;
|
||||
var onCommerceScreen = false;
|
||||
function onTabletScreenChanged(type, url) {
|
||||
onMarketplaceScreen = type === "Web" && url.indexOf(MARKETPLACE_URL) !== -1;
|
||||
var onWalletScreenNow = url.indexOf(MARKETPLACE_WALLET_QML_PATH) !== -1;
|
||||
var onCommerceScreenNow = type === "QML" && (url.indexOf(MARKETPLACE_CHECKOUT_QML_PATH) !== -1 || url === MARKETPLACE_PURCHASES_QML_PATH
|
||||
|| url.indexOf(MARKETPLACE_INSPECTIONCERTIFICATE_QML_PATH) !== -1);
|
||||
|
||||
if ((!onWalletScreenNow && onWalletScreen) || (!onCommerceScreenNow && onCommerceScreen)) { // exiting wallet or commerce screen
|
||||
maybeEnableHMDPreview();
|
||||
}
|
||||
=======
|
||||
// console.debug(ui.buttonName + " app reports: Tablet screen changed.\nNew screen type: " + type +
|
||||
// "\nNew screen URL: " + url + "\nCurrent app open status: " + ui.isOpen + "\n");
|
||||
};
|
||||
|
||||
function notificationDataProcessPage(data) {
|
||||
return data.data.updates;
|
||||
}
|
||||
>>>>>>> Stashed changes
|
||||
|
||||
onCommerceScreen = onCommerceScreenNow;
|
||||
onWalletScreen = onWalletScreenNow;
|
||||
wireEventBridge(onMarketplaceScreen || onCommerceScreen || onWalletScreen);
|
||||
|
||||
if (url === MARKETPLACE_PURCHASES_QML_PATH) {
|
||||
sendToQml({
|
||||
method: 'updatePurchases',
|
||||
referrerURL: referrerURL,
|
||||
filterText: filterText
|
||||
});
|
||||
>>>>>>> Stashed changes
|
||||
}
|
||||
break;
|
||||
case 'disable_ChooseRecipientNearbyMode':
|
||||
// Guard to prevent this code from being executed while sending money --
|
||||
// we only want to execute this while sending non-HFC gifts
|
||||
if (!onWalletScreen) {
|
||||
if (isUpdateOverlaysWired) {
|
||||
Script.update.disconnect(updateOverlays);
|
||||
isUpdateOverlaysWired = false;
|
||||
}
|
||||
removeOverlays();
|
||||
}
|
||||
break;
|
||||
case 'purchases_availableUpdatesReceived':
|
||||
shouldShowDot = message.numUpdates > 0;
|
||||
ui.messagesWaiting(shouldShowDot && !ui.isOpen);
|
||||
break;
|
||||
case 'purchases_updateWearables':
|
||||
var currentlyWornWearables = [];
|
||||
var ATTACHMENT_SEARCH_RADIUS = 100; // meters (just in case)
|
||||
|
||||
var nearbyEntities = Entities.findEntitiesByType('Model', MyAvatar.position, ATTACHMENT_SEARCH_RADIUS);
|
||||
|
||||
for (var i = 0; i < nearbyEntities.length; i++) {
|
||||
var currentProperties = Entities.getEntityProperties(
|
||||
nearbyEntities[i], ['certificateID', 'editionNumber', 'parentID']
|
||||
);
|
||||
if (currentProperties.parentID === MyAvatar.sessionUUID) {
|
||||
currentlyWornWearables.push({
|
||||
entityID: nearbyEntities[i],
|
||||
entityCertID: currentProperties.certificateID,
|
||||
entityEdition: currentProperties.editionNumber
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ui.tablet.sendToQml({ method: 'updateWearables', wornWearables: currentlyWornWearables });
|
||||
break;
|
||||
case 'sendAsset_sendPublicly':
|
||||
if (message.assetName !== "") {
|
||||
deleteSendAssetParticleEffect();
|
||||
sendAssetRecipient = message.recipient;
|
||||
var props = SEND_ASSET_PARTICLE_PROPERTIES;
|
||||
props.parentID = MyAvatar.sessionUUID;
|
||||
props.position = MyAvatar.position;
|
||||
props.position.y += 0.2;
|
||||
if (message.effectImage) {
|
||||
props.textures = message.effectImage;
|
||||
}
|
||||
sendAssetParticleEffect = Entities.addEntity(props, true);
|
||||
particleEffectTimestamp = Date.now();
|
||||
updateSendAssetParticleEffect();
|
||||
sendAssetParticleEffectUpdateTimer = Script.setInterval(updateSendAssetParticleEffect,
|
||||
SEND_ASSET_PARTICLE_TIMER_UPDATE);
|
||||
}
|
||||
break;
|
||||
case 'http.request':
|
||||
// Handled elsewhere, don't log.
|
||||
break;
|
||||
case 'goToPurchases_fromWalletHome': // HRS FIXME What's this about?
|
||||
// All of these are handled by wallet.js
|
||||
case 'purchases_updateWearables':
|
||||
case 'enable_ChooseRecipientNearbyMode':
|
||||
case 'disable_ChooseRecipientNearbyMode':
|
||||
case 'sendAsset_sendPublicly':
|
||||
case 'refreshConnections':
|
||||
case 'transactionHistory_goToBank':
|
||||
case 'purchases_walletNotSetUp':
|
||||
case 'purchases_openGoTo':
|
||||
case 'purchases_itemInfoClicked':
|
||||
case 'purchases_itemCertificateClicked':
|
||||
case 'clearShouldShowDotHistory':
|
||||
case 'giftAsset':
|
||||
break;
|
||||
default:
|
||||
print('Unrecognized message from Checkout.qml or Purchases.qml: ' + JSON.stringify(message));
|
||||
print('Unrecognized message from Checkout.qml: ' + JSON.stringify(message));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1188,6 +722,8 @@ var onTabletScreenChanged = function onTabletScreenChanged(type, url) {
|
|||
referrerURL: referrerURL,
|
||||
filterText: filterText
|
||||
});
|
||||
referrerURL = "";
|
||||
filterText = "";
|
||||
}
|
||||
|
||||
ui.isOpen = (onMarketplaceScreen || onCommerceScreen) && !onWalletScreen;
|
||||
|
@ -1204,15 +740,7 @@ var onTabletScreenChanged = function onTabletScreenChanged(type, url) {
|
|||
}
|
||||
|
||||
if (onCommerceScreen) {
|
||||
if (!isWired) {
|
||||
Users.usernameFromIDReply.connect(usernameFromIDReply);
|
||||
Controller.mousePressEvent.connect(handleMouseEvent);
|
||||
Controller.mouseMoveEvent.connect(handleMouseMoveEvent);
|
||||
triggerMapping.enable();
|
||||
triggerPressMapping.enable();
|
||||
}
|
||||
isWired = true;
|
||||
Wallet.refreshWalletStatus();
|
||||
WalletScriptingInterface.refreshWalletStatus();
|
||||
} else {
|
||||
if (onMarketplaceScreen) {
|
||||
onMarketplaceOpen('marketplace cta');
|
||||
|
@ -1234,44 +762,11 @@ var onTabletScreenChanged = function onTabletScreenChanged(type, url) {
|
|||
"\nNew screen URL: " + url + "\nCurrent app open status: " + ui.isOpen + "\n");
|
||||
};
|
||||
|
||||
function notificationDataProcessPage(data) {
|
||||
return data.data.updates;
|
||||
}
|
||||
|
||||
var shouldShowDot = false;
|
||||
function notificationPollCallback(updatesArray) {
|
||||
shouldShowDot = shouldShowDot || updatesArray.length > 0;
|
||||
ui.messagesWaiting(shouldShowDot && !ui.isOpen);
|
||||
|
||||
if (updatesArray.length > 0) {
|
||||
var message;
|
||||
if (!ui.notificationInitialCallbackMade) {
|
||||
message = updatesArray.length + " of your purchased items " +
|
||||
(updatesArray.length === 1 ? "has an update " : "have updates ") +
|
||||
"available. Open MARKET to update.";
|
||||
ui.notificationDisplayBanner(message);
|
||||
|
||||
ui.notificationPollCaresAboutSince = true;
|
||||
} else {
|
||||
for (var i = 0; i < updatesArray.length; i++) {
|
||||
message = "Update available for \"" +
|
||||
updatesArray[i].base_item_title + "\"." +
|
||||
"Open MARKET to update.";
|
||||
ui.notificationDisplayBanner(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isReturnedDataEmpty(data) {
|
||||
var historyArray = data.data.updates;
|
||||
return historyArray.length === 0;
|
||||
}
|
||||
|
||||
|
||||
var BUTTON_NAME = "MARKET";
|
||||
var MARKETPLACE_URL = METAVERSE_SERVER_URL + "/marketplace";
|
||||
var MARKETPLACE_URL_INITIAL = MARKETPLACE_URL + "?"; // Append "?" to signal injected script that it's the initial page.
|
||||
// Append "?" if necessary to signal injected script that it's the initial page.
|
||||
var MARKETPLACE_URL_INITIAL = MARKETPLACE_URL + (MARKETPLACE_URL.indexOf("?") > -1 ? "" : "?");
|
||||
var ui;
|
||||
function startup() {
|
||||
ui = new AppUi({
|
||||
|
@ -1280,50 +775,26 @@ function startup() {
|
|||
inject: MARKETPLACES_INJECT_SCRIPT_URL,
|
||||
home: MARKETPLACE_URL_INITIAL,
|
||||
onScreenChanged: onTabletScreenChanged,
|
||||
onMessage: onQmlMessageReceived,
|
||||
notificationPollEndpoint: "/api/v1/commerce/available_updates?per_page=10",
|
||||
notificationPollTimeoutMs: 300000,
|
||||
notificationDataProcessPage: notificationDataProcessPage,
|
||||
notificationPollCallback: notificationPollCallback,
|
||||
notificationPollStopPaginatingConditionMet: isReturnedDataEmpty,
|
||||
notificationPollCaresAboutSince: false // Changes to true after first poll
|
||||
onMessage: onQmlMessageReceived
|
||||
});
|
||||
ContextOverlay.contextOverlayClicked.connect(openInspectionCertificateQML);
|
||||
Entities.canWriteAssetsChanged.connect(onCanWriteAssetsChanged);
|
||||
GlobalServices.myUsernameChanged.connect(onUsernameChanged);
|
||||
ui.tablet.webEventReceived.connect(onWebEventReceived);
|
||||
Wallet.walletStatusChanged.connect(sendCommerceSettings);
|
||||
WalletScriptingInterface.walletStatusChanged.connect(sendCommerceSettings);
|
||||
Window.messageBoxClosed.connect(onMessageBoxClosed);
|
||||
ResourceRequestObserver.resourceRequestEvent.connect(onResourceRequestEvent);
|
||||
|
||||
Wallet.refreshWalletStatus();
|
||||
WalletScriptingInterface.refreshWalletStatus();
|
||||
}
|
||||
|
||||
var isWired = false;
|
||||
var isUpdateOverlaysWired = false;
|
||||
function off() {
|
||||
if (isWired) {
|
||||
Users.usernameFromIDReply.disconnect(usernameFromIDReply);
|
||||
Controller.mousePressEvent.disconnect(handleMouseEvent);
|
||||
Controller.mouseMoveEvent.disconnect(handleMouseMoveEvent);
|
||||
triggerMapping.disable();
|
||||
triggerPressMapping.disable();
|
||||
|
||||
isWired = false;
|
||||
}
|
||||
|
||||
if (isUpdateOverlaysWired) {
|
||||
Script.update.disconnect(updateOverlays);
|
||||
isUpdateOverlaysWired = false;
|
||||
}
|
||||
removeOverlays();
|
||||
}
|
||||
function shutdown() {
|
||||
maybeEnableHMDPreview();
|
||||
deleteSendAssetParticleEffect();
|
||||
|
||||
Window.messageBoxClosed.disconnect(onMessageBoxClosed);
|
||||
Wallet.walletStatusChanged.disconnect(sendCommerceSettings);
|
||||
WalletScriptingInterface.walletStatusChanged.disconnect(sendCommerceSettings);
|
||||
ui.tablet.webEventReceived.disconnect(onWebEventReceived);
|
||||
GlobalServices.myUsernameChanged.disconnect(onUsernameChanged);
|
||||
Entities.canWriteAssetsChanged.disconnect(onCanWriteAssetsChanged);
|
||||
|
|
|
@ -634,7 +634,7 @@
|
|||
Window.notifyEditError = onEditError;
|
||||
Window.notify = onNotify;
|
||||
Tablet.tabletNotification.connect(tabletNotification);
|
||||
Wallet.walletNotSetup.connect(walletNotSetup);
|
||||
WalletScriptingInterface.walletNotSetup.connect(walletNotSetup);
|
||||
|
||||
Messages.subscribe(NOTIFICATIONS_MESSAGE_CHANNEL);
|
||||
Messages.messageReceived.connect(onMessageReceived);
|
||||
|
|
|
@ -844,7 +844,7 @@ function notificationPollCallback(connectionsArray) {
|
|||
newOnlineUsers++;
|
||||
storedOnlineUsers[user.username] = user;
|
||||
|
||||
if (!ui.isOpen && ui.notificationInitialCallbackMade) {
|
||||
if (!ui.isOpen && ui.notificationInitialCallbackMade[0]) {
|
||||
message = user.username + " is available in " +
|
||||
user.location.root.name + ". Open PEOPLE to join them.";
|
||||
ui.notificationDisplayBanner(message);
|
||||
|
@ -868,7 +868,7 @@ function notificationPollCallback(connectionsArray) {
|
|||
shouldShowDot: shouldShowDot
|
||||
});
|
||||
|
||||
if (newOnlineUsers > 0 && !ui.notificationInitialCallbackMade) {
|
||||
if (newOnlineUsers > 0 && !ui.notificationInitialCallbackMade[0]) {
|
||||
message = newOnlineUsers + " of your connections " +
|
||||
(newOnlineUsers === 1 ? "is" : "are") + " available online. Open PEOPLE to join them.";
|
||||
ui.notificationDisplayBanner(message);
|
||||
|
@ -889,12 +889,12 @@ function startup() {
|
|||
onOpened: palOpened,
|
||||
onClosed: off,
|
||||
onMessage: fromQml,
|
||||
notificationPollEndpoint: "/api/v1/users?filter=connections&status=online&per_page=10",
|
||||
notificationPollTimeoutMs: 60000,
|
||||
notificationDataProcessPage: notificationDataProcessPage,
|
||||
notificationPollCallback: notificationPollCallback,
|
||||
notificationPollStopPaginatingConditionMet: isReturnedDataEmpty,
|
||||
notificationPollCaresAboutSince: false
|
||||
notificationPollEndpoint: ["/api/v1/users?filter=connections&status=online&per_page=10"],
|
||||
notificationPollTimeoutMs: [60000],
|
||||
notificationDataProcessPage: [notificationDataProcessPage],
|
||||
notificationPollCallback: [notificationPollCallback],
|
||||
notificationPollStopPaginatingConditionMet: [isReturnedDataEmpty],
|
||||
notificationPollCaresAboutSince: [false]
|
||||
});
|
||||
Window.domainChanged.connect(clearLocalQMLDataAndClosePAL);
|
||||
Window.domainConnectionRefused.connect(clearLocalQMLDataAndClosePAL);
|
||||
|
|
|
@ -37,7 +37,7 @@ function notificationPollCallback(userStoriesArray) {
|
|||
//
|
||||
pingPong = !pingPong;
|
||||
var totalNewStories = 0;
|
||||
var shouldNotifyIndividually = !ui.isOpen && ui.notificationInitialCallbackMade;
|
||||
var shouldNotifyIndividually = !ui.isOpen && ui.notificationInitialCallbackMade[0];
|
||||
userStoriesArray.forEach(function (story) {
|
||||
if (story.audience !== "for_connections" &&
|
||||
story.audience !== "for_feed") {
|
||||
|
@ -91,7 +91,7 @@ function notificationPollCallback(userStoriesArray) {
|
|||
shouldShowDot = totalNewStories > 0 || (totalStories > 0 && shouldShowDot);
|
||||
ui.messagesWaiting(shouldShowDot && !ui.isOpen);
|
||||
|
||||
if (totalStories > 0 && !ui.isOpen && !ui.notificationInitialCallbackMade) {
|
||||
if (totalStories > 0 && !ui.isOpen && !ui.notificationInitialCallbackMade[0]) {
|
||||
message = "There " + (totalStories === 1 ? "is " : "are ") + totalStories + " event" +
|
||||
(totalStories === 1 ? "" : "s") + " to know about. " +
|
||||
"Open GOTO to see " + (totalStories === 1 ? "it" : "them") + ".";
|
||||
|
@ -122,12 +122,12 @@ function startup() {
|
|||
sortOrder: 8,
|
||||
onOpened: gotoOpened,
|
||||
home: GOTO_QML_SOURCE,
|
||||
notificationPollEndpoint: endpoint,
|
||||
notificationPollTimeoutMs: 60000,
|
||||
notificationDataProcessPage: notificationDataProcessPage,
|
||||
notificationPollCallback: notificationPollCallback,
|
||||
notificationPollStopPaginatingConditionMet: isReturnedDataEmpty,
|
||||
notificationPollCaresAboutSince: false
|
||||
notificationPollEndpoint: [endpoint],
|
||||
notificationPollTimeoutMs: [60000],
|
||||
notificationDataProcessPage: [notificationDataProcessPage],
|
||||
notificationPollCallback: [notificationPollCallback],
|
||||
notificationPollStopPaginatingConditionMet: [isReturnedDataEmpty],
|
||||
notificationPollCaresAboutSince: [false]
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -100,12 +100,12 @@ bool TestFbx::isReady() const {
|
|||
|
||||
void TestFbx::parseFbx(const QByteArray& fbxData) {
|
||||
QVariantHash mapping;
|
||||
HFMGeometry* geometry = readFBX(fbxData, mapping);
|
||||
HFMModel* hfmModel = readFBX(fbxData, mapping);
|
||||
size_t totalVertexCount = 0;
|
||||
size_t totalIndexCount = 0;
|
||||
size_t totalPartCount = 0;
|
||||
size_t highestIndex = 0;
|
||||
for (const auto& mesh : geometry->meshes) {
|
||||
for (const auto& mesh : hfmModel->meshes) {
|
||||
size_t vertexCount = mesh.vertices.size();
|
||||
totalVertexCount += mesh.vertices.size();
|
||||
highestIndex = std::max(highestIndex, vertexCount);
|
||||
|
@ -123,7 +123,7 @@ void TestFbx::parseFbx(const QByteArray& fbxData) {
|
|||
std::vector<DrawElementsIndirectCommand> parts;
|
||||
parts.reserve(totalPartCount);
|
||||
_partCount = totalPartCount;
|
||||
for (const auto& mesh : geometry->meshes) {
|
||||
for (const auto& mesh : hfmModel->meshes) {
|
||||
baseVertex = vertices.size();
|
||||
|
||||
vec3 color;
|
||||
|
@ -133,7 +133,7 @@ void TestFbx::parseFbx(const QByteArray& fbxData) {
|
|||
partIndirect.firstIndex = (uint)indices.size();
|
||||
partIndirect.baseInstance = (uint)parts.size();
|
||||
_partTransforms.push_back(mesh.modelTransform);
|
||||
auto material = geometry->materials[part.materialID];
|
||||
auto material = hfmModel->materials[part.materialID];
|
||||
color = material.diffuseColor;
|
||||
for (auto index : part.quadTrianglesIndices) {
|
||||
indices.push_back(index);
|
||||
|
@ -163,7 +163,7 @@ void TestFbx::parseFbx(const QByteArray& fbxData) {
|
|||
_vertexBuffer->append(vertices);
|
||||
_indexBuffer->append(indices);
|
||||
_indirectBuffer->append(parts);
|
||||
delete geometry;
|
||||
delete hfmModel;
|
||||
}
|
||||
|
||||
void TestFbx::renderTest(size_t testId, RenderArgs* args) {
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include <render/ShapePipeline.h>
|
||||
|
||||
class HFMGeometry;
|
||||
class HFMModel;
|
||||
|
||||
class TestFbx : public GpuTestBase {
|
||||
size_t _partCount { 0 };
|
||||
|
|
|
@ -28,7 +28,7 @@ const glm::quat identity = glm::quat();
|
|||
const glm::quat quaterTurnAroundZ = glm::angleAxis(0.5f * PI, zAxis);
|
||||
|
||||
|
||||
void makeTestFBXJoints(HFMGeometry& geometry) {
|
||||
void makeTestFBXJoints(HFMModel& hfmModel) {
|
||||
HFMJoint joint;
|
||||
joint.isFree = false;
|
||||
joint.freeLineage.clear();
|
||||
|
@ -60,29 +60,29 @@ void makeTestFBXJoints(HFMGeometry& geometry) {
|
|||
joint.name = "A";
|
||||
joint.parentIndex = -1;
|
||||
joint.translation = origin;
|
||||
geometry.joints.push_back(joint);
|
||||
hfmModel.joints.push_back(joint);
|
||||
|
||||
joint.name = "B";
|
||||
joint.parentIndex = 0;
|
||||
joint.translation = xAxis;
|
||||
geometry.joints.push_back(joint);
|
||||
hfmModel.joints.push_back(joint);
|
||||
|
||||
joint.name = "C";
|
||||
joint.parentIndex = 1;
|
||||
joint.translation = xAxis;
|
||||
geometry.joints.push_back(joint);
|
||||
hfmModel.joints.push_back(joint);
|
||||
|
||||
joint.name = "D";
|
||||
joint.parentIndex = 2;
|
||||
joint.translation = xAxis;
|
||||
geometry.joints.push_back(joint);
|
||||
hfmModel.joints.push_back(joint);
|
||||
|
||||
// compute each joint's transform
|
||||
for (int i = 1; i < (int)geometry.joints.size(); ++i) {
|
||||
HFMJoint& j = geometry.joints[i];
|
||||
for (int i = 1; i < (int)hfmModel.joints.size(); ++i) {
|
||||
HFMJoint& j = hfmModel.joints[i];
|
||||
int parentIndex = j.parentIndex;
|
||||
// World = ParentWorld * T * (Roff * Rp) * Rpre * R * Rpost * (Rp-1 * Soff * Sp * S * Sp-1)
|
||||
j.transform = geometry.joints[parentIndex].transform *
|
||||
j.transform = hfmModel.joints[parentIndex].transform *
|
||||
glm::translate(j.translation) *
|
||||
j.preTransform *
|
||||
glm::mat4_cast(j.preRotation * j.rotation * j.postRotation) *
|
||||
|
@ -96,12 +96,12 @@ void AnimInverseKinematicsTests::testSingleChain() {
|
|||
|
||||
AnimContext context(false, false, false, glm::mat4(), glm::mat4());
|
||||
|
||||
HFMGeometry geometry;
|
||||
makeTestFBXJoints(geometry);
|
||||
HFMModel hfmModel;
|
||||
makeTestFBXJoints(hfmModel);
|
||||
|
||||
// create a skeleton and doll
|
||||
AnimPose offset;
|
||||
AnimSkeleton::Pointer skeletonPtr = std::make_shared<AnimSkeleton>(geometry);
|
||||
AnimSkeleton::Pointer skeletonPtr = std::make_shared<AnimSkeleton>(hfmModel);
|
||||
AnimInverseKinematics ikDoll("doll");
|
||||
|
||||
ikDoll.setSkeleton(skeletonPtr);
|
||||
|
@ -119,7 +119,7 @@ void AnimInverseKinematicsTests::testSingleChain() {
|
|||
poses.push_back(pose);
|
||||
|
||||
pose.trans() = xAxis;
|
||||
for (int i = 1; i < (int)geometry.joints.size(); ++i) {
|
||||
for (int i = 1; i < (int)hfmModel.joints.size(); ++i) {
|
||||
poses.push_back(pose);
|
||||
}
|
||||
ikDoll.loadPoses(poses);
|
||||
|
|
|
@ -54,7 +54,7 @@ SkeletonDumpApp::SkeletonDumpApp(int argc, char* argv[]) : QCoreApplication(argc
|
|||
return;
|
||||
}
|
||||
QByteArray blob = file.readAll();
|
||||
std::unique_ptr<HFMGeometry> geometry(readFBX(blob, QVariantHash()));
|
||||
std::unique_ptr<HFMModel> geometry(readFBX(blob, QVariantHash()));
|
||||
std::unique_ptr<AnimSkeleton> skeleton(new AnimSkeleton(*geometry));
|
||||
skeleton->dump(verbose);
|
||||
}
|
||||
|
|
|
@ -19,16 +19,16 @@
|
|||
|
||||
// FBXReader jumbles the order of the meshes by reading them back out of a hashtable. This will put
|
||||
// them back in the order in which they appeared in the file.
|
||||
bool HFMGeometryLessThan(const HFMMesh& e1, const HFMMesh& e2) {
|
||||
bool HFMModelLessThan(const HFMMesh& e1, const HFMMesh& e2) {
|
||||
return e1.meshIndex < e2.meshIndex;
|
||||
}
|
||||
void reSortHFMGeometryMeshes(HFMGeometry& geometry) {
|
||||
qSort(geometry.meshes.begin(), geometry.meshes.end(), HFMGeometryLessThan);
|
||||
void reSortHFMModelMeshes(HFMModel& hfmModel) {
|
||||
qSort(hfmModel.meshes.begin(), hfmModel.meshes.end(), HFMModelLessThan);
|
||||
}
|
||||
|
||||
|
||||
// Read all the meshes from provided FBX file
|
||||
bool vhacd::VHACDUtil::loadFBX(const QString filename, HFMGeometry& result) {
|
||||
bool vhacd::VHACDUtil::loadFBX(const QString filename, HFMModel& result) {
|
||||
if (_verbose) {
|
||||
qDebug() << "reading FBX file =" << filename << "...";
|
||||
}
|
||||
|
@ -41,19 +41,19 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, HFMGeometry& result) {
|
|||
}
|
||||
try {
|
||||
QByteArray fbxContents = fbx.readAll();
|
||||
HFMGeometry::Pointer geom;
|
||||
HFMModel::Pointer hfmModel;
|
||||
if (filename.toLower().endsWith(".obj")) {
|
||||
bool combineParts = false;
|
||||
geom = OBJReader().readOBJ(fbxContents, QVariantHash(), combineParts);
|
||||
hfmModel = OBJReader().readOBJ(fbxContents, QVariantHash(), combineParts);
|
||||
} else if (filename.toLower().endsWith(".fbx")) {
|
||||
geom.reset(readFBX(fbxContents, QVariantHash(), filename));
|
||||
hfmModel.reset(readFBX(fbxContents, QVariantHash(), filename));
|
||||
} else {
|
||||
qWarning() << "file has unknown extension" << filename;
|
||||
return false;
|
||||
}
|
||||
result = *geom;
|
||||
result = *hfmModel;
|
||||
|
||||
reSortHFMGeometryMeshes(result);
|
||||
reSortHFMModelMeshes(result);
|
||||
} catch (const QString& error) {
|
||||
qWarning() << "error reading" << filename << ":" << error;
|
||||
return false;
|
||||
|
@ -88,7 +88,7 @@ void getTrianglesInMeshPart(const HFMMeshPart &meshPart, std::vector<int>& trian
|
|||
}
|
||||
}
|
||||
|
||||
void vhacd::VHACDUtil::fattenMesh(const HFMMesh& mesh, const glm::mat4& geometryOffset, HFMMesh& result) const {
|
||||
void vhacd::VHACDUtil::fattenMesh(const HFMMesh& mesh, const glm::mat4& modelOffset, HFMMesh& result) const {
|
||||
// this is used to make meshes generated from a highfield collidable. each triangle
|
||||
// is converted into a tetrahedron and made into its own mesh-part.
|
||||
|
||||
|
@ -104,7 +104,7 @@ void vhacd::VHACDUtil::fattenMesh(const HFMMesh& mesh, const glm::mat4& geometry
|
|||
int indexStartOffset = result.vertices.size();
|
||||
|
||||
// new mesh gets the transformed points from the original
|
||||
glm::mat4 totalTransform = geometryOffset * mesh.modelTransform;
|
||||
glm::mat4 totalTransform = modelOffset * mesh.modelTransform;
|
||||
for (int i = 0; i < mesh.vertices.size(); i++) {
|
||||
// apply the source mesh's transform to the points
|
||||
glm::vec4 v = totalTransform * glm::vec4(mesh.vertices[i], 1.0f);
|
||||
|
@ -288,17 +288,17 @@ float computeDt(uint64_t start) {
|
|||
return (float)(usecTimestampNow() - start) / (float)USECS_PER_SECOND;
|
||||
}
|
||||
|
||||
bool vhacd::VHACDUtil::computeVHACD(HFMGeometry& geometry,
|
||||
bool vhacd::VHACDUtil::computeVHACD(HFMModel& hfmModel,
|
||||
VHACD::IVHACD::Parameters params,
|
||||
HFMGeometry& result,
|
||||
HFMModel& result,
|
||||
float minimumMeshSize, float maximumMeshSize) {
|
||||
if (_verbose) {
|
||||
qDebug() << "meshes =" << geometry.meshes.size();
|
||||
qDebug() << "meshes =" << hfmModel.meshes.size();
|
||||
}
|
||||
|
||||
// count the mesh-parts
|
||||
int numParts = 0;
|
||||
foreach (const HFMMesh& mesh, geometry.meshes) {
|
||||
foreach (const HFMMesh& mesh, hfmModel.meshes) {
|
||||
numParts += mesh.parts.size();
|
||||
}
|
||||
if (_verbose) {
|
||||
|
@ -316,7 +316,7 @@ bool vhacd::VHACDUtil::computeVHACD(HFMGeometry& geometry,
|
|||
|
||||
int meshIndex = 0;
|
||||
int validPartsFound = 0;
|
||||
foreach (const HFMMesh& mesh, geometry.meshes) {
|
||||
foreach (const HFMMesh& mesh, hfmModel.meshes) {
|
||||
|
||||
// find duplicate points
|
||||
int numDupes = 0;
|
||||
|
@ -337,7 +337,7 @@ bool vhacd::VHACDUtil::computeVHACD(HFMGeometry& geometry,
|
|||
|
||||
// each mesh has its own transform to move it to model-space
|
||||
std::vector<glm::vec3> vertices;
|
||||
glm::mat4 totalTransform = geometry.offset * mesh.modelTransform;
|
||||
glm::mat4 totalTransform = hfmModel.offset * mesh.modelTransform;
|
||||
foreach (glm::vec3 vertex, mesh.vertices) {
|
||||
vertices.push_back(glm::vec3(totalTransform * glm::vec4(vertex, 1.0f)));
|
||||
}
|
||||
|
|
|
@ -27,13 +27,13 @@ namespace vhacd {
|
|||
public:
|
||||
void setVerbose(bool verbose) { _verbose = verbose; }
|
||||
|
||||
bool loadFBX(const QString filename, HFMGeometry& result);
|
||||
bool loadFBX(const QString filename, HFMModel& result);
|
||||
|
||||
void fattenMesh(const HFMMesh& mesh, const glm::mat4& gometryOffset, HFMMesh& result) const;
|
||||
void fattenMesh(const HFMMesh& mesh, const glm::mat4& modelOffset, HFMMesh& result) const;
|
||||
|
||||
bool computeVHACD(HFMGeometry& geometry,
|
||||
bool computeVHACD(HFMModel& hfmModel,
|
||||
VHACD::IVHACD::Parameters params,
|
||||
HFMGeometry& result,
|
||||
HFMModel& result,
|
||||
float minimumMeshSize, float maximumMeshSize);
|
||||
|
||||
void getConvexResults(VHACD::IVHACD* convexifier, HFMMesh& resultMesh) const;
|
||||
|
|
|
@ -36,7 +36,7 @@ QString formatFloat(double n) {
|
|||
}
|
||||
|
||||
|
||||
bool VHACDUtilApp::writeOBJ(QString outFileName, HFMGeometry& geometry, bool outputCentimeters, int whichMeshPart) {
|
||||
bool VHACDUtilApp::writeOBJ(QString outFileName, HFMModel& hfmModel, bool outputCentimeters, int whichMeshPart) {
|
||||
QFile file(outFileName);
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
qWarning() << "unable to write to" << outFileName;
|
||||
|
@ -56,7 +56,7 @@ bool VHACDUtilApp::writeOBJ(QString outFileName, HFMGeometry& geometry, bool out
|
|||
|
||||
int vertexIndexOffset = 0;
|
||||
|
||||
foreach (const HFMMesh& mesh, geometry.meshes) {
|
||||
foreach (const HFMMesh& mesh, hfmModel.meshes) {
|
||||
bool verticesHaveBeenOutput = false;
|
||||
foreach (const HFMMeshPart &meshPart, mesh.parts) {
|
||||
if (whichMeshPart >= 0 && nth != (unsigned int) whichMeshPart) {
|
||||
|
@ -297,7 +297,7 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
|
|||
}
|
||||
|
||||
// load the mesh
|
||||
HFMGeometry fbx;
|
||||
HFMModel fbx;
|
||||
auto begin = std::chrono::high_resolution_clock::now();
|
||||
if (!vUtil.loadFBX(inputFilename, fbx)){
|
||||
_returnCode = VHACD_RETURN_CODE_FAILURE_TO_READ;
|
||||
|
@ -358,7 +358,7 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
|
|||
}
|
||||
begin = std::chrono::high_resolution_clock::now();
|
||||
|
||||
HFMGeometry result;
|
||||
HFMModel result;
|
||||
bool success = vUtil.computeVHACD(fbx, params, result, minimumMeshSize, maximumMeshSize);
|
||||
|
||||
end = std::chrono::high_resolution_clock::now();
|
||||
|
@ -398,7 +398,7 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
|
|||
}
|
||||
|
||||
if (fattenFaces) {
|
||||
HFMGeometry newFbx;
|
||||
HFMModel newFbx;
|
||||
HFMMesh result;
|
||||
|
||||
// count the mesh-parts
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
VHACDUtilApp(int argc, char* argv[]);
|
||||
~VHACDUtilApp();
|
||||
|
||||
bool writeOBJ(QString outFileName, HFMGeometry& geometry, bool outputCentimeters, int whichMeshPart = -1);
|
||||
bool writeOBJ(QString outFileName, HFMModel& hfmModel, bool outputCentimeters, int whichMeshPart = -1);
|
||||
|
||||
int getReturnCode() const { return _returnCode; }
|
||||
|
||||
|
|