mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 08:04:01 +02:00
Merge branch 'tablet-ui' into tablet-ui-login-logout
This commit is contained in:
commit
696825580e
48 changed files with 979 additions and 519 deletions
|
@ -371,25 +371,39 @@ void Agent::executeScript() {
|
|||
using namespace recording;
|
||||
static const FrameType AUDIO_FRAME_TYPE = Frame::registerFrameType(AudioConstants::getAudioFrameName());
|
||||
Frame::registerFrameHandler(AUDIO_FRAME_TYPE, [this, &scriptedAvatar](Frame::ConstPointer frame) {
|
||||
const QByteArray& audio = frame->data;
|
||||
static quint16 audioSequenceNumber{ 0 };
|
||||
Transform audioTransform;
|
||||
|
||||
QByteArray audio(frame->data);
|
||||
|
||||
if (_isNoiseGateEnabled) {
|
||||
static int numSamples = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL;
|
||||
_noiseGate.gateSamples(reinterpret_cast<int16_t*>(audio.data()), numSamples);
|
||||
}
|
||||
|
||||
computeLoudness(&audio, scriptedAvatar);
|
||||
|
||||
// the codec needs a flush frame before sending silent packets, so
|
||||
// do not send one if the gate closed in this block (eventually this can be crossfaded).
|
||||
auto packetType = PacketType::MicrophoneAudioNoEcho;
|
||||
if (scriptedAvatar->getAudioLoudness() == 0.0f && !_noiseGate.closedInLastBlock()) {
|
||||
packetType = PacketType::SilentAudioFrame;
|
||||
}
|
||||
|
||||
Transform audioTransform;
|
||||
auto headOrientation = scriptedAvatar->getHeadOrientation();
|
||||
audioTransform.setTranslation(scriptedAvatar->getPosition());
|
||||
audioTransform.setRotation(headOrientation);
|
||||
|
||||
computeLoudness(&audio, scriptedAvatar);
|
||||
|
||||
QByteArray encodedBuffer;
|
||||
if (_encoder) {
|
||||
_encoder->encode(audio, encodedBuffer);
|
||||
} else {
|
||||
encodedBuffer = audio;
|
||||
}
|
||||
|
||||
AbstractAudioInterface::emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), audioSequenceNumber,
|
||||
audioTransform, scriptedAvatar->getPosition(), glm::vec3(0),
|
||||
PacketType::MicrophoneAudioNoEcho, _selectedCodecName);
|
||||
packetType, _selectedCodecName);
|
||||
});
|
||||
|
||||
auto avatarHashMap = DependencyManager::set<AvatarHashMap>();
|
||||
|
@ -483,6 +497,14 @@ void Agent::setIsListeningToAudioStream(bool isListeningToAudioStream) {
|
|||
_isListeningToAudioStream = isListeningToAudioStream;
|
||||
}
|
||||
|
||||
void Agent::setIsNoiseGateEnabled(bool isNoiseGateEnabled) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setIsNoiseGateEnabled", Q_ARG(bool, isNoiseGateEnabled));
|
||||
return;
|
||||
}
|
||||
_isNoiseGateEnabled = isNoiseGateEnabled;
|
||||
}
|
||||
|
||||
void Agent::setIsAvatar(bool isAvatar) {
|
||||
// this must happen on Agent's main thread
|
||||
if (QThread::currentThread() != thread()) {
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include <plugins/CodecPlugin.h>
|
||||
|
||||
#include "AudioNoiseGate.h"
|
||||
#include "MixedAudioStream.h"
|
||||
#include "avatars/ScriptableAvatar.h"
|
||||
|
||||
|
@ -38,6 +39,7 @@ class Agent : public ThreadedAssignment {
|
|||
Q_PROPERTY(bool isAvatar READ isAvatar WRITE setIsAvatar)
|
||||
Q_PROPERTY(bool isPlayingAvatarSound READ isPlayingAvatarSound)
|
||||
Q_PROPERTY(bool isListeningToAudioStream READ isListeningToAudioStream WRITE setIsListeningToAudioStream)
|
||||
Q_PROPERTY(bool isNoiseGateEnabled READ isNoiseGateEnabled WRITE setIsNoiseGateEnabled)
|
||||
Q_PROPERTY(float lastReceivedAudioLoudness READ getLastReceivedAudioLoudness)
|
||||
Q_PROPERTY(QUuid sessionUUID READ getSessionUUID)
|
||||
|
||||
|
@ -52,6 +54,9 @@ public:
|
|||
bool isListeningToAudioStream() const { return _isListeningToAudioStream; }
|
||||
void setIsListeningToAudioStream(bool isListeningToAudioStream);
|
||||
|
||||
bool isNoiseGateEnabled() const { return _isNoiseGateEnabled; }
|
||||
void setIsNoiseGateEnabled(bool isNoiseGateEnabled);
|
||||
|
||||
float getLastReceivedAudioLoudness() const { return _lastReceivedAudioLoudness; }
|
||||
QUuid getSessionUUID() const;
|
||||
|
||||
|
@ -106,6 +111,9 @@ private:
|
|||
QTimer* _avatarIdentityTimer = nullptr;
|
||||
QHash<QUuid, quint16> _outgoingScriptAudioSequenceNumbers;
|
||||
|
||||
AudioNoiseGate _noiseGate;
|
||||
bool _isNoiseGateEnabled { false };
|
||||
|
||||
CodecPluginPointer _codec;
|
||||
QString _selectedCodecName;
|
||||
Encoder* _encoder { nullptr };
|
||||
|
|
|
@ -455,13 +455,13 @@ void EntityScriptServer::addingEntity(const EntityItemID& entityID) {
|
|||
|
||||
void EntityScriptServer::deletingEntity(const EntityItemID& entityID) {
|
||||
if (_entityViewer.getTree() && !_shuttingDown && _entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->unloadEntityScript(entityID);
|
||||
_entitiesScriptEngine->unloadEntityScript(entityID, true);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityScriptServer::entityServerScriptChanging(const EntityItemID& entityID, const bool reload) {
|
||||
if (_entityViewer.getTree() && !_shuttingDown) {
|
||||
_entitiesScriptEngine->unloadEntityScript(entityID);
|
||||
_entitiesScriptEngine->unloadEntityScript(entityID, true);
|
||||
checkAndCallPreload(entityID, reload);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -246,10 +246,13 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList
|
|||
_agentPermissions[editorKey]->set(NodePermissions::Permission::canAdjustLocks);
|
||||
}
|
||||
|
||||
QList<QHash<NodePermissionsKey, NodePermissionsPointer>> permissionsSets;
|
||||
permissionsSets << _standardAgentPermissions.get() << _agentPermissions.get();
|
||||
std::list<std::unordered_map<NodePermissionsKey, NodePermissionsPointer>> permissionsSets{
|
||||
_standardAgentPermissions.get(),
|
||||
_agentPermissions.get()
|
||||
};
|
||||
foreach (auto permissionsSet, permissionsSets) {
|
||||
foreach (NodePermissionsKey userKey, permissionsSet.keys()) {
|
||||
for (auto entry : permissionsSet) {
|
||||
const auto& userKey = entry.first;
|
||||
if (onlyEditorsAreRezzers) {
|
||||
if (permissionsSet[userKey]->can(NodePermissions::Permission::canAdjustLocks)) {
|
||||
permissionsSet[userKey]->set(NodePermissions::Permission::canRezPermanentEntities);
|
||||
|
@ -300,7 +303,6 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList
|
|||
}
|
||||
|
||||
QVariantMap& DomainServerSettingsManager::getDescriptorsMap() {
|
||||
|
||||
static const QString DESCRIPTORS{ "descriptors" };
|
||||
|
||||
auto& settingsMap = getSettingsMap();
|
||||
|
@ -1355,18 +1357,12 @@ QStringList DomainServerSettingsManager::getAllKnownGroupNames() {
|
|||
// extract all the group names from the group-permissions and group-forbiddens settings
|
||||
QSet<QString> result;
|
||||
|
||||
QHashIterator<NodePermissionsKey, NodePermissionsPointer> i(_groupPermissions.get());
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
NodePermissionsKey key = i.key();
|
||||
result += key.first;
|
||||
for (const auto& entry : _groupPermissions.get()) {
|
||||
result += entry.first.first;
|
||||
}
|
||||
|
||||
QHashIterator<NodePermissionsKey, NodePermissionsPointer> j(_groupForbiddens.get());
|
||||
while (j.hasNext()) {
|
||||
j.next();
|
||||
NodePermissionsKey key = j.key();
|
||||
result += key.first;
|
||||
for (const auto& entry : _groupForbiddens.get()) {
|
||||
result += entry.first.first;
|
||||
}
|
||||
|
||||
return result.toList();
|
||||
|
@ -1377,20 +1373,17 @@ bool DomainServerSettingsManager::setGroupID(const QString& groupName, const QUu
|
|||
_groupIDs[groupName.toLower()] = groupID;
|
||||
_groupNames[groupID] = groupName;
|
||||
|
||||
QHashIterator<NodePermissionsKey, NodePermissionsPointer> i(_groupPermissions.get());
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
NodePermissionsPointer perms = i.value();
|
||||
|
||||
for (const auto& entry : _groupPermissions.get()) {
|
||||
auto& perms = entry.second;
|
||||
if (perms->getID().toLower() == groupName.toLower() && !perms->isGroup()) {
|
||||
changed = true;
|
||||
perms->setGroupID(groupID);
|
||||
}
|
||||
}
|
||||
|
||||
QHashIterator<NodePermissionsKey, NodePermissionsPointer> j(_groupForbiddens.get());
|
||||
while (j.hasNext()) {
|
||||
j.next();
|
||||
NodePermissionsPointer perms = j.value();
|
||||
for (const auto& entry : _groupForbiddens.get()) {
|
||||
auto& perms = entry.second;
|
||||
if (perms->getID().toLower() == groupName.toLower() && !perms->isGroup()) {
|
||||
changed = true;
|
||||
perms->setGroupID(groupID);
|
||||
|
|
|
@ -177,7 +177,7 @@ ScrollingWindow {
|
|||
SHAPE_TYPE_STATIC_MESH
|
||||
],
|
||||
checkStateOnDisable: false,
|
||||
warningOnDisable: "Models with automatic collisions set to 'Exact' cannot be dynamic"
|
||||
warningOnDisable: "Models with 'Exact' automatic collisions cannot be dynamic"
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -107,10 +107,10 @@ ModalWindow {
|
|||
|
||||
QtObject {
|
||||
id: d;
|
||||
readonly property int minWidth: 480;
|
||||
readonly property int maxWdith: 1280;
|
||||
readonly property int minHeight: 120;
|
||||
readonly property int maxHeight: 720;
|
||||
readonly property int minWidth: 480
|
||||
readonly property int maxWdith: 1280
|
||||
readonly property int minHeight: 120
|
||||
readonly property int maxHeight: 720
|
||||
|
||||
function resize() {
|
||||
var targetWidth = Math.max(titleWidth, pane.width);
|
||||
|
@ -259,6 +259,7 @@ ModalWindow {
|
|||
visible: Boolean(root.warning);
|
||||
text: hifi.glyphs.alert;
|
||||
size: hifi.dimensions.controlLineHeight;
|
||||
width: 20 // Line up with checkbox.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import QtQuick 2.5
|
|||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Dialogs 1.2 as OriginalDialogs
|
||||
|
||||
import "../controls-uit" as ControlsUIT
|
||||
import "../controls-uit"
|
||||
import "../styles-uit"
|
||||
import "../windows"
|
||||
|
||||
|
@ -20,7 +20,9 @@ TabletModalWindow {
|
|||
id: root;
|
||||
HifiConstants { id: hifi; }
|
||||
|
||||
y: hifi.dimensions.tabletMenuHeader
|
||||
anchors.fill: parent
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
|
||||
title: ""
|
||||
visible: true;
|
||||
|
@ -108,18 +110,24 @@ TabletModalWindow {
|
|||
|
||||
TabletModalFrame {
|
||||
id: modalWindowItem
|
||||
width: parent.width - 12
|
||||
width: parent.width - 6
|
||||
height: 240
|
||||
anchors {
|
||||
verticalCenter: parent.verticalCenter
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
// Clicking dialog background defocuses active control.
|
||||
anchors.fill: parent
|
||||
onClicked: parent.forceActiveFocus();
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d;
|
||||
readonly property int minWidth: 470
|
||||
readonly property int maxWidth: 470
|
||||
readonly property int minHeight: 240
|
||||
readonly property int minHeight: 120
|
||||
readonly property int maxHeight: 720
|
||||
|
||||
function resize() {
|
||||
|
@ -130,8 +138,8 @@ TabletModalWindow {
|
|||
((keyboardEnabled && keyboardRaised) ? (keyboard.raisedHeight + hifi.dimensions.contentSpacing.y) : 0);
|
||||
|
||||
root.width = (targetWidth < d.minWidth) ? d.minWidth : ((targetWidth > d.maxWdith) ? d.maxWidth : targetWidth);
|
||||
root.height = (targetHeight < d.minHeight) ? d.minHeight : ((targetHeight > d.maxHeight) ?
|
||||
d.maxHeight : targetHeight);
|
||||
modalWindowItem.height = (targetHeight < d.minHeight) ? d.minHeight : ((targetHeight > d.maxHeight) ?
|
||||
d.maxHeight : targetHeight);
|
||||
if (checkBoxField.visible && comboBoxField.visible) {
|
||||
checkBoxField.width = extraInputs.width / 2;
|
||||
comboBoxField.width = extraInputs.width / 2;
|
||||
|
@ -140,141 +148,149 @@ TabletModalWindow {
|
|||
}
|
||||
}
|
||||
}
|
||||
// Item {
|
||||
// anchors {
|
||||
// // top: parent.top;
|
||||
// // bottom: extraInputs.visible ? extraInputs.top : buttons.top;
|
||||
// left: parent.left;
|
||||
// right: parent.right;
|
||||
// topMargin: 20
|
||||
// }
|
||||
|
||||
Item {
|
||||
anchors {
|
||||
top: parent.top;
|
||||
bottom: extraInputs.visible ? extraInputs.top : buttons.top;
|
||||
left: parent.left;
|
||||
right: parent.right;
|
||||
leftMargin: 12
|
||||
rightMargin: 12
|
||||
}
|
||||
|
||||
// FIXME make a text field type that can be bound to a history for autocompletion
|
||||
ControlsUIT.TextField {
|
||||
TextField {
|
||||
id: textField;
|
||||
label: root.textInput.label;
|
||||
focus: root.textInput ? true : false;
|
||||
visible: root.textInput ? true : false;
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left;
|
||||
right: parent.right;
|
||||
leftMargin: 5; rightMargin: 5;
|
||||
topMargin: textField.controlHeight - textField.height + 5
|
||||
bottom: keyboard.top;
|
||||
bottomMargin: hifi.dimensions.contentSpacing.y;
|
||||
}
|
||||
}
|
||||
|
||||
ControlsUIT.Keyboard {
|
||||
property alias keyboardOverride: root.keyboardOverride
|
||||
property alias keyboardRaised: root.keyboardRaised
|
||||
property alias punctuationMode: root.punctuationMode
|
||||
Keyboard {
|
||||
id: keyboard
|
||||
raised: keyboardEnabled && keyboardRaised
|
||||
numeric: punctuationMode
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
leftMargin: 5; rightMargin: 5;
|
||||
top: textField.bottom
|
||||
topMargin: raised ? hifi.dimensions.contentSpacing.y : 0
|
||||
bottom: parent.bottom
|
||||
bottomMargin: raised ? hifi.dimensions.contentSpacing.y : 0
|
||||
}
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
Row {
|
||||
id: extraInputs;
|
||||
visible: Boolean(root.checkBox || root.comboBox);
|
||||
Item {
|
||||
id: extraInputs;
|
||||
visible: Boolean(root.checkBox || root.comboBox);
|
||||
anchors {
|
||||
left: parent.left;
|
||||
right: parent.right;
|
||||
bottom: buttons.top;
|
||||
bottomMargin: hifi.dimensions.contentSpacing.y;
|
||||
leftMargin: 12
|
||||
rightMargin: 12
|
||||
}
|
||||
height: comboBoxField.controlHeight;
|
||||
onHeightChanged: d.resize();
|
||||
onWidthChanged: d.resize();
|
||||
z: 20
|
||||
|
||||
CheckBox {
|
||||
id: checkBoxField;
|
||||
text: root.checkBox.label;
|
||||
focus: Boolean(root.checkBox);
|
||||
visible: Boolean(root.checkBox);
|
||||
anchors {
|
||||
left: parent.left;
|
||||
right: parent.right;
|
||||
leftMargin: 5; rightMargin: 5;
|
||||
top: keyboard.bottom;
|
||||
topMargin: hifi.dimensions.contentSpacing.y + 20;
|
||||
}
|
||||
height: comboBoxField.controlHeight;
|
||||
onHeightChanged: d.resize();
|
||||
onWidthChanged: d.resize();
|
||||
|
||||
ControlsUIT.CheckBox {
|
||||
id: checkBoxField;
|
||||
text: root.checkBox.label;
|
||||
focus: Boolean(root.checkBox);
|
||||
visible: Boolean(root.checkBox);
|
||||
// anchors {
|
||||
// left: parent.left;
|
||||
// bottom: parent.bottom;
|
||||
// leftMargin: 6; // Magic number to align with warning icon
|
||||
// bottomMargin: 6;
|
||||
// }
|
||||
}
|
||||
|
||||
ControlsUIT.ComboBox {
|
||||
id: comboBoxField;
|
||||
label: root.comboBox.label;
|
||||
focus: Boolean(root.comboBox);
|
||||
visible: Boolean(root.comboBox);
|
||||
// anchors {
|
||||
// right: parent.right;
|
||||
// bottom: parent.bottom;
|
||||
// }
|
||||
model: root.comboBox ? root.comboBox.items : [];
|
||||
onAccepted: {
|
||||
updateCheckbox();
|
||||
focus = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttons;
|
||||
focus: true;
|
||||
spacing: hifi.dimensions.contentSpacing.x;
|
||||
layoutDirection: Qt.RightToLeft;
|
||||
onHeightChanged: d.resize();
|
||||
onWidthChanged: {
|
||||
d.resize();
|
||||
resizeWarningText();
|
||||
}
|
||||
|
||||
anchors {
|
||||
bottom: parent.bottom;
|
||||
left: parent.left;
|
||||
right: parent.right;
|
||||
bottomMargin: hifi.dimensions.contentSpacing.y;
|
||||
leftMargin: 5; rightMargin: 5;
|
||||
}
|
||||
|
||||
function resizeWarningText() {
|
||||
var rowWidth = buttons.width;
|
||||
var buttonsWidth = acceptButton.width + cancelButton.width + hifi.dimensions.contentSpacing.x * 2;
|
||||
var warningIconWidth = warningIcon.width + hifi.dimensions.contentSpacing.x;
|
||||
warningText.width = rowWidth - buttonsWidth - warningIconWidth;
|
||||
}
|
||||
|
||||
ControlsUIT.Button {
|
||||
id: cancelButton;
|
||||
action: cancelAction;
|
||||
}
|
||||
|
||||
ControlsUIT.Button {
|
||||
id: acceptButton;
|
||||
action: acceptAction;
|
||||
}
|
||||
|
||||
Text {
|
||||
id: warningText;
|
||||
visible: Boolean(root.warning);
|
||||
text: root.warning;
|
||||
wrapMode: Text.WordWrap;
|
||||
font.italic: true;
|
||||
maximumLineCount: 2;
|
||||
}
|
||||
|
||||
HiFiGlyphs {
|
||||
id: warningIcon;
|
||||
visible: Boolean(root.warning);
|
||||
text: hifi.glyphs.alert;
|
||||
size: hifi.dimensions.controlLineHeight;
|
||||
leftMargin: 6; // Magic number to align with warning icon
|
||||
bottomMargin: 6;
|
||||
}
|
||||
}
|
||||
// }//column
|
||||
|
||||
ComboBox {
|
||||
id: comboBoxField;
|
||||
label: root.comboBox.label;
|
||||
focus: Boolean(root.comboBox);
|
||||
visible: Boolean(root.comboBox);
|
||||
anchors {
|
||||
right: parent.right;
|
||||
bottom: parent.bottom;
|
||||
}
|
||||
model: root.comboBox ? root.comboBox.items : [];
|
||||
onAccepted: {
|
||||
updateCheckbox();
|
||||
focus = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttons;
|
||||
focus: true;
|
||||
spacing: hifi.dimensions.contentSpacing.x;
|
||||
layoutDirection: Qt.RightToLeft;
|
||||
onHeightChanged: d.resize();
|
||||
onWidthChanged: {
|
||||
d.resize();
|
||||
resizeWarningText();
|
||||
}
|
||||
z: 10
|
||||
|
||||
anchors {
|
||||
bottom: parent.bottom;
|
||||
left: parent.left;
|
||||
right: parent.right;
|
||||
bottomMargin: hifi.dimensions.contentSpacing.y;
|
||||
leftMargin: 12
|
||||
rightMargin: 12
|
||||
}
|
||||
|
||||
function resizeWarningText() {
|
||||
var rowWidth = buttons.width;
|
||||
var buttonsWidth = acceptButton.width + cancelButton.width + hifi.dimensions.contentSpacing.x * 2;
|
||||
var warningIconWidth = warningIcon.width + hifi.dimensions.contentSpacing.x;
|
||||
warningText.width = rowWidth - buttonsWidth - warningIconWidth;
|
||||
}
|
||||
|
||||
Button {
|
||||
id: cancelButton;
|
||||
action: cancelAction;
|
||||
}
|
||||
|
||||
Button {
|
||||
id: acceptButton;
|
||||
action: acceptAction;
|
||||
}
|
||||
|
||||
Text {
|
||||
id: warningText;
|
||||
visible: Boolean(root.warning);
|
||||
text: root.warning;
|
||||
wrapMode: Text.WordWrap;
|
||||
font.italic: true;
|
||||
maximumLineCount: 2;
|
||||
}
|
||||
|
||||
HiFiGlyphs {
|
||||
id: warningIcon;
|
||||
visible: Boolean(root.warning);
|
||||
text: hifi.glyphs.alert;
|
||||
size: hifi.dimensions.controlLineHeight;
|
||||
width: 20 // Line up with checkbox.
|
||||
}
|
||||
}
|
||||
|
||||
Action {
|
||||
id: cancelAction;
|
||||
text: qsTr("Cancel");
|
||||
|
|
|
@ -176,7 +176,7 @@ Rectangle {
|
|||
SHAPE_TYPE_STATIC_MESH
|
||||
],
|
||||
checkStateOnDisable: false,
|
||||
warningOnDisable: "Models with automatic collisions set to 'Exact' cannot be dynamic"
|
||||
warningOnDisable: "Models with 'Exact' automatic collisions cannot be dynamic"
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -9,34 +9,30 @@
|
|||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import "tabletWindows"
|
||||
import "../../dialogs"
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
StackView {
|
||||
id: profileRoot
|
||||
initialItem: root
|
||||
objectName: "stack"
|
||||
property var title: "Audio Preferences"
|
||||
property string title: "Audio Settings"
|
||||
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
|
||||
function pushSource(path) {
|
||||
editRoot.push(Qt.reslovedUrl(path));
|
||||
profileRoot.push(Qt.reslovedUrl(path));
|
||||
}
|
||||
|
||||
function popSource() {
|
||||
|
||||
profileRoot.pop();
|
||||
}
|
||||
|
||||
TabletPreferencesDialog {
|
||||
id: root
|
||||
property string title: "Audio Settings"
|
||||
objectName: "TabletAudioPreferences"
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
showCategories: ["Audio"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,34 +9,30 @@
|
|||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import "tabletWindows"
|
||||
import "../../dialogs"
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
StackView {
|
||||
id: profileRoot
|
||||
initialItem: root
|
||||
objectName: "stack"
|
||||
property var title: "Avatar Preferences"
|
||||
property string title: "Avatar Settings"
|
||||
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
|
||||
function pushSource(path) {
|
||||
editRoot.push(Qt.reslovedUrl(path));
|
||||
profileRoot.push(Qt.reslovedUrl(path));
|
||||
}
|
||||
|
||||
function popSource() {
|
||||
|
||||
profileRoot.pop();
|
||||
}
|
||||
|
||||
TabletPreferencesDialog {
|
||||
id: root
|
||||
property string title: "Avatar Preferences"
|
||||
objectName: "TabletAvatarPreferences"
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
showCategories: ["Avatar Basics", "Avatar Tuning", "Avatar Camera"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,35 +9,30 @@
|
|||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import "tabletWindows"
|
||||
import "../../dialogs"
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
StackView {
|
||||
id: profileRoot
|
||||
initialItem: root
|
||||
objectName: "stack"
|
||||
property var title: "General Prefernces"
|
||||
property string title: "General Settings"
|
||||
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
|
||||
|
||||
function pushSource(path) {
|
||||
editRoot.push(Qt.reslovedUrl(path));
|
||||
profileRoot.push(Qt.reslovedUrl(path));
|
||||
}
|
||||
|
||||
function popSource() {
|
||||
|
||||
profileRoot.pop();
|
||||
}
|
||||
|
||||
|
||||
TabletPreferencesDialog {
|
||||
id: root
|
||||
property string title: "General Preferences"
|
||||
objectName: "TabletGeneralPreferences"
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers", "Perception Neuron", "Kinect"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,34 +1,38 @@
|
|||
import QtQuick 2.5
|
||||
import Qt.labs.settings 1.0
|
||||
//
|
||||
// TabletGraphicsPreferences.qml
|
||||
//
|
||||
// Created by Vlad Stelmahovsky on 12 Mar 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import "tabletWindows"
|
||||
import "../../dialogs"
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
StackView {
|
||||
id: profileRoot
|
||||
initialItem: root
|
||||
objectName: "stack"
|
||||
property string title: "Graphics Settings"
|
||||
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
|
||||
function pushSource(path) {
|
||||
editRoot.push(Qt.reslovedUrl(path));
|
||||
profileRoot.push(Qt.reslovedUrl(path));
|
||||
}
|
||||
|
||||
function popSource() {
|
||||
|
||||
profileRoot.pop();
|
||||
}
|
||||
|
||||
TabletPreferencesDialog {
|
||||
id: root
|
||||
property string title: "Graphics Settings"
|
||||
objectName: "TabletGraphicsPreferences"
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
showCategories: ["Graphics"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,34 +1,38 @@
|
|||
import QtQuick 2.5
|
||||
import Qt.labs.settings 1.0
|
||||
//
|
||||
// TabletLodPreferences.qml
|
||||
//
|
||||
// Created by Vlad Stelmahovsky on 11 Mar 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
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import "tabletWindows"
|
||||
import "../../dialogs"
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
StackView {
|
||||
id: profileRoot
|
||||
initialItem: root
|
||||
objectName: "stack"
|
||||
property string title: "LOD Settings"
|
||||
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
|
||||
function pushSource(path) {
|
||||
editRoot.push(Qt.reslovedUrl(path));
|
||||
profileRoot.push(Qt.reslovedUrl(path));
|
||||
}
|
||||
|
||||
function popSource() {
|
||||
|
||||
profileRoot.pop();
|
||||
}
|
||||
|
||||
TabletPreferencesDialog {
|
||||
id: root
|
||||
property string title: "LOD Settings"
|
||||
objectName: "TabletLodPreferences"
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
showCategories: ["Level of Detail Tuning"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ FocusScope {
|
|||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onEntered: iconColorOverlay.color = "#1fc6a6";
|
||||
onExited: iconColorOverlay.color = "#ffffff";
|
||||
onExited: iconColorOverlay.color = "#34a2c7";
|
||||
// navigate back to root level menu
|
||||
onClicked: {
|
||||
buildMenu();
|
||||
|
|
|
@ -9,34 +9,30 @@
|
|||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import "tabletWindows"
|
||||
import "../../dialogs"
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtGraphicalEffects 1.0
|
||||
|
||||
StackView {
|
||||
id: profileRoot
|
||||
initialItem: root
|
||||
objectName: "stack"
|
||||
property var title: "Network Preferences"
|
||||
property var title: "Networking Settings"
|
||||
|
||||
property var eventBridge;
|
||||
signal sendToScript(var message);
|
||||
|
||||
function pushSource(path) {
|
||||
editRoot.push(Qt.reslovedUrl(path));
|
||||
profileRoot.push(Qt.reslovedUrl(path));
|
||||
}
|
||||
|
||||
function popSource() {
|
||||
|
||||
profileRoot.pop();
|
||||
}
|
||||
|
||||
TabletPreferencesDialog {
|
||||
id: root
|
||||
property string title: "Networking Settings"
|
||||
objectName: "NetworkingPreferences"
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
objectName: "TabletNetworkingPreferences"
|
||||
showCategories: ["Networking"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,21 +58,10 @@ Item {
|
|||
Tablet.getTablet("com.highfidelity.interface.tablet.system").gotoHomeScreen();
|
||||
}
|
||||
|
||||
HifiControls.TabletHeader {
|
||||
id: header
|
||||
title: parent.title
|
||||
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: main
|
||||
anchors {
|
||||
top: header.bottom
|
||||
top: parent.top
|
||||
bottom: footer.top
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
QPlainTextEdit {
|
||||
font-family: Inconsolata, Lucida Console, Andale Mono, Monaco;
|
||||
font-family: Inconsolata, Consolas, Courier New, monospace;
|
||||
font-size: 16px;
|
||||
padding-left: 28px;
|
||||
padding-top: 7px;
|
||||
|
@ -11,7 +11,7 @@ QPlainTextEdit {
|
|||
}
|
||||
|
||||
QLineEdit {
|
||||
font-family: Inconsolata, Lucida Console, Andale Mono, Monaco;
|
||||
font-family: Inconsolata, Consolas, Courier New, monospace;
|
||||
padding-left: 7px;
|
||||
background-color: #CCCCCC;
|
||||
border-width: 0;
|
||||
|
|
|
@ -20,55 +20,28 @@ using namespace render;
|
|||
CauterizedMeshPartPayload::CauterizedMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform)
|
||||
: ModelMeshPartPayload(model, meshIndex, partIndex, shapeIndex, transform, offsetTransform) {}
|
||||
|
||||
void CauterizedMeshPartPayload::updateTransformForSkinnedCauterizedMesh(const Transform& transform,
|
||||
const QVector<glm::mat4>& clusterMatrices,
|
||||
const QVector<glm::mat4>& cauterizedClusterMatrices) {
|
||||
_transform = transform;
|
||||
_cauterizedTransform = transform;
|
||||
|
||||
if (clusterMatrices.size() > 0) {
|
||||
_worldBound = AABox();
|
||||
for (auto& clusterMatrix : clusterMatrices) {
|
||||
AABox clusterBound = _localBound;
|
||||
clusterBound.transform(clusterMatrix);
|
||||
_worldBound += clusterBound;
|
||||
}
|
||||
|
||||
_worldBound.transform(transform);
|
||||
if (clusterMatrices.size() == 1) {
|
||||
_transform = _transform.worldTransform(Transform(clusterMatrices[0]));
|
||||
if (cauterizedClusterMatrices.size() != 0) {
|
||||
_cauterizedTransform = _cauterizedTransform.worldTransform(Transform(cauterizedClusterMatrices[0]));
|
||||
} else {
|
||||
_cauterizedTransform = _transform;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_worldBound = _localBound;
|
||||
_worldBound.transform(_drawTransform);
|
||||
}
|
||||
void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(
|
||||
const Transform& renderTransform,
|
||||
const gpu::BufferPointer& buffer) {
|
||||
_cauterizedTransform = renderTransform;
|
||||
_cauterizedClusterBuffer = buffer;
|
||||
}
|
||||
|
||||
void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const {
|
||||
// Still relying on the raw data from the model
|
||||
const Model::MeshState& state = _model->getMeshState(_meshIndex);
|
||||
SkeletonModel* skeleton = static_cast<SkeletonModel*>(_model);
|
||||
bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE) && skeleton->getEnableCauterization();
|
||||
|
||||
if (state.clusterBuffer) {
|
||||
if (useCauterizedMesh) {
|
||||
const Model::MeshState& cState = skeleton->getCauterizeMeshState(_meshIndex);
|
||||
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, cState.clusterBuffer);
|
||||
} else {
|
||||
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, state.clusterBuffer);
|
||||
if (useCauterizedMesh) {
|
||||
if (_cauterizedClusterBuffer) {
|
||||
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, _cauterizedClusterBuffer);
|
||||
}
|
||||
batch.setModelTransform(_cauterizedTransform);
|
||||
} else {
|
||||
if (_clusterBuffer) {
|
||||
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, _clusterBuffer);
|
||||
}
|
||||
batch.setModelTransform(_transform);
|
||||
} else {
|
||||
if (useCauterizedMesh) {
|
||||
batch.setModelTransform(_cauterizedTransform);
|
||||
} else {
|
||||
batch.setModelTransform(_transform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,12 +17,13 @@
|
|||
class CauterizedMeshPartPayload : public ModelMeshPartPayload {
|
||||
public:
|
||||
CauterizedMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform);
|
||||
void updateTransformForSkinnedCauterizedMesh(const Transform& transform,
|
||||
const QVector<glm::mat4>& clusterMatrices,
|
||||
const QVector<glm::mat4>& cauterizedClusterMatrices);
|
||||
|
||||
void updateTransformForCauterizedMesh(const Transform& renderTransform, const gpu::BufferPointer& buffer);
|
||||
|
||||
void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override;
|
||||
|
||||
private:
|
||||
gpu::BufferPointer _cauterizedClusterBuffer;
|
||||
Transform _cauterizedTransform;
|
||||
};
|
||||
|
||||
|
|
|
@ -26,8 +26,8 @@ CauterizedModel::~CauterizedModel() {
|
|||
}
|
||||
|
||||
void CauterizedModel::deleteGeometry() {
|
||||
Model::deleteGeometry();
|
||||
_cauterizeMeshStates.clear();
|
||||
Model::deleteGeometry();
|
||||
_cauterizeMeshStates.clear();
|
||||
}
|
||||
|
||||
bool CauterizedModel::updateGeometry() {
|
||||
|
@ -41,7 +41,7 @@ bool CauterizedModel::updateGeometry() {
|
|||
_cauterizeMeshStates.append(state);
|
||||
}
|
||||
}
|
||||
return needsFullUpdate;
|
||||
return needsFullUpdate;
|
||||
}
|
||||
|
||||
void CauterizedModel::createVisibleRenderItemSet() {
|
||||
|
@ -86,13 +86,13 @@ void CauterizedModel::createVisibleRenderItemSet() {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
Model::createVisibleRenderItemSet();
|
||||
Model::createVisibleRenderItemSet();
|
||||
}
|
||||
}
|
||||
|
||||
void CauterizedModel::createCollisionRenderItemSet() {
|
||||
// Temporary HACK: use base class method for now
|
||||
Model::createCollisionRenderItemSet();
|
||||
Model::createCollisionRenderItemSet();
|
||||
}
|
||||
|
||||
void CauterizedModel::updateClusterMatrices() {
|
||||
|
@ -122,8 +122,8 @@ void CauterizedModel::updateClusterMatrices() {
|
|||
state.clusterBuffer->setSubData(0, state.clusterMatrices.size() * sizeof(glm::mat4),
|
||||
(const gpu::Byte*) state.clusterMatrices.constData());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty.
|
||||
if (!_cauterizeBoneSet.empty()) {
|
||||
|
@ -191,6 +191,9 @@ void CauterizedModel::updateRenderItems() {
|
|||
return;
|
||||
}
|
||||
|
||||
// lazy update of cluster matrices used for rendering. We need to update them here, so we can correctly update the bounding box.
|
||||
self->updateClusterMatrices();
|
||||
|
||||
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||
|
||||
Transform modelTransform;
|
||||
|
@ -209,15 +212,22 @@ void CauterizedModel::updateRenderItems() {
|
|||
if (data._model && data._model->isLoaded()) {
|
||||
// Ensure the model geometry was not reset between frames
|
||||
if (deleteGeometryCounter == data._model->getGeometryCounter()) {
|
||||
// lazy update of cluster matrices used for rendering. We need to update them here, so we can correctly update the bounding box.
|
||||
data._model->updateClusterMatrices();
|
||||
|
||||
// update the model transform and bounding box for this render item.
|
||||
// this stuff identical to what happens in regular Model
|
||||
const Model::MeshState& state = data._model->getMeshState(data._meshIndex);
|
||||
Transform renderTransform = modelTransform;
|
||||
if (state.clusterMatrices.size() == 1) {
|
||||
renderTransform = modelTransform.worldTransform(Transform(state.clusterMatrices[0]));
|
||||
}
|
||||
data.updateTransformForSkinnedMesh(renderTransform, modelTransform, state.clusterBuffer);
|
||||
|
||||
// this stuff for cauterized mesh
|
||||
CauterizedModel* cModel = static_cast<CauterizedModel*>(data._model);
|
||||
assert(data._meshIndex < cModel->_cauterizeMeshStates.size());
|
||||
const Model::MeshState& cState = cModel->_cauterizeMeshStates.at(data._meshIndex);
|
||||
data.updateTransformForSkinnedCauterizedMesh(modelTransform, state.clusterMatrices, cState.clusterMatrices);
|
||||
const Model::MeshState& cState = cModel->getCauterizeMeshState(data._meshIndex);
|
||||
renderTransform = modelTransform;
|
||||
if (cState.clusterMatrices.size() == 1) {
|
||||
renderTransform = modelTransform.worldTransform(Transform(cState.clusterMatrices[0]));
|
||||
}
|
||||
data.updateTransformForCauterizedMesh(renderTransform, cState.clusterBuffer);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -154,9 +154,12 @@ MyAvatar::MyAvatar(RigPointer rig) :
|
|||
if (recordingInterface->getPlayFromCurrentLocation()) {
|
||||
setRecordingBasis();
|
||||
}
|
||||
_wasCharacterControllerEnabled = _characterController.isEnabled();
|
||||
_characterController.setEnabled(false);
|
||||
} else {
|
||||
clearRecordingBasis();
|
||||
useFullAvatarURL(_fullAvatarURLFromPreferences, _fullAvatarModelName);
|
||||
_characterController.setEnabled(_wasCharacterControllerEnabled);
|
||||
}
|
||||
|
||||
auto audioIO = DependencyManager::get<AudioClient>();
|
||||
|
|
|
@ -411,6 +411,7 @@ private:
|
|||
SharedSoundPointer _collisionSound;
|
||||
|
||||
MyCharacterController _characterController;
|
||||
bool _wasCharacterControllerEnabled { true };
|
||||
|
||||
AvatarWeakPointer _lookAtTargetAvatar;
|
||||
glm::vec3 _targetAvatarPosition;
|
||||
|
|
|
@ -28,17 +28,23 @@ const int SEARCH_BUTTON_LEFT = 25;
|
|||
const int SEARCH_BUTTON_WIDTH = 20;
|
||||
const int SEARCH_TOGGLE_BUTTON_WIDTH = 50;
|
||||
const int SEARCH_TEXT_WIDTH = 240;
|
||||
const int TIME_STAMP_LENGTH = 16;
|
||||
const int FONT_WEIGHT = 75;
|
||||
const QColor HIGHLIGHT_COLOR = QColor("#3366CC");
|
||||
const QColor BOLD_COLOR = QColor("#445c8c");
|
||||
const QString BOLD_PATTERN = "\\[\\d*\\/.*:\\d*:\\d*\\]";
|
||||
|
||||
class KeywordHighlighter : public QSyntaxHighlighter {
|
||||
class Highlighter : public QSyntaxHighlighter {
|
||||
public:
|
||||
KeywordHighlighter(QTextDocument* parent = nullptr);
|
||||
Highlighter(QTextDocument* parent = nullptr);
|
||||
void setBold(int indexToBold);
|
||||
QString keyword;
|
||||
|
||||
protected:
|
||||
void highlightBlock(const QString& text) override;
|
||||
|
||||
private:
|
||||
QTextCharFormat boldFormat;
|
||||
QTextCharFormat keywordFormat;
|
||||
|
||||
};
|
||||
|
@ -89,7 +95,7 @@ void BaseLogDialog::initControls() {
|
|||
_leftPad += SEARCH_TOGGLE_BUTTON_WIDTH + BUTTON_MARGIN;
|
||||
_searchPrevButton->show();
|
||||
connect(_searchPrevButton, SIGNAL(clicked()), SLOT(toggleSearchPrev()));
|
||||
|
||||
|
||||
_searchNextButton = new QPushButton(this);
|
||||
_searchNextButton->setObjectName("searchNextButton");
|
||||
_searchNextButton->setGeometry(_leftPad, ELEMENT_MARGIN, SEARCH_TOGGLE_BUTTON_WIDTH, ELEMENT_HEIGHT);
|
||||
|
@ -101,9 +107,8 @@ void BaseLogDialog::initControls() {
|
|||
_logTextBox = new QPlainTextEdit(this);
|
||||
_logTextBox->setReadOnly(true);
|
||||
_logTextBox->show();
|
||||
_highlighter = new KeywordHighlighter(_logTextBox->document());
|
||||
_highlighter = new Highlighter(_logTextBox->document());
|
||||
connect(_logTextBox, SIGNAL(selectionChanged()), SLOT(updateSelection()));
|
||||
|
||||
}
|
||||
|
||||
void BaseLogDialog::showEvent(QShowEvent* event) {
|
||||
|
@ -116,7 +121,9 @@ void BaseLogDialog::resizeEvent(QResizeEvent* event) {
|
|||
|
||||
void BaseLogDialog::appendLogLine(QString logLine) {
|
||||
if (logLine.contains(_searchTerm, Qt::CaseInsensitive)) {
|
||||
int indexToBold = _logTextBox->document()->characterCount();
|
||||
_logTextBox->appendPlainText(logLine.trimmed());
|
||||
_highlighter->setBold(indexToBold);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,7 +135,7 @@ void BaseLogDialog::handleSearchTextChanged(QString searchText) {
|
|||
if (searchText.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
QTextCursor cursor = _logTextBox->textCursor();
|
||||
if (cursor.hasSelection()) {
|
||||
QString selectedTerm = cursor.selectedText();
|
||||
|
@ -136,16 +143,16 @@ void BaseLogDialog::handleSearchTextChanged(QString searchText) {
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cursor.setPosition(0, QTextCursor::MoveAnchor);
|
||||
_logTextBox->setTextCursor(cursor);
|
||||
bool foundTerm = _logTextBox->find(searchText);
|
||||
|
||||
|
||||
if (!foundTerm) {
|
||||
cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
|
||||
_logTextBox->setTextCursor(cursor);
|
||||
}
|
||||
|
||||
|
||||
_searchTerm = searchText;
|
||||
_highlighter->keyword = searchText;
|
||||
_highlighter->rehighlight();
|
||||
|
@ -175,6 +182,7 @@ void BaseLogDialog::showLogData() {
|
|||
_logTextBox->clear();
|
||||
_logTextBox->appendPlainText(getCurrentLog());
|
||||
_logTextBox->ensureCursorVisible();
|
||||
_highlighter->rehighlight();
|
||||
}
|
||||
|
||||
void BaseLogDialog::updateSelection() {
|
||||
|
@ -187,16 +195,28 @@ void BaseLogDialog::updateSelection() {
|
|||
}
|
||||
}
|
||||
|
||||
KeywordHighlighter::KeywordHighlighter(QTextDocument* parent) : QSyntaxHighlighter(parent) {
|
||||
Highlighter::Highlighter(QTextDocument* parent) : QSyntaxHighlighter(parent) {
|
||||
boldFormat.setFontWeight(FONT_WEIGHT);
|
||||
boldFormat.setForeground(BOLD_COLOR);
|
||||
keywordFormat.setForeground(HIGHLIGHT_COLOR);
|
||||
}
|
||||
|
||||
void KeywordHighlighter::highlightBlock(const QString& text) {
|
||||
void Highlighter::highlightBlock(const QString& text) {
|
||||
QRegExp expression(BOLD_PATTERN);
|
||||
|
||||
int index = text.indexOf(expression, 0);
|
||||
|
||||
while (index >= 0) {
|
||||
int length = expression.matchedLength();
|
||||
setFormat(index, length, boldFormat);
|
||||
index = text.indexOf(expression, index + length);
|
||||
}
|
||||
|
||||
if (keyword.isNull() || keyword.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int index = text.indexOf(keyword, 0, Qt::CaseInsensitive);
|
||||
index = text.indexOf(keyword, 0, Qt::CaseInsensitive);
|
||||
int length = keyword.length();
|
||||
|
||||
while (index >= 0) {
|
||||
|
@ -204,3 +224,7 @@ void KeywordHighlighter::highlightBlock(const QString& text) {
|
|||
index = text.indexOf(keyword, index + length, Qt::CaseInsensitive);
|
||||
}
|
||||
}
|
||||
|
||||
void Highlighter::setBold(int indexToBold) {
|
||||
setFormat(indexToBold, TIME_STAMP_LENGTH, boldFormat);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ const int BUTTON_MARGIN = 8;
|
|||
class QPushButton;
|
||||
class QLineEdit;
|
||||
class QPlainTextEdit;
|
||||
class KeywordHighlighter;
|
||||
class Highlighter;
|
||||
|
||||
class BaseLogDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
@ -56,7 +56,7 @@ private:
|
|||
QPushButton* _searchPrevButton { nullptr };
|
||||
QPushButton* _searchNextButton { nullptr };
|
||||
QString _searchTerm;
|
||||
KeywordHighlighter* _highlighter { nullptr };
|
||||
Highlighter* _highlighter { nullptr };
|
||||
|
||||
void initControls();
|
||||
void showLogData();
|
||||
|
|
|
@ -45,13 +45,13 @@
|
|||
#include <AudioReverb.h>
|
||||
#include <AudioLimiter.h>
|
||||
#include <AudioConstants.h>
|
||||
#include <AudioNoiseGate.h>
|
||||
|
||||
#include <shared/RateCounter.h>
|
||||
|
||||
#include <plugins/CodecPlugin.h>
|
||||
|
||||
#include "AudioIOStats.h"
|
||||
#include "AudioNoiseGate.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning( push )
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// AudioNoiseGate.cpp
|
||||
// interface/src/audio
|
||||
// libraries/audio
|
||||
//
|
||||
// Created by Stephen Birarda on 2014-12-16.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
|
@ -9,29 +9,23 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "AudioNoiseGate.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string.h>
|
||||
|
||||
#include <AudioConstants.h>
|
||||
|
||||
#include "AudioNoiseGate.h"
|
||||
#include "AudioConstants.h"
|
||||
|
||||
const float AudioNoiseGate::CLIPPING_THRESHOLD = 0.90f;
|
||||
|
||||
AudioNoiseGate::AudioNoiseGate() :
|
||||
_inputBlockCounter(0),
|
||||
_lastLoudness(0.0f),
|
||||
_quietestBlock(std::numeric_limits<float>::max()),
|
||||
_loudestBlock(0.0f),
|
||||
_didClipInLastBlock(false),
|
||||
_dcOffset(0.0f),
|
||||
_measuredFloor(0.0f),
|
||||
_sampleCounter(0),
|
||||
_isOpen(false),
|
||||
_blocksToClose(0)
|
||||
{
|
||||
|
||||
}
|
||||
_blocksToClose(0) {}
|
||||
|
||||
void AudioNoiseGate::removeDCOffset(int16_t* samples, int numSamples) {
|
||||
//
|
||||
|
@ -80,7 +74,7 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
|
|||
float loudness = 0;
|
||||
int thisSample = 0;
|
||||
int samplesOverNoiseGate = 0;
|
||||
|
||||
|
||||
const float NOISE_GATE_HEIGHT = 7.0f;
|
||||
const int NOISE_GATE_WIDTH = 5;
|
||||
const int NOISE_GATE_CLOSE_BLOCK_DELAY = 5;
|
||||
|
@ -88,36 +82,22 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
|
|||
|
||||
// Check clipping, and check if should open noise gate
|
||||
_didClipInLastBlock = false;
|
||||
|
||||
|
||||
for (int i = 0; i < numSamples; i++) {
|
||||
thisSample = std::abs(samples[i]);
|
||||
if (thisSample >= ((float) AudioConstants::MAX_SAMPLE_VALUE * CLIPPING_THRESHOLD)) {
|
||||
_didClipInLastBlock = true;
|
||||
}
|
||||
|
||||
|
||||
loudness += thisSample;
|
||||
// Noise Reduction: Count peaks above the average loudness
|
||||
if (thisSample > (_measuredFloor * NOISE_GATE_HEIGHT)) {
|
||||
samplesOverNoiseGate++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_lastLoudness = fabs(loudness / numSamples);
|
||||
|
||||
if (_quietestBlock > _lastLoudness) {
|
||||
_quietestBlock = _lastLoudness;
|
||||
}
|
||||
if (_loudestBlock < _lastLoudness) {
|
||||
_loudestBlock = _lastLoudness;
|
||||
}
|
||||
|
||||
const int FRAMES_FOR_NOISE_DETECTION = 400;
|
||||
if (_inputBlockCounter++ > FRAMES_FOR_NOISE_DETECTION) {
|
||||
_quietestBlock = std::numeric_limits<float>::max();
|
||||
_loudestBlock = 0.0f;
|
||||
_inputBlockCounter = 0;
|
||||
}
|
||||
|
||||
|
||||
// If Noise Gate is enabled, check and turn the gate on and off
|
||||
float averageOfAllSampleBlocks = 0.0f;
|
||||
_sampleBlocks[_sampleCounter++] = _lastLoudness;
|
||||
|
@ -130,7 +110,7 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
|
|||
averageOfAllSampleBlocks += _sampleBlocks[j];
|
||||
}
|
||||
thisAverage /= NOISE_GATE_BLOCKS_TO_AVERAGE;
|
||||
|
||||
|
||||
if (thisAverage < smallestSample) {
|
||||
smallestSample = thisAverage;
|
||||
}
|
||||
|
@ -138,7 +118,7 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
|
|||
averageOfAllSampleBlocks /= NUMBER_OF_NOISE_SAMPLE_BLOCKS;
|
||||
_measuredFloor = smallestSample;
|
||||
_sampleCounter = 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
_closedInLastBlock = false;
|
||||
|
@ -156,7 +136,7 @@ void AudioNoiseGate::gateSamples(int16_t* samples, int numSamples) {
|
|||
}
|
||||
if (!_isOpen) {
|
||||
// First block after being closed gets faded to silence, we fade across
|
||||
// the entire block on fading out. All subsequent blocks are muted by being slammed
|
||||
// the entire block on fading out. All subsequent blocks are muted by being slammed
|
||||
// to zeros
|
||||
if (_closedInLastBlock) {
|
||||
float fadeSlope = (1.0f / numSamples);
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// AudioNoiseGate.h
|
||||
// interface/src/audio
|
||||
// libraries/audio
|
||||
//
|
||||
// Created by Stephen Birarda on 2014-12-16.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
|
@ -19,24 +19,21 @@ const int NUMBER_OF_NOISE_SAMPLE_BLOCKS = 300;
|
|||
class AudioNoiseGate {
|
||||
public:
|
||||
AudioNoiseGate();
|
||||
|
||||
|
||||
void gateSamples(int16_t* samples, int numSamples);
|
||||
void removeDCOffset(int16_t* samples, int numSamples);
|
||||
|
||||
|
||||
bool clippedInLastBlock() const { return _didClipInLastBlock; }
|
||||
bool closedInLastBlock() const { return _closedInLastBlock; }
|
||||
bool openedInLastBlock() const { return _openedInLastBlock; }
|
||||
bool isOpen() const { return _isOpen; }
|
||||
float getMeasuredFloor() const { return _measuredFloor; }
|
||||
float getLastLoudness() const { return _lastLoudness; }
|
||||
|
||||
|
||||
static const float CLIPPING_THRESHOLD;
|
||||
|
||||
|
||||
private:
|
||||
int _inputBlockCounter;
|
||||
float _lastLoudness;
|
||||
float _quietestBlock;
|
||||
float _loudestBlock;
|
||||
bool _didClipInLastBlock;
|
||||
float _dcOffset;
|
||||
float _measuredFloor;
|
||||
|
@ -48,4 +45,4 @@ private:
|
|||
int _blocksToClose;
|
||||
};
|
||||
|
||||
#endif // hifi_AudioNoiseGate_h
|
||||
#endif // hifi_AudioNoiseGate_h
|
|
@ -947,7 +947,7 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
|
|||
|
||||
void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
|
||||
if (_tree && !_shuttingDown && _entitiesScriptEngine) {
|
||||
_entitiesScriptEngine->unloadEntityScript(entityID);
|
||||
_entitiesScriptEngine->unloadEntityScript(entityID, true);
|
||||
}
|
||||
|
||||
forceRecheckEntities(); // reset our state to force checking our inside/outsideness of entities
|
||||
|
|
|
@ -13,18 +13,31 @@
|
|||
#define hifi_NodePermissions_h
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <QString>
|
||||
#include <QMap>
|
||||
#include <QVariant>
|
||||
#include <QUuid>
|
||||
|
||||
#include <QHash>
|
||||
#include <utility>
|
||||
#include "GroupRank.h"
|
||||
|
||||
class NodePermissions;
|
||||
using NodePermissionsPointer = std::shared_ptr<NodePermissions>;
|
||||
using NodePermissionsKey = QPair<QString, QUuid>; // name, rankID
|
||||
using NodePermissionsKey = std::pair<QString, QUuid>; // name, rankID
|
||||
using NodePermissionsKeyList = QList<QPair<QString, QUuid>>;
|
||||
|
||||
namespace std {
|
||||
template<>
|
||||
struct hash<NodePermissionsKey> {
|
||||
size_t operator()(const NodePermissionsKey& key) const {
|
||||
size_t result = qHash(key.first);
|
||||
result <<= 32;
|
||||
result |= qHash(key.second);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class NodePermissions {
|
||||
public:
|
||||
|
@ -100,27 +113,40 @@ public:
|
|||
NodePermissionsMap() { }
|
||||
NodePermissionsPointer& operator[](const NodePermissionsKey& key) {
|
||||
NodePermissionsKey dataKey(key.first.toLower(), key.second);
|
||||
if (!_data.contains(dataKey)) {
|
||||
if (0 == _data.count(dataKey)) {
|
||||
_data[dataKey] = NodePermissionsPointer(new NodePermissions(key));
|
||||
}
|
||||
return _data[dataKey];
|
||||
}
|
||||
NodePermissionsPointer operator[](const NodePermissionsKey& key) const {
|
||||
return _data.value(NodePermissionsKey(key.first.toLower(), key.second));
|
||||
NodePermissionsPointer result;
|
||||
auto itr = _data.find(NodePermissionsKey(key.first.toLower(), key.second));
|
||||
if (_data.end() != itr) {
|
||||
result = itr->second;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
bool contains(const NodePermissionsKey& key) const {
|
||||
return _data.contains(NodePermissionsKey(key.first.toLower(), key.second));
|
||||
return 0 != _data.count(NodePermissionsKey(key.first.toLower(), key.second));
|
||||
}
|
||||
bool contains(const QString& keyFirst, QUuid keySecond) const {
|
||||
return _data.contains(NodePermissionsKey(keyFirst.toLower(), keySecond));
|
||||
bool contains(const QString& keyFirst, const QUuid& keySecond) const {
|
||||
return 0 != _data.count(NodePermissionsKey(keyFirst.toLower(), keySecond));
|
||||
}
|
||||
QList<NodePermissionsKey> keys() const { return _data.keys(); }
|
||||
QHash<NodePermissionsKey, NodePermissionsPointer> get() { return _data; }
|
||||
|
||||
QList<NodePermissionsKey> keys() const {
|
||||
QList<NodePermissionsKey> result;
|
||||
for (const auto& entry : _data) {
|
||||
result.push_back(entry.first);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::unordered_map<NodePermissionsKey, NodePermissionsPointer>& get() { return _data; }
|
||||
void clear() { _data.clear(); }
|
||||
void remove(const NodePermissionsKey& key) { _data.remove(key); }
|
||||
void remove(const NodePermissionsKey& key) { _data.erase(key); }
|
||||
|
||||
private:
|
||||
QHash<NodePermissionsKey, NodePermissionsPointer> _data;
|
||||
std::unordered_map<NodePermissionsKey, NodePermissionsPointer> _data;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
|
||||
using namespace udt;
|
||||
|
||||
PacketQueue::PacketQueue() {
|
||||
_channels.emplace_back(new std::list<PacketPointer>());
|
||||
}
|
||||
|
||||
MessageNumber PacketQueue::getNextMessageNumber() {
|
||||
static const MessageNumber MAX_MESSAGE_NUMBER = MessageNumber(1) << MESSAGE_NUMBER_SIZE;
|
||||
_currentMessageNumber = (_currentMessageNumber + 1) % MAX_MESSAGE_NUMBER;
|
||||
|
@ -24,7 +28,7 @@ MessageNumber PacketQueue::getNextMessageNumber() {
|
|||
bool PacketQueue::isEmpty() const {
|
||||
LockGuard locker(_packetsLock);
|
||||
// Only the main channel and it is empty
|
||||
return (_channels.size() == 1) && _channels.front().empty();
|
||||
return (_channels.size() == 1) && _channels.front()->empty();
|
||||
}
|
||||
|
||||
PacketQueue::PacketPointer PacketQueue::takePacket() {
|
||||
|
@ -34,19 +38,19 @@ PacketQueue::PacketPointer PacketQueue::takePacket() {
|
|||
}
|
||||
|
||||
// Find next non empty channel
|
||||
if (_channels[nextIndex()].empty()) {
|
||||
if (_channels[nextIndex()]->empty()) {
|
||||
nextIndex();
|
||||
}
|
||||
auto& channel = _channels[_currentIndex];
|
||||
Q_ASSERT(!channel.empty());
|
||||
Q_ASSERT(!channel->empty());
|
||||
|
||||
// Take front packet
|
||||
auto packet = std::move(channel.front());
|
||||
channel.pop_front();
|
||||
auto packet = std::move(channel->front());
|
||||
channel->pop_front();
|
||||
|
||||
// Remove now empty channel (Don't remove the main channel)
|
||||
if (channel.empty() && _currentIndex != 0) {
|
||||
channel.swap(_channels.back());
|
||||
if (channel->empty() && _currentIndex != 0) {
|
||||
channel->swap(*_channels.back());
|
||||
_channels.pop_back();
|
||||
--_currentIndex;
|
||||
}
|
||||
|
@ -61,7 +65,7 @@ unsigned int PacketQueue::nextIndex() {
|
|||
|
||||
void PacketQueue::queuePacket(PacketPointer packet) {
|
||||
LockGuard locker(_packetsLock);
|
||||
_channels.front().push_back(std::move(packet));
|
||||
_channels.front()->push_back(std::move(packet));
|
||||
}
|
||||
|
||||
void PacketQueue::queuePacketList(PacketListPointer packetList) {
|
||||
|
@ -70,5 +74,6 @@ void PacketQueue::queuePacketList(PacketListPointer packetList) {
|
|||
}
|
||||
|
||||
LockGuard locker(_packetsLock);
|
||||
_channels.push_back(std::move(packetList->_packets));
|
||||
_channels.emplace_back(new std::list<PacketPointer>());
|
||||
_channels.back()->swap(packetList->_packets);
|
||||
}
|
||||
|
|
|
@ -30,10 +30,11 @@ class PacketQueue {
|
|||
using LockGuard = std::lock_guard<Mutex>;
|
||||
using PacketPointer = std::unique_ptr<Packet>;
|
||||
using PacketListPointer = std::unique_ptr<PacketList>;
|
||||
using Channel = std::list<PacketPointer>;
|
||||
using Channel = std::unique_ptr<std::list<PacketPointer>>;
|
||||
using Channels = std::vector<Channel>;
|
||||
|
||||
public:
|
||||
PacketQueue();
|
||||
void queuePacket(PacketPointer packet);
|
||||
void queuePacketList(PacketListPointer packetList);
|
||||
|
||||
|
@ -49,7 +50,7 @@ private:
|
|||
MessageNumber _currentMessageNumber { 0 };
|
||||
|
||||
mutable Mutex _packetsLock; // Protects the packets to be sent.
|
||||
Channels _channels = Channels(1); // One channel per packet list + Main channel
|
||||
Channels _channels; // One channel per packet list + Main channel
|
||||
unsigned int _currentIndex { 0 };
|
||||
};
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ void Deck::queueClip(ClipPointer clip, float timeOffset) {
|
|||
|
||||
// FIXME disabling multiple clips for now
|
||||
_clips.clear();
|
||||
_length = 0.0f;
|
||||
|
||||
// if the time offset is not zero, wrap in an OffsetClip
|
||||
if (timeOffset != 0.0f) {
|
||||
|
@ -153,8 +154,8 @@ void Deck::processFrames() {
|
|||
// if doing relative movement
|
||||
emit looped();
|
||||
} else {
|
||||
// otherwise pause playback
|
||||
pause();
|
||||
// otherwise stop playback
|
||||
stop();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -372,19 +372,12 @@ void ModelMeshPartPayload::notifyLocationChanged() {
|
|||
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& transform, const QVector<glm::mat4>& clusterMatrices) {
|
||||
_transform = transform;
|
||||
|
||||
if (clusterMatrices.size() > 0) {
|
||||
_worldBound = _adjustedLocalBound;
|
||||
_worldBound.transform(_transform);
|
||||
if (clusterMatrices.size() == 1) {
|
||||
_transform = _transform.worldTransform(Transform(clusterMatrices[0]));
|
||||
}
|
||||
} else {
|
||||
_worldBound = _localBound;
|
||||
_worldBound.transform(_transform);
|
||||
}
|
||||
void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform,
|
||||
const gpu::BufferPointer& buffer) {
|
||||
_transform = renderTransform;
|
||||
_worldBound = _adjustedLocalBound;
|
||||
_worldBound.transform(boundTransform);
|
||||
_clusterBuffer = buffer;
|
||||
}
|
||||
|
||||
ItemKey ModelMeshPartPayload::getKey() const {
|
||||
|
@ -532,9 +525,8 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) const {
|
|||
|
||||
void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const {
|
||||
// Still relying on the raw data from the model
|
||||
const Model::MeshState& state = _model->getMeshState(_meshIndex);
|
||||
if (state.clusterBuffer) {
|
||||
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, state.clusterBuffer);
|
||||
if (_clusterBuffer) {
|
||||
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, _clusterBuffer);
|
||||
}
|
||||
batch.setModelTransform(_transform);
|
||||
}
|
||||
|
@ -590,8 +582,6 @@ void ModelMeshPartPayload::render(RenderArgs* args) const {
|
|||
auto locations = args->_pipeline->locations;
|
||||
assert(locations);
|
||||
|
||||
// Bind the model transform and the skinCLusterMatrices if needed
|
||||
_model->updateClusterMatrices();
|
||||
bindTransform(batch, locations, args->_renderMode);
|
||||
|
||||
//Bind the index buffer and vertex buffer and Blend shapes if needed
|
||||
|
|
|
@ -89,8 +89,9 @@ public:
|
|||
typedef Payload::DataPointer Pointer;
|
||||
|
||||
void notifyLocationChanged() override;
|
||||
void updateTransformForSkinnedMesh(const Transform& transform,
|
||||
const QVector<glm::mat4>& clusterMatrices);
|
||||
void updateTransformForSkinnedMesh(const Transform& renderTransform,
|
||||
const Transform& boundTransform,
|
||||
const gpu::BufferPointer& buffer);
|
||||
|
||||
float computeFadeAlpha() const;
|
||||
|
||||
|
@ -108,6 +109,7 @@ public:
|
|||
|
||||
void computeAdjustedLocalBound(const QVector<glm::mat4>& clusterMatrices);
|
||||
|
||||
gpu::BufferPointer _clusterBuffer;
|
||||
Model* _model;
|
||||
|
||||
int _meshIndex;
|
||||
|
|
|
@ -227,6 +227,10 @@ void Model::updateRenderItems() {
|
|||
return;
|
||||
}
|
||||
|
||||
// lazy update of cluster matrices used for rendering.
|
||||
// We need to update them here so we can correctly update the bounding box.
|
||||
self->updateClusterMatrices();
|
||||
|
||||
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||
|
||||
uint32_t deleteGeometryCounter = self->_deleteGeometryCounter;
|
||||
|
@ -240,12 +244,12 @@ void Model::updateRenderItems() {
|
|||
Transform modelTransform = data._model->getTransform();
|
||||
modelTransform.setScale(glm::vec3(1.0f));
|
||||
|
||||
// lazy update of cluster matrices used for rendering. We need to update them here, so we can correctly update the bounding box.
|
||||
data._model->updateClusterMatrices();
|
||||
|
||||
// update the model transform and bounding box for this render item.
|
||||
const Model::MeshState& state = data._model->_meshStates.at(data._meshIndex);
|
||||
data.updateTransformForSkinnedMesh(modelTransform, state.clusterMatrices);
|
||||
const Model::MeshState& state = data._model->getMeshState(data._meshIndex);
|
||||
Transform renderTransform = modelTransform;
|
||||
if (state.clusterMatrices.size() == 1) {
|
||||
renderTransform = modelTransform.worldTransform(Transform(state.clusterMatrices[0]));
|
||||
}
|
||||
data.updateTransformForSkinnedMesh(renderTransform, modelTransform, state.clusterBuffer);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1048,7 +1052,7 @@ void Model::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
}
|
||||
|
||||
void Model::computeMeshPartLocalBounds() {
|
||||
for (auto& part : _modelMeshRenderItemsSet) {
|
||||
for (auto& part : _modelMeshRenderItemsSet) {
|
||||
assert(part->_meshIndex < _modelMeshRenderItemsSet.size());
|
||||
const Model::MeshState& state = _meshStates.at(part->_meshIndex);
|
||||
part->computeAdjustedLocalBound(state.clusterMatrices);
|
||||
|
|
|
@ -541,16 +541,6 @@ void ScriptEngine::init() {
|
|||
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
entityScriptingInterface->init();
|
||||
connect(entityScriptingInterface.data(), &EntityScriptingInterface::deletingEntity, this, [this](const EntityItemID& entityID) {
|
||||
if (_entityScripts.contains(entityID)) {
|
||||
if (isEntityScriptRunning(entityID)) {
|
||||
qCWarning(scriptengine) << "deletingEntity while entity script is still running!" << entityID;
|
||||
}
|
||||
_entityScripts.remove(entityID);
|
||||
emit entityScriptDetailsUpdated();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// register various meta-types
|
||||
registerMetaTypes(this);
|
||||
|
@ -1844,7 +1834,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co
|
|||
processDeferredEntityLoads(entityScript, entityID);
|
||||
}
|
||||
|
||||
void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) {
|
||||
void ScriptEngine::unloadEntityScript(const EntityItemID& entityID, bool shouldRemoveFromMap) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
#ifdef THREAD_DEBUGGING
|
||||
qCDebug(scriptengine) << "*** WARNING *** ScriptEngine::unloadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] "
|
||||
|
@ -1852,7 +1842,8 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) {
|
|||
#endif
|
||||
|
||||
QMetaObject::invokeMethod(this, "unloadEntityScript",
|
||||
Q_ARG(const EntityItemID&, entityID));
|
||||
Q_ARG(const EntityItemID&, entityID),
|
||||
Q_ARG(bool, shouldRemoveFromMap));
|
||||
return;
|
||||
}
|
||||
#ifdef THREAD_DEBUGGING
|
||||
|
@ -1867,7 +1858,12 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) {
|
|||
} else {
|
||||
qCDebug(scriptengine) << "unload called while !running" << entityID << oldDetails.status;
|
||||
}
|
||||
if (oldDetails.status != EntityScriptStatus::UNLOADED) {
|
||||
|
||||
if (shouldRemoveFromMap) {
|
||||
// this was a deleted entity, we've been asked to remove it from the map
|
||||
_entityScripts.remove(entityID);
|
||||
emit entityScriptDetailsUpdated();
|
||||
} else if (oldDetails.status != EntityScriptStatus::UNLOADED) {
|
||||
EntityScriptDetails newDetails;
|
||||
newDetails.status = EntityScriptStatus::UNLOADED;
|
||||
newDetails.lastModified = QDateTime::currentMSecsSinceEpoch();
|
||||
|
@ -1875,6 +1871,7 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) {
|
|||
newDetails.scriptText = oldDetails.scriptText;
|
||||
setEntityScriptDetails(entityID, newDetails);
|
||||
}
|
||||
|
||||
stopAllTimersForEntityScript(entityID);
|
||||
{
|
||||
// FIXME: shouldn't have to do this here, but currently something seems to be firing unloads moments after firing initial load requests
|
||||
|
|
|
@ -171,7 +171,7 @@ public:
|
|||
return _entityScripts.contains(entityID) && _entityScripts[entityID].status == EntityScriptStatus::RUNNING;
|
||||
}
|
||||
Q_INVOKABLE void loadEntityScript(const EntityItemID& entityID, const QString& entityScript, bool forceRedownload);
|
||||
Q_INVOKABLE void unloadEntityScript(const EntityItemID& entityID); // will call unload method
|
||||
Q_INVOKABLE void unloadEntityScript(const EntityItemID& entityID, bool shouldRemoveFromMap = false); // will call unload method
|
||||
Q_INVOKABLE void unloadAllEntityScripts();
|
||||
Q_INVOKABLE void callEntityScriptMethod(const EntityItemID& entityID, const QString& methodName,
|
||||
const QStringList& params = QStringList()) override;
|
||||
|
|
|
@ -56,7 +56,14 @@ public:
|
|||
QQuickWindow* getTabletWindow();
|
||||
|
||||
QObject* getFlags();
|
||||
|
||||
signals:
|
||||
/** jsdoc
|
||||
* Signaled when a tablet message or dialog is created
|
||||
* @function TabletProxy#tabletNotification
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void tabletNotification();
|
||||
|
||||
private:
|
||||
void processMenuEvents(QObject* object, const QKeyEvent* event);
|
||||
void processTabletEvents(QObject* object, const QKeyEvent* event);
|
||||
|
|
|
@ -223,6 +223,7 @@ QQuickItem* OffscreenUi::createMessageBox(Icon icon, const QString& title, const
|
|||
invokeResult = QMetaObject::invokeMethod(tabletRoot, "messageBox",
|
||||
Q_RETURN_ARG(QVariant, result),
|
||||
Q_ARG(QVariant, QVariant::fromValue(map)));
|
||||
emit tabletScriptingInterface->tabletNotification();
|
||||
}
|
||||
|
||||
if (!invokeResult) {
|
||||
|
@ -430,6 +431,7 @@ QQuickItem* OffscreenUi::createInputDialog(const Icon icon, const QString& title
|
|||
invokeResult = QMetaObject::invokeMethod(tabletRoot, "inputDialog",
|
||||
Q_RETURN_ARG(QVariant, result),
|
||||
Q_ARG(QVariant, QVariant::fromValue(map)));
|
||||
emit tabletScriptingInterface->tabletNotification();
|
||||
}
|
||||
if (!invokeResult) {
|
||||
qWarning() << "Failed to create message box";
|
||||
|
@ -457,6 +459,7 @@ QQuickItem* OffscreenUi::createCustomInputDialog(const Icon icon, const QString&
|
|||
invokeResult = QMetaObject::invokeMethod(tabletRoot, "inputDialog",
|
||||
Q_RETURN_ARG(QVariant, result),
|
||||
Q_ARG(QVariant, QVariant::fromValue(map)));
|
||||
emit tabletScriptingInterface->tabletNotification();
|
||||
}
|
||||
|
||||
if (!invokeResult) {
|
||||
|
@ -614,6 +617,7 @@ QString OffscreenUi::fileDialog(const QVariantMap& properties) {
|
|||
invokeResult = QMetaObject::invokeMethod(tabletRoot, "fileDialog",
|
||||
Q_RETURN_ARG(QVariant, buildDialogResult),
|
||||
Q_ARG(QVariant, QVariant::fromValue(properties)));
|
||||
emit tabletScriptingInterface->tabletNotification();
|
||||
}
|
||||
|
||||
if (!invokeResult) {
|
||||
|
|
|
@ -9,12 +9,14 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
/* globals HIFI_PUBLIC_BUCKET:true, Tool, ToolBar */
|
||||
|
||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||
Script.include("/~/system/libraries/toolBars.js");
|
||||
|
||||
var recordingFile = "recording.hfr";
|
||||
|
||||
function setPlayerOptions() {
|
||||
function setDefaultPlayerOptions() {
|
||||
Recording.setPlayFromCurrentLocation(true);
|
||||
Recording.setPlayerUseDisplayName(false);
|
||||
Recording.setPlayerUseAttachments(false);
|
||||
|
@ -38,16 +40,16 @@ var saveIcon;
|
|||
var loadIcon;
|
||||
var spacing;
|
||||
var timerOffset;
|
||||
setupToolBar();
|
||||
|
||||
var timer = null;
|
||||
var slider = null;
|
||||
|
||||
setupToolBar();
|
||||
setupTimer();
|
||||
|
||||
var watchStop = false;
|
||||
|
||||
function setupToolBar() {
|
||||
if (toolBar != null) {
|
||||
if (toolBar !== null) {
|
||||
print("Multiple calls to Recorder.js:setupToolBar()");
|
||||
return;
|
||||
}
|
||||
|
@ -56,6 +58,8 @@ function setupToolBar() {
|
|||
|
||||
toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL);
|
||||
|
||||
toolBar.onMove = onToolbarMove;
|
||||
|
||||
toolBar.setBack(COLOR_TOOL_BAR, ALPHA_OFF);
|
||||
|
||||
recordIcon = toolBar.addTool({
|
||||
|
@ -86,7 +90,7 @@ function setupToolBar() {
|
|||
visible: true
|
||||
}, false);
|
||||
|
||||
timerOffset = toolBar.width;
|
||||
timerOffset = toolBar.width + ToolBar.SPACING;
|
||||
spacing = toolBar.addSpacing(0);
|
||||
|
||||
saveIcon = toolBar.addTool({
|
||||
|
@ -112,15 +116,15 @@ function setupTimer() {
|
|||
text: (0.00).toFixed(3),
|
||||
backgroundColor: COLOR_OFF,
|
||||
x: 0, y: 0,
|
||||
width: 0, height: 0,
|
||||
leftMargin: 10, topMargin: 10,
|
||||
width: 200, height: 25,
|
||||
leftMargin: 5, topMargin: 3,
|
||||
alpha: 1.0, backgroundAlpha: 1.0,
|
||||
visible: true
|
||||
});
|
||||
|
||||
slider = { x: 0, y: 0,
|
||||
w: 200, h: 20,
|
||||
pos: 0.0, // 0.0 <= pos <= 1.0
|
||||
pos: 0.0 // 0.0 <= pos <= 1.0
|
||||
};
|
||||
slider.background = Overlays.addOverlay("text", {
|
||||
text: "",
|
||||
|
@ -144,20 +148,40 @@ function setupTimer() {
|
|||
});
|
||||
}
|
||||
|
||||
function onToolbarMove(newX, newY, deltaX, deltaY) {
|
||||
Overlays.editOverlay(timer, {
|
||||
x: newX + timerOffset - ToolBar.SPACING,
|
||||
y: newY
|
||||
});
|
||||
|
||||
slider.x = newX - ToolBar.SPACING;
|
||||
slider.y = newY - slider.h - ToolBar.SPACING;
|
||||
|
||||
Overlays.editOverlay(slider.background, {
|
||||
x: slider.x,
|
||||
y: slider.y
|
||||
});
|
||||
Overlays.editOverlay(slider.foreground, {
|
||||
x: slider.x,
|
||||
y: slider.y
|
||||
});
|
||||
}
|
||||
|
||||
function updateTimer() {
|
||||
var text = "";
|
||||
if (Recording.isRecording()) {
|
||||
text = formatTime(Recording.recorderElapsed());
|
||||
|
||||
} else {
|
||||
text = formatTime(Recording.playerElapsed()) + " / " +
|
||||
formatTime(Recording.playerLength());
|
||||
text = formatTime(Recording.playerElapsed()) + " / " + formatTime(Recording.playerLength());
|
||||
}
|
||||
|
||||
var timerWidth = text.length * 8 + ((Recording.isRecording()) ? 15 : 0);
|
||||
|
||||
Overlays.editOverlay(timer, {
|
||||
text: text
|
||||
})
|
||||
toolBar.changeSpacing(text.length * 8 + ((Recording.isRecording()) ? 15 : 0), spacing);
|
||||
text: text,
|
||||
width: timerWidth
|
||||
});
|
||||
toolBar.changeSpacing(timerWidth + ToolBar.SPACING, spacing);
|
||||
|
||||
if (Recording.isRecording()) {
|
||||
slider.pos = 1.0;
|
||||
|
@ -173,7 +197,7 @@ function updateTimer() {
|
|||
function formatTime(time) {
|
||||
var MIN_PER_HOUR = 60;
|
||||
var SEC_PER_MIN = 60;
|
||||
var MSEC_PER_SEC = 1000;
|
||||
var MSEC_DIGITS = 3;
|
||||
|
||||
var hours = Math.floor(time / (SEC_PER_MIN * MIN_PER_HOUR));
|
||||
time -= hours * (SEC_PER_MIN * MIN_PER_HOUR);
|
||||
|
@ -184,37 +208,19 @@ function formatTime(time) {
|
|||
var seconds = time;
|
||||
|
||||
var text = "";
|
||||
text += (hours > 0) ? hours + ":" :
|
||||
"";
|
||||
text += (minutes > 0) ? ((minutes < 10 && text != "") ? "0" : "") + minutes + ":" :
|
||||
"";
|
||||
text += ((seconds < 10 && text != "") ? "0" : "") + seconds.toFixed(3);
|
||||
text += (hours > 0) ? hours + ":" : "";
|
||||
text += (minutes > 0) ? ((minutes < 10 && text !== "") ? "0" : "") + minutes + ":" : "";
|
||||
text += ((seconds < 10 && text !== "") ? "0" : "") + seconds.toFixed(MSEC_DIGITS);
|
||||
return text;
|
||||
}
|
||||
|
||||
function moveUI() {
|
||||
var relative = { x: 70, y: 40 };
|
||||
toolBar.move(relative.x, windowDimensions.y - relative.y);
|
||||
Overlays.editOverlay(timer, {
|
||||
x: relative.x + timerOffset - ToolBar.SPACING,
|
||||
y: windowDimensions.y - relative.y - ToolBar.SPACING
|
||||
});
|
||||
|
||||
slider.x = relative.x - ToolBar.SPACING;
|
||||
slider.y = windowDimensions.y - relative.y - slider.h - ToolBar.SPACING;
|
||||
|
||||
Overlays.editOverlay(slider.background, {
|
||||
x: slider.x,
|
||||
y: slider.y,
|
||||
});
|
||||
Overlays.editOverlay(slider.foreground, {
|
||||
x: slider.x,
|
||||
y: slider.y,
|
||||
});
|
||||
}
|
||||
|
||||
function mousePressEvent(event) {
|
||||
clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
|
||||
var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
|
||||
|
||||
if (recordIcon === toolBar.clicked(clickedOverlay, false) && !Recording.isPlaying()) {
|
||||
if (!Recording.isRecording()) {
|
||||
|
@ -226,7 +232,11 @@ function mousePressEvent(event) {
|
|||
toolBar.setAlpha(ALPHA_OFF, loadIcon);
|
||||
} else {
|
||||
Recording.stopRecording();
|
||||
toolBar.selectTool(recordIcon, true );
|
||||
toolBar.selectTool(recordIcon, true);
|
||||
setDefaultPlayerOptions();
|
||||
// Plays the recording at the same spot as you recorded it
|
||||
Recording.setPlayFromCurrentLocation(false);
|
||||
Recording.setPlayerTime(0);
|
||||
Recording.loadLastRecording();
|
||||
toolBar.setAlpha(ALPHA_ON, playIcon);
|
||||
toolBar.setAlpha(ALPHA_ON, playLoopIcon);
|
||||
|
@ -240,7 +250,6 @@ function mousePressEvent(event) {
|
|||
toolBar.setAlpha(ALPHA_ON, saveIcon);
|
||||
toolBar.setAlpha(ALPHA_ON, loadIcon);
|
||||
} else if (Recording.playerLength() > 0) {
|
||||
setPlayerOptions();
|
||||
Recording.setPlayerLoop(false);
|
||||
Recording.startPlaying();
|
||||
toolBar.setAlpha(ALPHA_OFF, recordIcon);
|
||||
|
@ -255,7 +264,6 @@ function mousePressEvent(event) {
|
|||
toolBar.setAlpha(ALPHA_ON, saveIcon);
|
||||
toolBar.setAlpha(ALPHA_ON, loadIcon);
|
||||
} else if (Recording.playerLength() > 0) {
|
||||
setPlayerOptions();
|
||||
Recording.setPlayerLoop(true);
|
||||
Recording.startPlaying();
|
||||
toolBar.setAlpha(ALPHA_OFF, recordIcon);
|
||||
|
@ -263,7 +271,7 @@ function mousePressEvent(event) {
|
|||
toolBar.setAlpha(ALPHA_OFF, loadIcon);
|
||||
}
|
||||
} else if (saveIcon === toolBar.clicked(clickedOverlay)) {
|
||||
if (!Recording.isRecording() && !Recording.isPlaying() && Recording.playerLength() != 0) {
|
||||
if (!Recording.isRecording() && !Recording.isPlaying() && Recording.playerLength() !== 0) {
|
||||
recordingFile = Window.save("Save recording to file", ".", "Recordings (*.hfr)");
|
||||
if (!(recordingFile === "null" || recordingFile === null || recordingFile === "")) {
|
||||
Recording.saveRecording(recordingFile);
|
||||
|
@ -274,6 +282,7 @@ function mousePressEvent(event) {
|
|||
recordingFile = Window.browse("Load recording from file", ".", "Recordings (*.hfr *.rec *.HFR *.REC)");
|
||||
if (!(recordingFile === "null" || recordingFile === null || recordingFile === "")) {
|
||||
Recording.loadRecording(recordingFile);
|
||||
setDefaultPlayerOptions();
|
||||
}
|
||||
if (Recording.playerLength() > 0) {
|
||||
toolBar.setAlpha(ALPHA_ON, playIcon);
|
||||
|
@ -282,8 +291,8 @@ function mousePressEvent(event) {
|
|||
}
|
||||
}
|
||||
} else if (Recording.playerLength() > 0 &&
|
||||
slider.x < event.x && event.x < slider.x + slider.w &&
|
||||
slider.y < event.y && event.y < slider.y + slider.h) {
|
||||
slider.x < event.x && event.x < slider.x + slider.w &&
|
||||
slider.y < event.y && event.y < slider.y + slider.h) {
|
||||
isSliding = true;
|
||||
slider.pos = (event.x - slider.x) / slider.w;
|
||||
Recording.setPlayerTime(slider.pos * Recording.playerLength());
|
||||
|
@ -308,7 +317,7 @@ function mouseReleaseEvent(event) {
|
|||
|
||||
function update() {
|
||||
var newDimensions = Controller.getViewportDimensions();
|
||||
if (windowDimensions.x != newDimensions.x || windowDimensions.y != newDimensions.y) {
|
||||
if (windowDimensions.x !== newDimensions.x || windowDimensions.y !== newDimensions.y) {
|
||||
windowDimensions = newDimensions;
|
||||
moveUI();
|
||||
}
|
||||
|
|
|
@ -160,6 +160,7 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit
|
|||
visible: false
|
||||
});
|
||||
this.spacing = [];
|
||||
this.onMove = null;
|
||||
|
||||
this.addTool = function(properties, selectable, selected) {
|
||||
if (direction == ToolBar.HORIZONTAL) {
|
||||
|
@ -254,6 +255,9 @@ ToolBar = function(x, y, direction, optionalPersistenceKey, optionalInitialPosit
|
|||
y: y - ToolBar.SPACING
|
||||
});
|
||||
}
|
||||
if (this.onMove !== null) {
|
||||
this.onMove(x, y, dx, dy);
|
||||
};
|
||||
}
|
||||
|
||||
this.setAlpha = function(alpha, tool) {
|
||||
|
|
|
@ -94,11 +94,13 @@ var NotificationType = {
|
|||
LOD_WARNING: 2,
|
||||
CONNECTION_REFUSED: 3,
|
||||
EDIT_ERROR: 4,
|
||||
TABLET: 5,
|
||||
properties: [
|
||||
{ text: "Snapshot" },
|
||||
{ text: "Level of Detail" },
|
||||
{ text: "Connection Refused" },
|
||||
{ text: "Edit error" }
|
||||
{ text: "Edit error" },
|
||||
{ text: "Tablet" }
|
||||
],
|
||||
getTypeFromMenuItem: function(menuItemName) {
|
||||
if (menuItemName.substr(menuItemName.length - NOTIFICATION_MENU_ITEM_POST.length) !== NOTIFICATION_MENU_ITEM_POST) {
|
||||
|
@ -535,6 +537,10 @@ function onSnapshotTaken(pathStillSnapshot, pathAnimatedSnapshot, notify) {
|
|||
}
|
||||
}
|
||||
|
||||
function tabletNotification() {
|
||||
createNotification("Tablet needs your attention", NotificationType.TABLET);
|
||||
}
|
||||
|
||||
function processingGif() {
|
||||
createNotification("Processing GIF snapshot...", NotificationType.SNAPSHOT);
|
||||
}
|
||||
|
@ -641,7 +647,7 @@ Window.snapshotTaken.connect(onSnapshotTaken);
|
|||
Window.processingGif.connect(processingGif);
|
||||
Window.notifyEditError = onEditError;
|
||||
Window.notify = onNotify;
|
||||
|
||||
Tablet.tabletNotification.connect(tabletNotification);
|
||||
setup();
|
||||
|
||||
}()); // END LOCAL_SCOPE
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
Script.include("/~/system/libraries/utils.js");
|
||||
|
||||
var SETTING_KEY = "com.highfidelity.avatar.isSitting";
|
||||
var ROLE = "fly";
|
||||
var ANIMATION_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/animations/sitting_idle.fbx";
|
||||
var ANIMATION_FPS = 30;
|
||||
var ANIMATION_FIRST_FRAME = 1;
|
||||
|
@ -10,23 +9,25 @@
|
|||
var RELEASE_KEYS = ['w', 'a', 's', 'd', 'UP', 'LEFT', 'DOWN', 'RIGHT'];
|
||||
var RELEASE_TIME = 500; // ms
|
||||
var RELEASE_DISTANCE = 0.2; // meters
|
||||
var MAX_IK_ERROR = 20;
|
||||
var DESKTOP_UI_CHECK_INTERVAL = 250;
|
||||
var MAX_IK_ERROR = 30;
|
||||
var DESKTOP_UI_CHECK_INTERVAL = 100;
|
||||
var DESKTOP_MAX_DISTANCE = 5;
|
||||
var SIT_DELAY = 25
|
||||
var MAX_RESET_DISTANCE = 0.5
|
||||
|
||||
this.entityID = null;
|
||||
this.timers = {};
|
||||
this.animStateHandlerID = null;
|
||||
this.interval = null;
|
||||
|
||||
this.preload = function(entityID) {
|
||||
this.entityID = entityID;
|
||||
}
|
||||
this.unload = function() {
|
||||
if (MyAvatar.sessionUUID === this.getSeatUser()) {
|
||||
this.sitUp(this.entityID);
|
||||
if (Settings.getValue(SETTING_KEY) === this.entityID) {
|
||||
this.sitUp();
|
||||
}
|
||||
if (this.interval) {
|
||||
if (this.interval !== null) {
|
||||
Script.clearInterval(this.interval);
|
||||
this.interval = null;
|
||||
}
|
||||
|
@ -34,42 +35,60 @@
|
|||
}
|
||||
|
||||
this.setSeatUser = function(user) {
|
||||
var userData = Entities.getEntityProperties(this.entityID, ["userData"]).userData;
|
||||
userData = JSON.parse(userData);
|
||||
try {
|
||||
var userData = Entities.getEntityProperties(this.entityID, ["userData"]).userData;
|
||||
userData = JSON.parse(userData);
|
||||
|
||||
if (user) {
|
||||
userData.seat.user = user;
|
||||
} else {
|
||||
delete userData.seat.user;
|
||||
if (user !== null) {
|
||||
userData.seat.user = user;
|
||||
} else {
|
||||
delete userData.seat.user;
|
||||
}
|
||||
|
||||
Entities.editEntity(this.entityID, {
|
||||
userData: JSON.stringify(userData)
|
||||
});
|
||||
} catch (e) {
|
||||
// Do Nothing
|
||||
}
|
||||
|
||||
Entities.editEntity(this.entityID, {
|
||||
userData: JSON.stringify(userData)
|
||||
});
|
||||
}
|
||||
this.getSeatUser = function() {
|
||||
var properties = Entities.getEntityProperties(this.entityID, ["userData", "position"]);
|
||||
var userData = JSON.parse(properties.userData);
|
||||
try {
|
||||
var properties = Entities.getEntityProperties(this.entityID, ["userData", "position"]);
|
||||
var userData = JSON.parse(properties.userData);
|
||||
|
||||
if (userData.seat.user && userData.seat.user !== MyAvatar.sessionUUID) {
|
||||
var avatar = AvatarList.getAvatar(userData.seat.user);
|
||||
if (avatar && Vec3.distance(avatar.position, properties.position) > RELEASE_DISTANCE) {
|
||||
return null;
|
||||
// If MyAvatar return my uuid
|
||||
if (userData.seat.user === MyAvatar.sessionUUID) {
|
||||
return userData.seat.user;
|
||||
}
|
||||
|
||||
|
||||
// If Avatar appears to be sitting
|
||||
if (userData.seat.user) {
|
||||
var avatar = AvatarList.getAvatar(userData.seat.user);
|
||||
if (avatar && (Vec3.distance(avatar.position, properties.position) < RELEASE_DISTANCE)) {
|
||||
return userData.seat.user;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Do nothing
|
||||
}
|
||||
return userData.seat.user;
|
||||
|
||||
// Nobody on the seat
|
||||
return null;
|
||||
}
|
||||
|
||||
// Is the seat used
|
||||
this.checkSeatForAvatar = function() {
|
||||
var seatUser = this.getSeatUser();
|
||||
var avatarIdentifiers = AvatarList.getAvatarIdentifiers();
|
||||
for (var i in avatarIdentifiers) {
|
||||
var avatar = AvatarList.getAvatar(avatarIdentifiers[i]);
|
||||
if (avatar && avatar.sessionUUID === seatUser) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If MyAvatar appears to be sitting
|
||||
if (seatUser === MyAvatar.sessionUUID) {
|
||||
var properties = Entities.getEntityProperties(this.entityID, ["position"]);
|
||||
return Vec3.distance(MyAvatar.position, properties.position) < RELEASE_DISTANCE;
|
||||
}
|
||||
return false;
|
||||
|
||||
return seatUser !== null;
|
||||
}
|
||||
|
||||
this.sitDown = function() {
|
||||
|
@ -78,40 +97,50 @@
|
|||
return;
|
||||
}
|
||||
|
||||
this.setSeatUser(MyAvatar.sessionUUID);
|
||||
|
||||
var previousValue = Settings.getValue(SETTING_KEY);
|
||||
Settings.setValue(SETTING_KEY, this.entityID);
|
||||
this.setSeatUser(MyAvatar.sessionUUID);
|
||||
if (previousValue === "") {
|
||||
MyAvatar.characterControllerEnabled = false;
|
||||
MyAvatar.hmdLeanRecenterEnabled = false;
|
||||
MyAvatar.overrideRoleAnimation(ROLE, ANIMATION_URL, ANIMATION_FPS, true, ANIMATION_FIRST_FRAME, ANIMATION_LAST_FRAME);
|
||||
var ROLES = MyAvatar.getAnimationRoles();
|
||||
for (i in ROLES) {
|
||||
MyAvatar.overrideRoleAnimation(ROLES[i], ANIMATION_URL, ANIMATION_FPS, true, ANIMATION_FIRST_FRAME, ANIMATION_LAST_FRAME);
|
||||
}
|
||||
MyAvatar.resetSensorsAndBody();
|
||||
}
|
||||
|
||||
var that = this;
|
||||
Script.setTimeout(function() {
|
||||
var properties = Entities.getEntityProperties(that.entityID, ["position", "rotation"]);
|
||||
var index = MyAvatar.getJointIndex("Hips");
|
||||
MyAvatar.pinJoint(index, properties.position, properties.rotation);
|
||||
var properties = Entities.getEntityProperties(this.entityID, ["position", "rotation"]);
|
||||
var index = MyAvatar.getJointIndex("Hips");
|
||||
MyAvatar.pinJoint(index, properties.position, properties.rotation);
|
||||
|
||||
that.animStateHandlerID = MyAvatar.addAnimationStateHandler(function(properties) {
|
||||
return { headType: 0 };
|
||||
}, ["headType"]);
|
||||
Script.update.connect(that, that.update);
|
||||
Controller.keyPressEvent.connect(that, that.keyPressed);
|
||||
Controller.keyReleaseEvent.connect(that, that.keyReleased);
|
||||
for (var i in RELEASE_KEYS) {
|
||||
Controller.captureKeyEvents({ text: RELEASE_KEYS[i] });
|
||||
}
|
||||
}, SIT_DELAY);
|
||||
this.animStateHandlerID = MyAvatar.addAnimationStateHandler(function(properties) {
|
||||
return { headType: 0 };
|
||||
}, ["headType"]);
|
||||
Script.update.connect(this, this.update);
|
||||
Controller.keyPressEvent.connect(this, this.keyPressed);
|
||||
Controller.keyReleaseEvent.connect(this, this.keyReleased);
|
||||
for (var i in RELEASE_KEYS) {
|
||||
Controller.captureKeyEvents({ text: RELEASE_KEYS[i] });
|
||||
}
|
||||
}
|
||||
|
||||
this.sitUp = function() {
|
||||
this.setSeatUser(null);
|
||||
MyAvatar.removeAnimationStateHandler(this.animStateHandlerID);
|
||||
Script.update.disconnect(this, this.update);
|
||||
Controller.keyPressEvent.disconnect(this, this.keyPressed);
|
||||
Controller.keyReleaseEvent.disconnect(this, this.keyReleased);
|
||||
for (var i in RELEASE_KEYS) {
|
||||
Controller.releaseKeyEvents({ text: RELEASE_KEYS[i] });
|
||||
}
|
||||
|
||||
this.setSeatUser(null);
|
||||
if (Settings.getValue(SETTING_KEY) === this.entityID) {
|
||||
MyAvatar.restoreRoleAnimation(ROLE);
|
||||
Settings.setValue(SETTING_KEY, "");
|
||||
var ROLES = MyAvatar.getAnimationRoles();
|
||||
for (i in ROLES) {
|
||||
MyAvatar.restoreRoleAnimation(ROLES[i]);
|
||||
}
|
||||
MyAvatar.characterControllerEnabled = true;
|
||||
MyAvatar.hmdLeanRecenterEnabled = true;
|
||||
|
||||
|
@ -124,16 +153,6 @@
|
|||
MyAvatar.bodyPitch = 0.0;
|
||||
MyAvatar.bodyRoll = 0.0;
|
||||
}, SIT_DELAY);
|
||||
|
||||
Settings.setValue(SETTING_KEY, "");
|
||||
}
|
||||
|
||||
MyAvatar.removeAnimationStateHandler(this.animStateHandlerID);
|
||||
Script.update.disconnect(this, this.update);
|
||||
Controller.keyPressEvent.disconnect(this, this.keyPressed);
|
||||
Controller.keyReleaseEvent.disconnect(this, this.keyReleased);
|
||||
for (var i in RELEASE_KEYS) {
|
||||
Controller.releaseKeyEvents({ text: RELEASE_KEYS[i] });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,15 +202,22 @@
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
this.update = function(dt) {
|
||||
if (MyAvatar.sessionUUID === this.getSeatUser()) {
|
||||
var properties = Entities.getEntityProperties(this.entityID, ["position"]);
|
||||
var properties = Entities.getEntityProperties(this.entityID);
|
||||
var avatarDistance = Vec3.distance(MyAvatar.position, properties.position);
|
||||
var ikError = MyAvatar.getIKErrorOnLastSolve();
|
||||
if (avatarDistance > RELEASE_DISTANCE || ikError > MAX_IK_ERROR) {
|
||||
print("IK error: " + ikError + ", distance from chair: " + avatarDistance);
|
||||
this.sitUp(this.entityID);
|
||||
|
||||
// Move avatar in front of the chair to avoid getting stuck in collision hulls
|
||||
if (avatarDistance < MAX_RESET_DISTANCE) {
|
||||
var offset = { x: 0, y: 1.0, z: -0.5 - properties.dimensions.z * properties.registrationPoint.z };
|
||||
var position = Vec3.sum(properties.position, Vec3.multiplyQbyV(properties.rotation, offset));
|
||||
MyAvatar.position = position;
|
||||
}
|
||||
|
||||
this.sitUp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -203,6 +229,18 @@
|
|||
if (RELEASE_KEYS.indexOf(event.text) !== -1) {
|
||||
var that = this;
|
||||
this.timers[event.text] = Script.setTimeout(function() {
|
||||
delete that.timers[event.text];
|
||||
|
||||
var properties = Entities.getEntityProperties(that.entityID);
|
||||
var avatarDistance = Vec3.distance(MyAvatar.position, properties.position);
|
||||
|
||||
// Move avatar in front of the chair to avoid getting stuck in collision hulls
|
||||
if (avatarDistance < MAX_RESET_DISTANCE) {
|
||||
var offset = { x: 0, y: 1.0, z: -0.5 - properties.dimensions.z * properties.registrationPoint.z };
|
||||
var position = Vec3.sum(properties.position, Vec3.multiplyQbyV(properties.rotation, offset));
|
||||
MyAvatar.position = position;
|
||||
}
|
||||
|
||||
that.sitUp();
|
||||
}, RELEASE_TIME);
|
||||
}
|
||||
|
@ -223,7 +261,7 @@
|
|||
}
|
||||
|
||||
this.hoverEnterEntity = function(event) {
|
||||
if (isInEditMode() || (MyAvatar.sessionUUID === this.getSeatUser())) {
|
||||
if (isInEditMode() || this.interval !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -239,18 +277,18 @@
|
|||
}, DESKTOP_UI_CHECK_INTERVAL);
|
||||
}
|
||||
this.hoverLeaveEntity = function(event) {
|
||||
if (this.interval) {
|
||||
if (this.interval !== null) {
|
||||
Script.clearInterval(this.interval);
|
||||
this.interval = null;
|
||||
}
|
||||
this.cleanupOverlay();
|
||||
}
|
||||
|
||||
this.clickDownOnEntity = function () {
|
||||
if (isInEditMode() || (MyAvatar.sessionUUID === this.getSeatUser())) {
|
||||
this.clickDownOnEntity = function (id, event) {
|
||||
if (isInEditMode()) {
|
||||
return;
|
||||
}
|
||||
if (this.canSitDesktop()) {
|
||||
if (event.isPrimaryButton && this.canSitDesktop()) {
|
||||
this.sitDown();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,3 +17,5 @@ set_target_properties(ac-client PROPERTIES FOLDER "Tools")
|
|||
add_subdirectory(skeleton-dump)
|
||||
set_target_properties(skeleton-dump PROPERTIES FOLDER "Tools")
|
||||
|
||||
add_subdirectory(atp-get)
|
||||
set_target_properties(atp-get PROPERTIES FOLDER "Tools")
|
||||
|
|
3
tools/atp-get/CMakeLists.txt
Normal file
3
tools/atp-get/CMakeLists.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
set(TARGET_NAME atp-get)
|
||||
setup_hifi_project(Core Widgets)
|
||||
link_hifi_libraries(shared networking)
|
269
tools/atp-get/src/ATPGetApp.cpp
Normal file
269
tools/atp-get/src/ATPGetApp.cpp
Normal file
|
@ -0,0 +1,269 @@
|
|||
//
|
||||
// ATPGetApp.cpp
|
||||
// tools/atp-get/src
|
||||
//
|
||||
// Created by Seth Alves on 2017-3-15
|
||||
// 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 <QDataStream>
|
||||
#include <QTextStream>
|
||||
#include <QThread>
|
||||
#include <QFile>
|
||||
#include <QLoggingCategory>
|
||||
#include <QCommandLineParser>
|
||||
#include <NetworkLogging.h>
|
||||
#include <SharedLogging.h>
|
||||
#include <AddressManager.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <SettingHandle.h>
|
||||
|
||||
#include "ATPGetApp.h"
|
||||
|
||||
ATPGetApp::ATPGetApp(int argc, char* argv[]) :
|
||||
QCoreApplication(argc, argv)
|
||||
{
|
||||
// parse command-line
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription("High Fidelity ATP-Get");
|
||||
|
||||
const QCommandLineOption helpOption = parser.addHelpOption();
|
||||
|
||||
const QCommandLineOption verboseOutput("v", "verbose output");
|
||||
parser.addOption(verboseOutput);
|
||||
|
||||
const QCommandLineOption domainAddressOption("d", "domain-server address", "127.0.0.1");
|
||||
parser.addOption(domainAddressOption);
|
||||
|
||||
const QCommandLineOption cacheSTUNOption("s", "cache stun-server response");
|
||||
parser.addOption(cacheSTUNOption);
|
||||
|
||||
const QCommandLineOption listenPortOption("listenPort", "listen port", QString::number(INVALID_PORT));
|
||||
parser.addOption(listenPortOption);
|
||||
|
||||
|
||||
if (!parser.parse(QCoreApplication::arguments())) {
|
||||
qCritical() << parser.errorText() << endl;
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
if (parser.isSet(helpOption)) {
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
_verbose = parser.isSet(verboseOutput);
|
||||
if (!_verbose) {
|
||||
QLoggingCategory::setFilterRules("qt.network.ssl.warning=false");
|
||||
|
||||
const_cast<QLoggingCategory*>(&networking())->setEnabled(QtDebugMsg, false);
|
||||
const_cast<QLoggingCategory*>(&networking())->setEnabled(QtInfoMsg, false);
|
||||
const_cast<QLoggingCategory*>(&networking())->setEnabled(QtWarningMsg, false);
|
||||
|
||||
const_cast<QLoggingCategory*>(&shared())->setEnabled(QtDebugMsg, false);
|
||||
const_cast<QLoggingCategory*>(&shared())->setEnabled(QtInfoMsg, false);
|
||||
const_cast<QLoggingCategory*>(&shared())->setEnabled(QtWarningMsg, false);
|
||||
}
|
||||
|
||||
|
||||
QStringList filenames = parser.positionalArguments();
|
||||
if (filenames.empty() || filenames.size() > 2) {
|
||||
qDebug() << "give remote url and optional local filename as arguments";
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
_url = QUrl(filenames[0]);
|
||||
if (_url.scheme() != "atp") {
|
||||
qDebug() << "url should start with atp:";
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
if (filenames.size() == 2) {
|
||||
_localOutputFile = filenames[1];
|
||||
}
|
||||
|
||||
QString domainServerAddress = "127.0.0.1:40103";
|
||||
if (parser.isSet(domainAddressOption)) {
|
||||
domainServerAddress = parser.value(domainAddressOption);
|
||||
}
|
||||
|
||||
if (_verbose) {
|
||||
qDebug() << "domain-server address is" << domainServerAddress;
|
||||
}
|
||||
|
||||
int listenPort = INVALID_PORT;
|
||||
if (parser.isSet(listenPortOption)) {
|
||||
listenPort = parser.value(listenPortOption).toInt();
|
||||
}
|
||||
|
||||
Setting::init();
|
||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||
|
||||
DependencyManager::set<AccountManager>([&]{ return QString("Mozilla/5.0 (HighFidelityATPGet)"); });
|
||||
DependencyManager::set<AddressManager>();
|
||||
DependencyManager::set<NodeList>(NodeType::Agent, listenPort);
|
||||
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
// start the nodeThread so its event loop is running
|
||||
QThread* nodeThread = new QThread(this);
|
||||
nodeThread->setObjectName("NodeList Thread");
|
||||
nodeThread->start();
|
||||
|
||||
// make sure the node thread is given highest priority
|
||||
nodeThread->setPriority(QThread::TimeCriticalPriority);
|
||||
|
||||
// setup a timer for domain-server check ins
|
||||
QTimer* domainCheckInTimer = new QTimer(nodeList.data());
|
||||
connect(domainCheckInTimer, &QTimer::timeout, nodeList.data(), &NodeList::sendDomainServerCheckIn);
|
||||
domainCheckInTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS);
|
||||
|
||||
// put the NodeList and datagram processing on the node thread
|
||||
nodeList->moveToThread(nodeThread);
|
||||
|
||||
const DomainHandler& domainHandler = nodeList->getDomainHandler();
|
||||
|
||||
connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&)));
|
||||
// connect(&domainHandler, SIGNAL(resetting()), SLOT(resettingDomain()));
|
||||
// connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(clearDomainOctreeDetails()));
|
||||
connect(&domainHandler, &DomainHandler::domainConnectionRefused, this, &ATPGetApp::domainConnectionRefused);
|
||||
|
||||
connect(nodeList.data(), &NodeList::nodeAdded, this, &ATPGetApp::nodeAdded);
|
||||
connect(nodeList.data(), &NodeList::nodeKilled, this, &ATPGetApp::nodeKilled);
|
||||
connect(nodeList.data(), &NodeList::nodeActivated, this, &ATPGetApp::nodeActivated);
|
||||
// connect(nodeList.data(), &NodeList::uuidChanged, getMyAvatar(), &MyAvatar::setSessionUUID);
|
||||
// connect(nodeList.data(), &NodeList::uuidChanged, this, &ATPGetApp::setSessionUUID);
|
||||
connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &ATPGetApp::notifyPacketVersionMismatch);
|
||||
|
||||
nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer
|
||||
<< NodeType::EntityServer << NodeType::AssetServer << NodeType::MessagesMixer);
|
||||
|
||||
DependencyManager::get<AddressManager>()->handleLookupString(domainServerAddress, false);
|
||||
|
||||
auto assetClient = DependencyManager::set<AssetClient>();
|
||||
assetClient->init();
|
||||
|
||||
QTimer* doTimer = new QTimer(this);
|
||||
doTimer->setSingleShot(true);
|
||||
connect(doTimer, &QTimer::timeout, this, &ATPGetApp::timedOut);
|
||||
doTimer->start(4000);
|
||||
}
|
||||
|
||||
ATPGetApp::~ATPGetApp() {
|
||||
}
|
||||
|
||||
|
||||
void ATPGetApp::domainConnectionRefused(const QString& reasonMessage, int reasonCodeInt, const QString& extraInfo) {
|
||||
qDebug() << "domainConnectionRefused";
|
||||
}
|
||||
|
||||
void ATPGetApp::domainChanged(const QString& domainHostname) {
|
||||
if (_verbose) {
|
||||
qDebug() << "domainChanged";
|
||||
}
|
||||
}
|
||||
|
||||
void ATPGetApp::nodeAdded(SharedNodePointer node) {
|
||||
if (_verbose) {
|
||||
qDebug() << "node added: " << node->getType();
|
||||
}
|
||||
}
|
||||
|
||||
void ATPGetApp::nodeActivated(SharedNodePointer node) {
|
||||
if (node->getType() == NodeType::AssetServer) {
|
||||
lookup();
|
||||
}
|
||||
}
|
||||
|
||||
void ATPGetApp::nodeKilled(SharedNodePointer node) {
|
||||
qDebug() << "nodeKilled";
|
||||
}
|
||||
|
||||
void ATPGetApp::timedOut() {
|
||||
finish(1);
|
||||
}
|
||||
|
||||
void ATPGetApp::notifyPacketVersionMismatch() {
|
||||
if (_verbose) {
|
||||
qDebug() << "packet version mismatch";
|
||||
}
|
||||
finish(1);
|
||||
}
|
||||
|
||||
void ATPGetApp::lookup() {
|
||||
|
||||
auto path = _url.path();
|
||||
qDebug() << "path is " << path;
|
||||
|
||||
auto request = DependencyManager::get<AssetClient>()->createGetMappingRequest(path);
|
||||
QObject::connect(request, &GetMappingRequest::finished, this, [=](GetMappingRequest* request) mutable {
|
||||
auto result = request->getError();
|
||||
if (result == GetMappingRequest::NotFound) {
|
||||
qDebug() << "not found";
|
||||
} else if (result == GetMappingRequest::NoError) {
|
||||
qDebug() << "found, hash is " << request->getHash();
|
||||
download(request->getHash());
|
||||
} else {
|
||||
qDebug() << "error -- " << request->getError() << " -- " << request->getErrorString();
|
||||
}
|
||||
request->deleteLater();
|
||||
});
|
||||
request->start();
|
||||
}
|
||||
|
||||
void ATPGetApp::download(AssetHash hash) {
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
auto assetRequest = new AssetRequest(hash);
|
||||
|
||||
connect(assetRequest, &AssetRequest::finished, this, [this](AssetRequest* request) mutable {
|
||||
Q_ASSERT(request->getState() == AssetRequest::Finished);
|
||||
|
||||
if (request->getError() == AssetRequest::Error::NoError) {
|
||||
QString data = QString::fromUtf8(request->getData());
|
||||
if (_localOutputFile == "") {
|
||||
QTextStream cout(stdout);
|
||||
cout << data;
|
||||
} else {
|
||||
QFile outputHandle(_localOutputFile);
|
||||
if (outputHandle.open(QIODevice::ReadWrite)) {
|
||||
QTextStream stream( &outputHandle );
|
||||
stream << data;
|
||||
} else {
|
||||
qDebug() << "couldn't open output file:" << _localOutputFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
request->deleteLater();
|
||||
finish(0);
|
||||
});
|
||||
|
||||
assetRequest->start();
|
||||
}
|
||||
|
||||
void ATPGetApp::finish(int exitCode) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
// send the domain a disconnect packet, force stoppage of domain-server check-ins
|
||||
nodeList->getDomainHandler().disconnect();
|
||||
nodeList->setIsShuttingDown(true);
|
||||
|
||||
// tell the packet receiver we're shutting down, so it can drop packets
|
||||
nodeList->getPacketReceiver().setShouldDropPackets(true);
|
||||
|
||||
QThread* nodeThread = DependencyManager::get<NodeList>()->thread();
|
||||
// remove the NodeList from the DependencyManager
|
||||
DependencyManager::destroy<NodeList>();
|
||||
// ask the node thread to quit and wait until it is done
|
||||
nodeThread->quit();
|
||||
nodeThread->wait();
|
||||
|
||||
QCoreApplication::exit(exitCode);
|
||||
}
|
52
tools/atp-get/src/ATPGetApp.h
Normal file
52
tools/atp-get/src/ATPGetApp.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
//
|
||||
// ATPGetApp.h
|
||||
// tools/atp-get/src
|
||||
//
|
||||
// Created by Seth Alves on 2017-3-15
|
||||
// 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
|
||||
//
|
||||
|
||||
|
||||
#ifndef hifi_ATPGetApp_h
|
||||
#define hifi_ATPGetApp_h
|
||||
|
||||
#include <QApplication>
|
||||
#include <udt/Constants.h>
|
||||
#include <udt/Socket.h>
|
||||
#include <ReceivedMessage.h>
|
||||
#include <NetworkPeer.h>
|
||||
#include <NodeList.h>
|
||||
#include <AssetRequest.h>
|
||||
#include <MappingRequest.h>
|
||||
|
||||
|
||||
class ATPGetApp : public QCoreApplication {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ATPGetApp(int argc, char* argv[]);
|
||||
~ATPGetApp();
|
||||
|
||||
private slots:
|
||||
void domainConnectionRefused(const QString& reasonMessage, int reasonCodeInt, const QString& extraInfo);
|
||||
void domainChanged(const QString& domainHostname);
|
||||
void nodeAdded(SharedNodePointer node);
|
||||
void nodeActivated(SharedNodePointer node);
|
||||
void nodeKilled(SharedNodePointer node);
|
||||
void notifyPacketVersionMismatch();
|
||||
|
||||
private:
|
||||
NodeList* _nodeList;
|
||||
void timedOut();
|
||||
void lookup();
|
||||
void download(AssetHash hash);
|
||||
void finish(int exitCode);
|
||||
bool _verbose;
|
||||
|
||||
QUrl _url;
|
||||
QString _localOutputFile;
|
||||
};
|
||||
|
||||
#endif // hifi_ATPGetApp_h
|
31
tools/atp-get/src/main.cpp
Normal file
31
tools/atp-get/src/main.cpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// main.cpp
|
||||
// tools/atp-get/src
|
||||
//
|
||||
// Created by Seth Alves on 2017-3-15
|
||||
// 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 <iostream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <BuildInfo.h>
|
||||
|
||||
#include "ATPGetApp.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
QCoreApplication::setApplicationName(BuildInfo::AC_CLIENT_SERVER_NAME);
|
||||
QCoreApplication::setOrganizationName(BuildInfo::MODIFIED_ORGANIZATION);
|
||||
QCoreApplication::setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN);
|
||||
QCoreApplication::setApplicationVersion(BuildInfo::VERSION);
|
||||
|
||||
ATPGetApp app(argc, argv);
|
||||
|
||||
return app.exec();
|
||||
}
|
Loading…
Reference in a new issue