mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 20:31:29 +02:00
Merge branch 'master' into 21089
This commit is contained in:
commit
d33ac21aaa
62 changed files with 868 additions and 157 deletions
|
@ -88,6 +88,10 @@ void Agent::playAvatarSound(SharedSoundPointer sound) {
|
||||||
QMetaObject::invokeMethod(this, "playAvatarSound", Q_ARG(SharedSoundPointer, sound));
|
QMetaObject::invokeMethod(this, "playAvatarSound", Q_ARG(SharedSoundPointer, sound));
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
// TODO: seems to add occasional artifact in tests. I believe it is
|
||||||
|
// correct to do this, but need to figure out for sure, so commenting this
|
||||||
|
// out until I verify.
|
||||||
|
// _numAvatarSoundSentBytes = 0;
|
||||||
setAvatarSound(sound);
|
setAvatarSound(sound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -404,8 +408,37 @@ QUuid Agent::getSessionUUID() const {
|
||||||
return DependencyManager::get<NodeList>()->getSessionUUID();
|
return DependencyManager::get<NodeList>()->getSessionUUID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Agent::setIsListeningToAudioStream(bool isListeningToAudioStream) {
|
||||||
|
// this must happen on Agent's main thread
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "setIsListeningToAudioStream", Q_ARG(bool, isListeningToAudioStream));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_isListeningToAudioStream) {
|
||||||
|
// have to tell just the audio mixer to KillAvatar.
|
||||||
|
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
nodeList->eachMatchingNode(
|
||||||
|
[&](const SharedNodePointer& node)->bool {
|
||||||
|
return (node->getType() == NodeType::AudioMixer) && node->getActiveSocket();
|
||||||
|
},
|
||||||
|
[&](const SharedNodePointer& node) {
|
||||||
|
qDebug() << "sending KillAvatar message to Audio Mixers";
|
||||||
|
auto packet = NLPacket::create(PacketType::KillAvatar, NUM_BYTES_RFC4122_UUID, true);
|
||||||
|
packet->write(getSessionUUID().toRfc4122());
|
||||||
|
nodeList->sendPacket(std::move(packet), *node);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
_isListeningToAudioStream = isListeningToAudioStream;
|
||||||
|
}
|
||||||
|
|
||||||
void Agent::setIsAvatar(bool isAvatar) {
|
void Agent::setIsAvatar(bool isAvatar) {
|
||||||
|
// this must happen on Agent's main thread
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "setIsAvatar", Q_ARG(bool, isAvatar));
|
||||||
|
return;
|
||||||
|
}
|
||||||
_isAvatar = isAvatar;
|
_isAvatar = isAvatar;
|
||||||
|
|
||||||
if (_isAvatar && !_avatarIdentityTimer) {
|
if (_isAvatar && !_avatarIdentityTimer) {
|
||||||
|
@ -435,14 +468,16 @@ void Agent::setIsAvatar(bool isAvatar) {
|
||||||
// when we stop sending identity, but then get woken up again by the mixer itself, which sends
|
// when we stop sending identity, but then get woken up again by the mixer itself, which sends
|
||||||
// identity packets to everyone. Here we explicitly tell the mixer to kill the entry for us.
|
// identity packets to everyone. Here we explicitly tell the mixer to kill the entry for us.
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
auto packetList = NLPacketList::create(PacketType::KillAvatar, QByteArray(), true, true);
|
|
||||||
packetList->write(getSessionUUID().toRfc4122());
|
|
||||||
nodeList->eachMatchingNode(
|
nodeList->eachMatchingNode(
|
||||||
[&](const SharedNodePointer& node)->bool {
|
[&](const SharedNodePointer& node)->bool {
|
||||||
return node->getType() == NodeType::AvatarMixer && node->getActiveSocket();
|
return (node->getType() == NodeType::AvatarMixer || node->getType() == NodeType::AudioMixer)
|
||||||
|
&& node->getActiveSocket();
|
||||||
},
|
},
|
||||||
[&](const SharedNodePointer& node) {
|
[&](const SharedNodePointer& node) {
|
||||||
nodeList->sendPacketList(std::move(packetList), *node);
|
qDebug() << "sending KillAvatar message to Avatar and Audio Mixers";
|
||||||
|
auto packet = NLPacket::create(PacketType::KillAvatar, NUM_BYTES_RFC4122_UUID, true);
|
||||||
|
packet->write(getSessionUUID().toRfc4122());
|
||||||
|
nodeList->sendPacket(std::move(packet), *node);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
emit stopAvatarAudioTimer();
|
emit stopAvatarAudioTimer();
|
||||||
|
|
|
@ -49,7 +49,7 @@ public:
|
||||||
bool isPlayingAvatarSound() const { return _avatarSound != NULL; }
|
bool isPlayingAvatarSound() const { return _avatarSound != NULL; }
|
||||||
|
|
||||||
bool isListeningToAudioStream() const { return _isListeningToAudioStream; }
|
bool isListeningToAudioStream() const { return _isListeningToAudioStream; }
|
||||||
void setIsListeningToAudioStream(bool isListeningToAudioStream) { _isListeningToAudioStream = isListeningToAudioStream; }
|
void setIsListeningToAudioStream(bool isListeningToAudioStream);
|
||||||
|
|
||||||
float getLastReceivedAudioLoudness() const { return _lastReceivedAudioLoudness; }
|
float getLastReceivedAudioLoudness() const { return _lastReceivedAudioLoudness; }
|
||||||
QUuid getSessionUUID() const;
|
QUuid getSessionUUID() const;
|
||||||
|
|
|
@ -93,6 +93,7 @@ AudioMixer::AudioMixer(ReceivedMessage& message) :
|
||||||
packetReceiver.registerListener(PacketType::NegotiateAudioFormat, this, "handleNegotiateAudioFormat");
|
packetReceiver.registerListener(PacketType::NegotiateAudioFormat, this, "handleNegotiateAudioFormat");
|
||||||
packetReceiver.registerListener(PacketType::MuteEnvironment, this, "handleMuteEnvironmentPacket");
|
packetReceiver.registerListener(PacketType::MuteEnvironment, this, "handleMuteEnvironmentPacket");
|
||||||
packetReceiver.registerListener(PacketType::NodeIgnoreRequest, this, "handleNodeIgnoreRequestPacket");
|
packetReceiver.registerListener(PacketType::NodeIgnoreRequest, this, "handleNodeIgnoreRequestPacket");
|
||||||
|
packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket");
|
||||||
|
|
||||||
connect(nodeList.data(), &NodeList::nodeKilled, this, &AudioMixer::handleNodeKilled);
|
connect(nodeList.data(), &NodeList::nodeKilled, this, &AudioMixer::handleNodeKilled);
|
||||||
}
|
}
|
||||||
|
@ -590,14 +591,29 @@ void AudioMixer::handleNodeKilled(SharedNodePointer killedNode) {
|
||||||
// enumerate the connected listeners to remove HRTF objects for the disconnected node
|
// enumerate the connected listeners to remove HRTF objects for the disconnected node
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
nodeList->eachNode([](const SharedNodePointer& node) {
|
nodeList->eachNode([&killedNode](const SharedNodePointer& node) {
|
||||||
auto clientData = dynamic_cast<AudioMixerClientData*>(node->getLinkedData());
|
auto clientData = dynamic_cast<AudioMixerClientData*>(node->getLinkedData());
|
||||||
if (clientData) {
|
if (clientData) {
|
||||||
clientData->removeHRTFsForNode(node->getUUID());
|
clientData->removeHRTFsForNode(killedNode->getUUID());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioMixer::handleKillAvatarPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode) {
|
||||||
|
auto clientData = dynamic_cast<AudioMixerClientData*>(sendingNode->getLinkedData());
|
||||||
|
if (clientData) {
|
||||||
|
clientData->removeAgentAvatarAudioStream();
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
nodeList->eachNode([sendingNode](const SharedNodePointer& node){
|
||||||
|
auto listenerClientData = dynamic_cast<AudioMixerClientData*>(node->getLinkedData());
|
||||||
|
if (listenerClientData) {
|
||||||
|
listenerClientData->removeHRTFForStream(sendingNode->getUUID());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void AudioMixer::handleNodeIgnoreRequestPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode) {
|
void AudioMixer::handleNodeIgnoreRequestPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode) {
|
||||||
sendingNode->parseIgnoreRequestMessage(packet);
|
sendingNode->parseIgnoreRequestMessage(packet);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ private slots:
|
||||||
void handleNegotiateAudioFormat(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
|
void handleNegotiateAudioFormat(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode);
|
||||||
void handleNodeKilled(SharedNodePointer killedNode);
|
void handleNodeKilled(SharedNodePointer killedNode);
|
||||||
void handleNodeIgnoreRequestPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode);
|
void handleNodeIgnoreRequestPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode);
|
||||||
|
void handleKillAvatarPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode);
|
||||||
|
|
||||||
void removeHRTFsForFinishedInjector(const QUuid& streamID);
|
void removeHRTFsForFinishedInjector(const QUuid& streamID);
|
||||||
|
|
||||||
|
|
|
@ -73,11 +73,19 @@ void AudioMixerClientData::removeHRTFForStream(const QUuid& nodeID, const QUuid&
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioMixerClientData::removeAgentAvatarAudioStream() {
|
||||||
|
QWriteLocker writeLocker { &_streamsLock };
|
||||||
|
auto it = _audioStreams.find(QUuid());
|
||||||
|
if (it != _audioStreams.end()) {
|
||||||
|
_audioStreams.erase(it);
|
||||||
|
}
|
||||||
|
writeLocker.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
int AudioMixerClientData::parseData(ReceivedMessage& message) {
|
int AudioMixerClientData::parseData(ReceivedMessage& message) {
|
||||||
PacketType packetType = message.getType();
|
PacketType packetType = message.getType();
|
||||||
|
|
||||||
if (packetType == PacketType::AudioStreamStats) {
|
if (packetType == PacketType::AudioStreamStats) {
|
||||||
|
|
||||||
// skip over header, appendFlag, and num stats packed
|
// skip over header, appendFlag, and num stats packed
|
||||||
message.seek(sizeof(quint8) + sizeof(quint16));
|
message.seek(sizeof(quint8) + sizeof(quint16));
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,8 @@ public:
|
||||||
// removes an AudioHRTF object for a given stream
|
// removes an AudioHRTF object for a given stream
|
||||||
void removeHRTFForStream(const QUuid& nodeID, const QUuid& streamID = QUuid());
|
void removeHRTFForStream(const QUuid& nodeID, const QUuid& streamID = QUuid());
|
||||||
|
|
||||||
|
void removeAgentAvatarAudioStream();
|
||||||
|
|
||||||
int parseData(ReceivedMessage& message) override;
|
int parseData(ReceivedMessage& message) override;
|
||||||
|
|
||||||
// attempt to pop a frame from each audio stream, and return the number of streams from this client
|
// attempt to pop a frame from each audio stream, and return the number of streams from this client
|
||||||
|
|
22
cmake/templates/VersionInfo.rc.in
Normal file
22
cmake/templates/VersionInfo.rc.in
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
// Language and character set information as described at
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa381049(v=vs.85).aspx
|
||||||
|
#define US_ENGLISH_UNICODE "040904B0"
|
||||||
|
|
||||||
|
// More information about the format of this file can be found at
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa381058(v=vs.85).aspx
|
||||||
|
1 VERSIONINFO
|
||||||
|
BEGIN
|
||||||
|
BLOCK "StringFileInfo"
|
||||||
|
BEGIN
|
||||||
|
BLOCK US_ENGLISH_UNICODE
|
||||||
|
BEGIN
|
||||||
|
VALUE "CompanyName", "@BUILD_ORGANIZATION@"
|
||||||
|
VALUE "FileDescription", "@APP_FULL_NAME@"
|
||||||
|
VALUE "FileVersion", "@BUILD_VERSION@"
|
||||||
|
VALUE "InternalName", "@TARGET_NAME@"
|
||||||
|
VALUE "OriginalFilename", "@TARGET_NAME@.exe"
|
||||||
|
VALUE "ProductName", "@APP_FULL_NAME@"
|
||||||
|
VALUE "ProductVersion", "@BUILD_VERSION@"
|
||||||
|
END
|
||||||
|
END
|
||||||
|
END
|
|
@ -237,6 +237,7 @@ void DomainGatekeeper::updateNodePermissions() {
|
||||||
userPerms.permissions |= NodePermissions::Permission::canAdjustLocks;
|
userPerms.permissions |= NodePermissions::Permission::canAdjustLocks;
|
||||||
userPerms.permissions |= NodePermissions::Permission::canRezPermanentEntities;
|
userPerms.permissions |= NodePermissions::Permission::canRezPermanentEntities;
|
||||||
userPerms.permissions |= NodePermissions::Permission::canRezTemporaryEntities;
|
userPerms.permissions |= NodePermissions::Permission::canRezTemporaryEntities;
|
||||||
|
userPerms.permissions |= NodePermissions::Permission::canWriteToAssetServer;
|
||||||
} else {
|
} else {
|
||||||
// this node is an agent
|
// this node is an agent
|
||||||
const QHostAddress& addr = node->getLocalSocket().getAddress();
|
const QHostAddress& addr = node->getLocalSocket().getAddress();
|
||||||
|
@ -312,6 +313,7 @@ SharedNodePointer DomainGatekeeper::processAssignmentConnectRequest(const NodeCo
|
||||||
userPerms.permissions |= NodePermissions::Permission::canAdjustLocks;
|
userPerms.permissions |= NodePermissions::Permission::canAdjustLocks;
|
||||||
userPerms.permissions |= NodePermissions::Permission::canRezPermanentEntities;
|
userPerms.permissions |= NodePermissions::Permission::canRezPermanentEntities;
|
||||||
userPerms.permissions |= NodePermissions::Permission::canRezTemporaryEntities;
|
userPerms.permissions |= NodePermissions::Permission::canRezTemporaryEntities;
|
||||||
|
userPerms.permissions |= NodePermissions::Permission::canWriteToAssetServer;
|
||||||
newNode->setPermissions(userPerms);
|
newNode->setPermissions(userPerms);
|
||||||
return newNode;
|
return newNode;
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,8 +133,12 @@ elseif (WIN32)
|
||||||
set(CONFIGURE_ICON_RC_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Icon.rc")
|
set(CONFIGURE_ICON_RC_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Icon.rc")
|
||||||
configure_file("${HF_CMAKE_DIR}/templates/Icon.rc.in" ${CONFIGURE_ICON_RC_OUTPUT})
|
configure_file("${HF_CMAKE_DIR}/templates/Icon.rc.in" ${CONFIGURE_ICON_RC_OUTPUT})
|
||||||
|
|
||||||
|
set(APP_FULL_NAME "High Fidelity Interface")
|
||||||
|
set(CONFIGURE_VERSION_INFO_RC_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/VersionInfo.rc")
|
||||||
|
configure_file("${HF_CMAKE_DIR}/templates/VersionInfo.rc.in" ${CONFIGURE_VERSION_INFO_RC_OUTPUT})
|
||||||
|
|
||||||
# add an executable that also has the icon itself and the configured rc file as resources
|
# add an executable that also has the icon itself and the configured rc file as resources
|
||||||
add_executable(${TARGET_NAME} WIN32 ${INTERFACE_SRCS} ${QM} ${CONFIGURE_ICON_RC_OUTPUT})
|
add_executable(${TARGET_NAME} WIN32 ${INTERFACE_SRCS} ${QM} ${CONFIGURE_ICON_RC_OUTPUT} ${CONFIGURE_VERSION_INFO_RC_OUTPUT})
|
||||||
|
|
||||||
if (NOT DEV_BUILD)
|
if (NOT DEV_BUILD)
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
|
|
|
@ -50,21 +50,33 @@
|
||||||
function showKbm() {
|
function showKbm() {
|
||||||
document.getElementById("main_image").setAttribute("src", "img/controls-help-keyboard.png");
|
document.getElementById("main_image").setAttribute("src", "img/controls-help-keyboard.png");
|
||||||
}
|
}
|
||||||
function showHandControllers() {
|
function showViveControllers() {
|
||||||
document.getElementById("main_image").setAttribute("src", "img/controls-help-vive.png");
|
document.getElementById("main_image").setAttribute("src", "img/controls-help-vive.png");
|
||||||
}
|
}
|
||||||
function showGameController() {
|
function showXboxController() {
|
||||||
document.getElementById("main_image").setAttribute("src", "img/controls-help-gamepad.png");
|
document.getElementById("main_image").setAttribute("src", "img/controls-help-gamepad.png");
|
||||||
}
|
}
|
||||||
|
function load() {
|
||||||
|
console.log("In help.html: ", window.location.href);
|
||||||
|
parts = window.location.href.split("?");
|
||||||
|
if (parts.length > 0) {
|
||||||
|
var defaultTab = parts[1];
|
||||||
|
if (defaultTab == "xbox") {
|
||||||
|
showXboxController();
|
||||||
|
} else if (defaultTab == "vive") {
|
||||||
|
showViveControllers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body onload="load()">
|
||||||
<div id="image_area">
|
<div id="image_area">
|
||||||
<img id="main_image" src="img/controls-help-keyboard.png" width="1024px" height="720px"></img>
|
<img id="main_image" src="img/controls-help-keyboard.png" width="1024px" height="720px"></img>
|
||||||
<a href="#" id="kbm_button" onmousedown="showKbm()"></a>
|
<a href="#" id="kbm_button" onmousedown="showKbm()"></a>
|
||||||
<a href="#" id="hand_controllers_button" onmousedown="showHandControllers()"></a>
|
<a href="#" id="hand_controllers_button" onmousedown="showViveControllers()"></a>
|
||||||
<a href="#" id="game_controller_button" onmousedown="showGameController()"></a>
|
<a href="#" id="game_controller_button" onmousedown="showXboxController()"></a>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|
|
@ -312,6 +312,7 @@ FocusScope {
|
||||||
|
|
||||||
onPinnedChanged: {
|
onPinnedChanged: {
|
||||||
if (pinned) {
|
if (pinned) {
|
||||||
|
d.raiseWindow(desktop);
|
||||||
desktop.focus = true;
|
desktop.focus = true;
|
||||||
desktop.forceActiveFocus();
|
desktop.forceActiveFocus();
|
||||||
|
|
||||||
|
|
|
@ -51,27 +51,41 @@ OriginalDesktop.Desktop {
|
||||||
Toolbar {
|
Toolbar {
|
||||||
id: sysToolbar;
|
id: sysToolbar;
|
||||||
objectName: "com.highfidelity.interface.toolbar.system";
|
objectName: "com.highfidelity.interface.toolbar.system";
|
||||||
// These values will be overridden by sysToolbar.x/y if there is a saved position in Settings
|
anchors.horizontalCenter: settings.constrainToolbarToCenterX ? desktop.horizontalCenter : undefined;
|
||||||
// On exit, the sysToolbar position is saved to settings
|
// Literal 50 is overwritten by settings from previous session, and sysToolbar.x comes from settings when not constrained.
|
||||||
x: 30
|
x: sysToolbar.x
|
||||||
y: 50
|
y: 50
|
||||||
}
|
}
|
||||||
|
Settings {
|
||||||
|
id: settings;
|
||||||
|
category: "toolbar";
|
||||||
|
property bool constrainToolbarToCenterX: true;
|
||||||
|
}
|
||||||
|
function setConstrainToolbarToCenterX(constrain) { // Learn about c++ preference change.
|
||||||
|
settings.constrainToolbarToCenterX = constrain;
|
||||||
|
}
|
||||||
property var toolbars: (function (map) { // answer dictionary preloaded with sysToolbar
|
property var toolbars: (function (map) { // answer dictionary preloaded with sysToolbar
|
||||||
map[sysToolbar.objectName] = sysToolbar;
|
map[sysToolbar.objectName] = sysToolbar;
|
||||||
return map; })({});
|
return map; })({});
|
||||||
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
WebEngine.settings.javascriptCanOpenWindows = true;
|
WebEngine.settings.javascriptCanOpenWindows = true;
|
||||||
WebEngine.settings.javascriptCanAccessClipboard = false;
|
WebEngine.settings.javascriptCanAccessClipboard = false;
|
||||||
WebEngine.settings.spatialNavigationEnabled = false;
|
WebEngine.settings.spatialNavigationEnabled = false;
|
||||||
WebEngine.settings.localContentCanAccessRemoteUrls = true;
|
WebEngine.settings.localContentCanAccessRemoteUrls = true;
|
||||||
|
|
||||||
var toggleHudButton = sysToolbar.addButton({
|
[ // Allocate the standard buttons in the correct order. They will get images, etc., via scripts.
|
||||||
objectName: "hudToggle",
|
"hmdToggle", "mute", "mod", "help",
|
||||||
imageURL: "../../../icons/hud.svg",
|
"hudToggle",
|
||||||
visible: true,
|
"com.highfidelity.interface.system.editButton", "marketplace", "snapshot", "goto"
|
||||||
pinned: true,
|
].forEach(function (name) {
|
||||||
|
sysToolbar.addButton({objectName: name});
|
||||||
});
|
});
|
||||||
|
var toggleHudButton = sysToolbar.findButton("hudToggle");
|
||||||
|
toggleHudButton.imageURL = "../../../icons/hud.svg";
|
||||||
|
toggleHudButton.pinned = true;
|
||||||
|
sysToolbar.updatePinned(); // automatic when adding buttons only IFF button is pinned at creation.
|
||||||
|
|
||||||
toggleHudButton.buttonState = Qt.binding(function(){
|
toggleHudButton.buttonState = Qt.binding(function(){
|
||||||
return desktop.pinned ? 1 : 0
|
return desktop.pinned ? 1 : 0
|
||||||
|
|
|
@ -17,7 +17,7 @@ PreferencesDialog {
|
||||||
id: root
|
id: root
|
||||||
objectName: "GeneralPreferencesDialog"
|
objectName: "GeneralPreferencesDialog"
|
||||||
title: "General Settings"
|
title: "General Settings"
|
||||||
showCategories: ["Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers"]
|
showCategories: ["UI", "Snapshots", "Scripts", "Privacy", "Octree", "HMD", "Sixense Controllers"]
|
||||||
property var settings: Settings {
|
property var settings: Settings {
|
||||||
category: root.objectName
|
category: root.objectName
|
||||||
property alias x: root.x
|
property alias x: root.x
|
||||||
|
|
|
@ -114,6 +114,9 @@ Window {
|
||||||
// and allow scripts to be idempotent so they don't duplicate buttons if they're reloaded
|
// and allow scripts to be idempotent so they don't duplicate buttons if they're reloaded
|
||||||
var result = findButton(properties.objectName);
|
var result = findButton(properties.objectName);
|
||||||
if (result) {
|
if (result) {
|
||||||
|
for (var property in properties) {
|
||||||
|
result[property] = properties[property];
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
properties.toolbar = this;
|
properties.toolbar = this;
|
||||||
|
|
|
@ -525,6 +525,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
_mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)),
|
_mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)),
|
||||||
_previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION),
|
_previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION),
|
||||||
_fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES),
|
_fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES),
|
||||||
|
_constrainToolbarPosition("toolbar/constrainToolbarToCenterX", true),
|
||||||
_scaleMirror(1.0f),
|
_scaleMirror(1.0f),
|
||||||
_rotateMirror(0.0f),
|
_rotateMirror(0.0f),
|
||||||
_raiseMirror(0.0f),
|
_raiseMirror(0.0f),
|
||||||
|
@ -2152,12 +2153,27 @@ void Application::setFieldOfView(float fov) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::setSettingConstrainToolbarPosition(bool setting) {
|
||||||
|
_constrainToolbarPosition.set(setting);
|
||||||
|
DependencyManager::get<OffscreenUi>()->setConstrainToolbarToCenterX(setting);
|
||||||
|
}
|
||||||
|
|
||||||
void Application::aboutApp() {
|
void Application::aboutApp() {
|
||||||
InfoView::show(INFO_WELCOME_PATH);
|
InfoView::show(INFO_WELCOME_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::showHelp() {
|
void Application::showHelp() {
|
||||||
InfoView::show(INFO_HELP_PATH);
|
static const QString QUERY_STRING_XBOX = "xbox";
|
||||||
|
static const QString QUERY_STRING_VIVE = "vive";
|
||||||
|
|
||||||
|
QString queryString = "";
|
||||||
|
if (PluginUtils::isViveControllerAvailable()) {
|
||||||
|
queryString = QUERY_STRING_VIVE;
|
||||||
|
} else if (PluginUtils::isXboxControllerAvailable()) {
|
||||||
|
queryString = QUERY_STRING_XBOX;
|
||||||
|
}
|
||||||
|
|
||||||
|
InfoView::show(INFO_HELP_PATH, false, queryString);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::resizeEvent(QResizeEvent* event) {
|
void Application::resizeEvent(QResizeEvent* event) {
|
||||||
|
|
|
@ -206,6 +206,9 @@ public:
|
||||||
float getFieldOfView() { return _fieldOfView.get(); }
|
float getFieldOfView() { return _fieldOfView.get(); }
|
||||||
void setFieldOfView(float fov);
|
void setFieldOfView(float fov);
|
||||||
|
|
||||||
|
float getSettingConstrainToolbarPosition() { return _constrainToolbarPosition.get(); }
|
||||||
|
void setSettingConstrainToolbarPosition(bool setting);
|
||||||
|
|
||||||
NodeToOctreeSceneStats* getOcteeSceneStats() { return &_octreeServerSceneStats; }
|
NodeToOctreeSceneStats* getOcteeSceneStats() { return &_octreeServerSceneStats; }
|
||||||
|
|
||||||
virtual controller::ScriptingInterface* getControllerScriptingInterface() { return _controllerScriptingInterface; }
|
virtual controller::ScriptingInterface* getControllerScriptingInterface() { return _controllerScriptingInterface; }
|
||||||
|
@ -512,6 +515,7 @@ private:
|
||||||
|
|
||||||
Setting::Handle<QString> _previousScriptLocation;
|
Setting::Handle<QString> _previousScriptLocation;
|
||||||
Setting::Handle<float> _fieldOfView;
|
Setting::Handle<float> _fieldOfView;
|
||||||
|
Setting::Handle<bool> _constrainToolbarPosition;
|
||||||
|
|
||||||
float _scaleMirror;
|
float _scaleMirror;
|
||||||
float _rotateMirror;
|
float _rotateMirror;
|
||||||
|
|
|
@ -68,6 +68,13 @@ void setupPreferences() {
|
||||||
preferences->addPreference(new CheckPreference(AVATAR_BASICS, "Clear overlays when moving", getter, setter));
|
preferences->addPreference(new CheckPreference(AVATAR_BASICS, "Clear overlays when moving", getter, setter));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UI
|
||||||
|
{
|
||||||
|
auto getter = []()->bool { return qApp->getSettingConstrainToolbarPosition(); };
|
||||||
|
auto setter = [](bool value) { qApp->setSettingConstrainToolbarPosition(value); };
|
||||||
|
preferences->addPreference(new CheckPreference("UI", "Constrain Toolbar Position to Horizontal Center", getter, setter));
|
||||||
|
}
|
||||||
|
|
||||||
// Snapshots
|
// Snapshots
|
||||||
static const QString SNAPSHOTS { "Snapshots" };
|
static const QString SNAPSHOTS { "Snapshots" };
|
||||||
{
|
{
|
||||||
|
|
|
@ -89,7 +89,7 @@ QTemporaryFile* Snapshot::saveTempSnapshot(QImage image) {
|
||||||
QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary) {
|
QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary) {
|
||||||
|
|
||||||
// adding URL to snapshot
|
// adding URL to snapshot
|
||||||
QUrl currentURL = DependencyManager::get<AddressManager>()->currentAddress();
|
QUrl currentURL = DependencyManager::get<AddressManager>()->currentShareableAddress();
|
||||||
shot.setText(URL, currentURL.toString());
|
shot.setText(URL, currentURL.toString());
|
||||||
|
|
||||||
QString username = DependencyManager::get<AccountManager>()->getAccountInfo().getUsername();
|
QString username = DependencyManager::get<AccountManager>()->getAccountInfo().getUsername();
|
||||||
|
@ -146,7 +146,10 @@ QFile* Snapshot::savedFileForSnapshot(QImage & shot, bool isTemporary) {
|
||||||
void Snapshot::uploadSnapshot(const QString& filename) {
|
void Snapshot::uploadSnapshot(const QString& filename) {
|
||||||
|
|
||||||
const QString SNAPSHOT_UPLOAD_URL = "/api/v1/snapshots";
|
const QString SNAPSHOT_UPLOAD_URL = "/api/v1/snapshots";
|
||||||
static SnapshotUploader uploader;
|
// Alternatively to parseSnapshotData, we could pass the inWorldLocation through the call chain. This way is less disruptive to existing code.
|
||||||
|
SnapshotMetaData* snapshotData = Snapshot::parseSnapshotData(filename);
|
||||||
|
SnapshotUploader* uploader = new SnapshotUploader(snapshotData->getURL(), filename);
|
||||||
|
delete snapshotData;
|
||||||
|
|
||||||
QFile* file = new QFile(filename);
|
QFile* file = new QFile(filename);
|
||||||
Q_ASSERT(file->exists());
|
Q_ASSERT(file->exists());
|
||||||
|
@ -163,7 +166,7 @@ void Snapshot::uploadSnapshot(const QString& filename) {
|
||||||
multiPart->append(imagePart);
|
multiPart->append(imagePart);
|
||||||
|
|
||||||
auto accountManager = DependencyManager::get<AccountManager>();
|
auto accountManager = DependencyManager::get<AccountManager>();
|
||||||
JSONCallbackParameters callbackParams(&uploader, "uploadSuccess", &uploader, "uploadFailure");
|
JSONCallbackParameters callbackParams(uploader, "uploadSuccess", uploader, "uploadFailure");
|
||||||
|
|
||||||
accountManager->sendRequest(SNAPSHOT_UPLOAD_URL,
|
accountManager->sendRequest(SNAPSHOT_UPLOAD_URL,
|
||||||
AccountManagerAuth::Required,
|
AccountManagerAuth::Required,
|
||||||
|
|
|
@ -15,9 +15,13 @@
|
||||||
#include "scripting/WindowScriptingInterface.h"
|
#include "scripting/WindowScriptingInterface.h"
|
||||||
#include "SnapshotUploader.h"
|
#include "SnapshotUploader.h"
|
||||||
|
|
||||||
|
SnapshotUploader::SnapshotUploader(QUrl inWorldLocation, QString pathname) :
|
||||||
|
_inWorldLocation(inWorldLocation),
|
||||||
|
_pathname(pathname) {
|
||||||
|
}
|
||||||
|
|
||||||
void SnapshotUploader::uploadSuccess(QNetworkReply& reply) {
|
void SnapshotUploader::uploadSuccess(QNetworkReply& reply) {
|
||||||
const QString STORY_UPLOAD_URL = "/api/v1/user_stories";
|
const QString STORY_UPLOAD_URL = "/api/v1/user_stories";
|
||||||
static SnapshotUploader uploader;
|
|
||||||
|
|
||||||
// parse the reply for the thumbnail_url
|
// parse the reply for the thumbnail_url
|
||||||
QByteArray contents = reply.readAll();
|
QByteArray contents = reply.readAll();
|
||||||
|
@ -28,11 +32,8 @@ void SnapshotUploader::uploadSuccess(QNetworkReply& reply) {
|
||||||
QString thumbnailUrl = dataObject.value("thumbnail_url").toString();
|
QString thumbnailUrl = dataObject.value("thumbnail_url").toString();
|
||||||
QString imageUrl = dataObject.value("image_url").toString();
|
QString imageUrl = dataObject.value("image_url").toString();
|
||||||
auto addressManager = DependencyManager::get<AddressManager>();
|
auto addressManager = DependencyManager::get<AddressManager>();
|
||||||
QString placeName = addressManager->getPlaceName();
|
QString placeName = _inWorldLocation.authority(); // We currently only upload shareable places, in which case this is just host.
|
||||||
if (placeName.isEmpty()) {
|
QString currentPath = _inWorldLocation.path();
|
||||||
placeName = addressManager->getHost();
|
|
||||||
}
|
|
||||||
QString currentPath = addressManager->currentPath(true);
|
|
||||||
|
|
||||||
// create json post data
|
// create json post data
|
||||||
QJsonObject rootObject;
|
QJsonObject rootObject;
|
||||||
|
@ -48,7 +49,7 @@ void SnapshotUploader::uploadSuccess(QNetworkReply& reply) {
|
||||||
rootObject.insert("user_story", userStoryObject);
|
rootObject.insert("user_story", userStoryObject);
|
||||||
|
|
||||||
auto accountManager = DependencyManager::get<AccountManager>();
|
auto accountManager = DependencyManager::get<AccountManager>();
|
||||||
JSONCallbackParameters callbackParams(&uploader, "createStorySuccess", &uploader, "createStoryFailure");
|
JSONCallbackParameters callbackParams(this, "createStorySuccess", this, "createStoryFailure");
|
||||||
|
|
||||||
accountManager->sendRequest(STORY_UPLOAD_URL,
|
accountManager->sendRequest(STORY_UPLOAD_URL,
|
||||||
AccountManagerAuth::Required,
|
AccountManagerAuth::Required,
|
||||||
|
@ -56,20 +57,23 @@ void SnapshotUploader::uploadSuccess(QNetworkReply& reply) {
|
||||||
callbackParams,
|
callbackParams,
|
||||||
QJsonDocument(rootObject).toJson());
|
QJsonDocument(rootObject).toJson());
|
||||||
|
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
emit DependencyManager::get<WindowScriptingInterface>()->snapshotShared(contents);
|
emit DependencyManager::get<WindowScriptingInterface>()->snapshotShared(contents);
|
||||||
|
delete this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SnapshotUploader::uploadFailure(QNetworkReply& reply) {
|
void SnapshotUploader::uploadFailure(QNetworkReply& reply) {
|
||||||
emit DependencyManager::get<WindowScriptingInterface>()->snapshotShared(reply.readAll());
|
emit DependencyManager::get<WindowScriptingInterface>()->snapshotShared(reply.readAll()); // maybe someday include _inWorldLocation, _filename?
|
||||||
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SnapshotUploader::createStorySuccess(QNetworkReply& reply) {
|
void SnapshotUploader::createStorySuccess(QNetworkReply& reply) {
|
||||||
emit DependencyManager::get<WindowScriptingInterface>()->snapshotShared(QString());
|
emit DependencyManager::get<WindowScriptingInterface>()->snapshotShared(QString());
|
||||||
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SnapshotUploader::createStoryFailure(QNetworkReply& reply) {
|
void SnapshotUploader::createStoryFailure(QNetworkReply& reply) {
|
||||||
emit DependencyManager::get<WindowScriptingInterface>()->snapshotShared(reply.readAll());
|
emit DependencyManager::get<WindowScriptingInterface>()->snapshotShared(reply.readAll());
|
||||||
|
delete this;
|
||||||
}
|
}
|
|
@ -14,13 +14,19 @@
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QtNetwork/QNetworkReply>
|
#include <QtNetwork/QNetworkReply>
|
||||||
|
#include <QtCore/QUrl>
|
||||||
|
|
||||||
class SnapshotUploader : public QObject {
|
class SnapshotUploader : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public slots:
|
public:
|
||||||
|
SnapshotUploader(QUrl inWorldLocation, QString pathname);
|
||||||
|
public slots:
|
||||||
void uploadSuccess(QNetworkReply& reply);
|
void uploadSuccess(QNetworkReply& reply);
|
||||||
void uploadFailure(QNetworkReply& reply);
|
void uploadFailure(QNetworkReply& reply);
|
||||||
void createStorySuccess(QNetworkReply& reply);
|
void createStorySuccess(QNetworkReply& reply);
|
||||||
void createStoryFailure(QNetworkReply& reply);
|
void createStoryFailure(QNetworkReply& reply);
|
||||||
|
private:
|
||||||
|
QUrl _inWorldLocation;
|
||||||
|
QString _pathname;
|
||||||
};
|
};
|
||||||
#endif // hifi_SnapshotUploader_h
|
#endif // hifi_SnapshotUploader_h
|
|
@ -302,7 +302,7 @@ void Stats::updateStats(bool force) {
|
||||||
STAT_UPDATE(gpuTextureVirtualMemory, (int)BYTES_TO_MB(gpu::Texture::getTextureGPUVirtualMemoryUsage()));
|
STAT_UPDATE(gpuTextureVirtualMemory, (int)BYTES_TO_MB(gpu::Texture::getTextureGPUVirtualMemoryUsage()));
|
||||||
STAT_UPDATE(gpuTextureFramebufferMemory, (int)BYTES_TO_MB(gpu::Texture::getTextureGPUFramebufferMemoryUsage()));
|
STAT_UPDATE(gpuTextureFramebufferMemory, (int)BYTES_TO_MB(gpu::Texture::getTextureGPUFramebufferMemoryUsage()));
|
||||||
STAT_UPDATE(gpuTextureSparseMemory, (int)BYTES_TO_MB(gpu::Texture::getTextureGPUSparseMemoryUsage()));
|
STAT_UPDATE(gpuTextureSparseMemory, (int)BYTES_TO_MB(gpu::Texture::getTextureGPUSparseMemoryUsage()));
|
||||||
STAT_UPDATE(gpuSparseTextureEnabled, gpu::Texture::getEnableSparseTextures() ? 1 : 0);
|
STAT_UPDATE(gpuSparseTextureEnabled, qApp->getGPUContext()->getBackend()->isTextureManagementSparseEnabled() ? 1 : 0);
|
||||||
STAT_UPDATE(gpuFreeMemory, (int)BYTES_TO_MB(gpu::Context::getFreeGPUMemory()));
|
STAT_UPDATE(gpuFreeMemory, (int)BYTES_TO_MB(gpu::Context::getFreeGPUMemory()));
|
||||||
STAT_UPDATE(rectifiedTextureCount, (int)RECTIFIED_TEXTURE_COUNT.load());
|
STAT_UPDATE(rectifiedTextureCount, (int)RECTIFIED_TEXTURE_COUNT.load());
|
||||||
STAT_UPDATE(decimatedTextureCount, (int)DECIMATED_TEXTURE_COUNT.load());
|
STAT_UPDATE(decimatedTextureCount, (int)DECIMATED_TEXTURE_COUNT.load());
|
||||||
|
|
|
@ -55,7 +55,10 @@ void RenderableModelEntityItem::setModelURL(const QString& url) {
|
||||||
auto& currentURL = getParsedModelURL();
|
auto& currentURL = getParsedModelURL();
|
||||||
ModelEntityItem::setModelURL(url);
|
ModelEntityItem::setModelURL(url);
|
||||||
|
|
||||||
if (currentURL != getParsedModelURL() || !_model) {
|
if (currentURL != getParsedModelURL()) {
|
||||||
|
_needsModelReload = true;
|
||||||
|
}
|
||||||
|
if (_needsModelReload || !_model) {
|
||||||
EntityTreePointer tree = getTree();
|
EntityTreePointer tree = getTree();
|
||||||
if (tree) {
|
if (tree) {
|
||||||
QMetaObject::invokeMethod(tree.get(), "callLoader", Qt::QueuedConnection, Q_ARG(EntityItemID, getID()));
|
QMetaObject::invokeMethod(tree.get(), "callLoader", Qt::QueuedConnection, Q_ARG(EntityItemID, getID()));
|
||||||
|
@ -523,17 +526,24 @@ bool RenderableModelEntityItem::needsToCallUpdate() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderableModelEntityItem::update(const quint64& now) {
|
void RenderableModelEntityItem::update(const quint64& now) {
|
||||||
if (!_dimensionsInitialized && _model && _model->isActive()) {
|
if (!_dimensionsInitialized) {
|
||||||
if (_model->isLoaded()) {
|
if (_model) {
|
||||||
EntityItemProperties properties;
|
if (_model->isActive() && _model->isLoaded()) {
|
||||||
properties.setLastEdited(usecTimestampNow()); // we must set the edit time since we're editing it
|
EntityItemProperties properties;
|
||||||
auto extents = _model->getMeshExtents();
|
properties.setLastEdited(usecTimestampNow()); // we must set the edit time since we're editing it
|
||||||
properties.setDimensions(extents.maximum - extents.minimum);
|
auto extents = _model->getMeshExtents();
|
||||||
qCDebug(entitiesrenderer) << "Autoresizing:" << (!getName().isEmpty() ? getName() : getModelURL());
|
properties.setDimensions(extents.maximum - extents.minimum);
|
||||||
QMetaObject::invokeMethod(DependencyManager::get<EntityScriptingInterface>().data(), "editEntity",
|
qCDebug(entitiesrenderer) << "Autoresizing:" << (!getName().isEmpty() ? getName() : getModelURL());
|
||||||
Qt::QueuedConnection,
|
QMetaObject::invokeMethod(DependencyManager::get<EntityScriptingInterface>().data(), "editEntity",
|
||||||
Q_ARG(QUuid, getEntityItemID()),
|
Qt::QueuedConnection,
|
||||||
Q_ARG(EntityItemProperties, properties));
|
Q_ARG(QUuid, getEntityItemID()),
|
||||||
|
Q_ARG(EntityItemProperties, properties));
|
||||||
|
}
|
||||||
|
} else if (_needsModelReload) {
|
||||||
|
EntityTreePointer tree = getTree();
|
||||||
|
if (tree) {
|
||||||
|
QMetaObject::invokeMethod(tree.get(), "callLoader", Qt::QueuedConnection, Q_ARG(EntityItemID, getID()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1035,50 +1035,53 @@ void RenderablePolyVoxEntityItem::copyUpperEdgesFromNeighbors() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityItemPointer currentXPNeighbor = _xPNeighbor.lock();
|
auto currentXPNeighbor = getXPNeighbor();
|
||||||
EntityItemPointer currentYPNeighbor = _yPNeighbor.lock();
|
auto currentYPNeighbor = getYPNeighbor();
|
||||||
EntityItemPointer currentZPNeighbor = _zPNeighbor.lock();
|
auto currentZPNeighbor = getZPNeighbor();
|
||||||
|
|
||||||
if (currentXPNeighbor) {
|
if (currentXPNeighbor && currentXPNeighbor->getVoxelVolumeSize() == _voxelVolumeSize) {
|
||||||
auto polyVoxXPNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentXPNeighbor);
|
withWriteLock([&] {
|
||||||
if (polyVoxXPNeighbor->getVoxelVolumeSize() == _voxelVolumeSize) {
|
for (int y = 0; y < _volData->getHeight(); y++) {
|
||||||
withWriteLock([&] {
|
for (int z = 0; z < _volData->getDepth(); z++) {
|
||||||
|
uint8_t neighborValue = currentXPNeighbor->getVoxel(0, y, z);
|
||||||
|
if ((y == 0 || z == 0) && _volData->getVoxelAt(_volData->getWidth() - 1, y, z) != neighborValue) {
|
||||||
|
bonkNeighbors();
|
||||||
|
}
|
||||||
|
_volData->setVoxelAt(_volData->getWidth() - 1, y, z, neighborValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (currentYPNeighbor && currentYPNeighbor->getVoxelVolumeSize() == _voxelVolumeSize) {
|
||||||
|
withWriteLock([&] {
|
||||||
|
for (int x = 0; x < _volData->getWidth(); x++) {
|
||||||
|
for (int z = 0; z < _volData->getDepth(); z++) {
|
||||||
|
uint8_t neighborValue = currentYPNeighbor->getVoxel(x, 0, z);
|
||||||
|
if ((x == 0 || z == 0) && _volData->getVoxelAt(x, _volData->getHeight() - 1, z) != neighborValue) {
|
||||||
|
bonkNeighbors();
|
||||||
|
}
|
||||||
|
_volData->setVoxelAt(x, _volData->getHeight() - 1, z, neighborValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (currentZPNeighbor && currentZPNeighbor->getVoxelVolumeSize() == _voxelVolumeSize) {
|
||||||
|
withWriteLock([&] {
|
||||||
|
for (int x = 0; x < _volData->getWidth(); x++) {
|
||||||
for (int y = 0; y < _volData->getHeight(); y++) {
|
for (int y = 0; y < _volData->getHeight(); y++) {
|
||||||
for (int z = 0; z < _volData->getDepth(); z++) {
|
uint8_t neighborValue = currentZPNeighbor->getVoxel(x, y, 0);
|
||||||
uint8_t neighborValue = polyVoxXPNeighbor->getVoxel(0, y, z);
|
_volData->setVoxelAt(x, y, _volData->getDepth() - 1, neighborValue);
|
||||||
_volData->setVoxelAt(_volData->getWidth() - 1, y, z, neighborValue);
|
if ((x == 0 || y == 0) && _volData->getVoxelAt(x, y, _volData->getDepth() - 1) != neighborValue) {
|
||||||
|
bonkNeighbors();
|
||||||
}
|
}
|
||||||
|
_volData->setVoxelAt(x, y, _volData->getDepth() - 1, neighborValue);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
}
|
|
||||||
|
|
||||||
if (currentYPNeighbor) {
|
|
||||||
auto polyVoxYPNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentYPNeighbor);
|
|
||||||
if (polyVoxYPNeighbor->getVoxelVolumeSize() == _voxelVolumeSize) {
|
|
||||||
withWriteLock([&] {
|
|
||||||
for (int x = 0; x < _volData->getWidth(); x++) {
|
|
||||||
for (int z = 0; z < _volData->getDepth(); z++) {
|
|
||||||
uint8_t neighborValue = polyVoxYPNeighbor->getVoxel(x, 0, z);
|
|
||||||
_volData->setVoxelAt(x, _volData->getWidth() - 1, z, neighborValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentZPNeighbor) {
|
|
||||||
auto polyVoxZPNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentZPNeighbor);
|
|
||||||
if (polyVoxZPNeighbor->getVoxelVolumeSize() == _voxelVolumeSize) {
|
|
||||||
withWriteLock([&] {
|
|
||||||
for (int x = 0; x < _volData->getWidth(); x++) {
|
|
||||||
for (int y = 0; y < _volData->getHeight(); y++) {
|
|
||||||
uint8_t neighborValue = polyVoxZPNeighbor->getVoxel(x, y, 0);
|
|
||||||
_volData->setVoxelAt(x, y, _volData->getDepth() - 1, neighborValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1393,25 +1396,46 @@ void RenderablePolyVoxEntityItem::setZPNeighborID(const EntityItemID& zPNeighbor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<RenderablePolyVoxEntityItem> RenderablePolyVoxEntityItem::getXNNeighbor() {
|
||||||
|
return std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(_xNNeighbor.lock());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<RenderablePolyVoxEntityItem> RenderablePolyVoxEntityItem::getYNNeighbor() {
|
||||||
|
return std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(_yNNeighbor.lock());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<RenderablePolyVoxEntityItem> RenderablePolyVoxEntityItem::getZNNeighbor() {
|
||||||
|
return std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(_zNNeighbor.lock());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<RenderablePolyVoxEntityItem> RenderablePolyVoxEntityItem::getXPNeighbor() {
|
||||||
|
return std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(_xPNeighbor.lock());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<RenderablePolyVoxEntityItem> RenderablePolyVoxEntityItem::getYPNeighbor() {
|
||||||
|
return std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(_yPNeighbor.lock());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<RenderablePolyVoxEntityItem> RenderablePolyVoxEntityItem::getZPNeighbor() {
|
||||||
|
return std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(_zPNeighbor.lock());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void RenderablePolyVoxEntityItem::bonkNeighbors() {
|
void RenderablePolyVoxEntityItem::bonkNeighbors() {
|
||||||
// flag neighbors to the negative of this entity as needing to rebake their meshes.
|
// flag neighbors to the negative of this entity as needing to rebake their meshes.
|
||||||
cacheNeighbors();
|
cacheNeighbors();
|
||||||
|
|
||||||
EntityItemPointer currentXNNeighbor = _xNNeighbor.lock();
|
auto currentXNNeighbor = getXNNeighbor();
|
||||||
EntityItemPointer currentYNNeighbor = _yNNeighbor.lock();
|
auto currentYNNeighbor = getYNNeighbor();
|
||||||
EntityItemPointer currentZNNeighbor = _zNNeighbor.lock();
|
auto currentZNNeighbor = getZNNeighbor();
|
||||||
|
|
||||||
if (currentXNNeighbor && currentXNNeighbor->getType() == EntityTypes::PolyVox) {
|
if (currentXNNeighbor) {
|
||||||
auto polyVoxXNNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentXNNeighbor);
|
currentXNNeighbor->setVolDataDirty();
|
||||||
polyVoxXNNeighbor->setVolDataDirty();
|
|
||||||
}
|
}
|
||||||
if (currentYNNeighbor && currentYNNeighbor->getType() == EntityTypes::PolyVox) {
|
if (currentYNNeighbor) {
|
||||||
auto polyVoxYNNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentYNNeighbor);
|
currentYNNeighbor->setVolDataDirty();
|
||||||
polyVoxYNNeighbor->setVolDataDirty();
|
|
||||||
}
|
}
|
||||||
if (currentZNNeighbor && currentZNNeighbor->getType() == EntityTypes::PolyVox) {
|
if (currentZNNeighbor) {
|
||||||
auto polyVoxZNNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentZNNeighbor);
|
currentZNNeighbor->setVolDataDirty();
|
||||||
polyVoxZNNeighbor->setVolDataDirty();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,6 +116,13 @@ public:
|
||||||
virtual void setYPNeighborID(const EntityItemID& yPNeighborID) override;
|
virtual void setYPNeighborID(const EntityItemID& yPNeighborID) override;
|
||||||
virtual void setZPNeighborID(const EntityItemID& zPNeighborID) override;
|
virtual void setZPNeighborID(const EntityItemID& zPNeighborID) override;
|
||||||
|
|
||||||
|
std::shared_ptr<RenderablePolyVoxEntityItem> getXNNeighbor();
|
||||||
|
std::shared_ptr<RenderablePolyVoxEntityItem> getYNNeighbor();
|
||||||
|
std::shared_ptr<RenderablePolyVoxEntityItem> getZNNeighbor();
|
||||||
|
std::shared_ptr<RenderablePolyVoxEntityItem> getXPNeighbor();
|
||||||
|
std::shared_ptr<RenderablePolyVoxEntityItem> getYPNeighbor();
|
||||||
|
std::shared_ptr<RenderablePolyVoxEntityItem> getZPNeighbor();
|
||||||
|
|
||||||
virtual void updateRegistrationPoint(const glm::vec3& value) override;
|
virtual void updateRegistrationPoint(const glm::vec3& value) override;
|
||||||
|
|
||||||
void setVoxelsFromData(QByteArray uncompressedData, quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize);
|
void setVoxelsFromData(QByteArray uncompressedData, quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize);
|
||||||
|
|
|
@ -56,6 +56,7 @@ BackendPointer GLBackend::createBackend() {
|
||||||
}
|
}
|
||||||
result->initInput();
|
result->initInput();
|
||||||
result->initTransform();
|
result->initTransform();
|
||||||
|
result->initTextureManagementStage();
|
||||||
|
|
||||||
INSTANCE = result.get();
|
INSTANCE = result.get();
|
||||||
void* voidInstance = &(*result);
|
void* voidInstance = &(*result);
|
||||||
|
|
|
@ -176,6 +176,9 @@ public:
|
||||||
virtual void releaseQuery(GLuint id) const;
|
virtual void releaseQuery(GLuint id) const;
|
||||||
virtual void queueLambda(const std::function<void()> lambda) const;
|
virtual void queueLambda(const std::function<void()> lambda) const;
|
||||||
|
|
||||||
|
bool isTextureManagementSparseEnabled() const override { return (_textureManagement._sparseCapable && Texture::getEnableSparseTextures()); }
|
||||||
|
bool isTextureManagementIncrementalTransferEnabled() const override { return (_textureManagement._incrementalTransferCapable && Texture::getEnableIncrementalTextureTransfers()); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void recycle() const override;
|
void recycle() const override;
|
||||||
|
@ -364,6 +367,12 @@ protected:
|
||||||
|
|
||||||
void resetStages();
|
void resetStages();
|
||||||
|
|
||||||
|
struct TextureManagementStageState {
|
||||||
|
bool _sparseCapable { false };
|
||||||
|
bool _incrementalTransferCapable { false };
|
||||||
|
} _textureManagement;
|
||||||
|
virtual void initTextureManagementStage() {}
|
||||||
|
|
||||||
typedef void (GLBackend::*CommandCall)(const Batch&, size_t);
|
typedef void (GLBackend::*CommandCall)(const Batch&, size_t);
|
||||||
static CommandCall _commandCalls[Batch::NUM_COMMANDS];
|
static CommandCall _commandCalls[Batch::NUM_COMMANDS];
|
||||||
friend class GLState;
|
friend class GLState;
|
||||||
|
|
|
@ -111,7 +111,7 @@ float GLTexture::getMemoryPressure() {
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
// Hardcode texture limit for sparse textures at 1 GB for now
|
// Hardcode texture limit for sparse textures at 1 GB for now
|
||||||
availableTextureMemory = GPU_MEMORY_RESERVE_BYTES;
|
availableTextureMemory = TEXTURE_MEMORY_MIN_BYTES;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ public:
|
||||||
static GLuint allocate(const Texture& texture);
|
static GLuint allocate(const Texture& texture);
|
||||||
static const uint32_t DEFAULT_PAGE_DIMENSION = 128;
|
static const uint32_t DEFAULT_PAGE_DIMENSION = 128;
|
||||||
static const uint32_t DEFAULT_MAX_SPARSE_LEVEL = 0xFFFF;
|
static const uint32_t DEFAULT_MAX_SPARSE_LEVEL = 0xFFFF;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLuint externalId);
|
GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLuint externalId);
|
||||||
GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, bool transferrable);
|
GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, bool transferrable);
|
||||||
|
@ -132,6 +133,9 @@ protected:
|
||||||
|
|
||||||
// Output stage
|
// Output stage
|
||||||
void do_blit(const Batch& batch, size_t paramOffset) override;
|
void do_blit(const Batch& batch, size_t paramOffset) override;
|
||||||
|
|
||||||
|
// Texture Management Stage
|
||||||
|
void initTextureManagementStage() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} }
|
} }
|
||||||
|
|
|
@ -148,6 +148,24 @@ uint32_t SparseInfo::getPageCount(const uvec3& dimensions) const {
|
||||||
return pageCounts.x * pageCounts.y * pageCounts.z;
|
return pageCounts.x * pageCounts.y * pageCounts.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void GL45Backend::initTextureManagementStage() {
|
||||||
|
|
||||||
|
// enable the Sparse Texture on gl45
|
||||||
|
_textureManagement._sparseCapable = true;
|
||||||
|
_textureManagement._incrementalTransferCapable = true;
|
||||||
|
|
||||||
|
// But now let s refine the behavior based on vendor
|
||||||
|
std::string vendor { (const char*)glGetString(GL_VENDOR) };
|
||||||
|
if ((vendor.find("AMD") != std::string::npos) || (vendor.find("ATI") != std::string::npos) || (vendor.find("INTEL") != std::string::npos)) {
|
||||||
|
qCDebug(gpugllogging) << "GPU is sparse capable but force it off, vendor = " << vendor.c_str();
|
||||||
|
_textureManagement._sparseCapable = false;
|
||||||
|
} else {
|
||||||
|
qCDebug(gpugllogging) << "GPU is sparse capable, vendor = " << vendor.c_str();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
using TransferState = GL45Backend::GL45Texture::TransferState;
|
using TransferState = GL45Backend::GL45Texture::TransferState;
|
||||||
|
|
||||||
TransferState::TransferState(GL45Texture& texture) : texture(texture) {
|
TransferState::TransferState(GL45Texture& texture) : texture(texture) {
|
||||||
|
@ -250,7 +268,8 @@ GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture&
|
||||||
GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, bool transferrable)
|
GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, bool transferrable)
|
||||||
: GLTexture(backend, texture, allocate(texture), transferrable), _sparseInfo(*this), _transferState(*this) {
|
: GLTexture(backend, texture, allocate(texture), transferrable), _sparseInfo(*this), _transferState(*this) {
|
||||||
|
|
||||||
if (_transferrable && Texture::getEnableSparseTextures()) {
|
auto theBackend = _backend.lock();
|
||||||
|
if (_transferrable && theBackend && theBackend->isTextureManagementSparseEnabled()) {
|
||||||
_sparseInfo.maybeMakeSparse();
|
_sparseInfo.maybeMakeSparse();
|
||||||
if (_sparseInfo.sparse) {
|
if (_sparseInfo.sparse) {
|
||||||
Backend::incrementTextureGPUSparseCount();
|
Backend::incrementTextureGPUSparseCount();
|
||||||
|
@ -362,7 +381,8 @@ void GL45Texture::startTransfer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GL45Texture::continueTransfer() {
|
bool GL45Texture::continueTransfer() {
|
||||||
if (!Texture::getEnableIncrementalTextureTransfers()) {
|
auto backend = _backend.lock();
|
||||||
|
if (!backend || !backend->isTextureManagementIncrementalTransferEnabled()) {
|
||||||
size_t maxFace = GL_TEXTURE_CUBE_MAP == _target ? CUBE_NUM_FACES : 1;
|
size_t maxFace = GL_TEXTURE_CUBE_MAP == _target ? CUBE_NUM_FACES : 1;
|
||||||
for (uint8_t face = 0; face < maxFace; ++face) {
|
for (uint8_t face = 0; face < maxFace; ++face) {
|
||||||
for (uint16_t mipLevel = _minMip; mipLevel <= _maxMip; ++mipLevel) {
|
for (uint16_t mipLevel = _minMip; mipLevel <= _maxMip; ++mipLevel) {
|
||||||
|
|
|
@ -85,7 +85,8 @@ public:
|
||||||
|
|
||||||
void getStats(ContextStats& stats) const { stats = _stats; }
|
void getStats(ContextStats& stats) const { stats = _stats; }
|
||||||
|
|
||||||
|
virtual bool isTextureManagementSparseEnabled() const = 0;
|
||||||
|
virtual bool isTextureManagementIncrementalTransferEnabled() const = 0;
|
||||||
|
|
||||||
// These should only be accessed by Backend implementation to repport the buffer and texture allocations,
|
// These should only be accessed by Backend implementation to repport the buffer and texture allocations,
|
||||||
// they are NOT public calls
|
// they are NOT public calls
|
||||||
|
@ -125,6 +126,7 @@ protected:
|
||||||
friend class Context;
|
friend class Context;
|
||||||
ContextStats _stats;
|
ContextStats _stats;
|
||||||
StereoState _stereo;
|
StereoState _stereo;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Context {
|
class Context {
|
||||||
|
@ -270,7 +272,6 @@ protected:
|
||||||
static std::atomic<Size> _textureGPUFramebufferMemoryUsage;
|
static std::atomic<Size> _textureGPUFramebufferMemoryUsage;
|
||||||
static std::atomic<uint32_t> _textureGPUTransferCount;
|
static std::atomic<uint32_t> _textureGPUTransferCount;
|
||||||
|
|
||||||
|
|
||||||
friend class Backend;
|
friend class Backend;
|
||||||
};
|
};
|
||||||
typedef std::shared_ptr<Context> ContextPointer;
|
typedef std::shared_ptr<Context> ContextPointer;
|
||||||
|
|
|
@ -147,6 +147,7 @@ class Texture : public Resource {
|
||||||
|
|
||||||
static std::atomic<bool> _enableSparseTextures;
|
static std::atomic<bool> _enableSparseTextures;
|
||||||
static std::atomic<bool> _enableIncrementalTextureTransfers;
|
static std::atomic<bool> _enableIncrementalTextureTransfers;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static uint32_t getTextureCPUCount();
|
static uint32_t getTextureCPUCount();
|
||||||
static Size getTextureCPUMemoryUsage();
|
static Size getTextureCPUMemoryUsage();
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
|
#include <QMetaEnum>
|
||||||
|
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
|
||||||
|
@ -78,10 +79,36 @@ void HTTPResourceRequest::onRequestFinished() {
|
||||||
_loadedFromCache = _reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool();
|
_loadedFromCache = _reply->attribute(QNetworkRequest::SourceIsFromCacheAttribute).toBool();
|
||||||
_result = Success;
|
_result = Success;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case QNetworkReply::TimeoutError:
|
case QNetworkReply::TimeoutError:
|
||||||
_result = Timeout;
|
_result = Timeout;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case QNetworkReply::ContentNotFoundError: // Script.include('https://httpbin.org/status/404')
|
||||||
|
_result = NotFound;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QNetworkReply::ProtocolInvalidOperationError: // Script.include('https://httpbin.org/status/400')
|
||||||
|
_result = InvalidURL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QNetworkReply::UnknownContentError: // Script.include('QUrl("https://httpbin.org/status/402")')
|
||||||
|
case QNetworkReply::ContentOperationNotPermittedError: //Script.include('https://httpbin.org/status/403')
|
||||||
|
case QNetworkReply::AuthenticationRequiredError: // Script.include('https://httpbin.org/basic-auth/user/passwd')
|
||||||
|
_result = AccessDenied;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QNetworkReply::RemoteHostClosedError: // Script.include('http://127.0.0.1:22')
|
||||||
|
case QNetworkReply::ConnectionRefusedError: // Script.include(http://127.0.0.1:1')
|
||||||
|
case QNetworkReply::HostNotFoundError: // Script.include('http://foo.bar.highfidelity.io')
|
||||||
|
case QNetworkReply::ServiceUnavailableError: // Script.include('QUrl("https://httpbin.org/status/503")')
|
||||||
|
_result = ServerUnavailable;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QNetworkReply::UnknownServerError: // Script.include('QUrl("https://httpbin.org/status/504")')
|
||||||
|
case QNetworkReply::InternalServerError: // Script.include('QUrl("https://httpbin.org/status/500")')
|
||||||
default:
|
default:
|
||||||
|
qDebug() << "HTTPResourceRequest error:" << QMetaEnum::fromType<QNetworkReply::NetworkError>().valueToKey(_reply->error());
|
||||||
_result = Error;
|
_result = Error;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -451,6 +451,9 @@ bool OctreePacketData::appendValue(const QVector<bool>& value) {
|
||||||
bit = 0;
|
bit = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (bit != 0) {
|
||||||
|
destinationBuffer++;
|
||||||
|
}
|
||||||
int boolsSize = destinationBuffer - start;
|
int boolsSize = destinationBuffer - start;
|
||||||
success = append(start, boolsSize);
|
success = append(start, boolsSize);
|
||||||
if (success) {
|
if (success) {
|
||||||
|
@ -683,6 +686,10 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char *dataBytes, QVecto
|
||||||
uint16_t length;
|
uint16_t length;
|
||||||
memcpy(&length, dataBytes, sizeof(uint16_t));
|
memcpy(&length, dataBytes, sizeof(uint16_t));
|
||||||
dataBytes += sizeof(length);
|
dataBytes += sizeof(length);
|
||||||
|
if (length * sizeof(glm::vec3) > MAX_OCTREE_UNCOMRESSED_PACKET_SIZE) {
|
||||||
|
result.resize(0);
|
||||||
|
return sizeof(uint16_t);
|
||||||
|
}
|
||||||
result.resize(length);
|
result.resize(length);
|
||||||
memcpy(result.data(), dataBytes, length * sizeof(glm::vec3));
|
memcpy(result.data(), dataBytes, length * sizeof(glm::vec3));
|
||||||
return sizeof(uint16_t) + length * sizeof(glm::vec3);
|
return sizeof(uint16_t) + length * sizeof(glm::vec3);
|
||||||
|
@ -692,6 +699,10 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char *dataBytes, QVecto
|
||||||
uint16_t length;
|
uint16_t length;
|
||||||
memcpy(&length, dataBytes, sizeof(uint16_t));
|
memcpy(&length, dataBytes, sizeof(uint16_t));
|
||||||
dataBytes += sizeof(length);
|
dataBytes += sizeof(length);
|
||||||
|
if (length * sizeof(glm::quat) > MAX_OCTREE_UNCOMRESSED_PACKET_SIZE) {
|
||||||
|
result.resize(0);
|
||||||
|
return sizeof(uint16_t);
|
||||||
|
}
|
||||||
result.resize(length);
|
result.resize(length);
|
||||||
|
|
||||||
const unsigned char *start = dataBytes;
|
const unsigned char *start = dataBytes;
|
||||||
|
@ -706,6 +717,10 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QVecto
|
||||||
uint16_t length;
|
uint16_t length;
|
||||||
memcpy(&length, dataBytes, sizeof(uint16_t));
|
memcpy(&length, dataBytes, sizeof(uint16_t));
|
||||||
dataBytes += sizeof(length);
|
dataBytes += sizeof(length);
|
||||||
|
if (length * sizeof(float) > MAX_OCTREE_UNCOMRESSED_PACKET_SIZE) {
|
||||||
|
result.resize(0);
|
||||||
|
return sizeof(uint16_t);
|
||||||
|
}
|
||||||
result.resize(length);
|
result.resize(length);
|
||||||
memcpy(result.data(), dataBytes, length * sizeof(float));
|
memcpy(result.data(), dataBytes, length * sizeof(float));
|
||||||
return sizeof(uint16_t) + length * sizeof(float);
|
return sizeof(uint16_t) + length * sizeof(float);
|
||||||
|
@ -715,6 +730,10 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QVecto
|
||||||
uint16_t length;
|
uint16_t length;
|
||||||
memcpy(&length, dataBytes, sizeof(uint16_t));
|
memcpy(&length, dataBytes, sizeof(uint16_t));
|
||||||
dataBytes += sizeof(length);
|
dataBytes += sizeof(length);
|
||||||
|
if (length / 8 > MAX_OCTREE_UNCOMRESSED_PACKET_SIZE) {
|
||||||
|
result.resize(0);
|
||||||
|
return sizeof(uint16_t);
|
||||||
|
}
|
||||||
result.resize(length);
|
result.resize(length);
|
||||||
|
|
||||||
int bit = 0;
|
int bit = 0;
|
||||||
|
|
|
@ -256,8 +256,18 @@ const btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SHAPE_TYPE_SPHERE: {
|
case SHAPE_TYPE_SPHERE: {
|
||||||
float radius = info.getHalfExtents().x;
|
glm::vec3 halfExtents = info.getHalfExtents();
|
||||||
shape = new btSphereShape(radius);
|
float radius = halfExtents.x;
|
||||||
|
if (radius == halfExtents.y && radius == halfExtents.z) {
|
||||||
|
shape = new btSphereShape(radius);
|
||||||
|
} else {
|
||||||
|
ShapeInfo::PointList points;
|
||||||
|
points.reserve(NUM_UNIT_SPHERE_DIRECTIONS);
|
||||||
|
for (uint32_t i = 0; i < NUM_UNIT_SPHERE_DIRECTIONS; ++i) {
|
||||||
|
points.push_back(bulletToGLM(_unitSphereDirections[i]) * halfExtents);
|
||||||
|
}
|
||||||
|
shape = createConvexHull(points);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SHAPE_TYPE_CAPSULE_Y: {
|
case SHAPE_TYPE_CAPSULE_Y: {
|
||||||
|
|
|
@ -21,6 +21,9 @@ public:
|
||||||
virtual void pluginFocusOutEvent() = 0;
|
virtual void pluginFocusOutEvent() = 0;
|
||||||
virtual void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) = 0;
|
virtual void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) = 0;
|
||||||
|
|
||||||
|
// Some input plugins are comprised of multiple subdevices (SDL2, for instance).
|
||||||
|
// If an input plugin is only a single device, it will only return it's primary name.
|
||||||
|
virtual QStringList getSubdeviceNames() { return { getName() }; };
|
||||||
virtual bool isHandController() const = 0;
|
virtual bool isHandController() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -32,3 +32,26 @@ bool PluginUtils::isHandControllerAvailable() {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool isSubdeviceContainingNameAvailable(QString name) {
|
||||||
|
for (auto& inputPlugin : PluginManager::getInstance()->getInputPlugins()) {
|
||||||
|
if (inputPlugin->isActive()) {
|
||||||
|
auto subdeviceNames = inputPlugin->getSubdeviceNames();
|
||||||
|
for (auto& subdeviceName : subdeviceNames) {
|
||||||
|
if (subdeviceName.contains(name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool PluginUtils::isViveControllerAvailable() {
|
||||||
|
return isSubdeviceContainingNameAvailable("OpenVR");
|
||||||
|
};
|
||||||
|
|
||||||
|
bool PluginUtils::isXboxControllerAvailable() {
|
||||||
|
return isSubdeviceContainingNameAvailable("X360 Controller");
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -16,4 +16,6 @@ class PluginUtils {
|
||||||
public:
|
public:
|
||||||
static bool isHMDAvailable(const QString& pluginName = "");
|
static bool isHMDAvailable(const QString& pluginName = "");
|
||||||
static bool isHandControllerAvailable();
|
static bool isHandControllerAvailable();
|
||||||
|
static bool isViveControllerAvailable();
|
||||||
|
static bool isXboxControllerAvailable();
|
||||||
};
|
};
|
||||||
|
|
|
@ -55,7 +55,8 @@ void BatchLoader::start() {
|
||||||
// Use a proxy callback to handle the call and emit the signal in a thread-safe way.
|
// Use a proxy callback to handle the call and emit the signal in a thread-safe way.
|
||||||
// If BatchLoader is deleted before the callback is called, the subsequent "emit" call will not do
|
// If BatchLoader is deleted before the callback is called, the subsequent "emit" call will not do
|
||||||
// anything.
|
// anything.
|
||||||
ScriptCacheSignalProxy* proxy = new ScriptCacheSignalProxy(scriptCache.data());
|
ScriptCacheSignalProxy* proxy = new ScriptCacheSignalProxy();
|
||||||
|
connect(scriptCache.data(), &ScriptCache::destroyed, proxy, &ScriptCacheSignalProxy::deleteLater);
|
||||||
|
|
||||||
connect(proxy, &ScriptCacheSignalProxy::contentAvailable, this, [this](const QString& url, const QString& contents, bool isURL, bool success) {
|
connect(proxy, &ScriptCacheSignalProxy::contentAvailable, this, [this](const QString& url, const QString& contents, bool isURL, bool success) {
|
||||||
if (isURL && success) {
|
if (isURL && success) {
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
class ScriptCacheSignalProxy : public QObject {
|
class ScriptCacheSignalProxy : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
ScriptCacheSignalProxy(QObject* parent) : QObject(parent) { }
|
|
||||||
void receivedContent(const QString& url, const QString& contents, bool isURL, bool success);
|
void receivedContent(const QString& url, const QString& contents, bool isURL, bool success);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
|
@ -37,29 +37,30 @@ glm::quat Quat::lookAt(const glm::vec3& eye, const glm::vec3& center, const glm:
|
||||||
glm::quat Quat::lookAtSimple(const glm::vec3& eye, const glm::vec3& center) {
|
glm::quat Quat::lookAtSimple(const glm::vec3& eye, const glm::vec3& center) {
|
||||||
auto dir = glm::normalize(center - eye);
|
auto dir = glm::normalize(center - eye);
|
||||||
// if the direction is nearly aligned with the Y axis, then use the X axis for 'up'
|
// if the direction is nearly aligned with the Y axis, then use the X axis for 'up'
|
||||||
if (dir.x < 0.001f && dir.z < 0.001f) {
|
const float MAX_ABS_Y_COMPONENT = 0.9999991f;
|
||||||
|
if (fabsf(dir.y) > MAX_ABS_Y_COMPONENT) {
|
||||||
return lookAt(eye, center, Vectors::UNIT_X);
|
return lookAt(eye, center, Vectors::UNIT_X);
|
||||||
}
|
}
|
||||||
return lookAt(eye, center, Vectors::UNIT_Y);
|
return lookAt(eye, center, Vectors::UNIT_Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::quat Quat::multiply(const glm::quat& q1, const glm::quat& q2) {
|
glm::quat Quat::multiply(const glm::quat& q1, const glm::quat& q2) {
|
||||||
return q1 * q2;
|
return q1 * q2;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::quat Quat::fromVec3Degrees(const glm::vec3& eulerAngles) {
|
glm::quat Quat::fromVec3Degrees(const glm::vec3& eulerAngles) {
|
||||||
return glm::quat(glm::radians(eulerAngles));
|
return glm::quat(glm::radians(eulerAngles));
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::quat Quat::fromVec3Radians(const glm::vec3& eulerAngles) {
|
glm::quat Quat::fromVec3Radians(const glm::vec3& eulerAngles) {
|
||||||
return glm::quat(eulerAngles);
|
return glm::quat(eulerAngles);
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::quat Quat::fromPitchYawRollDegrees(float pitch, float yaw, float roll) {
|
glm::quat Quat::fromPitchYawRollDegrees(float pitch, float yaw, float roll) {
|
||||||
return glm::quat(glm::radians(glm::vec3(pitch, yaw, roll)));
|
return glm::quat(glm::radians(glm::vec3(pitch, yaw, roll)));
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::quat Quat::fromPitchYawRollRadians(float pitch, float yaw, float roll) {
|
glm::quat Quat::fromPitchYawRollRadians(float pitch, float yaw, float roll) {
|
||||||
return glm::quat(glm::vec3(pitch, yaw, roll));
|
return glm::quat(glm::vec3(pitch, yaw, roll));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -202,7 +202,14 @@ void ScriptCache::scriptContentAvailable() {
|
||||||
finished = true;
|
finished = true;
|
||||||
qCDebug(scriptengine) << "Done downloading script at:" << url.toString();
|
qCDebug(scriptengine) << "Done downloading script at:" << url.toString();
|
||||||
} else {
|
} else {
|
||||||
if (scriptRequest.numRetries < MAX_RETRIES) {
|
auto result = req->getResult();
|
||||||
|
bool irrecoverable =
|
||||||
|
result == ResourceRequest::AccessDenied ||
|
||||||
|
result == ResourceRequest::InvalidURL ||
|
||||||
|
result == ResourceRequest::NotFound ||
|
||||||
|
scriptRequest.numRetries >= MAX_RETRIES;
|
||||||
|
|
||||||
|
if (!irrecoverable) {
|
||||||
++scriptRequest.numRetries;
|
++scriptRequest.numRetries;
|
||||||
|
|
||||||
qDebug() << "Script request failed: " << url;
|
qDebug() << "Script request failed: " << url;
|
||||||
|
@ -222,6 +229,9 @@ void ScriptCache::scriptContentAvailable() {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Dubious, but retained here because it matches the behavior before fixing the threading
|
// Dubious, but retained here because it matches the behavior before fixing the threading
|
||||||
|
|
||||||
|
allCallbacks = scriptRequest.scriptUsers;
|
||||||
|
|
||||||
scriptContent = _scriptCache[url];
|
scriptContent = _scriptCache[url];
|
||||||
finished = true;
|
finished = true;
|
||||||
qCWarning(scriptengine) << "Error loading script from URL " << url;
|
qCWarning(scriptengine) << "Error loading script from URL " << url;
|
||||||
|
|
|
@ -10,9 +10,15 @@
|
||||||
|
|
||||||
#include <QtCore/QtGlobal>
|
#include <QtCore/QtGlobal>
|
||||||
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#include <atlbase.h>
|
#include <string>
|
||||||
#include <Wbemidl.h>
|
|
||||||
|
//#include <atlbase.h>
|
||||||
|
//#include <Wbemidl.h>
|
||||||
|
|
||||||
|
#include <dxgi1_3.h>
|
||||||
|
#pragma comment(lib, "dxgi.lib")
|
||||||
|
|
||||||
#elif defined(Q_OS_MAC)
|
#elif defined(Q_OS_MAC)
|
||||||
#include <OpenGL/OpenGL.h>
|
#include <OpenGL/OpenGL.h>
|
||||||
|
@ -53,9 +59,101 @@ GPUIdent* GPUIdent::ensureQuery(const QString& vendor, const QString& renderer)
|
||||||
CGLDestroyRendererInfo(rendererInfo);
|
CGLDestroyRendererInfo(rendererInfo);
|
||||||
|
|
||||||
#elif defined(Q_OS_WIN)
|
#elif defined(Q_OS_WIN)
|
||||||
|
|
||||||
|
struct ConvertLargeIntegerToQString {
|
||||||
|
QString convert(const LARGE_INTEGER& version) {
|
||||||
|
QString value;
|
||||||
|
value.append(QString::number(uint32_t(((version.HighPart & 0xFFFF0000) >> 16) & 0x0000FFFF)));
|
||||||
|
value.append(".");
|
||||||
|
value.append(QString::number(uint32_t((version.HighPart) & 0x0000FFFF)));
|
||||||
|
value.append(".");
|
||||||
|
value.append(QString::number(uint32_t(((version.LowPart & 0xFFFF0000) >> 16) & 0x0000FFFF)));
|
||||||
|
value.append(".");
|
||||||
|
value.append(QString::number(uint32_t((version.LowPart) & 0x0000FFFF)));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
} convertDriverVersionToString;
|
||||||
|
|
||||||
|
// Create the DXGI factory
|
||||||
|
// Let s get into DXGI land:
|
||||||
|
HRESULT hr = S_OK;
|
||||||
|
|
||||||
|
IDXGIFactory1* pFactory = nullptr;
|
||||||
|
hr = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)(&pFactory) );
|
||||||
|
if (hr != S_OK || pFactory == nullptr) {
|
||||||
|
qCDebug(shared) << "Unable to create DXGI";
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> validAdapterList;
|
||||||
|
using AdapterEntry = std::pair<std::pair<DXGI_ADAPTER_DESC1, LARGE_INTEGER>, std::vector<DXGI_OUTPUT_DESC>>;
|
||||||
|
std::vector<AdapterEntry> adapterToOutputs;
|
||||||
|
// Enumerate adapters and outputs
|
||||||
|
{
|
||||||
|
UINT adapterNum = 0;
|
||||||
|
IDXGIAdapter1* pAdapter = nullptr;
|
||||||
|
while (pFactory->EnumAdapters1(adapterNum, &pAdapter) != DXGI_ERROR_NOT_FOUND) {
|
||||||
|
|
||||||
|
// Found an adapter, get descriptor
|
||||||
|
DXGI_ADAPTER_DESC1 adapterDesc;
|
||||||
|
pAdapter->GetDesc1(&adapterDesc);
|
||||||
|
|
||||||
|
LARGE_INTEGER version;
|
||||||
|
hr = pAdapter->CheckInterfaceSupport(__uuidof(IDXGIDevice), &version);
|
||||||
|
|
||||||
|
std::wstring wDescription (adapterDesc.Description);
|
||||||
|
std::string description(wDescription.begin(), wDescription.end());
|
||||||
|
qCDebug(shared) << "Found adapter: " << description.c_str()
|
||||||
|
<< " Driver version: " << convertDriverVersionToString.convert(version);
|
||||||
|
|
||||||
|
AdapterEntry adapterEntry;
|
||||||
|
adapterEntry.first.first = adapterDesc;
|
||||||
|
adapterEntry.first.second = version;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
UINT outputNum = 0;
|
||||||
|
IDXGIOutput * pOutput;
|
||||||
|
bool hasOutputConnectedToDesktop = false;
|
||||||
|
while (pAdapter->EnumOutputs(outputNum, &pOutput) != DXGI_ERROR_NOT_FOUND) {
|
||||||
|
|
||||||
|
// FOund an output attached to the adapter, get descriptor
|
||||||
|
DXGI_OUTPUT_DESC outputDesc;
|
||||||
|
pOutput->GetDesc(&outputDesc);
|
||||||
|
|
||||||
|
adapterEntry.second.push_back(outputDesc);
|
||||||
|
|
||||||
|
std::wstring wDeviceName(outputDesc.DeviceName);
|
||||||
|
std::string deviceName(wDeviceName.begin(), wDeviceName.end());
|
||||||
|
qCDebug(shared) << " Found output: " << deviceName.c_str() << " desktop: " << (outputDesc.AttachedToDesktop ? "true" : "false")
|
||||||
|
<< " Rect [ l=" << outputDesc.DesktopCoordinates.left << " r=" << outputDesc.DesktopCoordinates.right
|
||||||
|
<< " b=" << outputDesc.DesktopCoordinates.bottom << " t=" << outputDesc.DesktopCoordinates.top << " ]";
|
||||||
|
|
||||||
|
hasOutputConnectedToDesktop |= (bool) outputDesc.AttachedToDesktop;
|
||||||
|
|
||||||
|
pOutput->Release();
|
||||||
|
outputNum++;
|
||||||
|
}
|
||||||
|
|
||||||
|
adapterToOutputs.push_back(adapterEntry);
|
||||||
|
|
||||||
|
// add this adapter to the valid list if has output
|
||||||
|
if (hasOutputConnectedToDesktop && !adapterEntry.second.empty()) {
|
||||||
|
validAdapterList.push_back(adapterNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
pAdapter->Release();
|
||||||
|
adapterNum++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pFactory->Release();
|
||||||
|
|
||||||
|
|
||||||
|
// THis was the previous technique used to detect the platform we are running on on windows.
|
||||||
|
/*
|
||||||
// COM must be initialized already using CoInitialize. E.g., by the audio subsystem.
|
// COM must be initialized already using CoInitialize. E.g., by the audio subsystem.
|
||||||
CComPtr<IWbemLocator> spLoc = NULL;
|
CComPtr<IWbemLocator> spLoc = NULL;
|
||||||
HRESULT hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_SERVER, IID_IWbemLocator, (LPVOID *)&spLoc);
|
hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_SERVER, IID_IWbemLocator, (LPVOID *)&spLoc);
|
||||||
if (hr != S_OK || spLoc == NULL) {
|
if (hr != S_OK || spLoc == NULL) {
|
||||||
qCDebug(shared) << "Unable to connect to WMI";
|
qCDebug(shared) << "Unable to connect to WMI";
|
||||||
return this;
|
return this;
|
||||||
|
@ -139,7 +237,7 @@ GPUIdent* GPUIdent::ensureQuery(const QString& vendor, const QString& renderer)
|
||||||
var.ChangeType(CIM_UINT64); // We're going to receive some integral type, but it might not be uint.
|
var.ChangeType(CIM_UINT64); // We're going to receive some integral type, but it might not be uint.
|
||||||
// We might be hosed here. The parameter is documented to be UINT32, but that's only 4 GB!
|
// We might be hosed here. The parameter is documented to be UINT32, but that's only 4 GB!
|
||||||
const ULONGLONG BYTES_PER_MEGABYTE = 1024 * 1024;
|
const ULONGLONG BYTES_PER_MEGABYTE = 1024 * 1024;
|
||||||
_dedicatedMemoryMB = (uint) (var.ullVal / BYTES_PER_MEGABYTE);
|
_dedicatedMemoryMB = (uint64_t) (var.ullVal / BYTES_PER_MEGABYTE);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
qCDebug(shared) << "Unable to get video AdapterRAM";
|
qCDebug(shared) << "Unable to get video AdapterRAM";
|
||||||
|
@ -149,6 +247,22 @@ GPUIdent* GPUIdent::ensureQuery(const QString& vendor, const QString& renderer)
|
||||||
}
|
}
|
||||||
hr = spEnumInst->Next(WBEM_INFINITE, 1, &spInstance.p, &uNumOfInstances);
|
hr = spEnumInst->Next(WBEM_INFINITE, 1, &spInstance.p, &uNumOfInstances);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!validAdapterList.empty()) {
|
||||||
|
auto& adapterEntry = adapterToOutputs[validAdapterList.front()];
|
||||||
|
|
||||||
|
std::wstring wDescription(adapterEntry.first.first.Description);
|
||||||
|
std::string description(wDescription.begin(), wDescription.end());
|
||||||
|
_name = QString(description.c_str());
|
||||||
|
|
||||||
|
_driver = convertDriverVersionToString.convert(adapterEntry.first.second);
|
||||||
|
|
||||||
|
const ULONGLONG BYTES_PER_MEGABYTE = 1024 * 1024;
|
||||||
|
_dedicatedMemoryMB = (uint64_t)(adapterEntry.first.first.DedicatedVideoMemory / BYTES_PER_MEGABYTE);
|
||||||
|
_isValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,17 +14,19 @@
|
||||||
#ifndef hifi_GPUIdent_h
|
#ifndef hifi_GPUIdent_h
|
||||||
#define hifi_GPUIdent_h
|
#define hifi_GPUIdent_h
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
class GPUIdent
|
class GPUIdent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
unsigned int getMemory() { return _dedicatedMemoryMB; }
|
uint64_t getMemory() { return _dedicatedMemoryMB; }
|
||||||
QString getName() { return _name; }
|
QString getName() { return _name; }
|
||||||
QString getDriver() { return _driver; }
|
QString getDriver() { return _driver; }
|
||||||
bool isValid() { return _isValid; }
|
bool isValid() { return _isValid; }
|
||||||
// E.g., GPUIdent::getInstance()->getMemory();
|
// E.g., GPUIdent::getInstance()->getMemory();
|
||||||
static GPUIdent* getInstance(const QString& vendor = "", const QString& renderer = "") { return _instance.ensureQuery(vendor, renderer); }
|
static GPUIdent* getInstance(const QString& vendor = "", const QString& renderer = "") { return _instance.ensureQuery(vendor, renderer); }
|
||||||
private:
|
private:
|
||||||
uint _dedicatedMemoryMB { 0 };
|
uint64_t _dedicatedMemoryMB { 0 };
|
||||||
QString _name { "" };
|
QString _name { "" };
|
||||||
QString _driver { "" };
|
QString _driver { "" };
|
||||||
bool _isQueried { false };
|
bool _isQueried { false };
|
||||||
|
|
|
@ -263,6 +263,14 @@ void quatFromScriptValue(const QScriptValue& object, glm::quat &quat) {
|
||||||
quat.y = object.property("y").toVariant().toFloat();
|
quat.y = object.property("y").toVariant().toFloat();
|
||||||
quat.z = object.property("z").toVariant().toFloat();
|
quat.z = object.property("z").toVariant().toFloat();
|
||||||
quat.w = object.property("w").toVariant().toFloat();
|
quat.w = object.property("w").toVariant().toFloat();
|
||||||
|
|
||||||
|
// enforce normalized quaternion
|
||||||
|
float length = glm::length(quat);
|
||||||
|
if (length > FLT_EPSILON) {
|
||||||
|
quat /= length;
|
||||||
|
} else {
|
||||||
|
quat = glm::quat();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::quat quatFromVariant(const QVariant &object, bool& isValid) {
|
glm::quat quatFromVariant(const QVariant &object, bool& isValid) {
|
||||||
|
@ -273,6 +281,14 @@ glm::quat quatFromVariant(const QVariant &object, bool& isValid) {
|
||||||
q.y = qvec3.y();
|
q.y = qvec3.y();
|
||||||
q.z = qvec3.z();
|
q.z = qvec3.z();
|
||||||
q.w = qvec3.scalar();
|
q.w = qvec3.scalar();
|
||||||
|
|
||||||
|
// enforce normalized quaternion
|
||||||
|
float length = glm::length(q);
|
||||||
|
if (length > FLT_EPSILON) {
|
||||||
|
q /= length;
|
||||||
|
} else {
|
||||||
|
q = glm::quat();
|
||||||
|
}
|
||||||
isValid = true;
|
isValid = true;
|
||||||
} else {
|
} else {
|
||||||
auto map = object.toMap();
|
auto map = object.toMap();
|
||||||
|
|
|
@ -33,13 +33,8 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString
|
||||||
_halfExtents = glm::vec3(0.0f);
|
_halfExtents = glm::vec3(0.0f);
|
||||||
break;
|
break;
|
||||||
case SHAPE_TYPE_BOX:
|
case SHAPE_TYPE_BOX:
|
||||||
|
case SHAPE_TYPE_SPHERE:
|
||||||
break;
|
break;
|
||||||
case SHAPE_TYPE_SPHERE: {
|
|
||||||
// sphere radius is max of halfExtents
|
|
||||||
float radius = glm::max(glm::max(halfExtents.x, halfExtents.y), halfExtents.z);
|
|
||||||
_halfExtents = glm::vec3(radius);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SHAPE_TYPE_COMPOUND:
|
case SHAPE_TYPE_COMPOUND:
|
||||||
case SHAPE_TYPE_STATIC_MESH:
|
case SHAPE_TYPE_STATIC_MESH:
|
||||||
_url = QUrl(url);
|
_url = QUrl(url);
|
||||||
|
@ -119,8 +114,7 @@ float ShapeInfo::computeVolume() const {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SHAPE_TYPE_SPHERE: {
|
case SHAPE_TYPE_SPHERE: {
|
||||||
float radius = _halfExtents.x;
|
volume = 4.0f * PI * _halfExtents.x * _halfExtents.y * _halfExtents.z / 3.0f;
|
||||||
volume = 4.0f * PI * radius * radius * radius / 3.0f;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SHAPE_TYPE_CYLINDER_Y: {
|
case SHAPE_TYPE_CYLINDER_Y: {
|
||||||
|
|
|
@ -37,7 +37,7 @@ QString fetchVersion(const QUrl& url) {
|
||||||
return r.trimmed();
|
return r.trimmed();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InfoView::show(const QString& path, bool firstOrChangedOnly) {
|
void InfoView::show(const QString& path, bool firstOrChangedOnly, QString urlQuery) {
|
||||||
static bool registered{ false };
|
static bool registered{ false };
|
||||||
if (!registered) {
|
if (!registered) {
|
||||||
registerType();
|
registerType();
|
||||||
|
@ -49,6 +49,8 @@ void InfoView::show(const QString& path, bool firstOrChangedOnly) {
|
||||||
} else {
|
} else {
|
||||||
url = QUrl::fromLocalFile(path);
|
url = QUrl::fromLocalFile(path);
|
||||||
}
|
}
|
||||||
|
url.setQuery(urlQuery);
|
||||||
|
|
||||||
if (firstOrChangedOnly) {
|
if (firstOrChangedOnly) {
|
||||||
const QString lastVersion = infoVersion.get();
|
const QString lastVersion = infoVersion.get();
|
||||||
const QString version = fetchVersion(url);
|
const QString version = fetchVersion(url);
|
||||||
|
|
|
@ -22,7 +22,7 @@ class InfoView : public QQuickItem {
|
||||||
static const QString NAME;
|
static const QString NAME;
|
||||||
public:
|
public:
|
||||||
static void registerType();
|
static void registerType();
|
||||||
static void show(const QString& path, bool firstOrChangedOnly = false);
|
static void show(const QString& path, bool firstOrChangedOnly = false, QString urlQuery = "");
|
||||||
|
|
||||||
InfoView(QQuickItem* parent = nullptr);
|
InfoView(QQuickItem* parent = nullptr);
|
||||||
QUrl url();
|
QUrl url();
|
||||||
|
|
|
@ -371,6 +371,13 @@ void OffscreenUi::setPinned(bool pinned) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OffscreenUi::setConstrainToolbarToCenterX(bool constrained) {
|
||||||
|
bool invokeResult = QMetaObject::invokeMethod(_desktop, "setConstrainToolbarToCenterX", Q_ARG(QVariant, constrained));
|
||||||
|
if (!invokeResult) {
|
||||||
|
qWarning() << "Failed to set toolbar constraint";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void OffscreenUi::addMenuInitializer(std::function<void(VrMenu*)> f) {
|
void OffscreenUi::addMenuInitializer(std::function<void(VrMenu*)> f) {
|
||||||
if (!_vrMenu) {
|
if (!_vrMenu) {
|
||||||
_queuedMenuInitializers.push_back(f);
|
_queuedMenuInitializers.push_back(f);
|
||||||
|
|
|
@ -52,6 +52,7 @@ public:
|
||||||
void setPinned(bool pinned = true);
|
void setPinned(bool pinned = true);
|
||||||
|
|
||||||
void togglePinned();
|
void togglePinned();
|
||||||
|
void setConstrainToolbarToCenterX(bool constrained);
|
||||||
|
|
||||||
bool eventFilter(QObject* originalDestination, QEvent* event) override;
|
bool eventFilter(QObject* originalDestination, QEvent* event) override;
|
||||||
void addMenuInitializer(std::function<void(VrMenu*)> f);
|
void addMenuInitializer(std::function<void(VrMenu*)> f);
|
||||||
|
|
|
@ -31,6 +31,8 @@ public:
|
||||||
|
|
||||||
const QString& getName() const { return _name; }
|
const QString& getName() const { return _name; }
|
||||||
|
|
||||||
|
SDL_GameController* getGameController() { return _sdlGameController; }
|
||||||
|
|
||||||
// Device functions
|
// Device functions
|
||||||
virtual controller::Input::NamedVector getAvailableInputs() const override;
|
virtual controller::Input::NamedVector getAvailableInputs() const override;
|
||||||
virtual QString getDefaultMappingConfig() const override;
|
virtual QString getDefaultMappingConfig() const override;
|
||||||
|
|
|
@ -65,8 +65,10 @@ void SDL2Manager::init() {
|
||||||
_openJoysticks[id] = joystick;
|
_openJoysticks[id] = joystick;
|
||||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||||
userInputMapper->registerDevice(joystick);
|
userInputMapper->registerDevice(joystick);
|
||||||
|
auto name = SDL_GameControllerName(controller);
|
||||||
|
_subdeviceNames << name;
|
||||||
emit joystickAdded(joystick.get());
|
emit joystickAdded(joystick.get());
|
||||||
emit subdeviceConnected(getName(), SDL_GameControllerName(controller));
|
emit subdeviceConnected(getName(), name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,6 +80,10 @@ void SDL2Manager::init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList SDL2Manager::getSubdeviceNames() {
|
||||||
|
return _subdeviceNames;
|
||||||
|
}
|
||||||
|
|
||||||
void SDL2Manager::deinit() {
|
void SDL2Manager::deinit() {
|
||||||
_openJoysticks.clear();
|
_openJoysticks.clear();
|
||||||
|
|
||||||
|
@ -157,15 +163,19 @@ void SDL2Manager::pluginUpdate(float deltaTime, const controller::InputCalibrati
|
||||||
Joystick::Pointer joystick = std::make_shared<Joystick>(id, controller);
|
Joystick::Pointer joystick = std::make_shared<Joystick>(id, controller);
|
||||||
_openJoysticks[id] = joystick;
|
_openJoysticks[id] = joystick;
|
||||||
userInputMapper->registerDevice(joystick);
|
userInputMapper->registerDevice(joystick);
|
||||||
|
QString name = SDL_GameControllerName(controller);
|
||||||
emit joystickAdded(joystick.get());
|
emit joystickAdded(joystick.get());
|
||||||
emit subdeviceConnected(getName(), SDL_GameControllerName(controller));
|
emit subdeviceConnected(getName(), name);
|
||||||
|
_subdeviceNames << name;
|
||||||
}
|
}
|
||||||
} else if (event.type == SDL_CONTROLLERDEVICEREMOVED) {
|
} else if (event.type == SDL_CONTROLLERDEVICEREMOVED) {
|
||||||
if (_openJoysticks.contains(event.cdevice.which)) {
|
if (_openJoysticks.contains(event.cdevice.which)) {
|
||||||
Joystick::Pointer joystick = _openJoysticks[event.cdevice.which];
|
Joystick::Pointer joystick = _openJoysticks[event.cdevice.which];
|
||||||
_openJoysticks.remove(event.cdevice.which);
|
_openJoysticks.remove(event.cdevice.which);
|
||||||
userInputMapper->removeDevice(joystick->getDeviceID());
|
userInputMapper->removeDevice(joystick->getDeviceID());
|
||||||
|
QString name = SDL_GameControllerName(joystick->getGameController());
|
||||||
emit joystickRemoved(joystick.get());
|
emit joystickRemoved(joystick.get());
|
||||||
|
_subdeviceNames.removeOne(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ public:
|
||||||
bool isSupported() const override;
|
bool isSupported() const override;
|
||||||
const QString& getName() const override { return NAME; }
|
const QString& getName() const override { return NAME; }
|
||||||
|
|
||||||
|
QStringList getSubdeviceNames() override;
|
||||||
bool isHandController() const override { return false; }
|
bool isHandController() const override { return false; }
|
||||||
|
|
||||||
void init() override;
|
void init() override;
|
||||||
|
@ -79,6 +80,7 @@ private:
|
||||||
QMap<SDL_JoystickID, Joystick::Pointer> _openJoysticks;
|
QMap<SDL_JoystickID, Joystick::Pointer> _openJoysticks;
|
||||||
bool _isInitialized { false } ;
|
bool _isInitialized { false } ;
|
||||||
static const QString NAME;
|
static const QString NAME;
|
||||||
|
QStringList _subdeviceNames;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi__SDL2Manager_h
|
#endif // hifi__SDL2Manager_h
|
||||||
|
|
|
@ -117,6 +117,17 @@ void OculusControllerManager::stopHapticPulse(bool leftHand) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList OculusControllerManager::getSubdeviceNames() {
|
||||||
|
QStringList devices;
|
||||||
|
if (_touch) {
|
||||||
|
devices << _touch->getName();
|
||||||
|
}
|
||||||
|
if (_remote) {
|
||||||
|
devices << _remote->getName();
|
||||||
|
}
|
||||||
|
return devices;
|
||||||
|
}
|
||||||
|
|
||||||
using namespace controller;
|
using namespace controller;
|
||||||
|
|
||||||
static const std::vector<std::pair<ovrButton, StandardButtonChannel>> BUTTON_MAP { {
|
static const std::vector<std::pair<ovrButton, StandardButtonChannel>> BUTTON_MAP { {
|
||||||
|
|
|
@ -27,6 +27,7 @@ public:
|
||||||
const QString& getName() const override { return NAME; }
|
const QString& getName() const override { return NAME; }
|
||||||
|
|
||||||
bool isHandController() const override { return _touch != nullptr; }
|
bool isHandController() const override { return _touch != nullptr; }
|
||||||
|
QStringList getSubdeviceNames() override;
|
||||||
|
|
||||||
bool activate() override;
|
bool activate() override;
|
||||||
void deactivate() override;
|
void deactivate() override;
|
||||||
|
|
|
@ -32,7 +32,8 @@ var DEFAULT_SCRIPTS = [
|
||||||
"system/controllers/toggleAdvancedMovementForHandControllers.js",
|
"system/controllers/toggleAdvancedMovementForHandControllers.js",
|
||||||
"system/dialTone.js",
|
"system/dialTone.js",
|
||||||
"system/firstPersonHMD.js",
|
"system/firstPersonHMD.js",
|
||||||
"system/snapshot.js"
|
"system/snapshot.js",
|
||||||
|
"system/help.js"
|
||||||
];
|
];
|
||||||
|
|
||||||
// add a menu item for debugging
|
// add a menu item for debugging
|
||||||
|
|
110
scripts/system/assets/images/tools/help.svg
Normal file
110
scripts/system/assets/images/tools/help.svg
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 50 200.1" style="enable-background:new 0 0 50 200.1;" xml:space="preserve">
|
||||||
|
<style type="text/css">
|
||||||
|
.st0{fill:#414042;}
|
||||||
|
.st1{fill:#FFFFFF;}
|
||||||
|
.st2{fill:#1E1E1E;}
|
||||||
|
.st3{fill:#333333;}
|
||||||
|
</style>
|
||||||
|
<g id="Layer_2">
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M50.1,146.1c0,2.2-1.8,4-4,4h-42c-2.2,0-4-1.8-4-4v-42c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V146.1z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path class="st0" d="M50,196.1c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4v-42c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V196.1z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<g>
|
||||||
|
<path class="st1" d="M50,46c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4V4c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V46z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="st2" d="M50,96.1c0,2.2-1.8,4-4,4H4c-2.2,0-4-1.8-4-4v-42c0-2.2,1.8-4,4-4h42c2.2,0,4,1.8,4,4V96.1z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g id="Layer_3">
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="st1" d="M20.1,86v6.4h-1.2v-2.7H16v2.7h-1.2V86H16v2.6h2.9V86H20.1z"/>
|
||||||
|
<path class="st1" d="M26.1,91.3v1.1h-4.4V86H26v1.1h-3.1v1.5h2.7v1h-2.7v1.7H26.1z"/>
|
||||||
|
<path class="st1" d="M27.3,92.4V86h1.2v5.3h3.3v1.1H27.3z"/>
|
||||||
|
<path class="st1" d="M32.8,92.4V86h2.7c0.3,0,0.6,0.1,0.8,0.2s0.5,0.3,0.6,0.5c0.2,0.2,0.3,0.4,0.4,0.7c0.1,0.3,0.2,0.5,0.2,0.8
|
||||||
|
c0,0.3,0,0.5-0.1,0.8c-0.1,0.3-0.2,0.5-0.4,0.7c-0.2,0.2-0.4,0.4-0.6,0.5c-0.2,0.1-0.5,0.2-0.8,0.2h-1.5v2.1H32.8z M34.1,89.2h1.4
|
||||||
|
c0.2,0,0.4-0.1,0.6-0.3c0.2-0.2,0.2-0.4,0.2-0.8c0-0.2,0-0.3-0.1-0.4c0-0.1-0.1-0.2-0.2-0.3c-0.1-0.1-0.2-0.2-0.3-0.2
|
||||||
|
c-0.1,0-0.2-0.1-0.3-0.1h-1.4V89.2z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="st1" d="M35.1,60.2c0.2,0,0.4,0.1,0.4,0.3v18.5c0,0.2-0.2,0.3-0.4,0.3H16.6c-0.2,0-0.3-0.2-0.3-0.3V60.5
|
||||||
|
c0-0.2,0.2-0.3,0.3-0.3H35.1 M35.1,58.5H16.6c-1.1,0-2.1,0.9-2.1,2v18.5c0,1.1,0.9,2.1,2.1,2.1h18.5c1.1,0,2.1-0.9,2.1-2.1V60.5
|
||||||
|
C37.2,59.3,36.2,58.5,35.1,58.5L35.1,58.5z"/>
|
||||||
|
<g>
|
||||||
|
<path class="st1" d="M21.6,64c2-0.6,2.9-0.8,4.8-0.8c2.8,0,4.1,0.9,4.1,3.5v0.4c0,1.7-0.6,2.4-1.7,2.8c-0.9,0.3-1.6,0.5-2.6,0.8
|
||||||
|
v1.8h-2l-0.3-3.1c1.2-0.4,2.2-0.7,3-1c0.8-0.3,1.1-0.7,1.1-1.3v-0.4c0-1.3-0.4-1.6-1.8-1.6c-1,0-1.6,0.1-2.4,0.4l-0.2,1.2h-2V64z
|
||||||
|
M23.8,75.3c0-0.9,0.4-1.3,1.4-1.3c1,0,1.4,0.4,1.4,1.3c0,0.9-0.5,1.3-1.4,1.3C24.2,76.6,23.8,76.2,23.8,75.3z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="st3" d="M20.1,36.3v6.4h-1.2V40H16v2.7h-1.2v-6.4H16v2.6h2.9v-2.6H20.1z"/>
|
||||||
|
<path class="st3" d="M26.1,41.6v1.1h-4.4v-6.4H26v1.1h-3.1v1.5h2.7v1h-2.7v1.7H26.1z"/>
|
||||||
|
<path class="st3" d="M27.3,42.7v-6.4h1.2v5.3h3.3v1.1H27.3z"/>
|
||||||
|
<path class="st3" d="M32.8,42.7v-6.4h2.7c0.3,0,0.6,0.1,0.8,0.2s0.5,0.3,0.6,0.5c0.2,0.2,0.3,0.4,0.4,0.7c0.1,0.3,0.2,0.5,0.2,0.8
|
||||||
|
c0,0.3,0,0.5-0.1,0.8c-0.1,0.3-0.2,0.5-0.4,0.7c-0.2,0.2-0.4,0.4-0.6,0.5c-0.2,0.1-0.5,0.2-0.8,0.2h-1.5v2.1H32.8z M34.1,39.5h1.4
|
||||||
|
c0.2,0,0.4-0.1,0.6-0.3c0.2-0.2,0.2-0.4,0.2-0.8c0-0.2,0-0.3-0.1-0.4c0-0.1-0.1-0.2-0.2-0.3c-0.1-0.1-0.2-0.2-0.3-0.2
|
||||||
|
c-0.1,0-0.2-0.1-0.3-0.1h-1.4V39.5z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="st3" d="M35.1,10.5c0.2,0,0.4,0.1,0.4,0.3v18.5c0,0.2-0.2,0.3-0.4,0.3H16.6c-0.2,0-0.3-0.2-0.3-0.3V10.7
|
||||||
|
c0-0.2,0.2-0.3,0.3-0.3H35.1 M35.1,8.7H16.6c-1.1,0-2.1,0.9-2.1,2v18.5c0,1.1,0.9,2.1,2.1,2.1h18.5c1.1,0,2.1-0.9,2.1-2.1V10.7
|
||||||
|
C37.2,9.6,36.2,8.7,35.1,8.7L35.1,8.7z"/>
|
||||||
|
<g>
|
||||||
|
<path class="st3" d="M21.6,14.3c2-0.6,2.9-0.8,4.8-0.8c2.8,0,4.1,0.9,4.1,3.5v0.4c0,1.7-0.6,2.4-1.7,2.8c-0.9,0.3-1.6,0.5-2.6,0.8
|
||||||
|
v1.8h-2l-0.3-3.1c1.2-0.4,2.2-0.7,3-1c0.8-0.3,1.1-0.7,1.1-1.3v-0.4c0-1.3-0.4-1.6-1.8-1.6c-1,0-1.6,0.1-2.4,0.4l-0.2,1.2h-2V14.3
|
||||||
|
z M23.8,25.6c0-0.9,0.4-1.3,1.4-1.3c1,0,1.4,0.4,1.4,1.3c0,0.9-0.5,1.3-1.4,1.3C24.2,26.9,23.8,26.5,23.8,25.6z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="st1" d="M20.1,136v6.4h-1.2v-2.7H16v2.7h-1.2V136H16v2.6h2.9V136H20.1z"/>
|
||||||
|
<path class="st1" d="M26.1,141.3v1.1h-4.4V136H26v1.1h-3.1v1.5h2.7v1h-2.7v1.7H26.1z"/>
|
||||||
|
<path class="st1" d="M27.3,142.4V136h1.2v5.3h3.3v1.1H27.3z"/>
|
||||||
|
<path class="st1" d="M32.8,142.4V136h2.7c0.3,0,0.6,0.1,0.8,0.2s0.5,0.3,0.6,0.5c0.2,0.2,0.3,0.4,0.4,0.7c0.1,0.3,0.2,0.5,0.2,0.8
|
||||||
|
c0,0.3,0,0.5-0.1,0.8c-0.1,0.3-0.2,0.5-0.4,0.7c-0.2,0.2-0.4,0.4-0.6,0.5c-0.2,0.1-0.5,0.2-0.8,0.2h-1.5v2.1H32.8z M34.1,139.2h1.4
|
||||||
|
c0.2,0,0.4-0.1,0.6-0.3c0.2-0.2,0.2-0.4,0.2-0.8c0-0.2,0-0.3-0.1-0.4c0-0.1-0.1-0.2-0.2-0.3c-0.1-0.1-0.2-0.2-0.3-0.2
|
||||||
|
c-0.1,0-0.2-0.1-0.3-0.1h-1.4V139.2z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="st1" d="M36.4,108.9c0.2,0,0.4,0.1,0.4,0.3v21c0,0.2-0.2,0.4-0.4,0.4h-21c-0.2,0-0.4-0.2-0.4-0.4v-21
|
||||||
|
c0-0.2,0.2-0.3,0.4-0.3H36.4 M36.4,106.9h-21c-1.3,0-2.3,1-2.3,2.3v21c0,1.3,1.1,2.3,2.3,2.3h21c1.3,0,2.4-1.1,2.4-2.3v-21
|
||||||
|
C38.8,107.9,37.7,106.9,36.4,106.9L36.4,106.9z"/>
|
||||||
|
<g>
|
||||||
|
<path class="st1" d="M21,113.2c2.3-0.7,3.3-0.9,5.5-0.9c3.2,0,4.6,1.1,4.6,4v0.5c0,2-0.7,2.8-2,3.2c-1,0.4-1.9,0.6-2.9,0.9v2H24
|
||||||
|
l-0.3-3.5c1.4-0.4,2.5-0.8,3.4-1.1c1-0.4,1.3-0.8,1.3-1.5v-0.5c0-1.5-0.4-1.8-2.1-1.8c-1.1,0-1.9,0.1-2.7,0.5l-0.2,1.4H21V113.2z
|
||||||
|
M23.5,126.1c0-1,0.5-1.5,1.6-1.5c1.1,0,1.6,0.5,1.6,1.5c0,1-0.6,1.5-1.6,1.5C24,127.6,23.5,127.1,23.5,126.1z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="st1" d="M20.1,186.1v6.4h-1.2v-2.7H16v2.7h-1.2v-6.4H16v2.6h2.9v-2.6H20.1z"/>
|
||||||
|
<path class="st1" d="M26.1,191.4v1.1h-4.4v-6.4H26v1.1h-3.1v1.5h2.7v1h-2.7v1.7H26.1z"/>
|
||||||
|
<path class="st1" d="M27.3,192.5v-6.4h1.2v5.3h3.3v1.1H27.3z"/>
|
||||||
|
<path class="st1" d="M32.8,192.5v-6.4h2.7c0.3,0,0.6,0.1,0.8,0.2s0.5,0.3,0.6,0.5c0.2,0.2,0.3,0.4,0.4,0.7c0.1,0.3,0.2,0.5,0.2,0.8
|
||||||
|
c0,0.3,0,0.5-0.1,0.8c-0.1,0.3-0.2,0.5-0.4,0.7c-0.2,0.2-0.4,0.4-0.6,0.5c-0.2,0.1-0.5,0.2-0.8,0.2h-1.5v2.1H32.8z M34.1,189.2h1.4
|
||||||
|
c0.2,0,0.4-0.1,0.6-0.3c0.2-0.2,0.2-0.4,0.2-0.8c0-0.2,0-0.3-0.1-0.4c0-0.1-0.1-0.2-0.2-0.3c-0.1-0.1-0.2-0.2-0.3-0.2
|
||||||
|
c-0.1,0-0.2-0.1-0.3-0.1h-1.4V189.2z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
<path class="st1" d="M35.1,160.3c0.2,0,0.4,0.1,0.4,0.3V179c0,0.2-0.2,0.3-0.4,0.3H16.6c-0.2,0-0.3-0.2-0.3-0.3v-18.5
|
||||||
|
c0-0.2,0.2-0.3,0.3-0.3H35.1 M35.1,158.5H16.6c-1.1,0-2.1,0.9-2.1,2V179c0,1.1,0.9,2.1,2.1,2.1h18.5c1.1,0,2.1-0.9,2.1-2.1v-18.5
|
||||||
|
C37.2,159.4,36.2,158.5,35.1,158.5L35.1,158.5z"/>
|
||||||
|
<g>
|
||||||
|
<path class="st1" d="M21.6,164.1c2-0.6,2.9-0.8,4.8-0.8c2.8,0,4.1,0.9,4.1,3.5v0.4c0,1.7-0.6,2.4-1.7,2.8
|
||||||
|
c-0.9,0.3-1.6,0.5-2.6,0.8v1.8h-2l-0.3-3.1c1.2-0.4,2.2-0.7,3-1c0.8-0.3,1.1-0.7,1.1-1.3v-0.4c0-1.3-0.4-1.6-1.8-1.6
|
||||||
|
c-1,0-1.6,0.1-2.4,0.4l-0.2,1.2h-2V164.1z M23.8,175.3c0-0.9,0.4-1.3,1.4-1.3c1,0,1.4,0.4,1.4,1.3c0,0.9-0.5,1.3-1.4,1.3
|
||||||
|
C24.2,176.7,23.8,176.2,23.8,175.3z"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 6.3 KiB |
41
scripts/system/help.js
Normal file
41
scripts/system/help.js
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
//
|
||||||
|
// help.js
|
||||||
|
// scripts/system/
|
||||||
|
//
|
||||||
|
// Created by Howard Stearns on 2 Nov 2016
|
||||||
|
// Copyright 2016 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
|
||||||
|
//
|
||||||
|
|
||||||
|
(function() { // BEGIN LOCAL_SCOPE
|
||||||
|
|
||||||
|
var toolBar = Toolbars.getToolbar("com.highfidelity.interface.toolbar.system");
|
||||||
|
var buttonName = "help"; // matching location reserved in Desktop.qml
|
||||||
|
var button = toolBar.addButton({
|
||||||
|
objectName: buttonName,
|
||||||
|
imageURL: Script.resolvePath("assets/images/tools/help.svg"),
|
||||||
|
visible: true,
|
||||||
|
hoverState: 2,
|
||||||
|
defaultState: 1,
|
||||||
|
buttonState: 1,
|
||||||
|
alpha: 0.9
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: make button state reflect whether the window is opened or closed (independently from us).
|
||||||
|
|
||||||
|
function onClicked(){
|
||||||
|
Menu.triggerOption('Help...')
|
||||||
|
}
|
||||||
|
|
||||||
|
button.clicked.connect(onClicked);
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(function () {
|
||||||
|
toolBar.removeButton(buttonName);
|
||||||
|
button.clicked.disconnect(onClicked);
|
||||||
|
});
|
||||||
|
|
||||||
|
}()); // END LOCAL_SCOPE
|
|
@ -1492,7 +1492,7 @@ function loaded() {
|
||||||
var lis = dropdown.parentNode.getElementsByTagName("li");
|
var lis = dropdown.parentNode.getElementsByTagName("li");
|
||||||
var text = "";
|
var text = "";
|
||||||
for (var i = 0; i < lis.length; i++) {
|
for (var i = 0; i < lis.length; i++) {
|
||||||
if (lis[i].getAttribute("value") === dropdown.value) {
|
if (String(lis[i].getAttribute("value")) === String(dropdown.value)) {
|
||||||
text = lis[i].textContent;
|
text = lis[i].textContent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -248,7 +248,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function update() {
|
function update() {
|
||||||
var viewport, diff, x;
|
var viewport, diff, x, gpuTextures;
|
||||||
|
|
||||||
initialDelayCooldown -= 30;
|
initialDelayCooldown -= 30;
|
||||||
|
|
||||||
|
@ -261,26 +261,28 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gpuTextures = Render.getConfig("Stats").textureGPUTransferCount;
|
||||||
|
|
||||||
// Update state
|
// Update state
|
||||||
if (!visible) { // Not visible because no recent downloads
|
if (!visible) { // Not visible because no recent downloads
|
||||||
if (displayProgress < 100) { // Have started downloading so fade in
|
if (displayProgress < 100 || gpuTextures > 0) { // Have started downloading so fade in
|
||||||
visible = true;
|
visible = true;
|
||||||
alphaDelta = ALPHA_DELTA_IN;
|
alphaDelta = ALPHA_DELTA_IN;
|
||||||
fadeTimer = Script.setInterval(fade, FADE_INTERVAL);
|
fadeTimer = Script.setInterval(fade, FADE_INTERVAL);
|
||||||
}
|
}
|
||||||
} else if (alphaDelta !== 0.0) { // Fading in or out
|
} else if (alphaDelta !== 0.0) { // Fading in or out
|
||||||
if (alphaDelta > 0) {
|
if (alphaDelta > 0) {
|
||||||
if (rawProgress === 100) { // Was downloading but now have finished so fade out
|
if (rawProgress === 100 && gpuTextures === 0) { // Was downloading but now have finished so fade out
|
||||||
alphaDelta = ALPHA_DELTA_OUT;
|
alphaDelta = ALPHA_DELTA_OUT;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (displayProgress < 100) { // Was finished downloading but have resumed so fade in
|
if (displayProgress < 100 || gpuTextures > 0) { // Was finished downloading but have resumed so fade in
|
||||||
alphaDelta = ALPHA_DELTA_IN;
|
alphaDelta = ALPHA_DELTA_IN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // Fully visible because downloading or recently so
|
} else { // Fully visible because downloading or recently so
|
||||||
if (fadeWaitTimer === null) {
|
if (fadeWaitTimer === null) {
|
||||||
if (rawProgress === 100) { // Was downloading but have finished so fade out soon
|
if (rawProgress === 100 && gpuTextures === 0) { // Was downloading but have finished so fade out soon
|
||||||
fadeWaitTimer = Script.setTimeout(function () {
|
fadeWaitTimer = Script.setTimeout(function () {
|
||||||
alphaDelta = ALPHA_DELTA_OUT;
|
alphaDelta = ALPHA_DELTA_OUT;
|
||||||
fadeTimer = Script.setInterval(fade, FADE_INTERVAL);
|
fadeTimer = Script.setInterval(fade, FADE_INTERVAL);
|
||||||
|
@ -288,7 +290,8 @@
|
||||||
}, FADE_OUT_WAIT);
|
}, FADE_OUT_WAIT);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (displayProgress < 100) { // Was finished and waiting to fade out but have resumed so don't fade out
|
if (displayProgress < 100 || gpuTextures > 0) { // Was finished and waiting to fade out but have resumed so
|
||||||
|
// don't fade out
|
||||||
Script.clearInterval(fadeWaitTimer);
|
Script.clearInterval(fadeWaitTimer);
|
||||||
fadeWaitTimer = null;
|
fadeWaitTimer = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ if (osType == "Darwin") {
|
||||||
} else if (osType == "Windows_NT") {
|
} else if (osType == "Windows_NT") {
|
||||||
options["version-string"] = {
|
options["version-string"] = {
|
||||||
CompanyName: "High Fidelity, Inc.",
|
CompanyName: "High Fidelity, Inc.",
|
||||||
FileDescription: SHORT_NAME,
|
FileDescription: FULL_NAME,
|
||||||
ProductName: FULL_NAME,
|
ProductName: FULL_NAME,
|
||||||
OriginalFilename: EXEC_NAME + ".exe"
|
OriginalFilename: EXEC_NAME + ".exe"
|
||||||
}
|
}
|
||||||
|
|
44
tools/atp-extract.py
Normal file
44
tools/atp-extract.py
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#
|
||||||
|
# Tool to extract atp files from the asset server cache.
|
||||||
|
# Usage: python2 atp-extract.py -[lxa] [filename]
|
||||||
|
#
|
||||||
|
# cd into the c:\Users\BettySpaghetti\AppData\Roaming\High Fidelity\assignment-client\assets dir
|
||||||
|
# run 'python2 atp-extract.py -l' to list all files
|
||||||
|
# run 'python2 atp-extract.py -x file' to extract that particular file to the current directory.
|
||||||
|
# run 'python2 atp-extract.py -a' to extract all files.
|
||||||
|
#
|
||||||
|
|
||||||
|
import os, json, sys, shutil
|
||||||
|
|
||||||
|
def loadMapFile(filename):
|
||||||
|
with open(filename, 'r') as f:
|
||||||
|
return json.load(f)
|
||||||
|
|
||||||
|
def extractFile(assetMap, filename):
|
||||||
|
if filename != None:
|
||||||
|
assetFilename = assetMap.get("/" + filename)
|
||||||
|
if assetFilename != None:
|
||||||
|
dir = os.path.dirname(filename)
|
||||||
|
if dir != "" and not os.path.exists(dir):
|
||||||
|
os.makedirs(dir)
|
||||||
|
shutil.copy("files/" + assetFilename, filename)
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
option = sys.argv[1]
|
||||||
|
if option == '-l':
|
||||||
|
assetMap = loadMapFile("map.json")
|
||||||
|
for key, value in assetMap.iteritems():
|
||||||
|
print key[1:]
|
||||||
|
elif option == '-x':
|
||||||
|
assetMap = loadMapFile("map.json")
|
||||||
|
outputFilename = sys.argv[2]
|
||||||
|
if not extractFile(assetMap, outputFilename):
|
||||||
|
print("Error could not extract file: \"" + outputFilename + "\"")
|
||||||
|
elif option == '-a':
|
||||||
|
assetMap = loadMapFile("map.json")
|
||||||
|
for key, value in assetMap.iteritems():
|
||||||
|
print("Extracting " + key[1:])
|
||||||
|
extractFile(assetMap, key[1:])
|
||||||
|
else:
|
||||||
|
print("unsuported option \"" + option + "\"")
|
|
@ -715,7 +715,8 @@ var stepTurnAround = function(name) {
|
||||||
this.tempTag = name + "-temporary";
|
this.tempTag = name + "-temporary";
|
||||||
|
|
||||||
this.onActionBound = this.onAction.bind(this);
|
this.onActionBound = this.onAction.bind(this);
|
||||||
this.numTimesTurnPressed = 0;
|
this.numTimesSnapTurnPressed = 0;
|
||||||
|
this.numTimesSmoothTurnPressed = 0;
|
||||||
}
|
}
|
||||||
stepTurnAround.prototype = {
|
stepTurnAround.prototype = {
|
||||||
start: function(onFinish) {
|
start: function(onFinish) {
|
||||||
|
@ -724,19 +725,26 @@ stepTurnAround.prototype = {
|
||||||
|
|
||||||
showEntitiesWithTag(this.tag);
|
showEntitiesWithTag(this.tag);
|
||||||
|
|
||||||
this.numTimesTurnPressed = 0;
|
this.numTimesSnapTurnPressed = 0;
|
||||||
|
this.numTimesSmoothTurnPressed = 0;
|
||||||
|
this.smoothTurnDown = false;
|
||||||
Controller.actionEvent.connect(this.onActionBound);
|
Controller.actionEvent.connect(this.onActionBound);
|
||||||
|
|
||||||
this.interval = Script.setInterval(function() {
|
this.interval = Script.setInterval(function() {
|
||||||
debug("TurnAround | Checking if finished", this.numTimesTurnPressed);
|
debug("TurnAround | Checking if finished",
|
||||||
|
this.numTimesSnapTurnPressed, this.numTimesSmoothTurnPressed);
|
||||||
var FORWARD_THRESHOLD = 90;
|
var FORWARD_THRESHOLD = 90;
|
||||||
var REQ_NUM_TIMES_PRESSED = 3;
|
var REQ_NUM_TIMES_SNAP_TURN_PRESSED = 3;
|
||||||
|
var REQ_NUM_TIMES_SMOOTH_TURN_PRESSED = 2;
|
||||||
|
|
||||||
var dir = Quat.getFront(MyAvatar.orientation);
|
var dir = Quat.getFront(MyAvatar.orientation);
|
||||||
var angle = Math.atan2(dir.z, dir.x);
|
var angle = Math.atan2(dir.z, dir.x);
|
||||||
var angleDegrees = ((angle / Math.PI) * 180);
|
var angleDegrees = ((angle / Math.PI) * 180);
|
||||||
|
|
||||||
if (this.numTimesTurnPressed >= REQ_NUM_TIMES_PRESSED && Math.abs(angleDegrees) < FORWARD_THRESHOLD) {
|
var hasTurnedEnough = this.numTimesSnapTurnPressed >= REQ_NUM_TIMES_SNAP_TURN_PRESSED
|
||||||
|
|| this.numTimesSmoothTurnPressed >= REQ_NUM_TIMES_SMOOTH_TURN_PRESSED;
|
||||||
|
var facingForward = Math.abs(angleDegrees) < FORWARD_THRESHOLD
|
||||||
|
if (hasTurnedEnough && facingForward) {
|
||||||
Script.clearInterval(this.interval);
|
Script.clearInterval(this.interval);
|
||||||
this.interval = null;
|
this.interval = null;
|
||||||
playSuccessSound();
|
playSuccessSound();
|
||||||
|
@ -746,9 +754,19 @@ stepTurnAround.prototype = {
|
||||||
},
|
},
|
||||||
onAction: function(action, value) {
|
onAction: function(action, value) {
|
||||||
var STEP_YAW_ACTION = 6;
|
var STEP_YAW_ACTION = 6;
|
||||||
|
var SMOOTH_YAW_ACTION = 4;
|
||||||
|
|
||||||
if (action == STEP_YAW_ACTION && value != 0) {
|
if (action == STEP_YAW_ACTION && value != 0) {
|
||||||
debug("TurnAround | Got yaw action");
|
debug("TurnAround | Got step yaw action");
|
||||||
this.numTimesTurnPressed += 1;
|
++this.numTimesSnapTurnPressed;
|
||||||
|
} else if (action == SMOOTH_YAW_ACTION) {
|
||||||
|
debug("TurnAround | Got smooth yaw action");
|
||||||
|
if (this.smoothTurnDown && value === 0) {
|
||||||
|
this.smoothTurnDown = false;
|
||||||
|
++this.numTimesSmoothTurnPressed;
|
||||||
|
} else if (!this.smoothTurnDown && value !== 0) {
|
||||||
|
this.smoothTurnDown = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
cleanup: function() {
|
cleanup: function() {
|
||||||
|
|
Loading…
Reference in a new issue