mirror of
https://github.com/overte-org/overte.git
synced 2025-07-10 14:18:46 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into last-edited-by
This commit is contained in:
commit
899dec8b10
37 changed files with 630 additions and 217 deletions
|
@ -512,12 +512,19 @@ void AvatarMixer::domainSettingsRequestComplete() {
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
nodeList->addNodeTypeToInterestSet(NodeType::Agent);
|
nodeList->addNodeTypeToInterestSet(NodeType::Agent);
|
||||||
|
|
||||||
nodeList->linkedDataCreateCallback = [] (Node* node) {
|
|
||||||
node->setLinkedData(std::unique_ptr<AvatarMixerClientData> { new AvatarMixerClientData });
|
|
||||||
};
|
|
||||||
|
|
||||||
// parse the settings to pull out the values we need
|
// parse the settings to pull out the values we need
|
||||||
parseDomainServerSettings(nodeList->getDomainHandler().getSettingsObject());
|
parseDomainServerSettings(nodeList->getDomainHandler().getSettingsObject());
|
||||||
|
|
||||||
|
float domainMinimumScale = _domainMinimumScale;
|
||||||
|
float domainMaximumScale = _domainMaximumScale;
|
||||||
|
|
||||||
|
nodeList->linkedDataCreateCallback = [domainMinimumScale, domainMaximumScale] (Node* node) {
|
||||||
|
auto clientData = std::unique_ptr<AvatarMixerClientData> { new AvatarMixerClientData };
|
||||||
|
clientData->getAvatar().setDomainMinimumScale(domainMinimumScale);
|
||||||
|
clientData->getAvatar().setDomainMaximumScale(domainMaximumScale);
|
||||||
|
|
||||||
|
node->setLinkedData(std::move(clientData));
|
||||||
|
};
|
||||||
|
|
||||||
// start the broadcastThread
|
// start the broadcastThread
|
||||||
_broadcastThread.start();
|
_broadcastThread.start();
|
||||||
|
@ -549,4 +556,22 @@ void AvatarMixer::parseDomainServerSettings(const QJsonObject& domainSettings) {
|
||||||
|
|
||||||
_maxKbpsPerNode = nodeBandwidthValue.toDouble(DEFAULT_NODE_SEND_BANDWIDTH) * KILO_PER_MEGA;
|
_maxKbpsPerNode = nodeBandwidthValue.toDouble(DEFAULT_NODE_SEND_BANDWIDTH) * KILO_PER_MEGA;
|
||||||
qDebug() << "The maximum send bandwidth per node is" << _maxKbpsPerNode << "kbps.";
|
qDebug() << "The maximum send bandwidth per node is" << _maxKbpsPerNode << "kbps.";
|
||||||
|
|
||||||
|
const QString AVATARS_SETTINGS_KEY = "avatars";
|
||||||
|
|
||||||
|
static const QString MIN_SCALE_OPTION = "min_avatar_scale";
|
||||||
|
float settingMinScale = domainSettings[AVATARS_SETTINGS_KEY].toObject()[MIN_SCALE_OPTION].toDouble(MIN_AVATAR_SCALE);
|
||||||
|
_domainMinimumScale = glm::clamp(settingMinScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE);
|
||||||
|
|
||||||
|
static const QString MAX_SCALE_OPTION = "max_avatar_scale";
|
||||||
|
float settingMaxScale = domainSettings[AVATARS_SETTINGS_KEY].toObject()[MAX_SCALE_OPTION].toDouble(MAX_AVATAR_SCALE);
|
||||||
|
_domainMaximumScale = glm::clamp(settingMaxScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE);
|
||||||
|
|
||||||
|
// make sure that the domain owner didn't flip min and max
|
||||||
|
if (_domainMinimumScale > _domainMaximumScale) {
|
||||||
|
std::swap(_domainMinimumScale, _domainMaximumScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "This domain requires a minimum avatar scale of" << _domainMinimumScale
|
||||||
|
<< "and a maximum avatar scale of" << _domainMaximumScale;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,9 @@ private:
|
||||||
|
|
||||||
float _maxKbpsPerNode = 0.0f;
|
float _maxKbpsPerNode = 0.0f;
|
||||||
|
|
||||||
|
float _domainMinimumScale { MIN_AVATAR_SCALE };
|
||||||
|
float _domainMaximumScale { MAX_AVATAR_SCALE };
|
||||||
|
|
||||||
QTimer* _broadcastTimer = nullptr;
|
QTimer* _broadcastTimer = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#include <AvatarData.h>
|
#include <AvatarData.h>
|
||||||
#include <ScriptEngine.h>
|
#include <ScriptEngine.h>
|
||||||
|
|
||||||
class ScriptableAvatar : public AvatarData, public Dependency{
|
class ScriptableAvatar : public AvatarData, public Dependency {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -39,4 +39,4 @@ private:
|
||||||
std::shared_ptr<AnimSkeleton> _animSkeleton;
|
std::shared_ptr<AnimSkeleton> _animSkeleton;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_ScriptableAvatar_h
|
#endif // hifi_ScriptableAvatar_h
|
||||||
|
|
|
@ -866,6 +866,29 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "avatars",
|
||||||
|
"label": "Avatars",
|
||||||
|
"assignment-types": [1, 2],
|
||||||
|
"settings": [
|
||||||
|
{
|
||||||
|
"name": "min_avatar_scale",
|
||||||
|
"type": "double",
|
||||||
|
"label": "Minimum Avatar Scale",
|
||||||
|
"help": "Limits the scale of avatars in your domain. Must be at least 0.005.",
|
||||||
|
"placeholder": 0.25,
|
||||||
|
"default": 0.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "max_avatar_scale",
|
||||||
|
"type": "double",
|
||||||
|
"label": "Maximum Avatar Scale",
|
||||||
|
"help": "Limits the scale of avatars in your domain. Cannot be greater than 1000.",
|
||||||
|
"placeholder": 3.0,
|
||||||
|
"default": 3.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "audio_env",
|
"name": "audio_env",
|
||||||
"label": "Audio Environment",
|
"label": "Audio Environment",
|
||||||
|
|
|
@ -4,12 +4,12 @@
|
||||||
{ "from": "GamePad.LY", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Actions.TranslateZ" },
|
{ "from": "GamePad.LY", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Actions.TranslateZ" },
|
||||||
{ "from": "GamePad.LX", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Actions.TranslateX" },
|
{ "from": "GamePad.LX", "filters": { "type": "deadZone", "min": 0.05 }, "to": "Actions.TranslateX" },
|
||||||
|
|
||||||
{ "from": "GamePad.LT", "to": "Standard.LTClick",
|
{ "from": "GamePad.LT", "to": "Standard.LTClick",
|
||||||
"peek": true,
|
"peek": true,
|
||||||
"filters": [ { "type": "hysteresis", "min": 0.85, "max": 0.9 } ]
|
"filters": [ { "type": "hysteresis", "min": 0.85, "max": 0.9 } ]
|
||||||
},
|
},
|
||||||
{ "from": "GamePad.LT", "to": "Standard.LT" },
|
{ "from": "GamePad.LT", "to": "Standard.LT" },
|
||||||
{ "from": "GamePad.LB", "to": "Standard.LB" },
|
{ "from": "GamePad.LB", "to": "Standard.LB" },
|
||||||
{ "from": "GamePad.LS", "to": "Standard.LS" },
|
{ "from": "GamePad.LS", "to": "Standard.LS" },
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,34 +27,34 @@
|
||||||
|
|
||||||
{ "from": "GamePad.RX", "to": "Actions.Yaw" },
|
{ "from": "GamePad.RX", "to": "Actions.Yaw" },
|
||||||
|
|
||||||
{ "from": "GamePad.RY",
|
{ "from": "GamePad.RY",
|
||||||
"to": "Actions.VERTICAL_UP",
|
"to": "Actions.VERTICAL_UP",
|
||||||
"filters":
|
"filters":
|
||||||
[
|
[
|
||||||
{ "type": "deadZone", "min": 0.95 },
|
{ "type": "deadZone", "min": 0.95 },
|
||||||
"invert"
|
"invert"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
{ "from": "GamePad.RT", "to": "Standard.RTClick",
|
{ "from": "GamePad.RT", "to": "Standard.RTClick",
|
||||||
"peek": true,
|
"peek": true,
|
||||||
"filters": [ { "type": "hysteresis", "min": 0.85, "max": 0.9 } ]
|
"filters": [ { "type": "hysteresis", "min": 0.85, "max": 0.9 } ]
|
||||||
},
|
},
|
||||||
{ "from": "GamePad.RT", "to": "Standard.RT" },
|
{ "from": "GamePad.RT", "to": "Standard.RT" },
|
||||||
{ "from": "GamePad.RB", "to": "Standard.RB" },
|
{ "from": "GamePad.RB", "to": "Standard.RB" },
|
||||||
{ "from": "GamePad.RS", "to": "Standard.RS" },
|
{ "from": "GamePad.RS", "to": "Standard.RS" },
|
||||||
|
|
||||||
{ "from": "GamePad.Start", "to": "Actions.CycleCamera" },
|
{ "from": "GamePad.Start", "to": "Actions.CycleCamera" },
|
||||||
{ "from": "GamePad.Back", "to": "Actions.ContextMenu" },
|
{ "from": "GamePad.Back", "to": "Standard.Start" },
|
||||||
|
|
||||||
{ "from": "GamePad.DU", "to": "Standard.DU" },
|
{ "from": "GamePad.DU", "to": "Standard.DU" },
|
||||||
{ "from": "GamePad.DD", "to": "Standard.DD" },
|
{ "from": "GamePad.DD", "to": "Standard.DD" },
|
||||||
{ "from": "GamePad.DL", "to": "Standard.DL" },
|
{ "from": "GamePad.DL", "to": "Standard.DL" },
|
||||||
{ "from": "GamePad.DR", "to": "Standard.DR" },
|
{ "from": "GamePad.DR", "to": "Standard.DR" },
|
||||||
|
|
||||||
{ "from": [ "GamePad.Y" ], "to": "Standard.RightPrimaryThumb", "peek": true },
|
{ "from": [ "GamePad.Y" ], "to": "Standard.RightPrimaryThumb", "peek": true },
|
||||||
{ "from": "GamePad.A", "to": "Standard.A" },
|
{ "from": "GamePad.A", "to": "Standard.A" },
|
||||||
{ "from": "GamePad.B", "to": "Standard.B" },
|
{ "from": "GamePad.B", "to": "Standard.B" },
|
||||||
{ "from": "GamePad.X", "to": "Standard.X" },
|
{ "from": "GamePad.X", "to": "Standard.X" },
|
||||||
{ "from": "GamePad.Y", "to": "Standard.Y" }
|
{ "from": "GamePad.Y", "to": "Standard.Y" }
|
||||||
]
|
]
|
||||||
|
|
|
@ -396,15 +396,6 @@ Menu::Menu() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Developer > Render > Enable Incremental Texture Transfer
|
|
||||||
{
|
|
||||||
auto action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::IncrementalTextureTransfer, 0, gpu::Texture::getEnableIncrementalTextureTransfers());
|
|
||||||
connect(action, &QAction::triggered, [&](bool checked) {
|
|
||||||
qDebug() << "[TEXTURE TRANSFER SUPPORT] --- Enable Incremental Texture Transfer menu option:" << checked;
|
|
||||||
gpu::Texture::setEnableIncrementalTextureTransfers(checked);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
qDebug() << "[TEXTURE TRANSFER SUPPORT] Incremental Texture Transfer and Dynamic Texture Management not supported on this platform.";
|
qDebug() << "[TEXTURE TRANSFER SUPPORT] Incremental Texture Transfer and Dynamic Texture Management not supported on this platform.";
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -112,7 +112,6 @@ namespace MenuOption {
|
||||||
const QString FrameTimer = "Show Timer";
|
const QString FrameTimer = "Show Timer";
|
||||||
const QString FullscreenMirror = "Mirror";
|
const QString FullscreenMirror = "Mirror";
|
||||||
const QString Help = "Help...";
|
const QString Help = "Help...";
|
||||||
const QString IncrementalTextureTransfer = "Enable Incremental Texture Transfer";
|
|
||||||
const QString IncreaseAvatarSize = "Increase Avatar Size";
|
const QString IncreaseAvatarSize = "Increase Avatar Size";
|
||||||
const QString IndependentMode = "Independent Mode";
|
const QString IndependentMode = "Independent Mode";
|
||||||
const QString ActionMotorControl = "Enable Default Motor Control";
|
const QString ActionMotorControl = "Enable Default Motor Control";
|
||||||
|
|
|
@ -165,16 +165,17 @@ AABox Avatar::getBounds() const {
|
||||||
|
|
||||||
void Avatar::animateScaleChanges(float deltaTime) {
|
void Avatar::animateScaleChanges(float deltaTime) {
|
||||||
float currentScale = getUniformScale();
|
float currentScale = getUniformScale();
|
||||||
if (currentScale != _targetScale) {
|
auto desiredScale = getDomainLimitedScale();
|
||||||
// use exponential decay toward _targetScale
|
if (currentScale != desiredScale) {
|
||||||
|
// use exponential decay toward the domain limit clamped scale
|
||||||
const float SCALE_ANIMATION_TIMESCALE = 0.5f;
|
const float SCALE_ANIMATION_TIMESCALE = 0.5f;
|
||||||
float blendFactor = glm::clamp(deltaTime / SCALE_ANIMATION_TIMESCALE, 0.0f, 1.0f);
|
float blendFactor = glm::clamp(deltaTime / SCALE_ANIMATION_TIMESCALE, 0.0f, 1.0f);
|
||||||
float animatedScale = (1.0f - blendFactor) * currentScale + blendFactor * _targetScale;
|
float animatedScale = (1.0f - blendFactor) * currentScale + blendFactor * desiredScale;
|
||||||
|
|
||||||
// snap to the end when we get close enough
|
// snap to the end when we get close enough
|
||||||
const float MIN_RELATIVE_SCALE_ERROR = 0.03f;
|
const float MIN_RELATIVE_SCALE_ERROR = 0.03f;
|
||||||
if (fabsf(_targetScale - currentScale) / _targetScale < MIN_RELATIVE_SCALE_ERROR) {
|
if (fabsf(desiredScale - currentScale) / desiredScale < MIN_RELATIVE_SCALE_ERROR) {
|
||||||
animatedScale = _targetScale;
|
animatedScale = desiredScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
setScale(glm::vec3(animatedScale)); // avatar scale is uniform
|
setScale(glm::vec3(animatedScale)); // avatar scale is uniform
|
||||||
|
|
|
@ -152,7 +152,7 @@ bool AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::
|
||||||
Transform avatarTransform;
|
Transform avatarTransform;
|
||||||
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||||
avatarTransform = myAvatar->getTransform();
|
avatarTransform = myAvatar->getTransform();
|
||||||
palmPosition = avatarTransform.transform(pose.getTranslation() / myAvatar->getTargetScale());
|
palmPosition = avatarTransform.transform(pose.getTranslation() / myAvatar->getDomainLimitedScale());
|
||||||
palmRotation = avatarTransform.getRotation() * pose.getRotation();
|
palmRotation = avatarTransform.getRotation() * pose.getRotation();
|
||||||
} else {
|
} else {
|
||||||
glm::vec3 avatarRigidBodyPosition;
|
glm::vec3 avatarRigidBodyPosition;
|
||||||
|
|
|
@ -130,6 +130,15 @@ MyAvatar::MyAvatar(RigPointer rig) :
|
||||||
connect(DependencyManager::get<AddressManager>().data(), &AddressManager::locationChangeRequired,
|
connect(DependencyManager::get<AddressManager>().data(), &AddressManager::locationChangeRequired,
|
||||||
this, static_cast<SlotType>(&MyAvatar::goToLocation));
|
this, static_cast<SlotType>(&MyAvatar::goToLocation));
|
||||||
|
|
||||||
|
// handle scale constraints imposed on us by the domain-server
|
||||||
|
auto& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler();
|
||||||
|
|
||||||
|
// when we connect to a domain and retrieve its settings, we restrict our max/min scale based on those settings
|
||||||
|
connect(&domainHandler, &DomainHandler::settingsReceived, this, &MyAvatar::restrictScaleFromDomainSettings);
|
||||||
|
|
||||||
|
// when we leave a domain we lift whatever restrictions that domain may have placed on our scale
|
||||||
|
connect(&domainHandler, &DomainHandler::disconnectedFromDomain, this, &MyAvatar::clearScaleRestriction);
|
||||||
|
|
||||||
_characterController.setEnabled(true);
|
_characterController.setEnabled(true);
|
||||||
|
|
||||||
_bodySensorMatrix = deriveBodyFromHMDSensor();
|
_bodySensorMatrix = deriveBodyFromHMDSensor();
|
||||||
|
@ -1823,25 +1832,104 @@ bool findAvatarAvatarPenetration(const glm::vec3 positionA, float radiusA, float
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::increaseSize() {
|
// There can be a separation between the _targetScale and the actual scale of the rendered avatar in a domain.
|
||||||
if ((1.0f + SCALING_RATIO) * _targetScale < MAX_AVATAR_SCALE) {
|
// When the avatar enters a domain where their target scale is not allowed according to the min/max
|
||||||
_targetScale *= (1.0f + SCALING_RATIO);
|
// we do not change their saved target scale. Instead, we use getDomainLimitedScale() to render the avatar
|
||||||
qCDebug(interfaceapp, "Changed scale to %f", (double)_targetScale);
|
// at a domain appropriate size. When the avatar leaves the limiting domain, we'll return them to their previous target scale.
|
||||||
|
// While connected to a domain that limits avatar scale if the user manually changes their avatar scale, we change
|
||||||
|
// target scale to match the new scale they have chosen. When they leave the domain they will not return to the scale they were
|
||||||
|
// before they entered the limiting domain.
|
||||||
|
|
||||||
|
void MyAvatar::clampTargetScaleToDomainLimits() {
|
||||||
|
// when we're about to change the target scale because the user has asked to increase or decrease their scale,
|
||||||
|
// we first make sure that we're starting from a target scale that is allowed by the current domain
|
||||||
|
|
||||||
|
auto clampedTargetScale = glm::clamp(_targetScale, _domainMinimumScale, _domainMaximumScale);
|
||||||
|
|
||||||
|
if (clampedTargetScale != _targetScale) {
|
||||||
|
qCDebug(interfaceapp, "Clamped scale to %f since original target scale %f was not allowed by domain",
|
||||||
|
clampedTargetScale, _targetScale);
|
||||||
|
|
||||||
|
setTargetScale(clampedTargetScale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MyAvatar::clampScaleChangeToDomainLimits(float desiredScale) {
|
||||||
|
auto clampedTargetScale = glm::clamp(desiredScale, _domainMinimumScale, _domainMaximumScale);
|
||||||
|
|
||||||
|
if (clampedTargetScale != desiredScale) {
|
||||||
|
qCDebug(interfaceapp, "Forcing scale to %f since %f is not allowed by domain",
|
||||||
|
clampedTargetScale, desiredScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTargetScale(clampedTargetScale);
|
||||||
|
qCDebug(interfaceapp, "Changed scale to %f", _targetScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyAvatar::increaseSize() {
|
||||||
|
// make sure we're starting from an allowable scale
|
||||||
|
clampTargetScaleToDomainLimits();
|
||||||
|
|
||||||
|
// calculate what our new scale should be
|
||||||
|
float updatedTargetScale = _targetScale * (1.0f + SCALING_RATIO);
|
||||||
|
|
||||||
|
// attempt to change to desired scale (clamped to the domain limits)
|
||||||
|
clampScaleChangeToDomainLimits(updatedTargetScale);
|
||||||
|
}
|
||||||
|
|
||||||
void MyAvatar::decreaseSize() {
|
void MyAvatar::decreaseSize() {
|
||||||
if (MIN_AVATAR_SCALE < (1.0f - SCALING_RATIO) * _targetScale) {
|
// make sure we're starting from an allowable scale
|
||||||
_targetScale *= (1.0f - SCALING_RATIO);
|
clampTargetScaleToDomainLimits();
|
||||||
qCDebug(interfaceapp, "Changed scale to %f", (double)_targetScale);
|
|
||||||
}
|
// calculate what our new scale should be
|
||||||
|
float updatedTargetScale = _targetScale * (1.0f - SCALING_RATIO);
|
||||||
|
|
||||||
|
// attempt to change to desired scale (clamped to the domain limits)
|
||||||
|
clampScaleChangeToDomainLimits(updatedTargetScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::resetSize() {
|
void MyAvatar::resetSize() {
|
||||||
_targetScale = 1.0f;
|
// attempt to reset avatar size to the default (clamped to domain limits)
|
||||||
qCDebug(interfaceapp, "Reset scale to %f", (double)_targetScale);
|
const float DEFAULT_AVATAR_SCALE = 1.0f;
|
||||||
|
|
||||||
|
clampScaleChangeToDomainLimits(DEFAULT_AVATAR_SCALE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MyAvatar::restrictScaleFromDomainSettings(const QJsonObject& domainSettingsObject) {
|
||||||
|
// pull out the minimum and maximum scale and set them to restrict our scale
|
||||||
|
|
||||||
|
static const QString AVATAR_SETTINGS_KEY = "avatars";
|
||||||
|
auto avatarsObject = domainSettingsObject[AVATAR_SETTINGS_KEY].toObject();
|
||||||
|
|
||||||
|
static const QString MIN_SCALE_OPTION = "min_avatar_scale";
|
||||||
|
float settingMinScale = avatarsObject[MIN_SCALE_OPTION].toDouble(MIN_AVATAR_SCALE);
|
||||||
|
setDomainMinimumScale(settingMinScale);
|
||||||
|
|
||||||
|
static const QString MAX_SCALE_OPTION = "max_avatar_scale";
|
||||||
|
float settingMaxScale = avatarsObject[MAX_SCALE_OPTION].toDouble(MAX_AVATAR_SCALE);
|
||||||
|
setDomainMaximumScale(settingMaxScale);
|
||||||
|
|
||||||
|
// make sure that the domain owner didn't flip min and max
|
||||||
|
if (_domainMinimumScale > _domainMaximumScale) {
|
||||||
|
std::swap(_domainMinimumScale, _domainMaximumScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
qCDebug(interfaceapp, "This domain requires a minimum avatar scale of %f and a maximum avatar scale of %f",
|
||||||
|
_domainMinimumScale, _domainMaximumScale);
|
||||||
|
|
||||||
|
// debug to log if this avatar's scale in this domain will be clamped
|
||||||
|
auto clampedScale = glm::clamp(_targetScale, _domainMinimumScale, _domainMaximumScale);
|
||||||
|
|
||||||
|
if (_targetScale != clampedScale) {
|
||||||
|
qCDebug(interfaceapp, "Avatar scale will be clamped to %f because %f is not allowed by current domain",
|
||||||
|
clampedScale, _targetScale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyAvatar::clearScaleRestriction() {
|
||||||
|
_domainMinimumScale = MIN_AVATAR_SCALE;
|
||||||
|
_domainMaximumScale = MAX_AVATAR_SCALE;
|
||||||
|
}
|
||||||
|
|
||||||
void MyAvatar::goToLocation(const QVariant& propertiesVar) {
|
void MyAvatar::goToLocation(const QVariant& propertiesVar) {
|
||||||
qCDebug(interfaceapp, "MyAvatar QML goToLocation");
|
qCDebug(interfaceapp, "MyAvatar QML goToLocation");
|
||||||
|
|
|
@ -292,6 +292,9 @@ public slots:
|
||||||
bool shouldFaceLocation = false);
|
bool shouldFaceLocation = false);
|
||||||
void goToLocation(const QVariant& properties);
|
void goToLocation(const QVariant& properties);
|
||||||
|
|
||||||
|
void restrictScaleFromDomainSettings(const QJsonObject& domainSettingsObject);
|
||||||
|
void clearScaleRestriction();
|
||||||
|
|
||||||
// Set/Get update the thrust that will move the avatar around
|
// Set/Get update the thrust that will move the avatar around
|
||||||
void addThrust(glm::vec3 newThrust) { _thrust += newThrust; };
|
void addThrust(glm::vec3 newThrust) { _thrust += newThrust; };
|
||||||
glm::vec3 getThrust() { return _thrust; };
|
glm::vec3 getThrust() { return _thrust; };
|
||||||
|
@ -369,6 +372,8 @@ private:
|
||||||
virtual void updatePalms() override {}
|
virtual void updatePalms() override {}
|
||||||
void lateUpdatePalms();
|
void lateUpdatePalms();
|
||||||
|
|
||||||
|
void clampTargetScaleToDomainLimits();
|
||||||
|
void clampScaleChangeToDomainLimits(float desiredScale);
|
||||||
|
|
||||||
float _driveKeys[MAX_DRIVE_KEYS];
|
float _driveKeys[MAX_DRIVE_KEYS];
|
||||||
bool _wasPushing;
|
bool _wasPushing;
|
||||||
|
|
|
@ -126,6 +126,23 @@ void MenuScriptingInterface::setIsOptionChecked(const QString& menuOption, bool
|
||||||
Q_ARG(bool, isChecked));
|
Q_ARG(bool, isChecked));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MenuScriptingInterface::isMenuEnabled(const QString& menuOption) {
|
||||||
|
if (QThread::currentThread() == qApp->thread()) {
|
||||||
|
return Menu::getInstance()->isOptionChecked(menuOption);
|
||||||
|
}
|
||||||
|
bool result;
|
||||||
|
QMetaObject::invokeMethod(Menu::getInstance(), "isMenuEnabled", Qt::BlockingQueuedConnection,
|
||||||
|
Q_RETURN_ARG(bool, result),
|
||||||
|
Q_ARG(const QString&, menuOption));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MenuScriptingInterface::setMenuEnabled(const QString& menuOption, bool isChecked) {
|
||||||
|
QMetaObject::invokeMethod(Menu::getInstance(), "setMenuEnabled",
|
||||||
|
Q_ARG(const QString&, menuOption),
|
||||||
|
Q_ARG(bool, isChecked));
|
||||||
|
}
|
||||||
|
|
||||||
void MenuScriptingInterface::triggerOption(const QString& menuOption) {
|
void MenuScriptingInterface::triggerOption(const QString& menuOption) {
|
||||||
QMetaObject::invokeMethod(Menu::getInstance(), "triggerOption", Q_ARG(const QString&, menuOption));
|
QMetaObject::invokeMethod(Menu::getInstance(), "triggerOption", Q_ARG(const QString&, menuOption));
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,9 @@ public slots:
|
||||||
void setIsOptionChecked(const QString& menuOption, bool isChecked);
|
void setIsOptionChecked(const QString& menuOption, bool isChecked);
|
||||||
|
|
||||||
void triggerOption(const QString& menuOption);
|
void triggerOption(const QString& menuOption);
|
||||||
|
|
||||||
|
bool isMenuEnabled(const QString& menuName);
|
||||||
|
void setMenuEnabled(const QString& menuName, bool isEnabled);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void menuItemEvent(const QString& menuItem);
|
void menuItemEvent(const QString& menuItem);
|
||||||
|
|
|
@ -308,6 +308,13 @@ void Rig::clearIKJointLimitHistory() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Rig::getJointParentIndex(int childIndex) const {
|
||||||
|
if (_animSkeleton && isIndexValid(childIndex)) {
|
||||||
|
return _animSkeleton->getParentIndex(childIndex);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
void Rig::setJointTranslation(int index, bool valid, const glm::vec3& translation, float priority) {
|
void Rig::setJointTranslation(int index, bool valid, const glm::vec3& translation, float priority) {
|
||||||
if (isIndexValid(index)) {
|
if (isIndexValid(index)) {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
|
@ -414,6 +421,16 @@ bool Rig::getAbsoluteJointTranslationInRigFrame(int jointIndex, glm::vec3& trans
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Rig::getAbsoluteJointPoseInRigFrame(int jointIndex, AnimPose& returnPose) const {
|
||||||
|
QReadLocker readLock(&_externalPoseSetLock);
|
||||||
|
if (jointIndex >= 0 && jointIndex < (int)_externalPoseSet._absolutePoses.size()) {
|
||||||
|
returnPose = _externalPoseSet._absolutePoses[jointIndex];
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Rig::getJointCombinedRotation(int jointIndex, glm::quat& result, const glm::quat& rotation) const {
|
bool Rig::getJointCombinedRotation(int jointIndex, glm::quat& result, const glm::quat& rotation) const {
|
||||||
// AJT: TODO: used by attachments
|
// AJT: TODO: used by attachments
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
|
|
|
@ -105,6 +105,8 @@ public:
|
||||||
|
|
||||||
void clearIKJointLimitHistory();
|
void clearIKJointLimitHistory();
|
||||||
|
|
||||||
|
int getJointParentIndex(int childIndex) const;
|
||||||
|
|
||||||
// geometry space
|
// geometry space
|
||||||
void setJointState(int index, bool valid, const glm::quat& rotation, const glm::vec3& translation, float priority);
|
void setJointState(int index, bool valid, const glm::quat& rotation, const glm::vec3& translation, float priority);
|
||||||
|
|
||||||
|
@ -133,6 +135,7 @@ public:
|
||||||
// rig space (thread-safe)
|
// rig space (thread-safe)
|
||||||
bool getAbsoluteJointRotationInRigFrame(int jointIndex, glm::quat& rotation) const;
|
bool getAbsoluteJointRotationInRigFrame(int jointIndex, glm::quat& rotation) const;
|
||||||
bool getAbsoluteJointTranslationInRigFrame(int jointIndex, glm::vec3& translation) const;
|
bool getAbsoluteJointTranslationInRigFrame(int jointIndex, glm::vec3& translation) const;
|
||||||
|
bool getAbsoluteJointPoseInRigFrame(int jointIndex, AnimPose& returnPose) const;
|
||||||
|
|
||||||
// legacy
|
// legacy
|
||||||
bool getJointCombinedRotation(int jointIndex, glm::quat& result, const glm::quat& rotation) const;
|
bool getJointCombinedRotation(int jointIndex, glm::quat& result, const glm::quat& rotation) const;
|
||||||
|
|
|
@ -210,7 +210,7 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) {
|
||||||
packFloatAngleToTwoByte((uint8_t*)(header->localOrientation + 0), bodyEulerAngles.y);
|
packFloatAngleToTwoByte((uint8_t*)(header->localOrientation + 0), bodyEulerAngles.y);
|
||||||
packFloatAngleToTwoByte((uint8_t*)(header->localOrientation + 1), bodyEulerAngles.x);
|
packFloatAngleToTwoByte((uint8_t*)(header->localOrientation + 1), bodyEulerAngles.x);
|
||||||
packFloatAngleToTwoByte((uint8_t*)(header->localOrientation + 2), bodyEulerAngles.z);
|
packFloatAngleToTwoByte((uint8_t*)(header->localOrientation + 2), bodyEulerAngles.z);
|
||||||
packFloatRatioToTwoByte((uint8_t*)(&header->scale), _targetScale);
|
packFloatRatioToTwoByte((uint8_t*)(&header->scale), getDomainLimitedScale());
|
||||||
header->lookAtPosition[0] = _headData->_lookAtPosition.x;
|
header->lookAtPosition[0] = _headData->_lookAtPosition.x;
|
||||||
header->lookAtPosition[1] = _headData->_lookAtPosition.y;
|
header->lookAtPosition[1] = _headData->_lookAtPosition.y;
|
||||||
header->lookAtPosition[2] = _headData->_lookAtPosition.z;
|
header->lookAtPosition[2] = _headData->_lookAtPosition.z;
|
||||||
|
@ -516,7 +516,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
||||||
}
|
}
|
||||||
return buffer.size();
|
return buffer.size();
|
||||||
}
|
}
|
||||||
_targetScale = std::max(MIN_AVATAR_SCALE, std::min(MAX_AVATAR_SCALE, scale));
|
setTargetScale(scale);
|
||||||
|
|
||||||
glm::vec3 lookAt = glm::vec3(header->lookAtPosition[0], header->lookAtPosition[1], header->lookAtPosition[2]);
|
glm::vec3 lookAt = glm::vec3(header->lookAtPosition[0], header->lookAtPosition[1], header->lookAtPosition[2]);
|
||||||
if (isNaN(lookAt)) {
|
if (isNaN(lookAt)) {
|
||||||
|
@ -1439,7 +1439,7 @@ QJsonObject AvatarData::toJson() const {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
qDebug() << "Warning -- AvatarData::toJson couldn't get avatar transform";
|
qDebug() << "Warning -- AvatarData::toJson couldn't get avatar transform";
|
||||||
}
|
}
|
||||||
avatarTransform.setScale(getTargetScale());
|
avatarTransform.setScale(getDomainLimitedScale());
|
||||||
if (recordingBasis) {
|
if (recordingBasis) {
|
||||||
root[JSON_AVATAR_BASIS] = Transform::toJson(*recordingBasis);
|
root[JSON_AVATAR_BASIS] = Transform::toJson(*recordingBasis);
|
||||||
// Find the relative transform
|
// Find the relative transform
|
||||||
|
@ -1451,7 +1451,7 @@ QJsonObject AvatarData::toJson() const {
|
||||||
root[JSON_AVATAR_RELATIVE] = Transform::toJson(avatarTransform);
|
root[JSON_AVATAR_RELATIVE] = Transform::toJson(avatarTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto scale = getTargetScale();
|
auto scale = getDomainLimitedScale();
|
||||||
if (scale != 1.0f) {
|
if (scale != 1.0f) {
|
||||||
root[JSON_AVATAR_SCALE] = scale;
|
root[JSON_AVATAR_SCALE] = scale;
|
||||||
}
|
}
|
||||||
|
|
|
@ -243,6 +243,12 @@ public:
|
||||||
void setTargetScale(float targetScale);
|
void setTargetScale(float targetScale);
|
||||||
void setTargetScaleVerbose(float targetScale);
|
void setTargetScaleVerbose(float targetScale);
|
||||||
|
|
||||||
|
float getDomainLimitedScale() const { return glm::clamp(_targetScale, _domainMinimumScale, _domainMaximumScale); }
|
||||||
|
void setDomainMinimumScale(float domainMinimumScale)
|
||||||
|
{ _domainMinimumScale = glm::clamp(domainMinimumScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE); }
|
||||||
|
void setDomainMaximumScale(float domainMaximumScale)
|
||||||
|
{ _domainMaximumScale = glm::clamp(domainMaximumScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE); }
|
||||||
|
|
||||||
// Hand State
|
// Hand State
|
||||||
Q_INVOKABLE void setHandState(char s) { _handState = s; }
|
Q_INVOKABLE void setHandState(char s) { _handState = s; }
|
||||||
Q_INVOKABLE char getHandState() const { return _handState; }
|
Q_INVOKABLE char getHandState() const { return _handState; }
|
||||||
|
@ -377,6 +383,8 @@ protected:
|
||||||
|
|
||||||
// Body scale
|
// Body scale
|
||||||
float _targetScale;
|
float _targetScale;
|
||||||
|
float _domainMinimumScale { MIN_AVATAR_SCALE };
|
||||||
|
float _domainMaximumScale { MAX_AVATAR_SCALE };
|
||||||
|
|
||||||
// Hand state (are we grabbing something or not)
|
// Hand state (are we grabbing something or not)
|
||||||
char _handState;
|
char _handState;
|
||||||
|
|
|
@ -310,14 +310,14 @@ bool RenderableModelEntityItem::getAnimationFrame() {
|
||||||
}
|
}
|
||||||
glm::mat4 finalMat = (translationMat * fbxJoints[index].preTransform *
|
glm::mat4 finalMat = (translationMat * fbxJoints[index].preTransform *
|
||||||
rotationMat * fbxJoints[index].postTransform);
|
rotationMat * fbxJoints[index].postTransform);
|
||||||
_absoluteJointTranslationsInObjectFrame[j] = extractTranslation(finalMat);
|
_localJointTranslations[j] = extractTranslation(finalMat);
|
||||||
_absoluteJointTranslationsInObjectFrameSet[j] = true;
|
_localJointTranslationsSet[j] = true;
|
||||||
_absoluteJointTranslationsInObjectFrameDirty[j] = true;
|
_localJointTranslationsDirty[j] = true;
|
||||||
|
|
||||||
_absoluteJointRotationsInObjectFrame[j] = glmExtractRotation(finalMat);
|
_localJointRotations[j] = glmExtractRotation(finalMat);
|
||||||
|
|
||||||
_absoluteJointRotationsInObjectFrameSet[j] = true;
|
_localJointRotationsSet[j] = true;
|
||||||
_absoluteJointRotationsInObjectFrameDirty[j] = true;
|
_localJointRotationsDirty[j] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -390,18 +390,18 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
||||||
getAnimationFrame();
|
getAnimationFrame();
|
||||||
|
|
||||||
// relay any inbound joint changes from scripts/animation/network to the model/rig
|
// relay any inbound joint changes from scripts/animation/network to the model/rig
|
||||||
for (int index = 0; index < _absoluteJointRotationsInObjectFrame.size(); index++) {
|
for (int index = 0; index < _localJointRotations.size(); index++) {
|
||||||
if (_absoluteJointRotationsInObjectFrameDirty[index]) {
|
if (_localJointRotationsDirty[index]) {
|
||||||
glm::quat rotation = _absoluteJointRotationsInObjectFrame[index];
|
glm::quat rotation = _localJointRotations[index];
|
||||||
_model->setJointRotation(index, true, rotation, 1.0f);
|
_model->setJointRotation(index, true, rotation, 1.0f);
|
||||||
_absoluteJointRotationsInObjectFrameDirty[index] = false;
|
_localJointRotationsDirty[index] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int index = 0; index < _absoluteJointTranslationsInObjectFrame.size(); index++) {
|
for (int index = 0; index < _localJointTranslations.size(); index++) {
|
||||||
if (_absoluteJointTranslationsInObjectFrameDirty[index]) {
|
if (_localJointTranslationsDirty[index]) {
|
||||||
glm::vec3 translation = _absoluteJointTranslationsInObjectFrame[index];
|
glm::vec3 translation = _localJointTranslations[index];
|
||||||
_model->setJointTranslation(index, true, translation, 1.0f);
|
_model->setJointTranslation(index, true, translation, 1.0f);
|
||||||
_absoluteJointTranslationsInObjectFrameDirty[index] = false;
|
_localJointTranslationsDirty[index] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1028,15 +1028,101 @@ glm::vec3 RenderableModelEntityItem::getAbsoluteJointTranslationInObjectFrame(in
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenderableModelEntityItem::setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) {
|
bool RenderableModelEntityItem::setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) {
|
||||||
|
if (!_model) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
RigPointer rig = _model->getRig();
|
||||||
|
if (!rig) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int jointParentIndex = rig->getJointParentIndex(index);
|
||||||
|
if (jointParentIndex == -1) {
|
||||||
|
return setLocalJointRotation(index, rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success;
|
||||||
|
AnimPose jointParentPose;
|
||||||
|
success = rig->getAbsoluteJointPoseInRigFrame(jointParentIndex, jointParentPose);
|
||||||
|
if (!success) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
AnimPose jointParentInversePose = jointParentPose.inverse();
|
||||||
|
|
||||||
|
AnimPose jointAbsolutePose; // in rig frame
|
||||||
|
success = rig->getAbsoluteJointPoseInRigFrame(index, jointAbsolutePose);
|
||||||
|
if (!success) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
jointAbsolutePose.rot = rotation;
|
||||||
|
|
||||||
|
AnimPose jointRelativePose = jointParentInversePose * jointAbsolutePose;
|
||||||
|
return setLocalJointRotation(index, jointRelativePose.rot);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderableModelEntityItem::setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) {
|
||||||
|
if (!_model) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
RigPointer rig = _model->getRig();
|
||||||
|
if (!rig) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int jointParentIndex = rig->getJointParentIndex(index);
|
||||||
|
if (jointParentIndex == -1) {
|
||||||
|
return setLocalJointTranslation(index, translation);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success;
|
||||||
|
AnimPose jointParentPose;
|
||||||
|
success = rig->getAbsoluteJointPoseInRigFrame(jointParentIndex, jointParentPose);
|
||||||
|
if (!success) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
AnimPose jointParentInversePose = jointParentPose.inverse();
|
||||||
|
|
||||||
|
AnimPose jointAbsolutePose; // in rig frame
|
||||||
|
success = rig->getAbsoluteJointPoseInRigFrame(index, jointAbsolutePose);
|
||||||
|
if (!success) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
jointAbsolutePose.trans = translation;
|
||||||
|
|
||||||
|
AnimPose jointRelativePose = jointParentInversePose * jointAbsolutePose;
|
||||||
|
return setLocalJointTranslation(index, jointRelativePose.trans);
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::quat RenderableModelEntityItem::getLocalJointRotation(int index) const {
|
||||||
|
if (_model) {
|
||||||
|
glm::quat result;
|
||||||
|
if (_model->getJointRotation(index, result)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return glm::quat();
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 RenderableModelEntityItem::getLocalJointTranslation(int index) const {
|
||||||
|
if (_model) {
|
||||||
|
glm::vec3 result;
|
||||||
|
if (_model->getJointTranslation(index, result)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return glm::vec3();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderableModelEntityItem::setLocalJointRotation(int index, const glm::quat& rotation) {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
_jointDataLock.withWriteLock([&] {
|
_jointDataLock.withWriteLock([&] {
|
||||||
_jointRotationsExplicitlySet = true;
|
_jointRotationsExplicitlySet = true;
|
||||||
resizeJointArrays();
|
resizeJointArrays();
|
||||||
if (index >= 0 && index < _absoluteJointRotationsInObjectFrame.size() &&
|
if (index >= 0 && index < _localJointRotations.size() &&
|
||||||
_absoluteJointRotationsInObjectFrame[index] != rotation) {
|
_localJointRotations[index] != rotation) {
|
||||||
_absoluteJointRotationsInObjectFrame[index] = rotation;
|
_localJointRotations[index] = rotation;
|
||||||
_absoluteJointRotationsInObjectFrameSet[index] = true;
|
_localJointRotationsSet[index] = true;
|
||||||
_absoluteJointRotationsInObjectFrameDirty[index] = true;
|
_localJointRotationsDirty[index] = true;
|
||||||
result = true;
|
result = true;
|
||||||
_needsJointSimulation = true;
|
_needsJointSimulation = true;
|
||||||
}
|
}
|
||||||
|
@ -1044,16 +1130,16 @@ bool RenderableModelEntityItem::setAbsoluteJointRotationInObjectFrame(int index,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenderableModelEntityItem::setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) {
|
bool RenderableModelEntityItem::setLocalJointTranslation(int index, const glm::vec3& translation) {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
_jointDataLock.withWriteLock([&] {
|
_jointDataLock.withWriteLock([&] {
|
||||||
_jointTranslationsExplicitlySet = true;
|
_jointTranslationsExplicitlySet = true;
|
||||||
resizeJointArrays();
|
resizeJointArrays();
|
||||||
if (index >= 0 && index < _absoluteJointTranslationsInObjectFrame.size() &&
|
if (index >= 0 && index < _localJointTranslations.size() &&
|
||||||
_absoluteJointTranslationsInObjectFrame[index] != translation) {
|
_localJointTranslations[index] != translation) {
|
||||||
_absoluteJointTranslationsInObjectFrame[index] = translation;
|
_localJointTranslations[index] = translation;
|
||||||
_absoluteJointTranslationsInObjectFrameSet[index] = true;
|
_localJointTranslationsSet[index] = true;
|
||||||
_absoluteJointTranslationsInObjectFrameDirty[index] = true;
|
_localJointTranslationsDirty[index] = true;
|
||||||
result = true;
|
result = true;
|
||||||
_needsJointSimulation = true;
|
_needsJointSimulation = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,12 @@ public:
|
||||||
virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override;
|
virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override;
|
||||||
virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override;
|
virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override;
|
||||||
|
|
||||||
|
|
||||||
|
virtual glm::quat getLocalJointRotation(int index) const override;
|
||||||
|
virtual glm::vec3 getLocalJointTranslation(int index) const override;
|
||||||
|
virtual bool setLocalJointRotation(int index, const glm::quat& rotation) override;
|
||||||
|
virtual bool setLocalJointTranslation(int index, const glm::vec3& translation) override;
|
||||||
|
|
||||||
virtual void setJointRotations(const QVector<glm::quat>& rotations) override;
|
virtual void setJointRotations(const QVector<glm::quat>& rotations) override;
|
||||||
virtual void setJointRotationsSet(const QVector<bool>& rotationsSet) override;
|
virtual void setJointRotationsSet(const QVector<bool>& rotationsSet) override;
|
||||||
virtual void setJointTranslations(const QVector<glm::vec3>& translations) override;
|
virtual void setJointTranslations(const QVector<glm::vec3>& translations) override;
|
||||||
|
|
|
@ -411,8 +411,9 @@ public:
|
||||||
// these are in the frame of this object
|
// these are in the frame of this object
|
||||||
virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override { return glm::quat(); }
|
virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override { return glm::quat(); }
|
||||||
virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override { return glm::vec3(0.0f); }
|
virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override { return glm::vec3(0.0f); }
|
||||||
virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; }
|
|
||||||
virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override { return false; }
|
virtual bool setLocalJointRotation(int index, const glm::quat& rotation) override { return false; }
|
||||||
|
virtual bool setLocalJointTranslation(int index, const glm::vec3& translation) override { return false; }
|
||||||
|
|
||||||
virtual int getJointIndex(const QString& name) const { return -1; }
|
virtual int getJointIndex(const QString& name) const { return -1; }
|
||||||
virtual QStringList getJointNames() const { return QStringList(); }
|
virtual QStringList getJointNames() const { return QStringList(); }
|
||||||
|
|
|
@ -1154,17 +1154,76 @@ bool EntityScriptingInterface::setAbsoluteJointRotationInObjectFrame(const QUuid
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec3 EntityScriptingInterface::getLocalJointTranslation(const QUuid& entityID, int jointIndex) {
|
||||||
|
if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::Model)) {
|
||||||
|
auto modelEntity = std::dynamic_pointer_cast<ModelEntityItem>(entity);
|
||||||
|
return modelEntity->getLocalJointTranslation(jointIndex);
|
||||||
|
} else {
|
||||||
|
return glm::vec3(0.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::quat EntityScriptingInterface::getLocalJointRotation(const QUuid& entityID, int jointIndex) {
|
||||||
|
if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::Model)) {
|
||||||
|
auto modelEntity = std::dynamic_pointer_cast<ModelEntityItem>(entity);
|
||||||
|
return modelEntity->getLocalJointRotation(jointIndex);
|
||||||
|
} else {
|
||||||
|
return glm::quat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EntityScriptingInterface::setLocalJointTranslation(const QUuid& entityID, int jointIndex, glm::vec3 translation) {
|
||||||
|
if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::Model)) {
|
||||||
|
auto now = usecTimestampNow();
|
||||||
|
auto modelEntity = std::dynamic_pointer_cast<ModelEntityItem>(entity);
|
||||||
|
bool result = modelEntity->setLocalJointTranslation(jointIndex, translation);
|
||||||
|
if (result) {
|
||||||
|
EntityItemProperties properties;
|
||||||
|
_entityTree->withWriteLock([&] {
|
||||||
|
properties = entity->getProperties();
|
||||||
|
entity->setLastBroadcast(now);
|
||||||
|
});
|
||||||
|
|
||||||
|
properties.setJointTranslationsDirty();
|
||||||
|
properties.setLastEdited(now);
|
||||||
|
queueEntityMessage(PacketType::EntityEdit, entityID, properties);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EntityScriptingInterface::setLocalJointRotation(const QUuid& entityID, int jointIndex, glm::quat rotation) {
|
||||||
|
if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::Model)) {
|
||||||
|
auto now = usecTimestampNow();
|
||||||
|
auto modelEntity = std::dynamic_pointer_cast<ModelEntityItem>(entity);
|
||||||
|
bool result = modelEntity->setLocalJointRotation(jointIndex, rotation);
|
||||||
|
if (result) {
|
||||||
|
EntityItemProperties properties;
|
||||||
|
_entityTree->withWriteLock([&] {
|
||||||
|
properties = entity->getProperties();
|
||||||
|
entity->setLastBroadcast(now);
|
||||||
|
});
|
||||||
|
|
||||||
|
properties.setJointRotationsDirty();
|
||||||
|
properties.setLastEdited(now);
|
||||||
|
queueEntityMessage(PacketType::EntityEdit, entityID, properties);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool EntityScriptingInterface::setAbsoluteJointRotationsInObjectFrame(const QUuid& entityID,
|
|
||||||
const QVector<glm::quat>& rotations) {
|
bool EntityScriptingInterface::setLocalJointRotations(const QUuid& entityID, const QVector<glm::quat>& rotations) {
|
||||||
if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::Model)) {
|
if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::Model)) {
|
||||||
auto now = usecTimestampNow();
|
auto now = usecTimestampNow();
|
||||||
auto modelEntity = std::dynamic_pointer_cast<ModelEntityItem>(entity);
|
auto modelEntity = std::dynamic_pointer_cast<ModelEntityItem>(entity);
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
for (int index = 0; index < rotations.size(); index++) {
|
for (int index = 0; index < rotations.size(); index++) {
|
||||||
result |= modelEntity->setAbsoluteJointRotationInObjectFrame(index, rotations[index]);
|
result |= modelEntity->setLocalJointRotation(index, rotations[index]);
|
||||||
}
|
}
|
||||||
if (result) {
|
if (result) {
|
||||||
EntityItemProperties properties;
|
EntityItemProperties properties;
|
||||||
|
@ -1184,15 +1243,14 @@ bool EntityScriptingInterface::setAbsoluteJointRotationsInObjectFrame(const QUui
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool EntityScriptingInterface::setAbsoluteJointTranslationsInObjectFrame(const QUuid& entityID,
|
bool EntityScriptingInterface::setLocalJointTranslations(const QUuid& entityID, const QVector<glm::vec3>& translations) {
|
||||||
const QVector<glm::vec3>& translations) {
|
|
||||||
if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::Model)) {
|
if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::Model)) {
|
||||||
auto now = usecTimestampNow();
|
auto now = usecTimestampNow();
|
||||||
auto modelEntity = std::dynamic_pointer_cast<ModelEntityItem>(entity);
|
auto modelEntity = std::dynamic_pointer_cast<ModelEntityItem>(entity);
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
for (int index = 0; index < translations.size(); index++) {
|
for (int index = 0; index < translations.size(); index++) {
|
||||||
result |= modelEntity->setAbsoluteJointTranslationInObjectFrame(index, translations[index]);
|
result |= modelEntity->setLocalJointTranslation(index, translations[index]);
|
||||||
}
|
}
|
||||||
if (result) {
|
if (result) {
|
||||||
EntityItemProperties properties;
|
EntityItemProperties properties;
|
||||||
|
@ -1211,12 +1269,12 @@ bool EntityScriptingInterface::setAbsoluteJointTranslationsInObjectFrame(const Q
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityScriptingInterface::setAbsoluteJointsDataInObjectFrame(const QUuid& entityID,
|
bool EntityScriptingInterface::setLocalJointsData(const QUuid& entityID,
|
||||||
const QVector<glm::quat>& rotations,
|
const QVector<glm::quat>& rotations,
|
||||||
const QVector<glm::vec3>& translations) {
|
const QVector<glm::vec3>& translations) {
|
||||||
// for a model with 80 joints, sending both these in one edit packet causes the packet to be too large.
|
// for a model with 80 joints, sending both these in one edit packet causes the packet to be too large.
|
||||||
return setAbsoluteJointRotationsInObjectFrame(entityID, rotations) ||
|
return setLocalJointRotations(entityID, rotations) ||
|
||||||
setAbsoluteJointTranslationsInObjectFrame(entityID, translations);
|
setLocalJointTranslations(entityID, translations);
|
||||||
}
|
}
|
||||||
|
|
||||||
int EntityScriptingInterface::getJointIndex(const QUuid& entityID, const QString& name) {
|
int EntityScriptingInterface::getJointIndex(const QUuid& entityID, const QString& name) {
|
||||||
|
|
|
@ -186,13 +186,17 @@ public slots:
|
||||||
Q_INVOKABLE glm::quat getAbsoluteJointRotationInObjectFrame(const QUuid& entityID, int jointIndex);
|
Q_INVOKABLE glm::quat getAbsoluteJointRotationInObjectFrame(const QUuid& entityID, int jointIndex);
|
||||||
Q_INVOKABLE bool setAbsoluteJointTranslationInObjectFrame(const QUuid& entityID, int jointIndex, glm::vec3 translation);
|
Q_INVOKABLE bool setAbsoluteJointTranslationInObjectFrame(const QUuid& entityID, int jointIndex, glm::vec3 translation);
|
||||||
Q_INVOKABLE bool setAbsoluteJointRotationInObjectFrame(const QUuid& entityID, int jointIndex, glm::quat rotation);
|
Q_INVOKABLE bool setAbsoluteJointRotationInObjectFrame(const QUuid& entityID, int jointIndex, glm::quat rotation);
|
||||||
Q_INVOKABLE bool setAbsoluteJointRotationsInObjectFrame(const QUuid& entityID,
|
|
||||||
const QVector<glm::quat>& rotations);
|
Q_INVOKABLE glm::vec3 getLocalJointTranslation(const QUuid& entityID, int jointIndex);
|
||||||
Q_INVOKABLE bool setAbsoluteJointTranslationsInObjectFrame(const QUuid& entityID,
|
Q_INVOKABLE glm::quat getLocalJointRotation(const QUuid& entityID, int jointIndex);
|
||||||
const QVector<glm::vec3>& translations);
|
Q_INVOKABLE bool setLocalJointTranslation(const QUuid& entityID, int jointIndex, glm::vec3 translation);
|
||||||
Q_INVOKABLE bool setAbsoluteJointsDataInObjectFrame(const QUuid& entityID,
|
Q_INVOKABLE bool setLocalJointRotation(const QUuid& entityID, int jointIndex, glm::quat rotation);
|
||||||
const QVector<glm::quat>& rotations,
|
|
||||||
const QVector<glm::vec3>& translations);
|
Q_INVOKABLE bool setLocalJointRotations(const QUuid& entityID, const QVector<glm::quat>& rotations);
|
||||||
|
Q_INVOKABLE bool setLocalJointTranslations(const QUuid& entityID, const QVector<glm::vec3>& translations);
|
||||||
|
Q_INVOKABLE bool setLocalJointsData(const QUuid& entityID,
|
||||||
|
const QVector<glm::quat>& rotations,
|
||||||
|
const QVector<glm::vec3>& translations);
|
||||||
|
|
||||||
Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name);
|
Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name);
|
||||||
Q_INVOKABLE QStringList getJointNames(const QUuid& entityID);
|
Q_INVOKABLE QStringList getJointNames(const QUuid& entityID);
|
||||||
|
|
|
@ -389,13 +389,13 @@ bool ModelEntityItem::shouldBePhysical() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelEntityItem::resizeJointArrays(int newSize) {
|
void ModelEntityItem::resizeJointArrays(int newSize) {
|
||||||
if (newSize >= 0 && newSize > _absoluteJointRotationsInObjectFrame.size()) {
|
if (newSize >= 0 && newSize > _localJointRotations.size()) {
|
||||||
_absoluteJointRotationsInObjectFrame.resize(newSize);
|
_localJointRotations.resize(newSize);
|
||||||
_absoluteJointRotationsInObjectFrameSet.resize(newSize);
|
_localJointRotationsSet.resize(newSize);
|
||||||
_absoluteJointRotationsInObjectFrameDirty.resize(newSize);
|
_localJointRotationsDirty.resize(newSize);
|
||||||
_absoluteJointTranslationsInObjectFrame.resize(newSize);
|
_localJointTranslations.resize(newSize);
|
||||||
_absoluteJointTranslationsInObjectFrameSet.resize(newSize);
|
_localJointTranslationsSet.resize(newSize);
|
||||||
_absoluteJointTranslationsInObjectFrameDirty.resize(newSize);
|
_localJointTranslationsDirty.resize(newSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,9 +404,9 @@ void ModelEntityItem::setJointRotations(const QVector<glm::quat>& rotations) {
|
||||||
_jointRotationsExplicitlySet = rotations.size() > 0;
|
_jointRotationsExplicitlySet = rotations.size() > 0;
|
||||||
resizeJointArrays(rotations.size());
|
resizeJointArrays(rotations.size());
|
||||||
for (int index = 0; index < rotations.size(); index++) {
|
for (int index = 0; index < rotations.size(); index++) {
|
||||||
if (_absoluteJointRotationsInObjectFrameSet[index]) {
|
if (_localJointRotationsSet[index]) {
|
||||||
_absoluteJointRotationsInObjectFrame[index] = rotations[index];
|
_localJointRotations[index] = rotations[index];
|
||||||
_absoluteJointRotationsInObjectFrameDirty[index] = true;
|
_localJointRotationsDirty[index] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -417,7 +417,7 @@ void ModelEntityItem::setJointRotationsSet(const QVector<bool>& rotationsSet) {
|
||||||
_jointRotationsExplicitlySet = rotationsSet.size() > 0;
|
_jointRotationsExplicitlySet = rotationsSet.size() > 0;
|
||||||
resizeJointArrays(rotationsSet.size());
|
resizeJointArrays(rotationsSet.size());
|
||||||
for (int index = 0; index < rotationsSet.size(); index++) {
|
for (int index = 0; index < rotationsSet.size(); index++) {
|
||||||
_absoluteJointRotationsInObjectFrameSet[index] = rotationsSet[index];
|
_localJointRotationsSet[index] = rotationsSet[index];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -427,9 +427,9 @@ void ModelEntityItem::setJointTranslations(const QVector<glm::vec3>& translation
|
||||||
_jointTranslationsExplicitlySet = translations.size() > 0;
|
_jointTranslationsExplicitlySet = translations.size() > 0;
|
||||||
resizeJointArrays(translations.size());
|
resizeJointArrays(translations.size());
|
||||||
for (int index = 0; index < translations.size(); index++) {
|
for (int index = 0; index < translations.size(); index++) {
|
||||||
if (_absoluteJointTranslationsInObjectFrameSet[index]) {
|
if (_localJointTranslationsSet[index]) {
|
||||||
_absoluteJointTranslationsInObjectFrame[index] = translations[index];
|
_localJointTranslations[index] = translations[index];
|
||||||
_absoluteJointTranslationsInObjectFrameSet[index] = true;
|
_localJointTranslationsSet[index] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -440,7 +440,7 @@ void ModelEntityItem::setJointTranslationsSet(const QVector<bool>& translationsS
|
||||||
_jointTranslationsExplicitlySet = translationsSet.size() > 0;
|
_jointTranslationsExplicitlySet = translationsSet.size() > 0;
|
||||||
resizeJointArrays(translationsSet.size());
|
resizeJointArrays(translationsSet.size());
|
||||||
for (int index = 0; index < translationsSet.size(); index++) {
|
for (int index = 0; index < translationsSet.size(); index++) {
|
||||||
_absoluteJointTranslationsInObjectFrameSet[index] = translationsSet[index];
|
_localJointTranslationsSet[index] = translationsSet[index];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -449,7 +449,7 @@ QVector<glm::quat> ModelEntityItem::getJointRotations() const {
|
||||||
QVector<glm::quat> result;
|
QVector<glm::quat> result;
|
||||||
_jointDataLock.withReadLock([&] {
|
_jointDataLock.withReadLock([&] {
|
||||||
if (_jointRotationsExplicitlySet) {
|
if (_jointRotationsExplicitlySet) {
|
||||||
result = _absoluteJointRotationsInObjectFrame;
|
result = _localJointRotations;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
|
@ -459,7 +459,7 @@ QVector<bool> ModelEntityItem::getJointRotationsSet() const {
|
||||||
QVector<bool> result;
|
QVector<bool> result;
|
||||||
_jointDataLock.withReadLock([&] {
|
_jointDataLock.withReadLock([&] {
|
||||||
if (_jointRotationsExplicitlySet) {
|
if (_jointRotationsExplicitlySet) {
|
||||||
result = _absoluteJointRotationsInObjectFrameSet;
|
result = _localJointRotationsSet;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -470,7 +470,7 @@ QVector<glm::vec3> ModelEntityItem::getJointTranslations() const {
|
||||||
QVector<glm::vec3> result;
|
QVector<glm::vec3> result;
|
||||||
_jointDataLock.withReadLock([&] {
|
_jointDataLock.withReadLock([&] {
|
||||||
if (_jointTranslationsExplicitlySet) {
|
if (_jointTranslationsExplicitlySet) {
|
||||||
result = _absoluteJointTranslationsInObjectFrame;
|
result = _localJointTranslations;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
|
@ -480,7 +480,7 @@ QVector<bool> ModelEntityItem::getJointTranslationsSet() const {
|
||||||
QVector<bool> result;
|
QVector<bool> result;
|
||||||
_jointDataLock.withReadLock([&] {
|
_jointDataLock.withReadLock([&] {
|
||||||
if (_jointTranslationsExplicitlySet) {
|
if (_jointTranslationsExplicitlySet) {
|
||||||
result = _absoluteJointTranslationsInObjectFrameSet;
|
result = _localJointTranslationsSet;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -117,9 +117,6 @@ public:
|
||||||
|
|
||||||
virtual bool shouldBePhysical() const override;
|
virtual bool shouldBePhysical() const override;
|
||||||
|
|
||||||
virtual glm::vec3 getJointPosition(int jointIndex) const { return glm::vec3(); }
|
|
||||||
virtual glm::quat getJointRotation(int jointIndex) const { return glm::quat(); }
|
|
||||||
|
|
||||||
virtual void setJointRotations(const QVector<glm::quat>& rotations);
|
virtual void setJointRotations(const QVector<glm::quat>& rotations);
|
||||||
virtual void setJointRotationsSet(const QVector<bool>& rotationsSet);
|
virtual void setJointRotationsSet(const QVector<bool>& rotationsSet);
|
||||||
virtual void setJointTranslations(const QVector<glm::vec3>& translations);
|
virtual void setJointTranslations(const QVector<glm::vec3>& translations);
|
||||||
|
@ -143,14 +140,14 @@ protected:
|
||||||
ReadWriteLockable _jointDataLock;
|
ReadWriteLockable _jointDataLock;
|
||||||
|
|
||||||
bool _jointRotationsExplicitlySet { false }; // were the joints set as a property or just side effect of animations
|
bool _jointRotationsExplicitlySet { false }; // were the joints set as a property or just side effect of animations
|
||||||
QVector<glm::quat> _absoluteJointRotationsInObjectFrame;
|
QVector<glm::quat> _localJointRotations;
|
||||||
QVector<bool> _absoluteJointRotationsInObjectFrameSet; // ever set?
|
QVector<bool> _localJointRotationsSet; // ever set?
|
||||||
QVector<bool> _absoluteJointRotationsInObjectFrameDirty; // needs a relay to model/rig?
|
QVector<bool> _localJointRotationsDirty; // needs a relay to model/rig?
|
||||||
|
|
||||||
bool _jointTranslationsExplicitlySet { false }; // were the joints set as a property or just side effect of animations
|
bool _jointTranslationsExplicitlySet { false }; // were the joints set as a property or just side effect of animations
|
||||||
QVector<glm::vec3> _absoluteJointTranslationsInObjectFrame;
|
QVector<glm::vec3> _localJointTranslations;
|
||||||
QVector<bool> _absoluteJointTranslationsInObjectFrameSet; // ever set?
|
QVector<bool> _localJointTranslationsSet; // ever set?
|
||||||
QVector<bool> _absoluteJointTranslationsInObjectFrameDirty; // needs a relay to model/rig?
|
QVector<bool> _localJointTranslationsDirty; // needs a relay to model/rig?
|
||||||
int _lastKnownCurrentFrame;
|
int _lastKnownCurrentFrame;
|
||||||
virtual void resizeJointArrays(int newSize = -1);
|
virtual void resizeJointArrays(int newSize = -1);
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include "GLHelpers.h"
|
#include "GLHelpers.h"
|
||||||
|
|
||||||
|
// Minimum gl version required is 4.1
|
||||||
#define MINIMUM_GL_VERSION 0x0401
|
#define MINIMUM_GL_VERSION 0x0401
|
||||||
|
|
||||||
OpenGLVersionChecker::OpenGLVersionChecker(int& argc, char** argv) :
|
OpenGLVersionChecker::OpenGLVersionChecker(int& argc, char** argv) :
|
||||||
|
@ -75,15 +76,26 @@ QJsonObject OpenGLVersionChecker::checkVersion(bool& valid, bool& override) {
|
||||||
// - major_number.minor_number
|
// - major_number.minor_number
|
||||||
// - major_number.minor_number.release_number
|
// - major_number.minor_number.release_number
|
||||||
// Reference: https://www.opengl.org/sdk/docs/man/docbook4/xhtml/glGetString.xml
|
// Reference: https://www.opengl.org/sdk/docs/man/docbook4/xhtml/glGetString.xml
|
||||||
const QString version { "version" };
|
|
||||||
QString glVersion = glData[version].toString();
|
int minimumMajorNumber = (MINIMUM_GL_VERSION >> 8) & 0xFF;
|
||||||
QStringList versionParts = glVersion.split(QRegularExpression("[\\.\\s]"));
|
|
||||||
int majorNumber = versionParts[0].toInt();
|
|
||||||
int minorNumber = versionParts[1].toInt();
|
|
||||||
int minimumMajorNumber = (MINIMUM_GL_VERSION >> 16);
|
|
||||||
int minimumMinorNumber = (MINIMUM_GL_VERSION & 0xFF);
|
int minimumMinorNumber = (MINIMUM_GL_VERSION & 0xFF);
|
||||||
valid = (majorNumber > minimumMajorNumber
|
int majorNumber = 0;
|
||||||
|| (majorNumber == minimumMajorNumber && minorNumber >= minimumMinorNumber));
|
int minorNumber = 0;
|
||||||
|
const QString version { "version" };
|
||||||
|
if (glData.contains(version)) {
|
||||||
|
QString glVersion = glData[version].toString();
|
||||||
|
QStringList versionParts = glVersion.split(QRegularExpression("[\\.\\s]"));
|
||||||
|
if (versionParts.size() >= 2) {
|
||||||
|
majorNumber = versionParts[0].toInt();
|
||||||
|
minorNumber = versionParts[1].toInt();
|
||||||
|
valid = (majorNumber > minimumMajorNumber
|
||||||
|
|| (majorNumber == minimumMajorNumber && minorNumber >= minimumMinorNumber));
|
||||||
|
} else {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Prompt user if below minimum
|
// Prompt user if below minimum
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#include "../gl/GLBackend.h"
|
#include "../gl/GLBackend.h"
|
||||||
#include "../gl/GLTexture.h"
|
#include "../gl/GLTexture.h"
|
||||||
|
|
||||||
|
#define INCREMENTAL_TRANSFER 0
|
||||||
|
|
||||||
namespace gpu { namespace gl45 {
|
namespace gpu { namespace gl45 {
|
||||||
|
|
||||||
using namespace gpu::gl;
|
using namespace gpu::gl;
|
||||||
|
@ -56,6 +58,7 @@ public:
|
||||||
GLint pageDimensionsIndex { 0 };
|
GLint pageDimensionsIndex { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if INCREMENTAL_TRANSFER
|
||||||
struct TransferState {
|
struct TransferState {
|
||||||
TransferState(GL45Texture& texture);
|
TransferState(GL45Texture& texture);
|
||||||
uvec3 currentPageSize() const;
|
uvec3 currentPageSize() const;
|
||||||
|
@ -74,6 +77,10 @@ public:
|
||||||
uvec3 mipOffset;
|
uvec3 mipOffset;
|
||||||
const uint8_t* srcPointer { nullptr };
|
const uint8_t* srcPointer { nullptr };
|
||||||
};
|
};
|
||||||
|
protected:
|
||||||
|
TransferState _transferState;
|
||||||
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void updateMips() override;
|
void updateMips() override;
|
||||||
void stripToMip(uint16_t newMinMip);
|
void stripToMip(uint16_t newMinMip);
|
||||||
|
@ -91,7 +98,6 @@ public:
|
||||||
void derez();
|
void derez();
|
||||||
|
|
||||||
SparseInfo _sparseInfo;
|
SparseInfo _sparseInfo;
|
||||||
TransferState _transferState;
|
|
||||||
uint32_t _allocatedPages { 0 };
|
uint32_t _allocatedPages { 0 };
|
||||||
uint32_t _lastMipAllocatedPages { 0 };
|
uint32_t _lastMipAllocatedPages { 0 };
|
||||||
uint16_t _mipOffset { 0 };
|
uint16_t _mipOffset { 0 };
|
||||||
|
|
|
@ -162,6 +162,8 @@ void GL45Backend::initTextureManagementStage() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if INCREMENTAL_TRANSFER
|
||||||
|
|
||||||
using TransferState = GL45Backend::GL45Texture::TransferState;
|
using TransferState = GL45Backend::GL45Texture::TransferState;
|
||||||
|
|
||||||
TransferState::TransferState(GL45Texture& texture) : texture(texture) {
|
TransferState::TransferState(GL45Texture& texture) : texture(texture) {
|
||||||
|
@ -246,6 +248,7 @@ void TransferState::populatePage(std::vector<uint8_t>& buffer) {
|
||||||
uvec3 TransferState::currentPageSize() const {
|
uvec3 TransferState::currentPageSize() const {
|
||||||
return glm::clamp(mipDimensions - mipOffset, uvec3(1), texture._sparseInfo.pageDimensions);
|
return glm::clamp(mipDimensions - mipOffset, uvec3(1), texture._sparseInfo.pageDimensions);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
GLuint GL45Texture::allocate(const Texture& texture) {
|
GLuint GL45Texture::allocate(const Texture& texture) {
|
||||||
GLuint result;
|
GLuint result;
|
||||||
|
@ -258,11 +261,19 @@ GLuint GL45Backend::getTextureID(const TexturePointer& texture, bool transfer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLuint externalId)
|
GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLuint externalId)
|
||||||
: GLTexture(backend, texture, externalId), _sparseInfo(*this), _transferState(*this) {
|
: GLTexture(backend, texture, externalId), _sparseInfo(*this)
|
||||||
|
#if INCREMENTAL_TRANSFER
|
||||||
|
, _transferState(*this)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, bool transferrable)
|
GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, bool transferrable)
|
||||||
: GLTexture(backend, texture, allocate(texture), transferrable), _sparseInfo(*this), _transferState(*this) {
|
: GLTexture(backend, texture, allocate(texture), transferrable), _sparseInfo(*this)
|
||||||
|
#if INCREMENTAL_TRANSFER
|
||||||
|
, _transferState(*this)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
|
||||||
auto theBackend = _backend.lock();
|
auto theBackend = _backend.lock();
|
||||||
if (_transferrable && theBackend && theBackend->isTextureManagementSparseEnabled()) {
|
if (_transferrable && theBackend && theBackend->isTextureManagementSparseEnabled()) {
|
||||||
|
@ -375,39 +386,40 @@ void GL45Texture::updateSize() const {
|
||||||
void GL45Texture::startTransfer() {
|
void GL45Texture::startTransfer() {
|
||||||
Parent::startTransfer();
|
Parent::startTransfer();
|
||||||
_sparseInfo.update();
|
_sparseInfo.update();
|
||||||
|
#if INCREMENTAL_TRANSFER
|
||||||
_transferState.updateMip();
|
_transferState.updateMip();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GL45Texture::continueTransfer() {
|
bool GL45Texture::continueTransfer() {
|
||||||
if (!Texture::getEnableIncrementalTextureTransfers()) {
|
#if !INCREMENTAL_TRANSFER
|
||||||
size_t maxFace = GL_TEXTURE_CUBE_MAP == _target ? CUBE_NUM_FACES : 1;
|
size_t maxFace = GL_TEXTURE_CUBE_MAP == _target ? CUBE_NUM_FACES : 1;
|
||||||
for (uint8_t face = 0; face < maxFace; ++face) {
|
for (uint8_t face = 0; face < maxFace; ++face) {
|
||||||
for (uint16_t mipLevel = _minMip; mipLevel <= _maxMip; ++mipLevel) {
|
for (uint16_t mipLevel = _minMip; mipLevel <= _maxMip; ++mipLevel) {
|
||||||
auto size = _gpuObject.evalMipDimensions(mipLevel);
|
auto size = _gpuObject.evalMipDimensions(mipLevel);
|
||||||
if (_sparseInfo.sparse && mipLevel <= _sparseInfo.maxSparseLevel) {
|
if (_sparseInfo.sparse && mipLevel <= _sparseInfo.maxSparseLevel) {
|
||||||
glTexturePageCommitmentEXT(_id, mipLevel, 0, 0, face, size.x, size.y, 1, GL_TRUE);
|
glTexturePageCommitmentEXT(_id, mipLevel, 0, 0, face, size.x, size.y, 1, GL_TRUE);
|
||||||
_allocatedPages += _sparseInfo.getPageCount(size);
|
_allocatedPages += _sparseInfo.getPageCount(size);
|
||||||
}
|
}
|
||||||
if (_gpuObject.isStoredMipFaceAvailable(mipLevel, face)) {
|
if (_gpuObject.isStoredMipFaceAvailable(mipLevel, face)) {
|
||||||
auto mip = _gpuObject.accessStoredMipFace(mipLevel, face);
|
auto mip = _gpuObject.accessStoredMipFace(mipLevel, face);
|
||||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), mip->getFormat());
|
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(_gpuObject.getTexelFormat(), mip->getFormat());
|
||||||
if (GL_TEXTURE_2D == _target) {
|
if (GL_TEXTURE_2D == _target) {
|
||||||
glTextureSubImage2D(_id, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData());
|
glTextureSubImage2D(_id, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData());
|
||||||
} else if (GL_TEXTURE_CUBE_MAP == _target) {
|
} else if (GL_TEXTURE_CUBE_MAP == _target) {
|
||||||
// DSA ARB does not work on AMD, so use EXT
|
// DSA ARB does not work on AMD, so use EXT
|
||||||
// glTextureSubImage3D(_id, mipLevel, 0, 0, face, size.x, size.y, 1, texelFormat.format, texelFormat.type, mip->readData());
|
// glTextureSubImage3D(_id, mipLevel, 0, 0, face, size.x, size.y, 1, texelFormat.format, texelFormat.type, mip->readData());
|
||||||
auto target = CUBE_FACE_LAYOUT[face];
|
auto target = CUBE_FACE_LAYOUT[face];
|
||||||
glTextureSubImage2DEXT(_id, target, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData());
|
glTextureSubImage2DEXT(_id, target, mipLevel, 0, 0, size.x, size.y, texelFormat.format, texelFormat.type, mip->readData());
|
||||||
} else {
|
} else {
|
||||||
Q_ASSERT(false);
|
Q_ASSERT(false);
|
||||||
}
|
|
||||||
(void)CHECK_GL_ERROR();
|
|
||||||
}
|
}
|
||||||
|
(void)CHECK_GL_ERROR();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
static std::vector<uint8_t> buffer;
|
static std::vector<uint8_t> buffer;
|
||||||
if (buffer.empty()) {
|
if (buffer.empty()) {
|
||||||
buffer.resize(DEFAULT_PAGE_BUFFER_SIZE);
|
buffer.resize(DEFAULT_PAGE_BUFFER_SIZE);
|
||||||
|
@ -458,6 +470,7 @@ bool GL45Texture::continueTransfer() {
|
||||||
_lastMipAllocatedPages = _allocatedPages;
|
_lastMipAllocatedPages = _allocatedPages;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void GL45Texture::finishTransfer() {
|
void GL45Texture::finishTransfer() {
|
||||||
|
|
|
@ -35,18 +35,15 @@ std::atomic<Texture::Size> Texture::_allowedCPUMemoryUsage { 0 };
|
||||||
|
|
||||||
|
|
||||||
#define MIN_CORES_FOR_INCREMENTAL_TEXTURES 5
|
#define MIN_CORES_FOR_INCREMENTAL_TEXTURES 5
|
||||||
bool recommendedIncrementalTransfers = (QThread::idealThreadCount() >= MIN_CORES_FOR_INCREMENTAL_TEXTURES);
|
bool recommendedSparseTextures = (QThread::idealThreadCount() >= MIN_CORES_FOR_INCREMENTAL_TEXTURES);
|
||||||
bool recommendedSparseTextures = recommendedIncrementalTransfers;
|
|
||||||
|
|
||||||
std::atomic<bool> Texture::_enableSparseTextures { recommendedIncrementalTransfers };
|
std::atomic<bool> Texture::_enableSparseTextures { recommendedSparseTextures };
|
||||||
std::atomic<bool> Texture::_enableIncrementalTextureTransfers { recommendedSparseTextures };
|
|
||||||
|
|
||||||
struct ReportTextureState {
|
struct ReportTextureState {
|
||||||
ReportTextureState() {
|
ReportTextureState() {
|
||||||
qDebug() << "[TEXTURE TRANSFER SUPPORT]"
|
qDebug() << "[TEXTURE TRANSFER SUPPORT]"
|
||||||
<< "\n\tidealThreadCount:" << QThread::idealThreadCount()
|
<< "\n\tidealThreadCount:" << QThread::idealThreadCount()
|
||||||
<< "\n\tRECOMMENDED enableSparseTextures:" << recommendedSparseTextures
|
<< "\n\tRECOMMENDED enableSparseTextures:" << recommendedSparseTextures;
|
||||||
<< "\n\tRECOMMENDED enableIncrementalTextures:" << recommendedIncrementalTransfers;
|
|
||||||
}
|
}
|
||||||
} report;
|
} report;
|
||||||
|
|
||||||
|
@ -59,16 +56,6 @@ void Texture::setEnableSparseTextures(bool enabled) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::setEnableIncrementalTextureTransfers(bool enabled) {
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
qDebug() << "[TEXTURE TRANSFER SUPPORT] SETTING - Enable Incremental Texture Transfer:" << enabled;
|
|
||||||
_enableIncrementalTextureTransfers = enabled;
|
|
||||||
#else
|
|
||||||
qDebug() << "[TEXTURE TRANSFER SUPPORT] Incremental Texture Transfer not supported on this platform.";
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Texture::updateTextureCPUMemoryUsage(Size prevObjectSize, Size newObjectSize) {
|
void Texture::updateTextureCPUMemoryUsage(Size prevObjectSize, Size newObjectSize) {
|
||||||
if (prevObjectSize == newObjectSize) {
|
if (prevObjectSize == newObjectSize) {
|
||||||
return;
|
return;
|
||||||
|
@ -84,10 +71,6 @@ bool Texture::getEnableSparseTextures() {
|
||||||
return _enableSparseTextures.load();
|
return _enableSparseTextures.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Texture::getEnableIncrementalTextureTransfers() {
|
|
||||||
return _enableIncrementalTextureTransfers.load();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t Texture::getTextureCPUCount() {
|
uint32_t Texture::getTextureCPUCount() {
|
||||||
return _textureCPUCount.load();
|
return _textureCPUCount.load();
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,10 +143,8 @@ class Texture : public Resource {
|
||||||
static std::atomic<uint32_t> _textureCPUCount;
|
static std::atomic<uint32_t> _textureCPUCount;
|
||||||
static std::atomic<Size> _textureCPUMemoryUsage;
|
static std::atomic<Size> _textureCPUMemoryUsage;
|
||||||
static std::atomic<Size> _allowedCPUMemoryUsage;
|
static std::atomic<Size> _allowedCPUMemoryUsage;
|
||||||
static void updateTextureCPUMemoryUsage(Size prevObjectSize, Size newObjectSize);
|
|
||||||
|
|
||||||
static std::atomic<bool> _enableSparseTextures;
|
static std::atomic<bool> _enableSparseTextures;
|
||||||
static std::atomic<bool> _enableIncrementalTextureTransfers;
|
static void updateTextureCPUMemoryUsage(Size prevObjectSize, Size newObjectSize);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static uint32_t getTextureCPUCount();
|
static uint32_t getTextureCPUCount();
|
||||||
|
@ -162,10 +160,7 @@ public:
|
||||||
static void setAllowedGPUMemoryUsage(Size size);
|
static void setAllowedGPUMemoryUsage(Size size);
|
||||||
|
|
||||||
static bool getEnableSparseTextures();
|
static bool getEnableSparseTextures();
|
||||||
static bool getEnableIncrementalTextureTransfers();
|
|
||||||
|
|
||||||
static void setEnableSparseTextures(bool enabled);
|
static void setEnableSparseTextures(bool enabled);
|
||||||
static void setEnableIncrementalTextureTransfers(bool enabled);
|
|
||||||
|
|
||||||
using ExternalRecycler = std::function<void(uint32, void*)>;
|
using ExternalRecycler = std::function<void(uint32, void*)>;
|
||||||
using ExternalIdAndFence = std::pair<uint32, void*>;
|
using ExternalIdAndFence = std::pair<uint32, void*>;
|
||||||
|
|
|
@ -272,27 +272,17 @@ void DomainHandler::setIsConnected(bool isConnected) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainHandler::requestDomainSettings() {
|
void DomainHandler::requestDomainSettings() {
|
||||||
// TODO: the nodes basically lock if they don't get a response - add a timeout to this so that they at least restart
|
qCDebug(networking) << "Requesting settings from domain server";
|
||||||
// if they can't get settings
|
|
||||||
|
Assignment::Type assignmentType = Assignment::typeForNodeType(DependencyManager::get<NodeList>()->getOwnerType());
|
||||||
NodeType_t owningNodeType = DependencyManager::get<NodeList>()->getOwnerType();
|
|
||||||
if (owningNodeType == NodeType::Agent) {
|
auto packet = NLPacket::create(PacketType::DomainSettingsRequest, sizeof(assignmentType), true, false);
|
||||||
// for now the agent nodes don't need any domain settings
|
packet->writePrimitive(assignmentType);
|
||||||
_settingsObject = QJsonObject();
|
|
||||||
emit settingsReceived(_settingsObject);
|
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||||
} else {
|
nodeList->sendPacket(std::move(packet), _sockAddr);
|
||||||
qCDebug(networking) << "Requesting settings from domain server";
|
|
||||||
|
_settingsTimer.start();
|
||||||
Assignment::Type assignmentType = Assignment::typeForNodeType(DependencyManager::get<NodeList>()->getOwnerType());
|
|
||||||
|
|
||||||
auto packet = NLPacket::create(PacketType::DomainSettingsRequest, sizeof(assignmentType), true, false);
|
|
||||||
packet->writePrimitive(assignmentType);
|
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
|
||||||
nodeList->sendPacket(std::move(packet), _sockAddr);
|
|
||||||
|
|
||||||
_settingsTimer.start();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainHandler::processSettingsPacketList(QSharedPointer<ReceivedMessage> packetList) {
|
void DomainHandler::processSettingsPacketList(QSharedPointer<ReceivedMessage> packetList) {
|
||||||
|
|
|
@ -144,6 +144,11 @@ public:
|
||||||
virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) { return false; }
|
virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) { return false; }
|
||||||
virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) {return false; }
|
virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) {return false; }
|
||||||
|
|
||||||
|
virtual glm::quat getLocalJointRotation(int index) const {return glm::quat(); }
|
||||||
|
virtual glm::vec3 getLocalJointTranslation(int index) const {return glm::vec3(); }
|
||||||
|
virtual bool setLocalJointRotation(int index, const glm::quat& rotation) { return false; }
|
||||||
|
virtual bool setLocalJointTranslation(int index, const glm::vec3& translation) { return false; }
|
||||||
|
|
||||||
SpatiallyNestablePointer getThisPointer() const;
|
SpatiallyNestablePointer getThisPointer() const;
|
||||||
|
|
||||||
void markAncestorMissing(bool value) { _missingAncestor = value; }
|
void markAncestorMissing(bool value) { _missingAncestor = value; }
|
||||||
|
|
|
@ -428,6 +428,25 @@ bool Menu::menuExists(const QString& menuName) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Menu::isMenuEnabled(const QString& menuName) {
|
||||||
|
QAction* action = getMenuAction(menuName);
|
||||||
|
|
||||||
|
// only proceed if the menu actually exists
|
||||||
|
if (action) {
|
||||||
|
return action->isEnabled();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Menu::setMenuEnabled(const QString& menuName, bool isEnabled) {
|
||||||
|
QAction* action = getMenuAction(menuName);
|
||||||
|
|
||||||
|
// only proceed if the menu actually exists
|
||||||
|
if (action) {
|
||||||
|
action->setEnabled(isEnabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Menu::addSeparator(const QString& menuName, const QString& separatorName, const QString& grouping) {
|
void Menu::addSeparator(const QString& menuName, const QString& separatorName, const QString& grouping) {
|
||||||
MenuWrapper* menuObj = getMenu(menuName);
|
MenuWrapper* menuObj = getMenu(menuName);
|
||||||
if (menuObj) {
|
if (menuObj) {
|
||||||
|
|
|
@ -106,6 +106,9 @@ public slots:
|
||||||
bool isOptionChecked(const QString& menuOption) const;
|
bool isOptionChecked(const QString& menuOption) const;
|
||||||
void setIsOptionChecked(const QString& menuOption, bool isChecked);
|
void setIsOptionChecked(const QString& menuOption, bool isChecked);
|
||||||
|
|
||||||
|
bool isMenuEnabled(const QString& menuName);
|
||||||
|
void setMenuEnabled(const QString& menuName, bool isEnabled);
|
||||||
|
|
||||||
bool getGroupingIsVisible(const QString& grouping);
|
bool getGroupingIsVisible(const QString& grouping);
|
||||||
void setGroupingIsVisible(const QString& grouping, bool isVisible); /// NOTE: the "" grouping is always visible
|
void setGroupingIsVisible(const QString& grouping, bool isVisible); /// NOTE: the "" grouping is always visible
|
||||||
|
|
||||||
|
|
|
@ -331,7 +331,7 @@ controller::Pose openVrControllerPoseToHandPose(bool isLeftHand, const mat4& mat
|
||||||
#define FAILED_MIN_SPEC_OVERLAY_FRIENDLY_NAME "Minimum specifications for SteamVR not met"
|
#define FAILED_MIN_SPEC_OVERLAY_FRIENDLY_NAME "Minimum specifications for SteamVR not met"
|
||||||
#define FAILED_MIN_SPEC_UPDATE_INTERVAL_MS 10
|
#define FAILED_MIN_SPEC_UPDATE_INTERVAL_MS 10
|
||||||
#define FAILED_MIN_SPEC_AUTO_QUIT_INTERVAL_MS (MSECS_PER_SECOND * 30)
|
#define FAILED_MIN_SPEC_AUTO_QUIT_INTERVAL_MS (MSECS_PER_SECOND * 30)
|
||||||
#define MIN_CORES_SPEC 5
|
#define MIN_CORES_SPEC 3
|
||||||
|
|
||||||
void showMinSpecWarning() {
|
void showMinSpecWarning() {
|
||||||
auto vrSystem = acquireOpenVrSystem();
|
auto vrSystem = acquireOpenVrSystem();
|
||||||
|
|
|
@ -203,6 +203,32 @@ function overlayFromWorldPoint(point) {
|
||||||
return { x: horizontalPixels, y: verticalPixels };
|
return { x: horizontalPixels, y: verticalPixels };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var gamePad = Controller.findDevice("GamePad");
|
||||||
|
function activeHudPoint2dGamePad() {
|
||||||
|
if (!HMD.active) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var headPosition = MyAvatar.getHeadPosition();
|
||||||
|
var headDirection = Quat.getUp(Quat.multiply(MyAvatar.headOrientation, Quat.angleAxis(-90, { x: 1, y: 0, z: 0 })));
|
||||||
|
|
||||||
|
var hudPoint3d = calculateRayUICollisionPoint(headPosition, headDirection);
|
||||||
|
|
||||||
|
if (!hudPoint3d) {
|
||||||
|
if (Menu.isOptionChecked("Overlays")) { // With our hud resetting strategy, hudPoint3d should be valid here
|
||||||
|
print('Controller is parallel to HUD'); // so let us know that our assumptions are wrong.
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var hudPoint2d = overlayFromWorldPoint(hudPoint3d);
|
||||||
|
|
||||||
|
// We don't know yet if we'll want to make the cursor or laser visble, but we need to move it to see if
|
||||||
|
// it's pointing at a QML tool (aka system overlay).
|
||||||
|
setReticlePosition(hudPoint2d);
|
||||||
|
|
||||||
|
return hudPoint2d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function activeHudPoint2d(activeHand) { // if controller is valid, update reticle position and answer 2d point. Otherwise falsey.
|
function activeHudPoint2d(activeHand) { // if controller is valid, update reticle position and answer 2d point. Otherwise falsey.
|
||||||
var controllerPose = getControllerWorldLocation(activeHand, true); // note: this will return head pose if hand pose is invalid (third eye)
|
var controllerPose = getControllerWorldLocation(activeHand, true); // note: this will return head pose if hand pose is invalid (third eye)
|
||||||
if (!controllerPose.valid) {
|
if (!controllerPose.valid) {
|
||||||
|
@ -210,7 +236,7 @@ function activeHudPoint2d(activeHand) { // if controller is valid, update reticl
|
||||||
}
|
}
|
||||||
var controllerPosition = controllerPose.position;
|
var controllerPosition = controllerPose.position;
|
||||||
var controllerDirection = Quat.getUp(controllerPose.rotation);
|
var controllerDirection = Quat.getUp(controllerPose.rotation);
|
||||||
|
|
||||||
var hudPoint3d = calculateRayUICollisionPoint(controllerPosition, controllerDirection);
|
var hudPoint3d = calculateRayUICollisionPoint(controllerPosition, controllerDirection);
|
||||||
if (!hudPoint3d) {
|
if (!hudPoint3d) {
|
||||||
if (Menu.isOptionChecked("Overlays")) { // With our hud resetting strategy, hudPoint3d should be valid here
|
if (Menu.isOptionChecked("Overlays")) { // With our hud resetting strategy, hudPoint3d should be valid here
|
||||||
|
@ -405,7 +431,7 @@ clickMapping.from(rightTrigger.full).when(isPointingAtOverlayStartedNonFullTrigg
|
||||||
clickMapping.from(leftTrigger.full).when(isPointingAtOverlayStartedNonFullTrigger(leftTrigger)).to(Controller.Actions.ReticleClick);
|
clickMapping.from(leftTrigger.full).when(isPointingAtOverlayStartedNonFullTrigger(leftTrigger)).to(Controller.Actions.ReticleClick);
|
||||||
// The following is essentially like Left and Right versions of
|
// The following is essentially like Left and Right versions of
|
||||||
// clickMapping.from(Controller.Standard.RightSecondaryThumb).peek().to(Controller.Actions.ContextMenu);
|
// clickMapping.from(Controller.Standard.RightSecondaryThumb).peek().to(Controller.Actions.ContextMenu);
|
||||||
// except that we first update the reticle position from the appropriate hand position, before invoking the ContextMenu.
|
// except that we first update the reticle position from the appropriate hand position, before invoking the .
|
||||||
var wantsMenu = 0;
|
var wantsMenu = 0;
|
||||||
clickMapping.from(function () { return wantsMenu; }).to(Controller.Actions.ContextMenu);
|
clickMapping.from(function () { return wantsMenu; }).to(Controller.Actions.ContextMenu);
|
||||||
clickMapping.from(Controller.Standard.RightSecondaryThumb).peek().to(function (clicked) {
|
clickMapping.from(Controller.Standard.RightSecondaryThumb).peek().to(function (clicked) {
|
||||||
|
@ -420,6 +446,13 @@ clickMapping.from(Controller.Standard.LeftSecondaryThumb).peek().to(function (cl
|
||||||
}
|
}
|
||||||
wantsMenu = clicked;
|
wantsMenu = clicked;
|
||||||
});
|
});
|
||||||
|
clickMapping.from(Controller.Standard.Start).peek().to(function (clicked) {
|
||||||
|
if (clicked) {
|
||||||
|
activeHudPoint2dGamePad();
|
||||||
|
}
|
||||||
|
|
||||||
|
wantsMenu = clicked;
|
||||||
|
});
|
||||||
clickMapping.from(Controller.Hardware.Keyboard.RightMouseClicked).peek().to(function () {
|
clickMapping.from(Controller.Hardware.Keyboard.RightMouseClicked).peek().to(function () {
|
||||||
// Allow the reticle depth to be set correctly:
|
// Allow the reticle depth to be set correctly:
|
||||||
// Wait a tick for the context menu to be displayed, and then simulate a (non-hand-controller) mouse move
|
// Wait a tick for the context menu to be displayed, and then simulate a (non-hand-controller) mouse move
|
||||||
|
@ -472,13 +505,16 @@ function update() {
|
||||||
expireMouseCursor();
|
expireMouseCursor();
|
||||||
clearSystemLaser();
|
clearSystemLaser();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSeeking(true);
|
updateSeeking(true);
|
||||||
if (!handControllerLockOut.expired(now)) {
|
if (!handControllerLockOut.expired(now)) {
|
||||||
return off(); // Let them use mouse in peace.
|
return off(); // Let them use mouse in peace.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Menu.isOptionChecked("First Person")) {
|
if (!Menu.isOptionChecked("First Person")) {
|
||||||
return off(); // What to do? menus can be behind hand!
|
return off(); // What to do? menus can be behind hand!
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!Window.hasFocus() && !HMD.active) || !Reticle.allowMouseCapture) {
|
if ((!Window.hasFocus() && !HMD.active) || !Reticle.allowMouseCapture) {
|
||||||
// In desktop it's pretty clear when another app is on top. In that case we bail, because
|
// In desktop it's pretty clear when another app is on top. In that case we bail, because
|
||||||
// hand controllers might be sputtering "valid" data and that will keep someone from deliberately
|
// hand controllers might be sputtering "valid" data and that will keep someone from deliberately
|
||||||
|
@ -487,14 +523,18 @@ function update() {
|
||||||
// other apps anyway. So in that case, we DO keep going even though we're not on top. (Fogbugz 1831.)
|
// other apps anyway. So in that case, we DO keep going even though we're not on top. (Fogbugz 1831.)
|
||||||
return off(); // Don't mess with other apps or paused mouse activity
|
return off(); // Don't mess with other apps or paused mouse activity
|
||||||
}
|
}
|
||||||
|
|
||||||
leftTrigger.update();
|
leftTrigger.update();
|
||||||
rightTrigger.update();
|
rightTrigger.update();
|
||||||
if (!activeTrigger.state) {
|
if (!activeTrigger.state) {
|
||||||
return off(); // No trigger
|
return off(); // No trigger
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getGrabCommunications()) {
|
if (getGrabCommunications()) {
|
||||||
return off();
|
return off();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var hudPoint2d = activeHudPoint2d(activeHand);
|
var hudPoint2d = activeHudPoint2d(activeHand);
|
||||||
if (!hudPoint2d) {
|
if (!hudPoint2d) {
|
||||||
return off();
|
return off();
|
||||||
|
|
|
@ -24,10 +24,16 @@ var desktopMenuItemName = "Desktop";
|
||||||
|
|
||||||
var toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
|
var toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
|
||||||
var button;
|
var button;
|
||||||
|
// Independent and Entity mode make people sick. Third Person and Mirror have traps that we need to work through.
|
||||||
|
// Disable them in hmd.
|
||||||
|
var desktopOnlyViews = ['Third Person', 'Mirror', 'Independent Mode', 'Entity Mode'];
|
||||||
function onHmdChanged(isHmd) {
|
function onHmdChanged(isHmd) {
|
||||||
button.writeProperty('buttonState', isHmd ? 0 : 1);
|
button.writeProperty('buttonState', isHmd ? 0 : 1);
|
||||||
button.writeProperty('defaultState', isHmd ? 0 : 1);
|
button.writeProperty('defaultState', isHmd ? 0 : 1);
|
||||||
button.writeProperty('hoverState', isHmd ? 2 : 3);
|
button.writeProperty('hoverState', isHmd ? 2 : 3);
|
||||||
|
desktopOnlyViews.forEach(function (view) {
|
||||||
|
Menu.setMenuEnabled("View>" + view, !isHmd);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
function onClicked(){
|
function onClicked(){
|
||||||
var isDesktop = Menu.isOptionChecked(desktopMenuItemName);
|
var isDesktop = Menu.isOptionChecked(desktopMenuItemName);
|
||||||
|
|
|
@ -228,7 +228,7 @@ var usersWindow = (function () {
|
||||||
|
|
||||||
var WINDOW_WIDTH = 260,
|
var WINDOW_WIDTH = 260,
|
||||||
WINDOW_MARGIN = 12,
|
WINDOW_MARGIN = 12,
|
||||||
WINDOW_BASE_MARGIN = 6, // A little less is needed in order look correct
|
WINDOW_BASE_MARGIN = 24, // A little less is needed in order look correct
|
||||||
WINDOW_FONT = {
|
WINDOW_FONT = {
|
||||||
size: 12
|
size: 12
|
||||||
},
|
},
|
||||||
|
@ -253,11 +253,17 @@ var usersWindow = (function () {
|
||||||
windowPane,
|
windowPane,
|
||||||
windowHeading,
|
windowHeading,
|
||||||
|
|
||||||
|
// Margin on the left and right side of the window to keep
|
||||||
|
// it from getting too close to the edge of the screen which
|
||||||
|
// is unclickable.
|
||||||
|
WINDOW_MARGIN_X = 20,
|
||||||
|
|
||||||
// Window border is similar to that of edit.js.
|
// Window border is similar to that of edit.js.
|
||||||
WINDOW_BORDER_WIDTH = WINDOW_WIDTH + 2 * WINDOW_BASE_MARGIN,
|
WINDOW_MARGIN_HALF = WINDOW_MARGIN / 2,
|
||||||
WINDOW_BORDER_TOP_MARGIN = 2 * WINDOW_BASE_MARGIN,
|
WINDOW_BORDER_WIDTH = WINDOW_WIDTH + 2 * WINDOW_MARGIN_HALF,
|
||||||
WINDOW_BORDER_BOTTOM_MARGIN = WINDOW_BASE_MARGIN,
|
WINDOW_BORDER_TOP_MARGIN = 2 * WINDOW_MARGIN_HALF,
|
||||||
WINDOW_BORDER_LEFT_MARGIN = WINDOW_BASE_MARGIN,
|
WINDOW_BORDER_BOTTOM_MARGIN = WINDOW_MARGIN_HALF,
|
||||||
|
WINDOW_BORDER_LEFT_MARGIN = WINDOW_MARGIN_HALF,
|
||||||
WINDOW_BORDER_RADIUS = 4,
|
WINDOW_BORDER_RADIUS = 4,
|
||||||
WINDOW_BORDER_COLOR = { red: 255, green: 255, blue: 255 },
|
WINDOW_BORDER_COLOR = { red: 255, green: 255, blue: 255 },
|
||||||
WINDOW_BORDER_ALPHA = 0.5,
|
WINDOW_BORDER_ALPHA = 0.5,
|
||||||
|
@ -450,7 +456,7 @@ var usersWindow = (function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function saturateWindowPosition() {
|
function saturateWindowPosition() {
|
||||||
windowPosition.x = Math.max(0, Math.min(viewport.x - WINDOW_WIDTH, windowPosition.x));
|
windowPosition.x = Math.max(WINDOW_MARGIN_X, Math.min(viewport.x - WINDOW_WIDTH - WINDOW_MARGIN_X, windowPosition.x));
|
||||||
windowPosition.y = Math.max(windowMinimumHeight, Math.min(viewport.y, windowPosition.y));
|
windowPosition.y = Math.max(windowMinimumHeight, Math.min(viewport.y, windowPosition.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue