Merge branch 'master' of https://github.com/highfidelity/hifi into loginInitiative2
|
@ -69,10 +69,10 @@ void ScriptableAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
|||
AvatarData::setSkeletonModelURL(skeletonModelURL);
|
||||
}
|
||||
|
||||
static AnimPose composeAnimPose(const FBXJoint& fbxJoint, const glm::quat rotation, const glm::vec3 translation) {
|
||||
static AnimPose composeAnimPose(const HFMJoint& joint, const glm::quat rotation, const glm::vec3 translation) {
|
||||
glm::mat4 translationMat = glm::translate(translation);
|
||||
glm::mat4 rotationMat = glm::mat4_cast(fbxJoint.preRotation * rotation * fbxJoint.postRotation);
|
||||
glm::mat4 finalMat = translationMat * fbxJoint.preTransform * rotationMat * fbxJoint.postTransform;
|
||||
glm::mat4 rotationMat = glm::mat4_cast(joint.preRotation * rotation * joint.postRotation);
|
||||
glm::mat4 finalMat = translationMat * joint.preTransform * rotationMat * joint.postTransform;
|
||||
return AnimPose(finalMat);
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ void ScriptableAvatar::update(float deltatime) {
|
|||
}
|
||||
_animationDetails.currentFrame = currentFrame;
|
||||
|
||||
const QVector<FBXJoint>& modelJoints = _bind->getGeometry().joints;
|
||||
const QVector<HFMJoint>& modelJoints = _bind->getGeometry().joints;
|
||||
QStringList animationJointNames = _animation->getJointNames();
|
||||
|
||||
const int nJoints = modelJoints.size();
|
||||
|
@ -102,8 +102,8 @@ void ScriptableAvatar::update(float deltatime) {
|
|||
}
|
||||
|
||||
const int frameCount = _animation->getFrames().size();
|
||||
const FBXAnimationFrame& floorFrame = _animation->getFrames().at((int)glm::floor(currentFrame) % frameCount);
|
||||
const FBXAnimationFrame& ceilFrame = _animation->getFrames().at((int)glm::ceil(currentFrame) % frameCount);
|
||||
const HFMAnimationFrame& floorFrame = _animation->getFrames().at((int)glm::floor(currentFrame) % frameCount);
|
||||
const HFMAnimationFrame& ceilFrame = _animation->getFrames().at((int)glm::ceil(currentFrame) % frameCount);
|
||||
const float frameFraction = glm::fract(currentFrame);
|
||||
std::vector<AnimPose> poses = _animSkeleton->getRelativeDefaultPoses();
|
||||
|
||||
|
|
|
@ -157,6 +157,11 @@ Item {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
Settings.setValue("keepMeLoggedIn/savedUsername", usernameField.text);
|
||||
linkAccountBody.login();
|
||||
}
|
||||
}
|
||||
Item {
|
||||
id: bottomContainer
|
||||
|
|
|
@ -86,7 +86,7 @@ Item {
|
|||
loginButtonAtSignIn.text = "Log In";
|
||||
loginButtonAtSignIn.color = hifi.buttons.black;
|
||||
emailField.placeholderText = "Username or Email";
|
||||
var savedUsername = Settings.getValue("wallet/savedUsername", "");
|
||||
var savedUsername = Settings.getValue("keepMeLoggedIn/savedUsername", "");
|
||||
emailField.text = savedUsername === "Unknown user" ? "" : savedUsername;
|
||||
emailField.anchors.top = loginContainer.top;
|
||||
emailField.anchors.topMargin = !root.isTablet ? 0.2 * root.height : 0.24 * root.height;
|
||||
|
@ -209,7 +209,6 @@ Item {
|
|||
width: banner.width
|
||||
height: signInBody.textFieldHeight
|
||||
font.family: signInBody.fontFamily
|
||||
text: Settings.getValue("wallet/savedUsername", "");
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
|
@ -311,8 +310,8 @@ Item {
|
|||
}
|
||||
HifiControlsUit.CheckBox {
|
||||
id: autoLogoutCheckbox
|
||||
checked: !Settings.getValue("wallet/autoLogout", false);
|
||||
text: qsTr("Keep Me Logged In")
|
||||
checked: Settings.getValue("keepMeLoggedIn", false);
|
||||
text: qsTr("Keep Me Logged In");
|
||||
boxSize: 18;
|
||||
labelFontFamily: signInBody.fontFamily
|
||||
labelFontSize: 18;
|
||||
|
@ -323,15 +322,17 @@ Item {
|
|||
right: passwordField.right;
|
||||
}
|
||||
onCheckedChanged: {
|
||||
Settings.setValue("wallet/autoLogout", !checked);
|
||||
Settings.setValue("keepMeLoggedIn", checked);
|
||||
if (checked) {
|
||||
Settings.setValue("wallet/savedUsername", Account.username);
|
||||
Settings.setValue("keepMeLoggedIn/savedUsername", Account.username);
|
||||
var savedUsername = Settings.getValue("keepMeLoggedIn/savedUsername", "");
|
||||
usernameField.text = savedUsername === "Unknown user" ? "" : savedUsername;
|
||||
} else {
|
||||
Settings.setValue("wallet/savedUsername", "");
|
||||
Settings.setValue("keepMeLoggedIn/savedUsername", "");
|
||||
}
|
||||
}
|
||||
Component.onDestruction: {
|
||||
Settings.setValue("wallet/autoLogout", !checked);
|
||||
Settings.setValue("keepMeLoggedIn", checked);
|
||||
}
|
||||
}
|
||||
Item {
|
||||
|
@ -431,6 +432,11 @@ Item {
|
|||
case Qt.Key_Enter:
|
||||
case Qt.Key_Return:
|
||||
event.accepted = true;
|
||||
if (loginDialog.isLogIn) {
|
||||
Settings.setValue("keepMeLoggedIn/savedUsername", emailField.text);
|
||||
} else {
|
||||
Settings.setValue("keepMeLoggedIn/savedUsername", usernameField.text);
|
||||
}
|
||||
signInBody.login();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
import Hifi 1.0 as Hifi
|
||||
import QtQuick 2.5
|
||||
import QtGraphicalEffects 1.0
|
||||
import "../../../styles-uit"
|
||||
import "../../../controls-uit" as HifiControlsUit
|
||||
import "../../../controls" as HifiControls
|
||||
import "qrc:////qml//styles-uit"
|
||||
import "qrc:////qml//controls-uit" as HifiControlsUit
|
||||
import "qrc:////qml//controls" as HifiControls
|
||||
|
||||
// references XXX from root context
|
||||
|
||||
|
@ -33,13 +33,15 @@ Rectangle {
|
|||
property string buttonLayout: "leftright";
|
||||
|
||||
readonly property string securityPicBodyText: "When you see your Security Pic, your actions and data are securely making use of your " +
|
||||
"Wallet's private keys.<br><br>You can change your Security Pic in your Wallet.";
|
||||
"private keys.<br><br>You can change your Security Pic via Settings > Security...";
|
||||
|
||||
id: root;
|
||||
visible: false;
|
||||
anchors.fill: parent;
|
||||
color: Qt.rgba(0, 0, 0, 0.5);
|
||||
z: 999;
|
||||
|
||||
HifiConstants { id: hifi; }
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible) {
|
||||
|
|
|
@ -74,8 +74,7 @@ In your Wallet's Send Money tab, choose from your list of connections, or choose
|
|||
isExpanded: false;
|
||||
question: "What is a Security Pic?"
|
||||
answer: "Your Security Pic acts as an extra layer of Wallet security. \
|
||||
When you see your Security Pic, you know that your actions and data are securely making use of your account. \
|
||||
<br><br><b><font color='#0093C5'><a href='#securitypic'>Tap here to change your Security Pic.</a></font></b>";
|
||||
When you see your Security Pic, you know that your actions and data are securely making use of your account.";
|
||||
}
|
||||
ListElement {
|
||||
isExpanded: false;
|
||||
|
@ -137,7 +136,7 @@ At the moment, there is currently no way to convert HFC to other currencies. Sta
|
|||
anchors.left: parent.left;
|
||||
width: parent.width;
|
||||
height: questionText.paintedHeight + 50;
|
||||
|
||||
|
||||
RalewaySemiBold {
|
||||
id: plusMinusButton;
|
||||
text: model.isExpanded ? "-" : "+";
|
||||
|
@ -217,8 +216,6 @@ At the moment, there is currently no way to convert HFC to other currencies. Sta
|
|||
}
|
||||
} else if (link === "#support") {
|
||||
Qt.openUrlExternally("mailto:support@highfidelity.com");
|
||||
} else if (link === "#securitypic") {
|
||||
sendSignalToWallet({method: 'walletSecurity_changeSecurityImage'});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,246 +0,0 @@
|
|||
//
|
||||
// Security.qml
|
||||
// qml/hifi/commerce/wallet
|
||||
//
|
||||
// Security
|
||||
//
|
||||
// Created by Zach Fox on 2017-08-18
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import Hifi 1.0 as Hifi
|
||||
import QtQuick 2.5
|
||||
import QtGraphicalEffects 1.0
|
||||
import "../../../styles-uit"
|
||||
import "../../../controls-uit" as HifiControlsUit
|
||||
import "../../../controls" as HifiControls
|
||||
|
||||
// references XXX from root context
|
||||
|
||||
Item {
|
||||
HifiConstants { id: hifi; }
|
||||
|
||||
id: root;
|
||||
property string keyFilePath;
|
||||
|
||||
Connections {
|
||||
target: Commerce;
|
||||
|
||||
onKeyFilePathIfExistsResult: {
|
||||
root.keyFilePath = path;
|
||||
}
|
||||
}
|
||||
|
||||
// Username Text
|
||||
RalewayRegular {
|
||||
id: usernameText;
|
||||
text: Account.username;
|
||||
// Text size
|
||||
size: 24;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
elide: Text.ElideRight;
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 20;
|
||||
width: parent.width/2;
|
||||
height: 80;
|
||||
}
|
||||
|
||||
Item {
|
||||
id: securityContainer;
|
||||
anchors.top: usernameText.bottom;
|
||||
anchors.topMargin: 20;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
anchors.bottom: parent.bottom;
|
||||
|
||||
RalewaySemiBold {
|
||||
id: securityText;
|
||||
text: "Security";
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 20;
|
||||
anchors.right: parent.right;
|
||||
height: 30;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.blueHighlight;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: securityTextSeparator;
|
||||
// Size
|
||||
width: parent.width;
|
||||
height: 1;
|
||||
// Anchors
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
anchors.top: securityText.bottom;
|
||||
anchors.topMargin: 8;
|
||||
// Style
|
||||
color: hifi.colors.faintGray;
|
||||
}
|
||||
|
||||
Item {
|
||||
id: changeSecurityImageContainer;
|
||||
anchors.top: securityTextSeparator.bottom;
|
||||
anchors.topMargin: 8;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 40;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 55;
|
||||
height: 75;
|
||||
|
||||
HiFiGlyphs {
|
||||
id: changeSecurityImageImage;
|
||||
text: hifi.glyphs.securityImage;
|
||||
// Size
|
||||
size: 80;
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.left: parent.left;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
text: "Security Pic";
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.left: changeSecurityImageImage.right;
|
||||
anchors.leftMargin: 30;
|
||||
width: 50;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
}
|
||||
|
||||
// "Change Security Pic" button
|
||||
HifiControlsUit.Button {
|
||||
id: changeSecurityImageButton;
|
||||
color: hifi.buttons.blue;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.right: parent.right;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
width: 140;
|
||||
height: 40;
|
||||
text: "Change";
|
||||
onClicked: {
|
||||
sendSignalToWallet({method: 'walletSecurity_changeSecurityImage'});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: autoLogoutContainer;
|
||||
anchors.top: changeSecurityImageContainer.bottom;
|
||||
anchors.topMargin: 8;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 40;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 55;
|
||||
height: 75;
|
||||
|
||||
HiFiGlyphs {
|
||||
id: autoLogoutImage;
|
||||
text: hifi.glyphs.walletKey;
|
||||
// Size
|
||||
size: 80;
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: 20;
|
||||
anchors.left: parent.left;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
}
|
||||
|
||||
HifiControlsUit.CheckBox {
|
||||
id: autoLogoutCheckbox;
|
||||
checked: Settings.getValue("wallet/autoLogout", false);
|
||||
text: "Automatically Log Out when Exiting Interface"
|
||||
// Anchors
|
||||
anchors.verticalCenter: autoLogoutImage.verticalCenter;
|
||||
anchors.left: autoLogoutImage.right;
|
||||
anchors.leftMargin: 20;
|
||||
anchors.right: autoLogoutHelp.left;
|
||||
anchors.rightMargin: 12;
|
||||
boxSize: 28;
|
||||
labelFontSize: 18;
|
||||
color: hifi.colors.white;
|
||||
onCheckedChanged: {
|
||||
Settings.setValue("wallet/autoLogout", checked);
|
||||
if (checked) {
|
||||
Settings.setValue("wallet/savedUsername", Account.username);
|
||||
} else {
|
||||
Settings.setValue("wallet/savedUsername", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
id: autoLogoutHelp;
|
||||
text: '[?]';
|
||||
// Anchors
|
||||
anchors.verticalCenter: autoLogoutImage.verticalCenter;
|
||||
anchors.right: parent.right;
|
||||
width: 30;
|
||||
height: 30;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.blueHighlight;
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
hoverEnabled: true;
|
||||
onEntered: {
|
||||
parent.color = hifi.colors.blueAccent;
|
||||
}
|
||||
onExited: {
|
||||
parent.color = hifi.colors.blueHighlight;
|
||||
}
|
||||
onClicked: {
|
||||
sendSignalToWallet({method: 'walletSecurity_autoLogoutHelp'});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// FUNCTION DEFINITIONS START
|
||||
//
|
||||
//
|
||||
// Function Name: fromScript()
|
||||
//
|
||||
// Relevant Variables:
|
||||
// None
|
||||
//
|
||||
// Arguments:
|
||||
// message: The message sent from the JavaScript.
|
||||
// Messages are in format "{method, params}", like json-rpc.
|
||||
//
|
||||
// Description:
|
||||
// Called when a message is received from a script.
|
||||
//
|
||||
function fromScript(message) {
|
||||
switch (message.method) {
|
||||
default:
|
||||
console.log('Unrecognized message from wallet.js:', JSON.stringify(message));
|
||||
}
|
||||
}
|
||||
signal sendSignalToWallet(var msg);
|
||||
//
|
||||
// FUNCTION DEFINITIONS END
|
||||
//
|
||||
}
|
|
@ -142,7 +142,7 @@ Rectangle {
|
|||
Image {
|
||||
id: titleBarSecurityImage;
|
||||
source: "";
|
||||
visible: titleBarSecurityImage.source !== "" && !securityImageChange.visible;
|
||||
visible: titleBarSecurityImage.source !== "";
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 6;
|
||||
anchors.top: parent.top;
|
||||
|
@ -232,10 +232,6 @@ Rectangle {
|
|||
root.isPassword = msg.isPasswordField;
|
||||
} else if (msg.method === 'walletSetup_lowerKeyboard') {
|
||||
root.keyboardRaised = false;
|
||||
} else if (msg.method === 'walletSecurity_changePassphraseCancelled') {
|
||||
root.activeView = "security";
|
||||
} else if (msg.method === 'walletSecurity_changePassphraseSuccess') {
|
||||
root.activeView = "security";
|
||||
} else {
|
||||
sendToScript(msg);
|
||||
}
|
||||
|
@ -245,27 +241,6 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
}
|
||||
SecurityImageChange {
|
||||
id: securityImageChange;
|
||||
visible: root.activeView === "securityImageChange";
|
||||
z: 997;
|
||||
anchors.top: titleBarContainer.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
anchors.bottom: parent.bottom;
|
||||
|
||||
Connections {
|
||||
onSendSignalToWallet: {
|
||||
if (msg.method === 'walletSecurity_changeSecurityImageCancelled') {
|
||||
root.activeView = "security";
|
||||
} else if (msg.method === 'walletSecurity_changeSecurityImageSuccess') {
|
||||
root.activeView = "security";
|
||||
} else {
|
||||
sendToScript(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// TAB CONTENTS START
|
||||
|
@ -366,39 +341,6 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
Security {
|
||||
id: security;
|
||||
visible: root.activeView === "security";
|
||||
anchors.top: titleBarContainer.bottom;
|
||||
anchors.bottom: tabButtonsContainer.top;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
|
||||
Connections {
|
||||
onSendSignalToWallet: {
|
||||
if (msg.method === 'walletSecurity_changePassphrase') {
|
||||
root.activeView = "passphraseChange";
|
||||
passphraseChange.clearPassphraseFields();
|
||||
passphraseChange.resetSubmitButton();
|
||||
} else if (msg.method === 'walletSecurity_changeSecurityImage') {
|
||||
securityImageChange.initModel();
|
||||
root.activeView = "securityImageChange";
|
||||
} else if (msg.method === 'walletSecurity_autoLogoutHelp') {
|
||||
lightboxPopup.titleText = "Automatically Log Out";
|
||||
lightboxPopup.bodyText = "By default, after you log in to High Fidelity, you will stay logged in to your High Fidelity " +
|
||||
"account even after you close and re-open Interface. This means anyone who opens Interface on your computer " +
|
||||
"could make purchases with your Wallet.\n\n" +
|
||||
"If you do not want to stay logged in across Interface sessions, check this box.";
|
||||
lightboxPopup.button1text = "CLOSE";
|
||||
lightboxPopup.button1method = function() {
|
||||
lightboxPopup.visible = false;
|
||||
}
|
||||
lightboxPopup.visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Help {
|
||||
id: help;
|
||||
visible: root.activeView === "help";
|
||||
|
@ -407,14 +349,6 @@ Rectangle {
|
|||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
|
||||
Connections {
|
||||
onSendSignalToWallet: {
|
||||
if (msg.method === 'walletSecurity_changeSecurityImage') {
|
||||
securityImageChange.initModel();
|
||||
root.activeView = "securityImageChange";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -427,8 +361,8 @@ Rectangle {
|
|||
//
|
||||
Item {
|
||||
id: tabButtonsContainer;
|
||||
visible: !needsLogIn.visible && root.activeView !== "passphraseChange" && root.activeView !== "securityImageChange" && sendMoney.currentActiveView !== "sendAssetStep";
|
||||
property int numTabs: 5;
|
||||
visible: !needsLogIn.visible && root.activeView !== "passphraseChange" && sendMoney.currentActiveView !== "sendAssetStep";
|
||||
property int numTabs: 4;
|
||||
// Size
|
||||
width: root.width;
|
||||
height: 90;
|
||||
|
@ -452,7 +386,7 @@ Rectangle {
|
|||
anchors.left: parent.left;
|
||||
anchors.bottom: parent.bottom;
|
||||
width: parent.width / tabButtonsContainer.numTabs;
|
||||
|
||||
|
||||
HiFiGlyphs {
|
||||
id: homeTabIcon;
|
||||
text: hifi.glyphs.home2;
|
||||
|
@ -506,7 +440,7 @@ Rectangle {
|
|||
anchors.left: walletHomeButtonContainer.right;
|
||||
anchors.bottom: parent.bottom;
|
||||
width: parent.width / tabButtonsContainer.numTabs;
|
||||
|
||||
|
||||
HiFiGlyphs {
|
||||
id: exchangeMoneyTabIcon;
|
||||
text: hifi.glyphs.leftRightArrows;
|
||||
|
@ -550,7 +484,7 @@ Rectangle {
|
|||
anchors.left: exchangeMoneyButtonContainer.right;
|
||||
anchors.bottom: parent.bottom;
|
||||
width: parent.width / tabButtonsContainer.numTabs;
|
||||
|
||||
|
||||
HiFiGlyphs {
|
||||
id: sendMoneyTabIcon;
|
||||
text: hifi.glyphs.paperPlane;
|
||||
|
@ -596,70 +530,16 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
|
||||
// "SECURITY" tab button
|
||||
Rectangle {
|
||||
id: securityButtonContainer;
|
||||
visible: !walletSetup.visible;
|
||||
color: root.activeView === "security" ? hifi.colors.blueAccent : hifi.colors.black;
|
||||
anchors.top: parent.top;
|
||||
anchors.left: sendMoneyButtonContainer.right;
|
||||
anchors.bottom: parent.bottom;
|
||||
width: parent.width / tabButtonsContainer.numTabs;
|
||||
|
||||
HiFiGlyphs {
|
||||
id: securityTabIcon;
|
||||
text: hifi.glyphs.lock;
|
||||
// Size
|
||||
size: 38;
|
||||
// Anchors
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: 2;
|
||||
// Style
|
||||
color: root.activeView === "security" || securityTabMouseArea.containsMouse ? hifi.colors.white : hifi.colors.blueHighlight;
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
text: "SECURITY";
|
||||
// Text size
|
||||
size: 16;
|
||||
// Anchors
|
||||
anchors.bottom: parent.bottom;
|
||||
height: parent.height/2;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 4;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 4;
|
||||
// Style
|
||||
color: root.activeView === "security" || securityTabMouseArea.containsMouse ? hifi.colors.white : hifi.colors.blueHighlight;
|
||||
wrapMode: Text.WordWrap;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
verticalAlignment: Text.AlignTop;
|
||||
}
|
||||
MouseArea {
|
||||
id: securityTabMouseArea;
|
||||
anchors.fill: parent;
|
||||
hoverEnabled: enabled;
|
||||
onClicked: {
|
||||
root.activeView = "security";
|
||||
tabButtonsContainer.resetTabButtonColors();
|
||||
}
|
||||
onEntered: parent.color = hifi.colors.blueHighlight;
|
||||
onExited: parent.color = root.activeView === "security" ? hifi.colors.blueAccent : hifi.colors.black;
|
||||
}
|
||||
}
|
||||
|
||||
// "HELP" tab button
|
||||
Rectangle {
|
||||
id: helpButtonContainer;
|
||||
visible: !walletSetup.visible;
|
||||
color: root.activeView === "help" ? hifi.colors.blueAccent : hifi.colors.black;
|
||||
anchors.top: parent.top;
|
||||
anchors.left: securityButtonContainer.right;
|
||||
anchors.left: sendMoneyButtonContainer.right;
|
||||
anchors.bottom: parent.bottom;
|
||||
width: parent.width / tabButtonsContainer.numTabs;
|
||||
|
||||
|
||||
HiFiGlyphs {
|
||||
id: helpTabIcon;
|
||||
text: hifi.glyphs.question;
|
||||
|
|
|
@ -243,7 +243,6 @@ Item {
|
|||
height: 50;
|
||||
text: "Set Up Wallet";
|
||||
onClicked: {
|
||||
securityImageSelection.initModel();
|
||||
root.activeView = "step_2";
|
||||
}
|
||||
}
|
||||
|
@ -267,124 +266,6 @@ Item {
|
|||
// FIRST PAGE END
|
||||
//
|
||||
|
||||
//
|
||||
// SECURITY IMAGE SELECTION START
|
||||
//
|
||||
Item {
|
||||
id: securityImageContainer;
|
||||
visible: root.activeView === "step_2";
|
||||
// Anchors
|
||||
anchors.top: titleBarContainer.bottom;
|
||||
anchors.topMargin: 30;
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 16;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 16;
|
||||
|
||||
// Text below title bar
|
||||
RalewayRegular {
|
||||
id: securityImageTitleHelper;
|
||||
text: "Choose a Security Pic:";
|
||||
// Text size
|
||||
size: 24;
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.left: parent.left;
|
||||
height: 50;
|
||||
width: paintedWidth;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignHLeft;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
|
||||
SecurityImageSelection {
|
||||
id: securityImageSelection;
|
||||
// Anchors
|
||||
anchors.top: securityImageTitleHelper.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
height: 300;
|
||||
|
||||
Connections {
|
||||
onSendSignalToWallet: {
|
||||
sendSignalToWallet(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Text below security images
|
||||
RalewayRegular {
|
||||
text: "<b>Your security picture shows you that the service asking for your passphrase is authorized.</b> You can change your secure picture at any time.";
|
||||
// Text size
|
||||
size: 18;
|
||||
// Anchors
|
||||
anchors.top: securityImageSelection.bottom;
|
||||
anchors.topMargin: 40;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
height: paintedHeight;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
wrapMode: Text.WordWrap;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignHLeft;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
|
||||
// Navigation Bar
|
||||
Item {
|
||||
// Size
|
||||
width: parent.width;
|
||||
height: 50;
|
||||
// Anchors:
|
||||
anchors.left: parent.left;
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.bottomMargin: 50;
|
||||
|
||||
// "Back" button
|
||||
HifiControlsUit.Button {
|
||||
color: hifi.buttons.noneBorderlessWhite;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.top: parent.top;
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 20;
|
||||
width: 200;
|
||||
text: "Back"
|
||||
onClicked: {
|
||||
securityImageSelection.resetSelection();
|
||||
root.activeView = "step_1";
|
||||
}
|
||||
}
|
||||
|
||||
// "Next" button
|
||||
HifiControlsUit.Button {
|
||||
enabled: securityImageSelection.currentIndex !== -1;
|
||||
color: hifi.buttons.blue;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.top: parent.top;
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 20;
|
||||
width: 200;
|
||||
text: "Next";
|
||||
onClicked: {
|
||||
root.lastPage = "step_2";
|
||||
var securityImagePath = securityImageSelection.getImagePathFromImageID(securityImageSelection.getSelectedImageIndex())
|
||||
Commerce.chooseSecurityImage(securityImagePath);
|
||||
root.activeView = "step_3";
|
||||
passphraseSelection.clearPassphraseFields();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// SECURITY IMAGE SELECTION END
|
||||
//
|
||||
|
||||
//
|
||||
// SECURE PASSPHRASE SELECTION START
|
||||
//
|
||||
|
@ -525,7 +406,6 @@ Item {
|
|||
width: 200;
|
||||
text: "Back"
|
||||
onClicked: {
|
||||
securityImageSelection.resetSelection();
|
||||
root.lastPage = "step_3";
|
||||
root.activeView = "step_2";
|
||||
}
|
||||
|
|
344
interface/resources/qml/hifi/dialogs/security/Security.qml
Normal file
|
@ -0,0 +1,344 @@
|
|||
//
|
||||
// Security.qml
|
||||
// qml\hifi\dialogs\security
|
||||
//
|
||||
// Security
|
||||
//
|
||||
// Created by Zach Fox on 2018-10-31
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import Hifi 1.0 as Hifi
|
||||
import QtQuick 2.5
|
||||
import QtGraphicalEffects 1.0
|
||||
import "qrc:////qml//styles-uit" as HifiStylesUit
|
||||
import "qrc:////qml//controls-uit" as HifiControlsUit
|
||||
import "qrc:////qml//controls" as HifiControls
|
||||
import "qrc:////qml//hifi//commerce//common" as HifiCommerceCommon
|
||||
|
||||
Rectangle {
|
||||
HifiStylesUit.HifiConstants { id: hifi; }
|
||||
|
||||
id: root;
|
||||
color: hifi.colors.baseGray;
|
||||
|
||||
property string title: "Security Settings";
|
||||
property bool walletSetUp;
|
||||
|
||||
QtObject {
|
||||
id: margins
|
||||
property real paddings: root.width / 20.25
|
||||
|
||||
property real sizeCheckBox: root.width / 13.5
|
||||
property real sizeText: root.width / 2.5
|
||||
property real sizeLevel: root.width / 5.8
|
||||
property real sizeDesktop: root.width / 5.8
|
||||
property real sizeVR: root.width / 13.5
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Commerce;
|
||||
|
||||
onWalletStatusResult: {
|
||||
if (walletStatus === 5) {
|
||||
Commerce.getSecurityImage();
|
||||
root.walletSetUp = true;
|
||||
} else {
|
||||
root.walletSetUp = false;
|
||||
}
|
||||
}
|
||||
|
||||
onSecurityImageResult: {
|
||||
if (exists) {
|
||||
currentSecurityPicture.source = "";
|
||||
currentSecurityPicture.source = "image://security/securityImage";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
Commerce.getWalletStatus();
|
||||
}
|
||||
|
||||
HifiCommerceCommon.CommerceLightbox {
|
||||
z: 996;
|
||||
id: lightboxPopup;
|
||||
visible: false;
|
||||
anchors.fill: parent;
|
||||
}
|
||||
|
||||
SecurityImageChange {
|
||||
id: securityImageChange;
|
||||
visible: false;
|
||||
z: 997;
|
||||
anchors.top: usernameText.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
anchors.bottom: parent.bottom;
|
||||
|
||||
Connections {
|
||||
onSendSignalToParent: {
|
||||
securityImageChange.visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Username Text
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: usernameText;
|
||||
text: Account.username === "Unknown user" ? "Please Log In" : Account.username;
|
||||
// Text size
|
||||
size: 24;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
elide: Text.ElideRight;
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 20;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 20;
|
||||
height: 60;
|
||||
}
|
||||
|
||||
Item {
|
||||
id: pleaseLogInContainer;
|
||||
visible: Account.username === "Unknown user";
|
||||
anchors.top: usernameText.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
anchors.bottom: parent.bottom;
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
text: "Please log in for security settings."
|
||||
// Text size
|
||||
size: 24;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
// Anchors
|
||||
anchors.bottom: openLoginButton.top;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
height: 60;
|
||||
}
|
||||
|
||||
HifiControlsUit.Button {
|
||||
id: openLoginButton;
|
||||
color: hifi.buttons.white;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.centerIn: parent;
|
||||
width: 140;
|
||||
height: 40;
|
||||
text: "Log In";
|
||||
onClicked: {
|
||||
DialogsManager.showLoginDialog();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: securitySettingsContainer;
|
||||
visible: !pleaseLogInContainer.visible;
|
||||
anchors.top: usernameText.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
anchors.bottom: parent.bottom;
|
||||
|
||||
Item {
|
||||
id: accountContainer;
|
||||
anchors.top: securitySettingsContainer.top;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
height: childrenRect.height;
|
||||
|
||||
Rectangle {
|
||||
id: accountHeaderContainer;
|
||||
anchors.top: parent.top;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
height: 55;
|
||||
color: hifi.colors.baseGrayHighlight;
|
||||
|
||||
HifiStylesUit.RalewaySemiBold {
|
||||
text: "Account";
|
||||
anchors.fill: parent;
|
||||
anchors.leftMargin: 20;
|
||||
color: hifi.colors.white;
|
||||
size: 18;
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: keepMeLoggedInContainer;
|
||||
anchors.top: accountHeaderContainer.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
height: 80;
|
||||
|
||||
HifiControlsUit.CheckBox {
|
||||
id: autoLogoutCheckbox;
|
||||
checked: Settings.getValue("keepMeLoggedIn", false);
|
||||
text: "Keep Me Logged In"
|
||||
// Anchors
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 20;
|
||||
boxSize: 24;
|
||||
labelFontSize: 18;
|
||||
colorScheme: hifi.colorSchemes.dark
|
||||
color: hifi.colors.white;
|
||||
width: 240;
|
||||
onCheckedChanged: {
|
||||
Settings.setValue("keepMeLoggedIn", checked);
|
||||
if (checked) {
|
||||
Settings.setValue("keepMeLoggedIn/savedUsername", Account.username);
|
||||
} else {
|
||||
Settings.setValue("keepMeLoggedIn/savedUsername", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HifiStylesUit.RalewaySemiBold {
|
||||
id: autoLogoutHelp;
|
||||
text: '[?]';
|
||||
// Anchors
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
anchors.right: autoLogoutCheckbox.right;
|
||||
width: 30;
|
||||
height: 30;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.blueHighlight;
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
hoverEnabled: true;
|
||||
onEntered: {
|
||||
parent.color = hifi.colors.blueAccent;
|
||||
}
|
||||
onExited: {
|
||||
parent.color = hifi.colors.blueHighlight;
|
||||
}
|
||||
onClicked: {
|
||||
lightboxPopup.titleText = "Keep Me Logged In";
|
||||
lightboxPopup.bodyText = "If you choose to stay logged in, ensure that this is a trusted device.\n\n" +
|
||||
"Also, remember that logging out may not disconnect you from a domain.";
|
||||
lightboxPopup.button1text = "OK";
|
||||
lightboxPopup.button1method = function() {
|
||||
lightboxPopup.visible = false;
|
||||
}
|
||||
lightboxPopup.visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: walletContainer;
|
||||
anchors.top: accountContainer.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
height: childrenRect.height;
|
||||
|
||||
Rectangle {
|
||||
id: walletHeaderContainer;
|
||||
anchors.top: parent.top;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
height: 55;
|
||||
color: hifi.colors.baseGrayHighlight;
|
||||
|
||||
HifiStylesUit.RalewaySemiBold {
|
||||
text: "Wallet";
|
||||
anchors.fill: parent;
|
||||
anchors.leftMargin: 20;
|
||||
color: hifi.colors.white;
|
||||
size: 18;
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: walletSecurityPictureContainer;
|
||||
visible: root.walletSetUp;
|
||||
anchors.top: walletHeaderContainer.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
height: 80;
|
||||
|
||||
Image {
|
||||
id: currentSecurityPicture;
|
||||
source: "";
|
||||
visible: true;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 20;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
height: 40;
|
||||
width: height;
|
||||
mipmap: true;
|
||||
cache: false;
|
||||
}
|
||||
|
||||
HifiStylesUit.RalewaySemiBold {
|
||||
id: securityPictureText;
|
||||
text: "Wallet Security Picture";
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.left: currentSecurityPicture.right;
|
||||
anchors.leftMargin: 12;
|
||||
width: paintedWidth;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
}
|
||||
|
||||
// "Change Security Pic" button
|
||||
HifiControlsUit.Button {
|
||||
id: changeSecurityImageButton;
|
||||
color: hifi.buttons.white;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.left: securityPictureText.right;
|
||||
anchors.leftMargin: 12;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
width: 140;
|
||||
height: 40;
|
||||
text: "Change";
|
||||
onClicked: {
|
||||
securityImageChange.visible = true;
|
||||
securityImageChange.initModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: walletNotSetUpContainer;
|
||||
visible: !root.walletSetUp;
|
||||
anchors.top: walletHeaderContainer.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
height: 60;
|
||||
|
||||
HifiStylesUit.RalewayRegular {
|
||||
text: "Your wallet is not set up.\n" +
|
||||
"Open the WALLET app to get started.";
|
||||
// Anchors
|
||||
anchors.fill: parent;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
//
|
||||
// SecurityImageChange.qml
|
||||
// qml/hifi/commerce/wallet
|
||||
// qml\hifi\dialogs\security
|
||||
//
|
||||
// SecurityImageChange
|
||||
// Security
|
||||
//
|
||||
// Created by Zach Fox on 2017-08-18
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
// Created by Zach Fox on 2018-10-31
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
@ -13,16 +13,17 @@
|
|||
|
||||
import Hifi 1.0 as Hifi
|
||||
import QtQuick 2.5
|
||||
import "../../../styles-uit"
|
||||
import "../../../controls-uit" as HifiControlsUit
|
||||
import "../../../controls" as HifiControls
|
||||
import "qrc:////qml//styles-uit" as HifiStylesUit
|
||||
import "qrc:////qml//controls-uit" as HifiControlsUit
|
||||
import "qrc:////qml//controls" as HifiControls
|
||||
|
||||
// references XXX from root context
|
||||
|
||||
Item {
|
||||
HifiConstants { id: hifi; }
|
||||
Rectangle {
|
||||
HifiStylesUit.HifiConstants { id: hifi; }
|
||||
|
||||
id: root;
|
||||
color: hifi.colors.baseGray;
|
||||
property bool justSubmitted: false;
|
||||
|
||||
Connections {
|
||||
|
@ -33,7 +34,7 @@ Item {
|
|||
securityImageChangePageSecurityImage.source = "image://security/securityImage";
|
||||
if (exists) { // Success submitting new security image
|
||||
if (root.justSubmitted) {
|
||||
sendSignalToWallet({method: "walletSecurity_changeSecurityImageSuccess"});
|
||||
sendSignalToParent({method: "walletSecurity_changeSecurityImageSuccess"});
|
||||
root.justSubmitted = false;
|
||||
}
|
||||
} else if (root.justSubmitted) {
|
||||
|
@ -72,7 +73,7 @@ Item {
|
|||
anchors.bottom: parent.bottom;
|
||||
height: 22;
|
||||
// Lock icon
|
||||
HiFiGlyphs {
|
||||
HifiStylesUit.HiFiGlyphs {
|
||||
id: lockIcon;
|
||||
text: hifi.glyphs.lock;
|
||||
anchors.bottom: parent.bottom;
|
||||
|
@ -83,8 +84,8 @@ Item {
|
|||
verticalAlignment: Text.AlignBottom;
|
||||
color: hifi.colors.white;
|
||||
}
|
||||
// "Security image" text below pic
|
||||
RalewayRegular {
|
||||
// "Security image" text below image
|
||||
HifiStylesUit.RalewayRegular {
|
||||
id: securityImageText;
|
||||
text: "SECURITY PIC";
|
||||
// Text size
|
||||
|
@ -116,9 +117,9 @@ Item {
|
|||
anchors.bottom: parent.bottom;
|
||||
|
||||
// "Change Security Image" text
|
||||
RalewaySemiBold {
|
||||
HifiStylesUit.RalewaySemiBold {
|
||||
id: securityImageTitle;
|
||||
text: "Change Security Pic:";
|
||||
text: "Change Security Image:";
|
||||
// Text size
|
||||
size: 18;
|
||||
anchors.top: parent.top;
|
||||
|
@ -139,12 +140,6 @@ Item {
|
|||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 16;
|
||||
height: 300;
|
||||
|
||||
Connections {
|
||||
onSendSignalToWallet: {
|
||||
sendSignalToWallet(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Navigation Bar
|
||||
|
@ -169,7 +164,7 @@ Item {
|
|||
width: 150;
|
||||
text: "Cancel"
|
||||
onClicked: {
|
||||
sendSignalToWallet({method: "walletSecurity_changeSecurityImageCancelled"});
|
||||
sendSignalToParent({method: "walletSecurity_changeSecurityImageCancelled"});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,7 +192,7 @@ Item {
|
|||
// SECURITY IMAGE SELECTION END
|
||||
//
|
||||
|
||||
signal sendSignalToWallet(var msg);
|
||||
signal sendSignalToParent(var msg);
|
||||
|
||||
function initModel() {
|
||||
securityImageSelection.initModel();
|
|
@ -1,11 +1,11 @@
|
|||
//
|
||||
// SecurityImageModel.qml
|
||||
// qml/hifi/commerce
|
||||
// qml\hifi\dialogs\security
|
||||
//
|
||||
// SecurityImageModel
|
||||
// Security
|
||||
//
|
||||
// Created by Zach Fox on 2017-08-17
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
// Created by Zach Fox on 2018-10-31
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
@ -1,11 +1,11 @@
|
|||
//
|
||||
// SecurityImageSelection.qml
|
||||
// qml/hifi/commerce/wallet
|
||||
// qml\hifi\dialogs\security
|
||||
//
|
||||
// SecurityImageSelection
|
||||
// Security
|
||||
//
|
||||
// Created by Zach Fox on 2017-08-17
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
// Created by Zach Fox on 2018-10-31
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
@ -13,14 +13,14 @@
|
|||
|
||||
import Hifi 1.0 as Hifi
|
||||
import QtQuick 2.5
|
||||
import "../../../styles-uit"
|
||||
import "../../../controls-uit" as HifiControlsUit
|
||||
import "../../../controls" as HifiControls
|
||||
import "qrc:////qml//styles-uit" as HifiStylesUit
|
||||
import "qrc:////qml//controls-uit" as HifiControlsUit
|
||||
import "qrc:////qml//controls" as HifiControls
|
||||
|
||||
// references XXX from root context
|
||||
|
||||
Item {
|
||||
HifiConstants { id: hifi; }
|
||||
HifiStylesUit.HifiConstants { id: hifi; }
|
||||
|
||||
id: root;
|
||||
property alias currentIndex: securityImageGrid.currentIndex;
|
||||
|
@ -64,17 +64,15 @@ Item {
|
|||
}
|
||||
}
|
||||
highlight: Rectangle {
|
||||
width: securityImageGrid.cellWidth;
|
||||
height: securityImageGrid.cellHeight;
|
||||
color: hifi.colors.blueHighlight;
|
||||
}
|
||||
width: securityImageGrid.cellWidth;
|
||||
height: securityImageGrid.cellHeight;
|
||||
color: hifi.colors.blueHighlight;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// FUNCTION DEFINITIONS START
|
||||
//
|
||||
signal sendSignalToWallet(var msg);
|
||||
|
||||
function getImagePathFromImageID(imageID) {
|
||||
return (imageID ? gridModel.getImagePathFromImageID(imageID) : "");
|
||||
}
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
|
@ -385,7 +385,7 @@ static const int INTERVAL_TO_CHECK_HMD_WORN_STATUS = 500; // milliseconds
|
|||
static const QString DESKTOP_DISPLAY_PLUGIN_NAME = "Desktop";
|
||||
static const QString ACTIVE_DISPLAY_PLUGIN_SETTING_NAME = "activeDisplayPlugin";
|
||||
static const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system";
|
||||
static const QString AUTO_LOGOUT_SETTING_NAME = "wallet/autoLogout";
|
||||
static const QString KEEP_ME_LOGGED_IN_SETTING_NAME = "keepMeLoggedIn";
|
||||
|
||||
const std::vector<std::pair<QString, Application::AcceptURLMethod>> Application::_acceptedExtensions {
|
||||
{ SVO_EXTENSION, &Application::importSVOFromURL },
|
||||
|
@ -2563,8 +2563,8 @@ void Application::cleanupBeforeQuit() {
|
|||
}
|
||||
DependencyManager::destroy<ScriptEngines>();
|
||||
|
||||
bool autoLogout = Setting::Handle<bool>(AUTO_LOGOUT_SETTING_NAME, false).get();
|
||||
if (autoLogout) {
|
||||
bool keepMeLoggedIn = Setting::Handle<bool>(KEEP_ME_LOGGED_IN_SETTING_NAME, false).get();
|
||||
if (!keepMeLoggedIn) {
|
||||
DependencyManager::get<AccountManager>()->removeAccountFromFile();
|
||||
}
|
||||
|
||||
|
@ -2969,13 +2969,13 @@ void Application::initializeUi() {
|
|||
QUrl{ "hifi/commerce/wallet/PassphraseChange.qml" },
|
||||
QUrl{ "hifi/commerce/wallet/PassphraseModal.qml" },
|
||||
QUrl{ "hifi/commerce/wallet/PassphraseSelection.qml" },
|
||||
QUrl{ "hifi/commerce/wallet/Security.qml" },
|
||||
QUrl{ "hifi/commerce/wallet/SecurityImageChange.qml" },
|
||||
QUrl{ "hifi/commerce/wallet/SecurityImageModel.qml" },
|
||||
QUrl{ "hifi/commerce/wallet/SecurityImageSelection.qml" },
|
||||
QUrl{ "hifi/commerce/wallet/Wallet.qml" },
|
||||
QUrl{ "hifi/commerce/wallet/WalletHome.qml" },
|
||||
QUrl{ "hifi/commerce/wallet/WalletSetup.qml" },
|
||||
QUrl{ "hifi/dialogs/security/Security.qml" },
|
||||
QUrl{ "hifi/dialogs/security/SecurityImageChange.qml" },
|
||||
QUrl{ "hifi/dialogs/security/SecurityImageModel.qml" },
|
||||
QUrl{ "hifi/dialogs/security/SecurityImageSelection.qml" },
|
||||
}, callback);
|
||||
qmlRegisterType<ResourceImageItem>("Hifi", 1, 0, "ResourceImageItem");
|
||||
qmlRegisterType<Preference>("Hifi", 1, 0, "Preference");
|
||||
|
|
|
@ -265,6 +265,18 @@ Menu::Menu() {
|
|||
QString("hifi/tablet/TabletGraphicsPreferences.qml"), "GraphicsPreferencesDialog");
|
||||
});
|
||||
|
||||
// Settings > Security...
|
||||
action = addActionToQMenuAndActionHash(settingsMenu, "Security...");
|
||||
connect(action, &QAction::triggered, [] {
|
||||
auto tablet = DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system");
|
||||
auto hmd = DependencyManager::get<HMDScriptingInterface>();
|
||||
tablet->pushOntoStack("hifi/dialogs/security/Security.qml");
|
||||
|
||||
if (!hmd->getShouldShowTablet()) {
|
||||
hmd->toggleShouldShowTablet();
|
||||
}
|
||||
});
|
||||
|
||||
// Settings > Developer Menu
|
||||
addCheckableActionToQMenuAndActionHash(settingsMenu, "Developer Menu", 0, false, this, SLOT(toggleDeveloperMenus()));
|
||||
|
||||
|
|
|
@ -235,7 +235,7 @@ bool ModelPackager::zipModel() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename, const FBXGeometry& geometry) {
|
||||
void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename, const HFMGeometry& geometry) {
|
||||
|
||||
bool isBodyType = _modelType == FSTReader::BODY_ONLY_MODEL || _modelType == FSTReader::HEAD_AND_BODY_MODEL;
|
||||
|
||||
|
@ -370,7 +370,7 @@ void ModelPackager::populateBasicMapping(QVariantHash& mapping, QString filename
|
|||
|
||||
void ModelPackager::listTextures() {
|
||||
_textures.clear();
|
||||
foreach (const FBXMaterial mat, _geometry->materials) {
|
||||
foreach (const HFMMaterial mat, _geometry->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 FBXGeometry;
|
||||
class HFMGeometry;
|
||||
|
||||
class ModelPackager : public QObject {
|
||||
public:
|
||||
|
@ -32,7 +32,7 @@ private:
|
|||
bool editProperties();
|
||||
bool zipModel();
|
||||
|
||||
void populateBasicMapping(QVariantHash& mapping, QString filename, const FBXGeometry& geometry);
|
||||
void populateBasicMapping(QVariantHash& mapping, QString filename, const HFMGeometry& geometry);
|
||||
|
||||
void listTextures();
|
||||
bool copyTextures(const QString& oldDir, const QDir& newDir);
|
||||
|
@ -44,7 +44,7 @@ private:
|
|||
QString _scriptDir;
|
||||
|
||||
QVariantHash _mapping;
|
||||
std::unique_ptr<FBXGeometry> _geometry;
|
||||
std::unique_ptr<HFMGeometry> _geometry;
|
||||
QStringList _textures;
|
||||
QStringList _scripts;
|
||||
};
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
|
||||
ModelPropertiesDialog::ModelPropertiesDialog(FSTReader::ModelType modelType, const QVariantHash& originalMapping,
|
||||
const QString& basePath, const FBXGeometry& geometry) :
|
||||
const QString& basePath, const HFMGeometry& geometry) :
|
||||
_modelType(modelType),
|
||||
_originalMapping(originalMapping),
|
||||
_basePath(basePath),
|
||||
|
@ -249,7 +249,7 @@ QComboBox* ModelPropertiesDialog::createJointBox(bool withNone) const {
|
|||
if (withNone) {
|
||||
box->addItem("(none)");
|
||||
}
|
||||
foreach (const FBXJoint& joint, _geometry.joints) {
|
||||
foreach (const HFMJoint& joint, _geometry.joints) {
|
||||
if (joint.isSkeletonJoint || !_geometry.hasSkeletonJoints) {
|
||||
box->addItem(joint.name);
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ class ModelPropertiesDialog : public QDialog {
|
|||
|
||||
public:
|
||||
ModelPropertiesDialog(FSTReader::ModelType modelType, const QVariantHash& originalMapping,
|
||||
const QString& basePath, const FBXGeometry& geometry);
|
||||
const QString& basePath, const HFMGeometry& geometry);
|
||||
|
||||
QVariantHash getMapping() const;
|
||||
|
||||
|
@ -50,7 +50,7 @@ private:
|
|||
FSTReader::ModelType _modelType;
|
||||
QVariantHash _originalMapping;
|
||||
QString _basePath;
|
||||
FBXGeometry _geometry;
|
||||
HFMGeometry _geometry;
|
||||
QLineEdit* _name = nullptr;
|
||||
QPushButton* _textureDirectory = nullptr;
|
||||
QPushButton* _scriptDirectory = nullptr;
|
||||
|
|
|
@ -155,7 +155,7 @@ MyAvatar::MyAvatar(QThread* thread) :
|
|||
});
|
||||
connect(_skeletonModel.get(), &Model::rigReady, this, [this]() {
|
||||
if (_shouldLoadScripts) {
|
||||
auto geometry = getSkeletonModel()->getFBXGeometry();
|
||||
auto geometry = getSkeletonModel()->getHFMGeometry();
|
||||
qApp->loadAvatarScripts(geometry.scripts);
|
||||
_shouldLoadScripts = false;
|
||||
}
|
||||
|
@ -2429,10 +2429,10 @@ void MyAvatar::attachmentDataToEntityProperties(const AttachmentData& data, Enti
|
|||
void MyAvatar::initHeadBones() {
|
||||
int neckJointIndex = -1;
|
||||
if (_skeletonModel->isLoaded()) {
|
||||
neckJointIndex = _skeletonModel->getFBXGeometry().neckJointIndex;
|
||||
neckJointIndex = _skeletonModel->getHFMGeometry().neckJointIndex;
|
||||
}
|
||||
if (neckJointIndex == -1) {
|
||||
neckJointIndex = (_skeletonModel->getFBXGeometry().headJointIndex - 1);
|
||||
neckJointIndex = (_skeletonModel->getHFMGeometry().headJointIndex - 1);
|
||||
if (neckJointIndex < 0) {
|
||||
// return if the head is not even there. can't cauterize!!
|
||||
return;
|
||||
|
@ -2443,7 +2443,7 @@ void MyAvatar::initHeadBones() {
|
|||
q.push(neckJointIndex);
|
||||
_headBoneSet.insert(neckJointIndex);
|
||||
|
||||
// fbxJoints only hold links to parents not children, so we have to do a bit of extra work here.
|
||||
// hfmJoints only hold links to parents not children, so we have to do a bit of extra work here.
|
||||
while (q.size() > 0) {
|
||||
int jointIndex = q.front();
|
||||
for (int i = 0; i < _skeletonModel->getJointStateCount(); i++) {
|
||||
|
@ -2592,11 +2592,11 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
|
|||
|
||||
if (_skeletonModel && _skeletonModel->isLoaded()) {
|
||||
const Rig& rig = _skeletonModel->getRig();
|
||||
const FBXGeometry& geometry = _skeletonModel->getFBXGeometry();
|
||||
const HFMGeometry& geometry = _skeletonModel->getHFMGeometry();
|
||||
for (int i = 0; i < rig.getJointStateCount(); i++) {
|
||||
AnimPose jointPose;
|
||||
rig.getAbsoluteJointPoseInRigFrame(i, jointPose);
|
||||
const FBXJointShapeInfo& shapeInfo = geometry.joints[i].shapeInfo;
|
||||
const HFMJointShapeInfo& shapeInfo = geometry.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->getFBXGeometry().scripts : QVector<QString>();
|
||||
QVector<QString> scripts = _skeletonModel->isLoaded() ? _skeletonModel->getHFMGeometry().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 FBXGeometry& geometry = getFBXGeometry();
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
|
||||
Head* head = _owningAvatar->getHead();
|
||||
|
||||
|
|
|
@ -219,7 +219,11 @@ QString transactionString(const QJsonObject& valueObject) {
|
|||
if (!message.isEmpty()) {
|
||||
result += QString("<br>with memo: <i>\"%1\"</i>").arg(message);
|
||||
}
|
||||
} else if (sentMoney <= 0 && receivedMoney <= 0 && (sentCerts > 0 || receivedCerts > 0) && !KNOWN_USERS.contains(valueObject["sender_name"].toString())) {
|
||||
} else if (sentMoney <= 0 && receivedMoney <= 0 &&
|
||||
(sentCerts > 0 || receivedCerts > 0) &&
|
||||
!KNOWN_USERS.contains(valueObject["sender_name"].toString()) &&
|
||||
!KNOWN_USERS.contains(valueObject["recipient_name"].toString())
|
||||
) {
|
||||
// this is a non-HFC asset transfer.
|
||||
if (sentCerts > 0) {
|
||||
QString recipient = userLink(valueObject["recipient_name"].toString(), valueObject["place_name"].toString());
|
||||
|
|
|
@ -687,7 +687,7 @@ void Wallet::chooseSecurityImage(const QString& filename) {
|
|||
delete _securityImage;
|
||||
}
|
||||
QString path = PathUtils::resourcesPath();
|
||||
path.append("/qml/hifi/commerce/wallet/");
|
||||
path.append("/qml/hifi/dialogs/security/");
|
||||
path.append(filename);
|
||||
|
||||
// now create a new security image pixmap
|
||||
|
|
|
@ -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 FBXGeometry& collisionGeometry = resource->getFBXGeometry();
|
||||
const HFMGeometry& collisionGeometry = resource->getHFMGeometry();
|
||||
|
||||
ShapeInfo::PointCollection& pointCollection = shapeInfo.getPointCollection();
|
||||
pointCollection.clear();
|
||||
|
@ -139,15 +139,15 @@ 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 FBXMesh& mesh, collisionGeometry.meshes) {
|
||||
foreach (const HFMMesh& mesh, collisionGeometry.meshes) {
|
||||
// each meshPart is a convex hull
|
||||
foreach (const FBXMeshPart &meshPart, mesh.parts) {
|
||||
foreach (const HFMMeshPart &meshPart, mesh.parts) {
|
||||
pointCollection.push_back(QVector<glm::vec3>());
|
||||
ShapeInfo::PointList& pointsInPart = pointCollection[i];
|
||||
|
||||
// run through all the triangles and (uniquely) add each point to the hull
|
||||
uint32_t numIndices = (uint32_t)meshPart.triangleIndices.size();
|
||||
// TODO: assert rather than workaround after we start sanitizing FBXMesh higher up
|
||||
// TODO: assert rather than workaround after we start sanitizing HFMMesh higher up
|
||||
//assert(numIndices % TRIANGLE_STRIDE == 0);
|
||||
numIndices -= numIndices % TRIANGLE_STRIDE; // WORKAROUND lack of sanity checking in FBXReader
|
||||
|
||||
|
@ -168,7 +168,7 @@ void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& sha
|
|||
|
||||
// run through all the quads and (uniquely) add each point to the hull
|
||||
numIndices = (uint32_t)meshPart.quadIndices.size();
|
||||
// TODO: assert rather than workaround after we start sanitizing FBXMesh higher up
|
||||
// TODO: assert rather than workaround after we start sanitizing HFMMesh higher up
|
||||
//assert(numIndices % QUAD_STRIDE == 0);
|
||||
numIndices -= numIndices % QUAD_STRIDE; // WORKAROUND lack of sanity checking in FBXReader
|
||||
|
||||
|
@ -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->getFBXGeometry().getUnscaledMeshExtents().size();
|
||||
glm::vec3 scaleToFit = dimensions / resource->getHFMGeometry().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 FBXGeometry& fbxGeometry = resource->getFBXGeometry();
|
||||
int numFbxMeshes = fbxGeometry.meshes.size();
|
||||
const HFMGeometry& hfmGeometry = resource->getHFMGeometry();
|
||||
int numHFMMeshes = hfmGeometry.meshes.size();
|
||||
int totalNumVertices = 0;
|
||||
for (int i = 0; i < numFbxMeshes; i++) {
|
||||
const FBXMesh& mesh = fbxGeometry.meshes.at(i);
|
||||
for (int i = 0; i < numHFMMeshes; i++) {
|
||||
const HFMMesh& mesh = hfmGeometry.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->getFBXGeometry().meshes;
|
||||
auto& meshes = resource->getHFMGeometry().meshes;
|
||||
int32_t numMeshes = (int32_t)(meshes.size());
|
||||
|
||||
const int MAX_ALLOWED_MESH_COUNT = 1000;
|
||||
|
@ -285,12 +285,12 @@ void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& sha
|
|||
if (type == SHAPE_TYPE_STATIC_MESH) {
|
||||
// copy into triangleIndices
|
||||
size_t triangleIndicesCount = 0;
|
||||
for (const FBXMeshPart& meshPart : mesh.parts) {
|
||||
for (const HFMMeshPart& meshPart : mesh.parts) {
|
||||
triangleIndicesCount += meshPart.triangleIndices.count();
|
||||
}
|
||||
triangleIndices.reserve((int)triangleIndicesCount);
|
||||
|
||||
for (const FBXMeshPart& meshPart : mesh.parts) {
|
||||
for (const HFMMeshPart& meshPart : mesh.parts) {
|
||||
const int* indexItr = meshPart.triangleIndices.cbegin();
|
||||
while (indexItr != meshPart.triangleIndices.cend()) {
|
||||
triangleIndices.push_back(*indexItr);
|
||||
|
@ -299,11 +299,11 @@ void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& sha
|
|||
}
|
||||
} else if (type == SHAPE_TYPE_SIMPLE_COMPOUND) {
|
||||
// for each mesh copy unique part indices, separated by special bogus (flag) index values
|
||||
for (const FBXMeshPart& meshPart : mesh.parts) {
|
||||
for (const HFMMeshPart& meshPart : mesh.parts) {
|
||||
// collect unique list of indices for this part
|
||||
std::set<int32_t> uniqueIndices;
|
||||
auto numIndices = meshPart.triangleIndices.count();
|
||||
// TODO: assert rather than workaround after we start sanitizing FBXMesh higher up
|
||||
// TODO: assert rather than workaround after we start sanitizing HFMMesh higher up
|
||||
//assert(numIndices% TRIANGLE_STRIDE == 0);
|
||||
numIndices -= numIndices % TRIANGLE_STRIDE; // WORKAROUND lack of sanity checking in FBXReader
|
||||
|
||||
|
|
|
@ -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 FBXGeometry) was always empty
|
||||
// note: going through Rig because Model::getJointNames() (which proxies to HFMGeometry) was always empty
|
||||
const Rig* rig = &(_model->getRig());
|
||||
return mapJoints<QStringList, QString>([rig](int jointIndex) -> QString {
|
||||
return rig->nameOfJoint(jointIndex);
|
||||
|
@ -574,7 +574,7 @@ void ModelOverlay::animate() {
|
|||
|
||||
QVector<JointData> jointsData;
|
||||
|
||||
const QVector<FBXAnimationFrame>& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy
|
||||
const QVector<HFMAnimationFrame>& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy
|
||||
int frameCount = frames.size();
|
||||
if (frameCount <= 0) {
|
||||
return;
|
||||
|
@ -606,10 +606,10 @@ void ModelOverlay::animate() {
|
|||
}
|
||||
|
||||
QStringList animationJointNames = _animation->getGeometry().getJointNames();
|
||||
auto& fbxJoints = _animation->getGeometry().joints;
|
||||
auto& hfmJoints = _animation->getGeometry().joints;
|
||||
|
||||
auto& originalFbxJoints = _model->getFBXGeometry().joints;
|
||||
auto& originalFbxIndices = _model->getFBXGeometry().jointIndices;
|
||||
auto& originalHFMJoints = _model->getHFMGeometry().joints;
|
||||
auto& originalFbxIndices = _model->getHFMGeometry().jointIndices;
|
||||
|
||||
const QVector<glm::quat>& rotations = frames[_lastKnownCurrentFrame].rotations;
|
||||
const QVector<glm::vec3>& translations = frames[_lastKnownCurrentFrame].translations;
|
||||
|
@ -626,23 +626,23 @@ void ModelOverlay::animate() {
|
|||
translationMat = glm::translate(translations[index]);
|
||||
}
|
||||
} else if (index < animationJointNames.size()) {
|
||||
QString jointName = fbxJoints[index].name;
|
||||
QString jointName = hfmJoints[index].name;
|
||||
|
||||
if (originalFbxIndices.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.
|
||||
translationMat = glm::translate(originalFbxJoints[remappedIndex].translation);
|
||||
translationMat = glm::translate(originalHFMJoints[remappedIndex].translation);
|
||||
}
|
||||
}
|
||||
glm::mat4 rotationMat;
|
||||
if (index < rotations.size()) {
|
||||
rotationMat = glm::mat4_cast(fbxJoints[index].preRotation * rotations[index] * fbxJoints[index].postRotation);
|
||||
rotationMat = glm::mat4_cast(hfmJoints[index].preRotation * rotations[index] * hfmJoints[index].postRotation);
|
||||
} else {
|
||||
rotationMat = glm::mat4_cast(fbxJoints[index].preRotation * fbxJoints[index].postRotation);
|
||||
rotationMat = glm::mat4_cast(hfmJoints[index].preRotation * hfmJoints[index].postRotation);
|
||||
}
|
||||
|
||||
glm::mat4 finalMat = (translationMat * fbxJoints[index].preTransform *
|
||||
rotationMat * fbxJoints[index].postTransform);
|
||||
glm::mat4 finalMat = (translationMat * hfmJoints[index].preTransform *
|
||||
rotationMat * hfmJoints[index].postTransform);
|
||||
auto& jointData = jointsData[j];
|
||||
jointData.translation = extractTranslation(finalMat);
|
||||
jointData.translationIsDefaultPose = false;
|
||||
|
|
|
@ -101,7 +101,7 @@ void AnimClip::copyFromNetworkAnim() {
|
|||
|
||||
// build a mapping from animation joint indices to skeleton joint indices.
|
||||
// by matching joints with the same name.
|
||||
const FBXGeometry& geom = _networkAnim->getGeometry();
|
||||
const HFMGeometry& geom = _networkAnim->getGeometry();
|
||||
AnimSkeleton animSkeleton(geom);
|
||||
const auto animJointCount = animSkeleton.getNumJoints();
|
||||
const auto skeletonJointCount = _skeleton->getNumJoints();
|
||||
|
@ -120,7 +120,7 @@ void AnimClip::copyFromNetworkAnim() {
|
|||
|
||||
for (int frame = 0; frame < frameCount; frame++) {
|
||||
|
||||
const FBXAnimationFrame& fbxAnimFrame = geom.animationFrames[frame];
|
||||
const HFMAnimationFrame& hfmAnimFrame = geom.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.
|
||||
|
@ -132,8 +132,8 @@ void AnimClip::copyFromNetworkAnim() {
|
|||
for (int animJoint = 0; animJoint < animJointCount; animJoint++) {
|
||||
int skeletonJoint = jointMap[animJoint];
|
||||
|
||||
const glm::vec3& fbxAnimTrans = fbxAnimFrame.translations[animJoint];
|
||||
const glm::quat& fbxAnimRot = fbxAnimFrame.rotations[animJoint];
|
||||
const glm::vec3& hfmAnimTrans = hfmAnimFrame.translations[animJoint];
|
||||
const glm::quat& hfmAnimRot = hfmAnimFrame.rotations[animJoint];
|
||||
|
||||
// skip joints that are in the animation but not in the skeleton.
|
||||
if (skeletonJoint >= 0 && skeletonJoint < skeletonJointCount) {
|
||||
|
@ -146,19 +146,19 @@ void AnimClip::copyFromNetworkAnim() {
|
|||
preRot.scale() = glm::vec3(1.0f);
|
||||
postRot.scale() = glm::vec3(1.0f);
|
||||
|
||||
AnimPose rot(glm::vec3(1.0f), fbxAnimRot, glm::vec3());
|
||||
AnimPose rot(glm::vec3(1.0f), hfmAnimRot, glm::vec3());
|
||||
|
||||
// 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& fbxZeroTrans = geom.animationFrames[0].translations[animJoint];
|
||||
const glm::vec3& hfmZeroTrans = geom.animationFrames[0].translations[animJoint];
|
||||
const AnimPose& relDefaultPose = _skeleton->getRelativeDefaultPose(skeletonJoint);
|
||||
float boneLengthScale = 1.0f;
|
||||
const float EPSILON = 0.0001f;
|
||||
if (fabsf(glm::length(fbxZeroTrans)) > EPSILON) {
|
||||
boneLengthScale = glm::length(relDefaultPose.trans()) / glm::length(fbxZeroTrans);
|
||||
if (fabsf(glm::length(hfmZeroTrans)) > EPSILON) {
|
||||
boneLengthScale = glm::length(relDefaultPose.trans()) / glm::length(hfmZeroTrans);
|
||||
}
|
||||
|
||||
AnimPose trans = AnimPose(glm::vec3(1.0f), glm::quat(), relDefaultPose.trans() + boneLengthScale * (fbxAnimTrans - fbxZeroTrans));
|
||||
AnimPose trans = AnimPose(glm::vec3(1.0f), glm::quat(), relDefaultPose.trans() + boneLengthScale * (hfmAnimTrans - hfmZeroTrans));
|
||||
|
||||
_anim[frame][skeletonJoint] = trans * preRot * rot * postRot;
|
||||
}
|
||||
|
|
|
@ -16,17 +16,17 @@
|
|||
|
||||
#include "AnimationLogging.h"
|
||||
|
||||
AnimSkeleton::AnimSkeleton(const FBXGeometry& fbxGeometry) {
|
||||
AnimSkeleton::AnimSkeleton(const HFMGeometry& geometry) {
|
||||
// convert to std::vector of joints
|
||||
std::vector<FBXJoint> joints;
|
||||
joints.reserve(fbxGeometry.joints.size());
|
||||
for (auto& joint : fbxGeometry.joints) {
|
||||
std::vector<HFMJoint> joints;
|
||||
joints.reserve(geometry.joints.size());
|
||||
for (auto& joint : geometry.joints) {
|
||||
joints.push_back(joint);
|
||||
}
|
||||
buildSkeletonFromJoints(joints);
|
||||
}
|
||||
|
||||
AnimSkeleton::AnimSkeleton(const std::vector<FBXJoint>& joints) {
|
||||
AnimSkeleton::AnimSkeleton(const std::vector<HFMJoint>& joints) {
|
||||
buildSkeletonFromJoints(joints);
|
||||
}
|
||||
|
||||
|
@ -166,7 +166,7 @@ void AnimSkeleton::mirrorAbsolutePoses(AnimPoseVec& poses) const {
|
|||
}
|
||||
}
|
||||
|
||||
void AnimSkeleton::buildSkeletonFromJoints(const std::vector<FBXJoint>& joints) {
|
||||
void AnimSkeleton::buildSkeletonFromJoints(const std::vector<HFMJoint>& joints) {
|
||||
_joints = joints;
|
||||
_jointsSize = (int)joints.size();
|
||||
// build a cache of bind poses
|
||||
|
@ -177,7 +177,7 @@ void AnimSkeleton::buildSkeletonFromJoints(const std::vector<FBXJoint>& joints)
|
|||
_relativePreRotationPoses.reserve(_jointsSize);
|
||||
_relativePostRotationPoses.reserve(_jointsSize);
|
||||
|
||||
// iterate over FBXJoints and extract the bind pose information.
|
||||
// iterate over HFMJoints and extract the bind pose information.
|
||||
for (int i = 0; i < _jointsSize; i++) {
|
||||
|
||||
// build pre and post transforms
|
||||
|
@ -240,7 +240,7 @@ void AnimSkeleton::dump(bool verbose) const {
|
|||
qCDebug(animation) << " absDefaultPose =" << getAbsoluteDefaultPose(i);
|
||||
qCDebug(animation) << " relDefaultPose =" << getRelativeDefaultPose(i);
|
||||
if (verbose) {
|
||||
qCDebug(animation) << " fbxJoint =";
|
||||
qCDebug(animation) << " hfmJoint =";
|
||||
qCDebug(animation) << " isFree =" << _joints[i].isFree;
|
||||
qCDebug(animation) << " freeLineage =" << _joints[i].freeLineage;
|
||||
qCDebug(animation) << " parentIndex =" << _joints[i].parentIndex;
|
||||
|
|
|
@ -23,8 +23,8 @@ public:
|
|||
using Pointer = std::shared_ptr<AnimSkeleton>;
|
||||
using ConstPointer = std::shared_ptr<const AnimSkeleton>;
|
||||
|
||||
explicit AnimSkeleton(const FBXGeometry& fbxGeometry);
|
||||
explicit AnimSkeleton(const std::vector<FBXJoint>& joints);
|
||||
explicit AnimSkeleton(const HFMGeometry& geometry);
|
||||
explicit AnimSkeleton(const std::vector<HFMJoint>& joints);
|
||||
int nameToJointIndex(const QString& jointName) const;
|
||||
const QString& getJointName(int jointIndex) const;
|
||||
int getNumJoints() const;
|
||||
|
@ -64,9 +64,9 @@ public:
|
|||
std::vector<int> lookUpJointIndices(const std::vector<QString>& jointNames) const;
|
||||
|
||||
protected:
|
||||
void buildSkeletonFromJoints(const std::vector<FBXJoint>& joints);
|
||||
void buildSkeletonFromJoints(const std::vector<HFMJoint>& joints);
|
||||
|
||||
std::vector<FBXJoint> _joints;
|
||||
std::vector<HFMJoint> _joints;
|
||||
int _jointsSize { 0 };
|
||||
AnimPoseVec _relativeDefaultPoses;
|
||||
AnimPoseVec _absoluteDefaultPoses;
|
||||
|
|
|
@ -69,7 +69,7 @@ void AnimationReader::run() {
|
|||
|
||||
if (urlValid) {
|
||||
// Parse the FBX directly from the QNetworkReply
|
||||
FBXGeometry::Pointer fbxgeo;
|
||||
HFMGeometry::Pointer fbxgeo;
|
||||
if (_url.path().toLower().endsWith(".fbx")) {
|
||||
fbxgeo.reset(readFBX(_data, QVariantHash(), _url.path()));
|
||||
} else {
|
||||
|
@ -100,40 +100,40 @@ QStringList Animation::getJointNames() const {
|
|||
}
|
||||
QStringList names;
|
||||
if (_geometry) {
|
||||
foreach (const FBXJoint& joint, _geometry->joints) {
|
||||
foreach (const HFMJoint& joint, _geometry->joints) {
|
||||
names.append(joint.name);
|
||||
}
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
QVector<FBXAnimationFrame> Animation::getFrames() const {
|
||||
QVector<HFMAnimationFrame> Animation::getFrames() const {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QVector<FBXAnimationFrame> result;
|
||||
QVector<HFMAnimationFrame> result;
|
||||
BLOCKING_INVOKE_METHOD(const_cast<Animation*>(this), "getFrames",
|
||||
Q_RETURN_ARG(QVector<FBXAnimationFrame>, result));
|
||||
Q_RETURN_ARG(QVector<HFMAnimationFrame>, result));
|
||||
return result;
|
||||
}
|
||||
if (_geometry) {
|
||||
return _geometry->animationFrames;
|
||||
} else {
|
||||
return QVector<FBXAnimationFrame>();
|
||||
return QVector<HFMAnimationFrame>();
|
||||
}
|
||||
}
|
||||
|
||||
const QVector<FBXAnimationFrame>& Animation::getFramesReference() const {
|
||||
const QVector<HFMAnimationFrame>& Animation::getFramesReference() const {
|
||||
return _geometry->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(FBXGeometry::Pointer)), SLOT(animationParseSuccess(FBXGeometry::Pointer)));
|
||||
connect(animationReader, SIGNAL(onSuccess(HFMGeometry::Pointer)), SLOT(animationParseSuccess(HFMGeometry::Pointer)));
|
||||
connect(animationReader, SIGNAL(onError(int, QString)), SLOT(animationParseError(int, QString)));
|
||||
QThreadPool::globalInstance()->start(animationReader);
|
||||
}
|
||||
|
||||
void Animation::animationParseSuccess(FBXGeometry::Pointer geometry) {
|
||||
void Animation::animationParseSuccess(HFMGeometry::Pointer geometry) {
|
||||
|
||||
qCDebug(animation) << "Animation parse success" << _url.toDisplayString();
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ public:
|
|||
|
||||
QString getType() const override { return "Animation"; }
|
||||
|
||||
const FBXGeometry& getGeometry() const { return *_geometry; }
|
||||
const HFMGeometry& getGeometry() const { return *_geometry; }
|
||||
|
||||
virtual bool isLoaded() const override;
|
||||
|
||||
|
@ -80,20 +80,20 @@ public:
|
|||
* @function AnimationObject.getFrames
|
||||
* @returns {FBXAnimationFrame[]}
|
||||
*/
|
||||
Q_INVOKABLE QVector<FBXAnimationFrame> getFrames() const;
|
||||
Q_INVOKABLE QVector<HFMAnimationFrame> getFrames() const;
|
||||
|
||||
const QVector<FBXAnimationFrame>& getFramesReference() const;
|
||||
const QVector<HFMAnimationFrame>& getFramesReference() const;
|
||||
|
||||
protected:
|
||||
virtual void downloadFinished(const QByteArray& data) override;
|
||||
|
||||
protected slots:
|
||||
void animationParseSuccess(FBXGeometry::Pointer geometry);
|
||||
void animationParseSuccess(HFMGeometry::Pointer geometry);
|
||||
void animationParseError(int error, QString str);
|
||||
|
||||
private:
|
||||
|
||||
FBXGeometry::Pointer _geometry;
|
||||
HFMGeometry::Pointer _geometry;
|
||||
};
|
||||
|
||||
/// Reads geometry in a worker thread.
|
||||
|
@ -105,7 +105,7 @@ public:
|
|||
virtual void run() override;
|
||||
|
||||
signals:
|
||||
void onSuccess(FBXGeometry::Pointer geometry);
|
||||
void onSuccess(HFMGeometry::Pointer geometry);
|
||||
void onError(int error, QString str);
|
||||
|
||||
private:
|
||||
|
|
|
@ -19,17 +19,17 @@ QStringList AnimationObject::getJointNames() const {
|
|||
return qscriptvalue_cast<AnimationPointer>(thisObject())->getJointNames();
|
||||
}
|
||||
|
||||
QVector<FBXAnimationFrame> AnimationObject::getFrames() const {
|
||||
QVector<HFMAnimationFrame> AnimationObject::getFrames() const {
|
||||
return qscriptvalue_cast<AnimationPointer>(thisObject())->getFrames();
|
||||
}
|
||||
|
||||
QVector<glm::quat> AnimationFrameObject::getRotations() const {
|
||||
return qscriptvalue_cast<FBXAnimationFrame>(thisObject()).rotations;
|
||||
return qscriptvalue_cast<HFMAnimationFrame>(thisObject()).rotations;
|
||||
}
|
||||
|
||||
void registerAnimationTypes(QScriptEngine* engine) {
|
||||
qScriptRegisterSequenceMetaType<QVector<FBXAnimationFrame> >(engine);
|
||||
engine->setDefaultPrototype(qMetaTypeId<FBXAnimationFrame>(), engine->newQObject(
|
||||
qScriptRegisterSequenceMetaType<QVector<HFMAnimationFrame> >(engine);
|
||||
engine->setDefaultPrototype(qMetaTypeId<HFMAnimationFrame>(), engine->newQObject(
|
||||
new AnimationFrameObject(), QScriptEngine::ScriptOwnership));
|
||||
engine->setDefaultPrototype(qMetaTypeId<AnimationPointer>(), engine->newQObject(
|
||||
new AnimationObject(), QScriptEngine::ScriptOwnership));
|
||||
|
|
|
@ -23,13 +23,13 @@ class QScriptEngine;
|
|||
class AnimationObject : public QObject, protected QScriptable {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QStringList jointNames READ getJointNames)
|
||||
Q_PROPERTY(QVector<FBXAnimationFrame> frames READ getFrames)
|
||||
Q_PROPERTY(QVector<HFMAnimationFrame> frames READ getFrames)
|
||||
|
||||
public:
|
||||
|
||||
Q_INVOKABLE QStringList getJointNames() const;
|
||||
|
||||
Q_INVOKABLE QVector<FBXAnimationFrame> getFrames() const;
|
||||
Q_INVOKABLE QVector<HFMAnimationFrame> getFrames() const;
|
||||
};
|
||||
|
||||
/// Scriptable wrapper for animation frames.
|
||||
|
|
|
@ -260,7 +260,7 @@ void Rig::destroyAnimGraph() {
|
|||
_rightEyeJointChildren.clear();
|
||||
}
|
||||
|
||||
void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOffset) {
|
||||
void Rig::initJointStates(const HFMGeometry& geometry, const glm::mat4& modelOffset) {
|
||||
_geometryOffset = AnimPose(geometry.offset);
|
||||
_invGeometryOffset = _geometryOffset.inverse();
|
||||
_geometryToRigTransform = modelOffset * geometry.offset;
|
||||
|
@ -307,7 +307,7 @@ void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOff
|
|||
_rightEyeJointChildren = _animSkeleton->getChildrenOfJoint(geometry.rightEyeJointIndex);
|
||||
}
|
||||
|
||||
void Rig::reset(const FBXGeometry& geometry) {
|
||||
void Rig::reset(const HFMGeometry& geometry) {
|
||||
_geometryOffset = AnimPose(geometry.offset);
|
||||
_invGeometryOffset = _geometryOffset.inverse();
|
||||
_animSkeleton = std::make_shared<AnimSkeleton>(geometry);
|
||||
|
@ -1253,7 +1253,7 @@ const glm::vec3 DOP14_NORMALS[DOP14_COUNT] = {
|
|||
// returns true if the given point lies inside of the k-dop, specified by shapeInfo & shapePose.
|
||||
// if the given point does lie within the k-dop, it also returns the amount of displacement necessary to push that point outward
|
||||
// such that it lies on the surface of the kdop.
|
||||
static bool findPointKDopDisplacement(const glm::vec3& point, const AnimPose& shapePose, const FBXJointShapeInfo& shapeInfo, glm::vec3& displacementOut) {
|
||||
static bool findPointKDopDisplacement(const glm::vec3& point, const AnimPose& shapePose, const HFMJointShapeInfo& shapeInfo, glm::vec3& displacementOut) {
|
||||
|
||||
// transform point into local space of jointShape.
|
||||
glm::vec3 localPoint = shapePose.inverse().xformPoint(point);
|
||||
|
@ -1299,8 +1299,8 @@ static bool findPointKDopDisplacement(const glm::vec3& point, const AnimPose& sh
|
|||
}
|
||||
}
|
||||
|
||||
glm::vec3 Rig::deflectHandFromTorso(const glm::vec3& handPosition, const FBXJointShapeInfo& hipsShapeInfo, const FBXJointShapeInfo& spineShapeInfo,
|
||||
const FBXJointShapeInfo& spine1ShapeInfo, const FBXJointShapeInfo& spine2ShapeInfo) const {
|
||||
glm::vec3 Rig::deflectHandFromTorso(const glm::vec3& handPosition, const HFMJointShapeInfo& hipsShapeInfo, const HFMJointShapeInfo& spineShapeInfo,
|
||||
const HFMJointShapeInfo& spine1ShapeInfo, const HFMJointShapeInfo& spine2ShapeInfo) const {
|
||||
glm::vec3 position = handPosition;
|
||||
glm::vec3 displacement;
|
||||
int hipsJoint = indexOfJoint("Hips");
|
||||
|
@ -1349,8 +1349,8 @@ glm::vec3 Rig::deflectHandFromTorso(const glm::vec3& handPosition, const FBXJoin
|
|||
void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnabled, bool hipsEstimated,
|
||||
bool leftArmEnabled, bool rightArmEnabled, bool headEnabled, float dt,
|
||||
const AnimPose& leftHandPose, const AnimPose& rightHandPose,
|
||||
const FBXJointShapeInfo& hipsShapeInfo, const FBXJointShapeInfo& spineShapeInfo,
|
||||
const FBXJointShapeInfo& spine1ShapeInfo, const FBXJointShapeInfo& spine2ShapeInfo,
|
||||
const HFMJointShapeInfo& hipsShapeInfo, const HFMJointShapeInfo& spineShapeInfo,
|
||||
const HFMJointShapeInfo& spine1ShapeInfo, const HFMJointShapeInfo& spine2ShapeInfo,
|
||||
const glm::mat4& rigToSensorMatrix, const glm::mat4& sensorToRigMatrix) {
|
||||
|
||||
const bool ENABLE_POLE_VECTORS = true;
|
||||
|
@ -2008,7 +2008,7 @@ void Rig::computeExternalPoses(const glm::mat4& modelOffsetMat) {
|
|||
}
|
||||
|
||||
void Rig::computeAvatarBoundingCapsule(
|
||||
const FBXGeometry& geometry,
|
||||
const HFMGeometry& geometry,
|
||||
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 FBXJointShapeInfo& shapeInfo = geometry.joints.at(index).shapeInfo;
|
||||
const HFMJointShapeInfo& shapeInfo = geometry.joints.at(index).shapeInfo;
|
||||
AnimPose pose = _animSkeleton->getAbsoluteDefaultPose(index);
|
||||
if (shapeInfo.points.size() > 0) {
|
||||
for (auto& point : shapeInfo.points) {
|
||||
|
|
|
@ -86,10 +86,10 @@ public:
|
|||
AnimPose secondaryControllerPoses[NumSecondaryControllerTypes]; // rig space
|
||||
uint8_t secondaryControllerFlags[NumSecondaryControllerTypes];
|
||||
bool isTalking;
|
||||
FBXJointShapeInfo hipsShapeInfo;
|
||||
FBXJointShapeInfo spineShapeInfo;
|
||||
FBXJointShapeInfo spine1ShapeInfo;
|
||||
FBXJointShapeInfo spine2ShapeInfo;
|
||||
HFMJointShapeInfo hipsShapeInfo;
|
||||
HFMJointShapeInfo spineShapeInfo;
|
||||
HFMJointShapeInfo spine1ShapeInfo;
|
||||
HFMJointShapeInfo spine2ShapeInfo;
|
||||
};
|
||||
|
||||
struct EyeParameters {
|
||||
|
@ -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 FBXGeometry& geometry, const glm::mat4& modelOffset);
|
||||
void reset(const FBXGeometry& geometry);
|
||||
void initJointStates(const HFMGeometry& geometry, const glm::mat4& modelOffset);
|
||||
void reset(const HFMGeometry& geometry);
|
||||
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 FBXGeometry& geometry, float& radiusOut, float& heightOut, glm::vec3& offsetOut) const;
|
||||
void computeAvatarBoundingCapsule(const HFMGeometry& geometry, float& radiusOut, float& heightOut, glm::vec3& offsetOut) const;
|
||||
|
||||
void setEnableInverseKinematics(bool enable);
|
||||
void setEnableAnimations(bool enable);
|
||||
|
@ -245,8 +245,8 @@ protected:
|
|||
void updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnabled, bool hipsEstimated,
|
||||
bool leftArmEnabled, bool rightArmEnabled, bool headEnabled, float dt,
|
||||
const AnimPose& leftHandPose, const AnimPose& rightHandPose,
|
||||
const FBXJointShapeInfo& hipsShapeInfo, const FBXJointShapeInfo& spineShapeInfo,
|
||||
const FBXJointShapeInfo& spine1ShapeInfo, const FBXJointShapeInfo& spine2ShapeInfo,
|
||||
const HFMJointShapeInfo& hipsShapeInfo, const HFMJointShapeInfo& spineShapeInfo,
|
||||
const HFMJointShapeInfo& spine1ShapeInfo, const HFMJointShapeInfo& spine2ShapeInfo,
|
||||
const glm::mat4& rigToSensorMatrix, const glm::mat4& sensorToRigMatrix);
|
||||
void updateFeet(bool leftFootEnabled, bool rightFootEnabled, bool headEnabled,
|
||||
const AnimPose& leftFootPose, const AnimPose& rightFootPose,
|
||||
|
@ -257,8 +257,8 @@ protected:
|
|||
|
||||
bool calculateElbowPoleVector(int handIndex, int elbowIndex, int armIndex, int oppositeArmIndex, glm::vec3& poleVector) const;
|
||||
glm::vec3 calculateKneePoleVector(int footJointIndex, int kneeJoint, int upLegIndex, int hipsIndex, const AnimPose& targetFootPose) const;
|
||||
glm::vec3 deflectHandFromTorso(const glm::vec3& handPosition, const FBXJointShapeInfo& hipsShapeInfo, const FBXJointShapeInfo& spineShapeInfo,
|
||||
const FBXJointShapeInfo& spine1ShapeInfo, const FBXJointShapeInfo& spine2ShapeInfo) const;
|
||||
glm::vec3 deflectHandFromTorso(const glm::vec3& handPosition, const HFMJointShapeInfo& hipsShapeInfo, const HFMJointShapeInfo& spineShapeInfo,
|
||||
const HFMJointShapeInfo& spine1ShapeInfo, const HFMJointShapeInfo& spine2ShapeInfo) const;
|
||||
|
||||
|
||||
AnimPose _modelOffset; // model to rig space
|
||||
|
|
|
@ -244,13 +244,20 @@ AudioClient::AudioClient() :
|
|||
// initialize wasapi; if getAvailableDevices is called from the CheckDevicesThread before this, it will crash
|
||||
getAvailableDevices(QAudio::AudioInput);
|
||||
getAvailableDevices(QAudio::AudioOutput);
|
||||
|
||||
|
||||
// start a thread to detect any device changes
|
||||
_checkDevicesTimer = new QTimer(this);
|
||||
connect(_checkDevicesTimer, &QTimer::timeout, this, [this] {
|
||||
QtConcurrent::run(QThreadPool::globalInstance(), [this] { checkDevices(); });
|
||||
});
|
||||
const unsigned long DEVICE_CHECK_INTERVAL_MSECS = 2 * 1000;
|
||||
connect(_checkDevicesTimer, &QTimer::timeout, this, [=] {
|
||||
QtConcurrent::run(QThreadPool::globalInstance(), [=] {
|
||||
checkDevices();
|
||||
// On some systems (Ubuntu) checking all the audio devices can take more than 2 seconds. To
|
||||
// avoid consuming all of the thread pool, don't start the check interval until the previous
|
||||
// check has completed.
|
||||
QMetaObject::invokeMethod(_checkDevicesTimer, "start", Q_ARG(int, DEVICE_CHECK_INTERVAL_MSECS));
|
||||
});
|
||||
});
|
||||
_checkDevicesTimer->setSingleShot(true);
|
||||
_checkDevicesTimer->start(DEVICE_CHECK_INTERVAL_MSECS);
|
||||
|
||||
// start a thread to detect peak value changes
|
||||
|
|
|
@ -498,8 +498,8 @@ void Avatar::relayJointDataToChildren() {
|
|||
glm::quat jointRotation;
|
||||
glm::vec3 jointTranslation;
|
||||
if (avatarJointIndex < 0) {
|
||||
jointRotation = modelEntity->getAbsoluteJointRotationInObjectFrame(jointIndex);
|
||||
jointTranslation = modelEntity->getAbsoluteJointTranslationInObjectFrame(jointIndex);
|
||||
jointRotation = modelEntity->getLocalJointRotation(jointIndex);
|
||||
jointTranslation = modelEntity->getLocalJointTranslation(jointIndex);
|
||||
map.push_back(-1);
|
||||
} else {
|
||||
int jointIndex = getJointIndex(jointName);
|
||||
|
@ -522,8 +522,8 @@ void Avatar::relayJointDataToChildren() {
|
|||
jointRotation = getJointRotation(avatarJointIndex);
|
||||
jointTranslation = getJointTranslation(avatarJointIndex);
|
||||
} else {
|
||||
jointRotation = modelEntity->getAbsoluteJointRotationInObjectFrame(jointIndex);
|
||||
jointTranslation = modelEntity->getAbsoluteJointTranslationInObjectFrame(jointIndex);
|
||||
jointRotation = modelEntity->getLocalJointRotation(jointIndex);
|
||||
jointTranslation = modelEntity->getLocalJointTranslation(jointIndex);
|
||||
}
|
||||
modelEntity->setLocalJointRotation(jointIndex, jointRotation);
|
||||
modelEntity->setLocalJointTranslation(jointIndex, jointTranslation);
|
||||
|
@ -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->getFBXGeometry().headJointIndex;
|
||||
int headJointIndex = _skeletonModel->getHFMGeometry().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->getFBXGeometry().headJointIndex;
|
||||
int headJointIndex = _skeletonModel->getHFMGeometry().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->getFBXGeometry().jointIndices;
|
||||
_modelJointIndicesCache = _skeletonModel->getHFMGeometry().jointIndices;
|
||||
_modelJointsCached = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ void SkeletonModel::setTextures(const QVariantMap& textures) {
|
|||
}
|
||||
|
||||
void SkeletonModel::initJointStates() {
|
||||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset);
|
||||
_rig.initJointStates(geometry, modelOffset);
|
||||
|
||||
|
@ -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 FBXGeometry& geometry = getFBXGeometry();
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
|
||||
Head* head = _owningAvatar->getHead();
|
||||
|
||||
|
@ -259,22 +259,22 @@ bool SkeletonModel::getRightShoulderPosition(glm::vec3& position) const {
|
|||
}
|
||||
|
||||
bool SkeletonModel::getHeadPosition(glm::vec3& headPosition) const {
|
||||
return isActive() && getJointPositionInWorldFrame(getFBXGeometry().headJointIndex, headPosition);
|
||||
return isActive() && getJointPositionInWorldFrame(getHFMGeometry().headJointIndex, headPosition);
|
||||
}
|
||||
|
||||
bool SkeletonModel::getNeckPosition(glm::vec3& neckPosition) const {
|
||||
return isActive() && getJointPositionInWorldFrame(getFBXGeometry().neckJointIndex, neckPosition);
|
||||
return isActive() && getJointPositionInWorldFrame(getHFMGeometry().neckJointIndex, neckPosition);
|
||||
}
|
||||
|
||||
bool SkeletonModel::getLocalNeckPosition(glm::vec3& neckPosition) const {
|
||||
return isActive() && getJointPosition(getFBXGeometry().neckJointIndex, neckPosition);
|
||||
return isActive() && getJointPosition(getHFMGeometry().neckJointIndex, neckPosition);
|
||||
}
|
||||
|
||||
bool SkeletonModel::getEyeModelPositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const {
|
||||
if (!isActive()) {
|
||||
return false;
|
||||
}
|
||||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
|
||||
if (getJointPosition(geometry.leftEyeJointIndex, firstEyePosition) &&
|
||||
getJointPosition(geometry.rightEyeJointIndex, secondEyePosition)) {
|
||||
|
@ -330,7 +330,7 @@ void SkeletonModel::computeBoundingShape() {
|
|||
return;
|
||||
}
|
||||
|
||||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
if (geometry.joints.isEmpty() || geometry.rootJointIndex == -1) {
|
||||
// rootJointIndex == -1 if the avatar model has no skeleton
|
||||
return;
|
||||
|
@ -369,7 +369,7 @@ void SkeletonModel::renderBoundingCollisionShapes(RenderArgs* args, gpu::Batch&
|
|||
}
|
||||
|
||||
bool SkeletonModel::hasSkeleton() {
|
||||
return isActive() ? getFBXGeometry().rootJointIndex != -1 : false;
|
||||
return isActive() ? getHFMGeometry().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() ? getFBXGeometry().leftHandJointIndex : -1; }
|
||||
int getLeftHandJointIndex() const { return isActive() ? getHFMGeometry().leftHandJointIndex : -1; }
|
||||
|
||||
/// Returns the index of the right hand joint, or -1 if not found.
|
||||
int getRightHandJointIndex() const { return isActive() ? getFBXGeometry().rightHandJointIndex : -1; }
|
||||
int getRightHandJointIndex() const { return isActive() ? getHFMGeometry().rightHandJointIndex : -1; }
|
||||
|
||||
bool getLeftGrabPosition(glm::vec3& position) const;
|
||||
bool getRightGrabPosition(glm::vec3& position) const;
|
||||
|
|
|
@ -206,7 +206,7 @@ void FBXBaker::importScene() {
|
|||
}
|
||||
#endif
|
||||
|
||||
_geometry = reader.extractFBXGeometry({}, _modelURL.toString());
|
||||
_geometry = reader.extractHFMGeometry({}, _modelURL.toString());
|
||||
_textureContentMap = reader._textureContent;
|
||||
}
|
||||
|
||||
|
@ -329,7 +329,7 @@ void FBXBaker::rewriteAndBakeSceneTextures() {
|
|||
for (FBXNode& textureChild : object->children) {
|
||||
|
||||
if (textureChild.name == "RelativeFilename") {
|
||||
QString fbxTextureFileName { textureChild.properties.at(0).toString() };
|
||||
QString hfmTextureFileName { textureChild.properties.at(0).toString() };
|
||||
|
||||
// grab the ID for this texture so we can figure out the
|
||||
// texture type from the loaded materials
|
||||
|
@ -337,7 +337,7 @@ void FBXBaker::rewriteAndBakeSceneTextures() {
|
|||
auto textureType = textureTypes[textureID];
|
||||
|
||||
// Compress the texture information and return the new filename to be added into the FBX scene
|
||||
auto bakedTextureFile = compressTexture(fbxTextureFileName, textureType);
|
||||
auto bakedTextureFile = compressTexture(hfmTextureFileName, textureType);
|
||||
|
||||
// If no errors or warnings have occurred during texture compression add the filename to the FBX scene
|
||||
if (!bakedTextureFile.isNull()) {
|
||||
|
|
|
@ -53,7 +53,7 @@ private:
|
|||
void rewriteAndBakeSceneModels();
|
||||
void rewriteAndBakeSceneTextures();
|
||||
|
||||
FBXGeometry* _geometry;
|
||||
HFMGeometry* _geometry;
|
||||
QHash<QString, int> _textureNameMatchCount;
|
||||
QHash<QUrl, QString> _remappedTexturePaths;
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ void ModelBaker::abort() {
|
|||
}
|
||||
}
|
||||
|
||||
bool ModelBaker::compressMesh(FBXMesh& mesh, bool hasDeformers, FBXNode& dracoMeshNode, GetMaterialIDCallback materialIDCallback) {
|
||||
bool ModelBaker::compressMesh(HFMMesh& mesh, bool hasDeformers, FBXNode& dracoMeshNode, GetMaterialIDCallback materialIDCallback) {
|
||||
if (mesh.wasCompressed) {
|
||||
handleError("Cannot re-bake a file that contains compressed mesh");
|
||||
return false;
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
const QString& bakedOutputDirectory, const QString& originalOutputDirectory = "");
|
||||
virtual ~ModelBaker();
|
||||
|
||||
bool compressMesh(FBXMesh& mesh, bool hasDeformers, FBXNode& dracoMeshNode, GetMaterialIDCallback materialIDCallback = nullptr);
|
||||
bool compressMesh(HFMMesh& mesh, bool hasDeformers, FBXNode& dracoMeshNode, GetMaterialIDCallback materialIDCallback = nullptr);
|
||||
QString compressTexture(QString textureFileName, image::TextureUsage::Type = image::TextureUsage::Type::DEFAULT_TEXTURE);
|
||||
virtual void setWasAborted(bool wasAborted) override;
|
||||
|
||||
|
|
|
@ -153,7 +153,7 @@ void OBJBaker::bakeOBJ() {
|
|||
checkIfTexturesFinished();
|
||||
}
|
||||
|
||||
void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
||||
void OBJBaker::createFBXNodeTree(FBXNode& rootNode, HFMGeometry& geometry) {
|
||||
// Generating FBX Header Node
|
||||
FBXNode headerNode;
|
||||
headerNode.name = FBX_HEADER_EXTENSION;
|
||||
|
@ -235,7 +235,7 @@ void OBJBaker::createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry) {
|
|||
auto size = meshParts.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
QString material = meshParts[i].materialID;
|
||||
FBXMaterial currentMaterial = geometry.materials[material];
|
||||
HFMMaterial currentMaterial = geometry.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, FBXGeometry& geometry) {
|
|||
}
|
||||
|
||||
// Set properties for material nodes
|
||||
void OBJBaker::setMaterialNodeProperties(FBXNode& materialNode, QString material, FBXGeometry& geometry) {
|
||||
void OBJBaker::setMaterialNodeProperties(FBXNode& materialNode, QString material, HFMGeometry& geometry) {
|
||||
auto materialID = nextNodeID();
|
||||
_materialIDs.push_back(materialID);
|
||||
materialNode.properties = { materialID, material, MESH };
|
||||
|
||||
FBXMaterial currentMaterial = geometry.materials[material];
|
||||
HFMMaterial currentMaterial = geometry.materials[material];
|
||||
|
||||
// Setting the hierarchy: Material -> Properties70 -> P -> Properties
|
||||
FBXNode properties70Node;
|
||||
|
|
|
@ -39,8 +39,8 @@ private slots:
|
|||
|
||||
private:
|
||||
void loadOBJ();
|
||||
void createFBXNodeTree(FBXNode& rootNode, FBXGeometry& geometry);
|
||||
void setMaterialNodeProperties(FBXNode& materialNode, QString material, FBXGeometry& geometry);
|
||||
void createFBXNodeTree(FBXNode& rootNode, HFMGeometry& geometry);
|
||||
void setMaterialNodeProperties(FBXNode& materialNode, QString material, HFMGeometry& geometry);
|
||||
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->getFBXGeometry().getUnscaledMeshExtents();
|
||||
Extents meshExtents = model->getHFMGeometry().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 FBXGeometry& collisionGeometry = _compoundShapeResource->getFBXGeometry();
|
||||
const HFMGeometry& collisionGeometry = _compoundShapeResource->getHFMGeometry();
|
||||
|
||||
ShapeInfo::PointCollection& pointCollection = shapeInfo.getPointCollection();
|
||||
pointCollection.clear();
|
||||
|
@ -411,15 +411,15 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
|
||||
// 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 FBXMesh& mesh, collisionGeometry.meshes) {
|
||||
foreach (const HFMMesh& mesh, collisionGeometry.meshes) {
|
||||
// each meshPart is a convex hull
|
||||
foreach (const FBXMeshPart &meshPart, mesh.parts) {
|
||||
foreach (const HFMMeshPart &meshPart, mesh.parts) {
|
||||
pointCollection.push_back(QVector<glm::vec3>());
|
||||
ShapeInfo::PointList& pointsInPart = pointCollection[i];
|
||||
|
||||
// run through all the triangles and (uniquely) add each point to the hull
|
||||
uint32_t numIndices = (uint32_t)meshPart.triangleIndices.size();
|
||||
// TODO: assert rather than workaround after we start sanitizing FBXMesh higher up
|
||||
// TODO: assert rather than workaround after we start sanitizing HFMMesh higher up
|
||||
//assert(numIndices % TRIANGLE_STRIDE == 0);
|
||||
numIndices -= numIndices % TRIANGLE_STRIDE; // WORKAROUND lack of sanity checking in FBXReader
|
||||
|
||||
|
@ -440,7 +440,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
|
||||
// run through all the quads and (uniquely) add each point to the hull
|
||||
numIndices = (uint32_t)meshPart.quadIndices.size();
|
||||
// TODO: assert rather than workaround after we start sanitizing FBXMesh higher up
|
||||
// TODO: assert rather than workaround after we start sanitizing HFMMesh higher up
|
||||
//assert(numIndices % QUAD_STRIDE == 0);
|
||||
numIndices -= numIndices % QUAD_STRIDE; // WORKAROUND lack of sanity checking in FBXReader
|
||||
|
||||
|
@ -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->getFBXGeometry().getUnscaledMeshExtents().size();
|
||||
glm::vec3 scaleToFit = dimensions / model->getHFMGeometry().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,14 +498,14 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
|
||||
// compute meshPart local transforms
|
||||
QVector<glm::mat4> localTransforms;
|
||||
const FBXGeometry& fbxGeometry = model->getFBXGeometry();
|
||||
int numFbxMeshes = fbxGeometry.meshes.size();
|
||||
const HFMGeometry& hfmGeometry = model->getHFMGeometry();
|
||||
int numHFMMeshes = hfmGeometry.meshes.size();
|
||||
int totalNumVertices = 0;
|
||||
glm::mat4 invRegistraionOffset = glm::translate(dimensions * (getRegistrationPoint() - ENTITY_ITEM_DEFAULT_REGISTRATION_POINT));
|
||||
for (int i = 0; i < numFbxMeshes; i++) {
|
||||
const FBXMesh& mesh = fbxGeometry.meshes.at(i);
|
||||
for (int i = 0; i < numHFMMeshes; i++) {
|
||||
const HFMMesh& mesh = hfmGeometry.meshes.at(i);
|
||||
if (mesh.clusters.size() > 0) {
|
||||
const FBXCluster& cluster = mesh.clusters.at(0);
|
||||
const HFMCluster& cluster = mesh.clusters.at(0);
|
||||
auto jointMatrix = model->getRig().getJointTransform(cluster.jointIndex);
|
||||
// we backtranslate by the registration offset so we can apply that offset to the shapeInfo later
|
||||
localTransforms.push_back(invRegistraionOffset * jointMatrix * cluster.inverseBindMatrix);
|
||||
|
@ -524,10 +524,10 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
|
||||
std::vector<std::shared_ptr<const graphics::Mesh>> meshes;
|
||||
if (type == SHAPE_TYPE_SIMPLE_COMPOUND) {
|
||||
auto& fbxMeshes = _compoundShapeResource->getFBXGeometry().meshes;
|
||||
meshes.reserve(fbxMeshes.size());
|
||||
for (auto& fbxMesh : fbxMeshes) {
|
||||
meshes.push_back(fbxMesh._mesh);
|
||||
auto& hfmMeshes = _compoundShapeResource->getHFMGeometry().meshes;
|
||||
meshes.reserve(hfmMeshes.size());
|
||||
for (auto& hfmMesh : hfmMeshes) {
|
||||
meshes.push_back(hfmMesh._mesh);
|
||||
}
|
||||
} else {
|
||||
meshes = model->getGeometry()->getMeshes();
|
||||
|
@ -594,7 +594,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
while (partItr != parts.cend<const graphics::Mesh::Part>()) {
|
||||
auto numIndices = partItr->_numIndices;
|
||||
if (partItr->_topology == graphics::Mesh::TRIANGLES) {
|
||||
// TODO: assert rather than workaround after we start sanitizing FBXMesh higher up
|
||||
// TODO: assert rather than workaround after we start sanitizing HFMMesh higher up
|
||||
//assert(numIndices % TRIANGLE_STRIDE == 0);
|
||||
numIndices -= numIndices % TRIANGLE_STRIDE; // WORKAROUND lack of sanity checking in FBXReader
|
||||
|
||||
|
@ -605,7 +605,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
++indexItr;
|
||||
}
|
||||
} else if (partItr->_topology == graphics::Mesh::TRIANGLE_STRIP) {
|
||||
// TODO: resurrect assert after we start sanitizing FBXMesh higher up
|
||||
// TODO: resurrect assert after we start sanitizing HFMMesh higher up
|
||||
//assert(numIndices > 2);
|
||||
|
||||
uint32_t approxNumIndices = TRIANGLE_STRIDE * numIndices;
|
||||
|
@ -651,7 +651,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
std::set<int32_t> uniqueIndices;
|
||||
auto numIndices = partItr->_numIndices;
|
||||
if (partItr->_topology == graphics::Mesh::TRIANGLES) {
|
||||
// TODO: assert rather than workaround after we start sanitizing FBXMesh higher up
|
||||
// TODO: assert rather than workaround after we start sanitizing HFMMesh higher up
|
||||
//assert(numIndices% TRIANGLE_STRIDE == 0);
|
||||
numIndices -= numIndices % TRIANGLE_STRIDE; // WORKAROUND lack of sanity checking in FBXReader
|
||||
|
||||
|
@ -662,7 +662,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
++indexItr;
|
||||
}
|
||||
} else if (partItr->_topology == graphics::Mesh::TRIANGLE_STRIP) {
|
||||
// TODO: resurrect assert after we start sanitizing FBXMesh higher up
|
||||
// TODO: resurrect assert after we start sanitizing HFMMesh higher up
|
||||
//assert(numIndices > TRIANGLE_STRIDE - 1);
|
||||
|
||||
auto indexItr = indices.cbegin<const gpu::BufferView::Index>() + partItr->_startIndex;
|
||||
|
@ -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->getFBXGeometry().convexHullContains(worldToEntity(point));
|
||||
return _compoundShapeResource->getHFMGeometry().convexHullContains(worldToEntity(point));
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -1135,7 +1135,7 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
|
|||
|
||||
QVector<EntityJointData> jointsData;
|
||||
|
||||
const QVector<FBXAnimationFrame>& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy
|
||||
const QVector<HFMAnimationFrame>& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy
|
||||
int frameCount = frames.size();
|
||||
if (frameCount <= 0) {
|
||||
return;
|
||||
|
@ -1160,10 +1160,10 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
|
|||
}
|
||||
|
||||
QStringList animationJointNames = _animation->getGeometry().getJointNames();
|
||||
auto& fbxJoints = _animation->getGeometry().joints;
|
||||
auto& hfmJoints = _animation->getGeometry().joints;
|
||||
|
||||
auto& originalFbxJoints = _model->getFBXGeometry().joints;
|
||||
auto& originalFbxIndices = _model->getFBXGeometry().jointIndices;
|
||||
auto& originalHFMJoints = _model->getHFMGeometry().joints;
|
||||
auto& originalHFMIndices = _model->getHFMGeometry().jointIndices;
|
||||
|
||||
bool allowTranslation = entity->getAnimationAllowTranslation();
|
||||
|
||||
|
@ -1182,22 +1182,22 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
|
|||
translationMat = glm::translate(translations[index]);
|
||||
}
|
||||
} else if (index < animationJointNames.size()) {
|
||||
QString jointName = fbxJoints[index].name; // Pushing this here so its not done on every entity, with the exceptions of those allowing for translation
|
||||
if (originalFbxIndices.contains(jointName)) {
|
||||
QString jointName = hfmJoints[index].name; // Pushing this here so its not done on every entity, with the exceptions of those allowing for translation
|
||||
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 it's translation.
|
||||
int remappedIndex = originalFbxIndices[jointName] - 1; // JointIndeces seem to always start from 1 and the found index is always 1 higher than actual.
|
||||
translationMat = glm::translate(originalFbxJoints[remappedIndex].translation);
|
||||
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);
|
||||
}
|
||||
}
|
||||
glm::mat4 rotationMat;
|
||||
if (index < rotations.size()) {
|
||||
rotationMat = glm::mat4_cast(fbxJoints[index].preRotation * rotations[index] * fbxJoints[index].postRotation);
|
||||
rotationMat = glm::mat4_cast(hfmJoints[index].preRotation * rotations[index] * hfmJoints[index].postRotation);
|
||||
} else {
|
||||
rotationMat = glm::mat4_cast(fbxJoints[index].preRotation * fbxJoints[index].postRotation);
|
||||
rotationMat = glm::mat4_cast(hfmJoints[index].preRotation * hfmJoints[index].postRotation);
|
||||
}
|
||||
|
||||
glm::mat4 finalMat = (translationMat * fbxJoints[index].preTransform *
|
||||
rotationMat * fbxJoints[index].postTransform);
|
||||
glm::mat4 finalMat = (translationMat * hfmJoints[index].preTransform *
|
||||
rotationMat * hfmJoints[index].postTransform);
|
||||
auto& jointData = jointsData[j];
|
||||
jointData.translation = extractTranslation(finalMat);
|
||||
jointData.translationSet = true;
|
||||
|
|
|
@ -70,8 +70,8 @@ public:
|
|||
};
|
||||
|
||||
|
||||
/// A single blendshape extracted from an FBX document.
|
||||
class FBXBlendshape {
|
||||
/// A single blendshape.
|
||||
class HFMBlendshape {
|
||||
public:
|
||||
QVector<int> indices;
|
||||
QVector<glm::vec3> vertices;
|
||||
|
@ -79,19 +79,19 @@ public:
|
|||
QVector<glm::vec3> tangents;
|
||||
};
|
||||
|
||||
struct FBXJointShapeInfo {
|
||||
// same units and frame as FBXJoint.translation
|
||||
struct HFMJointShapeInfo {
|
||||
// same units and frame as HFMJoint.translation
|
||||
glm::vec3 avgPoint;
|
||||
std::vector<float> dots;
|
||||
std::vector<glm::vec3> points;
|
||||
std::vector<glm::vec3> debugLines;
|
||||
};
|
||||
|
||||
/// A single joint (transformation node) extracted from an FBX document.
|
||||
class FBXJoint {
|
||||
/// A single joint (transformation node).
|
||||
class HFMJoint {
|
||||
public:
|
||||
|
||||
FBXJointShapeInfo shapeInfo;
|
||||
HFMJointShapeInfo shapeInfo;
|
||||
QVector<int> freeLineage;
|
||||
bool isFree;
|
||||
int parentIndex;
|
||||
|
@ -126,8 +126,8 @@ public:
|
|||
};
|
||||
|
||||
|
||||
/// A single binding to a joint in an FBX document.
|
||||
class FBXCluster {
|
||||
/// A single binding to a joint.
|
||||
class HFMCluster {
|
||||
public:
|
||||
|
||||
int jointIndex;
|
||||
|
@ -137,8 +137,8 @@ public:
|
|||
|
||||
const int MAX_NUM_PIXELS_FOR_FBX_TEXTURE = 2048 * 2048;
|
||||
|
||||
/// A texture map in an FBX document.
|
||||
class FBXTexture {
|
||||
/// A texture map.
|
||||
class HFMTexture {
|
||||
public:
|
||||
QString id;
|
||||
QString name;
|
||||
|
@ -156,7 +156,7 @@ public:
|
|||
};
|
||||
|
||||
/// A single part of a mesh (with the same material).
|
||||
class FBXMeshPart {
|
||||
class HFMMeshPart {
|
||||
public:
|
||||
|
||||
QVector<int> quadIndices; // original indices from the FBX mesh
|
||||
|
@ -166,10 +166,10 @@ public:
|
|||
QString materialID;
|
||||
};
|
||||
|
||||
class FBXMaterial {
|
||||
class HFMMaterial {
|
||||
public:
|
||||
FBXMaterial() {};
|
||||
FBXMaterial(const glm::vec3& diffuseColor, const glm::vec3& specularColor, const glm::vec3& emissiveColor,
|
||||
HFMMaterial() {};
|
||||
HFMMaterial(const glm::vec3& diffuseColor, const glm::vec3& specularColor, const glm::vec3& emissiveColor,
|
||||
float shininess, float opacity) :
|
||||
diffuseColor(diffuseColor),
|
||||
specularColor(specularColor),
|
||||
|
@ -203,17 +203,17 @@ public:
|
|||
QString shadingModel;
|
||||
graphics::MaterialPointer _material;
|
||||
|
||||
FBXTexture normalTexture;
|
||||
FBXTexture albedoTexture;
|
||||
FBXTexture opacityTexture;
|
||||
FBXTexture glossTexture;
|
||||
FBXTexture roughnessTexture;
|
||||
FBXTexture specularTexture;
|
||||
FBXTexture metallicTexture;
|
||||
FBXTexture emissiveTexture;
|
||||
FBXTexture occlusionTexture;
|
||||
FBXTexture scatteringTexture;
|
||||
FBXTexture lightmapTexture;
|
||||
HFMTexture normalTexture;
|
||||
HFMTexture albedoTexture;
|
||||
HFMTexture opacityTexture;
|
||||
HFMTexture glossTexture;
|
||||
HFMTexture roughnessTexture;
|
||||
HFMTexture specularTexture;
|
||||
HFMTexture metallicTexture;
|
||||
HFMTexture emissiveTexture;
|
||||
HFMTexture occlusionTexture;
|
||||
HFMTexture scatteringTexture;
|
||||
HFMTexture lightmapTexture;
|
||||
glm::vec2 lightmapParams{ 0.0f, 1.0f };
|
||||
|
||||
|
||||
|
@ -232,10 +232,10 @@ public:
|
|||
};
|
||||
|
||||
/// A single mesh (with optional blendshapes) extracted from an FBX document.
|
||||
class FBXMesh {
|
||||
class HFMMesh {
|
||||
public:
|
||||
|
||||
QVector<FBXMeshPart> parts;
|
||||
QVector<HFMMeshPart> parts;
|
||||
|
||||
QVector<glm::vec3> vertices;
|
||||
QVector<glm::vec3> normals;
|
||||
|
@ -247,12 +247,12 @@ public:
|
|||
QVector<uint16_t> clusterWeights;
|
||||
QVector<int32_t> originalIndices;
|
||||
|
||||
QVector<FBXCluster> clusters;
|
||||
QVector<HFMCluster> clusters;
|
||||
|
||||
Extents meshExtents;
|
||||
glm::mat4 modelTransform;
|
||||
|
||||
QVector<FBXBlendshape> blendshapes;
|
||||
QVector<HFMBlendshape> blendshapes;
|
||||
|
||||
unsigned int meshIndex; // the order the meshes appeared in the object file
|
||||
|
||||
|
@ -265,7 +265,7 @@ public:
|
|||
|
||||
class ExtractedMesh {
|
||||
public:
|
||||
FBXMesh mesh;
|
||||
HFMMesh mesh;
|
||||
QMultiHash<int, int> newIndices;
|
||||
QVector<QHash<int, int> > blendshapeIndexMaps;
|
||||
QVector<QPair<int, int> > partMaterialTextures;
|
||||
|
@ -278,14 +278,14 @@ public:
|
|||
* @property {Vec3[]} translations
|
||||
*/
|
||||
/// A single animation frame extracted from an FBX document.
|
||||
class FBXAnimationFrame {
|
||||
class HFMAnimationFrame {
|
||||
public:
|
||||
QVector<glm::quat> rotations;
|
||||
QVector<glm::vec3> translations;
|
||||
};
|
||||
|
||||
/// A light in an FBX document.
|
||||
class FBXLight {
|
||||
/// A light.
|
||||
class HFMLight {
|
||||
public:
|
||||
QString name;
|
||||
Transform transform;
|
||||
|
@ -293,7 +293,7 @@ public:
|
|||
float fogValue;
|
||||
glm::vec3 color;
|
||||
|
||||
FBXLight() :
|
||||
HFMLight() :
|
||||
name(),
|
||||
transform(),
|
||||
intensity(1.0f),
|
||||
|
@ -302,26 +302,26 @@ public:
|
|||
{}
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(FBXAnimationFrame)
|
||||
Q_DECLARE_METATYPE(QVector<FBXAnimationFrame>)
|
||||
Q_DECLARE_METATYPE(HFMAnimationFrame)
|
||||
Q_DECLARE_METATYPE(QVector<HFMAnimationFrame>)
|
||||
|
||||
/// A set of meshes extracted from an FBX document.
|
||||
class FBXGeometry {
|
||||
class HFMGeometry {
|
||||
public:
|
||||
using Pointer = std::shared_ptr<FBXGeometry>;
|
||||
using Pointer = std::shared_ptr<HFMGeometry>;
|
||||
|
||||
QString originalURL;
|
||||
QString author;
|
||||
QString applicationName; ///< the name of the application that generated the model
|
||||
|
||||
QVector<FBXJoint> joints;
|
||||
QVector<HFMJoint> joints;
|
||||
QHash<QString, int> jointIndices; ///< 1-based, so as to more easily detect missing indices
|
||||
bool hasSkeletonJoints;
|
||||
|
||||
QVector<FBXMesh> meshes;
|
||||
QVector<HFMMesh> meshes;
|
||||
QVector<QString> scripts;
|
||||
|
||||
QHash<QString, FBXMaterial> materials;
|
||||
QHash<QString, HFMMaterial> materials;
|
||||
|
||||
glm::mat4 offset; // This includes offset, rotation, and scale as specified by the FST file
|
||||
|
||||
|
@ -348,7 +348,7 @@ public:
|
|||
Extents bindExtents;
|
||||
Extents meshExtents;
|
||||
|
||||
QVector<FBXAnimationFrame> animationFrames;
|
||||
QVector<HFMAnimationFrame> animationFrames;
|
||||
|
||||
int getJointIndex(const QString& name) const { return jointIndices.value(name) - 1; }
|
||||
QStringList getJointNames() const;
|
||||
|
@ -368,7 +368,7 @@ public:
|
|||
QList<QString> blendshapeChannelNames;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(FBXGeometry)
|
||||
Q_DECLARE_METATYPE(FBXGeometry::Pointer)
|
||||
Q_DECLARE_METATYPE(HFMGeometry)
|
||||
Q_DECLARE_METATYPE(HFMGeometry::Pointer)
|
||||
|
||||
#endif // hifi_FBX_h_
|
||||
|
|
|
@ -40,19 +40,19 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
int FBXGeometryPointerMetaTypeId = qRegisterMetaType<FBXGeometry::Pointer>();
|
||||
int HFMGeometryPointerMetaTypeId = qRegisterMetaType<HFMGeometry::Pointer>();
|
||||
|
||||
QStringList FBXGeometry::getJointNames() const {
|
||||
QStringList HFMGeometry::getJointNames() const {
|
||||
QStringList names;
|
||||
foreach (const FBXJoint& joint, joints) {
|
||||
foreach (const HFMJoint& joint, joints) {
|
||||
names.append(joint.name);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
bool FBXGeometry::hasBlendedMeshes() const {
|
||||
bool HFMGeometry::hasBlendedMeshes() const {
|
||||
if (!meshes.isEmpty()) {
|
||||
foreach (const FBXMesh& mesh, meshes) {
|
||||
foreach (const HFMMesh& mesh, meshes) {
|
||||
if (!mesh.blendshapes.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ bool FBXGeometry::hasBlendedMeshes() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
Extents FBXGeometry::getUnscaledMeshExtents() const {
|
||||
Extents HFMGeometry::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,12 +74,12 @@ Extents FBXGeometry::getUnscaledMeshExtents() const {
|
|||
}
|
||||
|
||||
// TODO: Move to graphics::Mesh when Sam's ready
|
||||
bool FBXGeometry::convexHullContains(const glm::vec3& point) const {
|
||||
bool HFMGeometry::convexHullContains(const glm::vec3& point) const {
|
||||
if (!getUnscaledMeshExtents().containsPoint(point)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto checkEachPrimitive = [=](FBXMesh& mesh, QVector<int> indices, int primitiveSize) -> bool {
|
||||
auto checkEachPrimitive = [=](HFMMesh& mesh, QVector<int> indices, int primitiveSize) -> bool {
|
||||
// Check whether the point is "behind" all the primitives.
|
||||
int verticesSize = mesh.vertices.size();
|
||||
for (int j = 0;
|
||||
|
@ -124,16 +124,16 @@ bool FBXGeometry::convexHullContains(const glm::vec3& point) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
QString FBXGeometry::getModelNameOfMesh(int meshIndex) const {
|
||||
QString HFMGeometry::getModelNameOfMesh(int meshIndex) const {
|
||||
if (meshIndicesToModelNames.contains(meshIndex)) {
|
||||
return meshIndicesToModelNames.value(meshIndex);
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
int fbxGeometryMetaTypeId = qRegisterMetaType<FBXGeometry>();
|
||||
int fbxAnimationFrameMetaTypeId = qRegisterMetaType<FBXAnimationFrame>();
|
||||
int fbxAnimationFrameVectorMetaTypeId = qRegisterMetaType<QVector<FBXAnimationFrame> >();
|
||||
int hfmGeometryMetaTypeId = qRegisterMetaType<HFMGeometry>();
|
||||
int hfmAnimationFrameMetaTypeId = qRegisterMetaType<HFMAnimationFrame>();
|
||||
int hfmAnimationFrameVectorMetaTypeId = qRegisterMetaType<QVector<HFMAnimationFrame> >();
|
||||
|
||||
|
||||
glm::vec3 parseVec3(const QString& string) {
|
||||
|
@ -303,7 +303,7 @@ glm::mat4 getGlobalTransform(const QMultiMap<QString, QString>& _connectionParen
|
|||
class ExtractedBlendshape {
|
||||
public:
|
||||
QString id;
|
||||
FBXBlendshape blendshape;
|
||||
HFMBlendshape blendshape;
|
||||
};
|
||||
|
||||
void printNode(const FBXNode& node, int indentLevel) {
|
||||
|
@ -346,8 +346,8 @@ void appendModelIDs(const QString& parentID, const QMultiMap<QString, QString>&
|
|||
}
|
||||
}
|
||||
|
||||
FBXBlendshape extractBlendshape(const FBXNode& object) {
|
||||
FBXBlendshape blendshape;
|
||||
HFMBlendshape extractBlendshape(const FBXNode& object) {
|
||||
HFMBlendshape blendshape;
|
||||
foreach (const FBXNode& data, object.children) {
|
||||
if (data.name == "Indexes") {
|
||||
blendshape.indices = FBXReader::getIntVector(data);
|
||||
|
@ -362,9 +362,9 @@ FBXBlendshape extractBlendshape(const FBXNode& object) {
|
|||
return blendshape;
|
||||
}
|
||||
|
||||
using IndexAccessor = std::function<glm::vec3*(const FBXMesh&, int, int, glm::vec3*, glm::vec3&)>;
|
||||
using IndexAccessor = std::function<glm::vec3*(const HFMMesh&, int, int, glm::vec3*, glm::vec3&)>;
|
||||
|
||||
static void setTangents(const FBXMesh& mesh, const IndexAccessor& vertexAccessor, int firstIndex, int secondIndex,
|
||||
static void setTangents(const HFMMesh& mesh, const IndexAccessor& vertexAccessor, int firstIndex, int secondIndex,
|
||||
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals, QVector<glm::vec3>& tangents) {
|
||||
glm::vec3 vertex[2];
|
||||
glm::vec3 normal;
|
||||
|
@ -381,14 +381,14 @@ static void setTangents(const FBXMesh& mesh, const IndexAccessor& vertexAccessor
|
|||
}
|
||||
}
|
||||
|
||||
static void createTangents(const FBXMesh& mesh, bool generateFromTexCoords,
|
||||
static void createTangents(const HFMMesh& mesh, bool generateFromTexCoords,
|
||||
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals, QVector<glm::vec3>& tangents,
|
||||
IndexAccessor accessor) {
|
||||
// if we have a normal map (and texture coordinates), we must compute tangents
|
||||
if (generateFromTexCoords && !mesh.texCoords.isEmpty()) {
|
||||
tangents.resize(vertices.size());
|
||||
|
||||
foreach(const FBXMeshPart& part, mesh.parts) {
|
||||
foreach(const HFMMeshPart& part, mesh.parts) {
|
||||
for (int i = 0; i < part.quadIndices.size(); i += 4) {
|
||||
setTangents(mesh, accessor, part.quadIndices.at(i), part.quadIndices.at(i + 1), vertices, normals, tangents);
|
||||
setTangents(mesh, accessor, part.quadIndices.at(i + 1), part.quadIndices.at(i + 2), vertices, normals, tangents);
|
||||
|
@ -403,27 +403,27 @@ static void createTangents(const FBXMesh& 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 extractFBXGeometry part.triangleIndices.size() is not divisible by three ";
|
||||
qCDebug(modelformat) << "Error in extractHFMGeometry part.triangleIndices.size() is not divisible by three ";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _createBlendShapeTangents(FBXMesh& mesh, bool generateFromTexCoords, FBXBlendshape& blendShape);
|
||||
static void _createBlendShapeTangents(HFMMesh& mesh, bool generateFromTexCoords, HFMBlendshape& blendShape);
|
||||
|
||||
void FBXMesh::createBlendShapeTangents(bool generateTangents) {
|
||||
void HFMMesh::createBlendShapeTangents(bool generateTangents) {
|
||||
for (auto& blendShape : blendshapes) {
|
||||
_createBlendShapeTangents(*this, generateTangents, blendShape);
|
||||
}
|
||||
}
|
||||
|
||||
void FBXMesh::createMeshTangents(bool generateFromTexCoords) {
|
||||
FBXMesh& mesh = *this;
|
||||
void HFMMesh::createMeshTangents(bool generateFromTexCoords) {
|
||||
HFMMesh& mesh = *this;
|
||||
// This is the only workaround I've found to trick the compiler into understanding that mesh.tangents isn't
|
||||
// const in the lambda function.
|
||||
auto& tangents = mesh.tangents;
|
||||
createTangents(mesh, generateFromTexCoords, mesh.vertices, mesh.normals, mesh.tangents,
|
||||
[&](const FBXMesh& mesh, int firstIndex, int secondIndex, glm::vec3* outVertices, glm::vec3& outNormal) {
|
||||
[&](const HFMMesh& mesh, int firstIndex, int secondIndex, glm::vec3* outVertices, glm::vec3& outNormal) {
|
||||
outVertices[0] = mesh.vertices[firstIndex];
|
||||
outVertices[1] = mesh.vertices[secondIndex];
|
||||
outNormal = mesh.normals[firstIndex];
|
||||
|
@ -431,7 +431,7 @@ void FBXMesh::createMeshTangents(bool generateFromTexCoords) {
|
|||
});
|
||||
}
|
||||
|
||||
static void _createBlendShapeTangents(FBXMesh& mesh, bool generateFromTexCoords, FBXBlendshape& blendShape) {
|
||||
static void _createBlendShapeTangents(HFMMesh& mesh, bool generateFromTexCoords, HFMBlendshape& blendShape) {
|
||||
// Create lookup to get index in blend shape from vertex index in mesh
|
||||
std::vector<int> reverseIndices;
|
||||
reverseIndices.resize(mesh.vertices.size());
|
||||
|
@ -443,7 +443,7 @@ static void _createBlendShapeTangents(FBXMesh& mesh, bool generateFromTexCoords,
|
|||
}
|
||||
|
||||
createTangents(mesh, generateFromTexCoords, blendShape.vertices, blendShape.normals, blendShape.tangents,
|
||||
[&](const FBXMesh& mesh, int firstIndex, int secondIndex, glm::vec3* outVertices, glm::vec3& outNormal) {
|
||||
[&](const HFMMesh& mesh, int firstIndex, int secondIndex, glm::vec3* outVertices, glm::vec3& outNormal) {
|
||||
const auto index1 = reverseIndices[firstIndex];
|
||||
const auto index2 = reverseIndices[secondIndex];
|
||||
|
||||
|
@ -481,7 +481,7 @@ void addBlendshapes(const ExtractedBlendshape& extracted, const QList<WeightedIn
|
|||
foreach (const WeightedIndex& index, indices) {
|
||||
extractedMesh.mesh.blendshapes.resize(max(extractedMesh.mesh.blendshapes.size(), index.first + 1));
|
||||
extractedMesh.blendshapeIndexMaps.resize(extractedMesh.mesh.blendshapes.size());
|
||||
FBXBlendshape& blendshape = extractedMesh.mesh.blendshapes[index.first];
|
||||
HFMBlendshape& blendshape = extractedMesh.mesh.blendshapes[index.first];
|
||||
QHash<int, int>& blendshapeIndexMap = extractedMesh.blendshapeIndexMaps[index.first];
|
||||
for (int i = 0; i < extracted.blendshape.indices.size(); i++) {
|
||||
int oldIndex = extracted.blendshape.indices.at(i);
|
||||
|
@ -539,7 +539,7 @@ public:
|
|||
QVector<float> values;
|
||||
};
|
||||
|
||||
bool checkMaterialsHaveTextures(const QHash<QString, FBXMaterial>& materials,
|
||||
bool checkMaterialsHaveTextures(const QHash<QString, HFMMaterial>& materials,
|
||||
const QHash<QString, QByteArray>& textureFilenames, const QMultiMap<QString, QString>& _connectionChildMap) {
|
||||
foreach (const QString& materialID, materials.keys()) {
|
||||
foreach (const QString& childID, _connectionChildMap.values(materialID)) {
|
||||
|
@ -569,8 +569,8 @@ int matchTextureUVSetToAttributeChannel(const QString& texUVSetName, const QHash
|
|||
}
|
||||
|
||||
|
||||
FBXLight extractLight(const FBXNode& object) {
|
||||
FBXLight light;
|
||||
HFMLight extractLight(const FBXNode& object) {
|
||||
HFMLight light;
|
||||
foreach (const FBXNode& subobject, object.children) {
|
||||
QString childname = QString(subobject.name);
|
||||
if (subobject.name == "Properties70") {
|
||||
|
@ -615,7 +615,7 @@ QByteArray fileOnUrl(const QByteArray& filepath, const QString& url) {
|
|||
return filepath.mid(filepath.lastIndexOf('/') + 1);
|
||||
}
|
||||
|
||||
FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QString& url) {
|
||||
HFMGeometry* FBXReader::extractHFMGeometry(const QVariantHash& mapping, const QString& url) {
|
||||
const FBXNode& node = _rootNode;
|
||||
QMap<QString, ExtractedMesh> meshes;
|
||||
QHash<QString, QString> modelIDsToNames;
|
||||
|
@ -636,7 +636,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
QHash<QString, QString> yComponents;
|
||||
QHash<QString, QString> zComponents;
|
||||
|
||||
std::map<QString, FBXLight> lights;
|
||||
std::map<QString, HFMLight> lights;
|
||||
|
||||
QVariantHash joints = mapping.value("joint").toHash();
|
||||
QString jointEyeLeftName = processID(getString(joints.value("jointEyeLeft", "jointEyeLeft")));
|
||||
|
@ -689,8 +689,8 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
#if defined(DEBUG_FBXREADER)
|
||||
int unknown = 0;
|
||||
#endif
|
||||
FBXGeometry* geometryPtr = new FBXGeometry;
|
||||
FBXGeometry& geometry = *geometryPtr;
|
||||
HFMGeometry* geometryPtr = new HFMGeometry;
|
||||
HFMGeometry& geometry = *geometryPtr;
|
||||
|
||||
geometry.originalURL = url;
|
||||
|
||||
|
@ -944,7 +944,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
lightprop = vprop.toString();
|
||||
}
|
||||
|
||||
FBXLight light = extractLight(object);
|
||||
HFMLight light = extractLight(object);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1102,7 +1102,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
_textureContent.insert(filepath, content);
|
||||
}
|
||||
} else if (object.name == "Material") {
|
||||
FBXMaterial material;
|
||||
HFMMaterial material;
|
||||
material.name = (object.properties.at(1).toString());
|
||||
foreach (const FBXNode& subobject, object.children) {
|
||||
bool properties = false;
|
||||
|
@ -1255,7 +1255,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
#endif
|
||||
}
|
||||
material.materialID = getID(object.properties);
|
||||
_fbxMaterials.insert(material.materialID, material);
|
||||
_hfmMaterials.insert(material.materialID, material);
|
||||
|
||||
|
||||
} else if (object.name == "NodeAttribute") {
|
||||
|
@ -1276,7 +1276,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
|
||||
if (!attributetype.isEmpty()) {
|
||||
if (attributetype == "Light") {
|
||||
FBXLight light = extractLight(object);
|
||||
HFMLight light = extractLight(object);
|
||||
lights[attribID] = light;
|
||||
}
|
||||
}
|
||||
|
@ -1345,7 +1345,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
QString parentID = getID(connection.properties, 2);
|
||||
ooChildToParent.insert(childID, parentID);
|
||||
if (!hifiGlobalNodeID.isEmpty() && (parentID == hifiGlobalNodeID)) {
|
||||
std::map< QString, FBXLight >::iterator lightIt = lights.find(childID);
|
||||
std::map< QString, HFMLight >::iterator lightIt = lights.find(childID);
|
||||
if (lightIt != lights.end()) {
|
||||
_lightmapLevel = (*lightIt).second.intensity;
|
||||
if (_lightmapLevel <= 0.0f) {
|
||||
|
@ -1504,7 +1504,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
frameCount = qMax(frameCount, curve.values.size());
|
||||
}
|
||||
for (int i = 0; i < frameCount; i++) {
|
||||
FBXAnimationFrame frame;
|
||||
HFMAnimationFrame frame;
|
||||
frame.rotations.resize(modelIDs.size());
|
||||
frame.translations.resize(modelIDs.size());
|
||||
geometry.animationFrames.append(frame);
|
||||
|
@ -1515,7 +1515,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
geometry.hasSkeletonJoints = false;
|
||||
foreach (const QString& modelID, modelIDs) {
|
||||
const FBXModel& model = models[modelID];
|
||||
FBXJoint joint;
|
||||
HFMJoint joint;
|
||||
joint.isFree = freeJoints.contains(model.name);
|
||||
joint.parentIndex = model.parentIndex;
|
||||
|
||||
|
@ -1553,7 +1553,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
joint.distanceToParent = 0.0f;
|
||||
|
||||
} else {
|
||||
const FBXJoint& parentJoint = geometry.joints.at(joint.parentIndex);
|
||||
const HFMJoint& parentJoint = geometry.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;
|
||||
|
@ -1631,7 +1631,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
geometry.meshExtents.reset();
|
||||
|
||||
// Create the Material Library
|
||||
consolidateFBXMaterials(mapping);
|
||||
consolidateHFMMaterials(mapping);
|
||||
|
||||
// We can't allow the scaling of a given image to different sizes, because the hash used for the KTX cache is based on the original image
|
||||
// Allowing scaling of the same image to different sizes would cause different KTX files to target the same cache key
|
||||
|
@ -1643,7 +1643,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
// 33 - 128 textures --> 512
|
||||
// etc...
|
||||
QSet<QString> uniqueTextures;
|
||||
for (auto& material : _fbxMaterials) {
|
||||
for (auto& material : _hfmMaterials) {
|
||||
material.getTextureNames(uniqueTextures);
|
||||
}
|
||||
int numTextures = uniqueTextures.size();
|
||||
|
@ -1659,15 +1659,15 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
} while (numTextureThreshold < numTextures && maxWidth > MIN_MIP_TEXTURE_WIDTH);
|
||||
|
||||
qCDebug(modelformat) << "Capped square texture width =" << maxWidth << "for model" << url << "with" << numTextures << "textures";
|
||||
for (auto& material : _fbxMaterials) {
|
||||
for (auto& material : _hfmMaterials) {
|
||||
material.setMaxNumPixelsPerTexture(maxWidth * maxWidth);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
geometry.materials = _fbxMaterials;
|
||||
geometry.materials = _hfmMaterials;
|
||||
|
||||
// see if any materials have texture children
|
||||
bool materialsHaveTextures = checkMaterialsHaveTextures(_fbxMaterials, _textureFilenames, _connectionChildMap);
|
||||
bool materialsHaveTextures = checkMaterialsHaveTextures(_hfmMaterials, _textureFilenames, _connectionChildMap);
|
||||
|
||||
for (QMap<QString, ExtractedMesh>::iterator it = meshes.begin(); it != meshes.end(); it++) {
|
||||
ExtractedMesh& extracted = it.value();
|
||||
|
@ -1698,13 +1698,13 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
for (int i = children.size() - 1; i >= 0; i--) {
|
||||
|
||||
const QString& childID = children.at(i);
|
||||
if (_fbxMaterials.contains(childID)) {
|
||||
if (_hfmMaterials.contains(childID)) {
|
||||
// the pure material associated with this part
|
||||
FBXMaterial material = _fbxMaterials.value(childID);
|
||||
HFMMaterial material = _hfmMaterials.value(childID);
|
||||
|
||||
for (int j = 0; j < extracted.partMaterialTextures.size(); j++) {
|
||||
if (extracted.partMaterialTextures.at(j).first == materialIndex) {
|
||||
FBXMeshPart& part = extracted.mesh.parts[j];
|
||||
HFMMeshPart& part = extracted.mesh.parts[j];
|
||||
part.materialID = material.materialID;
|
||||
generateTangents |= material.needTangentSpace();
|
||||
}
|
||||
|
@ -1713,7 +1713,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
materialIndex++;
|
||||
|
||||
} else if (_textureFilenames.contains(childID)) {
|
||||
FBXTexture texture = getTexture(childID);
|
||||
HFMTexture texture = getTexture(childID);
|
||||
for (int j = 0; j < extracted.partMaterialTextures.size(); j++) {
|
||||
int partTexture = extracted.partMaterialTextures.at(j).second;
|
||||
if (partTexture == textureIndex && !(partTexture == 0 && materialsHaveTextures)) {
|
||||
|
@ -1736,34 +1736,34 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
if (!clusters.contains(clusterID)) {
|
||||
continue;
|
||||
}
|
||||
FBXCluster fbxCluster;
|
||||
HFMCluster hfmCluster;
|
||||
const Cluster& cluster = clusters[clusterID];
|
||||
clusterIDs.append(clusterID);
|
||||
|
||||
// see http://stackoverflow.com/questions/13566608/loading-skinning-information-from-fbx for a discussion
|
||||
// of skinning information in FBX
|
||||
QString jointID = _connectionChildMap.value(clusterID);
|
||||
fbxCluster.jointIndex = modelIDs.indexOf(jointID);
|
||||
if (fbxCluster.jointIndex == -1) {
|
||||
hfmCluster.jointIndex = modelIDs.indexOf(jointID);
|
||||
if (hfmCluster.jointIndex == -1) {
|
||||
qCDebug(modelformat) << "Joint not in model list: " << jointID;
|
||||
fbxCluster.jointIndex = 0;
|
||||
hfmCluster.jointIndex = 0;
|
||||
}
|
||||
|
||||
fbxCluster.inverseBindMatrix = glm::inverse(cluster.transformLink) * modelTransform;
|
||||
hfmCluster.inverseBindMatrix = glm::inverse(cluster.transformLink) * modelTransform;
|
||||
|
||||
// slam bottom row to (0, 0, 0, 1), we KNOW this is not a perspective matrix and
|
||||
// sometimes floating point fuzz can be introduced after the inverse.
|
||||
fbxCluster.inverseBindMatrix[0][3] = 0.0f;
|
||||
fbxCluster.inverseBindMatrix[1][3] = 0.0f;
|
||||
fbxCluster.inverseBindMatrix[2][3] = 0.0f;
|
||||
fbxCluster.inverseBindMatrix[3][3] = 1.0f;
|
||||
hfmCluster.inverseBindMatrix[0][3] = 0.0f;
|
||||
hfmCluster.inverseBindMatrix[1][3] = 0.0f;
|
||||
hfmCluster.inverseBindMatrix[2][3] = 0.0f;
|
||||
hfmCluster.inverseBindMatrix[3][3] = 1.0f;
|
||||
|
||||
fbxCluster.inverseBindTransform = Transform(fbxCluster.inverseBindMatrix);
|
||||
hfmCluster.inverseBindTransform = Transform(hfmCluster.inverseBindMatrix);
|
||||
|
||||
extracted.mesh.clusters.append(fbxCluster);
|
||||
extracted.mesh.clusters.append(hfmCluster);
|
||||
|
||||
// override the bind rotation with the transform link
|
||||
FBXJoint& joint = geometry.joints[fbxCluster.jointIndex];
|
||||
HFMJoint& joint = geometry.joints[hfmCluster.jointIndex];
|
||||
joint.inverseBindRotation = glm::inverse(extractRotation(cluster.transformLink));
|
||||
joint.bindTransform = cluster.transformLink;
|
||||
joint.bindTransformFoundInCluster = true;
|
||||
|
@ -1776,7 +1776,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
|
||||
// if we don't have a skinned joint, parent to the model itself
|
||||
if (extracted.mesh.clusters.isEmpty()) {
|
||||
FBXCluster cluster;
|
||||
HFMCluster cluster;
|
||||
cluster.jointIndex = modelIDs.indexOf(modelID);
|
||||
if (cluster.jointIndex == -1) {
|
||||
qCDebug(modelformat) << "Model not in model list: " << modelID;
|
||||
|
@ -1786,7 +1786,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
}
|
||||
|
||||
// whether we're skinned depends on how many clusters are attached
|
||||
const FBXCluster& firstFBXCluster = extracted.mesh.clusters.at(0);
|
||||
const HFMCluster& firstHFMCluster = extracted.mesh.clusters.at(0);
|
||||
glm::mat4 inverseModelTransform = glm::inverse(modelTransform);
|
||||
if (clusterIDs.size() > 1) {
|
||||
// this is a multi-mesh joint
|
||||
|
@ -1799,9 +1799,9 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
for (int i = 0; i < clusterIDs.size(); i++) {
|
||||
QString clusterID = clusterIDs.at(i);
|
||||
const Cluster& cluster = clusters[clusterID];
|
||||
const FBXCluster& fbxCluster = extracted.mesh.clusters.at(i);
|
||||
int jointIndex = fbxCluster.jointIndex;
|
||||
FBXJoint& joint = geometry.joints[jointIndex];
|
||||
const HFMCluster& hfmCluster = extracted.mesh.clusters.at(i);
|
||||
int jointIndex = hfmCluster.jointIndex;
|
||||
HFMJoint& joint = geometry.joints[jointIndex];
|
||||
glm::mat4 transformJointToMesh = inverseModelTransform * joint.bindTransform;
|
||||
glm::vec3 boneEnd = extractTranslation(transformJointToMesh);
|
||||
glm::vec3 boneBegin = boneEnd;
|
||||
|
@ -1881,8 +1881,8 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
}
|
||||
} else {
|
||||
// this is a single-mesh joint
|
||||
int jointIndex = firstFBXCluster.jointIndex;
|
||||
FBXJoint& joint = geometry.joints[jointIndex];
|
||||
int jointIndex = firstHFMCluster.jointIndex;
|
||||
HFMJoint& joint = geometry.joints[jointIndex];
|
||||
|
||||
// transform cluster vertices to joint-frame and save for later
|
||||
glm::mat4 meshToJoint = glm::inverse(joint.bindTransform) * modelTransform;
|
||||
|
@ -1924,7 +1924,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(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) {
|
||||
FBXJoint& joint = geometry.joints[i];
|
||||
HFMJoint& joint = geometry.joints[i];
|
||||
|
||||
// NOTE: points are in joint-frame
|
||||
ShapeVertices& points = shapeVertices.at(i);
|
||||
|
@ -1994,13 +1994,13 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
return geometryPtr;
|
||||
}
|
||||
|
||||
FBXGeometry* readFBX(const QByteArray& model, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) {
|
||||
HFMGeometry* readFBX(const QByteArray& model, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) {
|
||||
QBuffer buffer(const_cast<QByteArray*>(&model));
|
||||
buffer.open(QIODevice::ReadOnly);
|
||||
return readFBX(&buffer, mapping, url, loadLightmaps, lightmapLevel);
|
||||
}
|
||||
|
||||
FBXGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QString& url, bool loadLightmaps, float lightmapLevel) {
|
||||
HFMGeometry* 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 @@ FBXGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QStri
|
|||
|
||||
qCDebug(modelformat) << "Reading FBX: " << url;
|
||||
|
||||
return reader.extractFBXGeometry(mapping, url);
|
||||
return reader.extractHFMGeometry(mapping, url);
|
||||
}
|
||||
|
|
|
@ -36,11 +36,11 @@ class FBXNode;
|
|||
|
||||
/// Reads FBX geometry from the supplied model and mapping data.
|
||||
/// \exception QString if an error occurs in parsing
|
||||
FBXGeometry* readFBX(const QByteArray& model, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f);
|
||||
HFMGeometry* readFBX(const QByteArray& model, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f);
|
||||
|
||||
/// Reads FBX geometry from the supplied model and mapping data.
|
||||
/// \exception QString if an error occurs in parsing
|
||||
FBXGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f);
|
||||
HFMGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f);
|
||||
|
||||
class TextureParam {
|
||||
public:
|
||||
|
@ -103,20 +103,20 @@ class ExtractedMesh;
|
|||
|
||||
class FBXReader {
|
||||
public:
|
||||
FBXGeometry* _fbxGeometry;
|
||||
HFMGeometry* _hfmGeometry;
|
||||
|
||||
FBXNode _rootNode;
|
||||
static FBXNode parseFBX(QIODevice* device);
|
||||
|
||||
FBXGeometry* extractFBXGeometry(const QVariantHash& mapping, const QString& url);
|
||||
HFMGeometry* extractHFMGeometry(const QVariantHash& mapping, const QString& url);
|
||||
|
||||
static ExtractedMesh extractMesh(const FBXNode& object, unsigned int& meshIndex, bool deduplicate = true);
|
||||
QHash<QString, ExtractedMesh> meshes;
|
||||
static void buildModelMesh(FBXMesh& extractedMesh, const QString& url);
|
||||
static void buildModelMesh(HFMMesh& extractedMesh, const QString& url);
|
||||
|
||||
static glm::vec3 normalizeDirForPacking(const glm::vec3& dir);
|
||||
|
||||
FBXTexture getTexture(const QString& textureID);
|
||||
HFMTexture getTexture(const QString& textureID);
|
||||
|
||||
QHash<QString, QString> _textureNames;
|
||||
// Hashes the original RelativeFilename of textures
|
||||
|
@ -142,9 +142,9 @@ public:
|
|||
QHash<QString, QString> ambientFactorTextures;
|
||||
QHash<QString, QString> occlusionTextures;
|
||||
|
||||
QHash<QString, FBXMaterial> _fbxMaterials;
|
||||
QHash<QString, HFMMaterial> _hfmMaterials;
|
||||
|
||||
void consolidateFBXMaterials(const QVariantHash& mapping);
|
||||
void consolidateHFMMaterials(const QVariantHash& mapping);
|
||||
|
||||
bool _loadLightmaps = true;
|
||||
float _lightmapOffset = 0.0f;
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
#include "ModelFormatLogging.h"
|
||||
|
||||
void FBXMaterial::getTextureNames(QSet<QString>& textureList) const {
|
||||
void HFMMaterial::getTextureNames(QSet<QString>& textureList) const {
|
||||
if (!normalTexture.isNull()) {
|
||||
textureList.insert(normalTexture.name);
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ void FBXMaterial::getTextureNames(QSet<QString>& textureList) const {
|
|||
}
|
||||
}
|
||||
|
||||
void FBXMaterial::setMaxNumPixelsPerTexture(int maxNumPixels) {
|
||||
void HFMMaterial::setMaxNumPixelsPerTexture(int maxNumPixels) {
|
||||
normalTexture.maxNumPixels = maxNumPixels;
|
||||
albedoTexture.maxNumPixels = maxNumPixels;
|
||||
opacityTexture.maxNumPixels = maxNumPixels;
|
||||
|
@ -77,12 +77,12 @@ void FBXMaterial::setMaxNumPixelsPerTexture(int maxNumPixels) {
|
|||
lightmapTexture.maxNumPixels = maxNumPixels;
|
||||
}
|
||||
|
||||
bool FBXMaterial::needTangentSpace() const {
|
||||
bool HFMMaterial::needTangentSpace() const {
|
||||
return !normalTexture.isNull();
|
||||
}
|
||||
|
||||
FBXTexture FBXReader::getTexture(const QString& textureID) {
|
||||
FBXTexture texture;
|
||||
HFMTexture FBXReader::getTexture(const QString& textureID) {
|
||||
HFMTexture texture;
|
||||
const QByteArray& filepath = _textureFilepaths.value(textureID);
|
||||
texture.content = _textureContent.value(filepath);
|
||||
|
||||
|
@ -123,7 +123,7 @@ FBXTexture FBXReader::getTexture(const QString& textureID) {
|
|||
return texture;
|
||||
}
|
||||
|
||||
void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) {
|
||||
void FBXReader::consolidateHFMMaterials(const QVariantHash& mapping) {
|
||||
|
||||
QString materialMapString = mapping.value("materialMap").toString();
|
||||
QJsonDocument materialMapDocument = QJsonDocument::fromJson(materialMapString.toUtf8());
|
||||
|
@ -133,16 +133,16 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) {
|
|||
qCDebug(modelformat) << "fbx Material Map found but did not produce valid JSON:" << materialMapString;
|
||||
}
|
||||
}
|
||||
for (QHash<QString, FBXMaterial>::iterator it = _fbxMaterials.begin(); it != _fbxMaterials.end(); it++) {
|
||||
FBXMaterial& material = (*it);
|
||||
for (QHash<QString, HFMMaterial>::iterator it = _hfmMaterials.begin(); it != _hfmMaterials.end(); it++) {
|
||||
HFMMaterial& material = (*it);
|
||||
|
||||
// Maya is the exporting the shading model and we are trying to use it
|
||||
bool isMaterialLambert = (material.shadingModel.toLower() == "lambert");
|
||||
|
||||
// the pure material associated with this part
|
||||
bool detectDifferentUVs = false;
|
||||
FBXTexture diffuseTexture;
|
||||
FBXTexture diffuseFactorTexture;
|
||||
HFMTexture diffuseTexture;
|
||||
HFMTexture diffuseFactorTexture;
|
||||
QString diffuseTextureID = diffuseTextures.value(material.materialID);
|
||||
QString diffuseFactorTextureID = diffuseFactorTextures.value(material.materialID);
|
||||
|
||||
|
@ -169,7 +169,7 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) {
|
|||
detectDifferentUVs = (diffuseTexture.texcoordSet != 0) || (!diffuseTexture.transform.isIdentity());
|
||||
}
|
||||
|
||||
FBXTexture transparentTexture;
|
||||
HFMTexture transparentTexture;
|
||||
QString transparentTextureID = transparentTextures.value(material.materialID);
|
||||
// If PBS Material, systematically bind the albedo texture as transparency texture and check for the alpha channel
|
||||
if (material.isPBSMaterial) {
|
||||
|
@ -181,7 +181,7 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) {
|
|||
detectDifferentUVs |= (transparentTexture.texcoordSet != 0) || (!transparentTexture.transform.isIdentity());
|
||||
}
|
||||
|
||||
FBXTexture normalTexture;
|
||||
HFMTexture normalTexture;
|
||||
QString bumpTextureID = bumpTextures.value(material.materialID);
|
||||
QString normalTextureID = normalTextures.value(material.materialID);
|
||||
if (!normalTextureID.isNull()) {
|
||||
|
@ -198,7 +198,7 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) {
|
|||
detectDifferentUVs |= (normalTexture.texcoordSet != 0) || (!normalTexture.transform.isIdentity());
|
||||
}
|
||||
|
||||
FBXTexture specularTexture;
|
||||
HFMTexture specularTexture;
|
||||
QString specularTextureID = specularTextures.value(material.materialID);
|
||||
if (!specularTextureID.isNull()) {
|
||||
specularTexture = getTexture(specularTextureID);
|
||||
|
@ -206,7 +206,7 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) {
|
|||
material.specularTexture = specularTexture;
|
||||
}
|
||||
|
||||
FBXTexture metallicTexture;
|
||||
HFMTexture metallicTexture;
|
||||
QString metallicTextureID = metallicTextures.value(material.materialID);
|
||||
if (!metallicTextureID.isNull()) {
|
||||
metallicTexture = getTexture(metallicTextureID);
|
||||
|
@ -214,7 +214,7 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) {
|
|||
material.metallicTexture = metallicTexture;
|
||||
}
|
||||
|
||||
FBXTexture roughnessTexture;
|
||||
HFMTexture roughnessTexture;
|
||||
QString roughnessTextureID = roughnessTextures.value(material.materialID);
|
||||
if (!roughnessTextureID.isNull()) {
|
||||
roughnessTexture = getTexture(roughnessTextureID);
|
||||
|
@ -222,7 +222,7 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) {
|
|||
detectDifferentUVs |= (roughnessTexture.texcoordSet != 0) || (!roughnessTexture.transform.isIdentity());
|
||||
}
|
||||
|
||||
FBXTexture shininessTexture;
|
||||
HFMTexture shininessTexture;
|
||||
QString shininessTextureID = shininessTextures.value(material.materialID);
|
||||
if (!shininessTextureID.isNull()) {
|
||||
shininessTexture = getTexture(shininessTextureID);
|
||||
|
@ -230,7 +230,7 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) {
|
|||
detectDifferentUVs |= (shininessTexture.texcoordSet != 0) || (!shininessTexture.transform.isIdentity());
|
||||
}
|
||||
|
||||
FBXTexture emissiveTexture;
|
||||
HFMTexture emissiveTexture;
|
||||
QString emissiveTextureID = emissiveTextures.value(material.materialID);
|
||||
if (!emissiveTextureID.isNull()) {
|
||||
emissiveTexture = getTexture(emissiveTextureID);
|
||||
|
@ -245,7 +245,7 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) {
|
|||
}
|
||||
}
|
||||
|
||||
FBXTexture occlusionTexture;
|
||||
HFMTexture occlusionTexture;
|
||||
QString occlusionTextureID = occlusionTextures.value(material.materialID);
|
||||
if (occlusionTextureID.isNull()) {
|
||||
// 2nd chance
|
||||
|
@ -265,7 +265,7 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) {
|
|||
lightmapParams.x = _lightmapOffset;
|
||||
lightmapParams.y = _lightmapLevel;
|
||||
|
||||
FBXTexture ambientTexture;
|
||||
HFMTexture ambientTexture;
|
||||
QString ambientTextureID = ambientTextures.value(material.materialID);
|
||||
if (ambientTextureID.isNull()) {
|
||||
// 2nd chance
|
||||
|
@ -326,7 +326,7 @@ void FBXReader::consolidateFBXMaterials(const QVariantHash& mapping) {
|
|||
|
||||
if (materialOptions.contains("scatteringMap")) {
|
||||
QByteArray scatteringMap = materialOptions.value("scatteringMap").toVariant().toByteArray();
|
||||
material.scatteringTexture = FBXTexture();
|
||||
material.scatteringTexture = HFMTexture();
|
||||
material.scatteringTexture.name = material.name + ".scatteringMap";
|
||||
material.scatteringTexture.filename = scatteringMap;
|
||||
}
|
||||
|
|
|
@ -42,9 +42,9 @@
|
|||
|
||||
using vec2h = glm::tvec2<glm::detail::hdata>;
|
||||
|
||||
#define FBX_PACK_COLORS 1
|
||||
#define HFM_PACK_COLORS 1
|
||||
|
||||
#if FBX_PACK_COLORS
|
||||
#if HFM_PACK_COLORS
|
||||
using ColorType = glm::uint32;
|
||||
#define FBX_COLOR_ELEMENT gpu::Element::COLOR_RGBA_32
|
||||
#else
|
||||
|
@ -469,7 +469,7 @@ ExtractedMesh FBXReader::extractMesh(const FBXNode& object, unsigned int& meshIn
|
|||
|
||||
QPair<int, int> materialTexture(materialID, 0);
|
||||
|
||||
// grab or setup the FBXMeshPart for the part this face belongs to
|
||||
// grab or setup the HFMMeshPart for the part this face belongs to
|
||||
int& partIndexPlusOne = materialTextureParts[materialTexture];
|
||||
if (partIndexPlusOne == 0) {
|
||||
data.extracted.partMaterialTextures.append(materialTexture);
|
||||
|
@ -478,7 +478,7 @@ ExtractedMesh FBXReader::extractMesh(const FBXNode& object, unsigned int& meshIn
|
|||
}
|
||||
|
||||
// give the mesh part this index
|
||||
FBXMeshPart& part = data.extracted.mesh.parts[partIndexPlusOne - 1];
|
||||
HFMMeshPart& part = data.extracted.mesh.parts[partIndexPlusOne - 1];
|
||||
part.triangleIndices.append(firstCorner.value());
|
||||
part.triangleIndices.append(dracoFace[1].value());
|
||||
part.triangleIndices.append(dracoFace[2].value());
|
||||
|
@ -511,7 +511,7 @@ ExtractedMesh FBXReader::extractMesh(const FBXNode& object, unsigned int& meshIn
|
|||
data.extracted.mesh.parts.resize(data.extracted.mesh.parts.size() + 1);
|
||||
partIndex = data.extracted.mesh.parts.size();
|
||||
}
|
||||
FBXMeshPart& part = data.extracted.mesh.parts[partIndex - 1];
|
||||
HFMMeshPart& part = data.extracted.mesh.parts[partIndex - 1];
|
||||
|
||||
if (endIndex - beginIndex == 4) {
|
||||
appendIndex(data, part.quadIndices, beginIndex++, deduplicate);
|
||||
|
@ -565,9 +565,9 @@ glm::vec3 FBXReader::normalizeDirForPacking(const glm::vec3& dir) {
|
|||
return dir;
|
||||
}
|
||||
|
||||
void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) {
|
||||
void FBXReader::buildModelMesh(HFMMesh& extractedMesh, const QString& url) {
|
||||
unsigned int totalSourceIndices = 0;
|
||||
foreach(const FBXMeshPart& part, extractedMesh.parts) {
|
||||
foreach(const HFMMeshPart& part, extractedMesh.parts) {
|
||||
totalSourceIndices += (part.quadTrianglesIndices.size() + part.triangleIndices.size());
|
||||
}
|
||||
|
||||
|
@ -583,17 +583,17 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) {
|
|||
return;
|
||||
}
|
||||
|
||||
FBXMesh& fbxMesh = extractedMesh;
|
||||
HFMMesh& hfmMesh = extractedMesh;
|
||||
graphics::MeshPointer mesh(new graphics::Mesh());
|
||||
int numVerts = extractedMesh.vertices.size();
|
||||
|
||||
if (!fbxMesh.normals.empty() && fbxMesh.tangents.empty()) {
|
||||
if (!hfmMesh.normals.empty() && hfmMesh.tangents.empty()) {
|
||||
// Fill with a dummy value to force tangents to be present if there are normals
|
||||
fbxMesh.tangents.reserve(fbxMesh.normals.size());
|
||||
std::fill_n(std::back_inserter(fbxMesh.tangents), fbxMesh.normals.size(), Vectors::UNIT_X);
|
||||
hfmMesh.tangents.reserve(hfmMesh.normals.size());
|
||||
std::fill_n(std::back_inserter(hfmMesh.tangents), hfmMesh.normals.size(), Vectors::UNIT_X);
|
||||
}
|
||||
// Same thing with blend shapes
|
||||
for (auto& blendShape : fbxMesh.blendshapes) {
|
||||
for (auto& blendShape : hfmMesh.blendshapes) {
|
||||
if (!blendShape.normals.empty() && blendShape.tangents.empty()) {
|
||||
// Fill with a dummy value to force tangents to be present if there are normals
|
||||
blendShape.tangents.reserve(blendShape.normals.size());
|
||||
|
@ -609,8 +609,8 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) {
|
|||
|
||||
// Normal and tangent are always there together packed in normalized xyz32bits word (times 2)
|
||||
const auto normalElement = FBX_NORMAL_ELEMENT;
|
||||
const int normalsSize = fbxMesh.normals.size() * normalElement.getSize();
|
||||
const int tangentsSize = fbxMesh.tangents.size() * normalElement.getSize();
|
||||
const int normalsSize = hfmMesh.normals.size() * normalElement.getSize();
|
||||
const int tangentsSize = hfmMesh.tangents.size() * normalElement.getSize();
|
||||
// If there are normals then there should be tangents
|
||||
assert(normalsSize <= tangentsSize);
|
||||
if (tangentsSize > normalsSize) {
|
||||
|
@ -620,22 +620,22 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) {
|
|||
|
||||
// Color attrib
|
||||
const auto colorElement = FBX_COLOR_ELEMENT;
|
||||
const int colorsSize = fbxMesh.colors.size() * colorElement.getSize();
|
||||
const int colorsSize = hfmMesh.colors.size() * colorElement.getSize();
|
||||
|
||||
// Texture coordinates are stored in 2 half floats
|
||||
const auto texCoordsElement = gpu::Element(gpu::VEC2, gpu::HALF, gpu::UV);
|
||||
const int texCoordsSize = fbxMesh.texCoords.size() * texCoordsElement.getSize();
|
||||
const int texCoords1Size = fbxMesh.texCoords1.size() * texCoordsElement.getSize();
|
||||
const int texCoordsSize = hfmMesh.texCoords.size() * texCoordsElement.getSize();
|
||||
const int texCoords1Size = hfmMesh.texCoords1.size() * texCoordsElement.getSize();
|
||||
|
||||
// Support for 4 skinning clusters:
|
||||
// 4 Indices are uint8 ideally, uint16 if more than 256.
|
||||
const auto clusterIndiceElement = (fbxMesh.clusters.size() < UINT8_MAX ? gpu::Element(gpu::VEC4, gpu::UINT8, gpu::XYZW) : gpu::Element(gpu::VEC4, gpu::UINT16, gpu::XYZW));
|
||||
const auto clusterIndiceElement = (hfmMesh.clusters.size() < UINT8_MAX ? gpu::Element(gpu::VEC4, gpu::UINT8, gpu::XYZW) : gpu::Element(gpu::VEC4, gpu::UINT16, gpu::XYZW));
|
||||
// 4 Weights are normalized 16bits
|
||||
const auto clusterWeightElement = gpu::Element(gpu::VEC4, gpu::NUINT16, gpu::XYZW);
|
||||
|
||||
// Cluster indices and weights must be the same sizes
|
||||
const int NUM_CLUSTERS_PER_VERT = 4;
|
||||
const int numVertClusters = (fbxMesh.clusterIndices.size() == fbxMesh.clusterWeights.size() ? fbxMesh.clusterIndices.size() / NUM_CLUSTERS_PER_VERT : 0);
|
||||
const int numVertClusters = (hfmMesh.clusterIndices.size() == hfmMesh.clusterWeights.size() ? hfmMesh.clusterIndices.size() / NUM_CLUSTERS_PER_VERT : 0);
|
||||
const int clusterIndicesSize = numVertClusters * clusterIndiceElement.getSize();
|
||||
const int clusterWeightsSize = numVertClusters * clusterWeightElement.getSize();
|
||||
|
||||
|
@ -660,9 +660,9 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) {
|
|||
if (normalsSize > 0) {
|
||||
std::vector<NormalType> normalsAndTangents;
|
||||
|
||||
normalsAndTangents.reserve(fbxMesh.normals.size() + fbxMesh.tangents.size());
|
||||
for (auto normalIt = fbxMesh.normals.constBegin(), tangentIt = fbxMesh.tangents.constBegin();
|
||||
normalIt != fbxMesh.normals.constEnd();
|
||||
normalsAndTangents.reserve(hfmMesh.normals.size() + hfmMesh.tangents.size());
|
||||
for (auto normalIt = hfmMesh.normals.constBegin(), tangentIt = hfmMesh.tangents.constBegin();
|
||||
normalIt != hfmMesh.normals.constEnd();
|
||||
++normalIt, ++tangentIt) {
|
||||
#if FBX_PACK_NORMALS
|
||||
const auto normal = normalizeDirForPacking(*normalIt);
|
||||
|
@ -681,24 +681,24 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) {
|
|||
|
||||
// Pack colors
|
||||
if (colorsSize > 0) {
|
||||
#if FBX_PACK_COLORS
|
||||
#if HFM_PACK_COLORS
|
||||
std::vector<ColorType> colors;
|
||||
|
||||
colors.reserve(fbxMesh.colors.size());
|
||||
for (const auto& color : fbxMesh.colors) {
|
||||
colors.reserve(hfmMesh.colors.size());
|
||||
for (const auto& color : hfmMesh.colors) {
|
||||
colors.push_back(glm::packUnorm4x8(glm::vec4(color, 1.0f)));
|
||||
}
|
||||
vertBuffer->setSubData(colorsOffset, colorsSize, (const gpu::Byte*) colors.data());
|
||||
#else
|
||||
vertBuffer->setSubData(colorsOffset, colorsSize, (const gpu::Byte*) fbxMesh.colors.constData());
|
||||
vertBuffer->setSubData(colorsOffset, colorsSize, (const gpu::Byte*) hfmMesh.colors.constData());
|
||||
#endif
|
||||
}
|
||||
|
||||
// Pack Texcoords 0 and 1 (if exists)
|
||||
if (texCoordsSize > 0) {
|
||||
QVector<vec2h> texCoordData;
|
||||
texCoordData.reserve(fbxMesh.texCoords.size());
|
||||
for (auto& texCoordVec2f : fbxMesh.texCoords) {
|
||||
texCoordData.reserve(hfmMesh.texCoords.size());
|
||||
for (auto& texCoordVec2f : hfmMesh.texCoords) {
|
||||
vec2h texCoordVec2h;
|
||||
|
||||
texCoordVec2h.x = glm::detail::toFloat16(texCoordVec2f.x);
|
||||
|
@ -709,8 +709,8 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) {
|
|||
}
|
||||
if (texCoords1Size > 0) {
|
||||
QVector<vec2h> texCoordData;
|
||||
texCoordData.reserve(fbxMesh.texCoords1.size());
|
||||
for (auto& texCoordVec2f : fbxMesh.texCoords1) {
|
||||
texCoordData.reserve(hfmMesh.texCoords1.size());
|
||||
for (auto& texCoordVec2f : hfmMesh.texCoords1) {
|
||||
vec2h texCoordVec2h;
|
||||
|
||||
texCoordVec2h.x = glm::detail::toFloat16(texCoordVec2f.x);
|
||||
|
@ -722,22 +722,22 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) {
|
|||
|
||||
// Clusters data
|
||||
if (clusterIndicesSize > 0) {
|
||||
if (fbxMesh.clusters.size() < UINT8_MAX) {
|
||||
if (hfmMesh.clusters.size() < UINT8_MAX) {
|
||||
// yay! we can fit the clusterIndices within 8-bits
|
||||
int32_t numIndices = fbxMesh.clusterIndices.size();
|
||||
int32_t numIndices = hfmMesh.clusterIndices.size();
|
||||
QVector<uint8_t> clusterIndices;
|
||||
clusterIndices.resize(numIndices);
|
||||
for (int32_t i = 0; i < numIndices; ++i) {
|
||||
assert(fbxMesh.clusterIndices[i] <= UINT8_MAX);
|
||||
clusterIndices[i] = (uint8_t)(fbxMesh.clusterIndices[i]);
|
||||
assert(hfmMesh.clusterIndices[i] <= UINT8_MAX);
|
||||
clusterIndices[i] = (uint8_t)(hfmMesh.clusterIndices[i]);
|
||||
}
|
||||
vertBuffer->setSubData(clusterIndicesOffset, clusterIndicesSize, (const gpu::Byte*) clusterIndices.constData());
|
||||
} else {
|
||||
vertBuffer->setSubData(clusterIndicesOffset, clusterIndicesSize, (const gpu::Byte*) fbxMesh.clusterIndices.constData());
|
||||
vertBuffer->setSubData(clusterIndicesOffset, clusterIndicesSize, (const gpu::Byte*) hfmMesh.clusterIndices.constData());
|
||||
}
|
||||
}
|
||||
if (clusterWeightsSize > 0) {
|
||||
vertBuffer->setSubData(clusterWeightsOffset, clusterWeightsSize, (const gpu::Byte*) fbxMesh.clusterWeights.constData());
|
||||
vertBuffer->setSubData(clusterWeightsOffset, clusterWeightsSize, (const gpu::Byte*) hfmMesh.clusterWeights.constData());
|
||||
}
|
||||
|
||||
|
||||
|
@ -856,7 +856,7 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) {
|
|||
|
||||
// Index and Part Buffers
|
||||
unsigned int totalIndices = 0;
|
||||
foreach(const FBXMeshPart& part, extractedMesh.parts) {
|
||||
foreach(const HFMMeshPart& part, extractedMesh.parts) {
|
||||
totalIndices += (part.quadTrianglesIndices.size() + part.triangleIndices.size());
|
||||
}
|
||||
|
||||
|
@ -875,7 +875,7 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) {
|
|||
if (extractedMesh.parts.size() > 1) {
|
||||
indexNum = 0;
|
||||
}
|
||||
foreach(const FBXMeshPart& part, extractedMesh.parts) {
|
||||
foreach(const HFMMeshPart& part, extractedMesh.parts) {
|
||||
graphics::Mesh::Part modelPart(indexNum, 0, 0, graphics::Mesh::TRIANGLES);
|
||||
|
||||
if (part.quadTrianglesIndices.size()) {
|
||||
|
|
|
@ -697,7 +697,7 @@ glm::mat4 GLTFReader::getModelTransform(const GLTFNode& node) {
|
|||
return tmat;
|
||||
}
|
||||
|
||||
bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) {
|
||||
bool GLTFReader::buildGeometry(HFMGeometry& geometry, const QUrl& url) {
|
||||
|
||||
//Build dependencies
|
||||
QVector<QVector<int>> nodeDependencies(_file.nodes.size());
|
||||
|
@ -750,10 +750,10 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) {
|
|||
|
||||
for (int i = 0; i < materialIDs.size(); i++) {
|
||||
QString& matid = materialIDs[i];
|
||||
geometry.materials[matid] = FBXMaterial();
|
||||
FBXMaterial& fbxMaterial = geometry.materials[matid];
|
||||
fbxMaterial._material = std::make_shared<graphics::Material>();
|
||||
setFBXMaterial(fbxMaterial, _file.materials[i]);
|
||||
geometry.materials[matid] = HFMMaterial();
|
||||
HFMMaterial& hfmMaterial = geometry.materials[matid];
|
||||
hfmMaterial._material = std::make_shared<graphics::Material>();
|
||||
setHFMMaterial(hfmMaterial, _file.materials[i]);
|
||||
}
|
||||
|
||||
|
||||
|
@ -765,9 +765,9 @@ bool GLTFReader::buildGeometry(FBXGeometry& 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(FBXMesh());
|
||||
FBXMesh& mesh = geometry.meshes[geometry.meshes.size() - 1];
|
||||
FBXCluster cluster;
|
||||
geometry.meshes.append(HFMMesh());
|
||||
HFMMesh& mesh = geometry.meshes[geometry.meshes.size() - 1];
|
||||
HFMCluster cluster;
|
||||
cluster.jointIndex = 0;
|
||||
cluster.inverseBindMatrix = glm::mat4(1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
|
@ -775,7 +775,7 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) {
|
|||
0, 0, 0, 1);
|
||||
mesh.clusters.append(cluster);
|
||||
|
||||
FBXMeshPart part = FBXMeshPart();
|
||||
HFMMeshPart part = HFMMeshPart();
|
||||
|
||||
int indicesAccessorIdx = primitive.indices;
|
||||
|
||||
|
@ -910,7 +910,7 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) {
|
|||
return true;
|
||||
}
|
||||
|
||||
FBXGeometry* GLTFReader::readGLTF(QByteArray& model, const QVariantHash& mapping,
|
||||
HFMGeometry* GLTFReader::readGLTF(QByteArray& model, const QVariantHash& mapping,
|
||||
const QUrl& url, bool loadLightmaps, float lightmapLevel) {
|
||||
|
||||
_url = url;
|
||||
|
@ -924,12 +924,12 @@ FBXGeometry* GLTFReader::readGLTF(QByteArray& model, const QVariantHash& mapping
|
|||
|
||||
parseGLTF(model);
|
||||
//_file.dump();
|
||||
FBXGeometry* geometryPtr = new FBXGeometry();
|
||||
FBXGeometry& geometry = *geometryPtr;
|
||||
HFMGeometry* geometryPtr = new HFMGeometry();
|
||||
HFMGeometry& geometry = *geometryPtr;
|
||||
|
||||
buildGeometry(geometry, url);
|
||||
|
||||
//fbxDebugDump(geometry);
|
||||
//hfmDebugDump(geometry);
|
||||
return geometryPtr;
|
||||
|
||||
}
|
||||
|
@ -997,8 +997,8 @@ QNetworkReply* GLTFReader::request(QUrl& url, bool isTest) {
|
|||
return netReply; // trying to sync later on.
|
||||
}
|
||||
|
||||
FBXTexture GLTFReader::getFBXTexture(const GLTFTexture& texture) {
|
||||
FBXTexture fbxtex = FBXTexture();
|
||||
HFMTexture GLTFReader::getHFMTexture(const GLTFTexture& texture) {
|
||||
HFMTexture fbxtex = HFMTexture();
|
||||
fbxtex.texcoordSet = 0;
|
||||
|
||||
if (texture.defined["source"]) {
|
||||
|
@ -1014,7 +1014,7 @@ FBXTexture GLTFReader::getFBXTexture(const GLTFTexture& texture) {
|
|||
return fbxtex;
|
||||
}
|
||||
|
||||
void GLTFReader::setFBXMaterial(FBXMaterial& fbxmat, const GLTFMaterial& material) {
|
||||
void GLTFReader::setHFMMaterial(HFMMaterial& fbxmat, const GLTFMaterial& material) {
|
||||
|
||||
|
||||
if (material.defined["name"]) {
|
||||
|
@ -1029,17 +1029,17 @@ void GLTFReader::setFBXMaterial(FBXMaterial& fbxmat, const GLTFMaterial& materia
|
|||
}
|
||||
|
||||
if (material.defined["emissiveTexture"]) {
|
||||
fbxmat.emissiveTexture = getFBXTexture(_file.textures[material.emissiveTexture]);
|
||||
fbxmat.emissiveTexture = getHFMTexture(_file.textures[material.emissiveTexture]);
|
||||
fbxmat.useEmissiveMap = true;
|
||||
}
|
||||
|
||||
if (material.defined["normalTexture"]) {
|
||||
fbxmat.normalTexture = getFBXTexture(_file.textures[material.normalTexture]);
|
||||
fbxmat.normalTexture = getHFMTexture(_file.textures[material.normalTexture]);
|
||||
fbxmat.useNormalMap = true;
|
||||
}
|
||||
|
||||
if (material.defined["occlusionTexture"]) {
|
||||
fbxmat.occlusionTexture = getFBXTexture(_file.textures[material.occlusionTexture]);
|
||||
fbxmat.occlusionTexture = getHFMTexture(_file.textures[material.occlusionTexture]);
|
||||
fbxmat.useOcclusionMap = true;
|
||||
}
|
||||
|
||||
|
@ -1050,14 +1050,14 @@ void GLTFReader::setFBXMaterial(FBXMaterial& fbxmat, const GLTFMaterial& materia
|
|||
fbxmat.metallic = material.pbrMetallicRoughness.metallicFactor;
|
||||
}
|
||||
if (material.pbrMetallicRoughness.defined["baseColorTexture"]) {
|
||||
fbxmat.opacityTexture = getFBXTexture(_file.textures[material.pbrMetallicRoughness.baseColorTexture]);
|
||||
fbxmat.albedoTexture = getFBXTexture(_file.textures[material.pbrMetallicRoughness.baseColorTexture]);
|
||||
fbxmat.opacityTexture = getHFMTexture(_file.textures[material.pbrMetallicRoughness.baseColorTexture]);
|
||||
fbxmat.albedoTexture = getHFMTexture(_file.textures[material.pbrMetallicRoughness.baseColorTexture]);
|
||||
fbxmat.useAlbedoMap = true;
|
||||
}
|
||||
if (material.pbrMetallicRoughness.defined["metallicRoughnessTexture"]) {
|
||||
fbxmat.roughnessTexture = getFBXTexture(_file.textures[material.pbrMetallicRoughness.metallicRoughnessTexture]);
|
||||
fbxmat.roughnessTexture = getHFMTexture(_file.textures[material.pbrMetallicRoughness.metallicRoughnessTexture]);
|
||||
fbxmat.useRoughnessMap = true;
|
||||
fbxmat.metallicTexture = getFBXTexture(_file.textures[material.pbrMetallicRoughness.metallicRoughnessTexture]);
|
||||
fbxmat.metallicTexture = getHFMTexture(_file.textures[material.pbrMetallicRoughness.metallicRoughnessTexture]);
|
||||
fbxmat.useMetallicMap = true;
|
||||
}
|
||||
if (material.pbrMetallicRoughness.defined["roughnessFactor"]) {
|
||||
|
@ -1181,37 +1181,37 @@ void GLTFReader::retriangulate(const QVector<int>& inIndices, const QVector<glm:
|
|||
}
|
||||
}
|
||||
|
||||
void GLTFReader::fbxDebugDump(const FBXGeometry& fbxgeo) {
|
||||
qCDebug(modelformat) << "---------------- fbxGeometry ----------------";
|
||||
qCDebug(modelformat) << " hasSkeletonJoints =" << fbxgeo.hasSkeletonJoints;
|
||||
qCDebug(modelformat) << " offset =" << fbxgeo.offset;
|
||||
void GLTFReader::hfmDebugDump(const HFMGeometry& hfmgeo) {
|
||||
qCDebug(modelformat) << "---------------- hfmGeometry ----------------";
|
||||
qCDebug(modelformat) << " hasSkeletonJoints =" << hfmgeo.hasSkeletonJoints;
|
||||
qCDebug(modelformat) << " offset =" << hfmgeo.offset;
|
||||
|
||||
qCDebug(modelformat) << " leftEyeJointIndex =" << fbxgeo.leftEyeJointIndex;
|
||||
qCDebug(modelformat) << " rightEyeJointIndex =" << fbxgeo.rightEyeJointIndex;
|
||||
qCDebug(modelformat) << " neckJointIndex =" << fbxgeo.neckJointIndex;
|
||||
qCDebug(modelformat) << " rootJointIndex =" << fbxgeo.rootJointIndex;
|
||||
qCDebug(modelformat) << " leanJointIndex =" << fbxgeo.leanJointIndex;
|
||||
qCDebug(modelformat) << " headJointIndex =" << fbxgeo.headJointIndex;
|
||||
qCDebug(modelformat) << " leftHandJointIndex" << fbxgeo.leftHandJointIndex;
|
||||
qCDebug(modelformat) << " rightHandJointIndex" << fbxgeo.rightHandJointIndex;
|
||||
qCDebug(modelformat) << " leftToeJointIndex" << fbxgeo.leftToeJointIndex;
|
||||
qCDebug(modelformat) << " rightToeJointIndex" << fbxgeo.rightToeJointIndex;
|
||||
qCDebug(modelformat) << " leftEyeSize = " << fbxgeo.leftEyeSize;
|
||||
qCDebug(modelformat) << " rightEyeSize = " << fbxgeo.rightEyeSize;
|
||||
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) << " palmDirection = " << fbxgeo.palmDirection;
|
||||
qCDebug(modelformat) << " palmDirection = " << hfmgeo.palmDirection;
|
||||
|
||||
qCDebug(modelformat) << " neckPivot = " << fbxgeo.neckPivot;
|
||||
qCDebug(modelformat) << " neckPivot = " << hfmgeo.neckPivot;
|
||||
|
||||
qCDebug(modelformat) << " bindExtents.size() = " << fbxgeo.bindExtents.size();
|
||||
qCDebug(modelformat) << " meshExtents.size() = " << fbxgeo.meshExtents.size();
|
||||
qCDebug(modelformat) << " bindExtents.size() = " << hfmgeo.bindExtents.size();
|
||||
qCDebug(modelformat) << " meshExtents.size() = " << hfmgeo.meshExtents.size();
|
||||
|
||||
qCDebug(modelformat) << " jointIndices.size() =" << fbxgeo.jointIndices.size();
|
||||
qCDebug(modelformat) << " joints.count() =" << fbxgeo.joints.count();
|
||||
qCDebug(modelformat) << " jointIndices.size() =" << hfmgeo.jointIndices.size();
|
||||
qCDebug(modelformat) << " joints.count() =" << hfmgeo.joints.count();
|
||||
qCDebug(modelformat) << "---------------- Meshes ----------------";
|
||||
qCDebug(modelformat) << " meshes.count() =" << fbxgeo.meshes.count();
|
||||
qCDebug(modelformat) << " blendshapeChannelNames = " << fbxgeo.blendshapeChannelNames;
|
||||
foreach(FBXMesh mesh, fbxgeo.meshes) {
|
||||
qCDebug(modelformat) << " meshes.count() =" << hfmgeo.meshes.count();
|
||||
qCDebug(modelformat) << " blendshapeChannelNames = " << hfmgeo.blendshapeChannelNames;
|
||||
foreach(HFMMesh mesh, hfmgeo.meshes) {
|
||||
qCDebug(modelformat) << "\n";
|
||||
qCDebug(modelformat) << " meshpointer =" << mesh._mesh.get();
|
||||
qCDebug(modelformat) << " meshindex =" << mesh.meshIndex;
|
||||
|
@ -1227,7 +1227,7 @@ void GLTFReader::fbxDebugDump(const FBXGeometry& fbxgeo) {
|
|||
qCDebug(modelformat) << " modelTransform =" << mesh.modelTransform;
|
||||
qCDebug(modelformat) << " parts.count() =" << mesh.parts.count();
|
||||
qCDebug(modelformat) << "---------------- Meshes (blendshapes)--------";
|
||||
foreach(FBXBlendshape bshape, mesh.blendshapes) {
|
||||
foreach(HFMBlendshape bshape, mesh.blendshapes) {
|
||||
qCDebug(modelformat) << "\n";
|
||||
qCDebug(modelformat) << " bshape.indices.count() =" << bshape.indices.count();
|
||||
qCDebug(modelformat) << " bshape.vertices.count() =" << bshape.vertices.count();
|
||||
|
@ -1235,7 +1235,7 @@ void GLTFReader::fbxDebugDump(const FBXGeometry& fbxgeo) {
|
|||
qCDebug(modelformat) << "\n";
|
||||
}
|
||||
qCDebug(modelformat) << "---------------- Meshes (meshparts)--------";
|
||||
foreach(FBXMeshPart meshPart, mesh.parts) {
|
||||
foreach(HFMMeshPart meshPart, mesh.parts) {
|
||||
qCDebug(modelformat) << "\n";
|
||||
qCDebug(modelformat) << " quadIndices.count() =" << meshPart.quadIndices.count();
|
||||
qCDebug(modelformat) << " triangleIndices.count() =" << meshPart.triangleIndices.count();
|
||||
|
@ -1245,7 +1245,7 @@ void GLTFReader::fbxDebugDump(const FBXGeometry& fbxgeo) {
|
|||
}
|
||||
qCDebug(modelformat) << "---------------- Meshes (clusters)--------";
|
||||
qCDebug(modelformat) << " clusters.count() =" << mesh.clusters.count();
|
||||
foreach(FBXCluster cluster, mesh.clusters) {
|
||||
foreach(HFMCluster cluster, mesh.clusters) {
|
||||
qCDebug(modelformat) << "\n";
|
||||
qCDebug(modelformat) << " jointIndex =" << cluster.jointIndex;
|
||||
qCDebug(modelformat) << " inverseBindMatrix =" << cluster.inverseBindMatrix;
|
||||
|
@ -1254,18 +1254,18 @@ void GLTFReader::fbxDebugDump(const FBXGeometry& fbxgeo) {
|
|||
qCDebug(modelformat) << "\n";
|
||||
}
|
||||
qCDebug(modelformat) << "---------------- AnimationFrames ----------------";
|
||||
foreach(FBXAnimationFrame anim, fbxgeo.animationFrames) {
|
||||
foreach(HFMAnimationFrame anim, hfmgeo.animationFrames) {
|
||||
qCDebug(modelformat) << " anim.translations = " << anim.translations;
|
||||
qCDebug(modelformat) << " anim.rotations = " << anim.rotations;
|
||||
}
|
||||
QList<int> mitomona_keys = fbxgeo.meshIndicesToModelNames.keys();
|
||||
QList<int> mitomona_keys = hfmgeo.meshIndicesToModelNames.keys();
|
||||
foreach(int key, mitomona_keys) {
|
||||
qCDebug(modelformat) << " meshIndicesToModelNames key =" << key << " val =" << fbxgeo.meshIndicesToModelNames[key];
|
||||
qCDebug(modelformat) << " meshIndicesToModelNames key =" << key << " val =" << hfmgeo.meshIndicesToModelNames[key];
|
||||
}
|
||||
|
||||
qCDebug(modelformat) << "---------------- Materials ----------------";
|
||||
|
||||
foreach(FBXMaterial mat, fbxgeo.materials) {
|
||||
foreach(HFMMaterial mat, hfmgeo.materials) {
|
||||
qCDebug(modelformat) << "\n";
|
||||
qCDebug(modelformat) << " mat.materialID =" << mat.materialID;
|
||||
qCDebug(modelformat) << " diffuseColor =" << mat.diffuseColor;
|
||||
|
@ -1314,7 +1314,7 @@ void GLTFReader::fbxDebugDump(const FBXGeometry& fbxgeo) {
|
|||
|
||||
qCDebug(modelformat) << "---------------- Joints ----------------";
|
||||
|
||||
foreach(FBXJoint joint, fbxgeo.joints) {
|
||||
foreach(HFMJoint joint, hfmgeo.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();
|
||||
FBXGeometry* readGLTF(QByteArray& model, const QVariantHash& mapping,
|
||||
HFMGeometry* readGLTF(QByteArray& model, const QVariantHash& mapping,
|
||||
const QUrl& url, bool loadLightmaps = true, float lightmapLevel = 1.0f);
|
||||
private:
|
||||
GLTFFile _file;
|
||||
|
@ -714,7 +714,7 @@ private:
|
|||
|
||||
glm::mat4 getModelTransform(const GLTFNode& node);
|
||||
|
||||
bool buildGeometry(FBXGeometry& geometry, const QUrl& url);
|
||||
bool buildGeometry(HFMGeometry& geometry, const QUrl& url);
|
||||
bool parseGLTF(const QByteArray& model);
|
||||
|
||||
bool getStringVal(const QJsonObject& object, const QString& fieldname,
|
||||
|
@ -778,9 +778,9 @@ private:
|
|||
bool doesResourceExist(const QString& url);
|
||||
|
||||
|
||||
void setFBXMaterial(FBXMaterial& fbxmat, const GLTFMaterial& material);
|
||||
FBXTexture getFBXTexture(const GLTFTexture& texture);
|
||||
void fbxDebugDump(const FBXGeometry& fbxgeo);
|
||||
void setHFMMaterial(HFMMaterial& fbxmat, const GLTFMaterial& material);
|
||||
HFMTexture getHFMTexture(const GLTFTexture& texture);
|
||||
void hfmDebugDump(const HFMGeometry& hfmgeo);
|
||||
};
|
||||
|
||||
#endif // hifi_GLTFReader_h
|
|
@ -175,7 +175,7 @@ glm::vec2 OBJTokenizer::getVec2() {
|
|||
}
|
||||
|
||||
|
||||
void setMeshPartDefaults(FBXMeshPart& meshPart, QString materialID) {
|
||||
void setMeshPartDefaults(HFMMeshPart& meshPart, QString materialID) {
|
||||
meshPart.materialID = materialID;
|
||||
}
|
||||
|
||||
|
@ -488,12 +488,12 @@ QNetworkReply* request(QUrl& url, bool isTest) {
|
|||
}
|
||||
|
||||
|
||||
bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry,
|
||||
bool OBJReader::parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, HFMGeometry& geometry,
|
||||
float& scaleGuess, bool combineParts) {
|
||||
FaceGroup faces;
|
||||
FBXMesh& mesh = geometry.meshes[0];
|
||||
mesh.parts.append(FBXMeshPart());
|
||||
FBXMeshPart& meshPart = mesh.parts.last();
|
||||
HFMMesh& mesh = geometry.meshes[0];
|
||||
mesh.parts.append(HFMMeshPart());
|
||||
HFMMeshPart& meshPart = mesh.parts.last();
|
||||
bool sawG = false;
|
||||
bool result = true;
|
||||
int originalFaceCountForDebugging = 0;
|
||||
|
@ -652,13 +652,13 @@ done:
|
|||
}
|
||||
|
||||
|
||||
FBXGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, bool combineParts, const QUrl& url) {
|
||||
HFMGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& mapping, bool combineParts, const QUrl& url) {
|
||||
PROFILE_RANGE_EX(resource_parse, __FUNCTION__, 0xffff0000, nullptr);
|
||||
QBuffer buffer { &model };
|
||||
buffer.open(QIODevice::ReadOnly);
|
||||
|
||||
auto geometryPtr { std::make_shared<FBXGeometry>() };
|
||||
FBXGeometry& geometry { *geometryPtr };
|
||||
auto geometryPtr { std::make_shared<HFMGeometry>() };
|
||||
HFMGeometry& geometry { *geometryPtr };
|
||||
OBJTokenizer tokenizer { &buffer };
|
||||
float scaleGuess = 1.0f;
|
||||
|
||||
|
@ -666,14 +666,14 @@ FBXGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& m
|
|||
|
||||
_url = url;
|
||||
geometry.meshExtents.reset();
|
||||
geometry.meshes.append(FBXMesh());
|
||||
geometry.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)) {}
|
||||
|
||||
FBXMesh& mesh = geometry.meshes[0];
|
||||
HFMMesh& mesh = geometry.meshes[0];
|
||||
mesh.meshIndex = 0;
|
||||
|
||||
geometry.joints.resize(1);
|
||||
|
@ -688,7 +688,7 @@ FBXGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& m
|
|||
|
||||
geometry.jointIndices["x"] = 1;
|
||||
|
||||
FBXCluster cluster;
|
||||
HFMCluster cluster;
|
||||
cluster.jointIndex = 0;
|
||||
cluster.inverseBindMatrix = glm::mat4(1, 0, 0, 0,
|
||||
0, 1, 0, 0,
|
||||
|
@ -697,20 +697,20 @@ FBXGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& m
|
|||
mesh.clusters.append(cluster);
|
||||
|
||||
QMap<QString, int> materialMeshIdMap;
|
||||
QVector<FBXMeshPart> fbxMeshParts;
|
||||
QVector<HFMMeshPart> hfmMeshParts;
|
||||
for (int i = 0, meshPartCount = 0; i < mesh.parts.count(); i++, meshPartCount++) {
|
||||
FBXMeshPart& meshPart = mesh.parts[i];
|
||||
HFMMeshPart& meshPart = mesh.parts[i];
|
||||
FaceGroup faceGroup = faceGroups[meshPartCount];
|
||||
bool specifiesUV = false;
|
||||
foreach(OBJFace face, faceGroup) {
|
||||
// Go through all of the OBJ faces and determine the number of different materials necessary (each different material will be a unique mesh).
|
||||
// NOTE (trent/mittens 3/30/17): this seems hardcore wasteful and is slowed down a bit by iterating through the face group twice, but it's the best way I've thought of to hack multi-material support in an OBJ into this pipeline.
|
||||
if (!materialMeshIdMap.contains(face.materialName)) {
|
||||
// Create a new FBXMesh for this material mapping.
|
||||
// Create a new HFMMesh for this material mapping.
|
||||
materialMeshIdMap.insert(face.materialName, materialMeshIdMap.count());
|
||||
|
||||
fbxMeshParts.append(FBXMeshPart());
|
||||
FBXMeshPart& meshPartNew = fbxMeshParts.last();
|
||||
hfmMeshParts.append(HFMMeshPart());
|
||||
HFMMeshPart& meshPartNew = hfmMeshParts.last();
|
||||
meshPartNew.quadIndices = QVector<int>(meshPart.quadIndices); // Copy over quad indices [NOTE (trent/mittens, 4/3/17): Likely unnecessary since they go unused anyway].
|
||||
meshPartNew.quadTrianglesIndices = QVector<int>(meshPart.quadTrianglesIndices); // Copy over quad triangulated indices [NOTE (trent/mittens, 4/3/17): Likely unnecessary since they go unused anyway].
|
||||
meshPartNew.triangleIndices = QVector<int>(meshPart.triangleIndices); // Copy over triangle indices.
|
||||
|
@ -745,14 +745,14 @@ FBXGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& m
|
|||
// clean up old mesh parts.
|
||||
int unmodifiedMeshPartCount = mesh.parts.count();
|
||||
mesh.parts.clear();
|
||||
mesh.parts = QVector<FBXMeshPart>(fbxMeshParts);
|
||||
mesh.parts = QVector<HFMMeshPart>(hfmMeshParts);
|
||||
|
||||
for (int i = 0, meshPartCount = 0; i < unmodifiedMeshPartCount; i++, meshPartCount++) {
|
||||
FaceGroup faceGroup = faceGroups[meshPartCount];
|
||||
|
||||
// Now that each mesh has been created with its own unique material mappings, fill them with data (vertex data is duplicated, face data is not).
|
||||
foreach(OBJFace face, faceGroup) {
|
||||
FBXMeshPart& meshPart = mesh.parts[materialMeshIdMap[face.materialName]];
|
||||
HFMMeshPart& meshPart = mesh.parts[materialMeshIdMap[face.materialName]];
|
||||
|
||||
glm::vec3 v0 = checked_at(vertices, face.vertexIndices[0]);
|
||||
glm::vec3 v1 = checked_at(vertices, face.vertexIndices[1]);
|
||||
|
@ -824,7 +824,7 @@ FBXGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& m
|
|||
// Build the single mesh.
|
||||
FBXReader::buildModelMesh(mesh, url.toString());
|
||||
|
||||
// fbxDebugDump(geometry);
|
||||
// hfmDebugDump(geometry);
|
||||
} catch(const std::exception& e) {
|
||||
qCDebug(modelformat) << "OBJ reader fail: " << e.what();
|
||||
}
|
||||
|
@ -885,38 +885,38 @@ FBXGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& m
|
|||
if (!objMaterial.used) {
|
||||
continue;
|
||||
}
|
||||
geometry.materials[materialID] = FBXMaterial(objMaterial.diffuseColor,
|
||||
geometry.materials[materialID] = HFMMaterial(objMaterial.diffuseColor,
|
||||
objMaterial.specularColor,
|
||||
objMaterial.emissiveColor,
|
||||
objMaterial.shininess,
|
||||
objMaterial.opacity);
|
||||
FBXMaterial& fbxMaterial = geometry.materials[materialID];
|
||||
fbxMaterial.materialID = materialID;
|
||||
fbxMaterial._material = std::make_shared<graphics::Material>();
|
||||
graphics::MaterialPointer modelMaterial = fbxMaterial._material;
|
||||
HFMMaterial& hfmMaterial = geometry.materials[materialID];
|
||||
hfmMaterial.materialID = materialID;
|
||||
hfmMaterial._material = std::make_shared<graphics::Material>();
|
||||
graphics::MaterialPointer modelMaterial = hfmMaterial._material;
|
||||
|
||||
if (!objMaterial.diffuseTextureFilename.isEmpty()) {
|
||||
fbxMaterial.albedoTexture.filename = objMaterial.diffuseTextureFilename;
|
||||
hfmMaterial.albedoTexture.filename = objMaterial.diffuseTextureFilename;
|
||||
}
|
||||
if (!objMaterial.specularTextureFilename.isEmpty()) {
|
||||
fbxMaterial.specularTexture.filename = objMaterial.specularTextureFilename;
|
||||
hfmMaterial.specularTexture.filename = objMaterial.specularTextureFilename;
|
||||
}
|
||||
if (!objMaterial.emissiveTextureFilename.isEmpty()) {
|
||||
fbxMaterial.emissiveTexture.filename = objMaterial.emissiveTextureFilename;
|
||||
hfmMaterial.emissiveTexture.filename = objMaterial.emissiveTextureFilename;
|
||||
}
|
||||
if (!objMaterial.bumpTextureFilename.isEmpty()) {
|
||||
fbxMaterial.normalTexture.filename = objMaterial.bumpTextureFilename;
|
||||
fbxMaterial.normalTexture.isBumpmap = true;
|
||||
fbxMaterial.bumpMultiplier = objMaterial.bumpTextureOptions.bumpMultiplier;
|
||||
hfmMaterial.normalTexture.filename = objMaterial.bumpTextureFilename;
|
||||
hfmMaterial.normalTexture.isBumpmap = true;
|
||||
hfmMaterial.bumpMultiplier = objMaterial.bumpTextureOptions.bumpMultiplier;
|
||||
}
|
||||
if (!objMaterial.opacityTextureFilename.isEmpty()) {
|
||||
fbxMaterial.opacityTexture.filename = objMaterial.opacityTextureFilename;
|
||||
hfmMaterial.opacityTexture.filename = objMaterial.opacityTextureFilename;
|
||||
}
|
||||
|
||||
modelMaterial->setEmissive(fbxMaterial.emissiveColor);
|
||||
modelMaterial->setAlbedo(fbxMaterial.diffuseColor);
|
||||
modelMaterial->setMetallic(glm::length(fbxMaterial.specularColor));
|
||||
modelMaterial->setRoughness(graphics::Material::shininessToRoughness(fbxMaterial.shininess));
|
||||
modelMaterial->setEmissive(hfmMaterial.emissiveColor);
|
||||
modelMaterial->setAlbedo(hfmMaterial.diffuseColor);
|
||||
modelMaterial->setMetallic(glm::length(hfmMaterial.specularColor));
|
||||
modelMaterial->setRoughness(graphics::Material::shininessToRoughness(hfmMaterial.shininess));
|
||||
|
||||
bool applyTransparency = false;
|
||||
bool applyShininess = false;
|
||||
|
@ -971,7 +971,7 @@ FBXGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& m
|
|||
}
|
||||
|
||||
if (applyTransparency) {
|
||||
fbxMaterial.opacity = std::max(fbxMaterial.opacity, ILLUMINATION_MODEL_MIN_OPACITY);
|
||||
hfmMaterial.opacity = std::max(hfmMaterial.opacity, ILLUMINATION_MODEL_MIN_OPACITY);
|
||||
}
|
||||
if (applyShininess) {
|
||||
modelMaterial->setRoughness(ILLUMINATION_MODEL_APPLY_SHININESS);
|
||||
|
@ -985,18 +985,18 @@ FBXGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& m
|
|||
modelMaterial->setFresnel(glm::vec3(1.0f));
|
||||
}
|
||||
|
||||
modelMaterial->setOpacity(fbxMaterial.opacity);
|
||||
modelMaterial->setOpacity(hfmMaterial.opacity);
|
||||
}
|
||||
|
||||
return geometryPtr;
|
||||
}
|
||||
|
||||
void fbxDebugDump(const FBXGeometry& fbxgeo) {
|
||||
qCDebug(modelformat) << "---------------- fbxGeometry ----------------";
|
||||
qCDebug(modelformat) << " hasSkeletonJoints =" << fbxgeo.hasSkeletonJoints;
|
||||
qCDebug(modelformat) << " offset =" << fbxgeo.offset;
|
||||
qCDebug(modelformat) << " meshes.count() =" << fbxgeo.meshes.count();
|
||||
foreach (FBXMesh mesh, fbxgeo.meshes) {
|
||||
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) {
|
||||
qCDebug(modelformat) << " vertices.count() =" << mesh.vertices.count();
|
||||
qCDebug(modelformat) << " colors.count() =" << mesh.colors.count();
|
||||
qCDebug(modelformat) << " normals.count() =" << mesh.normals.count();
|
||||
|
@ -1014,7 +1014,7 @@ void fbxDebugDump(const FBXGeometry& fbxgeo) {
|
|||
qCDebug(modelformat) << " meshExtents =" << mesh.meshExtents;
|
||||
qCDebug(modelformat) << " modelTransform =" << mesh.modelTransform;
|
||||
qCDebug(modelformat) << " parts.count() =" << mesh.parts.count();
|
||||
foreach (FBXMeshPart meshPart, mesh.parts) {
|
||||
foreach (HFMMeshPart meshPart, mesh.parts) {
|
||||
qCDebug(modelformat) << " quadIndices.count() =" << meshPart.quadIndices.count();
|
||||
qCDebug(modelformat) << " triangleIndices.count() =" << meshPart.triangleIndices.count();
|
||||
/*
|
||||
|
@ -1031,16 +1031,16 @@ void fbxDebugDump(const FBXGeometry& fbxgeo) {
|
|||
*/
|
||||
}
|
||||
qCDebug(modelformat) << " clusters.count() =" << mesh.clusters.count();
|
||||
foreach (FBXCluster cluster, mesh.clusters) {
|
||||
foreach (HFMCluster cluster, mesh.clusters) {
|
||||
qCDebug(modelformat) << " jointIndex =" << cluster.jointIndex;
|
||||
qCDebug(modelformat) << " inverseBindMatrix =" << cluster.inverseBindMatrix;
|
||||
}
|
||||
}
|
||||
|
||||
qCDebug(modelformat) << " jointIndices =" << fbxgeo.jointIndices;
|
||||
qCDebug(modelformat) << " joints.count() =" << fbxgeo.joints.count();
|
||||
qCDebug(modelformat) << " jointIndices =" << hfmgeo.jointIndices;
|
||||
qCDebug(modelformat) << " joints.count() =" << hfmgeo.joints.count();
|
||||
|
||||
foreach (FBXJoint joint, fbxgeo.joints) {
|
||||
foreach (HFMJoint joint, hfmgeo.joints) {
|
||||
qCDebug(modelformat) << " isFree =" << joint.isFree;
|
||||
qCDebug(modelformat) << " freeLineage" << joint.freeLineage;
|
||||
qCDebug(modelformat) << " parentIndex" << joint.parentIndex;
|
||||
|
|
|
@ -42,7 +42,7 @@ public:
|
|||
bool add(const QByteArray& vertexIndex, const QByteArray& textureIndex, const QByteArray& normalIndex,
|
||||
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& vertexColors);
|
||||
// Return a set of one or more OBJFaces from this one, in which each is just a triangle.
|
||||
// Even though FBXMeshPart can handle quads, it would be messy to try to keep track of mixed-size faces, so we treat everything as triangles.
|
||||
// Even though HFMMeshPart can handle quads, it would be messy to try to keep track of mixed-size faces, so we treat everything as triangles.
|
||||
QVector<OBJFace> triangulate();
|
||||
private:
|
||||
void addFrom(const OBJFace* face, int index);
|
||||
|
@ -54,7 +54,7 @@ public:
|
|||
}
|
||||
;
|
||||
// Materials and references to material names can come in any order, and different mesh parts can refer to the same material.
|
||||
// Therefore it would get pretty hacky to try to use FBXMeshPart to store these as we traverse the files.
|
||||
// Therefore it would get pretty hacky to try to use HFMMeshPart to store these as we traverse the files.
|
||||
class OBJMaterial {
|
||||
public:
|
||||
float shininess;
|
||||
|
@ -87,13 +87,13 @@ public:
|
|||
QString currentMaterialName;
|
||||
QHash<QString, OBJMaterial> materials;
|
||||
|
||||
FBXGeometry::Pointer readOBJ(QByteArray& model, const QVariantHash& mapping, bool combineParts, const QUrl& url = QUrl());
|
||||
HFMGeometry::Pointer readOBJ(QByteArray& model, const QVariantHash& mapping, bool combineParts, const QUrl& url = QUrl());
|
||||
|
||||
private:
|
||||
QUrl _url;
|
||||
|
||||
QHash<QByteArray, bool> librariesSeen;
|
||||
bool parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, FBXGeometry& geometry,
|
||||
bool parseOBJGroup(OBJTokenizer& tokenizer, const QVariantHash& mapping, HFMGeometry& geometry,
|
||||
float& scaleGuess, bool combineParts);
|
||||
void parseMaterialLibrary(QIODevice* device);
|
||||
void parseTextureLine(const QByteArray& textureLine, QByteArray& filename, OBJMaterialTextureOptions& textureOptions);
|
||||
|
@ -103,5 +103,5 @@ 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(FBXMeshPart& meshPart, QString materialID);
|
||||
void fbxDebugDump(const FBXGeometry& fbxgeo);
|
||||
void setMeshPartDefaults(HFMMeshPart& meshPart, QString materialID);
|
||||
void hfmDebugDump(const HFMGeometry& hfmgeo);
|
||||
|
|
|
@ -128,7 +128,7 @@ void GeometryMappingResource::downloadFinished(const QByteArray& data) {
|
|||
|
||||
void GeometryMappingResource::onGeometryMappingLoaded(bool success) {
|
||||
if (success && _geometryResource) {
|
||||
_fbxGeometry = _geometryResource->_fbxGeometry;
|
||||
_hfmGeometry = _geometryResource->_hfmGeometry;
|
||||
_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"))) {
|
||||
|
||||
FBXGeometry::Pointer fbxGeometry;
|
||||
HFMGeometry::Pointer hfmGeometry;
|
||||
|
||||
if (_url.path().toLower().endsWith(".fbx")) {
|
||||
fbxGeometry.reset(readFBX(_data, _mapping, _url.path()));
|
||||
if (fbxGeometry->meshes.size() == 0 && fbxGeometry->joints.size() == 0) {
|
||||
hfmGeometry.reset(readFBX(_data, _mapping, _url.path()));
|
||||
if (hfmGeometry->meshes.size() == 0 && hfmGeometry->joints.size() == 0) {
|
||||
throw QString("empty geometry, possibly due to an unsupported FBX version");
|
||||
}
|
||||
} else if (_url.path().toLower().endsWith(".obj")) {
|
||||
fbxGeometry = OBJReader().readOBJ(_data, _mapping, _combineParts, _url);
|
||||
hfmGeometry = OBJReader().readOBJ(_data, _mapping, _combineParts, _url);
|
||||
} else if (_url.path().toLower().endsWith(".obj.gz")) {
|
||||
QByteArray uncompressedData;
|
||||
if (gunzip(_data, uncompressedData)){
|
||||
fbxGeometry = OBJReader().readOBJ(uncompressedData, _mapping, _combineParts, _url);
|
||||
hfmGeometry = 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>();
|
||||
fbxGeometry.reset(glreader->readGLTF(_data, _mapping, _url));
|
||||
if (fbxGeometry->meshes.size() == 0 && fbxGeometry->joints.size() == 0) {
|
||||
hfmGeometry.reset(glreader->readGLTF(_data, _mapping, _url));
|
||||
if (hfmGeometry->meshes.size() == 0 && hfmGeometry->joints.size() == 0) {
|
||||
throw QString("empty geometry, possibly due to an unsupported GLTF version");
|
||||
}
|
||||
} else {
|
||||
throw QString("unsupported format");
|
||||
}
|
||||
|
||||
// Add scripts to fbxgeometry
|
||||
// Add scripts to hfmGeometry
|
||||
if (!_mapping.value(SCRIPT_FIELD).isNull()) {
|
||||
QVariantList scripts = _mapping.values(SCRIPT_FIELD);
|
||||
for (auto &script : scripts) {
|
||||
fbxGeometry->scripts.push_back(script.toString());
|
||||
hfmGeometry->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(FBXGeometry::Pointer, fbxGeometry));
|
||||
Q_ARG(HFMGeometry::Pointer, hfmGeometry));
|
||||
}
|
||||
} else {
|
||||
throw QString("url is invalid");
|
||||
|
@ -262,7 +262,7 @@ public:
|
|||
virtual void downloadFinished(const QByteArray& data) override;
|
||||
|
||||
protected:
|
||||
Q_INVOKABLE void setGeometryDefinition(FBXGeometry::Pointer fbxGeometry);
|
||||
Q_INVOKABLE void setGeometryDefinition(HFMGeometry::Pointer hfmGeometry);
|
||||
|
||||
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(FBXGeometry::Pointer fbxGeometry) {
|
||||
void GeometryDefinitionResource::setGeometryDefinition(HFMGeometry::Pointer hfmGeometry) {
|
||||
// Assume ownership of the geometry pointer
|
||||
_fbxGeometry = fbxGeometry;
|
||||
_hfmGeometry = hfmGeometry;
|
||||
|
||||
// Copy materials
|
||||
QHash<QString, size_t> materialIDAtlas;
|
||||
for (const FBXMaterial& material : _fbxGeometry->materials) {
|
||||
for (const HFMMaterial& material : _hfmGeometry->materials) {
|
||||
materialIDAtlas[material.materialID] = _materials.size();
|
||||
_materials.push_back(std::make_shared<NetworkMaterial>(material, _textureBaseUrl));
|
||||
}
|
||||
|
@ -291,11 +291,11 @@ void GeometryDefinitionResource::setGeometryDefinition(FBXGeometry::Pointer fbxG
|
|||
std::shared_ptr<GeometryMeshes> meshes = std::make_shared<GeometryMeshes>();
|
||||
std::shared_ptr<GeometryMeshParts> parts = std::make_shared<GeometryMeshParts>();
|
||||
int meshID = 0;
|
||||
for (const FBXMesh& mesh : _fbxGeometry->meshes) {
|
||||
for (const HFMMesh& mesh : _hfmGeometry->meshes) {
|
||||
// Copy mesh pointers
|
||||
meshes->emplace_back(mesh._mesh);
|
||||
int partID = 0;
|
||||
for (const FBXMeshPart& part : mesh.parts) {
|
||||
for (const HFMMeshPart& part : mesh.parts) {
|
||||
// Construct local parts
|
||||
parts->push_back(std::make_shared<MeshPart>(meshID, partID, (int)materialIDAtlas[part.materialID]));
|
||||
partID++;
|
||||
|
@ -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) {
|
||||
_fbxGeometry = geometry._fbxGeometry;
|
||||
_hfmGeometry = geometry._hfmGeometry;
|
||||
_meshes = geometry._meshes;
|
||||
_meshParts = geometry._meshParts;
|
||||
|
||||
|
@ -444,8 +444,8 @@ void GeometryResource::deleter() {
|
|||
}
|
||||
|
||||
void GeometryResource::setTextures() {
|
||||
if (_fbxGeometry) {
|
||||
for (const FBXMaterial& material : _fbxGeometry->materials) {
|
||||
if (_hfmGeometry) {
|
||||
for (const HFMMaterial& material : _hfmGeometry->materials) {
|
||||
_materials.push_back(std::make_shared<NetworkMaterial>(material, _textureBaseUrl));
|
||||
}
|
||||
}
|
||||
|
@ -512,7 +512,7 @@ const QString& NetworkMaterial::getTextureName(MapChannel channel) {
|
|||
return NO_TEXTURE;
|
||||
}
|
||||
|
||||
QUrl NetworkMaterial::getTextureUrl(const QUrl& baseUrl, const FBXTexture& texture) {
|
||||
QUrl NetworkMaterial::getTextureUrl(const QUrl& baseUrl, const HFMTexture& texture) {
|
||||
if (texture.content.isEmpty()) {
|
||||
// External file: search relative to the baseUrl, in case filename is relative
|
||||
return baseUrl.resolved(QUrl(texture.filename));
|
||||
|
@ -529,22 +529,22 @@ QUrl NetworkMaterial::getTextureUrl(const QUrl& baseUrl, const FBXTexture& textu
|
|||
}
|
||||
}
|
||||
|
||||
graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& baseUrl, const FBXTexture& fbxTexture,
|
||||
graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& baseUrl, const HFMTexture& hfmTexture,
|
||||
image::TextureUsage::Type type, MapChannel channel) {
|
||||
|
||||
if (baseUrl.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto url = getTextureUrl(baseUrl, fbxTexture);
|
||||
const auto texture = DependencyManager::get<TextureCache>()->getTexture(url, type, fbxTexture.content, fbxTexture.maxNumPixels);
|
||||
_textures[channel] = Texture { fbxTexture.name, texture };
|
||||
const auto url = getTextureUrl(baseUrl, hfmTexture);
|
||||
const auto texture = DependencyManager::get<TextureCache>()->getTexture(url, type, hfmTexture.content, hfmTexture.maxNumPixels);
|
||||
_textures[channel] = Texture { hfmTexture.name, texture };
|
||||
|
||||
auto map = std::make_shared<graphics::TextureMap>();
|
||||
if (texture) {
|
||||
map->setTextureSource(texture->_textureSource);
|
||||
}
|
||||
map->setTextureTransform(fbxTexture.transform);
|
||||
map->setTextureTransform(hfmTexture.transform);
|
||||
|
||||
return map;
|
||||
}
|
||||
|
@ -624,7 +624,7 @@ void NetworkMaterial::setLightmapMap(const QUrl& url) {
|
|||
}
|
||||
}
|
||||
|
||||
NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl) :
|
||||
NetworkMaterial::NetworkMaterial(const HFMMaterial& material, const QUrl& textureBaseUrl) :
|
||||
graphics::Material(*material._material),
|
||||
_textures(MapChannel::NUM_MAP_CHANNELS)
|
||||
{
|
||||
|
|
|
@ -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)_fbxGeometry; }
|
||||
bool isGeometryLoaded() const { return (bool)_hfmGeometry; }
|
||||
|
||||
const FBXGeometry& getFBXGeometry() const { return *_fbxGeometry; }
|
||||
const HFMGeometry& getHFMGeometry() const { return *_hfmGeometry; }
|
||||
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 FBXGeometry> _fbxGeometry;
|
||||
std::shared_ptr<const HFMGeometry> _hfmGeometry;
|
||||
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 _fbxGeometry && _materials.empty(); }
|
||||
bool shouldSetTextures() const { return _hfmGeometry && _materials.empty(); }
|
||||
void setTextures();
|
||||
void resetTextures();
|
||||
|
||||
|
@ -165,7 +165,7 @@ public:
|
|||
using MapChannel = graphics::Material::MapChannel;
|
||||
|
||||
NetworkMaterial() : _textures(MapChannel::NUM_MAP_CHANNELS) {}
|
||||
NetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl);
|
||||
NetworkMaterial(const HFMMaterial& material, const QUrl& textureBaseUrl);
|
||||
NetworkMaterial(const NetworkMaterial& material);
|
||||
|
||||
void setAlbedoMap(const QUrl& url, bool useAlphaChannel);
|
||||
|
@ -201,8 +201,8 @@ protected:
|
|||
|
||||
private:
|
||||
// Helpers for the ctors
|
||||
QUrl getTextureUrl(const QUrl& baseUrl, const FBXTexture& fbxTexture);
|
||||
graphics::TextureMapPointer fetchTextureMap(const QUrl& baseUrl, const FBXTexture& fbxTexture,
|
||||
QUrl getTextureUrl(const QUrl& baseUrl, const HFMTexture& hfmTexture);
|
||||
graphics::TextureMapPointer fetchTextureMap(const QUrl& baseUrl, const HFMTexture& hfmTexture,
|
||||
image::TextureUsage::Type type, MapChannel channel);
|
||||
graphics::TextureMapPointer fetchTextureMap(const QUrl& url, image::TextureUsage::Type type, MapChannel channel);
|
||||
|
||||
|
|
|
@ -45,8 +45,10 @@ public:
|
|||
virtual void onTimeout() {}
|
||||
|
||||
virtual void onPacketSent(int wireSize, SequenceNumber seqNum, p_high_resolution_clock::time_point timePoint) {}
|
||||
virtual void onPacketReSent(int wireSize, SequenceNumber seqNum, p_high_resolution_clock::time_point timePoint) {}
|
||||
|
||||
virtual int estimatedTimeout() const = 0;
|
||||
|
||||
protected:
|
||||
void setMSS(int mss) { _mss = mss; }
|
||||
virtual void setInitialSendSequenceNumber(SequenceNumber seqNum) = 0;
|
||||
|
|
|
@ -195,7 +195,7 @@ void Connection::recordSentPackets(int wireSize, int payloadSize,
|
|||
void Connection::recordRetransmission(int wireSize, SequenceNumber seqNum, p_high_resolution_clock::time_point timePoint) {
|
||||
_stats.record(ConnectionStats::Stats::Retransmission);
|
||||
|
||||
_congestionControl->onPacketSent(wireSize, seqNum, timePoint);
|
||||
_congestionControl->onPacketReSent(wireSize, seqNum, timePoint);
|
||||
}
|
||||
|
||||
void Connection::sendACK() {
|
||||
|
@ -303,7 +303,7 @@ void Connection::processControl(ControlPacketPointer controlPacket) {
|
|||
// where the other end expired our connection. Let's reset.
|
||||
|
||||
#ifdef UDT_CONNECTION_DEBUG
|
||||
qCDebug(networking) << "Got HandshakeRequest from" << _destination << ", stopping SendQueue";
|
||||
qCDebug(networking) << "Got HandshakeRequest from" << _destination << ", stopping SendQueue";
|
||||
#endif
|
||||
_hasReceivedHandshakeACK = false;
|
||||
stopSendQueue();
|
||||
|
@ -327,19 +327,19 @@ void Connection::processACK(ControlPacketPointer controlPacket) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (ack <= _lastReceivedACK) {
|
||||
if (ack < _lastReceivedACK) {
|
||||
// this is an out of order ACK, bail
|
||||
// or
|
||||
// processing an already received ACK, bail
|
||||
return;
|
||||
}
|
||||
|
||||
_lastReceivedACK = ack;
|
||||
|
||||
// ACK the send queue so it knows what was received
|
||||
getSendQueue().ack(ack);
|
||||
|
||||
|
||||
if (ack > _lastReceivedACK) {
|
||||
// this is not a repeated ACK, so update our member and tell the send queue
|
||||
_lastReceivedACK = ack;
|
||||
|
||||
// ACK the send queue so it knows what was received
|
||||
getSendQueue().ack(ack);
|
||||
}
|
||||
|
||||
// give this ACK to the congestion control and update the send queue parameters
|
||||
updateCongestionControlAndSendQueue([this, ack, &controlPacket] {
|
||||
if (_congestionControl->onACK(ack, controlPacket->getReceiveTime())) {
|
||||
|
|
|
@ -481,6 +481,7 @@ bool SendQueue::isInactive(bool attemptedToSendPacket) {
|
|||
auto cvStatus = _emptyCondition.wait_for(locker, EMPTY_QUEUES_INACTIVE_TIMEOUT);
|
||||
|
||||
if (cvStatus == std::cv_status::timeout && (_packets.isEmpty() || isFlowWindowFull()) && _naks.isEmpty()) {
|
||||
|
||||
#ifdef UDT_CONNECTION_DEBUG
|
||||
qCDebug(networking) << "SendQueue to" << _destination << "has been empty for"
|
||||
<< EMPTY_QUEUES_INACTIVE_TIMEOUT.count()
|
||||
|
|
|
@ -27,112 +27,106 @@ TCPVegasCC::TCPVegasCC() {
|
|||
_baseRTT = std::numeric_limits<int>::max();
|
||||
}
|
||||
|
||||
bool TCPVegasCC::calculateRTT(p_high_resolution_clock::time_point sendTime, p_high_resolution_clock::time_point receiveTime) {
|
||||
// calculate the RTT (receive time - time ACK sent)
|
||||
int lastRTT = duration_cast<microseconds>(receiveTime - sendTime).count();
|
||||
|
||||
const int MAX_RTT_SAMPLE_MICROSECONDS = 10000000;
|
||||
|
||||
if (lastRTT < 0) {
|
||||
Q_ASSERT_X(false, __FUNCTION__, "calculated an RTT that is not > 0");
|
||||
return false;
|
||||
} else if (lastRTT == 0) {
|
||||
// we do not allow a zero microsecond RTT (as per the UNIX kernel implementation of TCP Vegas)
|
||||
lastRTT = 1;
|
||||
} else if (lastRTT > MAX_RTT_SAMPLE_MICROSECONDS) {
|
||||
// we cap the lastRTT to MAX_RTT_SAMPLE_MICROSECONDS to avoid overflows in window size calculations
|
||||
lastRTT = MAX_RTT_SAMPLE_MICROSECONDS;
|
||||
}
|
||||
|
||||
if (_ewmaRTT == -1) {
|
||||
// first RTT sample - set _ewmaRTT to the value and set the variance to half the value
|
||||
_ewmaRTT = lastRTT;
|
||||
_rttVariance = lastRTT / 2;
|
||||
} else {
|
||||
// This updates the RTT using exponential weighted moving average
|
||||
// This is the Jacobson's forumla for RTT estimation
|
||||
// http://www.mathcs.emory.edu/~cheung/Courses/455/Syllabus/7-transport/Jacobson-88.pdf
|
||||
|
||||
// Estimated RTT = (1 - x)(estimatedRTT) + (x)(sampleRTT)
|
||||
// (where x = 0.125 via Jacobson)
|
||||
|
||||
// Deviation = (1 - x)(deviation) + x |sampleRTT - estimatedRTT|
|
||||
// (where x = 0.25 via Jacobson)
|
||||
|
||||
static const int RTT_ESTIMATION_ALPHA = 8;
|
||||
static const int RTT_ESTIMATION_VARIANCE_ALPHA = 4;
|
||||
|
||||
_ewmaRTT = (_ewmaRTT * (RTT_ESTIMATION_ALPHA - 1) + lastRTT) / RTT_ESTIMATION_ALPHA;
|
||||
_rttVariance = (_rttVariance * (RTT_ESTIMATION_VARIANCE_ALPHA- 1)
|
||||
+ abs(lastRTT - _ewmaRTT)) / RTT_ESTIMATION_VARIANCE_ALPHA;
|
||||
}
|
||||
|
||||
// keep track of the lowest RTT during connection
|
||||
_baseRTT = std::min(_baseRTT, lastRTT);
|
||||
|
||||
// find the min RTT during the last RTT
|
||||
_currentMinRTT = std::min(_currentMinRTT, lastRTT);
|
||||
|
||||
// add 1 to the number of RTT samples collected during this RTT window
|
||||
++_numRTTs;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TCPVegasCC::onACK(SequenceNumber ack, p_high_resolution_clock::time_point receiveTime) {
|
||||
auto it = _sentPacketTimes.find(ack);
|
||||
|
||||
auto previousAck = _lastACK;
|
||||
_lastACK = ack;
|
||||
|
||||
if (it != _sentPacketTimes.end()) {
|
||||
bool wasDuplicateACK = (ack == previousAck);
|
||||
|
||||
// calculate the RTT (receive time - time ACK sent)
|
||||
int lastRTT = duration_cast<microseconds>(receiveTime - it->second).count();
|
||||
auto it = std::find_if(_sentPacketDatas.begin(), _sentPacketDatas.end(), [ack](SentPacketData& packetTime){
|
||||
return packetTime.sequenceNumber == ack;
|
||||
});
|
||||
|
||||
const int MAX_RTT_SAMPLE_MICROSECONDS = 10000000;
|
||||
if (!wasDuplicateACK && it != _sentPacketDatas.end()) {
|
||||
// check if we can unambigiously calculate an RTT from this ACK
|
||||
|
||||
if (lastRTT < 0) {
|
||||
Q_ASSERT_X(false, __FUNCTION__, "calculated an RTT that is not > 0");
|
||||
// for that to be the case,
|
||||
// any of the packets this ACK covers (from the current ACK back to our previous ACK)
|
||||
// must not have been re-sent
|
||||
bool canBeUsedForRTT = std::none_of(_sentPacketDatas.begin(), _sentPacketDatas.end(),
|
||||
[ack, previousAck](SentPacketData& sentPacketData)
|
||||
{
|
||||
return sentPacketData.sequenceNumber > previousAck
|
||||
&& sentPacketData.sequenceNumber <= ack
|
||||
&& sentPacketData.wasResent;
|
||||
});
|
||||
|
||||
auto sendTime = it->timePoint;
|
||||
|
||||
// remove all sent packet times up to this sequence number
|
||||
it = _sentPacketDatas.erase(_sentPacketDatas.begin(), it + 1);
|
||||
|
||||
// if we can use this ACK for an RTT calculation then do so
|
||||
// returning false if we calculate an invalid RTT
|
||||
if (canBeUsedForRTT && !calculateRTT(sendTime, receiveTime)) {
|
||||
return false;
|
||||
} else if (lastRTT == 0) {
|
||||
// we do not allow a zero microsecond RTT (as per the UNIX kernel implementation of TCP Vegas)
|
||||
lastRTT = 1;
|
||||
} else if (lastRTT > MAX_RTT_SAMPLE_MICROSECONDS) {
|
||||
// we cap the lastRTT to MAX_RTT_SAMPLE_MICROSECONDS to avoid overflows in window size calculations
|
||||
lastRTT = MAX_RTT_SAMPLE_MICROSECONDS;
|
||||
}
|
||||
}
|
||||
|
||||
if (_ewmaRTT == -1) {
|
||||
// first RTT sample - set _ewmaRTT to the value and set the variance to half the value
|
||||
_ewmaRTT = lastRTT;
|
||||
_rttVariance = lastRTT / 2;
|
||||
} else {
|
||||
// This updates the RTT using exponential weighted moving average
|
||||
// This is the Jacobson's forumla for RTT estimation
|
||||
// http://www.mathcs.emory.edu/~cheung/Courses/455/Syllabus/7-transport/Jacobson-88.pdf
|
||||
|
||||
// Estimated RTT = (1 - x)(estimatedRTT) + (x)(sampleRTT)
|
||||
// (where x = 0.125 via Jacobson)
|
||||
|
||||
// Deviation = (1 - x)(deviation) + x |sampleRTT - estimatedRTT|
|
||||
// (where x = 0.25 via Jacobson)
|
||||
|
||||
static const int RTT_ESTIMATION_ALPHA = 8;
|
||||
static const int RTT_ESTIMATION_VARIANCE_ALPHA = 4;
|
||||
|
||||
_ewmaRTT = (_ewmaRTT * (RTT_ESTIMATION_ALPHA - 1) + lastRTT) / RTT_ESTIMATION_ALPHA;
|
||||
_rttVariance = (_rttVariance * (RTT_ESTIMATION_VARIANCE_ALPHA- 1)
|
||||
+ abs(lastRTT - _ewmaRTT)) / RTT_ESTIMATION_VARIANCE_ALPHA;
|
||||
}
|
||||
|
||||
// add 1 to the number of ACKs during this RTT
|
||||
++_numACKs;
|
||||
|
||||
// keep track of the lowest RTT during connection
|
||||
_baseRTT = std::min(_baseRTT, lastRTT);
|
||||
|
||||
// find the min RTT during the last RTT
|
||||
_currentMinRTT = std::min(_currentMinRTT, lastRTT);
|
||||
|
||||
auto sinceLastAdjustment = duration_cast<microseconds>(p_high_resolution_clock::now() - _lastAdjustmentTime).count();
|
||||
if (sinceLastAdjustment >= _ewmaRTT) {
|
||||
performCongestionAvoidance(ack);
|
||||
}
|
||||
|
||||
// remove this sent packet time from the hash
|
||||
_sentPacketTimes.erase(it);
|
||||
auto sinceLastAdjustment = duration_cast<microseconds>(p_high_resolution_clock::now() - _lastAdjustmentTime).count();
|
||||
if (sinceLastAdjustment >= _ewmaRTT) {
|
||||
performCongestionAvoidance(ack);
|
||||
}
|
||||
|
||||
++_numACKSinceFastRetransmit;
|
||||
|
||||
// perform the fast re-transmit check if this is a duplicate ACK or if this is the first or second ACK
|
||||
// after a previous fast re-transmit
|
||||
if (ack == previousAck || _numACKSinceFastRetransmit < 3) {
|
||||
// we may need to re-send ackNum + 1 if it has been more than our estimated timeout since it was sent
|
||||
|
||||
auto it = _sentPacketTimes.find(ack + 1);
|
||||
if (it != _sentPacketTimes.end()) {
|
||||
|
||||
auto now = p_high_resolution_clock::now();
|
||||
auto sinceSend = duration_cast<microseconds>(now - it->second).count();
|
||||
|
||||
if (sinceSend >= estimatedTimeout()) {
|
||||
// break out of slow start, we've decided this is loss
|
||||
_slowStart = false;
|
||||
|
||||
// reset the fast re-transmit counter
|
||||
_numACKSinceFastRetransmit = 0;
|
||||
|
||||
// return true so the caller knows we needed a fast re-transmit
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// if this is the 3rd duplicate ACK, we fallback to Reno's fast re-transmit
|
||||
static const int RENO_FAST_RETRANSMIT_DUPLICATE_COUNT = 3;
|
||||
|
||||
++_duplicateACKCount;
|
||||
|
||||
if (ack == previousAck && _duplicateACKCount == RENO_FAST_RETRANSMIT_DUPLICATE_COUNT) {
|
||||
// break out of slow start, we just hit loss
|
||||
_slowStart = false;
|
||||
|
||||
// reset our fast re-transmit counters
|
||||
_numACKSinceFastRetransmit = 0;
|
||||
_duplicateACKCount = 0;
|
||||
|
||||
// return true so the caller knows we needed a fast re-transmit
|
||||
return true;
|
||||
}
|
||||
if (wasDuplicateACK || _numACKSinceFastRetransmit < 3) {
|
||||
return needsFastRetransmit(ack, wasDuplicateACK);
|
||||
} else {
|
||||
_duplicateACKCount = 0;
|
||||
}
|
||||
|
@ -141,6 +135,49 @@ bool TCPVegasCC::onACK(SequenceNumber ack, p_high_resolution_clock::time_point r
|
|||
return false;
|
||||
}
|
||||
|
||||
bool TCPVegasCC::needsFastRetransmit(SequenceNumber ack, bool wasDuplicateACK) {
|
||||
// we may need to re-send ackNum + 1 if it has been more than our estimated timeout since it was sent
|
||||
|
||||
auto nextIt = std::find_if(_sentPacketDatas.begin(), _sentPacketDatas.end(), [ack](SentPacketData& packetTime){
|
||||
return packetTime.sequenceNumber == ack + 1;
|
||||
});
|
||||
|
||||
if (nextIt != _sentPacketDatas.end()) {
|
||||
auto now = p_high_resolution_clock::now();
|
||||
auto sinceSend = duration_cast<microseconds>(now - nextIt->timePoint).count();
|
||||
|
||||
if (sinceSend >= estimatedTimeout()) {
|
||||
// break out of slow start, we've decided this is loss
|
||||
_slowStart = false;
|
||||
|
||||
// reset the fast re-transmit counter
|
||||
_numACKSinceFastRetransmit = 0;
|
||||
|
||||
// return true so the caller knows we needed a fast re-transmit
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// if this is the 3rd duplicate ACK, we fallback to Reno's fast re-transmit
|
||||
static const int RENO_FAST_RETRANSMIT_DUPLICATE_COUNT = 3;
|
||||
|
||||
++_duplicateACKCount;
|
||||
|
||||
if (wasDuplicateACK && _duplicateACKCount == RENO_FAST_RETRANSMIT_DUPLICATE_COUNT) {
|
||||
// break out of slow start, we just hit loss
|
||||
_slowStart = false;
|
||||
|
||||
// reset our fast re-transmit counters
|
||||
_numACKSinceFastRetransmit = 0;
|
||||
_duplicateACKCount = 0;
|
||||
|
||||
// return true so the caller knows we needed a fast re-transmit
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TCPVegasCC::performCongestionAvoidance(udt::SequenceNumber ack) {
|
||||
static int VEGAS_ALPHA_SEGMENTS = 4;
|
||||
static int VEGAS_BETA_SEGMENTS = 6;
|
||||
|
@ -158,7 +195,7 @@ void TCPVegasCC::performCongestionAvoidance(udt::SequenceNumber ack) {
|
|||
|
||||
int64_t windowSizeDiff = (int64_t) _congestionWindowSize * (rtt - _baseRTT) / _baseRTT;
|
||||
|
||||
if (_numACKs <= 2) {
|
||||
if (_numRTTs <= 2) {
|
||||
performRenoCongestionAvoidance(ack);
|
||||
} else {
|
||||
if (_slowStart) {
|
||||
|
@ -209,7 +246,7 @@ void TCPVegasCC::performCongestionAvoidance(udt::SequenceNumber ack) {
|
|||
_currentMinRTT = std::numeric_limits<int>::max();
|
||||
|
||||
// reset our count of collected RTT samples
|
||||
_numACKs = 0;
|
||||
_numRTTs = 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -230,29 +267,29 @@ void TCPVegasCC::performRenoCongestionAvoidance(SequenceNumber ack) {
|
|||
return;
|
||||
}
|
||||
|
||||
int numAcked = _numACKs;
|
||||
int numRTTCollected = _numRTTs;
|
||||
|
||||
if (_slowStart) {
|
||||
// while in slow start we grow the congestion window by the number of ACKed packets
|
||||
// allowing it to grow as high as the slow start threshold
|
||||
int congestionWindow = _congestionWindowSize + numAcked;
|
||||
int congestionWindow = _congestionWindowSize + numRTTCollected;
|
||||
|
||||
if (congestionWindow > udt::MAX_PACKETS_IN_FLIGHT) {
|
||||
// we're done with slow start, set the congestion window to the slow start threshold
|
||||
_congestionWindowSize = udt::MAX_PACKETS_IN_FLIGHT;
|
||||
|
||||
// figure out how many left over ACKs we should apply using the regular reno congestion avoidance
|
||||
numAcked = congestionWindow - udt::MAX_PACKETS_IN_FLIGHT;
|
||||
numRTTCollected = congestionWindow - udt::MAX_PACKETS_IN_FLIGHT;
|
||||
} else {
|
||||
_congestionWindowSize = congestionWindow;
|
||||
numAcked = 0;
|
||||
numRTTCollected = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// grab the size of the window prior to reno additive increase
|
||||
int preAIWindowSize = _congestionWindowSize;
|
||||
|
||||
if (numAcked > 0) {
|
||||
if (numRTTCollected > 0) {
|
||||
// Once we are out of slow start, we use additive increase to grow the window slowly.
|
||||
// We grow the congestion window by a single packet everytime the entire congestion window is sent.
|
||||
|
||||
|
@ -263,7 +300,7 @@ void TCPVegasCC::performRenoCongestionAvoidance(SequenceNumber ack) {
|
|||
}
|
||||
|
||||
// increase the window size by (1 / window size) for every ACK received
|
||||
_ackAICount += numAcked;
|
||||
_ackAICount += numRTTCollected;
|
||||
if (_ackAICount >= preAIWindowSize) {
|
||||
// when _ackAICount % preAIWindowSize == 0 then _ackAICount is 0
|
||||
// when _ackAICount % preAIWindowSize != 0 then _ackAICount is _ackAICount - (_ackAICount % preAIWindowSize)
|
||||
|
@ -277,8 +314,19 @@ void TCPVegasCC::performRenoCongestionAvoidance(SequenceNumber ack) {
|
|||
}
|
||||
|
||||
void TCPVegasCC::onPacketSent(int wireSize, SequenceNumber seqNum, p_high_resolution_clock::time_point timePoint) {
|
||||
if (_sentPacketTimes.find(seqNum) == _sentPacketTimes.end()) {
|
||||
_sentPacketTimes[seqNum] = timePoint;
|
||||
_sentPacketDatas.emplace_back(seqNum, timePoint);
|
||||
}
|
||||
|
||||
void TCPVegasCC::onPacketReSent(int wireSize, SequenceNumber seqNum, p_high_resolution_clock::time_point timePoint) {
|
||||
// look for our information for this sent packet
|
||||
auto it = std::find_if(_sentPacketDatas.begin(), _sentPacketDatas.end(), [seqNum](SentPacketData& sentPacketInfo){
|
||||
return sentPacketInfo.sequenceNumber == seqNum;
|
||||
});
|
||||
|
||||
// if we found information for this packet (it hasn't been erased because it hasn't yet been ACKed)
|
||||
// then mark it as re-sent so we know it cannot be used for RTT calculations
|
||||
if (it != _sentPacketDatas.end()) {
|
||||
it->wasResent = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ public:
|
|||
virtual void onTimeout() override {};
|
||||
|
||||
virtual void onPacketSent(int wireSize, SequenceNumber seqNum, p_high_resolution_clock::time_point timePoint) override;
|
||||
virtual void onPacketReSent(int wireSize, SequenceNumber seqNum, p_high_resolution_clock::time_point timePoint) override;
|
||||
|
||||
virtual int estimatedTimeout() const override;
|
||||
|
||||
|
@ -37,11 +38,23 @@ protected:
|
|||
virtual void performCongestionAvoidance(SequenceNumber ack);
|
||||
virtual void setInitialSendSequenceNumber(SequenceNumber seqNum) override { _lastACK = seqNum - 1; }
|
||||
private:
|
||||
bool calculateRTT(p_high_resolution_clock::time_point sendTime, p_high_resolution_clock::time_point receiveTime);
|
||||
bool needsFastRetransmit(SequenceNumber ack, bool wasDuplicateACK);
|
||||
|
||||
bool isCongestionWindowLimited();
|
||||
void performRenoCongestionAvoidance(SequenceNumber ack);
|
||||
|
||||
using PacketTimeList = std::map<SequenceNumber, p_high_resolution_clock::time_point>;
|
||||
PacketTimeList _sentPacketTimes; // Map of sequence numbers to sent time
|
||||
struct SentPacketData {
|
||||
SentPacketData(SequenceNumber seqNum, p_high_resolution_clock::time_point tPoint)
|
||||
: sequenceNumber(seqNum), timePoint(tPoint) {};
|
||||
|
||||
SequenceNumber sequenceNumber;
|
||||
p_high_resolution_clock::time_point timePoint;
|
||||
bool wasResent { false };
|
||||
};
|
||||
|
||||
using PacketTimeList = std::vector<SentPacketData>;
|
||||
PacketTimeList _sentPacketDatas; // association of sequence numbers to sent time, for RTT calc
|
||||
|
||||
p_high_resolution_clock::time_point _lastAdjustmentTime; // Time of last congestion control adjustment
|
||||
|
||||
|
@ -56,7 +69,7 @@ private:
|
|||
int _ewmaRTT { -1 }; // Exponential weighted moving average RTT
|
||||
int _rttVariance { 0 }; // Variance in collected RTT values
|
||||
|
||||
int _numACKs { 0 }; // Number of ACKs received during the last RTT (since last performed congestion avoidance)
|
||||
int _numRTTs { 0 }; // Number of RTTs calculated during the last RTT (since last performed congestion avoidance)
|
||||
|
||||
int _ackAICount { 0 }; // Counter for number of ACKs received for Reno additive increase
|
||||
int _duplicateACKCount { 0 }; // Counter for duplicate ACKs received
|
||||
|
|
|
@ -32,8 +32,8 @@ bool CauterizedModel::updateGeometry() {
|
|||
bool needsFullUpdate = Model::updateGeometry();
|
||||
if (_isCauterized && needsFullUpdate) {
|
||||
assert(_cauterizeMeshStates.empty());
|
||||
const FBXGeometry& fbxGeometry = getFBXGeometry();
|
||||
foreach (const FBXMesh& mesh, fbxGeometry.meshes) {
|
||||
const HFMGeometry& hfmGeometry = getHFMGeometry();
|
||||
foreach (const HFMMesh& mesh, hfmGeometry.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 FBXGeometry& fbxGeometry = getFBXGeometry();
|
||||
const HFMGeometry& hfmGeometry = getHFMGeometry();
|
||||
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(fbxGeometry.meshes[i], i);
|
||||
initializeBlendshapes(hfmGeometry.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,13 +109,13 @@ void CauterizedModel::updateClusterMatrices() {
|
|||
return;
|
||||
}
|
||||
_needsUpdateClusterMatrices = false;
|
||||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
|
||||
for (int i = 0; i < (int)_meshStates.size(); i++) {
|
||||
Model::MeshState& state = _meshStates[i];
|
||||
const FBXMesh& mesh = geometry.meshes.at(i);
|
||||
const HFMMesh& mesh = geometry.meshes.at(i);
|
||||
for (int j = 0; j < mesh.clusters.size(); j++) {
|
||||
const FBXCluster& cluster = mesh.clusters.at(j);
|
||||
const HFMCluster& cluster = mesh.clusters.at(j);
|
||||
if (_useDualQuaternionSkinning) {
|
||||
auto jointPose = _rig.getJointPose(cluster.jointIndex);
|
||||
Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans());
|
||||
|
@ -145,10 +145,10 @@ void CauterizedModel::updateClusterMatrices() {
|
|||
|
||||
for (int i = 0; i < _cauterizeMeshStates.size(); i++) {
|
||||
Model::MeshState& state = _cauterizeMeshStates[i];
|
||||
const FBXMesh& mesh = geometry.meshes.at(i);
|
||||
const HFMMesh& mesh = geometry.meshes.at(i);
|
||||
|
||||
for (int j = 0; j < mesh.clusters.size(); j++) {
|
||||
const FBXCluster& cluster = mesh.clusters.at(j);
|
||||
const HFMCluster& cluster = mesh.clusters.at(j);
|
||||
|
||||
if (_useDualQuaternionSkinning) {
|
||||
if (_cauterizeBoneSet.find(cluster.jointIndex) == _cauterizeBoneSet.end()) {
|
||||
|
|
|
@ -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 FBXGeometry& geometry = model->getFBXGeometry();
|
||||
const FBXMesh& mesh = geometry.meshes.at(_meshIndex);
|
||||
const HFMGeometry& geometry = model->getHFMGeometry();
|
||||
const HFMMesh& mesh = geometry.meshes.at(_meshIndex);
|
||||
|
||||
_isBlendShaped = !mesh.blendshapes.isEmpty();
|
||||
_hasTangents = !mesh.tangents.isEmpty();
|
||||
|
|
|
@ -183,7 +183,7 @@ bool Model::shouldInvalidatePayloadShapeKey(int meshIndex) {
|
|||
return true;
|
||||
}
|
||||
|
||||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
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.
|
||||
|
@ -278,7 +278,7 @@ void Model::setRenderItemsNeedUpdate() {
|
|||
|
||||
void Model::reset() {
|
||||
if (isLoaded()) {
|
||||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
_rig.reset(geometry);
|
||||
emit rigReset();
|
||||
emit rigReady();
|
||||
|
@ -295,13 +295,13 @@ bool Model::updateGeometry() {
|
|||
_needsReload = false;
|
||||
|
||||
// TODO: should all Models have a valid _rig?
|
||||
if (_rig.jointStatesEmpty() && getFBXGeometry().joints.size() > 0) {
|
||||
if (_rig.jointStatesEmpty() && getHFMGeometry().joints.size() > 0) {
|
||||
initJointStates();
|
||||
assert(_meshStates.empty());
|
||||
|
||||
const FBXGeometry& fbxGeometry = getFBXGeometry();
|
||||
const HFMGeometry& hfmGeometry = getHFMGeometry();
|
||||
int i = 0;
|
||||
foreach (const FBXMesh& mesh, fbxGeometry.meshes) {
|
||||
foreach (const HFMMesh& mesh, hfmGeometry.meshes) {
|
||||
MeshState state;
|
||||
state.clusterDualQuaternions.resize(mesh.clusters.size());
|
||||
state.clusterMatrices.resize(mesh.clusters.size());
|
||||
|
@ -319,7 +319,7 @@ bool Model::updateGeometry() {
|
|||
|
||||
// virtual
|
||||
void Model::initJointStates() {
|
||||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset);
|
||||
|
||||
_rig.initJointStates(geometry, modelOffset);
|
||||
|
@ -363,7 +363,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
|
|||
int bestShapeID = 0;
|
||||
int bestSubMeshIndex = 0;
|
||||
|
||||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
if (!_triangleSetsValid) {
|
||||
calculateTriangleSets(geometry);
|
||||
}
|
||||
|
@ -506,7 +506,7 @@ bool Model::findParabolaIntersectionAgainstSubMeshes(const glm::vec3& origin, co
|
|||
int bestShapeID = 0;
|
||||
int bestSubMeshIndex = 0;
|
||||
|
||||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
if (!_triangleSetsValid) {
|
||||
calculateTriangleSets(geometry);
|
||||
}
|
||||
|
@ -641,7 +641,7 @@ bool Model::convexHullContains(glm::vec3 point) {
|
|||
QMutexLocker locker(&_mutex);
|
||||
|
||||
if (!_triangleSetsValid) {
|
||||
calculateTriangleSets(getFBXGeometry());
|
||||
calculateTriangleSets(getHFMGeometry());
|
||||
}
|
||||
|
||||
// If we are inside the models box, then consider the submeshes...
|
||||
|
@ -753,14 +753,14 @@ bool Model::replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointe
|
|||
}
|
||||
// update triangles for picking
|
||||
{
|
||||
FBXGeometry geometry;
|
||||
HFMGeometry geometry;
|
||||
for (const auto& newMesh : meshes) {
|
||||
FBXMesh mesh;
|
||||
HFMMesh mesh;
|
||||
mesh._mesh = newMesh.getMeshPointer();
|
||||
mesh.vertices = buffer_helpers::mesh::attributeToVector<glm::vec3>(mesh._mesh, gpu::Stream::POSITION);
|
||||
int numParts = (int)newMesh.getMeshPointer()->getNumParts();
|
||||
for (int partID = 0; partID < numParts; partID++) {
|
||||
FBXMeshPart part;
|
||||
HFMMeshPart part;
|
||||
part.triangleIndices = buffer_helpers::bufferToVector<int>(mesh._mesh->getIndexBuffer(), "part.triangleIndices");
|
||||
mesh.parts << part;
|
||||
}
|
||||
|
@ -789,12 +789,12 @@ scriptable::ScriptableModelBase Model::getScriptableModel() {
|
|||
return result;
|
||||
}
|
||||
|
||||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
int numberOfMeshes = geometry.meshes.size();
|
||||
int shapeID = 0;
|
||||
for (int i = 0; i < numberOfMeshes; i++) {
|
||||
const FBXMesh& fbxMesh = geometry.meshes.at(i);
|
||||
if (auto mesh = fbxMesh._mesh) {
|
||||
const HFMMesh& hfmMesh = geometry.meshes.at(i);
|
||||
if (auto mesh = hfmMesh._mesh) {
|
||||
result.append(mesh);
|
||||
|
||||
int numParts = (int)mesh->getNumParts();
|
||||
|
@ -808,7 +808,7 @@ scriptable::ScriptableModelBase Model::getScriptableModel() {
|
|||
return result;
|
||||
}
|
||||
|
||||
void Model::calculateTriangleSets(const FBXGeometry& geometry) {
|
||||
void Model::calculateTriangleSets(const HFMGeometry& geometry) {
|
||||
PROFILE_RANGE(render, __FUNCTION__);
|
||||
|
||||
int numberOfMeshes = geometry.meshes.size();
|
||||
|
@ -818,14 +818,14 @@ void Model::calculateTriangleSets(const FBXGeometry& geometry) {
|
|||
_modelSpaceMeshTriangleSets.resize(numberOfMeshes);
|
||||
|
||||
for (int i = 0; i < numberOfMeshes; i++) {
|
||||
const FBXMesh& mesh = geometry.meshes.at(i);
|
||||
const HFMMesh& mesh = geometry.meshes.at(i);
|
||||
|
||||
const int numberOfParts = mesh.parts.size();
|
||||
auto& meshTriangleSets = _modelSpaceMeshTriangleSets[i];
|
||||
meshTriangleSets.resize(numberOfParts);
|
||||
|
||||
for (int j = 0; j < numberOfParts; j++) {
|
||||
const FBXMeshPart& part = mesh.parts.at(j);
|
||||
const HFMMeshPart& part = mesh.parts.at(j);
|
||||
|
||||
auto& partTriangleSet = meshTriangleSets[j];
|
||||
|
||||
|
@ -1114,7 +1114,7 @@ Extents Model::getBindExtents() const {
|
|||
if (!isActive()) {
|
||||
return Extents();
|
||||
}
|
||||
const Extents& bindExtents = getFBXGeometry().bindExtents;
|
||||
const Extents& bindExtents = getHFMGeometry().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 = getFBXGeometry().meshExtents;
|
||||
const Extents& extents = getHFMGeometry().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(getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f));
|
||||
glm::vec3 maximum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f));
|
||||
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));
|
||||
Extents scaledExtents = { minimum * _scale, maximum * _scale };
|
||||
return scaledExtents;
|
||||
}
|
||||
|
@ -1143,12 +1143,12 @@ Extents Model::getUnscaledMeshExtents() const {
|
|||
return Extents();
|
||||
}
|
||||
|
||||
const Extents& extents = getFBXGeometry().meshExtents;
|
||||
const Extents& extents = getHFMGeometry().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(getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f));
|
||||
glm::vec3 maximum = glm::vec3(getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f));
|
||||
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));
|
||||
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) ? getFBXGeometry().joints.at(jointIndex).parentIndex : -1;
|
||||
return (isActive() && jointIndex != -1) ? getHFMGeometry().joints.at(jointIndex).parentIndex : -1;
|
||||
}
|
||||
|
||||
int Model::getLastFreeJointIndex(int jointIndex) const {
|
||||
return (isActive() && jointIndex != -1) ? getFBXGeometry().joints.at(jointIndex).freeLineage.last() : -1;
|
||||
return (isActive() && jointIndex != -1) ? getHFMGeometry().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() ? getFBXGeometry().getJointNames() : QStringList();
|
||||
return isActive() ? getHFMGeometry().getJointNames() : QStringList();
|
||||
}
|
||||
|
||||
void Model::setScaleToFit(bool scaleToFit, const glm::vec3& dimensions, bool forceRescale) {
|
||||
|
@ -1415,12 +1415,12 @@ void Model::updateClusterMatrices() {
|
|||
}
|
||||
|
||||
_needsUpdateClusterMatrices = false;
|
||||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
for (int i = 0; i < (int) _meshStates.size(); i++) {
|
||||
MeshState& state = _meshStates[i];
|
||||
const FBXMesh& mesh = geometry.meshes.at(i);
|
||||
const HFMMesh& mesh = geometry.meshes.at(i);
|
||||
for (int j = 0; j < mesh.clusters.size(); j++) {
|
||||
const FBXCluster& cluster = mesh.clusters.at(j);
|
||||
const HFMCluster& cluster = mesh.clusters.at(j);
|
||||
if (_useDualQuaternionSkinning) {
|
||||
auto jointPose = _rig.getJointPose(cluster.jointIndex);
|
||||
Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans());
|
||||
|
@ -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& fbxGeometry = getFBXGeometry();
|
||||
auto& hfmGeometry = getHFMGeometry();
|
||||
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(fbxGeometry.meshes[i], i);
|
||||
initializeBlendshapes(hfmGeometry.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) {
|
||||
_fbxGeometry = std::make_shared<FBXGeometry>();
|
||||
_hfmGeometry = std::make_shared<HFMGeometry>();
|
||||
std::shared_ptr<GeometryMeshes> meshes = std::make_shared<GeometryMeshes>();
|
||||
meshes->push_back(mesh);
|
||||
_meshes = meshes;
|
||||
|
@ -1656,9 +1656,9 @@ 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->getFBXGeometry().meshes;
|
||||
auto meshes = _model->getHFMGeometry().meshes;
|
||||
int meshIndex = 0;
|
||||
foreach(const FBXMesh& mesh, meshes) {
|
||||
foreach(const HFMMesh& mesh, meshes) {
|
||||
auto modelMeshBlendshapeOffsets = _model->_blendshapeOffsets.find(meshIndex++);
|
||||
if (mesh.blendshapes.isEmpty() || modelMeshBlendshapeOffsets == _model->_blendshapeOffsets.end()) {
|
||||
// Not blendshaped or not initialized
|
||||
|
@ -1688,7 +1688,7 @@ void Blender::run() {
|
|||
}
|
||||
|
||||
float normalCoefficient = vertexCoefficient * NORMAL_COEFFICIENT_SCALE;
|
||||
const FBXBlendshape& blendshape = mesh.blendshapes.at(i);
|
||||
const HFMBlendshape& blendshape = mesh.blendshapes.at(i);
|
||||
|
||||
tbb::parallel_for(tbb::blocked_range<int>(0, blendshape.indices.size()), [&](const tbb::blocked_range<int>& range) {
|
||||
for (auto j = range.begin(); j < range.end(); j++) {
|
||||
|
@ -1731,7 +1731,7 @@ bool Model::maybeStartBlender() {
|
|||
return false;
|
||||
}
|
||||
|
||||
void Model::initializeBlendshapes(const FBXMesh& mesh, int index) {
|
||||
void Model::initializeBlendshapes(const HFMMesh& mesh, int index) {
|
||||
if (mesh.blendshapes.empty()) {
|
||||
// mesh doesn't have blendshape, did we allocate one though ?
|
||||
if (_blendshapeOffsets.find(index) != _blendshapeOffsets.end()) {
|
||||
|
|
|
@ -185,7 +185,7 @@ public:
|
|||
|
||||
/// Provided as a convenience, will crash if !isLoaded()
|
||||
// And so that getGeometry() isn't chained everywhere
|
||||
const FBXGeometry& getFBXGeometry() const { assert(isLoaded()); return _renderGeometry->getFBXGeometry(); }
|
||||
const HFMGeometry& getHFMGeometry() const { assert(isLoaded()); return _renderGeometry->getHFMGeometry(); }
|
||||
|
||||
bool isActive() const { return isLoaded(); }
|
||||
|
||||
|
@ -450,7 +450,7 @@ protected:
|
|||
|
||||
bool _overrideModelTransform { false };
|
||||
bool _triangleSetsValid { false };
|
||||
void calculateTriangleSets(const FBXGeometry& geometry);
|
||||
void calculateTriangleSets(const HFMGeometry& geometry);
|
||||
std::vector<std::vector<TriangleSet>> _modelSpaceMeshTriangleSets; // model space triangles for all sub meshes
|
||||
|
||||
virtual void createRenderItemSet();
|
||||
|
@ -506,7 +506,7 @@ protected:
|
|||
|
||||
bool shouldInvalidatePayloadShapeKey(int meshIndex);
|
||||
|
||||
void initializeBlendshapes(const FBXMesh& mesh, int index);
|
||||
void initializeBlendshapes(const HFMMesh& mesh, int index);
|
||||
|
||||
private:
|
||||
float _loadingPriority { 0.0f };
|
||||
|
|
|
@ -41,14 +41,14 @@ void SoftAttachmentModel::updateClusterMatrices() {
|
|||
|
||||
_needsUpdateClusterMatrices = false;
|
||||
|
||||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
const HFMGeometry& geometry = getHFMGeometry();
|
||||
|
||||
for (int i = 0; i < (int) _meshStates.size(); i++) {
|
||||
MeshState& state = _meshStates[i];
|
||||
const FBXMesh& mesh = geometry.meshes.at(i);
|
||||
const HFMMesh& mesh = geometry.meshes.at(i);
|
||||
|
||||
for (int j = 0; j < mesh.clusters.size(); j++) {
|
||||
const FBXCluster& cluster = mesh.clusters.at(j);
|
||||
const HFMCluster& cluster = mesh.clusters.at(j);
|
||||
|
||||
// TODO: cache these look-ups as an optimization
|
||||
int jointIndexOverride = getJointIndexOverride(cluster.jointIndex);
|
||||
|
|
|
@ -74,10 +74,12 @@ void SpatiallyNestable::setParentID(const QUuid& parentID) {
|
|||
}
|
||||
});
|
||||
|
||||
bool success = false;
|
||||
auto parent = getParentPointer(success);
|
||||
if (success && parent) {
|
||||
parent->updateQueryAACube();
|
||||
if (!_parentKnowsMe) {
|
||||
bool success = false;
|
||||
auto parent = getParentPointer(success);
|
||||
if (success && parent) {
|
||||
parent->updateQueryAACube();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|