mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 17:14:59 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into xboxLasers
Conflicts: libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h
This commit is contained in:
commit
1a28732b64
82 changed files with 1207 additions and 452 deletions
|
@ -453,7 +453,7 @@ bool AssetServer::loadMappingsFromFile() {
|
|||
while (it != _fileMappings.end()) {
|
||||
bool shouldDrop = false;
|
||||
|
||||
if (!isValidPath(it.key())) {
|
||||
if (!isValidFilePath(it.key())) {
|
||||
qWarning() << "Will not keep mapping for" << it.key() << "since it is not a valid path.";
|
||||
shouldDrop = true;
|
||||
}
|
||||
|
@ -508,7 +508,7 @@ bool AssetServer::writeMappingsToFile() {
|
|||
bool AssetServer::setMapping(AssetPath path, AssetHash hash) {
|
||||
path = path.trimmed();
|
||||
|
||||
if (!isValidPath(path)) {
|
||||
if (!isValidFilePath(path)) {
|
||||
qWarning() << "Cannot set a mapping for invalid path:" << path << "=>" << hash;
|
||||
return false;
|
||||
}
|
||||
|
@ -637,8 +637,8 @@ bool AssetServer::renameMapping(AssetPath oldPath, AssetPath newPath) {
|
|||
oldPath = oldPath.trimmed();
|
||||
newPath = newPath.trimmed();
|
||||
|
||||
if (!isValidPath(oldPath) || !isValidPath(newPath)) {
|
||||
qWarning() << "Cannot perform rename with invalid paths - both should have leading forward slashes:"
|
||||
if (!isValidFilePath(oldPath) || !isValidFilePath(newPath)) {
|
||||
qWarning() << "Cannot perform rename with invalid paths - both should have leading forward and no ending slashes:"
|
||||
<< oldPath << "=>" << newPath;
|
||||
|
||||
return false;
|
||||
|
|
|
@ -863,15 +863,6 @@
|
|||
"help": "The path to the directory assets are stored in.<br/>If this path is relative, it will be relative to the application data directory.<br/>If you change this path you will need to manually copy any existing assets from the previous directory.",
|
||||
"default": "",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "max_bandwidth",
|
||||
"type": "double",
|
||||
"label": "Max Bandwidth Per User",
|
||||
"help": "The maximum upstream bandwidth each user can use (in Mb/s).",
|
||||
"placeholder": "10.0",
|
||||
"default": "",
|
||||
"advanced": true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -41,8 +41,10 @@ endif ()
|
|||
|
||||
if (ANDROID)
|
||||
set(PLATFORM_QT_COMPONENTS AndroidExtras)
|
||||
set(PLATFORM_QT_LIBRARIES Qt5::AndroidExtras)
|
||||
else ()
|
||||
set(PLATFORM_QT_COMPONENTS WebEngine WebEngineWidgets)
|
||||
set(PLATFORM_QT_LIBRARIES Qt5::WebEngine Qt5::WebEngineWidgets)
|
||||
endif ()
|
||||
|
||||
find_package(
|
||||
|
@ -244,7 +246,8 @@ target_link_libraries(
|
|||
${TARGET_NAME}
|
||||
Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL
|
||||
Qt5::Qml Qt5::Quick Qt5::Script Qt5::Svg
|
||||
Qt5::WebChannel Qt5::WebEngine
|
||||
Qt5::WebChannel Qt5::WebEngine
|
||||
${PLATFORM_QT_LIBRARIES}
|
||||
)
|
||||
|
||||
if (UNIX)
|
||||
|
|
|
@ -21,6 +21,7 @@ import "controls-uit" as HifiControls
|
|||
Window {
|
||||
id: root
|
||||
HifiConstants { id: hifi }
|
||||
HifiStyles.HifiConstants { id: hifiStyleConstants }
|
||||
|
||||
objectName: "AddressBarDialog"
|
||||
title: "Go To"
|
||||
|
@ -29,7 +30,6 @@ Window {
|
|||
destroyOnHidden: false
|
||||
resizable: false
|
||||
pinnable: false;
|
||||
scale: 1.25 // Make this dialog a little larger than normal
|
||||
|
||||
width: addressBarDialog.implicitWidth
|
||||
height: addressBarDialog.implicitHeight
|
||||
|
@ -78,8 +78,7 @@ Window {
|
|||
property bool punctuationMode: false
|
||||
|
||||
implicitWidth: backgroundImage.width
|
||||
implicitHeight: backgroundImage.height + (keyboardEnabled ? keyboard.raisedHeight + 2 * hifi.layout.spacing : 0)
|
||||
+ cardHeight - 36 // Fudge to reduce bottom margin.
|
||||
implicitHeight: backgroundImage.height + (keyboardEnabled ? keyboard.height : 0) + cardHeight;
|
||||
|
||||
// The buttons have their button state changed on hover, so we have to manually fix them up here
|
||||
onBackEnabledChanged: backArrow.buttonState = addressBarDialog.backEnabled ? 1 : 0;
|
||||
|
@ -98,7 +97,7 @@ Window {
|
|||
spacing: hifi.layout.spacing;
|
||||
clip: true;
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: backgroundImage.top
|
||||
horizontalCenter: backgroundImage.horizontalCenter
|
||||
}
|
||||
model: suggestions;
|
||||
|
@ -133,16 +132,16 @@ Window {
|
|||
verticalCenter: scroll.verticalCenter;
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: backgroundImage
|
||||
source: "../images/address-bar.svg"
|
||||
width: 576 * root.scale
|
||||
height: 80 * root.scale
|
||||
width: 720
|
||||
height: 100
|
||||
anchors {
|
||||
top: scroll.bottom
|
||||
bottom: parent.keyboardEnabled ? keyboard.top : parent.bottom;
|
||||
}
|
||||
|
||||
property int inputAreaHeight: 56.0 * root.scale // Height of the background's input area
|
||||
property int inputAreaHeight: 70
|
||||
property int inputAreaStep: (height - inputAreaHeight) / 2
|
||||
|
||||
ToolbarButton {
|
||||
|
@ -189,7 +188,7 @@ Window {
|
|||
|
||||
HifiStyles.RalewayLight {
|
||||
id: notice;
|
||||
font.pixelSize: hifi.fonts.pixelSize * root.scale * 0.50;
|
||||
font.pixelSize: hifi.fonts.pixelSize * 0.50;
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: parent.inputAreaStep + 12
|
||||
|
@ -218,7 +217,7 @@ Window {
|
|||
topMargin: parent.inputAreaStep + (2 * hifi.layout.spacing)
|
||||
bottomMargin: parent.inputAreaStep
|
||||
}
|
||||
font.pixelSize: hifi.fonts.pixelSize * root.scale * 0.75
|
||||
font.pixelSize: hifi.fonts.pixelSize * 0.75
|
||||
cursorVisible: false
|
||||
onTextChanged: {
|
||||
filterChoicesByText();
|
||||
|
@ -267,7 +266,6 @@ Window {
|
|||
Window {
|
||||
width: 938
|
||||
height: 625
|
||||
scale: 0.8 // Reset scale of Window to 1.0 (counteract address bar's scale value of 1.25)
|
||||
HifiControls.WebView {
|
||||
anchors.fill: parent;
|
||||
id: storyCardHTML;
|
||||
|
@ -282,6 +280,7 @@ Window {
|
|||
verticalCenter: backgroundImage.verticalCenter;
|
||||
horizontalCenter: scroll.horizontalCenter;
|
||||
}
|
||||
z: 100
|
||||
}
|
||||
|
||||
HifiControls.Keyboard {
|
||||
|
@ -289,7 +288,7 @@ Window {
|
|||
raised: parent.keyboardEnabled // Ignore keyboardRaised; keep keyboard raised if enabled (i.e., in HMD).
|
||||
numeric: parent.punctuationMode
|
||||
anchors {
|
||||
top: backgroundImage.bottom
|
||||
bottom: parent.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
|
@ -432,10 +431,10 @@ Window {
|
|||
function updateLocationText(enteringAddress) {
|
||||
if (enteringAddress) {
|
||||
notice.text = "Go to a place, @user, path or network address";
|
||||
notice.color = "gray";
|
||||
notice.color = hifiStyleConstants.colors.baseGrayHighlight;
|
||||
} else {
|
||||
notice.text = AddressManager.isConnected ? "Your location:" : "Not Connected";
|
||||
notice.color = AddressManager.isConnected ? "gray" : "crimson";
|
||||
notice.color = AddressManager.isConnected ? hifiStyleConstants.colors.baseGrayHighlight : hifiStyleConstants.colors.redHighlight;
|
||||
// Display hostname, which includes ip address, localhost, and other non-placenames.
|
||||
location.text = (AddressManager.hostname || '') + (AddressManager.pathname ? AddressManager.pathname.match(/\/[^\/]+/)[0] : '');
|
||||
}
|
||||
|
|
|
@ -349,7 +349,7 @@ ScrollingWindow {
|
|||
},
|
||||
function(err, path) {
|
||||
print(err, path);
|
||||
if (!err) {
|
||||
if (err === "") {
|
||||
uploadProgressLabel.text = "Upload Complete";
|
||||
timer.interval = 1000;
|
||||
timer.repeat = false;
|
||||
|
@ -362,14 +362,15 @@ ScrollingWindow {
|
|||
console.log("Asset Browser - finished uploading: ", fileUrl);
|
||||
reload();
|
||||
} else {
|
||||
if (err > 0) {
|
||||
console.log("Asset Browser - error uploading: ", fileUrl, " - error ", err);
|
||||
var box = errorMessageBox("There was an error uploading:\n" + fileUrl + "\n" + Assets.getErrorString(err));
|
||||
box.selected.connect(reload);
|
||||
}
|
||||
uploadSpinner.visible = false;
|
||||
uploadButton.enabled = true;
|
||||
uploadOpen = false;
|
||||
|
||||
if (err !== -1) {
|
||||
console.log("Asset Browser - error uploading: ", fileUrl, " - error ", err);
|
||||
var box = errorMessageBox("There was an error uploading:\n" + fileUrl + "\n" + err);
|
||||
box.selected.connect(reload);
|
||||
}
|
||||
}
|
||||
}, dropping);
|
||||
}
|
||||
|
|
|
@ -29,8 +29,9 @@ Item {
|
|||
readonly property int maxHeight: 720
|
||||
|
||||
function resize() {
|
||||
var targetWidth = Math.max(titleWidth, additionalTextContainer.contentWidth)
|
||||
var targetHeight = 4 * hifi.dimensions.contentSpacing.y + buttons.height + additionalTextContainer.height
|
||||
var targetWidth = Math.max(titleWidth, Math.max(additionalTextContainer.contentWidth,
|
||||
termsContainer.contentWidth))
|
||||
var targetHeight = 5 * hifi.dimensions.contentSpacing.y + buttons.height + additionalTextContainer.height + termsContainer.height
|
||||
|
||||
root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth))
|
||||
root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
|
||||
|
@ -43,7 +44,7 @@ Item {
|
|||
top: parent.top
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
margins: 0
|
||||
topMargin: 3 * hifi.dimensions.contentSpacing.y
|
||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
|
@ -91,6 +92,25 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
InfoItem {
|
||||
id: termsContainer
|
||||
anchors {
|
||||
top: additionalTextContainer.bottom
|
||||
left: parent.left
|
||||
margins: 0
|
||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
|
||||
text: qsTr("By creating this user profile, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
|
||||
wrapMode: Text.WordWrap
|
||||
color: hifi.colors.baseGrayHighlight
|
||||
lineHeight: 1
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
onLinkActivated: loginDialog.openUrl(link)
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
root.title = qsTr("Complete Your Profile")
|
||||
root.iconText = "<"
|
||||
|
|
|
@ -42,8 +42,14 @@ Item {
|
|||
|
||||
function resize() {
|
||||
var targetWidth = Math.max(titleWidth, form.contentWidth);
|
||||
var targetHeight = hifi.dimensions.contentSpacing.y + mainTextContainer.height
|
||||
+ 4 * hifi.dimensions.contentSpacing.y + form.height + hifi.dimensions.contentSpacing.y + buttons.height;
|
||||
var targetHeight = hifi.dimensions.contentSpacing.y + mainTextContainer.height +
|
||||
4 * hifi.dimensions.contentSpacing.y + form.height +
|
||||
hifi.dimensions.contentSpacing.y + buttons.height;
|
||||
|
||||
if (additionalInformation.visible) {
|
||||
targetWidth = Math.max(targetWidth, additionalInformation.width);
|
||||
targetHeight += hifi.dimensions.contentSpacing.y + additionalInformation.height
|
||||
}
|
||||
|
||||
root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth));
|
||||
root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
|
||||
|
@ -136,6 +142,25 @@ Item {
|
|||
|
||||
}
|
||||
|
||||
InfoItem {
|
||||
id: additionalInformation
|
||||
anchors {
|
||||
top: form.bottom
|
||||
left: parent.left
|
||||
margins: 0
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
|
||||
visible: loginDialog.isSteamRunning()
|
||||
|
||||
text: qsTr("Your steam account informations will not be exposed to other users.")
|
||||
wrapMode: Text.WordWrap
|
||||
color: hifi.colors.baseGrayHighlight
|
||||
lineHeight: 1
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
// Override ScrollingWindow's keyboard that would be at very bottom of dialog.
|
||||
Keyboard {
|
||||
raised: keyboardEnabled && keyboardRaised
|
||||
|
|
|
@ -27,6 +27,13 @@ Item {
|
|||
loginDialog.createAccountFromStream(textField.text)
|
||||
}
|
||||
|
||||
|
||||
property bool keyboardEnabled: false
|
||||
property bool keyboardRaised: false
|
||||
property bool punctuationMode: false
|
||||
|
||||
onKeyboardRaisedChanged: d.resize();
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
readonly property int minWidth: 480
|
||||
|
@ -35,15 +42,16 @@ Item {
|
|||
readonly property int maxHeight: 720
|
||||
|
||||
function resize() {
|
||||
var targetWidth = Math.max(titleWidth, Math.max(mainTextContainer.contentWidth,
|
||||
termsContainer.contentWidth))
|
||||
var targetWidth = Math.max(titleWidth, mainTextContainer.contentWidth)
|
||||
var targetHeight = mainTextContainer.height +
|
||||
2 * hifi.dimensions.contentSpacing.y + textField.height +
|
||||
5 * hifi.dimensions.contentSpacing.y + termsContainer.height +
|
||||
1 * hifi.dimensions.contentSpacing.y + buttons.height
|
||||
hifi.dimensions.contentSpacing.y + textField.height +
|
||||
hifi.dimensions.contentSpacing.y + buttons.height
|
||||
|
||||
root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth))
|
||||
root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
|
||||
+ (keyboardEnabled && keyboardRaised ? (200 + 2 * hifi.dimensions.contentSpacing.y) : hifi.dimensions.contentSpacing.y)
|
||||
|
||||
height = root.height
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,39 +79,32 @@ Item {
|
|||
top: mainTextContainer.bottom
|
||||
left: parent.left
|
||||
margins: 0
|
||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
width: 250
|
||||
|
||||
placeholderText: "Choose your own"
|
||||
}
|
||||
|
||||
InfoItem {
|
||||
id: termsContainer
|
||||
// Override ScrollingWindow's keyboard that would be at very bottom of dialog.
|
||||
Keyboard {
|
||||
raised: keyboardEnabled && keyboardRaised
|
||||
numeric: punctuationMode
|
||||
anchors {
|
||||
top: textField.bottom
|
||||
left: parent.left
|
||||
margins: 0
|
||||
topMargin: 3 * hifi.dimensions.contentSpacing.y
|
||||
right: parent.right
|
||||
bottom: buttons.top
|
||||
bottomMargin: keyboardRaised ? 2 * hifi.dimensions.contentSpacing.y : 0
|
||||
}
|
||||
|
||||
text: qsTr("By creating this user profile, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
|
||||
wrapMode: Text.WordWrap
|
||||
color: hifi.colors.baseGrayHighlight
|
||||
lineHeight: 1
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
||||
onLinkActivated: loginDialog.openUrl(link)
|
||||
}
|
||||
|
||||
Row {
|
||||
id: buttons
|
||||
anchors {
|
||||
top: termsContainer.bottom
|
||||
bottom: parent.bottom
|
||||
right: parent.right
|
||||
margins: 0
|
||||
topMargin: 1 * hifi.dimensions.contentSpacing.y
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
|
@ -130,8 +131,10 @@ Item {
|
|||
Component.onCompleted: {
|
||||
root.title = qsTr("Complete Your Profile")
|
||||
root.iconText = "<"
|
||||
keyboardEnabled = HMD.active;
|
||||
d.resize();
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: loginDialog
|
||||
onHandleCreateCompleted: {
|
||||
|
|
|
@ -10,10 +10,10 @@
|
|||
|
||||
import QtQuick 2.5
|
||||
import QtWebEngine 1.2
|
||||
import HFWebEngineProfile 1.0
|
||||
|
||||
WebEngineView {
|
||||
id: root
|
||||
property var newUrl;
|
||||
|
||||
profile: desktop.browserProfile
|
||||
|
||||
|
@ -25,28 +25,6 @@ WebEngineView {
|
|||
});
|
||||
}
|
||||
|
||||
// FIXME hack to get the URL with the auth token included. Remove when we move to Qt 5.6
|
||||
Timer {
|
||||
id: urlReplacementTimer
|
||||
running: false
|
||||
repeat: false
|
||||
interval: 50
|
||||
onTriggered: url = newUrl;
|
||||
}
|
||||
|
||||
onUrlChanged: {
|
||||
var originalUrl = url.toString();
|
||||
newUrl = urlHandler.fixupUrl(originalUrl).toString();
|
||||
if (newUrl !== originalUrl) {
|
||||
root.stop();
|
||||
if (urlReplacementTimer.running) {
|
||||
console.warn("Replacement timer already running");
|
||||
return;
|
||||
}
|
||||
urlReplacementTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
onLoadingChanged: {
|
||||
// Required to support clicking on "hifi://" links
|
||||
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
|
||||
|
|
|
@ -2,6 +2,7 @@ import QtQuick 2.5
|
|||
import QtWebEngine 1.1
|
||||
import QtWebChannel 1.0
|
||||
import "../controls-uit" as HiFiControls
|
||||
import HFWebEngineProfile 1.0
|
||||
|
||||
Item {
|
||||
property alias url: root.url
|
||||
|
@ -31,6 +32,11 @@ Item {
|
|||
width: parent.width
|
||||
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height
|
||||
|
||||
profile: HFWebEngineProfile {
|
||||
id: webviewProfile
|
||||
storageName: "qmlWebEngine"
|
||||
}
|
||||
|
||||
// creates a global EventBridge object.
|
||||
WebEngineScript {
|
||||
id: createGlobalEventBridge
|
||||
|
@ -62,28 +68,6 @@ Item {
|
|||
root.profile.httpUserAgent = "Mozilla/5.0 Chrome (HighFidelityInterface)";
|
||||
}
|
||||
|
||||
// FIXME hack to get the URL with the auth token included. Remove when we move to Qt 5.6
|
||||
Timer {
|
||||
id: urlReplacementTimer
|
||||
running: false
|
||||
repeat: false
|
||||
interval: 50
|
||||
onTriggered: url = root.newUrl;
|
||||
}
|
||||
|
||||
onUrlChanged: {
|
||||
var originalUrl = url.toString();
|
||||
root.newUrl = urlHandler.fixupUrl(originalUrl).toString();
|
||||
if (root.newUrl !== originalUrl) {
|
||||
root.stop();
|
||||
if (urlReplacementTimer.running) {
|
||||
console.warn("Replacement timer already running");
|
||||
return;
|
||||
}
|
||||
urlReplacementTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
onFeaturePermissionRequested: {
|
||||
grantFeaturePermission(securityOrigin, feature, true);
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ FocusScope {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
onHeightChanged: d.handleSizeChanged();
|
||||
|
||||
onWidthChanged: d.handleSizeChanged();
|
||||
|
|
|
@ -2,6 +2,7 @@ import QtQuick 2.5
|
|||
import QtQuick.Controls 1.4
|
||||
import QtWebEngine 1.1;
|
||||
import Qt.labs.settings 1.0
|
||||
import HFWebEngineProfile 1.0
|
||||
|
||||
import "../desktop" as OriginalDesktop
|
||||
import ".."
|
||||
|
@ -20,17 +21,14 @@ OriginalDesktop.Desktop {
|
|||
onEntered: ApplicationCompositor.reticleOverDesktop = true
|
||||
onExited: ApplicationCompositor.reticleOverDesktop = false
|
||||
acceptedButtons: Qt.NoButton
|
||||
|
||||
|
||||
}
|
||||
|
||||
// The tool window, one instance
|
||||
property alias toolWindow: toolWindow
|
||||
ToolWindow { id: toolWindow }
|
||||
|
||||
property var browserProfile: WebEngineProfile {
|
||||
property var browserProfile: HFWebEngineProfile {
|
||||
id: webviewProfile
|
||||
httpUserAgent: "Chrome/48.0 (HighFidelityInterface)"
|
||||
storageName: "qmlWebEngine"
|
||||
}
|
||||
|
||||
|
@ -127,5 +125,3 @@ OriginalDesktop.Desktop {
|
|||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include <QtQml/QQmlEngine>
|
||||
#include <QtQuick/QQuickWindow>
|
||||
|
||||
#include <QtWebEngineWidgets/QWebEngineProfile>
|
||||
|
||||
#include <QtWidgets/QDesktopWidget>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
|
||||
|
@ -126,6 +128,7 @@
|
|||
#include "InterfaceLogging.h"
|
||||
#include "LODManager.h"
|
||||
#include "ModelPackager.h"
|
||||
#include "networking/HFWebEngineProfile.h"
|
||||
#include "scripting/AccountScriptingInterface.h"
|
||||
#include "scripting/AssetMappingsScriptingInterface.h"
|
||||
#include "scripting/AudioDeviceScriptingInterface.h"
|
||||
|
@ -1698,6 +1701,7 @@ void Application::initializeUi() {
|
|||
UpdateDialog::registerType();
|
||||
qmlRegisterType<Preference>("Hifi", 1, 0, "Preference");
|
||||
|
||||
qmlRegisterType<HFWebEngineProfile>("HFWebEngineProfile", 1, 0, "HFWebEngineProfile");
|
||||
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
offscreenUi->create(_glWidget->qglContext());
|
||||
|
|
|
@ -50,50 +50,69 @@ void renderWorldBox(gpu::Batch& batch) {
|
|||
static const float DASH_LENGTH = 1.0f;
|
||||
static const float GAP_LENGTH = 1.0f;
|
||||
auto transform = Transform{};
|
||||
static std::array<int, 18> geometryIds;
|
||||
static std::once_flag initGeometryIds;
|
||||
std::call_once(initGeometryIds, [&] {
|
||||
for (size_t i = 0; i < geometryIds.size(); ++i) {
|
||||
geometryIds[i] = geometryCache->allocateID();
|
||||
}
|
||||
});
|
||||
|
||||
batch.setModelTransform(transform);
|
||||
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(HALF_TREE_SCALE, 0.0f, 0.0f), RED);
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(HALF_TREE_SCALE, 0.0f, 0.0f), RED, geometryIds[0]);
|
||||
geometryCache->renderDashedLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(-HALF_TREE_SCALE, 0.0f, 0.0f), DASHED_RED,
|
||||
DASH_LENGTH, GAP_LENGTH);
|
||||
DASH_LENGTH, GAP_LENGTH, geometryIds[1]);
|
||||
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, HALF_TREE_SCALE, 0.0f), GREEN);
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, HALF_TREE_SCALE, 0.0f), GREEN, geometryIds[2]);
|
||||
geometryCache->renderDashedLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, -HALF_TREE_SCALE, 0.0f), DASHED_GREEN,
|
||||
DASH_LENGTH, GAP_LENGTH);
|
||||
DASH_LENGTH, GAP_LENGTH, geometryIds[3]);
|
||||
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, HALF_TREE_SCALE), BLUE);
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, HALF_TREE_SCALE), BLUE, geometryIds[4]);
|
||||
geometryCache->renderDashedLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, -HALF_TREE_SCALE), DASHED_BLUE,
|
||||
DASH_LENGTH, GAP_LENGTH);
|
||||
DASH_LENGTH, GAP_LENGTH, geometryIds[5]);
|
||||
|
||||
// X center boundaries
|
||||
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, -HALF_TREE_SCALE, 0.0f),
|
||||
glm::vec3(HALF_TREE_SCALE, -HALF_TREE_SCALE, 0.0f), GREY);
|
||||
glm::vec3(HALF_TREE_SCALE, -HALF_TREE_SCALE, 0.0f), GREY,
|
||||
geometryIds[6]);
|
||||
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, -HALF_TREE_SCALE, 0.0f),
|
||||
glm::vec3(-HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f), GREY);
|
||||
glm::vec3(-HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f), GREY,
|
||||
geometryIds[7]);
|
||||
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f),
|
||||
glm::vec3(HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f), GREY);
|
||||
glm::vec3(HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f), GREY,
|
||||
geometryIds[8]);
|
||||
geometryCache->renderLine(batch, glm::vec3(HALF_TREE_SCALE, -HALF_TREE_SCALE, 0.0f),
|
||||
glm::vec3(HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f), GREY);
|
||||
glm::vec3(HALF_TREE_SCALE, HALF_TREE_SCALE, 0.0f), GREY,
|
||||
geometryIds[9]);
|
||||
|
||||
// Z center boundaries
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, -HALF_TREE_SCALE, -HALF_TREE_SCALE),
|
||||
glm::vec3(0.0f, -HALF_TREE_SCALE, HALF_TREE_SCALE), GREY);
|
||||
glm::vec3(0.0f, -HALF_TREE_SCALE, HALF_TREE_SCALE), GREY,
|
||||
geometryIds[10]);
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, -HALF_TREE_SCALE, -HALF_TREE_SCALE),
|
||||
glm::vec3(0.0f, HALF_TREE_SCALE, -HALF_TREE_SCALE), GREY);
|
||||
glm::vec3(0.0f, HALF_TREE_SCALE, -HALF_TREE_SCALE), GREY,
|
||||
geometryIds[11]);
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, HALF_TREE_SCALE, -HALF_TREE_SCALE),
|
||||
glm::vec3(0.0f, HALF_TREE_SCALE, HALF_TREE_SCALE), GREY);
|
||||
glm::vec3(0.0f, HALF_TREE_SCALE, HALF_TREE_SCALE), GREY,
|
||||
geometryIds[12]);
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, -HALF_TREE_SCALE, HALF_TREE_SCALE),
|
||||
glm::vec3(0.0f, HALF_TREE_SCALE, HALF_TREE_SCALE), GREY);
|
||||
glm::vec3(0.0f, HALF_TREE_SCALE, HALF_TREE_SCALE), GREY,
|
||||
geometryIds[13]);
|
||||
|
||||
// Center boundaries
|
||||
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, 0.0f, -HALF_TREE_SCALE),
|
||||
glm::vec3(-HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), GREY);
|
||||
glm::vec3(-HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), GREY,
|
||||
geometryIds[14]);
|
||||
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, 0.0f, -HALF_TREE_SCALE),
|
||||
glm::vec3(HALF_TREE_SCALE, 0.0f, -HALF_TREE_SCALE), GREY);
|
||||
glm::vec3(HALF_TREE_SCALE, 0.0f, -HALF_TREE_SCALE), GREY,
|
||||
geometryIds[15]);
|
||||
geometryCache->renderLine(batch, glm::vec3(HALF_TREE_SCALE, 0.0f, -HALF_TREE_SCALE),
|
||||
glm::vec3(HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), GREY);
|
||||
glm::vec3(HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), GREY,
|
||||
geometryIds[16]);
|
||||
geometryCache->renderLine(batch, glm::vec3(-HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE),
|
||||
glm::vec3(HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), GREY);
|
||||
glm::vec3(HALF_TREE_SCALE, 0.0f, HALF_TREE_SCALE), GREY,
|
||||
geometryIds[17]);
|
||||
|
||||
|
||||
geometryCache->renderWireCubeInstance(batch, GREY4);
|
||||
|
|
|
@ -99,6 +99,11 @@ Avatar::Avatar(RigPointer rig) :
|
|||
|
||||
_skeletonModel = std::make_shared<SkeletonModel>(this, nullptr, rig);
|
||||
connect(_skeletonModel.get(), &Model::setURLFinished, this, &Avatar::setModelURLFinished);
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
_nameRectGeometryID = geometryCache->allocateID();
|
||||
_leftPointerGeometryID = geometryCache->allocateID();
|
||||
_rightPointerGeometryID = geometryCache->allocateID();
|
||||
}
|
||||
|
||||
Avatar::~Avatar() {
|
||||
|
@ -119,6 +124,13 @@ Avatar::~Avatar() {
|
|||
delete _motionState;
|
||||
_motionState = nullptr;
|
||||
}
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (geometryCache) {
|
||||
geometryCache->releaseID(_nameRectGeometryID);
|
||||
geometryCache->releaseID(_leftPointerGeometryID);
|
||||
geometryCache->releaseID(_rightPointerGeometryID);
|
||||
}
|
||||
}
|
||||
|
||||
void Avatar::init() {
|
||||
|
@ -492,7 +504,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
|
|||
pointerTransform.setRotation(rotation);
|
||||
batch.setModelTransform(pointerTransform);
|
||||
geometryCache->bindSimpleProgram(batch);
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor);
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor, _leftPointerGeometryID);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -516,7 +528,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
|
|||
pointerTransform.setRotation(rotation);
|
||||
batch.setModelTransform(pointerTransform);
|
||||
geometryCache->bindSimpleProgram(batch);
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor);
|
||||
geometryCache->renderLine(batch, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, laserLength, 0.0f), laserColor, _rightPointerGeometryID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -603,14 +615,14 @@ void Avatar::fixupModelsInScene() {
|
|||
_skeletonModel->removeFromScene(scene, pendingChanges);
|
||||
_skeletonModel->addToScene(scene, pendingChanges);
|
||||
}
|
||||
for (auto& attachmentModel : _attachmentModels) {
|
||||
for (auto attachmentModel : _attachmentModels) {
|
||||
if (attachmentModel->isRenderable() && attachmentModel->needsFixupInScene()) {
|
||||
attachmentModel->removeFromScene(scene, pendingChanges);
|
||||
attachmentModel->addToScene(scene, pendingChanges);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& attachmentModelToRemove : _attachmentsToRemove) {
|
||||
for (auto attachmentModelToRemove : _attachmentsToRemove) {
|
||||
attachmentModelToRemove->removeFromScene(scene, pendingChanges);
|
||||
}
|
||||
_attachmentsToDelete.insert(_attachmentsToDelete.end(), _attachmentsToRemove.begin(), _attachmentsToRemove.end());
|
||||
|
@ -782,7 +794,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const
|
|||
PROFILE_RANGE_BATCH(batch, __FUNCTION__":renderBevelCornersRect");
|
||||
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, false, true, true, true);
|
||||
DependencyManager::get<GeometryCache>()->renderBevelCornersRect(batch, left, bottom, width, height,
|
||||
bevelDistance, backgroundColor);
|
||||
bevelDistance, backgroundColor, _nameRectGeometryID);
|
||||
}
|
||||
|
||||
// Render actual name
|
||||
|
|
|
@ -248,6 +248,9 @@ protected:
|
|||
ThreadSafeValueCache<glm::quat> _rightPalmRotationCache { glm::quat() };
|
||||
|
||||
private:
|
||||
int _leftPointerGeometryID { 0 };
|
||||
int _rightPointerGeometryID { 0 };
|
||||
int _nameRectGeometryID { 0 };
|
||||
bool _initialized;
|
||||
bool _shouldAnimate { true };
|
||||
bool _shouldSkipRender { false };
|
||||
|
|
27
interface/src/networking/HFWebEngineProfile.cpp
Normal file
27
interface/src/networking/HFWebEngineProfile.cpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// HFWebEngineProfile.cpp
|
||||
// interface/src/networking
|
||||
//
|
||||
// Created by Stephen Birarda on 2016-10-17.
|
||||
// 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
|
||||
//
|
||||
|
||||
#include "HFWebEngineProfile.h"
|
||||
|
||||
#include "HFWebEngineRequestInterceptor.h"
|
||||
|
||||
static const QString QML_WEB_ENGINE_STORAGE_NAME = "qmlWebEngine";
|
||||
|
||||
HFWebEngineProfile::HFWebEngineProfile(QObject* parent) :
|
||||
QQuickWebEngineProfile(parent)
|
||||
{
|
||||
static const QString WEB_ENGINE_USER_AGENT = "Chrome/48.0 (HighFidelityInterface)";
|
||||
setHttpUserAgent(WEB_ENGINE_USER_AGENT);
|
||||
|
||||
// we use the HFWebEngineRequestInterceptor to make sure that web requests are authenticated for the interface user
|
||||
auto requestInterceptor = new HFWebEngineRequestInterceptor(this);
|
||||
setRequestInterceptor(requestInterceptor);
|
||||
}
|
25
interface/src/networking/HFWebEngineProfile.h
Normal file
25
interface/src/networking/HFWebEngineProfile.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// HFWebEngineProfile.h
|
||||
// interface/src/networking
|
||||
//
|
||||
// Created by Stephen Birarda on 2016-10-17.
|
||||
// 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
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef hifi_HFWebEngineProfile_h
|
||||
#define hifi_HFWebEngineProfile_h
|
||||
|
||||
#include <QtWebEngine/QQuickWebEngineProfile>
|
||||
|
||||
class HFWebEngineProfile : public QQuickWebEngineProfile {
|
||||
public:
|
||||
HFWebEngineProfile(QObject* parent = Q_NULLPTR);
|
||||
};
|
||||
|
||||
|
||||
#endif // hifi_HFWebEngineProfile_h
|
40
interface/src/networking/HFWebEngineRequestInterceptor.cpp
Normal file
40
interface/src/networking/HFWebEngineRequestInterceptor.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// HFWebEngineRequestInterceptor.cpp
|
||||
// interface/src/networking
|
||||
//
|
||||
// Created by Stephen Birarda on 2016-10-14.
|
||||
// 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
|
||||
//
|
||||
|
||||
#include "HFWebEngineRequestInterceptor.h"
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
#include <AccountManager.h>
|
||||
|
||||
bool isAuthableHighFidelityURL(const QUrl& url) {
|
||||
static const QStringList HF_HOSTS = {
|
||||
"highfidelity.com", "highfidelity.io",
|
||||
"metaverse.highfidelity.com", "metaverse.highfidelity.io"
|
||||
};
|
||||
|
||||
return url.scheme() == "https" && HF_HOSTS.contains(url.host());
|
||||
}
|
||||
|
||||
void HFWebEngineRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) {
|
||||
// check if this is a request to a highfidelity URL
|
||||
if (isAuthableHighFidelityURL(info.requestUrl())) {
|
||||
// if we have an access token, add it to the right HTTP header for authorization
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
||||
if (accountManager->hasValidAccessToken()) {
|
||||
static const QString OAUTH_AUTHORIZATION_HEADER = "Authorization";
|
||||
|
||||
QString bearerTokenString = "Bearer " + accountManager->getAccountInfo().getAccessToken().token;
|
||||
info.setHttpHeader(OAUTH_AUTHORIZATION_HEADER.toLocal8Bit(), bearerTokenString.toLocal8Bit());
|
||||
}
|
||||
}
|
||||
}
|
26
interface/src/networking/HFWebEngineRequestInterceptor.h
Normal file
26
interface/src/networking/HFWebEngineRequestInterceptor.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// HFWebEngineRequestInterceptor.h
|
||||
// interface/src/networking
|
||||
//
|
||||
// Created by Stephen Birarda on 2016-10-14.
|
||||
// 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
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef hifi_HFWebEngineRequestInterceptor_h
|
||||
#define hifi_HFWebEngineRequestInterceptor_h
|
||||
|
||||
#include <QWebEngineUrlRequestInterceptor>
|
||||
|
||||
class HFWebEngineRequestInterceptor : public QWebEngineUrlRequestInterceptor {
|
||||
public:
|
||||
HFWebEngineRequestInterceptor(QObject* parent) : QWebEngineUrlRequestInterceptor(parent) {};
|
||||
|
||||
virtual void interceptRequest(QWebEngineUrlRequestInfo& info) override;
|
||||
};
|
||||
|
||||
#endif // hifi_HFWebEngineRequestInterceptor_h
|
|
@ -40,9 +40,18 @@ ApplicationOverlay::ApplicationOverlay()
|
|||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
_domainStatusBorder = geometryCache->allocateID();
|
||||
_magnifierBorder = geometryCache->allocateID();
|
||||
_qmlGeometryId = geometryCache->allocateID();
|
||||
_rearViewGeometryId = geometryCache->allocateID();
|
||||
}
|
||||
|
||||
ApplicationOverlay::~ApplicationOverlay() {
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (geometryCache) {
|
||||
geometryCache->releaseID(_domainStatusBorder);
|
||||
geometryCache->releaseID(_magnifierBorder);
|
||||
geometryCache->releaseID(_qmlGeometryId);
|
||||
geometryCache->releaseID(_rearViewGeometryId);
|
||||
}
|
||||
}
|
||||
|
||||
// Renders the overlays either to a texture or to the screen
|
||||
|
@ -112,7 +121,7 @@ void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) {
|
|||
batch.setModelTransform(Transform());
|
||||
batch.resetViewTransform();
|
||||
batch.setResourceTexture(0, _uiTexture);
|
||||
geometryCache->renderUnitQuad(batch, glm::vec4(1));
|
||||
geometryCache->renderUnitQuad(batch, glm::vec4(1), _qmlGeometryId);
|
||||
}
|
||||
|
||||
void ApplicationOverlay::renderAudioScope(RenderArgs* renderArgs) {
|
||||
|
@ -188,7 +197,7 @@ void ApplicationOverlay::renderRearView(RenderArgs* renderArgs) {
|
|||
|
||||
batch.setResourceTexture(0, selfieTexture);
|
||||
float alpha = DependencyManager::get<OffscreenUi>()->getDesktop()->property("unpinnedAlpha").toFloat();
|
||||
geometryCache->renderQuad(batch, bottomLeft, topRight, texCoordMinCorner, texCoordMaxCorner, glm::vec4(1.0f, 1.0f, 1.0f, alpha));
|
||||
geometryCache->renderQuad(batch, bottomLeft, topRight, texCoordMinCorner, texCoordMaxCorner, glm::vec4(1.0f, 1.0f, 1.0f, alpha), _rearViewGeometryId);
|
||||
|
||||
batch.setResourceTexture(0, renderArgs->_whiteTexture);
|
||||
}
|
||||
|
|
|
@ -50,6 +50,8 @@ private:
|
|||
gpu::TexturePointer _overlayDepthTexture;
|
||||
gpu::TexturePointer _overlayColorTexture;
|
||||
gpu::FramebufferPointer _overlayFramebuffer;
|
||||
int _qmlGeometryId { 0 };
|
||||
int _rearViewGeometryId { 0 };
|
||||
};
|
||||
|
||||
#endif // hifi_ApplicationOverlay_h
|
||||
|
|
|
@ -18,9 +18,29 @@
|
|||
|
||||
QString const Cube3DOverlay::TYPE = "cube";
|
||||
|
||||
Cube3DOverlay::Cube3DOverlay() {
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
for (size_t i = 0; i < _geometryIds.size(); ++i) {
|
||||
_geometryIds[i] = geometryCache->allocateID();
|
||||
}
|
||||
}
|
||||
|
||||
Cube3DOverlay::Cube3DOverlay(const Cube3DOverlay* cube3DOverlay) :
|
||||
Volume3DOverlay(cube3DOverlay)
|
||||
{
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
for (size_t i = 0; i < _geometryIds.size(); ++i) {
|
||||
_geometryIds[i] = geometryCache->allocateID();
|
||||
}
|
||||
}
|
||||
|
||||
Cube3DOverlay::~Cube3DOverlay() {
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (geometryCache) {
|
||||
for (size_t i = 0; i < _geometryIds.size(); ++i) {
|
||||
geometryCache->releaseID(_geometryIds[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cube3DOverlay::render(RenderArgs* args) {
|
||||
|
@ -71,20 +91,20 @@ void Cube3DOverlay::render(RenderArgs* args) {
|
|||
glm::vec3 topLeftFar(-halfDimensions.x, halfDimensions.y, halfDimensions.z);
|
||||
glm::vec3 topRightFar(halfDimensions.x, halfDimensions.y, halfDimensions.z);
|
||||
|
||||
geometryCache->renderDashedLine(*batch, bottomLeftNear, bottomRightNear, cubeColor);
|
||||
geometryCache->renderDashedLine(*batch, bottomRightNear, bottomRightFar, cubeColor);
|
||||
geometryCache->renderDashedLine(*batch, bottomRightFar, bottomLeftFar, cubeColor);
|
||||
geometryCache->renderDashedLine(*batch, bottomLeftFar, bottomLeftNear, cubeColor);
|
||||
geometryCache->renderDashedLine(*batch, bottomLeftNear, bottomRightNear, cubeColor, _geometryIds[0]);
|
||||
geometryCache->renderDashedLine(*batch, bottomRightNear, bottomRightFar, cubeColor, _geometryIds[1]);
|
||||
geometryCache->renderDashedLine(*batch, bottomRightFar, bottomLeftFar, cubeColor, _geometryIds[2]);
|
||||
geometryCache->renderDashedLine(*batch, bottomLeftFar, bottomLeftNear, cubeColor, _geometryIds[3]);
|
||||
|
||||
geometryCache->renderDashedLine(*batch, topLeftNear, topRightNear, cubeColor);
|
||||
geometryCache->renderDashedLine(*batch, topRightNear, topRightFar, cubeColor);
|
||||
geometryCache->renderDashedLine(*batch, topRightFar, topLeftFar, cubeColor);
|
||||
geometryCache->renderDashedLine(*batch, topLeftFar, topLeftNear, cubeColor);
|
||||
geometryCache->renderDashedLine(*batch, topLeftNear, topRightNear, cubeColor, _geometryIds[4]);
|
||||
geometryCache->renderDashedLine(*batch, topRightNear, topRightFar, cubeColor, _geometryIds[5]);
|
||||
geometryCache->renderDashedLine(*batch, topRightFar, topLeftFar, cubeColor, _geometryIds[6]);
|
||||
geometryCache->renderDashedLine(*batch, topLeftFar, topLeftNear, cubeColor, _geometryIds[7]);
|
||||
|
||||
geometryCache->renderDashedLine(*batch, bottomLeftNear, topLeftNear, cubeColor);
|
||||
geometryCache->renderDashedLine(*batch, bottomRightNear, topRightNear, cubeColor);
|
||||
geometryCache->renderDashedLine(*batch, bottomLeftFar, topLeftFar, cubeColor);
|
||||
geometryCache->renderDashedLine(*batch, bottomRightFar, topRightFar, cubeColor);
|
||||
geometryCache->renderDashedLine(*batch, bottomLeftNear, topLeftNear, cubeColor, _geometryIds[8]);
|
||||
geometryCache->renderDashedLine(*batch, bottomRightNear, topRightNear, cubeColor, _geometryIds[9]);
|
||||
geometryCache->renderDashedLine(*batch, bottomLeftFar, topLeftFar, cubeColor, _geometryIds[10]);
|
||||
geometryCache->renderDashedLine(*batch, bottomRightFar, topRightFar, cubeColor, _geometryIds[11]);
|
||||
|
||||
} else {
|
||||
transform.setScale(dimensions);
|
||||
|
|
|
@ -20,9 +20,10 @@ public:
|
|||
static QString const TYPE;
|
||||
virtual QString getType() const override { return TYPE; }
|
||||
|
||||
Cube3DOverlay() {}
|
||||
Cube3DOverlay();
|
||||
Cube3DOverlay(const Cube3DOverlay* cube3DOverlay);
|
||||
|
||||
~Cube3DOverlay();
|
||||
|
||||
virtual void render(RenderArgs* args) override;
|
||||
virtual const render::ShapeKey getShapeKey() override;
|
||||
|
||||
|
@ -37,6 +38,8 @@ public:
|
|||
|
||||
private:
|
||||
float _borderSize;
|
||||
// edges on a cube
|
||||
std::array<int, 12> _geometryIds;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ const float DEFAULT_SCALE = 100.0f;
|
|||
Grid3DOverlay::Grid3DOverlay() {
|
||||
setDimensions(DEFAULT_SCALE);
|
||||
updateGrid();
|
||||
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
|
||||
}
|
||||
|
||||
Grid3DOverlay::Grid3DOverlay(const Grid3DOverlay* grid3DOverlay) :
|
||||
|
@ -32,6 +33,14 @@ Grid3DOverlay::Grid3DOverlay(const Grid3DOverlay* grid3DOverlay) :
|
|||
_minorGridEvery(grid3DOverlay->_minorGridEvery)
|
||||
{
|
||||
updateGrid();
|
||||
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
|
||||
}
|
||||
|
||||
Grid3DOverlay::~Grid3DOverlay() {
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (geometryCache) {
|
||||
geometryCache->releaseID(_geometryId);
|
||||
}
|
||||
}
|
||||
|
||||
AABox Grid3DOverlay::getBounds() const {
|
||||
|
@ -80,7 +89,7 @@ void Grid3DOverlay::render(RenderArgs* args) {
|
|||
DependencyManager::get<GeometryCache>()->renderGrid(*batch, minCorner, maxCorner,
|
||||
_minorGridRowDivisions, _minorGridColDivisions, MINOR_GRID_EDGE,
|
||||
_majorGridRowDivisions, _majorGridColDivisions, MAJOR_GRID_EDGE,
|
||||
gridColor, _drawInFront);
|
||||
gridColor, _drawInFront, _geometryId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ public:
|
|||
|
||||
Grid3DOverlay();
|
||||
Grid3DOverlay(const Grid3DOverlay* grid3DOverlay);
|
||||
~Grid3DOverlay();
|
||||
|
||||
virtual AABox getBounds() const override;
|
||||
|
||||
|
@ -48,6 +49,7 @@ private:
|
|||
float _minorGridEvery { 1.0f };
|
||||
float _minorGridRowDivisions;
|
||||
float _minorGridColDivisions;
|
||||
int _geometryId { 0 };
|
||||
};
|
||||
|
||||
#endif // hifi_Grid3DOverlay_h
|
||||
|
|
|
@ -24,7 +24,7 @@ QString const Image3DOverlay::TYPE = "image3d";
|
|||
|
||||
Image3DOverlay::Image3DOverlay() {
|
||||
_isLoaded = false;
|
||||
_emissive = false;
|
||||
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
|
||||
}
|
||||
|
||||
Image3DOverlay::Image3DOverlay(const Image3DOverlay* image3DOverlay) :
|
||||
|
@ -34,6 +34,14 @@ Image3DOverlay::Image3DOverlay(const Image3DOverlay* image3DOverlay) :
|
|||
_emissive(image3DOverlay->_emissive),
|
||||
_fromImage(image3DOverlay->_fromImage)
|
||||
{
|
||||
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
|
||||
}
|
||||
|
||||
Image3DOverlay::~Image3DOverlay() {
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (geometryCache) {
|
||||
geometryCache->releaseID(_geometryId);
|
||||
}
|
||||
}
|
||||
|
||||
void Image3DOverlay::update(float deltatime) {
|
||||
|
@ -100,7 +108,8 @@ void Image3DOverlay::render(RenderArgs* args) {
|
|||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(
|
||||
*batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
|
||||
glm::vec4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha)
|
||||
glm::vec4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha),
|
||||
_geometryId
|
||||
);
|
||||
|
||||
batch->setResourceTexture(0, args->_whiteTexture); // restore default white color after me
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
|
||||
Image3DOverlay();
|
||||
Image3DOverlay(const Image3DOverlay* image3DOverlay);
|
||||
|
||||
~Image3DOverlay();
|
||||
virtual void render(RenderArgs* args) override;
|
||||
|
||||
virtual void update(float deltatime) override;
|
||||
|
@ -48,9 +48,10 @@ public:
|
|||
private:
|
||||
QString _url;
|
||||
NetworkTexturePointer _texture;
|
||||
bool _emissive;
|
||||
bool _emissive { false };
|
||||
|
||||
QRect _fromImage; // where from in the image to sample
|
||||
int _geometryId { 0 };
|
||||
};
|
||||
|
||||
#endif // hifi_Image3DOverlay_h
|
||||
|
|
|
@ -19,6 +19,10 @@ QString const Rectangle3DOverlay::TYPE = "rectangle3d";
|
|||
Rectangle3DOverlay::Rectangle3DOverlay() :
|
||||
_geometryCacheID(DependencyManager::get<GeometryCache>()->allocateID())
|
||||
{
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
for (size_t i = 0; i < _rectGeometryIds.size(); ++i) {
|
||||
_rectGeometryIds[i] = geometryCache->allocateID();
|
||||
}
|
||||
qDebug() << "Building rect3d overlay";
|
||||
}
|
||||
|
||||
|
@ -26,14 +30,21 @@ Rectangle3DOverlay::Rectangle3DOverlay(const Rectangle3DOverlay* rectangle3DOver
|
|||
Planar3DOverlay(rectangle3DOverlay),
|
||||
_geometryCacheID(DependencyManager::get<GeometryCache>()->allocateID())
|
||||
{
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
for (size_t i = 0; i < _rectGeometryIds.size(); ++i) {
|
||||
_rectGeometryIds[i] = geometryCache->allocateID();
|
||||
}
|
||||
qDebug() << "Building rect3d overlay";
|
||||
}
|
||||
|
||||
Rectangle3DOverlay::~Rectangle3DOverlay() {
|
||||
qDebug() << "Destryoing rect3d overlay";
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (_geometryCacheID && geometryCache) {
|
||||
if (geometryCache) {
|
||||
geometryCache->releaseID(_geometryCacheID);
|
||||
for (size_t i = 0; i < _rectGeometryIds.size(); ++i) {
|
||||
geometryCache->releaseID(_rectGeometryIds[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,7 +77,7 @@ void Rectangle3DOverlay::render(RenderArgs* args) {
|
|||
glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, 0.0f);
|
||||
glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
geometryCache->bindSimpleProgram(*batch);
|
||||
geometryCache->renderQuad(*batch, topLeft, bottomRight, rectangleColor);
|
||||
geometryCache->renderQuad(*batch, topLeft, bottomRight, rectangleColor, _geometryCacheID);
|
||||
} else {
|
||||
geometryCache->bindSimpleProgram(*batch, false, false, false, true, true);
|
||||
if (getIsDashedLine()) {
|
||||
|
@ -75,10 +86,10 @@ void Rectangle3DOverlay::render(RenderArgs* args) {
|
|||
glm::vec3 point3(halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
glm::vec3 point4(-halfDimensions.x, halfDimensions.y, 0.0f);
|
||||
|
||||
geometryCache->renderDashedLine(*batch, point1, point2, rectangleColor);
|
||||
geometryCache->renderDashedLine(*batch, point2, point3, rectangleColor);
|
||||
geometryCache->renderDashedLine(*batch, point3, point4, rectangleColor);
|
||||
geometryCache->renderDashedLine(*batch, point4, point1, rectangleColor);
|
||||
geometryCache->renderDashedLine(*batch, point1, point2, rectangleColor, _rectGeometryIds[0]);
|
||||
geometryCache->renderDashedLine(*batch, point2, point3, rectangleColor, _rectGeometryIds[1]);
|
||||
geometryCache->renderDashedLine(*batch, point3, point4, rectangleColor, _rectGeometryIds[2]);
|
||||
geometryCache->renderDashedLine(*batch, point4, point1, rectangleColor, _rectGeometryIds[3]);
|
||||
} else {
|
||||
if (halfDimensions != _previousHalfDimensions) {
|
||||
QVector<glm::vec3> border;
|
||||
|
|
|
@ -30,6 +30,7 @@ public:
|
|||
virtual Rectangle3DOverlay* createClone() const override;
|
||||
private:
|
||||
int _geometryCacheID;
|
||||
std::array<int, 4> _rectGeometryIds;
|
||||
glm::vec2 _previousHalfDimensions;
|
||||
};
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ QString const Text3DOverlay::TYPE = "text3d";
|
|||
|
||||
Text3DOverlay::Text3DOverlay() {
|
||||
_textRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE);
|
||||
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
|
||||
}
|
||||
|
||||
Text3DOverlay::Text3DOverlay(const Text3DOverlay* text3DOverlay) :
|
||||
|
@ -39,10 +40,15 @@ Text3DOverlay::Text3DOverlay(const Text3DOverlay* text3DOverlay) :
|
|||
_bottomMargin(text3DOverlay->_bottomMargin)
|
||||
{
|
||||
_textRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE);
|
||||
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
|
||||
}
|
||||
|
||||
Text3DOverlay::~Text3DOverlay() {
|
||||
delete _textRenderer;
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (geometryCache) {
|
||||
geometryCache->releaseID(_geometryId);
|
||||
}
|
||||
}
|
||||
|
||||
xColor Text3DOverlay::getBackgroundColor() {
|
||||
|
@ -97,7 +103,7 @@ void Text3DOverlay::render(RenderArgs* args) {
|
|||
|
||||
glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, SLIGHTLY_BEHIND);
|
||||
glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, SLIGHTLY_BEHIND);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, quadColor);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, quadColor, _geometryId);
|
||||
|
||||
// Same font properties as textSize()
|
||||
float maxHeight = (float)_textRenderer->computeExtent("Xy").y * LINE_SCALE_RATIO;
|
||||
|
|
|
@ -74,6 +74,7 @@ private:
|
|||
float _topMargin { 0.1f };
|
||||
float _rightMargin { 0.1f };
|
||||
float _bottomMargin { 0.1f };
|
||||
int _geometryId { 0 };
|
||||
};
|
||||
|
||||
#endif // hifi_Text3DOverlay_h
|
||||
|
|
|
@ -32,7 +32,9 @@ static float OPAQUE_ALPHA_THRESHOLD = 0.99f;
|
|||
|
||||
QString const Web3DOverlay::TYPE = "web3d";
|
||||
|
||||
Web3DOverlay::Web3DOverlay() : _dpi(DPI) { }
|
||||
Web3DOverlay::Web3DOverlay() : _dpi(DPI) {
|
||||
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
|
||||
}
|
||||
|
||||
Web3DOverlay::Web3DOverlay(const Web3DOverlay* Web3DOverlay) :
|
||||
Billboard3DOverlay(Web3DOverlay),
|
||||
|
@ -40,6 +42,7 @@ Web3DOverlay::Web3DOverlay(const Web3DOverlay* Web3DOverlay) :
|
|||
_dpi(Web3DOverlay->_dpi),
|
||||
_resolution(Web3DOverlay->_resolution)
|
||||
{
|
||||
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
|
||||
}
|
||||
|
||||
Web3DOverlay::~Web3DOverlay() {
|
||||
|
@ -55,6 +58,10 @@ Web3DOverlay::~Web3DOverlay() {
|
|||
webSurface->deleteLater();
|
||||
});
|
||||
}
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (geometryCache) {
|
||||
geometryCache->releaseID(_geometryId);
|
||||
}
|
||||
}
|
||||
|
||||
void Web3DOverlay::update(float deltatime) {
|
||||
|
@ -79,6 +86,9 @@ void Web3DOverlay::render(RenderArgs* args) {
|
|||
});
|
||||
};
|
||||
_webSurface = QSharedPointer<OffscreenQmlSurface>(new OffscreenQmlSurface(), deleter);
|
||||
// FIXME, the max FPS could be better managed by being dynamic (based on the number of current surfaces
|
||||
// and the current rendering load)
|
||||
_webSurface->setMaxFps(10);
|
||||
_webSurface->create(currentContext);
|
||||
_webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/controls/"));
|
||||
_webSurface->load("WebView.qml");
|
||||
|
@ -122,7 +132,7 @@ void Web3DOverlay::render(RenderArgs* args) {
|
|||
} else {
|
||||
geometryCache->bindOpaqueWebBrowserProgram(batch);
|
||||
}
|
||||
geometryCache->renderQuad(batch, halfSize * -1.0f, halfSize, vec2(0), vec2(1), color);
|
||||
geometryCache->renderQuad(batch, halfSize * -1.0f, halfSize, vec2(0), vec2(1), color, _geometryId);
|
||||
batch.setResourceTexture(0, args->_whiteTexture); // restore default white color after me
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ private:
|
|||
QString _url;
|
||||
float _dpi;
|
||||
vec2 _resolution{ 640, 480 };
|
||||
int _geometryId { 0 };
|
||||
};
|
||||
|
||||
#endif // hifi_Web3DOverlay_h
|
||||
|
|
|
@ -112,6 +112,10 @@ void HmdDisplayPlugin::internalDeactivate() {
|
|||
void HmdDisplayPlugin::customizeContext() {
|
||||
Parent::customizeContext();
|
||||
_overlayRenderer.build();
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
for (size_t i = 0; i < _geometryIds.size(); ++i) {
|
||||
_geometryIds[i] = geometryCache->allocateID();
|
||||
}
|
||||
}
|
||||
|
||||
void HmdDisplayPlugin::uncustomizeContext() {
|
||||
|
@ -126,6 +130,11 @@ void HmdDisplayPlugin::uncustomizeContext() {
|
|||
});
|
||||
_overlayRenderer = OverlayRenderer();
|
||||
_previewTexture.reset();
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
for (size_t i = 0; i < _geometryIds.size(); ++i) {
|
||||
geometryCache->releaseID(_geometryIds[i]);
|
||||
}
|
||||
Parent::uncustomizeContext();
|
||||
}
|
||||
|
||||
|
@ -385,10 +394,11 @@ void HmdDisplayPlugin::updateFrameData() {
|
|||
castDirection = glm::inverse(_presentUiModelTransform.getRotation()) * castDirection;
|
||||
}
|
||||
|
||||
// this offset needs to match GRAB_POINT_SPHERE_OFFSET in scripts/system/libraries/controllers.js
|
||||
//static const vec3 GRAB_POINT_SPHERE_OFFSET = vec3(0.1f, 0.04f, -0.32f);
|
||||
static const vec3 GRAB_POINT_SPHERE_OFFSET = vec3(0.0f, 0.0f, -0.175f);
|
||||
vec3 grabPointOffset = GRAB_POINT_SPHERE_OFFSET;
|
||||
// this offset needs to match GRAB_POINT_SPHERE_OFFSET in scripts/system/libraries/controllers.js:19
|
||||
static const vec3 GRAB_POINT_SPHERE_OFFSET(0.04f, 0.13f, 0.039f); // x = upward, y = forward, z = lateral
|
||||
|
||||
// swizzle grab point so that (x = upward, y = lateral, z = forward)
|
||||
vec3 grabPointOffset = glm::vec3(GRAB_POINT_SPHERE_OFFSET.x, GRAB_POINT_SPHERE_OFFSET.z, -GRAB_POINT_SPHERE_OFFSET.y);
|
||||
if (i == 0) {
|
||||
grabPointOffset.x *= -1.0f; // this changes between left and right hands
|
||||
}
|
||||
|
@ -708,18 +718,12 @@ void HmdDisplayPlugin::compositeExtra() {
|
|||
const float glowWidth = 0.05f;
|
||||
if (laser.valid()) {
|
||||
const auto& points = _presentHandLaserPoints[index];
|
||||
geometryCache->renderGlowLine(batch, points.first, points.second, laser.color,
|
||||
glowIntensity, glowWidth, _glowLineID);
|
||||
geometryCache->renderGlowLine(batch, points.first, points.second, laser.color, _geometryIds[index]);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
HmdDisplayPlugin::HmdDisplayPlugin() {
|
||||
_glowLineID = DependencyManager::get<GeometryCache>()->allocateID();
|
||||
}
|
||||
|
||||
HmdDisplayPlugin::~HmdDisplayPlugin() {
|
||||
qDebug() << "Destroying HmdDisplayPlugin";
|
||||
DependencyManager::get<GeometryCache>()->releaseID(_glowLineID);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
class HmdDisplayPlugin : public OpenGLDisplayPlugin {
|
||||
using Parent = OpenGLDisplayPlugin;
|
||||
public:
|
||||
HmdDisplayPlugin();
|
||||
~HmdDisplayPlugin();
|
||||
bool isHmd() const override final { return true; }
|
||||
float getIPD() const override final { return _ipd; }
|
||||
|
@ -79,6 +78,7 @@ protected:
|
|||
|
||||
Transform _presentUiModelTransform;
|
||||
std::array<HandLaserInfo, 2> _presentHandLasers;
|
||||
std::array<int, 2> _geometryIds;
|
||||
std::array<mat4, 2> _presentHandPoses;
|
||||
std::array<std::pair<vec3, vec3>, 2> _presentHandLaserPoints;
|
||||
|
||||
|
@ -156,6 +156,4 @@ private:
|
|||
void updatePipeline();
|
||||
void render(HmdDisplayPlugin& plugin);
|
||||
} _overlayRenderer;
|
||||
|
||||
int _glowLineID { -1 };
|
||||
};
|
||||
|
|
|
@ -24,6 +24,14 @@ EntityItemPointer RenderableTextEntityItem::factory(const EntityItemID& entityID
|
|||
return entity;
|
||||
}
|
||||
|
||||
RenderableTextEntityItem::~RenderableTextEntityItem() {
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (_geometryID && geometryCache) {
|
||||
geometryCache->releaseID(_geometryID);
|
||||
}
|
||||
delete _textRenderer;
|
||||
}
|
||||
|
||||
void RenderableTextEntityItem::render(RenderArgs* args) {
|
||||
PerformanceTimer perfTimer("RenderableTextEntityItem::render");
|
||||
Q_ASSERT(getType() == EntityTypes::Text);
|
||||
|
@ -62,9 +70,12 @@ void RenderableTextEntityItem::render(RenderArgs* args) {
|
|||
transformToTopLeft.setScale(1.0f); // Use a scale of one so that the text is not deformed
|
||||
|
||||
batch.setModelTransform(transformToTopLeft);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, false, transparent, false, false, true);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, minCorner, maxCorner, backgroundColor);
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (!_geometryID) {
|
||||
_geometryID = geometryCache->allocateID();
|
||||
}
|
||||
geometryCache->bindSimpleProgram(batch, false, transparent, false, false, true);
|
||||
geometryCache->renderQuad(batch, minCorner, maxCorner, backgroundColor, _geometryID);
|
||||
|
||||
float scale = _lineHeight / _textRenderer->getFontSize();
|
||||
transformToTopLeft.setScale(scale); // Scale to have the correct line height
|
||||
|
|
|
@ -23,13 +23,14 @@ class RenderableTextEntityItem : public TextEntityItem {
|
|||
public:
|
||||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
RenderableTextEntityItem(const EntityItemID& entityItemID) : TextEntityItem(entityItemID) { }
|
||||
~RenderableTextEntityItem() { delete _textRenderer; }
|
||||
~RenderableTextEntityItem();
|
||||
|
||||
virtual void render(RenderArgs* args) override;
|
||||
|
||||
SIMPLE_RENDERABLE();
|
||||
|
||||
private:
|
||||
int _geometryID { 0 };
|
||||
TextRenderer3D* _textRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE / 2.0f);
|
||||
};
|
||||
|
||||
|
|
|
@ -52,11 +52,16 @@ RenderableWebEntityItem::RenderableWebEntityItem(const EntityItemID& entityItemI
|
|||
_touchDevice.setType(QTouchDevice::TouchScreen);
|
||||
_touchDevice.setName("RenderableWebEntityItemTouchDevice");
|
||||
_touchDevice.setMaximumTouchPoints(4);
|
||||
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
|
||||
}
|
||||
|
||||
RenderableWebEntityItem::~RenderableWebEntityItem() {
|
||||
destroyWebSurface();
|
||||
qDebug() << "Destroyed web entity " << getID();
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (geometryCache) {
|
||||
geometryCache->releaseID(_geometryId);
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderableWebEntityItem::buildWebSurface(EntityTreeRenderer* renderer) {
|
||||
|
@ -95,11 +100,14 @@ bool RenderableWebEntityItem::buildWebSurface(EntityTreeRenderer* renderer) {
|
|||
};
|
||||
_webSurface = QSharedPointer<OffscreenQmlSurface>(new OffscreenQmlSurface(), deleter);
|
||||
|
||||
// FIXME, the max FPS could be better managed by being dynamic (based on the number of current surfaces
|
||||
// and the current rendering load)
|
||||
_webSurface->setMaxFps(10);
|
||||
|
||||
// The lifetime of the QML surface MUST be managed by the main thread
|
||||
// Additionally, we MUST use local variables copied by value, rather than
|
||||
// member variables, since they would implicitly refer to a this that
|
||||
// is no longer valid
|
||||
|
||||
_webSurface->create(currentContext);
|
||||
_webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/controls/"));
|
||||
_webSurface->load("WebView.qml", [&](QQmlContext* context, QObject* obj) {
|
||||
|
@ -228,7 +236,7 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
|
|||
} else {
|
||||
DependencyManager::get<GeometryCache>()->bindOpaqueWebBrowserProgram(batch);
|
||||
}
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, texMin, texMax, glm::vec4(1.0f, 1.0f, 1.0f, fadeRatio));
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, texMin, texMax, glm::vec4(1.0f, 1.0f, 1.0f, fadeRatio), _geometryId);
|
||||
}
|
||||
|
||||
void RenderableWebEntityItem::setSourceUrl(const QString& value) {
|
||||
|
|
|
@ -69,6 +69,7 @@ private:
|
|||
QMetaObject::Connection _mouseReleaseConnection;
|
||||
QMetaObject::Connection _mouseMoveConnection;
|
||||
QMetaObject::Connection _hoverLeaveConnection;
|
||||
int _geometryId { 0 };
|
||||
};
|
||||
|
||||
#endif // hifi_RenderableWebEntityItem_h
|
||||
|
|
|
@ -40,19 +40,6 @@
|
|||
#include "TextureRecycler.h"
|
||||
#include "Context.h"
|
||||
|
||||
QString fixupHifiUrl(const QString& urlString) {
|
||||
static const QString ACCESS_TOKEN_PARAMETER = "access_token";
|
||||
static const QString ALLOWED_HOST = "metaverse.highfidelity.com";
|
||||
QUrl url(urlString);
|
||||
QUrlQuery query(url);
|
||||
if (url.host() == ALLOWED_HOST && query.allQueryItemValues(ACCESS_TOKEN_PARAMETER).empty()) {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
query.addQueryItem(ACCESS_TOKEN_PARAMETER, accountManager->getAccountInfo().getAccessToken().token);
|
||||
url.setQuery(query.query());
|
||||
return url.toString();
|
||||
}
|
||||
return urlString;
|
||||
}
|
||||
|
||||
class UrlHandler : public QObject {
|
||||
Q_OBJECT
|
||||
|
@ -66,11 +53,6 @@ public:
|
|||
static auto handler = dynamic_cast<AbstractUriHandler*>(qApp);
|
||||
return handler->acceptURL(url);
|
||||
}
|
||||
|
||||
// FIXME hack for authentication, remove when we migrate to Qt 5.6
|
||||
Q_INVOKABLE QString fixupUrl(const QString& originalUrl) {
|
||||
return fixupHifiUrl(originalUrl);
|
||||
}
|
||||
};
|
||||
|
||||
// Time between receiving a request to render the offscreen UI actually triggering
|
||||
|
@ -140,7 +122,9 @@ void OffscreenQmlSurface::setupFbo() {
|
|||
|
||||
void OffscreenQmlSurface::cleanup() {
|
||||
_canvas->makeCurrent();
|
||||
_renderControl->invalidate();
|
||||
|
||||
delete _renderControl; // and invalidate
|
||||
|
||||
if (_depthStencil) {
|
||||
glDeleteRenderbuffers(1, &_depthStencil);
|
||||
_depthStencil = 0;
|
||||
|
@ -255,7 +239,6 @@ OffscreenQmlSurface::~OffscreenQmlSurface() {
|
|||
QObject::disconnect(&_updateTimer);
|
||||
QObject::disconnect(qApp);
|
||||
|
||||
|
||||
cleanup();
|
||||
|
||||
_canvas->deleteLater();
|
||||
|
@ -315,8 +298,8 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
|
|||
_qmlComponent = new QQmlComponent(_qmlEngine);
|
||||
|
||||
|
||||
connect(_renderControl, &QQuickRenderControl::renderRequested, [this] { _render = true; });
|
||||
connect(_renderControl, &QQuickRenderControl::sceneChanged, [this] { _render = _polish = true; });
|
||||
connect(_renderControl, &QQuickRenderControl::renderRequested, this, [this] { _render = true; });
|
||||
connect(_renderControl, &QQuickRenderControl::sceneChanged, this, [this] { _render = _polish = true; });
|
||||
|
||||
if (!_canvas->makeCurrent()) {
|
||||
qWarning("Failed to make context current for QML Renderer");
|
||||
|
|
|
@ -70,6 +70,11 @@ bool saveToCache(const QUrl& url, const QByteArray& file) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool isValidFilePath(const AssetPath& filePath) {
|
||||
QRegExp filePathRegex { ASSET_FILE_PATH_REGEX_STRING };
|
||||
return filePathRegex.exactMatch(filePath);
|
||||
}
|
||||
|
||||
bool isValidPath(const AssetPath& path) {
|
||||
QRegExp pathRegex { ASSET_PATH_REGEX_STRING };
|
||||
return pathRegex.exactMatch(path);
|
||||
|
|
|
@ -31,7 +31,8 @@ const size_t SHA256_HASH_LENGTH = 32;
|
|||
const size_t SHA256_HASH_HEX_LENGTH = 64;
|
||||
const uint64_t MAX_UPLOAD_SIZE = 1000 * 1000 * 1000; // 1GB
|
||||
|
||||
const QString ASSET_PATH_REGEX_STRING = "^\\/(?!\\/)(?:[^\\/]|\\/(?!\\/))*$";
|
||||
const QString ASSET_FILE_PATH_REGEX_STRING = "^(\\/[^\\/\\0]+)+$";
|
||||
const QString ASSET_PATH_REGEX_STRING = "^\\/([^\\/\\0]+(\\/)?)+$";
|
||||
const QString ASSET_HASH_REGEX_STRING = QString("^[a-fA-F0-9]{%1}$").arg(SHA256_HASH_HEX_LENGTH);
|
||||
|
||||
enum AssetServerError : uint8_t {
|
||||
|
@ -59,6 +60,7 @@ QByteArray hashData(const QByteArray& data);
|
|||
QByteArray loadFromCache(const QUrl& url);
|
||||
bool saveToCache(const QUrl& url, const QByteArray& file);
|
||||
|
||||
bool isValidFilePath(const AssetPath& path);
|
||||
bool isValidPath(const AssetPath& path);
|
||||
bool isValidHash(const QString& hashString);
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ GetMappingRequest::GetMappingRequest(const AssetPath& path) : _path(path.trimmed
|
|||
void GetMappingRequest::doStart() {
|
||||
|
||||
// short circuit the request if the path is invalid
|
||||
if (!isValidPath(_path)) {
|
||||
if (!isValidFilePath(_path)) {
|
||||
_error = MappingRequest::InvalidPath;
|
||||
emit finished(this);
|
||||
return;
|
||||
|
@ -139,7 +139,7 @@ SetMappingRequest::SetMappingRequest(const AssetPath& path, const AssetHash& has
|
|||
void SetMappingRequest::doStart() {
|
||||
|
||||
// short circuit the request if the hash or path are invalid
|
||||
auto validPath = isValidPath(_path);
|
||||
auto validPath = isValidFilePath(_path);
|
||||
auto validHash = isValidHash(_hash);
|
||||
if (!validPath || !validHash) {
|
||||
_error = !validPath ? MappingRequest::InvalidPath : MappingRequest::InvalidHash;
|
||||
|
@ -226,7 +226,7 @@ RenameMappingRequest::RenameMappingRequest(const AssetPath& oldPath, const Asset
|
|||
void RenameMappingRequest::doStart() {
|
||||
|
||||
// short circuit the request if either of the paths are invalid
|
||||
if (!isValidPath(_oldPath) || !isValidPath(_newPath)) {
|
||||
if (!isValidFilePath(_oldPath) || !isValidFilePath(_newPath)) {
|
||||
_error = InvalidPath;
|
||||
emit finished(this);
|
||||
return;
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
#include <QtCore/QIODevice>
|
||||
|
||||
#include <PortableHighResolutionClock.h>
|
||||
|
||||
#include "../HifiSockAddr.h"
|
||||
#include "Constants.h"
|
||||
|
||||
|
@ -80,6 +82,9 @@ public:
|
|||
|
||||
qint64 writeString(const QString& string);
|
||||
QString readString();
|
||||
|
||||
void setReceiveTime(p_high_resolution_clock::time_point receiveTime) { _receiveTime = receiveTime; }
|
||||
p_high_resolution_clock::time_point getReceiveTime() const { return _receiveTime; }
|
||||
|
||||
template<typename T> qint64 peekPrimitive(T* data);
|
||||
template<typename T> qint64 readPrimitive(T* data);
|
||||
|
@ -108,6 +113,8 @@ protected:
|
|||
qint64 _payloadSize = 0; // How much of the payload is actually used
|
||||
|
||||
HifiSockAddr _senderSockAddr; // sender address for packet (only used on receiving end)
|
||||
|
||||
p_high_resolution_clock::time_point _receiveTime; // captures the time the packet received (only used on receiving end)
|
||||
};
|
||||
|
||||
template<typename T> qint64 BasePacket::peekPrimitive(T* data) {
|
||||
|
|
|
@ -45,11 +45,11 @@ DefaultCC::DefaultCC() :
|
|||
{
|
||||
_mss = udt::MAX_PACKET_SIZE_WITH_UDP_HEADER;
|
||||
|
||||
_congestionWindowSize = 16.0;
|
||||
_congestionWindowSize = 16;
|
||||
setPacketSendPeriod(1.0);
|
||||
}
|
||||
|
||||
void DefaultCC::onACK(SequenceNumber ackNum) {
|
||||
bool DefaultCC::onACK(SequenceNumber ackNum, p_high_resolution_clock::time_point receiveTime) {
|
||||
double increase = 0;
|
||||
|
||||
// Note from UDT original code:
|
||||
|
@ -61,7 +61,7 @@ void DefaultCC::onACK(SequenceNumber ackNum) {
|
|||
// we will only adjust once per sync interval so check that it has been at least that long now
|
||||
auto now = p_high_resolution_clock::now();
|
||||
if (duration_cast<microseconds>(now - _lastRCTime).count() < synInterval()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// our last rate increase time is now
|
||||
|
@ -93,13 +93,13 @@ void DefaultCC::onACK(SequenceNumber ackNum) {
|
|||
|
||||
// during slow start we perform no rate increases
|
||||
if (_slowStart) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// if loss has happened since the last rate increase we do not perform another increase
|
||||
if (_loss) {
|
||||
_loss = false;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
double capacitySpeedDelta = (_bandwidth - USECS_PER_SECOND / _packetSendPeriod);
|
||||
|
@ -132,6 +132,8 @@ void DefaultCC::onACK(SequenceNumber ackNum) {
|
|||
}
|
||||
|
||||
setPacketSendPeriod((_packetSendPeriod * synInterval()) / (_packetSendPeriod * increase + synInterval()));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void DefaultCC::onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) {
|
||||
|
@ -218,7 +220,7 @@ void DefaultCC::stopSlowStart() {
|
|||
// If no receiving rate is observed, we have to compute the sending
|
||||
// rate according to the current window size, and decrease it
|
||||
// using the method below.
|
||||
setPacketSendPeriod(_congestionWindowSize / (_rtt + synInterval()));
|
||||
setPacketSendPeriod(double(_congestionWindowSize) / (_rtt + synInterval()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,9 +40,18 @@ public:
|
|||
void setMaxBandwidth(int maxBandwidth);
|
||||
|
||||
virtual void init() {}
|
||||
virtual void onACK(SequenceNumber ackNum) {}
|
||||
|
||||
// return value specifies if connection should perform a fast re-transmit of ACK + 1 (used in TCP style congestion control)
|
||||
virtual bool onACK(SequenceNumber ackNum, p_high_resolution_clock::time_point receiveTime) { return false; }
|
||||
|
||||
virtual void onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) {}
|
||||
virtual void onTimeout() {}
|
||||
|
||||
virtual bool shouldNAK() { return true; }
|
||||
virtual bool shouldACK2() { return true; }
|
||||
virtual bool shouldProbe() { return true; }
|
||||
|
||||
virtual void onPacketSent(int wireSize, SequenceNumber seqNum, p_high_resolution_clock::time_point timePoint) {}
|
||||
protected:
|
||||
void setAckInterval(int ackInterval) { _ackInterval = ackInterval; }
|
||||
void setRTO(int rto) { _userDefinedRTO = true; _rto = rto; }
|
||||
|
@ -57,11 +66,11 @@ protected:
|
|||
void setPacketSendPeriod(double newSendPeriod); // call this internally to ensure send period doesn't go past max bandwidth
|
||||
|
||||
double _packetSendPeriod { 1.0 }; // Packet sending period, in microseconds
|
||||
double _congestionWindowSize { 16.0 }; // Congestion window size, in packets
|
||||
int _congestionWindowSize { 16 }; // Congestion window size, in packets
|
||||
|
||||
int _bandwidth { 0 }; // estimated bandwidth, packets per second
|
||||
std::atomic<int> _maxBandwidth { -1 }; // Maximum desired bandwidth, bits per second
|
||||
double _maxCongestionWindowSize { 0.0 }; // maximum cwnd size, in packets
|
||||
int _maxCongestionWindowSize { 0 }; // maximum cwnd size, in packets
|
||||
|
||||
int _mss { 0 }; // Maximum Packet Size, including all packet headers
|
||||
SequenceNumber _sendCurrSeqNum; // current maximum seq num sent out
|
||||
|
@ -102,7 +111,7 @@ public:
|
|||
DefaultCC();
|
||||
|
||||
public:
|
||||
virtual void onACK(SequenceNumber ackNum) override;
|
||||
virtual bool onACK(SequenceNumber ackNum, p_high_resolution_clock::time_point receiveTime) override;
|
||||
virtual void onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) override;
|
||||
virtual void onTimeout() override;
|
||||
|
||||
|
|
|
@ -118,12 +118,14 @@ SendQueue& Connection::getSendQueue() {
|
|||
QObject::connect(_sendQueue.get(), &SendQueue::queueInactive, this, &Connection::queueInactive);
|
||||
QObject::connect(_sendQueue.get(), &SendQueue::timeout, this, &Connection::queueTimeout);
|
||||
QObject::connect(_sendQueue.get(), &SendQueue::shortCircuitLoss, this, &Connection::queueShortCircuitLoss);
|
||||
|
||||
|
||||
// set defaults on the send queue from our congestion control object and estimatedTimeout()
|
||||
_sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod);
|
||||
_sendQueue->setSyncInterval(_synInterval);
|
||||
_sendQueue->setEstimatedTimeout(estimatedTimeout());
|
||||
_sendQueue->setFlowWindowSize(std::min(_flowWindowSize, (int) _congestionControl->_congestionWindowSize));
|
||||
_sendQueue->setProbePacketEnabled(_congestionControl->shouldProbe());
|
||||
|
||||
// give the randomized sequence number to the congestion control object
|
||||
_congestionControl->setInitialSendSequenceNumber(_sendQueue->getCurrentSequenceNumber());
|
||||
|
@ -150,13 +152,13 @@ void Connection::queueInactive() {
|
|||
}
|
||||
|
||||
void Connection::queueTimeout() {
|
||||
updateCongestionControlAndSendQueue([this]{
|
||||
updateCongestionControlAndSendQueue([this] {
|
||||
_congestionControl->onTimeout();
|
||||
});
|
||||
}
|
||||
|
||||
void Connection::queueShortCircuitLoss(quint32 sequenceNumber) {
|
||||
updateCongestionControlAndSendQueue([this, sequenceNumber]{
|
||||
updateCongestionControlAndSendQueue([this, sequenceNumber] {
|
||||
_congestionControl->onLoss(SequenceNumber { sequenceNumber }, SequenceNumber { sequenceNumber });
|
||||
});
|
||||
}
|
||||
|
@ -223,9 +225,11 @@ void Connection::sync() {
|
|||
// reset the number of light ACKs or non SYN ACKs during this sync interval
|
||||
_lightACKsDuringSYN = 1;
|
||||
_acksDuringSYN = 1;
|
||||
|
||||
// we send out a periodic ACK every rate control interval
|
||||
sendACK();
|
||||
|
||||
if (_congestionControl->_ackInterval > 1) {
|
||||
// we send out a periodic ACK every rate control interval
|
||||
sendACK();
|
||||
}
|
||||
|
||||
if (_lossList.getLength() > 0) {
|
||||
// check if we need to re-transmit a loss list
|
||||
|
@ -260,12 +264,17 @@ void Connection::sync() {
|
|||
}
|
||||
}
|
||||
|
||||
void Connection::recordSentPackets(int dataSize, int payloadSize) {
|
||||
_stats.recordSentPackets(payloadSize, dataSize);
|
||||
void Connection::recordSentPackets(int wireSize, int payloadSize,
|
||||
SequenceNumber seqNum, p_high_resolution_clock::time_point timePoint) {
|
||||
_stats.recordSentPackets(payloadSize, wireSize);
|
||||
|
||||
_congestionControl->onPacketSent(wireSize, seqNum, timePoint);
|
||||
}
|
||||
|
||||
void Connection::recordRetransmission() {
|
||||
void Connection::recordRetransmission(int wireSize, SequenceNumber seqNum, p_high_resolution_clock::time_point timePoint) {
|
||||
_stats.record(ConnectionStats::Stats::Retransmission);
|
||||
|
||||
_congestionControl->onPacketSent(wireSize, seqNum, timePoint);
|
||||
}
|
||||
|
||||
void Connection::sendACK(bool wasCausedBySyncTimeout) {
|
||||
|
@ -308,8 +317,8 @@ void Connection::sendACK(bool wasCausedBySyncTimeout) {
|
|||
|
||||
// pack the available buffer size, in packets
|
||||
// in our implementation we have no hard limit on receive buffer size, send the default value
|
||||
_ackPacket->writePrimitive((int32_t) udt::CONNECTION_RECEIVE_BUFFER_SIZE_PACKETS);
|
||||
|
||||
_ackPacket->writePrimitive((int32_t) udt::MAX_PACKETS_IN_FLIGHT);
|
||||
|
||||
if (wasCausedBySyncTimeout) {
|
||||
// grab the up to date packet receive speed and estimated bandwidth
|
||||
int32_t packetReceiveSpeed = _receiveWindow.getPacketReceiveSpeed();
|
||||
|
@ -475,23 +484,24 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in
|
|||
} else {
|
||||
_lossList.append(_lastReceivedSequenceNumber + 1, sequenceNumber - 1);
|
||||
}
|
||||
|
||||
// Send a NAK packet
|
||||
sendNAK(sequenceNumber);
|
||||
|
||||
// figure out when we should send the next loss report, if we haven't heard anything back
|
||||
_nakInterval = estimatedTimeout();
|
||||
|
||||
int receivedPacketsPerSecond = _receiveWindow.getPacketReceiveSpeed();
|
||||
if (receivedPacketsPerSecond > 0) {
|
||||
// the NAK interval is at least the _minNAKInterval
|
||||
// but might be the time required for all lost packets to be retransmitted
|
||||
_nakInterval += (int) (_lossList.getLength() * (USECS_PER_SECOND / receivedPacketsPerSecond));
|
||||
}
|
||||
|
||||
// the NAK interval is at least the _minNAKInterval but might be the value calculated above, if that is larger
|
||||
_nakInterval = std::max(_nakInterval, _minNAKInterval);
|
||||
|
||||
if (_congestionControl->shouldNAK()) {
|
||||
// Send a NAK packet
|
||||
sendNAK(sequenceNumber);
|
||||
|
||||
// figure out when we should send the next loss report, if we haven't heard anything back
|
||||
_nakInterval = estimatedTimeout();
|
||||
|
||||
int receivedPacketsPerSecond = _receiveWindow.getPacketReceiveSpeed();
|
||||
if (receivedPacketsPerSecond > 0) {
|
||||
// the NAK interval is at least the _minNAKInterval
|
||||
// but might be the time required for all lost packets to be retransmitted
|
||||
_nakInterval += (int) (_lossList.getLength() * (USECS_PER_SECOND / receivedPacketsPerSecond));
|
||||
}
|
||||
|
||||
// the NAK interval is at least the _minNAKInterval but might be the value calculated above, if that is larger
|
||||
_nakInterval = std::max(_nakInterval, _minNAKInterval);
|
||||
}
|
||||
}
|
||||
|
||||
bool wasDuplicate = false;
|
||||
|
@ -508,7 +518,10 @@ bool Connection::processReceivedSequenceNumber(SequenceNumber sequenceNumber, in
|
|||
++_packetsSinceACK;
|
||||
|
||||
// check if we need to send an ACK, according to CC params
|
||||
if (_congestionControl->_ackInterval > 0 && _packetsSinceACK >= _congestionControl->_ackInterval * _acksDuringSYN) {
|
||||
if (_congestionControl->_ackInterval == 1) {
|
||||
// using a congestion control that ACKs every packet (like TCP Vegas)
|
||||
sendACK(true);
|
||||
} else if (_congestionControl->_ackInterval > 0 && _packetsSinceACK >= _congestionControl->_ackInterval * _acksDuringSYN) {
|
||||
_acksDuringSYN++;
|
||||
sendACK(false);
|
||||
} else if (_congestionControl->_lightACKInterval > 0
|
||||
|
@ -598,7 +611,8 @@ void Connection::processACK(ControlPacketPointer controlPacket) {
|
|||
|
||||
microseconds sinceLastACK2 = duration_cast<microseconds>(currentTime - lastACK2SendTime);
|
||||
|
||||
if (sinceLastACK2.count() >= _synInterval || currentACKSubSequenceNumber == _lastSentACK2) {
|
||||
if (_congestionControl->shouldACK2()
|
||||
&& (sinceLastACK2.count() >= _synInterval || currentACKSubSequenceNumber == _lastSentACK2)) {
|
||||
// Send ACK2 packet
|
||||
sendACK2(currentACKSubSequenceNumber);
|
||||
|
||||
|
@ -678,8 +692,11 @@ void Connection::processACK(ControlPacketPointer controlPacket) {
|
|||
}
|
||||
|
||||
// give this ACK to the congestion control and update the send queue parameters
|
||||
updateCongestionControlAndSendQueue([this, ack](){
|
||||
_congestionControl->onACK(ack);
|
||||
updateCongestionControlAndSendQueue([this, ack, &controlPacket] {
|
||||
if (_congestionControl->onACK(ack, controlPacket->getReceiveTime())) {
|
||||
// the congestion control has told us it needs a fast re-transmit of ack + 1, add that now
|
||||
_sendQueue->fastRetransmit(ack + 1);
|
||||
}
|
||||
});
|
||||
|
||||
_stats.record(ConnectionStats::Stats::ProcessedACK);
|
||||
|
@ -764,7 +781,7 @@ void Connection::processNAK(ControlPacketPointer controlPacket) {
|
|||
getSendQueue().nak(start, end);
|
||||
|
||||
// give the loss to the congestion control object and update the send queue parameters
|
||||
updateCongestionControlAndSendQueue([this, start, end](){
|
||||
updateCongestionControlAndSendQueue([this, start, end] {
|
||||
_congestionControl->onLoss(start, end);
|
||||
});
|
||||
|
||||
|
|
|
@ -87,8 +87,8 @@ signals:
|
|||
void receiverHandshakeRequestComplete(const HifiSockAddr& sockAddr);
|
||||
|
||||
private slots:
|
||||
void recordSentPackets(int payload, int total);
|
||||
void recordRetransmission();
|
||||
void recordSentPackets(int wireSize, int payloadSize, SequenceNumber seqNum, p_high_resolution_clock::time_point timePoint);
|
||||
void recordRetransmission(int wireSize, SequenceNumber sequenceNumber, p_high_resolution_clock::time_point timePoint);
|
||||
void queueInactive();
|
||||
void queueTimeout();
|
||||
void queueShortCircuitLoss(quint32 sequenceNumber);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "SequenceNumber.h"
|
||||
|
||||
namespace udt {
|
||||
|
||||
static const int UDP_IPV4_HEADER_SIZE = 28;
|
||||
static const int MAX_PACKET_SIZE_WITH_UDP_HEADER = 1492;
|
||||
static const int MAX_PACKET_SIZE = MAX_PACKET_SIZE_WITH_UDP_HEADER - UDP_IPV4_HEADER_SIZE;
|
||||
|
|
|
@ -58,8 +58,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
|||
case PacketType::AssetGetInfo:
|
||||
case PacketType::AssetGet:
|
||||
case PacketType::AssetUpload:
|
||||
// Removal of extension from Asset requests
|
||||
return 18;
|
||||
return static_cast<PacketVersion>(AssetServerPacketVersion::VegasCongestionControl);
|
||||
case PacketType::NodeIgnoreRequest:
|
||||
return 18; // Introduction of node ignore request (which replaced an unused packet tpye)
|
||||
|
||||
|
|
|
@ -189,6 +189,10 @@ const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_SIMPLE_HULLS = 62;
|
|||
const PacketVersion VERSION_WEB_ENTITIES_SUPPORT_DPI = 63;
|
||||
const PacketVersion VERSION_ENTITIES_ARROW_ACTION = 64;
|
||||
|
||||
enum class AssetServerPacketVersion: PacketVersion {
|
||||
VegasCongestionControl = 19
|
||||
};
|
||||
|
||||
enum class AvatarMixerPacketVersion : PacketVersion {
|
||||
TranslationSupport = 17,
|
||||
SoftAttachmentSupport,
|
||||
|
|
|
@ -180,6 +180,16 @@ void SendQueue::nak(SequenceNumber start, SequenceNumber end) {
|
|||
_emptyCondition.notify_one();
|
||||
}
|
||||
|
||||
void SendQueue::fastRetransmit(udt::SequenceNumber ack) {
|
||||
{
|
||||
std::lock_guard<std::mutex> nakLocker(_naksLock);
|
||||
_naks.insert(ack, ack);
|
||||
}
|
||||
|
||||
// call notify_one on the condition_variable_any in case the send thread is sleeping waiting for losses to re-send
|
||||
_emptyCondition.notify_one();
|
||||
}
|
||||
|
||||
void SendQueue::overrideNAKListFromPacket(ControlPacket& packet) {
|
||||
// this is a response from the client, re-set our timeout expiry
|
||||
_lastReceiverResponse = QDateTime::currentMSecsSinceEpoch();
|
||||
|
@ -242,11 +252,13 @@ bool SendQueue::sendNewPacketAndAddToSentList(std::unique_ptr<Packet> newPacket,
|
|||
newPacket->writeSequenceNumber(sequenceNumber);
|
||||
|
||||
// Save packet/payload size before we move it
|
||||
auto packetSize = newPacket->getDataSize();
|
||||
auto packetSize = newPacket->getWireSize();
|
||||
auto payloadSize = newPacket->getPayloadSize();
|
||||
|
||||
auto bytesWritten = sendPacket(*newPacket);
|
||||
|
||||
emit packetSent(packetSize, payloadSize, sequenceNumber, p_high_resolution_clock::now());
|
||||
|
||||
{
|
||||
// Insert the packet we have just sent in the sent list
|
||||
QWriteLocker locker(&_sentLock);
|
||||
|
@ -256,8 +268,6 @@ bool SendQueue::sendNewPacketAndAddToSentList(std::unique_ptr<Packet> newPacket,
|
|||
}
|
||||
Q_ASSERT_X(!newPacket, "SendQueue::sendNewPacketAndAddToSentList()", "Overriden packet in sent list");
|
||||
|
||||
emit packetSent(packetSize, payloadSize);
|
||||
|
||||
if (bytesWritten < 0) {
|
||||
// this is a short-circuit loss - we failed to put this packet on the wire
|
||||
// so immediately add it to the loss list
|
||||
|
@ -328,60 +338,66 @@ void SendQueue::run() {
|
|||
return;
|
||||
}
|
||||
|
||||
// push the next packet timestamp forwards by the current packet send period
|
||||
auto nextPacketDelta = (newPacketCount == 2 ? 2 : 1) * _packetSendPeriod;
|
||||
nextPacketTimestamp += std::chrono::microseconds(nextPacketDelta);
|
||||
if (_packetSendPeriod > 0) {
|
||||
// push the next packet timestamp forwards by the current packet send period
|
||||
auto nextPacketDelta = (newPacketCount == 2 ? 2 : 1) * _packetSendPeriod;
|
||||
nextPacketTimestamp += std::chrono::microseconds(nextPacketDelta);
|
||||
|
||||
// sleep as long as we need for next packet send, if we can
|
||||
auto now = p_high_resolution_clock::now();
|
||||
// sleep as long as we need for next packet send, if we can
|
||||
auto now = p_high_resolution_clock::now();
|
||||
|
||||
auto timeToSleep = duration_cast<microseconds>(nextPacketTimestamp - now);
|
||||
auto timeToSleep = duration_cast<microseconds>(nextPacketTimestamp - now);
|
||||
|
||||
// we use nextPacketTimestamp so that we don't fall behind, not to force long sleeps
|
||||
// we'll never allow nextPacketTimestamp to force us to sleep for more than nextPacketDelta
|
||||
// so cap it to that value
|
||||
if (timeToSleep > std::chrono::microseconds(nextPacketDelta)) {
|
||||
// reset the nextPacketTimestamp so that it is correct next time we come around
|
||||
nextPacketTimestamp = now + std::chrono::microseconds(nextPacketDelta);
|
||||
// we use nextPacketTimestamp so that we don't fall behind, not to force long sleeps
|
||||
// we'll never allow nextPacketTimestamp to force us to sleep for more than nextPacketDelta
|
||||
// so cap it to that value
|
||||
if (timeToSleep > std::chrono::microseconds(nextPacketDelta)) {
|
||||
// reset the nextPacketTimestamp so that it is correct next time we come around
|
||||
nextPacketTimestamp = now + std::chrono::microseconds(nextPacketDelta);
|
||||
|
||||
timeToSleep = std::chrono::microseconds(nextPacketDelta);
|
||||
}
|
||||
timeToSleep = std::chrono::microseconds(nextPacketDelta);
|
||||
}
|
||||
|
||||
// we're seeing SendQueues sleep for a long period of time here,
|
||||
// which can lock the NodeList if it's attempting to clear connections
|
||||
// for now we guard this by capping the time this thread and sleep for
|
||||
// we're seeing SendQueues sleep for a long period of time here,
|
||||
// which can lock the NodeList if it's attempting to clear connections
|
||||
// for now we guard this by capping the time this thread and sleep for
|
||||
|
||||
const microseconds MAX_SEND_QUEUE_SLEEP_USECS { 2000000 };
|
||||
if (timeToSleep > MAX_SEND_QUEUE_SLEEP_USECS) {
|
||||
qWarning() << "udt::SendQueue wanted to sleep for" << timeToSleep.count() << "microseconds";
|
||||
qWarning() << "Capping sleep to" << MAX_SEND_QUEUE_SLEEP_USECS.count();
|
||||
qWarning() << "PSP:" << _packetSendPeriod << "NPD:" << nextPacketDelta
|
||||
const microseconds MAX_SEND_QUEUE_SLEEP_USECS { 2000000 };
|
||||
if (timeToSleep > MAX_SEND_QUEUE_SLEEP_USECS) {
|
||||
qWarning() << "udt::SendQueue wanted to sleep for" << timeToSleep.count() << "microseconds";
|
||||
qWarning() << "Capping sleep to" << MAX_SEND_QUEUE_SLEEP_USECS.count();
|
||||
qWarning() << "PSP:" << _packetSendPeriod << "NPD:" << nextPacketDelta
|
||||
<< "NPT:" << nextPacketTimestamp.time_since_epoch().count()
|
||||
<< "NOW:" << now.time_since_epoch().count();
|
||||
|
||||
// alright, we're in a weird state
|
||||
// we want to know why this is happening so we can implement a better fix than this guard
|
||||
// send some details up to the API (if the user allows us) that indicate how we could such a large timeToSleep
|
||||
static const QString SEND_QUEUE_LONG_SLEEP_ACTION = "sendqueue-sleep";
|
||||
// alright, we're in a weird state
|
||||
// we want to know why this is happening so we can implement a better fix than this guard
|
||||
// send some details up to the API (if the user allows us) that indicate how we could such a large timeToSleep
|
||||
static const QString SEND_QUEUE_LONG_SLEEP_ACTION = "sendqueue-sleep";
|
||||
|
||||
// setup a json object with the details we want
|
||||
QJsonObject longSleepObject;
|
||||
longSleepObject["timeToSleep"] = qint64(timeToSleep.count());
|
||||
longSleepObject["packetSendPeriod"] = _packetSendPeriod.load();
|
||||
longSleepObject["nextPacketDelta"] = nextPacketDelta;
|
||||
longSleepObject["nextPacketTimestamp"] = qint64(nextPacketTimestamp.time_since_epoch().count());
|
||||
longSleepObject["then"] = qint64(now.time_since_epoch().count());
|
||||
// setup a json object with the details we want
|
||||
QJsonObject longSleepObject;
|
||||
longSleepObject["timeToSleep"] = qint64(timeToSleep.count());
|
||||
longSleepObject["packetSendPeriod"] = _packetSendPeriod.load();
|
||||
longSleepObject["nextPacketDelta"] = nextPacketDelta;
|
||||
longSleepObject["nextPacketTimestamp"] = qint64(nextPacketTimestamp.time_since_epoch().count());
|
||||
longSleepObject["then"] = qint64(now.time_since_epoch().count());
|
||||
|
||||
// hopefully send this event using the user activity logger
|
||||
UserActivityLogger::getInstance().logAction(SEND_QUEUE_LONG_SLEEP_ACTION, longSleepObject);
|
||||
|
||||
timeToSleep = MAX_SEND_QUEUE_SLEEP_USECS;
|
||||
// hopefully send this event using the user activity logger
|
||||
UserActivityLogger::getInstance().logAction(SEND_QUEUE_LONG_SLEEP_ACTION, longSleepObject);
|
||||
|
||||
timeToSleep = MAX_SEND_QUEUE_SLEEP_USECS;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(timeToSleep);
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(timeToSleep);
|
||||
}
|
||||
}
|
||||
|
||||
void SendQueue::setProbePacketEnabled(bool enabled) {
|
||||
_shouldSendProbes = enabled;
|
||||
}
|
||||
|
||||
int SendQueue::maybeSendNewPacket() {
|
||||
if (!isFlowWindowFull()) {
|
||||
// we didn't re-send a packet, so time to send a new one
|
||||
|
@ -399,7 +415,7 @@ int SendQueue::maybeSendNewPacket() {
|
|||
std::unique_ptr<Packet> secondPacket;
|
||||
bool shouldSendPairTail = false;
|
||||
|
||||
if (((uint32_t) nextNumber & 0xF) == 0) {
|
||||
if (_shouldSendProbes && ((uint32_t) nextNumber & 0xF) == 0) {
|
||||
// the first packet is the first in a probe pair - every 16 (rightmost 16 bits = 0) packets
|
||||
// pull off a second packet if we can before we unlock
|
||||
shouldSendPairTail = true;
|
||||
|
@ -492,7 +508,7 @@ bool SendQueue::maybeResendPacket() {
|
|||
sentLocker.unlock();
|
||||
}
|
||||
|
||||
emit packetRetransmitted();
|
||||
emit packetRetransmitted(resendPacket.getWireSize(), it->first, p_high_resolution_clock::now());
|
||||
|
||||
// Signal that we did resend a packet
|
||||
return true;
|
||||
|
|
|
@ -64,18 +64,21 @@ public:
|
|||
|
||||
void setEstimatedTimeout(int estimatedTimeout) { _estimatedTimeout = estimatedTimeout; }
|
||||
void setSyncInterval(int syncInterval) { _syncInterval = syncInterval; }
|
||||
|
||||
void setProbePacketEnabled(bool enabled);
|
||||
|
||||
public slots:
|
||||
void stop();
|
||||
|
||||
void ack(SequenceNumber ack);
|
||||
void nak(SequenceNumber start, SequenceNumber end);
|
||||
void fastRetransmit(SequenceNumber ack);
|
||||
void overrideNAKListFromPacket(ControlPacket& packet);
|
||||
void handshakeACK(SequenceNumber initialSequenceNumber);
|
||||
|
||||
signals:
|
||||
void packetSent(int dataSize, int payloadSize);
|
||||
void packetRetransmitted();
|
||||
void packetSent(int wireSize, int payloadSize, SequenceNumber seqNum, p_high_resolution_clock::time_point timePoint);
|
||||
void packetRetransmitted(int wireSize, SequenceNumber seqNum, p_high_resolution_clock::time_point timePoint);
|
||||
|
||||
void queueInactive();
|
||||
|
||||
|
@ -139,6 +142,9 @@ private:
|
|||
std::condition_variable _handshakeACKCondition;
|
||||
|
||||
std::condition_variable_any _emptyCondition;
|
||||
|
||||
|
||||
std::atomic<bool> _shouldSendProbes { true };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,14 @@
|
|||
|
||||
#include "SequenceNumber.h"
|
||||
|
||||
#include <QtCore/QMetaType>
|
||||
|
||||
using namespace udt;
|
||||
|
||||
Q_DECLARE_METATYPE(SequenceNumber);
|
||||
|
||||
int sequenceNumberMetaTypeID = qRegisterMetaType<SequenceNumber>();
|
||||
|
||||
int udt::seqlen(const SequenceNumber& seq1, const SequenceNumber& seq2) {
|
||||
return (seq1._value <= seq2._value) ? (seq2._value - seq1._value + 1)
|
||||
: (seq2._value - seq1._value + SequenceNumber::MAX + 2);
|
||||
|
|
|
@ -118,8 +118,14 @@ qint64 Socket::writeBasePacket(const udt::BasePacket& packet, const HifiSockAddr
|
|||
qint64 Socket::writePacket(const Packet& packet, const HifiSockAddr& sockAddr) {
|
||||
Q_ASSERT_X(!packet.isReliable(), "Socket::writePacket", "Cannot send a reliable packet unreliably");
|
||||
|
||||
SequenceNumber sequenceNumber;
|
||||
{
|
||||
Lock lock(_unreliableSequenceNumbersMutex);
|
||||
sequenceNumber = ++_unreliableSequenceNumbers[sockAddr];
|
||||
}
|
||||
|
||||
// write the correct sequence number to the Packet here
|
||||
packet.writeSequenceNumber(++_unreliableSequenceNumbers[sockAddr]);
|
||||
packet.writeSequenceNumber(sequenceNumber);
|
||||
|
||||
return writeDatagram(packet.getData(), packet.getDataSize(), sockAddr);
|
||||
}
|
||||
|
@ -289,6 +295,9 @@ void Socket::messageFailed(Connection* connection, Packet::MessageNumber message
|
|||
void Socket::readPendingDatagrams() {
|
||||
int packetSizeWithHeader = -1;
|
||||
while ((packetSizeWithHeader = _udpSocket.pendingDatagramSize()) != -1) {
|
||||
// grab a time point we can mark as the receive time of this packet
|
||||
auto receiveTime = p_high_resolution_clock::now();
|
||||
|
||||
// setup a HifiSockAddr to read into
|
||||
HifiSockAddr senderSockAddr;
|
||||
|
||||
|
@ -311,6 +320,7 @@ void Socket::readPendingDatagrams() {
|
|||
// we have a registered unfiltered handler for this HifiSockAddr - call that and return
|
||||
if (it->second) {
|
||||
auto basePacket = BasePacket::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr);
|
||||
basePacket->setReceiveTime(receiveTime);
|
||||
it->second(std::move(basePacket));
|
||||
}
|
||||
|
||||
|
@ -323,6 +333,7 @@ void Socket::readPendingDatagrams() {
|
|||
if (isControlPacket) {
|
||||
// setup a control packet from the data we just read
|
||||
auto controlPacket = ControlPacket::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr);
|
||||
controlPacket->setReceiveTime(receiveTime);
|
||||
|
||||
// move this control packet to the matching connection, if there is one
|
||||
auto connection = findOrCreateConnection(senderSockAddr);
|
||||
|
@ -334,6 +345,7 @@ void Socket::readPendingDatagrams() {
|
|||
} else {
|
||||
// setup a Packet from the data we just read
|
||||
auto packet = Packet::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr);
|
||||
packet->setReceiveTime(receiveTime);
|
||||
|
||||
// call our verification operator to see if this packet is verified
|
||||
if (!_packetFilterOperator || _packetFilterOperator(*packet)) {
|
||||
|
|
|
@ -16,13 +16,14 @@
|
|||
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtNetwork/QUdpSocket>
|
||||
|
||||
#include "../HifiSockAddr.h"
|
||||
#include "CongestionControl.h"
|
||||
#include "TCPVegasCC.h"
|
||||
#include "Connection.h"
|
||||
|
||||
//#define UDT_CONNECTION_DEBUG
|
||||
|
@ -46,6 +47,10 @@ using MessageFailureHandler = std::function<void(HifiSockAddr, udt::Packet::Mess
|
|||
|
||||
class Socket : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
using Mutex = std::mutex;
|
||||
using Lock = std::unique_lock<Mutex>;
|
||||
|
||||
public:
|
||||
using StatsVector = std::vector<std::pair<HifiSockAddr, ConnectionStats::Stats>>;
|
||||
|
||||
|
@ -121,7 +126,9 @@ private:
|
|||
MessageHandler _messageHandler;
|
||||
MessageFailureHandler _messageFailureHandler;
|
||||
ConnectionCreationFilterOperator _connectionCreationFilterOperator;
|
||||
|
||||
|
||||
Mutex _unreliableSequenceNumbersMutex;
|
||||
|
||||
std::unordered_map<HifiSockAddr, BasePacketHandler> _unfilteredHandlers;
|
||||
std::unordered_map<HifiSockAddr, SequenceNumber> _unreliableSequenceNumbers;
|
||||
std::unordered_map<HifiSockAddr, std::unique_ptr<Connection>> _connectionsHash;
|
||||
|
@ -130,8 +137,8 @@ private:
|
|||
QTimer* _synTimer { nullptr };
|
||||
|
||||
int _maxBandwidth { -1 };
|
||||
|
||||
std::unique_ptr<CongestionControlVirtualFactory> _ccFactory { new CongestionControlFactory<DefaultCC>() };
|
||||
|
||||
std::unique_ptr<CongestionControlVirtualFactory> _ccFactory { new CongestionControlFactory<TCPVegasCC>() };
|
||||
|
||||
friend UDTTest;
|
||||
};
|
||||
|
|
282
libraries/networking/src/udt/TCPVegasCC.cpp
Normal file
282
libraries/networking/src/udt/TCPVegasCC.cpp
Normal file
|
@ -0,0 +1,282 @@
|
|||
//
|
||||
// TCPVegasCC.cpp
|
||||
// libraries/networking/src/udt
|
||||
//
|
||||
// Created by Stephen Birarda on 2016-09-20.
|
||||
// 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
|
||||
//
|
||||
|
||||
#include "TCPVegasCC.h"
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QtGlobal>
|
||||
|
||||
using namespace udt;
|
||||
using namespace std::chrono;
|
||||
|
||||
TCPVegasCC::TCPVegasCC() {
|
||||
_packetSendPeriod = 0.0;
|
||||
_congestionWindowSize = 2;
|
||||
|
||||
setAckInterval(1); // TCP sends an ACK for every packet received
|
||||
|
||||
// set our minimum RTT variables to the maximum possible value
|
||||
// we can't do this as a member initializer until our VS has support for constexpr
|
||||
_currentMinRTT = std::numeric_limits<int>::max();
|
||||
_baseRTT = std::numeric_limits<int>::max();
|
||||
}
|
||||
|
||||
bool TCPVegasCC::onACK(SequenceNumber ack, p_high_resolution_clock::time_point receiveTime) {
|
||||
auto it = _sentPacketTimes.find(ack);
|
||||
|
||||
auto previousAck = _lastACK;
|
||||
_lastACK = ack;
|
||||
|
||||
if (it != _sentPacketTimes.end()) {
|
||||
|
||||
// calculate the RTT (receive time - time ACK sent)
|
||||
int lastRTT = duration_cast<microseconds>(receiveTime - it->second).count();
|
||||
|
||||
const int MAX_RTT_SAMPLE_MICROSECONDS = 10000000;
|
||||
|
||||
if (lastRTT < 0) {
|
||||
Q_ASSERT_X(false, __FUNCTION__, "calculated an RTT that is not > 0");
|
||||
return false;
|
||||
} else if (lastRTT == 0) {
|
||||
// we do not allow a zero microsecond RTT (as per the UNIX kernel implementation of TCP Vegas)
|
||||
lastRTT = 1;
|
||||
} else if (lastRTT > MAX_RTT_SAMPLE_MICROSECONDS) {
|
||||
// we cap the lastRTT to MAX_RTT_SAMPLE_MICROSECONDS to avoid overflows in window size calculations
|
||||
lastRTT = MAX_RTT_SAMPLE_MICROSECONDS;
|
||||
}
|
||||
|
||||
if (_ewmaRTT == -1) {
|
||||
// first RTT sample - set _ewmaRTT to the value and set the variance to half the value
|
||||
_ewmaRTT = lastRTT;
|
||||
_rttVariance = lastRTT / 2;
|
||||
} else {
|
||||
// This updates the RTT using exponential weighted moving average
|
||||
// This is the Jacobson's forumla for RTT estimation
|
||||
// http://www.mathcs.emory.edu/~cheung/Courses/455/Syllabus/7-transport/Jacobson-88.pdf
|
||||
|
||||
// Estimated RTT = (1 - x)(estimatedRTT) + (x)(sampleRTT)
|
||||
// (where x = 0.125 via Jacobson)
|
||||
|
||||
// Deviation = (1 - x)(deviation) + x |sampleRTT - estimatedRTT|
|
||||
// (where x = 0.25 via Jacobson)
|
||||
|
||||
static const int RTT_ESTIMATION_ALPHA = 8;
|
||||
static const int RTT_ESTIMATION_VARIANCE_ALPHA = 4;
|
||||
|
||||
_ewmaRTT = (_ewmaRTT * (RTT_ESTIMATION_ALPHA - 1) + lastRTT) / RTT_ESTIMATION_ALPHA;
|
||||
_rttVariance = (_rttVariance * (RTT_ESTIMATION_VARIANCE_ALPHA- 1)
|
||||
+ abs(lastRTT - _ewmaRTT)) / RTT_ESTIMATION_VARIANCE_ALPHA;
|
||||
}
|
||||
|
||||
// add 1 to the number of ACKs during this RTT
|
||||
++_numACKs;
|
||||
|
||||
// keep track of the lowest RTT during connection
|
||||
_baseRTT = std::min(_baseRTT, lastRTT);
|
||||
|
||||
// find the min RTT during the last RTT
|
||||
_currentMinRTT = std::min(_currentMinRTT, lastRTT);
|
||||
|
||||
auto sinceLastAdjustment = duration_cast<microseconds>(p_high_resolution_clock::now() - _lastAdjustmentTime).count();
|
||||
if (sinceLastAdjustment >= _ewmaRTT) {
|
||||
performCongestionAvoidance(ack);
|
||||
}
|
||||
|
||||
// remove this sent packet time from the hash
|
||||
_sentPacketTimes.erase(it);
|
||||
}
|
||||
|
||||
++_numACKSinceFastRetransmit;
|
||||
|
||||
// perform the fast re-transmit check if this is a duplicate ACK or if this is the first or second ACK
|
||||
// after a previous fast re-transmit
|
||||
if (ack == previousAck || _numACKSinceFastRetransmit < 3) {
|
||||
// we may need to re-send ackNum + 1 if it has been more than our estimated timeout since it was sent
|
||||
|
||||
auto it = _sentPacketTimes.find(ack + 1);
|
||||
if (it != _sentPacketTimes.end()) {
|
||||
auto estimatedTimeout = _ewmaRTT + _rttVariance * 4;
|
||||
|
||||
auto now = p_high_resolution_clock::now();
|
||||
auto sinceSend = duration_cast<microseconds>(now - it->second).count();
|
||||
|
||||
if (sinceSend >= estimatedTimeout) {
|
||||
// break out of slow start, we've decided this is loss
|
||||
_slowStart = false;
|
||||
|
||||
// reset the fast re-transmit counter
|
||||
_numACKSinceFastRetransmit = 0;
|
||||
|
||||
// return true so the caller knows we needed a fast re-transmit
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// if this is the 3rd duplicate ACK, we fallback to Reno's fast re-transmit
|
||||
static const int RENO_FAST_RETRANSMIT_DUPLICATE_COUNT = 3;
|
||||
|
||||
++_duplicateACKCount;
|
||||
|
||||
if (ack == previousAck && _duplicateACKCount == RENO_FAST_RETRANSMIT_DUPLICATE_COUNT) {
|
||||
// break out of slow start, we just hit loss
|
||||
_slowStart = false;
|
||||
|
||||
// reset our fast re-transmit counters
|
||||
_numACKSinceFastRetransmit = 0;
|
||||
_duplicateACKCount = 0;
|
||||
|
||||
// return true so the caller knows we needed a fast re-transmit
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
_duplicateACKCount = 0;
|
||||
}
|
||||
|
||||
// ACK processed, no fast re-transmit required
|
||||
return false;
|
||||
}
|
||||
|
||||
void TCPVegasCC::performCongestionAvoidance(udt::SequenceNumber ack) {
|
||||
static int VEGAS_ALPHA_SEGMENTS = 4;
|
||||
static int VEGAS_BETA_SEGMENTS = 6;
|
||||
static int VEGAS_GAMMA_SEGMENTS = 1;
|
||||
|
||||
// http://pages.cs.wisc.edu/~akella/CS740/S08/740-Papers/BOP94.pdf
|
||||
// Use the Vegas algorithm to see if we should
|
||||
// increase or decrease the congestion window size, and by how much
|
||||
|
||||
// Grab the minimum RTT seen during the last RTT (since the last performed congestion avoidance)
|
||||
|
||||
// Taking the min avoids the effects of delayed ACKs
|
||||
// (though congestion may be noticed a bit later)
|
||||
int rtt = _currentMinRTT;
|
||||
|
||||
int64_t windowSizeDiff = (int64_t) _congestionWindowSize * (rtt - _baseRTT) / _baseRTT;
|
||||
|
||||
if (_numACKs <= 2) {
|
||||
performRenoCongestionAvoidance(ack);
|
||||
} else {
|
||||
if (_slowStart) {
|
||||
if (windowSizeDiff > VEGAS_GAMMA_SEGMENTS) {
|
||||
// we're going too fast - this breaks us out of slow start and we switch to linear increase/decrease
|
||||
_slowStart = false;
|
||||
|
||||
int expectedWindowSize = _congestionWindowSize * _baseRTT / rtt;
|
||||
_baseRTT = std::numeric_limits<int>::max();
|
||||
|
||||
// drop the congestion window size to the expected size, if smaller
|
||||
_congestionWindowSize = std::min(_congestionWindowSize, expectedWindowSize + 1);
|
||||
|
||||
} else if (++_slowStartOddAdjust & 1) {
|
||||
// we're in slow start and not going too fast
|
||||
// this means that once every second RTT we perform exponential congestion window growth
|
||||
_congestionWindowSize *= 2;
|
||||
}
|
||||
} else {
|
||||
// this is the normal linear increase/decrease of the Vegas algorithm
|
||||
// to figure out where the congestion window should be
|
||||
if (windowSizeDiff > VEGAS_BETA_SEGMENTS) {
|
||||
// the old congestion window was too fast (difference > beta)
|
||||
// so reduce it to slow down
|
||||
--_congestionWindowSize;
|
||||
|
||||
} else if (windowSizeDiff < VEGAS_ALPHA_SEGMENTS) {
|
||||
// there aren't enough packets on the wire, add more to the congestion window
|
||||
++_congestionWindowSize;
|
||||
} else {
|
||||
// sending rate seems good, no congestion window adjustment
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we never allow the congestion window to be smaller than two packets
|
||||
static int VEGAS_CW_MIN_PACKETS = 2;
|
||||
if (_congestionWindowSize < VEGAS_CW_MIN_PACKETS) {
|
||||
_congestionWindowSize = VEGAS_CW_MIN_PACKETS;
|
||||
} else if (_congestionWindowSize > udt::MAX_PACKETS_IN_FLIGHT) {
|
||||
_congestionWindowSize = udt::MAX_PACKETS_IN_FLIGHT;
|
||||
}
|
||||
|
||||
// mark this as the last adjustment time
|
||||
_lastAdjustmentTime = p_high_resolution_clock::now();
|
||||
|
||||
// reset our state for the next RTT
|
||||
_currentMinRTT = std::numeric_limits<int>::max();
|
||||
|
||||
// reset our count of collected RTT samples
|
||||
_numACKs = 0;
|
||||
}
|
||||
|
||||
bool TCPVegasCC::isCongestionWindowLimited() {
|
||||
if (_slowStart) {
|
||||
return true;
|
||||
} else {
|
||||
return seqlen(_sendCurrSeqNum, _lastACK) < _congestionWindowSize;
|
||||
}
|
||||
}
|
||||
|
||||
void TCPVegasCC::performRenoCongestionAvoidance(SequenceNumber ack) {
|
||||
if (!isCongestionWindowLimited()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int numAcked = _numACKs;
|
||||
|
||||
if (_slowStart) {
|
||||
// while in slow start we grow the congestion window by the number of ACKed packets
|
||||
// allowing it to grow as high as the slow start threshold
|
||||
int congestionWindow = _congestionWindowSize + numAcked;
|
||||
|
||||
if (congestionWindow > udt::MAX_PACKETS_IN_FLIGHT) {
|
||||
// we're done with slow start, set the congestion window to the slow start threshold
|
||||
_congestionWindowSize = udt::MAX_PACKETS_IN_FLIGHT;
|
||||
|
||||
// figure out how many left over ACKs we should apply using the regular reno congestion avoidance
|
||||
numAcked = congestionWindow - udt::MAX_PACKETS_IN_FLIGHT;
|
||||
} else {
|
||||
_congestionWindowSize = congestionWindow;
|
||||
numAcked = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// grab the size of the window prior to reno additive increase
|
||||
int preAIWindowSize = _congestionWindowSize;
|
||||
|
||||
if (numAcked > 0) {
|
||||
// Once we are out of slow start, we use additive increase to grow the window slowly.
|
||||
// We grow the congestion window by a single packet everytime the entire congestion window is sent.
|
||||
|
||||
// If credits accumulated at a higher preAIWindowSize, apply them gently now.
|
||||
if (_ackAICount >= preAIWindowSize) {
|
||||
_ackAICount = 0;
|
||||
++_congestionWindowSize;
|
||||
}
|
||||
|
||||
// increase the window size by (1 / window size) for every ACK received
|
||||
_ackAICount += numAcked;
|
||||
if (_ackAICount >= preAIWindowSize) {
|
||||
// when _ackAICount % preAIWindowSize == 0 then _ackAICount is 0
|
||||
// when _ackAICount % preAIWindowSize != 0 then _ackAICount is _ackAICount - (_ackAICount % preAIWindowSize)
|
||||
|
||||
int delta = _ackAICount / preAIWindowSize;
|
||||
|
||||
_ackAICount -= delta * preAIWindowSize;
|
||||
_congestionWindowSize += delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TCPVegasCC::onPacketSent(int wireSize, SequenceNumber seqNum, p_high_resolution_clock::time_point timePoint) {
|
||||
if (_sentPacketTimes.find(seqNum) == _sentPacketTimes.end()) {
|
||||
_sentPacketTimes[seqNum] = timePoint;
|
||||
}
|
||||
}
|
||||
|
77
libraries/networking/src/udt/TCPVegasCC.h
Normal file
77
libraries/networking/src/udt/TCPVegasCC.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
//
|
||||
// TCPVegasCC.h
|
||||
// libraries/networking/src/udt
|
||||
//
|
||||
// Created by Stephen Birarda on 2016-09-20.
|
||||
// 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
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef hifi_TCPVegasCC_h
|
||||
#define hifi_TCPVegasCC_h
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "CongestionControl.h"
|
||||
#include "Constants.h"
|
||||
|
||||
namespace udt {
|
||||
|
||||
|
||||
class TCPVegasCC : public CongestionControl {
|
||||
public:
|
||||
TCPVegasCC();
|
||||
|
||||
virtual bool onACK(SequenceNumber ackNum, p_high_resolution_clock::time_point receiveTime) override;
|
||||
virtual void onLoss(SequenceNumber rangeStart, SequenceNumber rangeEnd) override {};
|
||||
virtual void onTimeout() override {};
|
||||
|
||||
virtual bool shouldNAK() override { return false; }
|
||||
virtual bool shouldACK2() override { return false; }
|
||||
virtual bool shouldProbe() override { return false; }
|
||||
|
||||
virtual void onPacketSent(int wireSize, SequenceNumber seqNum, p_high_resolution_clock::time_point timePoint) override;
|
||||
|
||||
protected:
|
||||
virtual void performCongestionAvoidance(SequenceNumber ack);
|
||||
virtual void setInitialSendSequenceNumber(SequenceNumber seqNum) override { _lastACK = seqNum - 1; }
|
||||
private:
|
||||
bool isCongestionWindowLimited();
|
||||
void performRenoCongestionAvoidance(SequenceNumber ack);
|
||||
|
||||
using PacketTimeList = std::map<SequenceNumber, p_high_resolution_clock::time_point>;
|
||||
PacketTimeList _sentPacketTimes; // Map of sequence numbers to sent time
|
||||
|
||||
p_high_resolution_clock::time_point _lastAdjustmentTime; // Time of last congestion control adjustment
|
||||
|
||||
bool _slowStart { true }; // Marker for slow start phase
|
||||
|
||||
SequenceNumber _lastACK; // Sequence number of last packet that was ACKed
|
||||
|
||||
int _numACKSinceFastRetransmit { 3 }; // Number of ACKs received since fast re-transmit, default avoids immediate re-transmit
|
||||
|
||||
int _currentMinRTT; // Current min RTT during last RTT (since last congestion avoidance check), in microseconds
|
||||
int _baseRTT; // Lowest RTT during connection, in microseconds
|
||||
int _ewmaRTT { -1 }; // Exponential weighted moving average RTT
|
||||
int _rttVariance { 0 }; // Variance in collected RTT values
|
||||
|
||||
int _numACKs { 0 }; // Number of ACKs received during the last RTT (since last performed congestion avoidance)
|
||||
|
||||
int _ackAICount { 0 }; // Counter for number of ACKs received for Reno additive increase
|
||||
int _duplicateACKCount { 0 }; // Counter for duplicate ACKs received
|
||||
|
||||
int _slowStartOddAdjust { 0 }; // Marker for every window adjustment every other RTT in slow-start
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // hifi_TCPVegasCC_h
|
|
@ -29,6 +29,14 @@
|
|||
|
||||
|
||||
Antialiasing::Antialiasing() {
|
||||
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
|
||||
}
|
||||
|
||||
Antialiasing::~Antialiasing() {
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (geometryCache) {
|
||||
geometryCache->releaseID(_geometryId);
|
||||
}
|
||||
}
|
||||
|
||||
const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() {
|
||||
|
@ -150,7 +158,7 @@ void Antialiasing::run(const render::SceneContextPointer& sceneContext, const re
|
|||
glm::vec2 topRight(1.0f, 1.0f);
|
||||
glm::vec2 texCoordTopLeft(0.0f, 0.0f);
|
||||
glm::vec2 texCoordBottomRight(1.0f, 1.0f);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color, _geometryId);
|
||||
|
||||
|
||||
// Blend step
|
||||
|
@ -159,6 +167,6 @@ void Antialiasing::run(const render::SceneContextPointer& sceneContext, const re
|
|||
batch.setFramebuffer(sourceBuffer);
|
||||
batch.setPipeline(getBlendPipeline());
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color, _geometryId);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ public:
|
|||
using JobModel = render::Job::ModelI<Antialiasing, gpu::FramebufferPointer, Config>;
|
||||
|
||||
Antialiasing();
|
||||
~Antialiasing();
|
||||
void configure(const Config& config) {}
|
||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& sourceBuffer);
|
||||
|
||||
|
@ -46,7 +47,7 @@ private:
|
|||
|
||||
gpu::PipelinePointer _antialiasingPipeline;
|
||||
gpu::PipelinePointer _blendPipeline;
|
||||
|
||||
int _geometryId { 0 };
|
||||
};
|
||||
|
||||
#endif // hifi_AntialiasingEffect_h
|
||||
|
|
|
@ -237,6 +237,14 @@ DebugDeferredBuffer::DebugDeferredBuffer() {
|
|||
CustomPipeline pipeline;
|
||||
pipeline.info = QFileInfo(QString::fromStdString(CUSTOM_FILE));
|
||||
_customPipelines.emplace(CUSTOM_FILE, pipeline);
|
||||
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
|
||||
}
|
||||
|
||||
DebugDeferredBuffer::~DebugDeferredBuffer() {
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (geometryCache) {
|
||||
geometryCache->releaseID(_geometryId);
|
||||
}
|
||||
}
|
||||
|
||||
std::string DebugDeferredBuffer::getShaderSourceCode(Mode mode, std::string customFile) {
|
||||
|
@ -403,51 +411,51 @@ void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const Ren
|
|||
|
||||
batch.setPipeline(getPipeline(_mode, first));
|
||||
|
||||
if (deferredFramebuffer) {
|
||||
batch.setResourceTexture(Albedo, deferredFramebuffer->getDeferredColorTexture());
|
||||
batch.setResourceTexture(Normal, deferredFramebuffer->getDeferredNormalTexture());
|
||||
batch.setResourceTexture(Specular, deferredFramebuffer->getDeferredSpecularTexture());
|
||||
batch.setResourceTexture(Depth, deferredFramebuffer->getPrimaryDepthTexture());
|
||||
batch.setResourceTexture(Lighting, deferredFramebuffer->getLightingTexture());
|
||||
}
|
||||
if (!lightStage.lights.empty()) {
|
||||
batch.setResourceTexture(Shadow, lightStage.lights[0]->shadow.framebuffer->getDepthStencilBuffer());
|
||||
}
|
||||
if (deferredFramebuffer) {
|
||||
batch.setResourceTexture(Albedo, deferredFramebuffer->getDeferredColorTexture());
|
||||
batch.setResourceTexture(Normal, deferredFramebuffer->getDeferredNormalTexture());
|
||||
batch.setResourceTexture(Specular, deferredFramebuffer->getDeferredSpecularTexture());
|
||||
batch.setResourceTexture(Depth, deferredFramebuffer->getPrimaryDepthTexture());
|
||||
batch.setResourceTexture(Lighting, deferredFramebuffer->getLightingTexture());
|
||||
}
|
||||
if (!lightStage.lights.empty()) {
|
||||
batch.setResourceTexture(Shadow, lightStage.lights[0]->shadow.framebuffer->getDepthStencilBuffer());
|
||||
}
|
||||
|
||||
if (linearDepthTarget) {
|
||||
batch.setResourceTexture(LinearDepth, linearDepthTarget->getLinearDepthTexture());
|
||||
batch.setResourceTexture(HalfLinearDepth, linearDepthTarget->getHalfLinearDepthTexture());
|
||||
batch.setResourceTexture(HalfNormal, linearDepthTarget->getHalfNormalTexture());
|
||||
}
|
||||
if (surfaceGeometryFramebuffer) {
|
||||
batch.setResourceTexture(Curvature, surfaceGeometryFramebuffer->getCurvatureTexture());
|
||||
batch.setResourceTexture(DiffusedCurvature, surfaceGeometryFramebuffer->getLowCurvatureTexture());
|
||||
}
|
||||
if (ambientOcclusionFramebuffer) {
|
||||
batch.setResourceTexture(AmbientOcclusion, ambientOcclusionFramebuffer->getOcclusionTexture());
|
||||
batch.setResourceTexture(AmbientOcclusionBlurred, ambientOcclusionFramebuffer->getOcclusionBlurredTexture());
|
||||
}
|
||||
if (linearDepthTarget) {
|
||||
batch.setResourceTexture(LinearDepth, linearDepthTarget->getLinearDepthTexture());
|
||||
batch.setResourceTexture(HalfLinearDepth, linearDepthTarget->getHalfLinearDepthTexture());
|
||||
batch.setResourceTexture(HalfNormal, linearDepthTarget->getHalfNormalTexture());
|
||||
}
|
||||
if (surfaceGeometryFramebuffer) {
|
||||
batch.setResourceTexture(Curvature, surfaceGeometryFramebuffer->getCurvatureTexture());
|
||||
batch.setResourceTexture(DiffusedCurvature, surfaceGeometryFramebuffer->getLowCurvatureTexture());
|
||||
}
|
||||
if (ambientOcclusionFramebuffer) {
|
||||
batch.setResourceTexture(AmbientOcclusion, ambientOcclusionFramebuffer->getOcclusionTexture());
|
||||
batch.setResourceTexture(AmbientOcclusionBlurred, ambientOcclusionFramebuffer->getOcclusionBlurredTexture());
|
||||
}
|
||||
const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
const glm::vec2 bottomLeft(_size.x, _size.y);
|
||||
const glm::vec2 topRight(_size.z, _size.w);
|
||||
geometryBuffer->renderQuad(batch, bottomLeft, topRight, color);
|
||||
geometryBuffer->renderQuad(batch, bottomLeft, topRight, color, _geometryId);
|
||||
|
||||
|
||||
batch.setResourceTexture(Albedo, nullptr);
|
||||
batch.setResourceTexture(Normal, nullptr);
|
||||
batch.setResourceTexture(Specular, nullptr);
|
||||
batch.setResourceTexture(Depth, nullptr);
|
||||
batch.setResourceTexture(Lighting, nullptr);
|
||||
batch.setResourceTexture(Shadow, nullptr);
|
||||
batch.setResourceTexture(LinearDepth, nullptr);
|
||||
batch.setResourceTexture(HalfLinearDepth, nullptr);
|
||||
batch.setResourceTexture(HalfNormal, nullptr);
|
||||
batch.setResourceTexture(Albedo, nullptr);
|
||||
batch.setResourceTexture(Normal, nullptr);
|
||||
batch.setResourceTexture(Specular, nullptr);
|
||||
batch.setResourceTexture(Depth, nullptr);
|
||||
batch.setResourceTexture(Lighting, nullptr);
|
||||
batch.setResourceTexture(Shadow, nullptr);
|
||||
batch.setResourceTexture(LinearDepth, nullptr);
|
||||
batch.setResourceTexture(HalfLinearDepth, nullptr);
|
||||
batch.setResourceTexture(HalfNormal, nullptr);
|
||||
|
||||
batch.setResourceTexture(Curvature, nullptr);
|
||||
batch.setResourceTexture(DiffusedCurvature, nullptr);
|
||||
batch.setResourceTexture(Curvature, nullptr);
|
||||
batch.setResourceTexture(DiffusedCurvature, nullptr);
|
||||
|
||||
batch.setResourceTexture(AmbientOcclusion, nullptr);
|
||||
batch.setResourceTexture(AmbientOcclusionBlurred, nullptr);
|
||||
batch.setResourceTexture(AmbientOcclusion, nullptr);
|
||||
batch.setResourceTexture(AmbientOcclusionBlurred, nullptr);
|
||||
|
||||
});
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ public:
|
|||
using JobModel = render::Job::ModelI<DebugDeferredBuffer, Inputs, Config>;
|
||||
|
||||
DebugDeferredBuffer();
|
||||
~DebugDeferredBuffer();
|
||||
|
||||
void configure(const Config& config);
|
||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs);
|
||||
|
@ -96,6 +97,7 @@ private:
|
|||
|
||||
StandardPipelines _pipelines;
|
||||
CustomPipelines _customPipelines;
|
||||
int _geometryId { 0 };
|
||||
};
|
||||
|
||||
#endif // hifi_DebugDeferredBuffer_h
|
|
@ -525,8 +525,7 @@ void GeometryCache::renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, co
|
|||
Vec2FloatPairPair key(majorKey, minorKey);
|
||||
|
||||
// Make the gridbuffer
|
||||
if ((registered && (!_registeredGridBuffers.contains(id) || _lastRegisteredGridBuffer[id] != key)) ||
|
||||
(!registered && !_gridBuffers.contains(key))) {
|
||||
if (registered && (!_registeredGridBuffers.contains(id) || _lastRegisteredGridBuffer[id] != key)) {
|
||||
GridSchema gridSchema;
|
||||
GridBuffer gridBuffer = std::make_shared<gpu::Buffer>(sizeof(GridSchema), (const gpu::Byte*) &gridSchema);
|
||||
|
||||
|
@ -534,12 +533,8 @@ void GeometryCache::renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, co
|
|||
gridBuffer = _registeredGridBuffers[id];
|
||||
}
|
||||
|
||||
if (registered) {
|
||||
_registeredGridBuffers[id] = gridBuffer;
|
||||
_lastRegisteredGridBuffer[id] = key;
|
||||
} else {
|
||||
_gridBuffers[key] = gridBuffer;
|
||||
}
|
||||
_registeredGridBuffers[id] = gridBuffer;
|
||||
_lastRegisteredGridBuffer[id] = key;
|
||||
|
||||
gridBuffer.edit<GridSchema>().period = glm::vec4(majorRows, majorCols, minorRows, minorCols);
|
||||
gridBuffer.edit<GridSchema>().offset.x = -(majorEdge / majorRows) / 2;
|
||||
|
@ -552,7 +547,7 @@ void GeometryCache::renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, co
|
|||
}
|
||||
|
||||
// Set the grid pipeline
|
||||
useGridPipeline(batch, registered ? _registeredGridBuffers[id] : _gridBuffers[key], isLayered);
|
||||
useGridPipeline(batch, _registeredGridBuffers[id], isLayered);
|
||||
|
||||
renderQuad(batch, minCorner, maxCorner, MIN_TEX_COORD, MAX_TEX_COORD, color, id);
|
||||
}
|
||||
|
@ -805,7 +800,7 @@ void GeometryCache::renderVertices(gpu::Batch& batch, gpu::Primitive primitiveTy
|
|||
void GeometryCache::renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id) {
|
||||
bool registered = (id != UNKNOWN_ID);
|
||||
Vec3Pair key(glm::vec3(x, y, 0.0f), glm::vec3(width, height, bevelDistance));
|
||||
BatchItemDetails& details = registered ? _registeredBevelRects[id] : _bevelRects[key];
|
||||
BatchItemDetails& details = _registeredBevelRects[id];
|
||||
// if this is a registered quad, and we have buffers, then check to see if the geometry changed and rebuild if needed
|
||||
if (registered && details.isCreated) {
|
||||
Vec3Pair& lastKey = _lastRegisteredBevelRects[id];
|
||||
|
@ -906,7 +901,7 @@ void GeometryCache::renderBevelCornersRect(gpu::Batch& batch, int x, int y, int
|
|||
void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, const glm::vec4& color, int id) {
|
||||
bool registered = (id != UNKNOWN_ID);
|
||||
Vec4Pair key(glm::vec4(minCorner.x, minCorner.y, maxCorner.x, maxCorner.y), color);
|
||||
BatchItemDetails& details = registered ? _registeredQuad2D[id] : _quad2D[key];
|
||||
BatchItemDetails& details = _registeredQuad2D[id];
|
||||
|
||||
// if this is a registered quad, and we have buffers, then check to see if the geometry changed and rebuild if needed
|
||||
if (registered && details.isCreated) {
|
||||
|
@ -991,14 +986,13 @@ void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, co
|
|||
const glm::vec2& texCoordMinCorner, const glm::vec2& texCoordMaxCorner,
|
||||
const glm::vec4& color, int id) {
|
||||
|
||||
bool registered = (id != UNKNOWN_ID);
|
||||
Vec4PairVec4 key(Vec4Pair(glm::vec4(minCorner.x, minCorner.y, maxCorner.x, maxCorner.y),
|
||||
glm::vec4(texCoordMinCorner.x, texCoordMinCorner.y, texCoordMaxCorner.x, texCoordMaxCorner.y)),
|
||||
color);
|
||||
BatchItemDetails& details = registered ? _registeredQuad2DTextures[id] : _quad2DTextures[key];
|
||||
BatchItemDetails& details = _registeredQuad2DTextures[id];
|
||||
|
||||
// if this is a registered quad, and we have buffers, then check to see if the geometry changed and rebuild if needed
|
||||
if (registered && details.isCreated) {
|
||||
if (details.isCreated) {
|
||||
Vec4PairVec4& lastKey = _lastRegisteredQuad2DTexture[id];
|
||||
if (lastKey != key) {
|
||||
details.clear();
|
||||
|
@ -1077,7 +1071,7 @@ void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, co
|
|||
void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec3& minCorner, const glm::vec3& maxCorner, const glm::vec4& color, int id) {
|
||||
bool registered = (id != UNKNOWN_ID);
|
||||
Vec3PairVec4 key(Vec3Pair(minCorner, maxCorner), color);
|
||||
BatchItemDetails& details = registered ? _registeredQuad3D[id] : _quad3D[key];
|
||||
BatchItemDetails& details = _registeredQuad3D[id];
|
||||
|
||||
// if this is a registered quad, and we have buffers, then check to see if the geometry changed and rebuild if needed
|
||||
if (registered && details.isCreated) {
|
||||
|
@ -1173,7 +1167,7 @@ void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec3& topLeft, cons
|
|||
Vec4Pair(glm::vec4(texCoordTopLeft.x, texCoordTopLeft.y, texCoordBottomRight.x, texCoordBottomRight.y),
|
||||
color));
|
||||
|
||||
BatchItemDetails& details = registered ? _registeredQuad3DTextures[id] : _quad3DTextures[key];
|
||||
BatchItemDetails& details = _registeredQuad3DTextures[id];
|
||||
|
||||
// if this is a registered quad, and we have buffers, then check to see if the geometry changed and rebuild if needed
|
||||
if (registered && details.isCreated) {
|
||||
|
@ -1254,7 +1248,7 @@ void GeometryCache::renderDashedLine(gpu::Batch& batch, const glm::vec3& start,
|
|||
|
||||
bool registered = (id != UNKNOWN_ID);
|
||||
Vec3PairVec2Pair key(Vec3Pair(start, end), Vec2Pair(glm::vec2(color.x, color.y), glm::vec2(color.z, color.w)));
|
||||
BatchItemDetails& details = registered ? _registeredDashedLines[id] : _dashedLines[key];
|
||||
BatchItemDetails& details = _registeredDashedLines[id];
|
||||
|
||||
// if this is a registered , and we have buffers, then check to see if the geometry changed and rebuild if needed
|
||||
if (registered && details.isCreated) {
|
||||
|
@ -1423,7 +1417,7 @@ void GeometryCache::renderLine(gpu::Batch& batch, const glm::vec3& p1, const glm
|
|||
bool registered = (id != UNKNOWN_ID);
|
||||
Vec3Pair key(p1, p2);
|
||||
|
||||
BatchItemDetails& details = registered ? _registeredLine3DVBOs[id] : _line3DVBOs[key];
|
||||
BatchItemDetails& details = _registeredLine3DVBOs[id];
|
||||
|
||||
int compactColor1 = ((int(color1.x * 255.0f) & 0xFF)) |
|
||||
((int(color1.y * 255.0f) & 0xFF) << 8) |
|
||||
|
@ -1512,7 +1506,7 @@ void GeometryCache::renderLine(gpu::Batch& batch, const glm::vec2& p1, const glm
|
|||
bool registered = (id != UNKNOWN_ID);
|
||||
Vec2Pair key(p1, p2);
|
||||
|
||||
BatchItemDetails& details = registered ? _registeredLine2DVBOs[id] : _line2DVBOs[key];
|
||||
BatchItemDetails& details = _registeredLine2DVBOs[id];
|
||||
|
||||
int compactColor1 = ((int(color1.x * 255.0f) & 0xFF)) |
|
||||
((int(color1.y * 255.0f) & 0xFF) << 8) |
|
||||
|
@ -1628,7 +1622,7 @@ void GeometryCache::renderGlowLine(gpu::Batch& batch, const glm::vec3& p1, const
|
|||
|
||||
Vec3Pair key(p1, p2);
|
||||
bool registered = (id != UNKNOWN_ID);
|
||||
BatchItemDetails& details = registered ? _registeredLine3DVBOs[id] : _line3DVBOs[key];
|
||||
BatchItemDetails& details = _registeredLine3DVBOs[id];
|
||||
|
||||
int compactColor = ((int(color.x * 255.0f) & 0xFF)) |
|
||||
((int(color.y * 255.0f) & 0xFF) << 8) |
|
||||
|
|
|
@ -230,73 +230,79 @@ public:
|
|||
void renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner,
|
||||
int majorRows, int majorCols, float majorEdge,
|
||||
int minorRows, int minorCols, float minorEdge,
|
||||
const glm::vec4& color, bool isLayered, int id = UNKNOWN_ID);
|
||||
const glm::vec4& color, bool isLayered, int id);
|
||||
void renderGrid(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner,
|
||||
int rows, int cols, float edge, const glm::vec4& color, bool isLayered, int id = UNKNOWN_ID) {
|
||||
int rows, int cols, float edge, const glm::vec4& color, bool isLayered, int id) {
|
||||
renderGrid(batch, minCorner, maxCorner, rows, cols, edge, 0, 0, 0.0f, color, isLayered, id);
|
||||
}
|
||||
|
||||
void renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id = UNKNOWN_ID);
|
||||
void renderBevelCornersRect(gpu::Batch& batch, int x, int y, int width, int height, int bevelDistance, const glm::vec4& color, int id);
|
||||
|
||||
void renderUnitQuad(gpu::Batch& batch, const glm::vec4& color = glm::vec4(1), int id = UNKNOWN_ID);
|
||||
void renderUnitQuad(gpu::Batch& batch, const glm::vec4& color, int id);
|
||||
|
||||
void renderQuad(gpu::Batch& batch, int x, int y, int width, int height, const glm::vec4& color, int id = UNKNOWN_ID)
|
||||
void renderUnitQuad(gpu::Batch& batch, int id) {
|
||||
renderUnitQuad(batch, glm::vec4(1), id);
|
||||
}
|
||||
|
||||
void renderQuad(gpu::Batch& batch, int x, int y, int width, int height, const glm::vec4& color, int id)
|
||||
{ renderQuad(batch, glm::vec2(x,y), glm::vec2(x + width, y + height), color, id); }
|
||||
|
||||
// TODO: I think there's a bug in this version of the renderQuad() that's not correctly rebuilding the vbos
|
||||
// if the color changes by the corners are the same, as evidenced by the audio meter which should turn white
|
||||
// when it's clipping
|
||||
void renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, const glm::vec4& color, int id = UNKNOWN_ID);
|
||||
void renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner, const glm::vec4& color, int id);
|
||||
|
||||
void renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner,
|
||||
const glm::vec2& texCoordMinCorner, const glm::vec2& texCoordMaxCorner,
|
||||
const glm::vec4& color, int id = UNKNOWN_ID);
|
||||
const glm::vec4& color, int id);
|
||||
|
||||
void renderQuad(gpu::Batch& batch, const glm::vec3& minCorner, const glm::vec3& maxCorner, const glm::vec4& color, int id = UNKNOWN_ID);
|
||||
void renderQuad(gpu::Batch& batch, const glm::vec3& minCorner, const glm::vec3& maxCorner, const glm::vec4& color, int id);
|
||||
|
||||
void renderQuad(gpu::Batch& batch, const glm::vec3& topLeft, const glm::vec3& bottomLeft,
|
||||
const glm::vec3& bottomRight, const glm::vec3& topRight,
|
||||
const glm::vec2& texCoordTopLeft, const glm::vec2& texCoordBottomLeft,
|
||||
const glm::vec2& texCoordBottomRight, const glm::vec2& texCoordTopRight,
|
||||
const glm::vec4& color, int id = UNKNOWN_ID);
|
||||
const glm::vec4& color, int id);
|
||||
|
||||
|
||||
void renderLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2, const glm::vec3& color, int id = UNKNOWN_ID)
|
||||
void renderLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2, const glm::vec3& color, int id)
|
||||
{ renderLine(batch, p1, p2, color, color, id); }
|
||||
|
||||
void renderLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2,
|
||||
const glm::vec3& color1, const glm::vec3& color2, int id = UNKNOWN_ID)
|
||||
const glm::vec3& color1, const glm::vec3& color2, int id)
|
||||
{ renderLine(batch, p1, p2, glm::vec4(color1, 1.0f), glm::vec4(color2, 1.0f), id); }
|
||||
|
||||
void renderLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2,
|
||||
const glm::vec4& color, int id = UNKNOWN_ID)
|
||||
const glm::vec4& color, int id)
|
||||
{ renderLine(batch, p1, p2, color, color, id); }
|
||||
|
||||
void renderLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2,
|
||||
const glm::vec4& color1, const glm::vec4& color2, int id = UNKNOWN_ID);
|
||||
const glm::vec4& color1, const glm::vec4& color2, int id);
|
||||
|
||||
void renderGlowLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2,
|
||||
const glm::vec4& color, float glowIntensity = 1.0f, float glowWidth = 0.05f, int id = UNKNOWN_ID);
|
||||
const glm::vec4& color, float glowIntensity, float glowWidth, int id);
|
||||
|
||||
void renderDashedLine(gpu::Batch& batch, const glm::vec3& start, const glm::vec3& end, const glm::vec4& color,
|
||||
int id = UNKNOWN_ID)
|
||||
void renderGlowLine(gpu::Batch& batch, const glm::vec3& p1, const glm::vec3& p2, const glm::vec4& color, int id)
|
||||
{ renderGlowLine(batch, p1, p2, color, 1.0f, 0.05f, id); }
|
||||
|
||||
void renderDashedLine(gpu::Batch& batch, const glm::vec3& start, const glm::vec3& end, const glm::vec4& color, int id)
|
||||
{ renderDashedLine(batch, start, end, color, 0.05f, 0.025f, id); }
|
||||
|
||||
void renderDashedLine(gpu::Batch& batch, const glm::vec3& start, const glm::vec3& end, const glm::vec4& color,
|
||||
const float dash_length, const float gap_length, int id = UNKNOWN_ID);
|
||||
const float dash_length, const float gap_length, int id);
|
||||
|
||||
void renderLine(gpu::Batch& batch, const glm::vec2& p1, const glm::vec2& p2, const glm::vec3& color, int id = UNKNOWN_ID)
|
||||
void renderLine(gpu::Batch& batch, const glm::vec2& p1, const glm::vec2& p2, const glm::vec3& color, int id)
|
||||
{ renderLine(batch, p1, p2, glm::vec4(color, 1.0f), id); }
|
||||
|
||||
void renderLine(gpu::Batch& batch, const glm::vec2& p1, const glm::vec2& p2, const glm::vec4& color, int id = UNKNOWN_ID)
|
||||
void renderLine(gpu::Batch& batch, const glm::vec2& p1, const glm::vec2& p2, const glm::vec4& color, int id)
|
||||
{ renderLine(batch, p1, p2, color, color, id); }
|
||||
|
||||
void renderLine(gpu::Batch& batch, const glm::vec2& p1, const glm::vec2& p2,
|
||||
const glm::vec3& color1, const glm::vec3& color2, int id = UNKNOWN_ID)
|
||||
const glm::vec3& color1, const glm::vec3& color2, int id)
|
||||
{ renderLine(batch, p1, p2, glm::vec4(color1, 1.0f), glm::vec4(color2, 1.0f), id); }
|
||||
|
||||
void renderLine(gpu::Batch& batch, const glm::vec2& p1, const glm::vec2& p2,
|
||||
const glm::vec4& color1, const glm::vec4& color2, int id = UNKNOWN_ID);
|
||||
const glm::vec4& color1, const glm::vec4& color2, int id);
|
||||
|
||||
void updateVertices(int id, const QVector<glm::vec2>& points, const glm::vec4& color);
|
||||
void updateVertices(int id, const QVector<glm::vec2>& points, const QVector<glm::vec4>& colors);
|
||||
|
@ -381,41 +387,32 @@ private:
|
|||
int _nextID{ 1 };
|
||||
|
||||
QHash<int, Vec3PairVec4Pair> _lastRegisteredQuad3DTexture;
|
||||
QHash<Vec3PairVec4Pair, BatchItemDetails> _quad3DTextures;
|
||||
QHash<int, BatchItemDetails> _registeredQuad3DTextures;
|
||||
|
||||
QHash<int, Vec4PairVec4> _lastRegisteredQuad2DTexture;
|
||||
QHash<Vec4PairVec4, BatchItemDetails> _quad2DTextures;
|
||||
QHash<int, BatchItemDetails> _registeredQuad2DTextures;
|
||||
|
||||
QHash<int, Vec3PairVec4> _lastRegisteredQuad3D;
|
||||
QHash<Vec3PairVec4, BatchItemDetails> _quad3D;
|
||||
QHash<int, BatchItemDetails> _registeredQuad3D;
|
||||
|
||||
QHash<int, Vec4Pair> _lastRegisteredQuad2D;
|
||||
QHash<Vec4Pair, BatchItemDetails> _quad2D;
|
||||
QHash<int, BatchItemDetails> _registeredQuad2D;
|
||||
|
||||
QHash<int, Vec3Pair> _lastRegisteredBevelRects;
|
||||
QHash<Vec3Pair, BatchItemDetails> _bevelRects;
|
||||
QHash<int, BatchItemDetails> _registeredBevelRects;
|
||||
|
||||
QHash<int, Vec3Pair> _lastRegisteredLine3D;
|
||||
QHash<Vec3Pair, BatchItemDetails> _line3DVBOs;
|
||||
QHash<int, BatchItemDetails> _registeredLine3DVBOs;
|
||||
|
||||
QHash<int, Vec2Pair> _lastRegisteredLine2D;
|
||||
QHash<Vec2Pair, BatchItemDetails> _line2DVBOs;
|
||||
QHash<int, BatchItemDetails> _registeredLine2DVBOs;
|
||||
|
||||
QHash<int, BatchItemDetails> _registeredVertices;
|
||||
|
||||
QHash<int, Vec3PairVec2Pair> _lastRegisteredDashedLines;
|
||||
QHash<Vec3PairVec2Pair, BatchItemDetails> _dashedLines;
|
||||
QHash<int, BatchItemDetails> _registeredDashedLines;
|
||||
|
||||
QHash<int, Vec2FloatPairPair> _lastRegisteredGridBuffer;
|
||||
QHash<Vec2FloatPairPair, GridBuffer> _gridBuffers;
|
||||
QHash<int, GridBuffer> _registeredGridBuffers;
|
||||
|
||||
gpu::ShaderPointer _simpleShader;
|
||||
|
|
|
@ -33,6 +33,14 @@
|
|||
|
||||
|
||||
HitEffect::HitEffect() {
|
||||
_geometryId = DependencyManager::get<GeometryCache>()->allocateID();
|
||||
}
|
||||
|
||||
HitEffect::~HitEffect() {
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (_geometryId && geometryCache) {
|
||||
geometryCache->releaseID(_geometryId);
|
||||
}
|
||||
}
|
||||
|
||||
const gpu::PipelinePointer& HitEffect::getHitEffectPipeline() {
|
||||
|
@ -77,10 +85,10 @@ void HitEffect::run(const render::SceneContextPointer& sceneContext, const rende
|
|||
|
||||
batch.setPipeline(getHitEffectPipeline());
|
||||
|
||||
glm::vec4 color(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
glm::vec2 bottomLeft(-1.0f, -1.0f);
|
||||
glm::vec2 topRight(1.0f, 1.0f);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, bottomLeft, topRight, color);
|
||||
static const glm::vec4 color(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
static const glm::vec2 bottomLeft(-1.0f, -1.0f);
|
||||
static const glm::vec2 topRight(1.0f, 1.0f);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, bottomLeft, topRight, color, _geometryId);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -24,12 +24,14 @@ public:
|
|||
using JobModel = render::Job::Model<HitEffect, Config>;
|
||||
|
||||
HitEffect();
|
||||
~HitEffect();
|
||||
void configure(const Config& config) {}
|
||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
||||
|
||||
const gpu::PipelinePointer& getHitEffectPipeline();
|
||||
|
||||
private:
|
||||
int _geometryId { 0 };
|
||||
gpu::PipelinePointer _hitEffectPipeline;
|
||||
};
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ void render::renderStateSortShapes(const SceneContextPointer& sceneContext, cons
|
|||
|
||||
{
|
||||
assert(item.getKey().isShape());
|
||||
const auto& key = item.getShapeKey();
|
||||
const auto key = item.getShapeKey();
|
||||
if (key.isValid() && !key.hasOwnPipeline()) {
|
||||
auto& bucket = sortedShapes[key];
|
||||
if (bucket.empty()) {
|
||||
|
|
|
@ -143,13 +143,13 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a
|
|||
if (url.toLower().left(METAVERSE_API_URL.length()) == METAVERSE_API_URL) {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
||||
if (accountManager->hasValidAccessToken()) {
|
||||
QUrlQuery urlQuery(_url.query());
|
||||
urlQuery.addQueryItem("access_token", accountManager->getAccountInfo().getAccessToken().token);
|
||||
_url.setQuery(urlQuery);
|
||||
if (_url.scheme() == "https" && accountManager->hasValidAccessToken()) {
|
||||
static const QString HTTP_AUTHORIZATION_HEADER = "Authorization";
|
||||
QString bearerString = "Bearer " + accountManager->getAccountInfo().getAccessToken().token;
|
||||
_request.setRawHeader(HTTP_AUTHORIZATION_HEADER.toLocal8Bit(), bearerString.toLocal8Bit());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!username.isEmpty()) {
|
||||
_url.setUserName(username);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,9 @@ const vec3& Vectors::UP = Vectors::UNIT_Y;
|
|||
const vec3& Vectors::FRONT = Vectors::UNIT_NEG_Z;
|
||||
|
||||
const quat Quaternions::IDENTITY{ 1.0f, 0.0f, 0.0f, 0.0f };
|
||||
const quat Quaternions::X_180{ 0.0f, 1.0f, 0.0f, 0.0f };
|
||||
const quat Quaternions::Y_180{ 0.0f, 0.0f, 1.0f, 0.0f };
|
||||
const quat Quaternions::Z_180{ 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
|
||||
// Safe version of glm::mix; based on the code in Nick Bobick's article,
|
||||
// http://www.gamasutra.com/features/19980703/quaternions_01.htm (via Clyde,
|
||||
|
|
|
@ -58,7 +58,9 @@ glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha);
|
|||
class Quaternions {
|
||||
public:
|
||||
static const quat IDENTITY;
|
||||
static const quat X_180;
|
||||
static const quat Y_180;
|
||||
static const quat Z_180;
|
||||
};
|
||||
|
||||
class Vectors {
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
|
||||
#include <chrono>
|
||||
|
||||
#include <QtCore/QMetaType>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
@ -47,5 +49,11 @@ using p_high_resolution_clock = std::chrono::high_resolution_clock;
|
|||
|
||||
#endif
|
||||
|
||||
Q_DECLARE_METATYPE(p_high_resolution_clock::time_point);
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
__attribute__((unused))
|
||||
#endif
|
||||
static const int timePointMetaTypeID = qRegisterMetaType<p_high_resolution_clock::time_point>();
|
||||
|
||||
#endif // hifi_PortableHighResolutionClock_h
|
||||
|
|
|
@ -86,13 +86,10 @@ QString QmlWebWindowClass::getURL() const {
|
|||
return result.toString();
|
||||
}
|
||||
|
||||
// HACK find a good place to declare and store this
|
||||
extern QString fixupHifiUrl(const QString& urlString);
|
||||
|
||||
void QmlWebWindowClass::setURL(const QString& urlString) {
|
||||
DependencyManager::get<OffscreenUi>()->executeOnUiThread([=] {
|
||||
if (!_qmlWindow.isNull()) {
|
||||
_qmlWindow->setProperty(URL_PROPERTY, fixupHifiUrl(urlString));
|
||||
_qmlWindow->setProperty(URL_PROPERTY, urlString);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ class QmlWebWindowClass : public QmlWindowClass {
|
|||
public:
|
||||
static QScriptValue constructor(QScriptContext* context, QScriptEngine* engine);
|
||||
|
||||
public slots:
|
||||
public slots:
|
||||
QString getURL() const;
|
||||
void setURL(const QString& url);
|
||||
|
||||
|
|
|
@ -299,10 +299,12 @@ controller::Pose openVrControllerPoseToHandPose(bool isLeftHand, const mat4& mat
|
|||
static const glm::quat leftRotationOffset = glm::inverse(leftQuarterZ * eighthX) * touchToHand;
|
||||
static const glm::quat rightRotationOffset = glm::inverse(rightQuarterZ * eighthX) * touchToHand;
|
||||
|
||||
static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches
|
||||
static const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f,
|
||||
CONTROLLER_LENGTH_OFFSET / 2.0f,
|
||||
CONTROLLER_LENGTH_OFFSET * 2.0f);
|
||||
// this needs to match the leftBasePosition in tutorial/viveControllerConfiguration.js:21
|
||||
static const float CONTROLLER_LATERAL_OFFSET = 0.0381f;
|
||||
static const float CONTROLLER_VERTICAL_OFFSET = 0.0495f;
|
||||
static const float CONTROLLER_FORWARD_OFFSET = 0.1371f;
|
||||
static const glm::vec3 CONTROLLER_OFFSET(CONTROLLER_LATERAL_OFFSET, CONTROLLER_VERTICAL_OFFSET, CONTROLLER_FORWARD_OFFSET);
|
||||
|
||||
static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET;
|
||||
static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET;
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@ function messageHandler(channel, messageString, senderID) {
|
|||
position: Vec3.sum(MyAvatar.position, {x: coord(), y: 0, z: coord()}),
|
||||
orientation: Quat.fromPitchYawRollDegrees(0, Quat.safeEulerAngles(MyAvatar.orientation).y + (turnSpread * (Math.random() - 0.5)), 0),
|
||||
soundData: chatter && SOUND_DATA,
|
||||
skeletonModelURL: "http://howard-stearns.github.io/models/resources/meshes/defaultAvatar_full.fst",
|
||||
animationData: ANIMATION_DATA
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
/* global setEntityCustomData, getEntityCustomData, flatten, Xform, Script, Quat, Vec3, MyAvatar, Entities, Overlays, Settings, Reticle, Controller, Camera, Messages, Mat4, getControllerWorldLocation, getGrabPointSphereOffset */
|
||||
/* global setEntityCustomData, getEntityCustomData, flatten, Xform, Script, Quat, Vec3, MyAvatar, Entities, Overlays, Settings, Reticle, Controller, Camera, Messages, Mat4, getControllerWorldLocation, getGrabPointSphereOffset, setGrabCommunications */
|
||||
|
||||
(function() { // BEGIN LOCAL_SCOPE
|
||||
|
||||
|
@ -27,7 +27,7 @@ var WANT_DEBUG_STATE = false;
|
|||
var WANT_DEBUG_SEARCH_NAME = null;
|
||||
|
||||
var FORCE_IGNORE_IK = false;
|
||||
var SHOW_GRAB_POINT_SPHERE = true;
|
||||
var SHOW_GRAB_POINT_SPHERE = false;
|
||||
|
||||
//
|
||||
// these tune time-averaging and "on" value for analog trigger
|
||||
|
@ -101,7 +101,7 @@ var MAX_EQUIP_HOTSPOT_RADIUS = 1.0;
|
|||
|
||||
var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position
|
||||
|
||||
var NEAR_GRAB_RADIUS = 0.04; // radius used for palm vs object for near grabbing.
|
||||
var NEAR_GRAB_RADIUS = 0.1; // radius used for palm vs object for near grabbing.
|
||||
var NEAR_GRAB_MAX_DISTANCE = 1.0; // you cannot grab objects that are this far away from your hand
|
||||
|
||||
var NEAR_GRAB_PICK_RADIUS = 0.25; // radius used for search ray vs object for near grabbing.
|
||||
|
@ -835,7 +835,7 @@ function MyController(hand) {
|
|||
this.grabPointSphere = Overlays.addOverlay("sphere", {
|
||||
localPosition: getGrabPointSphereOffset(this.handToController()),
|
||||
localRotation: { x: 0, y: 0, z: 0, w: 1 },
|
||||
dimensions: GRAB_POINT_SPHERE_RADIUS,
|
||||
dimensions: GRAB_POINT_SPHERE_RADIUS * 2,
|
||||
color: GRAB_POINT_SPHERE_COLOR,
|
||||
alpha: GRAB_POINT_SPHERE_ALPHA,
|
||||
solid: true,
|
||||
|
@ -2091,12 +2091,12 @@ function MyController(hand) {
|
|||
var TEAR_AWAY_DISTANCE = 0.1;
|
||||
var dist = distanceBetweenPointAndEntityBoundingBox(handPosition, props);
|
||||
if (dist > TEAR_AWAY_DISTANCE) {
|
||||
this.autoUnequipCounter += 1;
|
||||
this.autoUnequipCounter += deltaTime;
|
||||
} else {
|
||||
this.autoUnequipCounter = 0;
|
||||
}
|
||||
|
||||
if (this.autoUnequipCounter > 1) {
|
||||
if (this.autoUnequipCounter > 0.25) {
|
||||
// for whatever reason, the held/equipped entity has been pulled away. ungrab or unequip.
|
||||
print("handControllerGrab -- autoreleasing held or equipped item because it is far from hand." +
|
||||
props.parentID + ", dist = " + dist);
|
||||
|
@ -2661,6 +2661,15 @@ mapping.from([Controller.Standard.RightPrimaryThumb]).peek().to(rightController.
|
|||
|
||||
Controller.enableMapping(MAPPING_NAME);
|
||||
|
||||
function handleMenuEvent(menuItem) {
|
||||
if (menuItem === "Show Grab Sphere") {
|
||||
SHOW_GRAB_POINT_SPHERE = Menu.isOptionChecked("Show Grab Sphere");
|
||||
}
|
||||
}
|
||||
|
||||
Menu.addMenuItem({ menuName: "Developer", menuItemName: "Show Grab Sphere", isCheckable: true, isChecked: false });
|
||||
Menu.menuItemEvent.connect(handleMenuEvent);
|
||||
|
||||
// the section below allows the grab script to listen for messages
|
||||
// that disable either one or both hands. useful for two handed items
|
||||
var handToDisable = 'none';
|
||||
|
@ -2776,6 +2785,7 @@ var updateIntervalTimer = Script.setInterval(function(){
|
|||
}, BASIC_TIMER_INTERVAL_MS);
|
||||
|
||||
function cleanup() {
|
||||
Menu.removeMenuItem("Developer", "Show Grab Sphere");
|
||||
Script.clearInterval(updateIntervalTimer);
|
||||
rightController.cleanup();
|
||||
leftController.cleanup();
|
||||
|
|
|
@ -15,13 +15,8 @@ getGrabCommunications = function getFarGrabCommunications() {
|
|||
return !!Settings.getValue(GRAB_COMMUNICATIONS_SETTING, "");
|
||||
}
|
||||
|
||||
|
||||
// var GRAB_POINT_SPHERE_OFFSET = { x: 0, y: 0.2, z: 0 };
|
||||
// var GRAB_POINT_SPHERE_OFFSET = { x: 0.1, y: 0.175, z: 0.04 };
|
||||
// var GRAB_POINT_SPHERE_OFFSET = { x: 0.1, y: 0.32, z: 0.04 };
|
||||
|
||||
// this offset needs to match the one in libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp
|
||||
var GRAB_POINT_SPHERE_OFFSET = { x: 0.0, y: 0.175, z: 0.0 };
|
||||
// this offset needs to match the one in libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp:378
|
||||
var GRAB_POINT_SPHERE_OFFSET = { x: 0.04, y: 0.13, z: 0.039 }; // x = upward, y = forward, z = lateral
|
||||
|
||||
getGrabPointSphereOffset = function(handController) {
|
||||
if (handController === Controller.Standard.RightHand) {
|
||||
|
|
|
@ -381,7 +381,7 @@ var usersWindow = (function () {
|
|||
|
||||
isLoggedIn = false,
|
||||
isVisible = true,
|
||||
isMinimized = true,
|
||||
isMinimized = false,
|
||||
isBorderVisible = false,
|
||||
|
||||
viewport,
|
||||
|
@ -418,7 +418,9 @@ var usersWindow = (function () {
|
|||
}
|
||||
|
||||
// Reserve space for title, friends button, and option controls
|
||||
nonUsersHeight = WINDOW_MARGIN + windowLineHeight + FRIENDS_BUTTON_SPACER + FRIENDS_BUTTON_HEIGHT + DISPLAY_SPACER
|
||||
nonUsersHeight = WINDOW_MARGIN + windowLineHeight
|
||||
+ (shouldShowFriendsButton() ? FRIENDS_BUTTON_SPACER + FRIENDS_BUTTON_HEIGHT : 0)
|
||||
+ DISPLAY_SPACER
|
||||
+ windowLineHeight + VISIBILITY_SPACER
|
||||
+ windowLineHeight + WINDOW_BASE_MARGIN;
|
||||
|
||||
|
@ -485,16 +487,22 @@ var usersWindow = (function () {
|
|||
y: scrollbarBarPosition.y
|
||||
});
|
||||
|
||||
|
||||
x = windowLeft + WINDOW_MARGIN;
|
||||
y = windowPosition.y - FRIENDS_BUTTON_HEIGHT - DISPLAY_SPACER
|
||||
y = windowPosition.y
|
||||
- DISPLAY_SPACER
|
||||
- windowLineHeight - VISIBILITY_SPACER
|
||||
- windowLineHeight - WINDOW_BASE_MARGIN;
|
||||
Overlays.editOverlay(friendsButton, {
|
||||
x: x,
|
||||
y: y
|
||||
});
|
||||
if (shouldShowFriendsButton()) {
|
||||
y -= FRIENDS_BUTTON_HEIGHT;
|
||||
Overlays.editOverlay(friendsButton, {
|
||||
x: x,
|
||||
y: y
|
||||
});
|
||||
y += FRIENDS_BUTTON_HEIGHT;
|
||||
}
|
||||
|
||||
y += FRIENDS_BUTTON_HEIGHT + DISPLAY_SPACER;
|
||||
y += DISPLAY_SPACER;
|
||||
displayControl.updatePosition(x, y);
|
||||
|
||||
y += windowLineHeight + VISIBILITY_SPACER;
|
||||
|
@ -563,6 +571,10 @@ var usersWindow = (function () {
|
|||
});
|
||||
}
|
||||
|
||||
function shouldShowFriendsButton() {
|
||||
return isVisible && isLoggedIn && !isMinimized;
|
||||
}
|
||||
|
||||
function updateOverlayVisibility() {
|
||||
Overlays.editOverlay(windowBorder, {
|
||||
visible: isVisible && isBorderVisible
|
||||
|
@ -574,7 +586,7 @@ var usersWindow = (function () {
|
|||
visible: isVisible
|
||||
});
|
||||
Overlays.editOverlay(minimizeButton, {
|
||||
visible: isLoggedIn && isVisible
|
||||
visible: isVisible
|
||||
});
|
||||
Overlays.editOverlay(scrollbarBackground, {
|
||||
visible: isVisible && isUsingScrollbars && !isMinimized
|
||||
|
@ -583,7 +595,7 @@ var usersWindow = (function () {
|
|||
visible: isVisible && isUsingScrollbars && !isMinimized
|
||||
});
|
||||
Overlays.editOverlay(friendsButton, {
|
||||
visible: isVisible && !isMinimized
|
||||
visible: shouldShowFriendsButton()
|
||||
});
|
||||
displayControl.setVisible(isVisible && !isMinimized);
|
||||
visibilityControl.setVisible(isVisible && !isMinimized);
|
||||
|
@ -659,12 +671,11 @@ var usersWindow = (function () {
|
|||
}
|
||||
}
|
||||
|
||||
checkLoggedIn();
|
||||
calculateWindowHeight();
|
||||
updateUsersDisplay();
|
||||
updateOverlayPositions();
|
||||
|
||||
checkLoggedIn();
|
||||
|
||||
} else {
|
||||
print("Error: Request for users status returned " + usersRequest.status + " " + usersRequest.statusText);
|
||||
usersTimer = Script.setTimeout(pollUsers, HTTP_GET_TIMEOUT); // Try again after a longer delay.
|
||||
|
@ -1182,7 +1193,7 @@ var usersWindow = (function () {
|
|||
pollUsers();
|
||||
|
||||
// Set minimized at end - setup code does not handle `minimized == false` correctly
|
||||
setMinimized(isValueTrue(Settings.getValue(SETTING_USERS_WINDOW_MINIMIZED, false)));
|
||||
setMinimized(isValueTrue(Settings.getValue(SETTING_USERS_WINDOW_MINIMIZED, true)));
|
||||
}
|
||||
|
||||
function tearDown() {
|
||||
|
|
|
@ -18,10 +18,12 @@
|
|||
#include <QtCore/QElapsedTimer>
|
||||
#include <QtCore/QLoggingCategory>
|
||||
#include <QtCore/QRegularExpression>
|
||||
#include <QtCore/QSettings>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QThreadPool>
|
||||
|
||||
|
||||
#include <QtGui/QGuiApplication>
|
||||
#include <QtGui/QResizeEvent>
|
||||
#include <QtGui/QWindow>
|
||||
|
|
|
@ -25,7 +25,7 @@ const QCommandLineOption TARGET_OPTION {
|
|||
"IP:PORT or HOSTNAME:PORT"
|
||||
};
|
||||
const QCommandLineOption PACKET_SIZE {
|
||||
"packet-size", "size for sent packets in bytes (defaults to " + QString(MAX_PACKET_SIZE) + ")", "bytes",
|
||||
"packet-size", "size for sent packets in bytes (defaults to " + QString::number(udt::MAX_PACKET_SIZE) + ")", "bytes",
|
||||
QString(udt::MAX_PACKET_SIZE)
|
||||
};
|
||||
const QCommandLineOption MIN_PACKET_SIZE {
|
||||
|
|
|
@ -16,16 +16,20 @@ var rightBaseRotation = Quat.multiply(
|
|||
Quat.fromPitchYawRollDegrees(0, 0, -90)
|
||||
)
|
||||
);
|
||||
var CONTROLLER_LENGTH_OFFSET = 0.0762;
|
||||
|
||||
// keep these in sync with the values from plugins/openvr/src/OpenVrHelpers.cpp:303
|
||||
var CONTROLLER_LATERAL_OFFSET = 0.0381;
|
||||
var CONTROLLER_VERTICAL_OFFSET = 0.0495;
|
||||
var CONTROLLER_FORWARD_OFFSET = 0.1371;
|
||||
var leftBasePosition = {
|
||||
x: CONTROLLER_LENGTH_OFFSET / 2,
|
||||
y: CONTROLLER_LENGTH_OFFSET * 2,
|
||||
z: CONTROLLER_LENGTH_OFFSET / 2
|
||||
x: CONTROLLER_VERTICAL_OFFSET,
|
||||
y: CONTROLLER_FORWARD_OFFSET,
|
||||
z: CONTROLLER_LATERAL_OFFSET
|
||||
};
|
||||
var rightBasePosition = {
|
||||
x: -CONTROLLER_LENGTH_OFFSET / 2,
|
||||
y: CONTROLLER_LENGTH_OFFSET * 2,
|
||||
z: CONTROLLER_LENGTH_OFFSET / 2
|
||||
x: -CONTROLLER_VERTICAL_OFFSET,
|
||||
y: CONTROLLER_FORWARD_OFFSET,
|
||||
z: CONTROLLER_LATERAL_OFFSET
|
||||
};
|
||||
|
||||
var viveNaturalDimensions = {
|
||||
|
|
Loading…
Reference in a new issue