mirror of
https://github.com/overte-org/overte.git
synced 2025-04-08 21:33:00 +02:00
Merge branch 'master' of https://github.com/burtsloane/hifi into midi
This commit is contained in:
commit
4f7243e444
115 changed files with 2347 additions and 1170 deletions
|
@ -132,7 +132,7 @@ void AvatarMixer::start() {
|
|||
auto start = usecTimestampNow();
|
||||
nodeList->nestedEach([&](NodeList::const_iterator cbegin, NodeList::const_iterator cend) {
|
||||
std::for_each(cbegin, cend, [&](const SharedNodePointer& node) {
|
||||
manageDisplayName(node);
|
||||
manageIdentityData(node);
|
||||
++_sumListeners;
|
||||
});
|
||||
}, &lockWait, &nodeTransform, &functor);
|
||||
|
@ -183,8 +183,9 @@ void AvatarMixer::start() {
|
|||
|
||||
// NOTE: nodeData->getAvatar() might be side effected, must be called when access to node/nodeData
|
||||
// is guaranteed to not be accessed by other thread
|
||||
void AvatarMixer::manageDisplayName(const SharedNodePointer& node) {
|
||||
void AvatarMixer::manageIdentityData(const SharedNodePointer& node) {
|
||||
AvatarMixerClientData* nodeData = reinterpret_cast<AvatarMixerClientData*>(node->getLinkedData());
|
||||
bool sendIdentity = false;
|
||||
if (nodeData && nodeData->getAvatarSessionDisplayNameMustChange()) {
|
||||
AvatarData& avatar = nodeData->getAvatar();
|
||||
const QString& existingBaseDisplayName = nodeData->getBaseDisplayName();
|
||||
|
@ -210,9 +211,39 @@ void AvatarMixer::manageDisplayName(const SharedNodePointer& node) {
|
|||
soFar.second++; // refcount
|
||||
nodeData->flagIdentityChange();
|
||||
nodeData->setAvatarSessionDisplayNameMustChange(false);
|
||||
sendIdentityPacket(nodeData, node); // Tell node whose name changed about its new session display name.
|
||||
sendIdentity = true;
|
||||
qCDebug(avatars) << "Giving session display name" << sessionDisplayName << "to node with ID" << node->getUUID();
|
||||
}
|
||||
if (nodeData && nodeData->getAvatarSkeletonModelUrlMustChange()) { // never true for an empty _avatarWhitelist
|
||||
nodeData->setAvatarSkeletonModelUrlMustChange(false);
|
||||
AvatarData& avatar = nodeData->getAvatar();
|
||||
static const QUrl emptyURL("");
|
||||
QUrl url = avatar.cannonicalSkeletonModelURL(emptyURL);
|
||||
if (!isAvatarInWhitelist(url)) {
|
||||
qCDebug(avatars) << "Forbidden avatar" << nodeData->getNodeID() << avatar.getSkeletonModelURL() << "replaced with" << (_replacementAvatar.isEmpty() ? "default" : _replacementAvatar);
|
||||
avatar.setSkeletonModelURL(_replacementAvatar);
|
||||
sendIdentity = true;
|
||||
}
|
||||
}
|
||||
if (sendIdentity) {
|
||||
sendIdentityPacket(nodeData, node); // Tell node whose name changed about its new session display name or avatar.
|
||||
}
|
||||
}
|
||||
|
||||
bool AvatarMixer::isAvatarInWhitelist(const QUrl& url) {
|
||||
// The avatar is in the whitelist if:
|
||||
// 1. The avatar's URL's host matches one of the hosts of the URLs in the whitelist AND
|
||||
// 2. The avatar's URL's path starts with the path of that same URL in the whitelist
|
||||
for (const auto& whiteListedPrefix : _avatarWhitelist) {
|
||||
auto whiteListURL = QUrl::fromUserInput(whiteListedPrefix);
|
||||
// check if this script URL matches the whitelist domain and, optionally, is beneath the path
|
||||
if (url.host().compare(whiteListURL.host(), Qt::CaseInsensitive) == 0 &&
|
||||
url.path().startsWith(whiteListURL.path(), Qt::CaseInsensitive)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void AvatarMixer::throttle(std::chrono::microseconds duration, int frame) {
|
||||
|
@ -402,13 +433,17 @@ void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer<ReceivedMessage> mes
|
|||
AvatarData::parseAvatarIdentityPacket(message->getMessage(), identity);
|
||||
bool identityChanged = false;
|
||||
bool displayNameChanged = false;
|
||||
avatar.processAvatarIdentity(identity, identityChanged, displayNameChanged);
|
||||
bool skeletonModelUrlChanged = false;
|
||||
avatar.processAvatarIdentity(identity, identityChanged, displayNameChanged, skeletonModelUrlChanged);
|
||||
if (identityChanged) {
|
||||
QMutexLocker nodeDataLocker(&nodeData->getMutex());
|
||||
nodeData->flagIdentityChange();
|
||||
if (displayNameChanged) {
|
||||
nodeData->setAvatarSessionDisplayNameMustChange(true);
|
||||
}
|
||||
if (skeletonModelUrlChanged && !_avatarWhitelist.isEmpty()) {
|
||||
nodeData->setAvatarSkeletonModelUrlMustChange(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -764,4 +799,19 @@ void AvatarMixer::parseDomainServerSettings(const QJsonObject& domainSettings) {
|
|||
qCDebug(avatars) << "This domain requires a minimum avatar scale of" << _domainMinimumScale
|
||||
<< "and a maximum avatar scale of" << _domainMaximumScale;
|
||||
|
||||
const QString AVATAR_WHITELIST_DEFAULT{ "" };
|
||||
static const QString AVATAR_WHITELIST_OPTION = "avatar_whitelist";
|
||||
_avatarWhitelist = domainSettings[AVATARS_SETTINGS_KEY].toObject()[AVATAR_WHITELIST_OPTION].toString(AVATAR_WHITELIST_DEFAULT).split(',', QString::KeepEmptyParts);
|
||||
|
||||
static const QString REPLACEMENT_AVATAR_OPTION = "replacement_avatar";
|
||||
_replacementAvatar = domainSettings[AVATARS_SETTINGS_KEY].toObject()[REPLACEMENT_AVATAR_OPTION].toString(REPLACEMENT_AVATAR_DEFAULT);
|
||||
|
||||
if ((_avatarWhitelist.count() == 1) && _avatarWhitelist[0].isEmpty()) {
|
||||
_avatarWhitelist.clear(); // KeepEmptyParts above will parse "," as ["", ""] (which is ok), but "" as [""] (which is not ok).
|
||||
}
|
||||
if (_avatarWhitelist.isEmpty()) {
|
||||
qCDebug(avatars) << "All avatars are allowed.";
|
||||
} else {
|
||||
qCDebug(avatars) << "Avatars other than" << _avatarWhitelist << "will be replaced by" << (_replacementAvatar.isEmpty() ? "default" : _replacementAvatar);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,12 @@ private:
|
|||
void parseDomainServerSettings(const QJsonObject& domainSettings);
|
||||
void sendIdentityPacket(AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode);
|
||||
|
||||
void manageDisplayName(const SharedNodePointer& node);
|
||||
void manageIdentityData(const SharedNodePointer& node);
|
||||
bool isAvatarInWhitelist(const QUrl& url);
|
||||
|
||||
const QString REPLACEMENT_AVATAR_DEFAULT{ "" };
|
||||
QStringList _avatarWhitelist { };
|
||||
QString _replacementAvatar { REPLACEMENT_AVATAR_DEFAULT };
|
||||
|
||||
p_high_resolution_clock::time_point _lastFrameTimestamp;
|
||||
|
||||
|
|
|
@ -65,6 +65,8 @@ public:
|
|||
void flagIdentityChange() { _identityChangeTimestamp = usecTimestampNow(); }
|
||||
bool getAvatarSessionDisplayNameMustChange() const { return _avatarSessionDisplayNameMustChange; }
|
||||
void setAvatarSessionDisplayNameMustChange(bool set = true) { _avatarSessionDisplayNameMustChange = set; }
|
||||
bool getAvatarSkeletonModelUrlMustChange() const { return _avatarSkeletonModelUrlMustChange; }
|
||||
void setAvatarSkeletonModelUrlMustChange(bool set = true) { _avatarSkeletonModelUrlMustChange = set; }
|
||||
|
||||
void resetNumAvatarsSentLastFrame() { _numAvatarsSentLastFrame = 0; }
|
||||
void incrementNumAvatarsSentLastFrame() { ++_numAvatarsSentLastFrame; }
|
||||
|
@ -146,6 +148,7 @@ private:
|
|||
|
||||
uint64_t _identityChangeTimestamp;
|
||||
bool _avatarSessionDisplayNameMustChange{ true };
|
||||
bool _avatarSkeletonModelUrlMustChange{ false };
|
||||
|
||||
int _numAvatarsSentLastFrame = 0;
|
||||
int _numFramesSinceAdjustment = 0;
|
||||
|
|
|
@ -47,7 +47,7 @@ void OctreeInboundPacketProcessor::resetStats() {
|
|||
_singleSenderStats.clear();
|
||||
}
|
||||
|
||||
unsigned long OctreeInboundPacketProcessor::getMaxWait() const {
|
||||
uint32_t OctreeInboundPacketProcessor::getMaxWait() const {
|
||||
// calculate time until next sendNackPackets()
|
||||
quint64 nextNackTime = _lastNackTime + TOO_LONG_SINCE_LAST_NACK;
|
||||
quint64 now = usecTimestampNow();
|
||||
|
|
|
@ -80,7 +80,7 @@ protected:
|
|||
|
||||
virtual void processPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) override;
|
||||
|
||||
virtual unsigned long getMaxWait() const override;
|
||||
virtual uint32_t getMaxWait() const override;
|
||||
virtual void preProcess() override;
|
||||
virtual void midProcess() override;
|
||||
|
||||
|
|
|
@ -866,6 +866,22 @@
|
|||
"help": "Limits the scale of avatars in your domain. Cannot be greater than 1000.",
|
||||
"placeholder": 3.0,
|
||||
"default": 3.0
|
||||
},
|
||||
{
|
||||
"name": "avatar_whitelist",
|
||||
"label": "Avatars Allowed from:",
|
||||
"help": "Comma separated list of URLs (with optional paths) that avatar .fst files are allowed from. If someone attempts to use an avatar with a different domain, it will be rejected and the replacement avatar will be used. If left blank, any domain is allowed.",
|
||||
"placeholder": "",
|
||||
"default": "",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "replacement_avatar",
|
||||
"label": "Replacement Avatar for disallowed avatars",
|
||||
"help": "A URL for an avatar .fst to be used when someone tries to use an avatar that is not allowed. If left blank, the generic default avatar is used.",
|
||||
"placeholder": "",
|
||||
"default": "",
|
||||
"advanced": true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -223,6 +223,14 @@ $(document).ready(function(){
|
|||
// set focus to the first input in the new row
|
||||
$target.closest('table').find('tr.inputs input:first').focus();
|
||||
}
|
||||
|
||||
var tableRows = sibling.parent();
|
||||
var tableBody = tableRows.parent();
|
||||
|
||||
// if theres no more siblings, we should jump to a new row
|
||||
if (sibling.next().length == 0 && tableRows.nextAll().length == 1) {
|
||||
tableBody.find("." + Settings.ADD_ROW_BUTTON_CLASS).click();
|
||||
}
|
||||
}
|
||||
|
||||
} else if ($target.is('input')) {
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
{
|
||||
"RenderShadowTask": {
|
||||
"Enabled": {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"RenderDeferredTask": {
|
||||
"AmbientOcclusion": {
|
||||
"RenderMainView": {
|
||||
"RenderShadowTask": {
|
||||
"Enabled": {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"RenderDeferredTask": {
|
||||
"AmbientOcclusion": {
|
||||
"Enabled": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ var EventBridge;
|
|||
var webChannel = new QWebChannel(qt.webChannelTransport, function (channel) {
|
||||
// replace the TempEventBridge with the real one.
|
||||
var tempEventBridge = EventBridge;
|
||||
EventBridge = channel.objects.eventBridgeWrapper.eventBridge;
|
||||
EventBridge = channel.objects.eventBridge;
|
||||
tempEventBridge._callbacks.forEach(function (callback) {
|
||||
EventBridge.scriptEventReceived.connect(callback);
|
||||
});
|
||||
|
|
Binary file not shown.
|
@ -1,85 +1,89 @@
|
|||
name = Jointy3
|
||||
name = mannequin
|
||||
type = body+head
|
||||
scale = 1
|
||||
filename = Jointy3/Jointy3.fbx
|
||||
texdir = Jointy3/textures
|
||||
filename = mannequin/mannequin.baked.fbx
|
||||
joint = jointEyeLeft = LeftEye
|
||||
joint = jointRightHand = RightHand
|
||||
joint = jointHead = Head
|
||||
joint = jointEyeRight = RightEye
|
||||
joint = jointLean = Spine
|
||||
joint = jointNeck = Neck
|
||||
joint = jointLeftHand = LeftHand
|
||||
joint = jointEyeRight = RightEye
|
||||
joint = jointHead = Head
|
||||
joint = jointRightHand = RightHand
|
||||
joint = jointRoot = Hips
|
||||
joint = jointLean = Spine
|
||||
joint = jointEyeLeft = LeftEye
|
||||
freeJoint = LeftArm
|
||||
freeJoint = LeftForeArm
|
||||
freeJoint = RightArm
|
||||
freeJoint = RightForeArm
|
||||
jointIndex = RightHand = 17
|
||||
jointIndex = LeftHandIndex3 = 56
|
||||
jointIndex = Hips = 0
|
||||
jointIndex = LeftHandRing2 = 47
|
||||
jointIndex = LeftHandThumb3 = 60
|
||||
jointIndex = RightShoulder = 14
|
||||
jointIndex = RightHandRing1 = 30
|
||||
jointIndex = RightHandRing3 = 32
|
||||
jointIndex = LeftHandPinky4 = 45
|
||||
jointIndex = LeftHandRing1 = 46
|
||||
jointIndex = LeftFoot = 8
|
||||
jointIndex = RightHandIndex2 = 23
|
||||
jointIndex = RightToeBase = 4
|
||||
jointIndex = RightHandMiddle4 = 29
|
||||
jointIndex = RightHandPinky4 = 37
|
||||
jointIndex = LeftToe_End = 10
|
||||
jointIndex = RightEye = 66
|
||||
jointIndex = RightHandPinky2 = 35
|
||||
jointIndex = RightHandRing2 = 31
|
||||
jointIndex = LeftHand = 41
|
||||
jointIndex = RightToe_End = 5
|
||||
jointIndex = LeftEye = 65
|
||||
jointIndex = LeftHandThumb2 = 59
|
||||
jointIndex = pCylinder73Shape1 = 67
|
||||
jointIndex = LeftShoulder = 38
|
||||
jointIndex = LeftHandIndex2 = 55
|
||||
jointIndex = RightForeArm = 16
|
||||
jointIndex = LeftHandMiddle2 = 51
|
||||
jointIndex = RightHandRing4 = 33
|
||||
jointIndex = LeftLeg = 7
|
||||
jointIndex = LeftHandThumb4 = 61
|
||||
jointIndex = LeftForeArm = 40
|
||||
jointIndex = HeadTop_End = 64
|
||||
jointIndex = RightHandPinky1 = 34
|
||||
jointIndex = RightHandIndex1 = 22
|
||||
jointIndex = LeftHandIndex1 = 54
|
||||
jointIndex = RightLeg = 2
|
||||
jointIndex = RightHandIndex4 = 25
|
||||
jointIndex = Neck = 62
|
||||
jointIndex = LeftHandMiddle1 = 50
|
||||
jointIndex = RightHandPinky3 = 36
|
||||
jointIndex = LeftHandPinky2 = 43
|
||||
jointIndex = RightHandMiddle3 = 28
|
||||
jointIndex = RightHandThumb4 = 21
|
||||
jointIndex = LeftUpLeg = 6
|
||||
jointIndex = RightFoot = 3
|
||||
jointIndex = LeftHandThumb1 = 58
|
||||
jointIndex = LeftArm = 39
|
||||
jointIndex = RightHandMiddle1 = 26
|
||||
jointIndex = LeftHandRing3 = 48
|
||||
jointIndex = LeftHandMiddle4 = 53
|
||||
jointIndex = RightUpLeg = 1
|
||||
jointIndex = RightHandMiddle2 = 27
|
||||
jointIndex = LeftToeBase = 9
|
||||
jointIndex = RightHandThumb2 = 19
|
||||
jointIndex = Spine2 = 13
|
||||
jointIndex = Spine = 11
|
||||
jointIndex = LeftHandRing4 = 49
|
||||
jointIndex = Head = 63
|
||||
jointIndex = LeftHandPinky3 = 44
|
||||
bs = EyeBlink_L = blink = 1
|
||||
bs = JawOpen = mouth_Open = 1
|
||||
bs = LipsFunnel = Oo = 1
|
||||
bs = BrowsU_L = brow_Up = 1
|
||||
jointIndex = RightHandIndex2 = 27
|
||||
jointIndex = LeftHandIndex2 = 51
|
||||
jointIndex = RightUpLeg = 6
|
||||
jointIndex = RightToe_End = 10
|
||||
jointIndex = RightEye = 65
|
||||
jointIndex = LeftHandPinky1 = 42
|
||||
jointIndex = RightHandThumb1 = 18
|
||||
jointIndex = LeftHandIndex4 = 57
|
||||
jointIndex = LeftHandMiddle3 = 52
|
||||
jointIndex = RightHandIndex3 = 24
|
||||
jointIndex = Spine1 = 12
|
||||
jointIndex = RightHandRing1 = 22
|
||||
jointIndex = face = 67
|
||||
jointIndex = LeftUpLeg = 1
|
||||
jointIndex = LeftHand = 41
|
||||
jointIndex = LeftHandMiddle1 = 58
|
||||
jointIndex = LeftHandIndex1 = 50
|
||||
jointIndex = LeftEye = 64
|
||||
jointIndex = RightHandIndex1 = 26
|
||||
jointIndex = LeftHandPinky4 = 45
|
||||
jointIndex = RightArm = 15
|
||||
jointIndex = RightHandThumb3 = 20
|
||||
jointIndex = LeftShoulder = 38
|
||||
jointIndex = RightHandPinky2 = 19
|
||||
jointIndex = RightHandThumb1 = 30
|
||||
jointIndex = RightForeArm = 16
|
||||
jointIndex = LeftHandMiddle3 = 60
|
||||
jointIndex = Neck = 62
|
||||
jointIndex = LeftHandThumb1 = 54
|
||||
jointIndex = RightHandMiddle2 = 35
|
||||
jointIndex = LeftHandMiddle4 = 61
|
||||
jointIndex = mannequin = 68
|
||||
jointIndex = Spine1 = 12
|
||||
jointIndex = RightFoot = 8
|
||||
jointIndex = RightHand = 17
|
||||
jointIndex = LeftHandIndex3 = 52
|
||||
jointIndex = RightHandIndex3 = 28
|
||||
jointIndex = RightHandMiddle4 = 37
|
||||
jointIndex = LeftLeg = 2
|
||||
jointIndex = RightHandMiddle1 = 34
|
||||
jointIndex = Spine2 = 13
|
||||
jointIndex = LeftHandMiddle2 = 59
|
||||
jointIndex = LeftHandPinky3 = 44
|
||||
jointIndex = LeftHandThumb3 = 56
|
||||
jointIndex = LeftHandRing4 = 49
|
||||
jointIndex = RightHandThumb2 = 31
|
||||
jointIndex = LeftHandRing3 = 48
|
||||
jointIndex = HeadTop_End = 66
|
||||
jointIndex = LeftHandThumb4 = 57
|
||||
jointIndex = RightHandThumb3 = 32
|
||||
jointIndex = RightHandPinky1 = 18
|
||||
jointIndex = RightLeg = 7
|
||||
jointIndex = RightHandMiddle3 = 36
|
||||
jointIndex = RightHandPinky3 = 20
|
||||
jointIndex = LeftToeBase = 4
|
||||
jointIndex = LeftForeArm = 40
|
||||
jointIndex = RightShoulder = 14
|
||||
jointIndex = LeftHandRing2 = 47
|
||||
jointIndex = LeftHandThumb2 = 55
|
||||
jointIndex = Head = 63
|
||||
jointIndex = RightHandRing4 = 25
|
||||
jointIndex = LeftHandRing1 = 46
|
||||
jointIndex = LeftFoot = 3
|
||||
jointIndex = RightHandRing3 = 24
|
||||
jointIndex = RightHandThumb4 = 33
|
||||
jointIndex = LeftArm = 39
|
||||
jointIndex = LeftToe_End = 5
|
||||
jointIndex = RightToeBase = 9
|
||||
jointIndex = RightHandPinky4 = 21
|
||||
jointIndex = Spine = 11
|
||||
jointIndex = LeftHandIndex4 = 53
|
||||
jointIndex = LeftHandPinky2 = 43
|
||||
jointIndex = RightHandIndex4 = 29
|
||||
jointIndex = Hips = 0
|
||||
jointIndex = RightHandRing2 = 23
|
||||
|
|
BIN
interface/resources/meshes/mannequin/Eyes.ktx
Executable file
BIN
interface/resources/meshes/mannequin/Eyes.ktx
Executable file
Binary file not shown.
BIN
interface/resources/meshes/mannequin/lambert1_Base_Color.ktx
Executable file
BIN
interface/resources/meshes/mannequin/lambert1_Base_Color.ktx
Executable file
Binary file not shown.
BIN
interface/resources/meshes/mannequin/lambert1_Normal_OpenGL.ktx
Executable file
BIN
interface/resources/meshes/mannequin/lambert1_Normal_OpenGL.ktx
Executable file
Binary file not shown.
BIN
interface/resources/meshes/mannequin/lambert1_Roughness.ktx
Executable file
BIN
interface/resources/meshes/mannequin/lambert1_Roughness.ktx
Executable file
Binary file not shown.
BIN
interface/resources/meshes/mannequin/mannequin.baked.fbx
Executable file
BIN
interface/resources/meshes/mannequin/mannequin.baked.fbx
Executable file
Binary file not shown.
|
@ -21,8 +21,6 @@ ScrollingWindow {
|
|||
property alias url: webview.url
|
||||
property alias webView: webview
|
||||
|
||||
property alias eventBridge: eventBridgeWrapper.eventBridge
|
||||
|
||||
signal loadingChanged(int status)
|
||||
|
||||
x: 100
|
||||
|
@ -210,17 +208,6 @@ ScrollingWindow {
|
|||
url: "https://highfidelity.com/"
|
||||
profile: FileTypeProfile;
|
||||
|
||||
property alias eventBridgeWrapper: eventBridgeWrapper
|
||||
|
||||
QtObject {
|
||||
id: eventBridgeWrapper
|
||||
WebChannel.id: "eventBridgeWrapper"
|
||||
property var eventBridge;
|
||||
}
|
||||
|
||||
|
||||
webChannel.registeredObjects: [eventBridgeWrapper]
|
||||
|
||||
// Create a global EventBridge object for raiseAndLowerKeyboard.
|
||||
WebEngineScript {
|
||||
id: createGlobalEventBridge
|
||||
|
@ -267,6 +254,8 @@ ScrollingWindow {
|
|||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
webChannel.registerObject("eventBridge", eventBridge);
|
||||
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
|
||||
desktop.initWebviewProfileHandlers(webview.profile);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,15 +26,8 @@ Windows.ScrollingWindow {
|
|||
// Don't destroy on close... otherwise the JS/C++ will have a dangling pointer
|
||||
destroyOnCloseButton: false
|
||||
property alias source: webview.url
|
||||
property alias eventBridge: eventBridgeWrapper.eventBridge;
|
||||
property alias scriptUrl: webview.userScriptUrl
|
||||
|
||||
QtObject {
|
||||
id: eventBridgeWrapper
|
||||
WebChannel.id: "eventBridgeWrapper"
|
||||
property var eventBridge;
|
||||
}
|
||||
|
||||
// This is for JS/QML communication, which is unused in a WebWindow,
|
||||
// but not having this here results in spurious warnings about a
|
||||
// missing signal
|
||||
|
@ -70,7 +63,6 @@ Windows.ScrollingWindow {
|
|||
url: "about:blank"
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
webChannel.registeredObjects: [eventBridgeWrapper]
|
||||
|
||||
property string userScriptUrl: ""
|
||||
|
||||
|
@ -107,6 +99,8 @@ Windows.ScrollingWindow {
|
|||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
webChannel.registerObject("eventBridge", eventBridge);
|
||||
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
|
||||
eventBridge.webEventReceived.connect(onWebEventReceived);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,15 +30,6 @@ Windows.Window {
|
|||
property bool keyboardRaised: false
|
||||
property bool punctuationMode: false
|
||||
|
||||
// JavaScript event bridge object in case QML content includes Web content.
|
||||
property alias eventBridge: eventBridgeWrapper.eventBridge;
|
||||
|
||||
QtObject {
|
||||
id: eventBridgeWrapper
|
||||
WebChannel.id: "eventBridgeWrapper"
|
||||
property var eventBridge;
|
||||
}
|
||||
|
||||
onSourceChanged: {
|
||||
if (dynamicContent) {
|
||||
dynamicContent.destroy();
|
||||
|
|
|
@ -18,7 +18,6 @@ Item {
|
|||
property variant permissionsBar: {'securityOrigin':'none','feature':'none'}
|
||||
property alias url: webview.url
|
||||
property WebEngineView webView: webview
|
||||
property alias eventBridge: eventBridgeWrapper.eventBridge
|
||||
property bool canGoBack: webview.canGoBack
|
||||
property bool canGoForward: webview.canGoForward
|
||||
|
||||
|
@ -32,12 +31,6 @@ Item {
|
|||
webview.profile = profile;
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: eventBridgeWrapper
|
||||
WebChannel.id: "eventBridgeWrapper"
|
||||
property var eventBridge;
|
||||
}
|
||||
|
||||
WebEngineView {
|
||||
id: webview
|
||||
objectName: "webEngineView"
|
||||
|
@ -78,9 +71,10 @@ Item {
|
|||
|
||||
property string newUrl: ""
|
||||
|
||||
webChannel.registeredObjects: [eventBridgeWrapper]
|
||||
|
||||
Component.onCompleted: {
|
||||
webChannel.registerObject("eventBridge", eventBridge);
|
||||
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
|
||||
|
||||
// Ensure the JS from the web-engine makes it to our logging
|
||||
webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
||||
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
|
||||
|
|
|
@ -79,15 +79,11 @@ ScrollingWindow {
|
|||
id: webView
|
||||
anchors.fill: parent
|
||||
enabled: false
|
||||
property alias eventBridgeWrapper: eventBridgeWrapper
|
||||
|
||||
QtObject {
|
||||
id: eventBridgeWrapper
|
||||
WebChannel.id: "eventBridgeWrapper"
|
||||
property var eventBridge
|
||||
Component.onCompleted: {
|
||||
webChannel.registerObject("eventBridge", eventBridge);
|
||||
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
|
||||
}
|
||||
|
||||
webChannel.registeredObjects: [eventBridgeWrapper]
|
||||
onEnabledChanged: toolWindow.updateVisiblity()
|
||||
}
|
||||
}
|
||||
|
@ -251,12 +247,9 @@ ScrollingWindow {
|
|||
tab.enabled = true;
|
||||
tab.originalUrl = properties.source;
|
||||
|
||||
var eventBridge = properties.eventBridge;
|
||||
|
||||
var result = tab.item;
|
||||
result.enabled = true;
|
||||
tabView.tabCount++;
|
||||
result.eventBridgeWrapper.eventBridge = eventBridge;
|
||||
result.url = properties.source;
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import "../controls-uit" as HiFiControls
|
|||
Item {
|
||||
property alias url: root.url
|
||||
property alias scriptURL: root.userScriptUrl
|
||||
property alias eventBridge: eventBridgeWrapper.eventBridge
|
||||
property alias canGoBack: root.canGoBack;
|
||||
property var goBack: root.goBack;
|
||||
property alias urlTag: root.urlTag
|
||||
|
@ -22,12 +21,6 @@ Item {
|
|||
}
|
||||
*/
|
||||
|
||||
QtObject {
|
||||
id: eventBridgeWrapper
|
||||
WebChannel.id: "eventBridgeWrapper"
|
||||
property var eventBridge;
|
||||
}
|
||||
|
||||
property alias viewProfile: root.profile
|
||||
|
||||
WebEngineView {
|
||||
|
@ -71,10 +64,11 @@ Item {
|
|||
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ]
|
||||
|
||||
property string newUrl: ""
|
||||
|
||||
webChannel.registeredObjects: [eventBridgeWrapper]
|
||||
|
||||
|
||||
Component.onCompleted: {
|
||||
webChannel.registerObject("eventBridge", eventBridge);
|
||||
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
|
||||
// Ensure the JS from the web-engine makes it to our logging
|
||||
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
||||
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
|
||||
|
|
|
@ -17,7 +17,6 @@ Item {
|
|||
property int headerHeight: 70
|
||||
property string url
|
||||
property string scriptURL
|
||||
property alias eventBridge: eventBridgeWrapper.eventBridge
|
||||
property bool keyboardEnabled: false
|
||||
property bool keyboardRaised: false
|
||||
property bool punctuationMode: false
|
||||
|
@ -135,12 +134,6 @@ Item {
|
|||
loadUrl(url);
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: eventBridgeWrapper
|
||||
WebChannel.id: "eventBridgeWrapper"
|
||||
property var eventBridge;
|
||||
}
|
||||
|
||||
WebEngineView {
|
||||
id: webview
|
||||
objectName: "webEngineView"
|
||||
|
@ -182,9 +175,9 @@ Item {
|
|||
|
||||
property string newUrl: ""
|
||||
|
||||
webChannel.registeredObjects: [eventBridgeWrapper]
|
||||
|
||||
Component.onCompleted: {
|
||||
webChannel.registerObject("eventBridge", eventBridge);
|
||||
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
|
||||
// Ensure the JS from the web-engine makes it to our logging
|
||||
webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
||||
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
|
||||
|
|
|
@ -6,7 +6,6 @@ import "../controls-uit" as HiFiControls
|
|||
Item {
|
||||
property alias url: root.url
|
||||
property alias scriptURL: root.userScriptUrl
|
||||
property alias eventBridge: eventBridgeWrapper.eventBridge
|
||||
property alias canGoBack: root.canGoBack;
|
||||
property var goBack: root.goBack;
|
||||
property alias urlTag: root.urlTag
|
||||
|
@ -22,12 +21,6 @@ Item {
|
|||
}
|
||||
*/
|
||||
|
||||
QtObject {
|
||||
id: eventBridgeWrapper
|
||||
WebChannel.id: "eventBridgeWrapper"
|
||||
property var eventBridge;
|
||||
}
|
||||
|
||||
property alias viewProfile: root.profile
|
||||
|
||||
WebEngineView {
|
||||
|
@ -72,9 +65,9 @@ Item {
|
|||
|
||||
property string newUrl: ""
|
||||
|
||||
webChannel.registeredObjects: [eventBridgeWrapper]
|
||||
|
||||
Component.onCompleted: {
|
||||
webChannel.registerObject("eventBridge", eventBridge);
|
||||
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
|
||||
// Ensure the JS from the web-engine makes it to our logging
|
||||
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
||||
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
|
||||
|
|
|
@ -20,7 +20,6 @@ TabletModalWindow {
|
|||
id: loginDialogRoot
|
||||
objectName: "LoginDialog"
|
||||
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
property bool isHMD: false
|
||||
property bool gotoPreviousApp: false;
|
||||
|
|
|
@ -24,8 +24,6 @@ Window {
|
|||
resizable: true
|
||||
modality: Qt.ApplicationModal
|
||||
|
||||
property alias eventBridge: eventBridgeWrapper.eventBridge
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
|
||||
|
@ -45,16 +43,6 @@ Window {
|
|||
bottom: keyboard.top
|
||||
}
|
||||
|
||||
property alias eventBridgeWrapper: eventBridgeWrapper
|
||||
|
||||
QtObject {
|
||||
id: eventBridgeWrapper
|
||||
WebChannel.id: "eventBridgeWrapper"
|
||||
property var eventBridge;
|
||||
}
|
||||
|
||||
webChannel.registeredObjects: [eventBridgeWrapper]
|
||||
|
||||
// Create a global EventBridge object for raiseAndLowerKeyboard.
|
||||
WebEngineScript {
|
||||
id: createGlobalEventBridge
|
||||
|
@ -73,6 +61,10 @@ Window {
|
|||
|
||||
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard ]
|
||||
|
||||
Component.onCompleted: {
|
||||
webChannel.registerObject("eventBridge", eventBridge);
|
||||
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
Keyboard {
|
||||
|
|
|
@ -116,9 +116,7 @@ Preference {
|
|||
|
||||
Component {
|
||||
id: tabletAvatarBrowserBuilder;
|
||||
TabletAvatarBrowser {
|
||||
eventBridge: tabletRoot.eventBridge
|
||||
}
|
||||
TabletAvatarBrowser { }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ Rectangle {
|
|||
HifiConstants { id: hifi; }
|
||||
objectName: "AudioWindow"
|
||||
|
||||
property var eventBridge;
|
||||
property string title: "Audio Options"
|
||||
signal sendToScript(var message);
|
||||
|
||||
|
|
|
@ -44,7 +44,6 @@ Rectangle {
|
|||
property var activeTab: "nearbyTab";
|
||||
property bool currentlyEditingDisplayName: false
|
||||
property bool punctuationMode: false;
|
||||
property var eventBridge;
|
||||
|
||||
HifiConstants { id: hifi; }
|
||||
|
||||
|
@ -129,7 +128,7 @@ Rectangle {
|
|||
pal.sendToScript({method: 'refreshNearby', params: params});
|
||||
}
|
||||
|
||||
Item {
|
||||
Rectangle {
|
||||
id: palTabContainer;
|
||||
// Anchors
|
||||
anchors {
|
||||
|
@ -138,6 +137,7 @@ Rectangle {
|
|||
left: parent.left;
|
||||
right: parent.right;
|
||||
}
|
||||
color: "white";
|
||||
Rectangle {
|
||||
id: tabSelectorContainer;
|
||||
// Anchors
|
||||
|
@ -1043,7 +1043,6 @@ Rectangle {
|
|||
} // Keyboard
|
||||
|
||||
HifiControls.TabletWebView {
|
||||
eventBridge: pal.eventBridge;
|
||||
id: userInfoViewer;
|
||||
anchors {
|
||||
top: parent.top;
|
||||
|
|
|
@ -24,7 +24,6 @@ Rectangle {
|
|||
property string title: "Asset Browser"
|
||||
property bool keyboardRaised: false
|
||||
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
property bool isHMD: false
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ Rectangle {
|
|||
id: root
|
||||
objectName: "DCConectionTiming"
|
||||
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
property bool isHMD: false
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ Rectangle {
|
|||
id: root
|
||||
|
||||
objectName: "DebugWindow"
|
||||
property var eventBridge;
|
||||
|
||||
property var title: "Debug Window"
|
||||
property bool isHMD: false
|
||||
|
|
|
@ -20,7 +20,6 @@ Rectangle {
|
|||
id: root
|
||||
objectName: "EntityStatistics"
|
||||
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
property bool isHMD: false
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ Rectangle {
|
|||
id: root
|
||||
objectName: "LODTools"
|
||||
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
property bool isHMD: false
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@ Rectangle {
|
|||
property string title: "Running Scripts"
|
||||
HifiConstants { id: hifi }
|
||||
signal sendToScript(var message);
|
||||
property var eventBridge;
|
||||
property var scripts: ScriptDiscoveryService;
|
||||
property var scriptsModel: scripts.scriptsModelFilter
|
||||
property var runningScriptsModel: ListModel { }
|
||||
|
|
|
@ -7,14 +7,12 @@ StackView {
|
|||
objectName: "stack"
|
||||
initialItem: Qt.resolvedUrl('EditTabView.qml')
|
||||
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
function pushSource(path) {
|
||||
editRoot.push(Qt.resolvedUrl(path));
|
||||
editRoot.currentItem.eventBridge = editRoot.eventBridge;
|
||||
editRoot.currentItem.sendToScript.connect(editRoot.sendToScript);
|
||||
}
|
||||
|
||||
|
|
|
@ -181,7 +181,6 @@ TabView {
|
|||
WebView {
|
||||
id: entityListToolWebView
|
||||
url: "../../../../../scripts/system/html/entityList.html"
|
||||
eventBridge: editRoot.eventBridge
|
||||
anchors.fill: parent
|
||||
enabled: true
|
||||
}
|
||||
|
@ -196,7 +195,6 @@ TabView {
|
|||
WebView {
|
||||
id: entityPropertiesWebView
|
||||
url: "../../../../../scripts/system/html/entityProperties.html"
|
||||
eventBridge: editRoot.eventBridge
|
||||
anchors.fill: parent
|
||||
enabled: true
|
||||
}
|
||||
|
@ -211,7 +209,6 @@ TabView {
|
|||
WebView {
|
||||
id: gridControlsWebView
|
||||
url: "../../../../../scripts/system/html/gridControls.html"
|
||||
eventBridge: editRoot.eventBridge
|
||||
anchors.fill: parent
|
||||
enabled: true
|
||||
}
|
||||
|
@ -226,7 +223,6 @@ TabView {
|
|||
WebView {
|
||||
id: particleExplorerWebView
|
||||
url: "../../../../../scripts/system/particle_explorer/particleExplorer.html"
|
||||
eventBridge: editRoot.eventBridge
|
||||
anchors.fill: parent
|
||||
enabled: true
|
||||
}
|
||||
|
@ -289,7 +285,7 @@ TabView {
|
|||
editTabView.currentIndex = id;
|
||||
} else {
|
||||
console.warn('Attempt to switch to invalid tab:', id);
|
||||
}
|
||||
}
|
||||
} else if (typeof id === 'string'){
|
||||
switch (id.toLowerCase()) {
|
||||
case 'create':
|
||||
|
|
|
@ -18,7 +18,6 @@ import "../../dialogs"
|
|||
|
||||
Rectangle {
|
||||
id: inputRecorder
|
||||
property var eventBridge;
|
||||
HifiConstants { id: hifi }
|
||||
signal sendToScript(var message);
|
||||
color: hifi.colors.baseGray;
|
||||
|
|
|
@ -20,7 +20,6 @@ Rectangle {
|
|||
// height: parent.height
|
||||
HifiConstants { id: hifi }
|
||||
color: hifi.colors.baseGray;
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
property bool keyboardEnabled: false
|
||||
property bool punctuationMode: false
|
||||
|
|
|
@ -29,7 +29,6 @@ StackView {
|
|||
initialItem: addressBarDialog
|
||||
width: parent !== null ? parent.width : undefined
|
||||
height: parent !== null ? parent.height : undefined
|
||||
property var eventBridge;
|
||||
property int cardWidth: 212;
|
||||
property int cardHeight: 152;
|
||||
property string metaverseBase: addressBarDialog.metaverseServerUrl + "/api/v1/";
|
||||
|
@ -80,7 +79,6 @@ StackView {
|
|||
var card = tabletWebView.createObject();
|
||||
card.url = addressBarDialog.metaverseServerUrl + targetString;
|
||||
card.parentStackItem = root;
|
||||
card.eventBridge = root.eventBridge;
|
||||
root.push(card);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ Item {
|
|||
property bool keyboardRaised: false
|
||||
property bool punctuationMode: false
|
||||
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
|
||||
anchors.fill: parent
|
||||
|
|
|
@ -19,7 +19,6 @@ StackView {
|
|||
objectName: "stack"
|
||||
property string title: "Audio Settings"
|
||||
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
|
||||
function pushSource(path) {
|
||||
|
|
|
@ -19,7 +19,6 @@ StackView {
|
|||
objectName: "stack"
|
||||
property string title: "Avatar Settings"
|
||||
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
|
||||
function pushSource(path) {
|
||||
|
|
|
@ -19,7 +19,6 @@ StackView {
|
|||
objectName: "stack"
|
||||
property string title: "General Settings"
|
||||
property alias gotoPreviousApp: root.gotoPreviousApp;
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
|
||||
function pushSource(path) {
|
||||
|
|
|
@ -19,7 +19,6 @@ StackView {
|
|||
objectName: "stack"
|
||||
property string title: "Graphics Settings"
|
||||
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
|
||||
function pushSource(path) {
|
||||
|
|
|
@ -19,7 +19,6 @@ StackView {
|
|||
objectName: "stack"
|
||||
property string title: "LOD Settings"
|
||||
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
|
||||
function pushSource(path) {
|
||||
|
|
|
@ -21,7 +21,6 @@ FocusScope {
|
|||
property var point: Qt.point(50, 50);
|
||||
TabletMenuStack { id: menuPopperUpper }
|
||||
property string subMenu: ""
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
|
||||
Rectangle {
|
||||
|
|
|
@ -49,7 +49,6 @@ Item {
|
|||
|
||||
function pushSource(path) {
|
||||
d.push(Qt.resolvedUrl(path));
|
||||
d.currentItem.eventBridge = tabletMenu.eventBridge
|
||||
d.currentItem.sendToScript.connect(tabletMenu.sendToScript);
|
||||
d.currentItem.focus = true;
|
||||
d.currentItem.forceActiveFocus();
|
||||
|
|
|
@ -19,7 +19,6 @@ StackView {
|
|||
objectName: "stack"
|
||||
property var title: "Networking Settings"
|
||||
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
|
||||
function pushSource(path) {
|
||||
|
|
|
@ -8,7 +8,6 @@ Item {
|
|||
id: tabletRoot
|
||||
objectName: "tabletRoot"
|
||||
property string username: "Unknown user"
|
||||
property var eventBridge;
|
||||
property var rootMenu;
|
||||
property var openModal: null;
|
||||
property var openMessage: null;
|
||||
|
@ -111,7 +110,6 @@ Item {
|
|||
function openBrowserWindow(request, profile) {
|
||||
var component = Qt.createComponent("../../controls/TabletWebView.qml");
|
||||
var newWindow = component.createObject(tabletRoot);
|
||||
newWindow.eventBridge = tabletRoot.eventBridge;
|
||||
newWindow.remove = true;
|
||||
newWindow.profile = profile;
|
||||
request.openIn(newWindow.webView);
|
||||
|
@ -175,7 +173,7 @@ Item {
|
|||
// Hook up callback for clara.io download from the marketplace.
|
||||
Connections {
|
||||
id: eventBridgeConnection
|
||||
target: null
|
||||
target: eventBridge
|
||||
onWebEventReceived: {
|
||||
if (message.slice(0, 17) === "CLARA.IO DOWNLOAD") {
|
||||
ApplicationInterface.addAssetToWorldFromURL(message.slice(18));
|
||||
|
@ -184,10 +182,6 @@ Item {
|
|||
}
|
||||
|
||||
onLoaded: {
|
||||
if (loader.item.hasOwnProperty("eventBridge")) {
|
||||
loader.item.eventBridge = eventBridge;
|
||||
eventBridgeConnection.target = eventBridge
|
||||
}
|
||||
if (loader.item.hasOwnProperty("sendToScript")) {
|
||||
loader.item.sendToScript.connect(tabletRoot.sendToScript);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ Windows.ScrollingWindow {
|
|||
id: tabletRoot
|
||||
objectName: "tabletRoot"
|
||||
property string username: "Unknown user"
|
||||
property var eventBridge;
|
||||
|
||||
property var rootMenu;
|
||||
property string subMenu: ""
|
||||
|
@ -93,7 +92,7 @@ Windows.ScrollingWindow {
|
|||
// Hook up callback for clara.io download from the marketplace.
|
||||
Connections {
|
||||
id: eventBridgeConnection
|
||||
target: null
|
||||
target: eventBridge
|
||||
onWebEventReceived: {
|
||||
if (message.slice(0, 17) === "CLARA.IO DOWNLOAD") {
|
||||
ApplicationInterface.addAssetToWorldFromURL(message.slice(18));
|
||||
|
@ -102,10 +101,6 @@ Windows.ScrollingWindow {
|
|||
}
|
||||
|
||||
onLoaded: {
|
||||
if (loader.item.hasOwnProperty("eventBridge")) {
|
||||
loader.item.eventBridge = eventBridge;
|
||||
eventBridgeConnection.target = eventBridge
|
||||
}
|
||||
if (loader.item.hasOwnProperty("sendToScript")) {
|
||||
loader.item.sendToScript.connect(tabletRoot.sendToScript);
|
||||
}
|
||||
|
|
|
@ -27,8 +27,6 @@ Item {
|
|||
property bool keyboardRaised: false
|
||||
property bool punctuationMode: false
|
||||
|
||||
property alias eventBridge: eventBridgeWrapper.eventBridge
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
BaseWebView {
|
||||
|
@ -43,14 +41,6 @@ Item {
|
|||
bottom: footer.top
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: eventBridgeWrapper
|
||||
WebChannel.id: "eventBridgeWrapper"
|
||||
property var eventBridge;
|
||||
}
|
||||
|
||||
webChannel.registeredObjects: [eventBridgeWrapper]
|
||||
|
||||
// Create a global EventBridge object for raiseAndLowerKeyboard.
|
||||
WebEngineScript {
|
||||
id: createGlobalEventBridge
|
||||
|
@ -68,6 +58,11 @@ Item {
|
|||
}
|
||||
|
||||
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard ]
|
||||
|
||||
Component.onCompleted: {
|
||||
webChannel.registerObject("eventBridge", eventBridge);
|
||||
webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
|
|
|
@ -115,6 +115,7 @@
|
|||
#include <render/RenderFetchCullSortTask.h>
|
||||
#include <RenderDeferredTask.h>
|
||||
#include <RenderForwardTask.h>
|
||||
#include <RenderViewTask.h>
|
||||
#include <ResourceCache.h>
|
||||
#include <ResourceRequest.h>
|
||||
#include <SandboxUtils.h>
|
||||
|
@ -1726,6 +1727,10 @@ void Application::cleanupBeforeQuit() {
|
|||
|
||||
// Cleanup all overlays after the scripts, as scripts might add more
|
||||
_overlays.cleanupAllOverlays();
|
||||
// The cleanup process enqueues the transactions but does not process them. Calling this here will force the actual
|
||||
// removal of the items.
|
||||
// See https://highfidelity.fogbugz.com/f/cases/5328
|
||||
_main3DScene->processTransactionQueue();
|
||||
|
||||
// first stop all timers directly or by invokeMethod
|
||||
// depending on what thread they run in
|
||||
|
@ -1872,15 +1877,9 @@ void Application::initializeGL() {
|
|||
|
||||
// Set up the render engine
|
||||
render::CullFunctor cullFunctor = LODManager::shouldRender;
|
||||
_renderEngine->addJob<RenderShadowTask>("RenderShadowTask", cullFunctor);
|
||||
const auto items = _renderEngine->addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor);
|
||||
assert(items.canCast<RenderFetchCullSortTask::Output>());
|
||||
static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD";
|
||||
if (QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD)) {
|
||||
_renderEngine->addJob<RenderForwardTask>("Forward", items);
|
||||
} else {
|
||||
_renderEngine->addJob<RenderDeferredTask>("RenderDeferredTask", items);
|
||||
}
|
||||
bool isDeferred = !QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD);
|
||||
_renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, isDeferred);
|
||||
_renderEngine->load();
|
||||
_renderEngine->registerScene(_main3DScene);
|
||||
|
||||
|
@ -5082,7 +5081,7 @@ namespace render {
|
|||
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape(); }
|
||||
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); }
|
||||
template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) {
|
||||
if (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE && Menu::getInstance()->isOptionChecked(MenuOption::WorldAxes)) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::WorldAxes)) {
|
||||
PerformanceTimer perfTimer("worldBox");
|
||||
|
||||
auto& batch = *args->_batch;
|
||||
|
@ -5303,6 +5302,11 @@ void Application::nodeActivated(SharedNodePointer node) {
|
|||
|
||||
if (node->getType() == NodeType::AvatarMixer) {
|
||||
// new avatar mixer, send off our identity packet on next update loop
|
||||
// Reset skeletonModelUrl if the last server modified our choice.
|
||||
static const QUrl empty{};
|
||||
if (getMyAvatar()->getFullAvatarURLFromPreferences() != getMyAvatar()->cannonicalSkeletonModelURL(empty)) {
|
||||
getMyAvatar()->resetFullAvatarURL();
|
||||
}
|
||||
getMyAvatar()->markIdentityDataChanged();
|
||||
getMyAvatar()->resetLastSent();
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ CrashHandler::Action CrashHandler::promptUserForAction(bool showCrashMessage) {
|
|||
layout->addWidget(label);
|
||||
|
||||
QRadioButton* option1 = new QRadioButton("Reset all my settings");
|
||||
QRadioButton* option2 = new QRadioButton("Reset my settings but retain avatar info.");
|
||||
QRadioButton* option2 = new QRadioButton("Reset my settings but keep essential info");
|
||||
QRadioButton* option3 = new QRadioButton("Continue with my current settings");
|
||||
option3->setChecked(true);
|
||||
layout->addWidget(option1);
|
||||
|
@ -95,7 +95,7 @@ CrashHandler::Action CrashHandler::promptUserForAction(bool showCrashMessage) {
|
|||
return CrashHandler::DELETE_INTERFACE_INI;
|
||||
}
|
||||
if (option2->isChecked()) {
|
||||
return CrashHandler::RETAIN_AVATAR_INFO;
|
||||
return CrashHandler::RETAIN_IMPORTANT_INFO;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,7 +104,7 @@ CrashHandler::Action CrashHandler::promptUserForAction(bool showCrashMessage) {
|
|||
}
|
||||
|
||||
void CrashHandler::handleCrash(CrashHandler::Action action) {
|
||||
if (action != CrashHandler::DELETE_INTERFACE_INI && action != CrashHandler::RETAIN_AVATAR_INFO) {
|
||||
if (action != CrashHandler::DELETE_INTERFACE_INI && action != CrashHandler::RETAIN_IMPORTANT_INFO) {
|
||||
// CrashHandler::DO_NOTHING or unexpected value
|
||||
return;
|
||||
}
|
||||
|
@ -116,12 +116,15 @@ void CrashHandler::handleCrash(CrashHandler::Action action) {
|
|||
const QString DISPLAY_NAME_KEY = "displayName";
|
||||
const QString FULL_AVATAR_URL_KEY = "fullAvatarURL";
|
||||
const QString FULL_AVATAR_MODEL_NAME_KEY = "fullAvatarModelName";
|
||||
const QString TUTORIAL_COMPLETE_FLAG_KEY = "tutorialComplete";
|
||||
|
||||
QString displayName;
|
||||
QUrl fullAvatarURL;
|
||||
QString fullAvatarModelName;
|
||||
QUrl address;
|
||||
bool tutorialComplete = false;
|
||||
|
||||
if (action == CrashHandler::RETAIN_AVATAR_INFO) {
|
||||
if (action == CrashHandler::RETAIN_IMPORTANT_INFO) {
|
||||
// Read avatar info
|
||||
|
||||
// Location and orientation
|
||||
|
@ -135,6 +138,9 @@ void CrashHandler::handleCrash(CrashHandler::Action action) {
|
|||
fullAvatarURL = settings.value(FULL_AVATAR_URL_KEY).toUrl();
|
||||
fullAvatarModelName = settings.value(FULL_AVATAR_MODEL_NAME_KEY).toString();
|
||||
settings.endGroup();
|
||||
|
||||
// Tutorial complete
|
||||
tutorialComplete = settings.value(TUTORIAL_COMPLETE_FLAG_KEY).toBool();
|
||||
}
|
||||
|
||||
// Delete Interface.ini
|
||||
|
@ -143,7 +149,7 @@ void CrashHandler::handleCrash(CrashHandler::Action action) {
|
|||
settingsFile.remove();
|
||||
}
|
||||
|
||||
if (action == CrashHandler::RETAIN_AVATAR_INFO) {
|
||||
if (action == CrashHandler::RETAIN_IMPORTANT_INFO) {
|
||||
// Write avatar info
|
||||
|
||||
// Location and orientation
|
||||
|
@ -157,6 +163,9 @@ void CrashHandler::handleCrash(CrashHandler::Action action) {
|
|||
settings.setValue(FULL_AVATAR_URL_KEY, fullAvatarURL);
|
||||
settings.setValue(FULL_AVATAR_MODEL_NAME_KEY, fullAvatarModelName);
|
||||
settings.endGroup();
|
||||
|
||||
// Tutorial complete
|
||||
settings.setValue(TUTORIAL_COMPLETE_FLAG_KEY, tutorialComplete);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ public:
|
|||
private:
|
||||
enum Action {
|
||||
DELETE_INTERFACE_INI,
|
||||
RETAIN_AVATAR_INFO,
|
||||
RETAIN_IMPORTANT_INFO,
|
||||
DO_NOTHING
|
||||
};
|
||||
|
||||
|
|
|
@ -794,6 +794,77 @@ controller::Pose MyAvatar::getRightHandTipPose() const {
|
|||
return pose;
|
||||
}
|
||||
|
||||
glm::vec3 MyAvatar::worldToJointPoint(const glm::vec3& position, const int jointIndex) const {
|
||||
glm::vec3 jointPos = getPosition();//default value if no or invalid joint specified
|
||||
glm::quat jointRot = getRotation();//default value if no or invalid joint specified
|
||||
if (jointIndex != -1) {
|
||||
if (_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPos)) {
|
||||
_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot);
|
||||
} else {
|
||||
qWarning() << "Invalid joint index specified: " << jointIndex;
|
||||
}
|
||||
}
|
||||
glm::vec3 modelOffset = position - jointPos;
|
||||
glm::vec3 jointSpacePosition = glm::inverse(jointRot) * modelOffset;
|
||||
|
||||
return jointSpacePosition;
|
||||
}
|
||||
|
||||
glm::vec3 MyAvatar::worldToJointDirection(const glm::vec3& worldDir, const int jointIndex) const {
|
||||
glm::quat jointRot = getRotation();//default value if no or invalid joint specified
|
||||
if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) {
|
||||
qWarning() << "Invalid joint index specified: " << jointIndex;
|
||||
}
|
||||
|
||||
glm::vec3 jointSpaceDir = glm::inverse(jointRot) * worldDir;
|
||||
return jointSpaceDir;
|
||||
}
|
||||
|
||||
glm::quat MyAvatar::worldToJointRotation(const glm::quat& worldRot, const int jointIndex) const {
|
||||
glm::quat jointRot = getRotation();//default value if no or invalid joint specified
|
||||
if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) {
|
||||
qWarning() << "Invalid joint index specified: " << jointIndex;
|
||||
}
|
||||
glm::quat jointSpaceRot = glm::inverse(jointRot) * worldRot;
|
||||
return jointSpaceRot;
|
||||
}
|
||||
|
||||
glm::vec3 MyAvatar::jointToWorldPoint(const glm::vec3& jointSpacePos, const int jointIndex) const {
|
||||
glm::vec3 jointPos = getPosition();//default value if no or invalid joint specified
|
||||
glm::quat jointRot = getRotation();//default value if no or invalid joint specified
|
||||
|
||||
if (jointIndex != -1) {
|
||||
if (_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPos)) {
|
||||
_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot);
|
||||
} else {
|
||||
qWarning() << "Invalid joint index specified: " << jointIndex;
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 worldOffset = jointRot * jointSpacePos;
|
||||
glm::vec3 worldPos = jointPos + worldOffset;
|
||||
|
||||
return worldPos;
|
||||
}
|
||||
|
||||
glm::vec3 MyAvatar::jointToWorldDirection(const glm::vec3& jointSpaceDir, const int jointIndex) const {
|
||||
glm::quat jointRot = getRotation();//default value if no or invalid joint specified
|
||||
if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) {
|
||||
qWarning() << "Invalid joint index specified: " << jointIndex;
|
||||
}
|
||||
glm::vec3 worldDir = jointRot * jointSpaceDir;
|
||||
return worldDir;
|
||||
}
|
||||
|
||||
glm::quat MyAvatar::jointToWorldRotation(const glm::quat& jointSpaceRot, const int jointIndex) const {
|
||||
glm::quat jointRot = getRotation();//default value if no or invalid joint specified
|
||||
if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) {
|
||||
qWarning() << "Invalid joint index specified: " << jointIndex;
|
||||
}
|
||||
glm::quat worldRot = jointRot * jointSpaceRot;
|
||||
return worldRot;
|
||||
}
|
||||
|
||||
// virtual
|
||||
void MyAvatar::render(RenderArgs* renderArgs) {
|
||||
// don't render if we've been asked to disable local rendering
|
||||
|
@ -1890,6 +1961,32 @@ void MyAvatar::updateOrientation(float deltaTime) {
|
|||
totalBodyYaw += (speedFactor * deltaAngle * (180.0f / PI));
|
||||
}
|
||||
|
||||
// Use head/HMD roll to turn while walking or flying.
|
||||
if (qApp->isHMDMode() && _hmdRollControlEnabled) {
|
||||
// Turn with head roll.
|
||||
const float MIN_CONTROL_SPEED = 0.01f;
|
||||
float speed = glm::length(getVelocity());
|
||||
if (speed >= MIN_CONTROL_SPEED) {
|
||||
// Feather turn when stopping moving.
|
||||
float speedFactor;
|
||||
if (getDriveKey(TRANSLATE_Z) != 0.0f || _lastDrivenSpeed == 0.0f) {
|
||||
_lastDrivenSpeed = speed;
|
||||
speedFactor = 1.0f;
|
||||
} else {
|
||||
speedFactor = glm::min(speed / _lastDrivenSpeed, 1.0f);
|
||||
}
|
||||
|
||||
float direction = glm::dot(getVelocity(), getRotation() * Vectors::UNIT_NEG_Z) > 0.0f ? 1.0f : -1.0f;
|
||||
|
||||
float rollAngle = glm::degrees(asinf(glm::dot(IDENTITY_UP, _hmdSensorOrientation * IDENTITY_RIGHT)));
|
||||
float rollSign = rollAngle < 0.0f ? -1.0f : 1.0f;
|
||||
rollAngle = fabsf(rollAngle);
|
||||
rollAngle = rollAngle > _hmdRollControlDeadZone ? rollSign * (rollAngle - _hmdRollControlDeadZone) : 0.0f;
|
||||
|
||||
totalBodyYaw += speedFactor * direction * rollAngle * deltaTime * _hmdRollControlRate;
|
||||
}
|
||||
}
|
||||
|
||||
// update body orientation by movement inputs
|
||||
glm::quat initialOrientation = getOrientationOutbound();
|
||||
setOrientation(getOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, totalBodyYaw, 0.0f))));
|
||||
|
|
|
@ -132,6 +132,10 @@ class MyAvatar : public Avatar {
|
|||
Q_PROPERTY(bool characterControllerEnabled READ getCharacterControllerEnabled WRITE setCharacterControllerEnabled)
|
||||
Q_PROPERTY(bool useAdvancedMovementControls READ useAdvancedMovementControls WRITE setUseAdvancedMovementControls)
|
||||
|
||||
Q_PROPERTY(bool hmdRollControlEnabled READ getHMDRollControlEnabled WRITE setHMDRollControlEnabled)
|
||||
Q_PROPERTY(float hmdRollControlDeadZone READ getHMDRollControlDeadZone WRITE setHMDRollControlDeadZone)
|
||||
Q_PROPERTY(float hmdRollControlRate READ getHMDRollControlRate WRITE setHMDRollControlRate)
|
||||
|
||||
public:
|
||||
enum DriveKeys {
|
||||
TRANSLATE_X = 0,
|
||||
|
@ -337,6 +341,13 @@ public:
|
|||
void setUseAdvancedMovementControls(bool useAdvancedMovementControls)
|
||||
{ _useAdvancedMovementControls.set(useAdvancedMovementControls); }
|
||||
|
||||
void setHMDRollControlEnabled(bool value) { _hmdRollControlEnabled = value; }
|
||||
bool getHMDRollControlEnabled() const { return _hmdRollControlEnabled; }
|
||||
void setHMDRollControlDeadZone(float value) { _hmdRollControlDeadZone = value; }
|
||||
float getHMDRollControlDeadZone() const { return _hmdRollControlDeadZone; }
|
||||
void setHMDRollControlRate(float value) { _hmdRollControlRate = value; }
|
||||
float getHMDRollControlRate() const { return _hmdRollControlRate; }
|
||||
|
||||
// get/set avatar data
|
||||
void saveData();
|
||||
void loadData();
|
||||
|
@ -378,6 +389,15 @@ public:
|
|||
Q_INVOKABLE controller::Pose getLeftHandTipPose() const;
|
||||
Q_INVOKABLE controller::Pose getRightHandTipPose() const;
|
||||
|
||||
// world-space to avatar-space rigconversion functions
|
||||
Q_INVOKABLE glm::vec3 worldToJointPoint(const glm::vec3& position, const int jointIndex = -1) const;
|
||||
Q_INVOKABLE glm::vec3 worldToJointDirection(const glm::vec3& direction, const int jointIndex = -1) const;
|
||||
Q_INVOKABLE glm::quat worldToJointRotation(const glm::quat& rotation, const int jointIndex = -1) const;
|
||||
|
||||
Q_INVOKABLE glm::vec3 jointToWorldPoint(const glm::vec3& position, const int jointIndex = -1) const;
|
||||
Q_INVOKABLE glm::vec3 jointToWorldDirection(const glm::vec3& direction, const int jointIndex = -1) const;
|
||||
Q_INVOKABLE glm::quat jointToWorldRotation(const glm::quat& rotation, const int jointIndex = -1) const;
|
||||
|
||||
AvatarWeakPointer getLookAtTargetAvatar() const { return _lookAtTargetAvatar; }
|
||||
void updateLookAtTargetAvatar();
|
||||
void clearLookAtTargetAvatar();
|
||||
|
@ -678,6 +698,13 @@ private:
|
|||
bool _useSnapTurn { true };
|
||||
bool _clearOverlayWhenMoving { true };
|
||||
|
||||
const float ROLL_CONTROL_DEAD_ZONE_DEFAULT = 8.0f; // deg
|
||||
const float ROLL_CONTROL_RATE_DEFAULT = 2.5f; // deg/sec/deg
|
||||
bool _hmdRollControlEnabled { true };
|
||||
float _hmdRollControlDeadZone { ROLL_CONTROL_DEAD_ZONE_DEFAULT };
|
||||
float _hmdRollControlRate { ROLL_CONTROL_RATE_DEFAULT };
|
||||
float _lastDrivenSpeed { 0.0f };
|
||||
|
||||
// working copies -- see AvatarData for thread-safe _sensorToWorldMatrixCache, used for outward facing access
|
||||
glm::mat4 _sensorToWorldMatrix { glm::mat4() };
|
||||
|
||||
|
|
|
@ -48,15 +48,31 @@ AudioDeviceScriptingInterface::AudioDeviceScriptingInterface(): QAbstractListMod
|
|||
SettingsScriptingInterface* settings = SettingsScriptingInterface::getInstance();
|
||||
const QString inDevice = settings->getValue("audio_input_device", _currentInputDevice).toString();
|
||||
if (inDevice != _currentInputDevice) {
|
||||
qCDebug(audioclient) << __FUNCTION__ << "about to call setInputDeviceAsync() device: [" << inDevice << "] _currentInputDevice:" << _currentInputDevice;
|
||||
setInputDeviceAsync(inDevice);
|
||||
// before using the old setting, check to make sure the device still exists....
|
||||
bool inDeviceExists = DependencyManager::get<AudioClient>()->getNamedAudioDeviceForModeExists(QAudio::AudioInput, inDevice);
|
||||
|
||||
if (inDeviceExists) {
|
||||
qCDebug(audioclient) << __FUNCTION__ << "about to call setInputDeviceAsync() device: [" << inDevice << "] _currentInputDevice:" << _currentInputDevice;
|
||||
setInputDeviceAsync(inDevice);
|
||||
} else {
|
||||
qCDebug(audioclient) << __FUNCTION__ << "previously selected device no longer exists inDevice: [" << inDevice << "] keeping device _currentInputDevice:" << _currentInputDevice;
|
||||
}
|
||||
}
|
||||
|
||||
// If the audio_output_device setting is not available, use the _currentOutputDevice
|
||||
auto outDevice = settings->getValue("audio_output_device", _currentOutputDevice).toString();
|
||||
|
||||
if (outDevice != _currentOutputDevice) {
|
||||
qCDebug(audioclient) << __FUNCTION__ << "about to call setOutputDeviceAsync() outDevice: [" << outDevice << "] _currentOutputDevice:" << _currentOutputDevice;
|
||||
setOutputDeviceAsync(outDevice);
|
||||
// before using the old setting, check to make sure the device still exists....
|
||||
bool outDeviceExists = DependencyManager::get<AudioClient>()->getNamedAudioDeviceForModeExists(QAudio::AudioOutput, outDevice);
|
||||
|
||||
if (outDeviceExists) {
|
||||
qCDebug(audioclient) << __FUNCTION__ << "about to call setOutputDeviceAsync() outDevice: [" << outDevice << "] _currentOutputDevice:" << _currentOutputDevice;
|
||||
setOutputDeviceAsync(outDevice);
|
||||
} else {
|
||||
qCDebug(audioclient) << __FUNCTION__ << "previously selected device no longer exists outDevice: [" << outDevice << "] keeping device _currentOutputDevice:" << _currentOutputDevice;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1164,9 +1164,32 @@ void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, f
|
|||
bool bodySensorTrackingEnabled = params.isLeftFootEnabled || params.isRightFootEnabled;
|
||||
|
||||
const float RELAX_DURATION = 0.6f;
|
||||
const float CONTROL_DURATION = 0.4f;
|
||||
const bool TO_CONTROLLED = true;
|
||||
const bool FROM_CONTROLLED = false;
|
||||
const bool LEFT_HAND = true;
|
||||
const bool RIGHT_HAND = false;
|
||||
|
||||
if (params.isLeftEnabled) {
|
||||
if (!_isLeftHandControlled) {
|
||||
_leftHandControlTimeRemaining = CONTROL_DURATION;
|
||||
_isLeftHandControlled = true;
|
||||
}
|
||||
|
||||
glm::vec3 handPosition = params.leftPosition;
|
||||
glm::quat handRotation = params.leftOrientation;
|
||||
|
||||
if (_leftHandControlTimeRemaining > 0.0f) {
|
||||
// Move hand from non-controlled position to controlled position.
|
||||
_leftHandControlTimeRemaining = std::max(_leftHandControlTimeRemaining - dt, 0.0f);
|
||||
AnimPose handPose(Vectors::ONE, handRotation, handPosition);
|
||||
if (transitionHandPose(_leftHandControlTimeRemaining, CONTROL_DURATION, handPose, LEFT_HAND, TO_CONTROLLED,
|
||||
handPose)) {
|
||||
handPosition = handPose.trans();
|
||||
handRotation = handPose.rot();
|
||||
}
|
||||
}
|
||||
|
||||
if (!bodySensorTrackingEnabled) {
|
||||
// prevent the hand IK targets from intersecting the body capsule
|
||||
glm::vec3 displacement;
|
||||
|
@ -1176,27 +1199,22 @@ void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, f
|
|||
}
|
||||
|
||||
_animVars.set("leftHandPosition", handPosition);
|
||||
_animVars.set("leftHandRotation", params.leftOrientation);
|
||||
_animVars.set("leftHandRotation", handRotation);
|
||||
_animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition);
|
||||
|
||||
_isLeftHandControlled = true;
|
||||
_lastLeftHandControlledPose = AnimPose(glm::vec3(1.0f), params.leftOrientation, handPosition);
|
||||
_lastLeftHandControlledPose = AnimPose(Vectors::ONE, handRotation, handPosition);
|
||||
} else {
|
||||
if (_isLeftHandControlled) {
|
||||
_leftHandRelaxDuration = RELAX_DURATION;
|
||||
_leftHandRelaxTimeRemaining = RELAX_DURATION;
|
||||
_isLeftHandControlled = false;
|
||||
}
|
||||
|
||||
if (_leftHandRelaxDuration > 0) {
|
||||
if (_leftHandRelaxTimeRemaining > 0.0f) {
|
||||
// Move hand from controlled position to non-controlled position.
|
||||
_leftHandRelaxDuration = std::max(_leftHandRelaxDuration - dt, 0.0f);
|
||||
auto ikNode = getAnimInverseKinematicsNode();
|
||||
if (ikNode) {
|
||||
float alpha = 1.0f - _leftHandRelaxDuration / RELAX_DURATION;
|
||||
const AnimPose geometryToRigTransform(_geometryToRigTransform);
|
||||
AnimPose uncontrolledHandPose = geometryToRigTransform * ikNode->getUncontrolledLeftHandPose();
|
||||
AnimPose handPose;
|
||||
::blend(1, &_lastLeftHandControlledPose, &uncontrolledHandPose, alpha, &handPose);
|
||||
_leftHandRelaxTimeRemaining = std::max(_leftHandRelaxTimeRemaining - dt, 0.0f);
|
||||
AnimPose handPose;
|
||||
if (transitionHandPose(_leftHandRelaxTimeRemaining, RELAX_DURATION, _lastLeftHandControlledPose, LEFT_HAND,
|
||||
FROM_CONTROLLED, handPose)) {
|
||||
_animVars.set("leftHandPosition", handPose.trans());
|
||||
_animVars.set("leftHandRotation", handPose.rot());
|
||||
_animVars.set("leftHandType", (int)IKTarget::Type::RotationAndPosition);
|
||||
|
@ -1209,7 +1227,25 @@ void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, f
|
|||
}
|
||||
|
||||
if (params.isRightEnabled) {
|
||||
if (!_isRightHandControlled) {
|
||||
_rightHandControlTimeRemaining = CONTROL_DURATION;
|
||||
_isRightHandControlled = true;
|
||||
}
|
||||
|
||||
glm::vec3 handPosition = params.rightPosition;
|
||||
glm::quat handRotation = params.rightOrientation;
|
||||
|
||||
if (_rightHandControlTimeRemaining > 0.0f) {
|
||||
// Move hand from non-controlled position to controlled position.
|
||||
_rightHandControlTimeRemaining = std::max(_rightHandControlTimeRemaining - dt, 0.0f);
|
||||
AnimPose handPose(Vectors::ONE, handRotation, handPosition);
|
||||
if (transitionHandPose(_rightHandControlTimeRemaining, CONTROL_DURATION, handPose, RIGHT_HAND, TO_CONTROLLED,
|
||||
handPose)) {
|
||||
handPosition = handPose.trans();
|
||||
handRotation = handPose.rot();
|
||||
}
|
||||
}
|
||||
|
||||
if (!bodySensorTrackingEnabled) {
|
||||
// prevent the hand IK targets from intersecting the body capsule
|
||||
glm::vec3 displacement;
|
||||
|
@ -1219,27 +1255,22 @@ void Rig::updateFromHandAndFeetParameters(const HandAndFeetParameters& params, f
|
|||
}
|
||||
|
||||
_animVars.set("rightHandPosition", handPosition);
|
||||
_animVars.set("rightHandRotation", params.rightOrientation);
|
||||
_animVars.set("rightHandRotation", handRotation);
|
||||
_animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition);
|
||||
|
||||
_isRightHandControlled = true;
|
||||
_lastRightHandControlledPose = AnimPose(glm::vec3(1.0f), params.rightOrientation, handPosition);
|
||||
_lastRightHandControlledPose = AnimPose(Vectors::ONE, handRotation, handPosition);
|
||||
} else {
|
||||
if (_isRightHandControlled) {
|
||||
_rightHandRelaxDuration = RELAX_DURATION;
|
||||
_rightHandRelaxTimeRemaining = RELAX_DURATION;
|
||||
_isRightHandControlled = false;
|
||||
}
|
||||
|
||||
if (_rightHandRelaxDuration > 0) {
|
||||
if (_rightHandRelaxTimeRemaining > 0.0f) {
|
||||
// Move hand from controlled position to non-controlled position.
|
||||
_rightHandRelaxDuration = std::max(_rightHandRelaxDuration - dt, 0.0f);
|
||||
auto ikNode = getAnimInverseKinematicsNode();
|
||||
if (ikNode) {
|
||||
float alpha = 1.0f - _rightHandRelaxDuration / RELAX_DURATION;
|
||||
const AnimPose geometryToRigTransform(_geometryToRigTransform);
|
||||
AnimPose uncontrolledHandPose = geometryToRigTransform * ikNode->getUncontrolledRightHandPose();
|
||||
AnimPose handPose;
|
||||
::blend(1, &_lastRightHandControlledPose, &uncontrolledHandPose, alpha, &handPose);
|
||||
_rightHandRelaxTimeRemaining = std::max(_rightHandRelaxTimeRemaining - dt, 0.0f);
|
||||
AnimPose handPose;
|
||||
if (transitionHandPose(_rightHandRelaxTimeRemaining, RELAX_DURATION, _lastRightHandControlledPose, RIGHT_HAND,
|
||||
FROM_CONTROLLED, handPose)) {
|
||||
_animVars.set("rightHandPosition", handPose.trans());
|
||||
_animVars.set("rightHandRotation", handPose.rot());
|
||||
_animVars.set("rightHandType", (int)IKTarget::Type::RotationAndPosition);
|
||||
|
@ -1545,3 +1576,25 @@ void Rig::computeAvatarBoundingCapsule(
|
|||
glm::vec3 rigCenter = (geometryToRig * (0.5f * (totalExtents.maximum + totalExtents.minimum)));
|
||||
localOffsetOut = rigCenter - (geometryToRig * rootPosition);
|
||||
}
|
||||
|
||||
bool Rig::transitionHandPose(float deltaTime, float totalDuration, AnimPose& controlledHandPose, bool isLeftHand,
|
||||
bool isToControlled, AnimPose& returnHandPose) {
|
||||
auto ikNode = getAnimInverseKinematicsNode();
|
||||
if (ikNode) {
|
||||
float alpha = 1.0f - deltaTime / totalDuration;
|
||||
const AnimPose geometryToRigTransform(_geometryToRigTransform);
|
||||
AnimPose uncontrolledHandPose;
|
||||
if (isLeftHand) {
|
||||
uncontrolledHandPose = geometryToRigTransform * ikNode->getUncontrolledLeftHandPose();
|
||||
} else {
|
||||
uncontrolledHandPose = geometryToRigTransform * ikNode->getUncontrolledRightHandPose();
|
||||
}
|
||||
if (isToControlled) {
|
||||
::blend(1, &uncontrolledHandPose, &controlledHandPose, alpha, &returnHandPose);
|
||||
} else {
|
||||
::blend(1, &controlledHandPose, &uncontrolledHandPose, alpha, &returnHandPose);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -352,10 +352,15 @@ private:
|
|||
int _nextStateHandlerId { 0 };
|
||||
QMutex _stateMutex;
|
||||
|
||||
bool transitionHandPose(float deltaTime, float totalDuration, AnimPose& controlledHandPose, bool isLeftHand,
|
||||
bool isToControlled, AnimPose& returnHandPose);
|
||||
|
||||
bool _isLeftHandControlled { false };
|
||||
bool _isRightHandControlled { false };
|
||||
float _leftHandRelaxDuration { 0.0f };
|
||||
float _rightHandRelaxDuration { 0.0f };
|
||||
float _leftHandControlTimeRemaining { 0.0f };
|
||||
float _rightHandControlTimeRemaining { 0.0f };
|
||||
float _leftHandRelaxTimeRemaining { 0.0f };
|
||||
float _rightHandRelaxTimeRemaining { 0.0f };
|
||||
AnimPose _lastLeftHandControlledPose;
|
||||
AnimPose _lastRightHandControlledPose;
|
||||
};
|
||||
|
|
|
@ -184,6 +184,8 @@ AudioClient::AudioClient() :
|
|||
checkDevices();
|
||||
});
|
||||
});
|
||||
const unsigned long DEVICE_CHECK_INTERVAL_MSECS = 2 * 1000;
|
||||
_checkDevicesTimer->start(DEVICE_CHECK_INTERVAL_MSECS);
|
||||
|
||||
|
||||
configureReverb();
|
||||
|
@ -393,6 +395,11 @@ QAudioDeviceInfo defaultAudioDeviceForMode(QAudio::Mode mode) {
|
|||
return (mode == QAudio::AudioInput) ? QAudioDeviceInfo::defaultInputDevice() : QAudioDeviceInfo::defaultOutputDevice();
|
||||
}
|
||||
|
||||
bool AudioClient::getNamedAudioDeviceForModeExists(QAudio::Mode mode, const QString& deviceName) {
|
||||
return (getNamedAudioDeviceForMode(mode, deviceName).deviceName() == deviceName);
|
||||
}
|
||||
|
||||
|
||||
// attempt to use the native sample rate and channel count
|
||||
bool nativeFormatForAudioDevice(const QAudioDeviceInfo& audioDevice,
|
||||
QAudioFormat& audioFormat) {
|
||||
|
|
|
@ -149,6 +149,8 @@ public:
|
|||
|
||||
static const float CALLBACK_ACCELERATOR_RATIO;
|
||||
|
||||
bool getNamedAudioDeviceForModeExists(QAudio::Mode mode, const QString& deviceName);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
static QString friendlyNameForAudioDevice(wchar_t* guid);
|
||||
#endif
|
||||
|
|
|
@ -1504,7 +1504,7 @@ QUrl AvatarData::cannonicalSkeletonModelURL(const QUrl& emptyURL) const {
|
|||
return _skeletonModelURL.scheme() == "file" ? emptyURL : _skeletonModelURL;
|
||||
}
|
||||
|
||||
void AvatarData::processAvatarIdentity(const Identity& identity, bool& identityChanged, bool& displayNameChanged) {
|
||||
void AvatarData::processAvatarIdentity(const Identity& identity, bool& identityChanged, bool& displayNameChanged, bool& skeletonModelUrlChanged) {
|
||||
|
||||
if (identity.sequenceId < _identitySequenceId) {
|
||||
qCDebug(avatars) << "Ignoring older identity packet for avatar" << getSessionUUID()
|
||||
|
@ -1517,6 +1517,7 @@ void AvatarData::processAvatarIdentity(const Identity& identity, bool& identityC
|
|||
if (_firstSkeletonCheck || (identity.skeletonModelURL != cannonicalSkeletonModelURL(emptyURL))) {
|
||||
setSkeletonModelURL(identity.skeletonModelURL);
|
||||
identityChanged = true;
|
||||
skeletonModelUrlChanged = true;
|
||||
if (_firstSkeletonCheck) {
|
||||
displayNameChanged = true;
|
||||
}
|
||||
|
|
|
@ -368,6 +368,7 @@ public:
|
|||
virtual ~AvatarData();
|
||||
|
||||
static const QUrl& defaultFullAvatarModelUrl();
|
||||
QUrl cannonicalSkeletonModelURL(const QUrl& empty) const;
|
||||
|
||||
virtual bool isMyAvatar() const { return false; }
|
||||
|
||||
|
@ -536,9 +537,8 @@ public:
|
|||
|
||||
static void parseAvatarIdentityPacket(const QByteArray& data, Identity& identityOut);
|
||||
|
||||
// identityChanged returns true if identity has changed, false otherwise.
|
||||
// displayNameChanged returns true if displayName has changed, false otherwise.
|
||||
void processAvatarIdentity(const Identity& identity, bool& identityChanged, bool& displayNameChanged);
|
||||
// identityChanged returns true if identity has changed, false otherwise. Similarly for displayNameChanged and skeletonModelUrlChange.
|
||||
void processAvatarIdentity(const Identity& identity, bool& identityChanged, bool& displayNameChanged, bool& skeletonModelUrlChanged);
|
||||
|
||||
QByteArray identityByteArray() const;
|
||||
|
||||
|
@ -697,7 +697,6 @@ protected:
|
|||
QVector<AttachmentData> _attachmentData;
|
||||
QString _displayName;
|
||||
QString _sessionDisplayName { };
|
||||
QUrl cannonicalSkeletonModelURL(const QUrl& empty) const;
|
||||
|
||||
QHash<QString, int> _jointIndices; ///< 1-based, since zero is returned for missing keys
|
||||
QStringList _jointNames; ///< in order of depth-first traversal
|
||||
|
|
|
@ -148,8 +148,9 @@ void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer<ReceivedMessage>
|
|||
auto avatar = newOrExistingAvatar(identity.uuid, sendingNode);
|
||||
bool identityChanged = false;
|
||||
bool displayNameChanged = false;
|
||||
bool skeletonModelUrlChanged = false;
|
||||
// In this case, the "sendingNode" is the Avatar Mixer.
|
||||
avatar->processAvatarIdentity(identity, identityChanged, displayNameChanged);
|
||||
avatar->processAvatarIdentity(identity, identityChanged, displayNameChanged, skeletonModelUrlChanged);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -605,7 +605,7 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori
|
|||
|
||||
QString extraInfo;
|
||||
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance,
|
||||
face, surfaceNormal, extraInfo, precisionPicking, precisionPicking);
|
||||
face, surfaceNormal, extraInfo, precisionPicking, false);
|
||||
}
|
||||
|
||||
void RenderableModelEntityItem::getCollisionGeometryResource() {
|
||||
|
|
|
@ -460,17 +460,11 @@ FBXLight extractLight(const FBXNode& object) {
|
|||
}
|
||||
|
||||
QByteArray fileOnUrl(const QByteArray& filepath, const QString& url) {
|
||||
QString path = QFileInfo(url).path();
|
||||
QByteArray filename = filepath;
|
||||
QFileInfo checkFile(path + "/" + filepath);
|
||||
// in order to match the behaviour when loading models from remote URLs
|
||||
// we assume that all external textures are right beside the loaded model
|
||||
// ignoring any relative paths or absolute paths inside of models
|
||||
|
||||
// check if the file exists at the RelativeFilename
|
||||
if (!(checkFile.exists() && checkFile.isFile())) {
|
||||
// if not, assume it is in the fbx directory
|
||||
filename = filename.mid(filename.lastIndexOf('/') + 1);
|
||||
}
|
||||
|
||||
return filename;
|
||||
return filepath.mid(filepath.lastIndexOf('/') + 1);
|
||||
}
|
||||
|
||||
FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QString& url) {
|
||||
|
|
|
@ -277,6 +277,23 @@ QString getEventBridgeJavascript() {
|
|||
return javaScriptToInject;
|
||||
}
|
||||
|
||||
class EventBridgeWrapper : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QObject* eventBridge READ getEventBridge CONSTANT);
|
||||
|
||||
public:
|
||||
EventBridgeWrapper(QObject* eventBridge, QObject* parent = nullptr) : QObject(parent), _eventBridge(eventBridge) {
|
||||
}
|
||||
|
||||
QObject* getEventBridge() {
|
||||
return _eventBridge;
|
||||
}
|
||||
|
||||
private:
|
||||
QObject* _eventBridge;
|
||||
};
|
||||
|
||||
|
||||
|
||||
QQmlEngine* acquireEngine(QQuickWindow* window) {
|
||||
Q_ASSERT(QThread::currentThread() == qApp->thread());
|
||||
|
@ -430,7 +447,6 @@ OffscreenQmlSurface::~OffscreenQmlSurface() {
|
|||
|
||||
_canvas->deleteLater();
|
||||
_rootItem->deleteLater();
|
||||
_qmlComponent->deleteLater();
|
||||
_quickWindow->deleteLater();
|
||||
releaseEngine();
|
||||
}
|
||||
|
@ -473,11 +489,12 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
|
|||
_qmlContext = new QQmlContext(qmlEngine->rootContext());
|
||||
|
||||
_qmlContext->setContextProperty("offscreenWindow", QVariant::fromValue(getWindow()));
|
||||
_qmlContext->setContextProperty("globalEventBridge", this);
|
||||
_qmlContext->setContextProperty("eventBridge", this);
|
||||
_qmlContext->setContextProperty("webEntity", this);
|
||||
|
||||
_qmlComponent = new QQmlComponent(qmlEngine);
|
||||
|
||||
// FIXME Compatibility mechanism for existing HTML and JS that uses eventBridgeWrapper
|
||||
// Find a way to flag older scripts using this mechanism and wanr that this is deprecated
|
||||
_qmlContext->setContextProperty("eventBridgeWrapper", new EventBridgeWrapper(this, _qmlContext));
|
||||
|
||||
if (!_canvas->makeCurrent()) {
|
||||
qWarning("Failed to make context current for QML Renderer");
|
||||
|
@ -577,71 +594,79 @@ void OffscreenQmlSurface::setBaseUrl(const QUrl& baseUrl) {
|
|||
_qmlContext->setBaseUrl(baseUrl);
|
||||
}
|
||||
|
||||
QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) {
|
||||
QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, std::function<void(QQmlContext*, QObject*)> f) {
|
||||
// Synchronous loading may take a while; restart the deadlock timer
|
||||
QMetaObject::invokeMethod(qApp, "updateHeartbeat", Qt::DirectConnection);
|
||||
|
||||
if ((qmlSource.isRelative() && !qmlSource.isEmpty()) || qmlSource.scheme() == QLatin1String("file")) {
|
||||
_qmlComponent->loadUrl(_qmlContext->resolvedUrl(qmlSource), QQmlComponent::PreferSynchronous);
|
||||
} else {
|
||||
_qmlComponent->loadUrl(qmlSource, QQmlComponent::PreferSynchronous);
|
||||
QQmlContext* targetContext = _qmlContext;
|
||||
if (_rootItem && createNewContext) {
|
||||
targetContext = new QQmlContext(targetContext);
|
||||
}
|
||||
|
||||
QUrl finalQmlSource = qmlSource;
|
||||
if ((qmlSource.isRelative() && !qmlSource.isEmpty()) || qmlSource.scheme() == QLatin1String("file")) {
|
||||
finalQmlSource = _qmlContext->resolvedUrl(qmlSource);
|
||||
}
|
||||
|
||||
if (_qmlComponent->isLoading()) {
|
||||
connect(_qmlComponent, &QQmlComponent::statusChanged, this,
|
||||
[this, f](QQmlComponent::Status){
|
||||
finishQmlLoad(f);
|
||||
});
|
||||
auto qmlComponent = new QQmlComponent(_qmlContext->engine(), finalQmlSource, QQmlComponent::PreferSynchronous);
|
||||
if (qmlComponent->isLoading()) {
|
||||
connect(qmlComponent, &QQmlComponent::statusChanged, this,
|
||||
[this, qmlComponent, targetContext, f](QQmlComponent::Status) {
|
||||
finishQmlLoad(qmlComponent, targetContext, f);
|
||||
});
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return finishQmlLoad(f);
|
||||
return finishQmlLoad(qmlComponent, targetContext, f);
|
||||
}
|
||||
|
||||
QObject* OffscreenQmlSurface::loadInNewContext(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) {
|
||||
return load(qmlSource, true, f);
|
||||
}
|
||||
|
||||
QObject* OffscreenQmlSurface::load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f) {
|
||||
return load(qmlSource, false, f);
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::clearCache() {
|
||||
_qmlContext->engine()->clearComponentCache();
|
||||
}
|
||||
|
||||
QObject* OffscreenQmlSurface::finishQmlLoad(std::function<void(QQmlContext*, QObject*)> f) {
|
||||
#if 0
|
||||
if (!_rootItem) {
|
||||
QQmlComponent component(_qmlContext->engine());
|
||||
component.setData(R"QML(
|
||||
import QtQuick 2.0
|
||||
import QtWebChannel 1.0
|
||||
Item { Component.onCompleted: globalEventBridge.WebChannel.id = "globalEventBridge"; }
|
||||
)QML", QUrl());
|
||||
QObject *helper = component.create(_qmlContext);
|
||||
qDebug() << "Created helper";
|
||||
}
|
||||
#endif
|
||||
disconnect(_qmlComponent, &QQmlComponent::statusChanged, this, 0);
|
||||
if (_qmlComponent->isError()) {
|
||||
QList<QQmlError> errorList = _qmlComponent->errors();
|
||||
foreach(const QQmlError& error, errorList) {
|
||||
qWarning() << error.url() << error.line() << error;
|
||||
QObject* OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function<void(QQmlContext*, QObject*)> f) {
|
||||
disconnect(qmlComponent, &QQmlComponent::statusChanged, this, 0);
|
||||
if (qmlComponent->isError()) {
|
||||
for (const auto& error : qmlComponent->errors()) {
|
||||
qCWarning(glLogging) << error.url() << error.line() << error;
|
||||
}
|
||||
qmlComponent->deleteLater();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
QObject* newObject = _qmlComponent->beginCreate(_qmlContext);
|
||||
if (_qmlComponent->isError()) {
|
||||
QList<QQmlError> errorList = _qmlComponent->errors();
|
||||
foreach(const QQmlError& error, errorList)
|
||||
QObject* newObject = qmlComponent->beginCreate(qmlContext);
|
||||
if (qmlComponent->isError()) {
|
||||
for (const auto& error : qmlComponent->errors()) {
|
||||
qCWarning(glLogging) << error.url() << error.line() << error;
|
||||
}
|
||||
if (!_rootItem) {
|
||||
qFatal("Unable to finish loading QML root");
|
||||
}
|
||||
qmlComponent->deleteLater();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
_qmlContext->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
newObject->setProperty("eventBridge", QVariant::fromValue(this));
|
||||
qmlContext->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
f(qmlContext, newObject);
|
||||
|
||||
f(_qmlContext, newObject);
|
||||
_qmlComponent->completeCreate();
|
||||
QObject* eventBridge = qmlContext->contextProperty("eventBridge").value<QObject*>();
|
||||
if (qmlContext != _qmlContext && eventBridge && eventBridge != this) {
|
||||
// FIXME Compatibility mechanism for existing HTML and JS that uses eventBridgeWrapper
|
||||
// Find a way to flag older scripts using this mechanism and wanr that this is deprecated
|
||||
qmlContext->setContextProperty("eventBridgeWrapper", new EventBridgeWrapper(eventBridge, qmlContext));
|
||||
}
|
||||
|
||||
qmlComponent->completeCreate();
|
||||
qmlComponent->deleteLater();
|
||||
|
||||
|
||||
// All quick items should be focusable
|
||||
|
|
|
@ -48,6 +48,8 @@ public:
|
|||
void resize(const QSize& size, bool forceResize = false);
|
||||
QSize size() const;
|
||||
|
||||
Q_INVOKABLE QObject* load(const QUrl& qmlSource, bool createNewContext, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {});
|
||||
Q_INVOKABLE QObject* loadInNewContext(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {});
|
||||
Q_INVOKABLE QObject* load(const QUrl& qmlSource, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {});
|
||||
Q_INVOKABLE QObject* load(const QString& qmlSourceFile, std::function<void(QQmlContext*, QObject*)> f = [](QQmlContext*, QObject*) {}) {
|
||||
return load(QUrl(qmlSourceFile), f);
|
||||
|
@ -118,7 +120,7 @@ protected:
|
|||
void setFocusText(bool newFocusText);
|
||||
|
||||
private:
|
||||
QObject* finishQmlLoad(std::function<void(QQmlContext*, QObject*)> f);
|
||||
QObject* finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function<void(QQmlContext*, QObject*)> f);
|
||||
QPointF mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject);
|
||||
void setupFbo();
|
||||
bool allowNewFrame(uint8_t fps);
|
||||
|
@ -134,7 +136,6 @@ private:
|
|||
QQuickWindow* _quickWindow { nullptr };
|
||||
QMyQuickRenderControl* _renderControl{ nullptr };
|
||||
QQmlContext* _qmlContext { nullptr };
|
||||
QQmlComponent* _qmlComponent { nullptr };
|
||||
QQuickItem* _rootItem { nullptr };
|
||||
OffscreenGLCanvas* _canvas { nullptr };
|
||||
|
||||
|
|
|
@ -63,11 +63,17 @@ void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) {
|
|||
int useScissor = batch._params[paramOffset + 0]._int;
|
||||
|
||||
GLuint glmask = 0;
|
||||
bool restoreStencilMask = false;
|
||||
uint8_t cacheStencilMask = 0xFF;
|
||||
if (masks & Framebuffer::BUFFER_STENCIL) {
|
||||
glClearStencil(stencil);
|
||||
glmask |= GL_STENCIL_BUFFER_BIT;
|
||||
// TODO: we will probably need to also check the write mask of stencil like we do
|
||||
// for depth buffer, but as would say a famous Fez owner "We'll cross that bridge when we come to it"
|
||||
|
||||
cacheStencilMask = _pipeline._stateCache.stencilActivation.getWriteMaskFront();
|
||||
if (cacheStencilMask != 0xFF) {
|
||||
restoreStencilMask = true;
|
||||
glStencilMask( 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
bool restoreDepthMask = false;
|
||||
|
@ -121,6 +127,11 @@ void GLBackend::do_clearFramebuffer(const Batch& batch, size_t paramOffset) {
|
|||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
// Restore Stencil write mask
|
||||
if (restoreStencilMask) {
|
||||
glStencilMask(cacheStencilMask);
|
||||
}
|
||||
|
||||
// Restore write mask meaning turn back off
|
||||
if (restoreDepthMask) {
|
||||
glDepthMask(GL_FALSE);
|
||||
|
|
|
@ -584,7 +584,7 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t
|
|||
return matchingNode;
|
||||
} else {
|
||||
// we didn't have this node, so add them
|
||||
Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, permissions, connectionSecret, this);
|
||||
Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket, permissions, connectionSecret);
|
||||
|
||||
if (nodeType == NodeType::AudioMixer) {
|
||||
LimitedNodeList::flagTimeForConnectionStep(LimitedNodeList::AddedAudioMixer);
|
||||
|
@ -617,24 +617,28 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t
|
|||
}
|
||||
|
||||
// insert the new node and release our read lock
|
||||
_nodeHash.insert(UUIDNodePair(newNode->getUUID(), newNodePointer));
|
||||
_nodeHash.emplace(newNode->getUUID(), newNodePointer);
|
||||
readLocker.unlock();
|
||||
|
||||
qCDebug(networking) << "Added" << *newNode;
|
||||
|
||||
auto weakPtr = newNodePointer.toWeakRef(); // We don't want the lambdas to hold a strong ref
|
||||
|
||||
emit nodeAdded(newNodePointer);
|
||||
if (newNodePointer->getActiveSocket()) {
|
||||
emit nodeActivated(newNodePointer);
|
||||
} else {
|
||||
connect(newNodePointer.data(), &NetworkPeer::socketActivated, this, [=] {
|
||||
emit nodeActivated(newNodePointer);
|
||||
disconnect(newNodePointer.data(), &NetworkPeer::socketActivated, this, 0);
|
||||
connect(newNodePointer.data(), &NetworkPeer::socketActivated, this, [this, weakPtr] {
|
||||
auto sharedPtr = weakPtr.lock();
|
||||
if (sharedPtr) {
|
||||
emit nodeActivated(sharedPtr);
|
||||
disconnect(sharedPtr.data(), &NetworkPeer::socketActivated, this, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Signal when a socket changes, so we can start the hole punch over.
|
||||
auto weakPtr = newNodePointer.toWeakRef(); // We don't want the lambda to hold a strong ref
|
||||
connect(newNodePointer.data(), &NetworkPeer::socketUpdated, this, [=] {
|
||||
connect(newNodePointer.data(), &NetworkPeer::socketUpdated, this, [this, weakPtr] {
|
||||
emit nodeSocketUpdated(weakPtr);
|
||||
});
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
Node(const QUuid& uuid, NodeType_t type,
|
||||
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket,
|
||||
const NodePermissions& permissions, const QUuid& connectionSecret = QUuid(),
|
||||
QObject* parent = 0);
|
||||
QObject* parent = nullptr);
|
||||
|
||||
bool operator==(const Node& otherNode) const { return _uuid == otherNode._uuid; }
|
||||
bool operator!=(const Node& otherNode) const { return !(*this == otherNode); }
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
class ReceivedPacketProcessor : public GenericThread {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static const uint64_t MAX_WAIT_TIME { 100 }; // Max wait time in ms
|
||||
|
||||
ReceivedPacketProcessor();
|
||||
|
||||
/// Add packet from network receive thread to the processing queue.
|
||||
|
@ -63,8 +65,8 @@ protected:
|
|||
/// Implements generic processing behavior for this thread.
|
||||
virtual bool process() override;
|
||||
|
||||
/// Determines the timeout of the wait when there are no packets to process. Default value means no timeout
|
||||
virtual unsigned long getMaxWait() const { return ULONG_MAX; }
|
||||
/// Determines the timeout of the wait when there are no packets to process. Default value is 100ms to allow for regular event processing.
|
||||
virtual uint32_t getMaxWait() const { return MAX_WAIT_TIME; }
|
||||
|
||||
/// Override to do work before the packets processing loop. Default does nothing.
|
||||
virtual void preProcess() { }
|
||||
|
|
|
@ -56,7 +56,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
|||
case PacketType::AvatarData:
|
||||
case PacketType::BulkAvatarData:
|
||||
case PacketType::KillAvatar:
|
||||
return static_cast<PacketVersion>(AvatarMixerPacketVersion::AvatarIdentitySequenceId);
|
||||
return static_cast<PacketVersion>(AvatarMixerPacketVersion::MannequinDefaultAvatar);
|
||||
case PacketType::MessagesData:
|
||||
return static_cast<PacketVersion>(MessageDataVersion::TextOrBinaryData);
|
||||
case PacketType::ICEServerHeartbeat:
|
||||
|
|
|
@ -236,7 +236,8 @@ enum class AvatarMixerPacketVersion : PacketVersion {
|
|||
AvatarAsChildFixes,
|
||||
StickAndBallDefaultAvatar,
|
||||
IdentityPacketsIncludeUpdateTime,
|
||||
AvatarIdentitySequenceId
|
||||
AvatarIdentitySequenceId,
|
||||
MannequinDefaultAvatar
|
||||
};
|
||||
|
||||
enum class DomainConnectRequestVersion : PacketVersion {
|
||||
|
|
|
@ -35,14 +35,13 @@ void JurisdictionListener::nodeKilled(SharedNodePointer node) {
|
|||
}
|
||||
|
||||
bool JurisdictionListener::queueJurisdictionRequest() {
|
||||
auto packet = NLPacket::create(PacketType::JurisdictionRequest, 0);
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
int nodeCount = 0;
|
||||
|
||||
nodeList->eachNode([&](const SharedNodePointer& node) {
|
||||
if (node->getType() == getNodeType() && node->getActiveSocket()) {
|
||||
auto packet = NLPacket::create(PacketType::JurisdictionRequest, 0);
|
||||
_packetSender.queuePacketForSending(node, std::move(packet));
|
||||
nodeCount++;
|
||||
}
|
||||
|
|
|
@ -41,8 +41,6 @@ bool JurisdictionSender::process() {
|
|||
|
||||
// call our ReceivedPacketProcessor base class process so we'll get any pending packets
|
||||
if (continueProcessing && (continueProcessing = ReceivedPacketProcessor::process())) {
|
||||
auto packet = (_jurisdictionMap) ? _jurisdictionMap->packIntoPacket()
|
||||
: JurisdictionMap::packEmptyJurisdictionIntoMessage(getNodeType());
|
||||
int nodeCount = 0;
|
||||
|
||||
lockRequestingNodes();
|
||||
|
@ -53,6 +51,8 @@ bool JurisdictionSender::process() {
|
|||
SharedNodePointer node = DependencyManager::get<NodeList>()->nodeWithUUID(nodeUUID);
|
||||
|
||||
if (node && node->getActiveSocket()) {
|
||||
auto packet = (_jurisdictionMap) ? _jurisdictionMap->packIntoPacket()
|
||||
: JurisdictionMap::packEmptyJurisdictionIntoMessage(getNodeType());
|
||||
_packetSender.queuePacketForSending(node, std::move(packet));
|
||||
nodeCount++;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include "AntialiasingEffect.h"
|
||||
#include "StencilMaskPass.h"
|
||||
#include "TextureCache.h"
|
||||
#include "FramebufferCache.h"
|
||||
#include "DependencyManager.h"
|
||||
#include "ViewFrustum.h"
|
||||
#include "GeometryCache.h"
|
||||
|
@ -40,9 +39,9 @@ Antialiasing::~Antialiasing() {
|
|||
}
|
||||
}
|
||||
|
||||
const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() {
|
||||
int width = DependencyManager::get<FramebufferCache>()->getFrameBufferSize().width();
|
||||
int height = DependencyManager::get<FramebufferCache>()->getFrameBufferSize().height();
|
||||
const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline(RenderArgs* args) {
|
||||
int width = args->_viewport.z;
|
||||
int height = args->_viewport.w;
|
||||
|
||||
if (_antialiasingBuffer && _antialiasingBuffer->getSize() != uvec2(width, height)) {
|
||||
_antialiasingBuffer.reset();
|
||||
|
@ -51,7 +50,7 @@ const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() {
|
|||
if (!_antialiasingBuffer) {
|
||||
// Link the antialiasing FBO to texture
|
||||
_antialiasingBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("antialiasing"));
|
||||
auto format = gpu::Element::COLOR_SRGBA_32; // DependencyManager::get<FramebufferCache>()->getLightingTexture()->getTexelFormat();
|
||||
auto format = gpu::Element::COLOR_SRGBA_32;
|
||||
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
|
||||
_antialiasingTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, defaultSampler);
|
||||
_antialiasingBuffer->setRenderBuffer(0, _antialiasingTexture);
|
||||
|
@ -110,19 +109,13 @@ void Antialiasing::run(const render::RenderContextPointer& renderContext, const
|
|||
|
||||
RenderArgs* args = renderContext->args;
|
||||
|
||||
if (args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
|
||||
return;
|
||||
}
|
||||
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
|
||||
// FIXME: NEED to simplify that code to avoid all the GeometryCahce call, this is purely pixel manipulation
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
QSize framebufferSize = framebufferCache->getFrameBufferSize();
|
||||
float fbWidth = framebufferSize.width();
|
||||
float fbHeight = framebufferSize.height();
|
||||
float fbWidth = renderContext->args->_viewport.z;
|
||||
float fbHeight = renderContext->args->_viewport.w;
|
||||
// float sMin = args->_viewport.x / fbWidth;
|
||||
// float sWidth = args->_viewport.z / fbWidth;
|
||||
// float tMin = args->_viewport.y / fbHeight;
|
||||
|
@ -137,10 +130,10 @@ void Antialiasing::run(const render::RenderContextPointer& renderContext, const
|
|||
batch.setModelTransform(Transform());
|
||||
|
||||
// FXAA step
|
||||
getAntialiasingPipeline();
|
||||
auto pipeline = getAntialiasingPipeline(renderContext->args);
|
||||
batch.setResourceTexture(0, sourceBuffer->getRenderBuffer(0));
|
||||
batch.setFramebuffer(_antialiasingBuffer);
|
||||
batch.setPipeline(getAntialiasingPipeline());
|
||||
batch.setPipeline(pipeline);
|
||||
|
||||
// initialize the view-space unpacking uniforms using frustum data
|
||||
float left, right, bottom, top, nearVal, farVal;
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
void configure(const Config& config) {}
|
||||
void run(const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& sourceBuffer);
|
||||
|
||||
const gpu::PipelinePointer& getAntialiasingPipeline();
|
||||
const gpu::PipelinePointer& getAntialiasingPipeline(RenderArgs* args);
|
||||
const gpu::PipelinePointer& getBlendPipeline();
|
||||
|
||||
private:
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include <ViewFrustum.h>
|
||||
|
||||
#include "GeometryCache.h"
|
||||
#include "FramebufferCache.h"
|
||||
#include "TextureCache.h"
|
||||
#include "DeferredLightingEffect.h"
|
||||
|
||||
|
@ -410,7 +409,6 @@ void DebugDeferredBuffer::run(const RenderContextPointer& renderContext, const I
|
|||
batch.setViewportTransform(args->_viewport);
|
||||
|
||||
const auto geometryBuffer = DependencyManager::get<GeometryCache>();
|
||||
const auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
const auto textureCache = DependencyManager::get<TextureCache>();
|
||||
|
||||
glm::mat4 projMat;
|
||||
|
|
|
@ -418,10 +418,7 @@ model::MeshPointer DeferredLightingEffect::getSpotLightMesh() {
|
|||
}
|
||||
|
||||
void PreparePrimaryFramebuffer::run(const RenderContextPointer& renderContext, gpu::FramebufferPointer& primaryFramebuffer) {
|
||||
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
auto framebufferSize = framebufferCache->getFrameBufferSize();
|
||||
glm::uvec2 frameSize(framebufferSize.width(), framebufferSize.height());
|
||||
glm::uvec2 frameSize(renderContext->args->_viewport.z, renderContext->args->_viewport.w);
|
||||
|
||||
// Resizing framebuffers instead of re-building them seems to cause issues with threaded
|
||||
// rendering
|
||||
|
@ -504,10 +501,7 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext,
|
|||
{
|
||||
// Framebuffer copy operations cannot function as multipass stereo operations.
|
||||
batch.enableStereo(false);
|
||||
|
||||
// perform deferred lighting, rendering to free fbo
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
|
||||
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();
|
||||
|
||||
|
|
|
@ -152,9 +152,9 @@ public:
|
|||
int numInputLights { 0 };
|
||||
int numClusteredLights { 0 };
|
||||
|
||||
void setNumClusteredLightReferences(int numRefs) { numClusteredLightReferences = numRefs; emit dirty(); }
|
||||
void setNumInputLights(int numLights) { numInputLights = numLights; emit dirty(); }
|
||||
void setNumClusteredLights(int numLights) { numClusteredLights = numLights; emit dirty(); }
|
||||
void setNumClusteredLightReferences(int numRefs) { numClusteredLightReferences = numRefs; }
|
||||
void setNumInputLights(int numLights) { numInputLights = numLights; }
|
||||
void setNumClusteredLights(int numLights) { numClusteredLights = numLights; }
|
||||
|
||||
int numSceneLights { 0 };
|
||||
int numFreeSceneLights { 0 };
|
||||
|
|
|
@ -48,6 +48,7 @@ void RenderShadowMap::run(const render::RenderContextPointer& renderContext,
|
|||
RenderArgs* args = renderContext->args;
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
args->_batch = &batch;
|
||||
batch.enableStereo(false);
|
||||
|
||||
glm::ivec4 viewport{0, 0, fbo->getWidth(), fbo->getHeight()};
|
||||
batch.setViewportTransform(viewport);
|
||||
|
@ -114,7 +115,7 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
|
|||
skinProgram, state);
|
||||
}
|
||||
|
||||
const auto cachedMode = task.addJob<RenderShadowSetup>("Setup");
|
||||
const auto cachedMode = task.addJob<RenderShadowSetup>("ShadowSetup");
|
||||
|
||||
// CPU jobs:
|
||||
// Fetch and cull the items from the scene
|
||||
|
@ -129,7 +130,7 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
|
|||
// GPU jobs: Render to shadow map
|
||||
task.addJob<RenderShadowMap>("RenderShadowMap", sortedShapes, shapePlumber);
|
||||
|
||||
task.addJob<RenderShadowTeardown>("Teardown", cachedMode);
|
||||
task.addJob<RenderShadowTeardown>("ShadowTeardown", cachedMode);
|
||||
}
|
||||
|
||||
void RenderShadowTask::configure(const Config& configuration) {
|
||||
|
|
33
libraries/render-utils/src/RenderViewTask.cpp
Normal file
33
libraries/render-utils/src/RenderViewTask.cpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// RenderViewTask.cpp
|
||||
// render-utils/src/
|
||||
//
|
||||
// Created by Sam Gateau on 5/25/2017.
|
||||
// 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
|
||||
//
|
||||
#include "RenderViewTask.h"
|
||||
|
||||
#include "RenderShadowTask.h"
|
||||
#include "RenderDeferredTask.h"
|
||||
#include "RenderForwardTask.h"
|
||||
|
||||
|
||||
|
||||
void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, bool isDeferred) {
|
||||
// auto items = input.get<Input>();
|
||||
|
||||
task.addJob<RenderShadowTask>("RenderShadowTask", cullFunctor);
|
||||
|
||||
const auto items = task.addJob<RenderFetchCullSortTask>("FetchCullSort", cullFunctor);
|
||||
assert(items.canCast<RenderFetchCullSortTask::Output>());
|
||||
|
||||
if (isDeferred) {
|
||||
task.addJob<RenderDeferredTask>("RenderDeferredTask", items);
|
||||
} else {
|
||||
task.addJob<RenderForwardTask>("Forward", items);
|
||||
}
|
||||
}
|
||||
|
31
libraries/render-utils/src/RenderViewTask.h
Normal file
31
libraries/render-utils/src/RenderViewTask.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// RenderViewTask.h
|
||||
// render-utils/src/
|
||||
//
|
||||
// Created by Sam Gateau on 5/25/2017.
|
||||
// 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
|
||||
//
|
||||
#pragma once
|
||||
#ifndef hifi_RenderViewTask_h
|
||||
#define hifi_RenderViewTask_h
|
||||
|
||||
#include <render/Engine.h>
|
||||
#include <render/RenderFetchCullSortTask.h>
|
||||
|
||||
|
||||
class RenderViewTask {
|
||||
public:
|
||||
using Input = RenderFetchCullSortTask::Output;
|
||||
using JobModel = render::Task::ModelI<RenderViewTask, Input>;
|
||||
|
||||
RenderViewTask() {}
|
||||
|
||||
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // hifi_RenderViewTask_h
|
|
@ -14,6 +14,8 @@
|
|||
#include "../RenderUtilsLogging.h"
|
||||
#include "FontFamilies.h"
|
||||
|
||||
static std::mutex fontMutex;
|
||||
|
||||
struct TextureVertex {
|
||||
glm::vec2 pos;
|
||||
glm::vec2 tex;
|
||||
|
@ -56,6 +58,7 @@ Font::Pointer Font::load(QIODevice& fontFile) {
|
|||
}
|
||||
|
||||
Font::Pointer Font::load(const QString& family) {
|
||||
std::lock_guard<std::mutex> lock(fontMutex);
|
||||
if (!LOADED_FONTS.contains(family)) {
|
||||
|
||||
static const QString SDFF_COURIER_PRIME_FILENAME{ ":/CourierPrime.sdff" };
|
||||
|
|
|
@ -31,10 +31,10 @@ public:
|
|||
const glm::vec4* color, EffectType effectType,
|
||||
const glm::vec2& bound, bool layered = false);
|
||||
|
||||
static Pointer load(QIODevice& fontFile);
|
||||
static Pointer load(const QString& family);
|
||||
|
||||
private:
|
||||
static Pointer load(QIODevice& fontFile);
|
||||
QStringList tokenizeForWrapping(const QString& str) const;
|
||||
QStringList splitLines(const QString& str) const;
|
||||
glm::vec2 computeTokenExtent(const QString& str) const;
|
||||
|
|
|
@ -63,6 +63,4 @@ void EngineStats::run(const RenderContextPointer& renderContext) {
|
|||
|
||||
config->frameSetPipelineCount = _gpuStats._PSNumSetPipelines;
|
||||
config->frameSetInputFormatCount = _gpuStats._ISNumFormatChanges;
|
||||
|
||||
config->emitDirty();
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ void TaskConfig::connectChildConfig(QConfigPointer childConfig, const std::strin
|
|||
if (childConfig->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) {
|
||||
// Connect dirty->refresh if defined
|
||||
QObject::connect(childConfig.get(), SIGNAL(dirty()), this, SLOT(refresh()));
|
||||
QObject::connect(childConfig.get(), SIGNAL(dirtyEnabled()), this, SLOT(refresh()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,6 +51,7 @@ void TaskConfig::transferChildrenConfigs(QConfigPointer source) {
|
|||
if (child->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) {
|
||||
// Connect dirty->refresh if defined
|
||||
QObject::connect(child, SIGNAL(dirty()), this, SLOT(refresh()));
|
||||
QObject::connect(child, SIGNAL(dirtyEnabled()), this, SLOT(refresh()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ protected:
|
|||
class JobConfig : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(double cpuRunTime READ getCPURunTime NOTIFY newStats()) //ms
|
||||
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
|
||||
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY dirtyEnabled())
|
||||
|
||||
double _msCPURunTime{ 0.0 };
|
||||
public:
|
||||
|
@ -99,7 +99,7 @@ public:
|
|||
JobConfig(bool enabled) : alwaysEnabled{ false }, enabled{ enabled } {}
|
||||
|
||||
bool isEnabled() { return alwaysEnabled || enabled; }
|
||||
void setEnabled(bool enable) { enabled = alwaysEnabled || enable; }
|
||||
void setEnabled(bool enable) { enabled = alwaysEnabled || enable; emit dirtyEnabled(); }
|
||||
|
||||
bool alwaysEnabled{ true };
|
||||
bool enabled{ true };
|
||||
|
@ -121,6 +121,7 @@ public slots:
|
|||
signals:
|
||||
void loaded();
|
||||
void newStats();
|
||||
void dirtyEnabled();
|
||||
};
|
||||
|
||||
class TaskConfig : public JobConfig {
|
||||
|
|
|
@ -170,6 +170,7 @@ protected:
|
|||
std::string _name = "";
|
||||
};
|
||||
|
||||
|
||||
// A task is a specialized job to run a collection of other jobs
|
||||
// It can be created on any type T by aliasing the type JobModel in the class T
|
||||
// using JobModel = Task::Model<T>
|
||||
|
|
|
@ -540,7 +540,7 @@ void TabletProxy::gotoWebScreen(const QString& url, const QString& injectedJavaS
|
|||
|
||||
QObject* TabletProxy::addButton(const QVariant& properties) {
|
||||
auto tabletButtonProxy = QSharedPointer<TabletButtonProxy>(new TabletButtonProxy(properties.toMap()));
|
||||
std::lock_guard<std::mutex> guard(_tabletMutex);
|
||||
std::unique_lock<std::mutex> guard(_tabletMutex);
|
||||
_tabletButtonProxies.push_back(tabletButtonProxy);
|
||||
if (!_toolbarMode && _qmlTabletRoot) {
|
||||
auto tablet = getQmlTablet();
|
||||
|
@ -550,7 +550,6 @@ QObject* TabletProxy::addButton(const QVariant& properties) {
|
|||
qCCritical(scriptengine) << "Could not find tablet in TabletRoot.qml";
|
||||
}
|
||||
} else if (_toolbarMode) {
|
||||
|
||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||
QObject* toolbarProxy = tabletScriptingInterface->getSystemToolbarProxy();
|
||||
|
||||
|
@ -559,6 +558,8 @@ QObject* TabletProxy::addButton(const QVariant& properties) {
|
|||
connectionType = Qt::BlockingQueuedConnection;
|
||||
}
|
||||
|
||||
guard.unlock();
|
||||
|
||||
// copy properties from tablet button proxy to toolbar button proxy.
|
||||
QObject* toolbarButtonProxy = nullptr;
|
||||
bool hasResult = QMetaObject::invokeMethod(toolbarProxy, "addButton", connectionType, Q_RETURN_ARG(QObject*, toolbarButtonProxy), Q_ARG(QVariant, tabletButtonProxy->getProperties()));
|
||||
|
@ -576,31 +577,38 @@ bool TabletProxy::onHomeScreen() {
|
|||
}
|
||||
|
||||
void TabletProxy::removeButton(QObject* tabletButtonProxy) {
|
||||
std::lock_guard<std::mutex> guard(_tabletMutex);
|
||||
std::unique_lock<std::mutex> guard(_tabletMutex);
|
||||
|
||||
auto tablet = getQmlTablet();
|
||||
if (!tablet) {
|
||||
qCCritical(scriptengine) << "Could not find tablet in TabletRoot.qml";
|
||||
}
|
||||
|
||||
auto iter = std::find(_tabletButtonProxies.begin(), _tabletButtonProxies.end(), tabletButtonProxy);
|
||||
if (iter != _tabletButtonProxies.end()) {
|
||||
if (!_toolbarMode && _qmlTabletRoot) {
|
||||
(*iter)->setQmlButton(nullptr);
|
||||
if (tablet) {
|
||||
QMetaObject::invokeMethod(tablet, "removeButtonProxy", Qt::AutoConnection, Q_ARG(QVariant, (*iter)->getProperties()));
|
||||
}
|
||||
} else if (_toolbarMode) {
|
||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||
QObject* toolbarProxy = tabletScriptingInterface->getSystemToolbarProxy();
|
||||
|
||||
// remove button from toolbarProxy
|
||||
QMetaObject::invokeMethod(toolbarProxy, "removeButton", Qt::AutoConnection, Q_ARG(QVariant, (*iter)->getUuid().toString()));
|
||||
(*iter)->setToolbarButtonProxy(nullptr);
|
||||
QSharedPointer<TabletButtonProxy> buttonProxy;
|
||||
{
|
||||
auto iter = std::find(_tabletButtonProxies.begin(), _tabletButtonProxies.end(), tabletButtonProxy);
|
||||
if (iter == _tabletButtonProxies.end()) {
|
||||
qCWarning(scriptengine) << "TabletProxy::removeButton() could not find button " << tabletButtonProxy;
|
||||
return;
|
||||
}
|
||||
buttonProxy = *iter;
|
||||
_tabletButtonProxies.erase(iter);
|
||||
} else {
|
||||
qCWarning(scriptengine) << "TabletProxy::removeButton() could not find button " << tabletButtonProxy;
|
||||
}
|
||||
|
||||
if (!_toolbarMode && _qmlTabletRoot) {
|
||||
buttonProxy->setQmlButton(nullptr);
|
||||
if (tablet) {
|
||||
guard.unlock();
|
||||
QMetaObject::invokeMethod(tablet, "removeButtonProxy", Qt::AutoConnection, Q_ARG(QVariant, buttonProxy->getProperties()));
|
||||
}
|
||||
} else if (_toolbarMode) {
|
||||
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
|
||||
QObject* toolbarProxy = tabletScriptingInterface->getSystemToolbarProxy();
|
||||
|
||||
// remove button from toolbarProxy
|
||||
guard.unlock();
|
||||
QMetaObject::invokeMethod(toolbarProxy, "removeButton", Qt::AutoConnection, Q_ARG(QVariant, buttonProxy->getUuid().toString()));
|
||||
buttonProxy->setToolbarButtonProxy(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
//
|
||||
|
||||
#include <QDebug>
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
#include "GenericThread.h"
|
||||
|
||||
|
@ -73,6 +74,7 @@ void GenericThread::threadRoutine() {
|
|||
}
|
||||
|
||||
while (!_stopThread) {
|
||||
QCoreApplication::processEvents();
|
||||
|
||||
// override this function to do whatever your class actually does, return false to exit thread early
|
||||
if (!process()) {
|
||||
|
|
|
@ -104,9 +104,9 @@ void QmlWindowClass::initQml(QVariantMap properties) {
|
|||
Q_ASSERT(invokeResult);
|
||||
} else {
|
||||
// Build the event bridge and wrapper on the main thread
|
||||
offscreenUi->load(qmlSource(), [&](QQmlContext* context, QObject* object) {
|
||||
offscreenUi->loadInNewContext(qmlSource(), [&](QQmlContext* context, QObject* object) {
|
||||
_qmlWindow = object;
|
||||
_qmlWindow->setProperty("eventBridge", QVariant::fromValue(this));
|
||||
context->setContextProperty("eventBridge", this);
|
||||
context->engine()->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
context->engine()->setObjectOwnership(object, QQmlEngine::CppOwnership);
|
||||
if (properties.contains(TITLE_PROPERTY)) {
|
||||
|
|
|
@ -10,10 +10,10 @@ if (WIN32)
|
|||
# we're using static GLEW, so define GLEW_STATIC
|
||||
add_definitions(-DGLEW_STATIC)
|
||||
set(TARGET_NAME openvr)
|
||||
setup_hifi_plugin(OpenGL Script Qml Widgets)
|
||||
setup_hifi_plugin(OpenGL Script Qml Widgets Multimedia)
|
||||
link_hifi_libraries(shared gl networking controllers ui
|
||||
plugins display-plugins ui-plugins input-plugins script-engine
|
||||
render-utils model gpu gpu-gl render model-networking fbx ktx image procedural)
|
||||
audio-client render-utils model gpu gpu-gl render model-networking fbx ktx image procedural)
|
||||
|
||||
include_hifi_library_headers(octree)
|
||||
|
||||
|
@ -21,4 +21,5 @@ if (WIN32)
|
|||
find_package(OpenVR REQUIRED)
|
||||
target_include_directories(${TARGET_NAME} PRIVATE ${OPENVR_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${OPENVR_LIBRARIES})
|
||||
target_link_libraries(${TARGET_NAME} Winmm.lib)
|
||||
endif()
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
//
|
||||
#include "OpenVrDisplayPlugin.h"
|
||||
|
||||
// Odd ordering of header is required to avoid 'macro redinition warnings'
|
||||
#include <AudioClient.h>
|
||||
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QLoggingCategory>
|
||||
#include <QtCore/QFileInfo>
|
||||
|
@ -713,3 +716,30 @@ bool OpenVrDisplayPlugin::isKeyboardVisible() {
|
|||
int OpenVrDisplayPlugin::getRequiredThreadCount() const {
|
||||
return Parent::getRequiredThreadCount() + (_threadedSubmit ? 1 : 0);
|
||||
}
|
||||
|
||||
QString OpenVrDisplayPlugin::getPreferredAudioInDevice() const {
|
||||
QString device = getVrSettingString(vr::k_pch_audio_Section, vr::k_pch_audio_OnPlaybackDevice_String);
|
||||
if (!device.isEmpty()) {
|
||||
static const WCHAR INIT = 0;
|
||||
size_t size = device.size() + 1;
|
||||
std::vector<WCHAR> deviceW;
|
||||
deviceW.assign(size, INIT);
|
||||
device.toWCharArray(deviceW.data());
|
||||
device = AudioClient::friendlyNameForAudioDevice(deviceW.data());
|
||||
}
|
||||
return device;
|
||||
}
|
||||
|
||||
QString OpenVrDisplayPlugin::getPreferredAudioOutDevice() const {
|
||||
QString device = getVrSettingString(vr::k_pch_audio_Section, vr::k_pch_audio_OnRecordDevice_String);
|
||||
if (!device.isEmpty()) {
|
||||
static const WCHAR INIT = 0;
|
||||
size_t size = device.size() + 1;
|
||||
std::vector<WCHAR> deviceW;
|
||||
deviceW.assign(size, INIT);
|
||||
device.toWCharArray(deviceW.data());
|
||||
device = AudioClient::friendlyNameForAudioDevice(deviceW.data());
|
||||
}
|
||||
return device;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,9 @@ public:
|
|||
// Possibly needs an additional thread for VR submission
|
||||
int getRequiredThreadCount() const override;
|
||||
|
||||
QString getPreferredAudioInDevice() const override;
|
||||
QString getPreferredAudioOutDevice() const override;
|
||||
|
||||
protected:
|
||||
bool internalActivate() override;
|
||||
void internalDeactivate() override;
|
||||
|
|
|
@ -72,6 +72,21 @@ bool openVrSupported() {
|
|||
return (enableDebugOpenVR || !isOculusPresent()) && vr::VR_IsHmdPresent();
|
||||
}
|
||||
|
||||
QString getVrSettingString(const char* section, const char* setting) {
|
||||
QString result;
|
||||
static const uint32_t BUFFER_SIZE = 1024;
|
||||
static char BUFFER[BUFFER_SIZE];
|
||||
vr::IVRSettings * vrSettings = vr::VRSettings();
|
||||
if (vrSettings) {
|
||||
vr::EVRSettingsError error = vr::VRSettingsError_None;
|
||||
vrSettings->GetString(vr::k_pch_audio_Section, vr::k_pch_audio_OnPlaybackDevice_String, BUFFER, BUFFER_SIZE, &error);
|
||||
if (error == vr::VRSettingsError_None) {
|
||||
result = BUFFER;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
vr::IVRSystem* acquireOpenVrSystem() {
|
||||
bool hmdPresent = vr::VR_IsHmdPresent();
|
||||
if (hmdPresent) {
|
||||
|
@ -82,6 +97,7 @@ vr::IVRSystem* acquireOpenVrSystem() {
|
|||
#endif
|
||||
vr::EVRInitError eError = vr::VRInitError_None;
|
||||
activeHmd = vr::VR_Init(&eError, vr::VRApplication_Scene);
|
||||
|
||||
#if DEV_BUILD
|
||||
qCDebug(displayplugins) << "OpenVR display: HMD is " << activeHmd << " error is " << eError;
|
||||
#endif
|
||||
|
|
|
@ -25,6 +25,7 @@ bool openVrQuitRequested();
|
|||
void enableOpenVrKeyboard(PluginContainer* container);
|
||||
void disableOpenVrKeyboard();
|
||||
bool isOpenVrKeyboardShown();
|
||||
QString getVrSettingString(const char* section, const char* setting);
|
||||
|
||||
|
||||
template<typename F>
|
||||
|
|
|
@ -123,15 +123,18 @@ bool ViveControllerManager::isSupported() const {
|
|||
bool ViveControllerManager::activate() {
|
||||
InputPlugin::activate();
|
||||
|
||||
_container->addMenu(MENU_PATH);
|
||||
_container->addMenuItem(PluginType::INPUT_PLUGIN, MENU_PATH, RENDER_CONTROLLERS,
|
||||
[this] (bool clicked) { this->setRenderControllers(clicked); },
|
||||
true, true);
|
||||
|
||||
if (!_system) {
|
||||
_system = acquireOpenVrSystem();
|
||||
}
|
||||
Q_ASSERT(_system);
|
||||
|
||||
if (!_system) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_container->addMenu(MENU_PATH);
|
||||
_container->addMenuItem(PluginType::INPUT_PLUGIN, MENU_PATH, RENDER_CONTROLLERS,
|
||||
[this](bool clicked) { this->setRenderControllers(clicked); },
|
||||
true, true);
|
||||
|
||||
enableOpenVrKeyboard(_container);
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue