mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 17:35:08 +02:00
Adding the reverse transformation
This commit is contained in:
commit
108910052a
46 changed files with 1820 additions and 208 deletions
|
@ -368,11 +368,11 @@ void DomainServer::setupNodeListAndAssignments() {
|
|||
const QString CUSTOM_LOCAL_PORT_OPTION = "metaverse.local_port";
|
||||
|
||||
QVariant localPortValue = _settingsManager.valueOrDefaultValueForKeyPath(CUSTOM_LOCAL_PORT_OPTION);
|
||||
unsigned short domainServerPort = (unsigned short) localPortValue.toUInt();
|
||||
int domainServerPort = localPortValue.toInt();
|
||||
|
||||
QVariantMap& settingsMap = _settingsManager.getSettingsMap();
|
||||
|
||||
unsigned short domainServerDTLSPort = 0;
|
||||
int domainServerDTLSPort = INVALID_PORT;
|
||||
|
||||
if (_isUsingDTLS) {
|
||||
domainServerDTLSPort = DEFAULT_DOMAIN_SERVER_DTLS_PORT;
|
||||
|
|
43
interface/resources/html/createGlobalEventBridge.js
Normal file
43
interface/resources/html/createGlobalEventBridge.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// createGlobalEventBridge.js
|
||||
//
|
||||
// Created by Anthony J. Thibault on 9/7/2016
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// Stick a EventBridge object in the global namespace.
|
||||
var EventBridge;
|
||||
(function () {
|
||||
// the TempEventBridge class queues up emitWebEvent messages and executes them when the real EventBridge is ready.
|
||||
// Similarly, it holds all scriptEventReceived callbacks, and hooks them up to the real EventBridge.
|
||||
function TempEventBridge() {
|
||||
var self = this;
|
||||
this._callbacks = [];
|
||||
this._messages = [];
|
||||
this.scriptEventReceived = {
|
||||
connect: function (callback) {
|
||||
self._callbacks.push(callback);
|
||||
}
|
||||
};
|
||||
this.emitWebEvent = function (message) {
|
||||
self._messages.push(message);
|
||||
};
|
||||
};
|
||||
|
||||
EventBridge = new TempEventBridge();
|
||||
|
||||
var webChannel = new QWebChannel(qt.webChannelTransport, function (channel) {
|
||||
// replace the TempEventBridge with the real one.
|
||||
var tempEventBridge = EventBridge;
|
||||
EventBridge = channel.objects.eventBridgeWrapper.eventBridge;
|
||||
tempEventBridge._callbacks.forEach(function (callback) {
|
||||
EventBridge.scriptEventReceived.connect(callback);
|
||||
});
|
||||
tempEventBridge._messages.forEach(function (message) {
|
||||
EventBridge.emitWebEvent(message);
|
||||
});
|
||||
});
|
||||
})();
|
41
interface/resources/html/raiseAndLowerKeyboard.js
Normal file
41
interface/resources/html/raiseAndLowerKeyboard.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// Created by Anthony Thibault on 2016-09-02
|
||||
// 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
|
||||
//
|
||||
// Sends messages over the EventBridge when text input is required.
|
||||
//
|
||||
(function () {
|
||||
var POLL_FREQUENCY = 500; // ms
|
||||
var MAX_WARNINGS = 3;
|
||||
var numWarnings = 0;
|
||||
|
||||
function shouldRaiseKeyboard() {
|
||||
if (document.activeElement.nodeName == "INPUT" || document.activeElement.nodeName == "TEXTAREA") {
|
||||
return true;
|
||||
} else {
|
||||
// check for contenteditable attribute
|
||||
for (var i = 0; i < document.activeElement.attributes.length; i++) {
|
||||
if (document.activeElement.attributes[i].name === "contenteditable" &&
|
||||
document.activeElement.attributes[i].value === "true") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
setInterval(function () {
|
||||
var event = shouldRaiseKeyboard() ? "_RAISE_KEYBOARD" : "_LOWER_KEYBOARD";
|
||||
if (typeof EventBridge != "undefined") {
|
||||
EventBridge.emitWebEvent(event);
|
||||
} else {
|
||||
if (numWarnings < MAX_WARNINGS) {
|
||||
console.log("WARNING: no global EventBridge object found");
|
||||
numWarnings++;
|
||||
}
|
||||
}
|
||||
}, POLL_FREQUENCY);
|
||||
})();
|
|
@ -1,6 +1,6 @@
|
|||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.2
|
||||
import QtWebEngine 1.1
|
||||
import QtWebEngine 1.2
|
||||
|
||||
import "controls-uit"
|
||||
import "styles" as HifiStyles
|
||||
|
@ -223,6 +223,9 @@ ScrollingWindow {
|
|||
var newWindow = component.createObject(desktop);
|
||||
request.openIn(newWindow.webView)
|
||||
}
|
||||
onWindowCloseRequested: {
|
||||
root.destroy();
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
desktop.initWebviewProfileHandlers(webview.profile)
|
||||
|
|
|
@ -15,7 +15,7 @@ WebEngineView {
|
|||
id: root
|
||||
property var newUrl;
|
||||
|
||||
profile.httpUserAgent: "Mozilla/5.0 Chrome/38.0 (HighFidelityInterface)"
|
||||
profile: desktop.browserProfile
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log("Connecting JS messaging to Hifi Logging")
|
||||
|
@ -60,9 +60,4 @@ WebEngineView {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This breaks the webchannel used for passing messages. Fixed in Qt 5.6
|
||||
// See https://bugreports.qt.io/browse/QTBUG-49521
|
||||
//profile: desktop.browserProfile
|
||||
}
|
||||
|
|
164
interface/resources/qml/controls/Key.qml
Normal file
164
interface/resources/qml/controls/Key.qml
Normal file
|
@ -0,0 +1,164 @@
|
|||
import QtQuick 2.0
|
||||
|
||||
Item {
|
||||
id: keyItem
|
||||
width: 45
|
||||
height: 50
|
||||
property string glyph: "a"
|
||||
property bool toggle: false // does this button have the toggle behaivor?
|
||||
property bool toggled: false // is this button currently toggled?
|
||||
property alias mouseArea: mouseArea1
|
||||
|
||||
function resetToggledMode(mode) {
|
||||
toggled = mode;
|
||||
if (toggled) {
|
||||
state = "mouseDepressed";
|
||||
} else {
|
||||
state = "";
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea1
|
||||
width: 36
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
|
||||
onCanceled: {
|
||||
if (toggled) {
|
||||
keyItem.state = "mouseDepressed";
|
||||
} else {
|
||||
keyItem.state = "";
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
mouse.accepted = true;
|
||||
webEntity.synthesizeKeyPress(glyph);
|
||||
if (toggle) {
|
||||
toggled = !toggled;
|
||||
}
|
||||
}
|
||||
|
||||
onDoubleClicked: {
|
||||
mouse.accepted = true;
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
keyItem.state = "mouseOver";
|
||||
}
|
||||
|
||||
onExited: {
|
||||
if (toggled) {
|
||||
keyItem.state = "mouseDepressed";
|
||||
} else {
|
||||
keyItem.state = "";
|
||||
}
|
||||
}
|
||||
|
||||
onPressed: {
|
||||
keyItem.state = "mouseClicked";
|
||||
mouse.accepted = true;
|
||||
}
|
||||
|
||||
onReleased: {
|
||||
if (containsMouse) {
|
||||
keyItem.state = "mouseOver";
|
||||
} else {
|
||||
if (toggled) {
|
||||
keyItem.state = "mouseDepressed";
|
||||
} else {
|
||||
keyItem.state = "";
|
||||
}
|
||||
}
|
||||
mouse.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: roundedRect
|
||||
width: 30
|
||||
color: "#121212"
|
||||
radius: 2
|
||||
border.color: "#00000000"
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 4
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 4
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 4
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 4
|
||||
}
|
||||
|
||||
Text {
|
||||
id: letter
|
||||
y: 6
|
||||
width: 50
|
||||
color: "#ffffff"
|
||||
text: glyph
|
||||
style: Text.Normal
|
||||
font.family: "Tahoma"
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 0
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 8
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.pixelSize: 28
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "mouseOver"
|
||||
|
||||
PropertyChanges {
|
||||
target: roundedRect
|
||||
color: "#121212"
|
||||
radius: 3
|
||||
border.width: 2
|
||||
border.color: "#00b4ef"
|
||||
}
|
||||
|
||||
PropertyChanges {
|
||||
target: letter
|
||||
color: "#00b4ef"
|
||||
style: Text.Normal
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "mouseClicked"
|
||||
PropertyChanges {
|
||||
target: roundedRect
|
||||
color: "#1080b8"
|
||||
border.width: 2
|
||||
border.color: "#00b4ef"
|
||||
}
|
||||
|
||||
PropertyChanges {
|
||||
target: letter
|
||||
color: "#121212"
|
||||
styleColor: "#00000000"
|
||||
style: Text.Normal
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "mouseDepressed"
|
||||
PropertyChanges {
|
||||
target: roundedRect
|
||||
color: "#0578b1"
|
||||
border.width: 0
|
||||
}
|
||||
|
||||
PropertyChanges {
|
||||
target: letter
|
||||
color: "#121212"
|
||||
styleColor: "#00000000"
|
||||
style: Text.Normal
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
390
interface/resources/qml/controls/Keyboard.qml
Normal file
390
interface/resources/qml/controls/Keyboard.qml
Normal file
|
@ -0,0 +1,390 @@
|
|||
import QtQuick 2.0
|
||||
|
||||
Item {
|
||||
id: keyboardBase
|
||||
height: 200
|
||||
property alias shiftKey: key27
|
||||
property bool shiftMode: false
|
||||
|
||||
function resetShiftMode(mode) {
|
||||
shiftMode = mode;
|
||||
shiftKey.resetToggledMode(mode);
|
||||
}
|
||||
|
||||
function toUpper(str) {
|
||||
if (str === ",") {
|
||||
return "<";
|
||||
} else if (str === ".") {
|
||||
return ">";
|
||||
} else if (str === "/") {
|
||||
return "?";
|
||||
} else {
|
||||
return str.toUpperCase(str);
|
||||
}
|
||||
}
|
||||
|
||||
function toLower(str) {
|
||||
if (str === "<") {
|
||||
return ",";
|
||||
} else if (str === ">") {
|
||||
return ".";
|
||||
} else if (str === "?") {
|
||||
return "/";
|
||||
} else {
|
||||
return str.toLowerCase(str);
|
||||
}
|
||||
}
|
||||
|
||||
function forEachKey(func) {
|
||||
var i, j;
|
||||
for (i = 0; i < column1.children.length; i++) {
|
||||
var row = column1.children[i];
|
||||
for (j = 0; j < row.children.length; j++) {
|
||||
var key = row.children[j];
|
||||
func(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onShiftModeChanged: {
|
||||
forEachKey(function (key) {
|
||||
if (shiftMode) {
|
||||
key.glyph = keyboardBase.toUpper(key.glyph);
|
||||
} else {
|
||||
key.glyph = keyboardBase.toLower(key.glyph);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function alphaKeyClickedHandler(mouseArea) {
|
||||
// reset shift mode to false after first keypress
|
||||
if (shiftMode) {
|
||||
resetShiftMode(false);
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
// hook up callbacks to every ascii key
|
||||
forEachKey(function (key) {
|
||||
if (/^[a-z]+$/i.test(key.glyph)) {
|
||||
key.mouseArea.onClicked.connect(alphaKeyClickedHandler);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: leftRect
|
||||
y: 0
|
||||
height: 200
|
||||
color: "#252525"
|
||||
anchors.right: keyboardRect.left
|
||||
anchors.rightMargin: 0
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: keyboardRect
|
||||
x: 206
|
||||
y: 0
|
||||
width: 480
|
||||
height: 200
|
||||
color: "#252525"
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 0
|
||||
|
||||
Column {
|
||||
id: column1
|
||||
width: 480
|
||||
height: 200
|
||||
|
||||
Row {
|
||||
id: row1
|
||||
width: 480
|
||||
height: 50
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
|
||||
Key {
|
||||
id: key1
|
||||
width: 44
|
||||
glyph: "q"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key2
|
||||
width: 44
|
||||
glyph: "w"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key3
|
||||
width: 44
|
||||
glyph: "e"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key4
|
||||
width: 43
|
||||
glyph: "r"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key5
|
||||
width: 43
|
||||
glyph: "t"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key6
|
||||
width: 44
|
||||
glyph: "y"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key7
|
||||
width: 44
|
||||
glyph: "u"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key8
|
||||
width: 43
|
||||
glyph: "i"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key9
|
||||
width: 42
|
||||
glyph: "o"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key10
|
||||
width: 44
|
||||
glyph: "p"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key28
|
||||
width: 45
|
||||
glyph: "←"
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: row2
|
||||
width: 480
|
||||
height: 50
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 18
|
||||
|
||||
Key {
|
||||
id: key11
|
||||
width: 43
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key12
|
||||
width: 43
|
||||
glyph: "s"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key13
|
||||
width: 43
|
||||
glyph: "d"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key14
|
||||
width: 43
|
||||
glyph: "f"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key15
|
||||
width: 43
|
||||
glyph: "g"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key16
|
||||
width: 43
|
||||
glyph: "h"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key17
|
||||
width: 43
|
||||
glyph: "j"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key18
|
||||
width: 43
|
||||
glyph: "k"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key19
|
||||
width: 43
|
||||
glyph: "l"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key32
|
||||
width: 75
|
||||
glyph: "⏎"
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: row3
|
||||
width: 480
|
||||
height: 50
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
|
||||
Key {
|
||||
id: key27
|
||||
width: 46
|
||||
glyph: "⇪"
|
||||
toggle: true
|
||||
onToggledChanged: {
|
||||
shiftMode = toggled;
|
||||
}
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key20
|
||||
width: 43
|
||||
glyph: "z"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key21
|
||||
width: 43
|
||||
glyph: "x"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key22
|
||||
width: 43
|
||||
glyph: "c"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key23
|
||||
width: 43
|
||||
glyph: "v"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key24
|
||||
width: 43
|
||||
glyph: "b"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key25
|
||||
width: 43
|
||||
glyph: "n"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key26
|
||||
width: 44
|
||||
glyph: "m"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key31
|
||||
width: 43
|
||||
glyph: ","
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key33
|
||||
width: 43
|
||||
glyph: "."
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key36
|
||||
width: 46
|
||||
glyph: "/"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Row {
|
||||
id: row4
|
||||
width: 480
|
||||
height: 50
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 19
|
||||
|
||||
Key {
|
||||
id: key30
|
||||
width: 89
|
||||
glyph: "&123"
|
||||
mouseArea.onClicked: {
|
||||
keyboardBase.parent.punctuationMode = true;
|
||||
}
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key29
|
||||
width: 285
|
||||
glyph: " "
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key34
|
||||
width: 43
|
||||
glyph: "⇦"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key35
|
||||
x: 343
|
||||
width: 43
|
||||
glyph: "⇨"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: rightRect
|
||||
y: 280
|
||||
height: 200
|
||||
color: "#252525"
|
||||
border.width: 0
|
||||
anchors.left: keyboardRect.right
|
||||
anchors.leftMargin: 0
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 0
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: rectangle1
|
||||
color: "#ffffff"
|
||||
anchors.bottom: keyboardRect.top
|
||||
anchors.bottomMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 0
|
||||
}
|
||||
|
||||
}
|
324
interface/resources/qml/controls/KeyboardPunctuation.qml
Normal file
324
interface/resources/qml/controls/KeyboardPunctuation.qml
Normal file
|
@ -0,0 +1,324 @@
|
|||
import QtQuick 2.0
|
||||
|
||||
Item {
|
||||
id: keyboardBase
|
||||
height: 200
|
||||
Rectangle {
|
||||
id: leftRect
|
||||
y: 0
|
||||
height: 200
|
||||
color: "#252525"
|
||||
anchors.right: keyboardRect.left
|
||||
anchors.rightMargin: 0
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: keyboardRect
|
||||
x: 206
|
||||
y: 0
|
||||
width: 480
|
||||
height: 200
|
||||
color: "#252525"
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 0
|
||||
|
||||
Column {
|
||||
id: column1
|
||||
width: 480
|
||||
height: 200
|
||||
|
||||
Row {
|
||||
id: row1
|
||||
width: 480
|
||||
height: 50
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
|
||||
Key {
|
||||
id: key1
|
||||
width: 43
|
||||
glyph: "1"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key2
|
||||
width: 43
|
||||
glyph: "2"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key3
|
||||
width: 43
|
||||
glyph: "3"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key4
|
||||
width: 43
|
||||
glyph: "4"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key5
|
||||
width: 43
|
||||
glyph: "5"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key6
|
||||
width: 43
|
||||
glyph: "6"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key7
|
||||
width: 43
|
||||
glyph: "7"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key8
|
||||
width: 43
|
||||
glyph: "8"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key9
|
||||
width: 43
|
||||
glyph: "9"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key10
|
||||
width: 43
|
||||
glyph: "0"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key28
|
||||
width: 50
|
||||
glyph: "←"
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: row2
|
||||
width: 480
|
||||
height: 50
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
|
||||
Key {
|
||||
id: key11
|
||||
width: 43
|
||||
glyph: "!"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key12
|
||||
width: 43
|
||||
glyph: "@"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key13
|
||||
width: 43
|
||||
glyph: "#"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key14
|
||||
width: 43
|
||||
glyph: "$"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key15
|
||||
width: 43
|
||||
glyph: "%"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key16
|
||||
width: 43
|
||||
glyph: "^"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key17
|
||||
width: 43
|
||||
glyph: "&"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key18
|
||||
width: 43
|
||||
glyph: "*"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key19
|
||||
width: 43
|
||||
glyph: "("
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key32
|
||||
width: 43
|
||||
glyph: ")"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key37
|
||||
width: 50
|
||||
glyph: "⏎"
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: row3
|
||||
width: 480
|
||||
height: 50
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 4
|
||||
|
||||
Key {
|
||||
id: key27
|
||||
width: 43
|
||||
glyph: "="
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key20
|
||||
width: 43
|
||||
glyph: "+"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key21
|
||||
width: 43
|
||||
glyph: "-"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key22
|
||||
width: 43
|
||||
glyph: "_"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key23
|
||||
width: 43
|
||||
glyph: ";"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key24
|
||||
width: 43
|
||||
glyph: ":"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key25
|
||||
width: 43
|
||||
glyph: "'"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key26
|
||||
width: 43
|
||||
glyph: "\""
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key31
|
||||
width: 43
|
||||
glyph: "<"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key33
|
||||
width: 43
|
||||
glyph: ">"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key36
|
||||
width: 43
|
||||
glyph: "?"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Row {
|
||||
id: row4
|
||||
width: 480
|
||||
height: 50
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 19
|
||||
|
||||
Key {
|
||||
id: key30
|
||||
width: 65
|
||||
glyph: "abc"
|
||||
mouseArea.onClicked: {
|
||||
keyboardBase.parent.punctuationMode = false
|
||||
}
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key29
|
||||
width: 285
|
||||
glyph: " "
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key34
|
||||
width: 43
|
||||
glyph: "⇦"
|
||||
}
|
||||
|
||||
Key {
|
||||
id: key35
|
||||
x: 343
|
||||
width: 43
|
||||
glyph: "⇨"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: rightRect
|
||||
y: 280
|
||||
height: 200
|
||||
color: "#252525"
|
||||
border.width: 0
|
||||
anchors.left: keyboardRect.right
|
||||
anchors.leftMargin: 0
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 0
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: rectangle1
|
||||
color: "#ffffff"
|
||||
anchors.bottom: keyboardRect.top
|
||||
anchors.bottomMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 0
|
||||
}
|
||||
|
||||
}
|
|
@ -1,63 +1,136 @@
|
|||
import QtQuick 2.5
|
||||
import QtWebEngine 1.1
|
||||
import QtWebChannel 1.0
|
||||
|
||||
WebEngineView {
|
||||
id: root
|
||||
property var newUrl;
|
||||
Item {
|
||||
property alias url: root.url
|
||||
property alias eventBridge: eventBridgeWrapper.eventBridge
|
||||
property bool keyboardRaised: false
|
||||
property bool punctuationMode: false
|
||||
|
||||
profile: desktop.browserProfile
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log("Connecting JS messaging to Hifi Logging")
|
||||
// Ensure the JS from the web-engine makes it to our logging
|
||||
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
||||
console.log("Web Window JS message: " + sourceID + " " + lineNumber + " " + message);
|
||||
});
|
||||
QtObject {
|
||||
id: eventBridgeWrapper
|
||||
WebChannel.id: "eventBridgeWrapper"
|
||||
property var eventBridge;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
WebEngineView {
|
||||
id: root
|
||||
x: 0
|
||||
y: 0
|
||||
width: parent.width
|
||||
height: keyboardRaised ? parent.height - keyboard1.height : parent.height
|
||||
|
||||
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();
|
||||
// creates a global EventBridge object.
|
||||
WebEngineScript {
|
||||
id: createGlobalEventBridge
|
||||
sourceCode: eventBridgeJavaScriptToInject
|
||||
injectionPoint: WebEngineScript.DocumentCreation
|
||||
worldId: WebEngineScript.MainWorld
|
||||
}
|
||||
}
|
||||
|
||||
onFeaturePermissionRequested: {
|
||||
grantFeaturePermission(securityOrigin, feature, true);
|
||||
}
|
||||
// detects when to raise and lower virtual keyboard
|
||||
WebEngineScript {
|
||||
id: raiseAndLowerKeyboard
|
||||
injectionPoint: WebEngineScript.Deferred
|
||||
sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js"
|
||||
worldId: WebEngineScript.MainWorld
|
||||
}
|
||||
|
||||
onLoadingChanged: {
|
||||
// Required to support clicking on "hifi://" links
|
||||
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
|
||||
var url = loadRequest.url.toString();
|
||||
if (urlHandler.canHandleUrl(url)) {
|
||||
if (urlHandler.handleUrl(url)) {
|
||||
root.stop();
|
||||
userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard ]
|
||||
|
||||
property string newUrl: ""
|
||||
|
||||
webChannel.registeredObjects: [eventBridgeWrapper]
|
||||
|
||||
Component.onCompleted: {
|
||||
console.log("Connecting JS messaging to Hifi Logging");
|
||||
// Ensure the JS from the web-engine makes it to our logging
|
||||
root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
||||
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
onLoadingChanged: {
|
||||
keyboardRaised = false;
|
||||
punctuationMode = false;
|
||||
keyboard1.resetShiftMode(false);
|
||||
|
||||
// Required to support clicking on "hifi://" links
|
||||
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
|
||||
var url = loadRequest.url.toString();
|
||||
if (urlHandler.canHandleUrl(url)) {
|
||||
if (urlHandler.handleUrl(url)) {
|
||||
root.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onNewViewRequested:{
|
||||
if (desktop) {
|
||||
var component = Qt.createComponent("../Browser.qml");
|
||||
var newWindow = component.createObject(desktop);
|
||||
request.openIn(newWindow.webView);
|
||||
onNewViewRequested:{
|
||||
// desktop is not defined for web-entities
|
||||
if (desktop) {
|
||||
var component = Qt.createComponent("../Browser.qml");
|
||||
var newWindow = component.createObject(desktop);
|
||||
request.openIn(newWindow.webView);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// virtual keyboard, letters
|
||||
Keyboard {
|
||||
id: keyboard1
|
||||
y: keyboardRaised ? parent.height : 0
|
||||
height: keyboardRaised ? 200 : 0
|
||||
visible: keyboardRaised && !punctuationMode
|
||||
enabled: keyboardRaised && !punctuationMode
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 0
|
||||
}
|
||||
|
||||
KeyboardPunctuation {
|
||||
id: keyboard2
|
||||
y: keyboardRaised ? parent.height : 0
|
||||
height: keyboardRaised ? 200 : 0
|
||||
visible: keyboardRaised && punctuationMode
|
||||
enabled: keyboardRaised && punctuationMode
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,8 +46,20 @@ OriginalDesktop.Desktop {
|
|||
}
|
||||
}
|
||||
|
||||
property var toolbars: ({})
|
||||
Component { id: toolbarBuilder; Toolbar { } }
|
||||
// This used to create sysToolbar dynamically with a call to getToolbar() within onCompleted.
|
||||
// Beginning with QT 5.6, this stopped working, as anything added to toolbars too early got
|
||||
// wiped during startup.
|
||||
Toolbar {
|
||||
id: sysToolbar;
|
||||
objectName: "com.highfidelity.interface.toolbar.system";
|
||||
// Magic: sysToolbar.x and y come from settings, and are bound before the properties specified here are applied.
|
||||
x: sysToolbar.x;
|
||||
y: sysToolbar.y;
|
||||
}
|
||||
property var toolbars: (function (map) { // answer dictionary preloaded with sysToolbar
|
||||
map[sysToolbar.objectName] = sysToolbar;
|
||||
return map; })({});
|
||||
|
||||
Component.onCompleted: {
|
||||
WebEngine.settings.javascriptCanOpenWindows = true;
|
||||
|
@ -55,7 +67,6 @@ OriginalDesktop.Desktop {
|
|||
WebEngine.settings.spatialNavigationEnabled = false;
|
||||
WebEngine.settings.localContentCanAccessRemoteUrls = true;
|
||||
|
||||
var sysToolbar = desktop.getToolbar("com.highfidelity.interface.toolbar.system");
|
||||
var toggleHudButton = sysToolbar.addButton({
|
||||
objectName: "hudToggle",
|
||||
imageURL: "../../../icons/hud.svg",
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import QtQuick 2.5
|
||||
import Qt.labs.settings 1.0
|
||||
|
||||
import "../../dialogs"
|
||||
|
||||
PreferencesDialog {
|
||||
id: root
|
||||
objectName: "NetworkingPreferencesDialog"
|
||||
title: "Networking Settings"
|
||||
showCategories: ["Networking"]
|
||||
property var settings: Settings {
|
||||
category: root.objectName
|
||||
property alias x: root.x
|
||||
property alias y: root.y
|
||||
property alias width: root.width
|
||||
property alias height: root.height
|
||||
}
|
||||
}
|
||||
|
|
@ -400,12 +400,10 @@ static const QString STATE_GROUNDED = "Grounded";
|
|||
static const QString STATE_NAV_FOCUSED = "NavigationFocused";
|
||||
|
||||
bool setupEssentials(int& argc, char** argv) {
|
||||
unsigned int listenPort = 0; // bind to an ephemeral port by default
|
||||
const char** constArgv = const_cast<const char**>(argv);
|
||||
const char* portStr = getCmdOption(argc, constArgv, "--listenPort");
|
||||
if (portStr) {
|
||||
listenPort = atoi(portStr);
|
||||
}
|
||||
const int listenPort = portStr ? atoi(portStr) : INVALID_PORT;
|
||||
|
||||
// Set build version
|
||||
QCoreApplication::setApplicationVersion(BuildInfo::VERSION);
|
||||
|
||||
|
|
|
@ -223,7 +223,7 @@ public:
|
|||
// the isHMDMode is true whenever we use the interface from an HMD and not a standard flat display
|
||||
// rendering of several elements depend on that
|
||||
// TODO: carry that information on the Camera as a setting
|
||||
bool isHMDMode() const;
|
||||
virtual bool isHMDMode() const override;
|
||||
glm::mat4 getHMDSensorPose() const;
|
||||
glm::mat4 getEyeOffset(int eye) const;
|
||||
glm::mat4 getEyeProjection(int eye) const;
|
||||
|
|
|
@ -522,6 +522,11 @@ Menu::Menu() {
|
|||
|
||||
// Developer > Network >>>
|
||||
MenuWrapper* networkMenu = developerMenu->addMenu("Network");
|
||||
action = addActionToQMenuAndActionHash(networkMenu, MenuOption::Networking);
|
||||
connect(action, &QAction::triggered, [] {
|
||||
DependencyManager::get<OffscreenUi>()->toggle(QUrl("hifi/dialogs/NetworkingPreferencesDialog.qml"),
|
||||
"NetworkingPreferencesDialog");
|
||||
});
|
||||
addActionToQMenuAndActionHash(networkMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()));
|
||||
addCheckableActionToQMenuAndActionHash(networkMenu,
|
||||
MenuOption::DisableActivityLogger,
|
||||
|
|
|
@ -129,6 +129,7 @@ namespace MenuOption {
|
|||
const QString MuteEnvironment = "Mute Environment";
|
||||
const QString MuteFaceTracking = "Mute Face Tracking";
|
||||
const QString NamesAboveHeads = "Names Above Heads";
|
||||
const QString Networking = "Networking...";
|
||||
const QString NoFaceTracking = "None";
|
||||
const QString OctreeStats = "Entity Statistics";
|
||||
const QString OnePointCalibration = "1 Point Calibration";
|
||||
|
|
|
@ -332,4 +332,19 @@ void setupPreferences() {
|
|||
preferences->addPreference(preference);
|
||||
}
|
||||
}
|
||||
{
|
||||
static const QString RENDER("Networking");
|
||||
|
||||
auto nodelist = DependencyManager::get<NodeList>();
|
||||
{
|
||||
static const int MIN_PORT_NUMBER { 0 };
|
||||
static const int MAX_PORT_NUMBER { 65535 };
|
||||
auto getter = [nodelist] { return static_cast<int>(nodelist->getSocketLocalPort()); };
|
||||
auto setter = [nodelist](int preset) { nodelist->setSocketLocalPort(static_cast<quint16>(preset)); };
|
||||
auto preference = new IntSpinnerPreference(RENDER, "Listening Port", getter, setter);
|
||||
preference->setMin(MIN_PORT_NUMBER);
|
||||
preference->setMax(MAX_PORT_NUMBER);
|
||||
preferences->addPreference(preference);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -512,7 +512,7 @@ void OpenGLDisplayPlugin::compositeOverlay() {
|
|||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
} else {
|
||||
batch.setViewportTransform(ivec4(uvec2(0), _currentFrame->framebuffer->getSize()));
|
||||
batch.setViewportTransform(ivec4(uvec2(0), _compositeFramebuffer->getSize()));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
}
|
||||
});
|
||||
|
@ -536,7 +536,7 @@ void OpenGLDisplayPlugin::compositePointer() {
|
|||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
} else {
|
||||
batch.setViewportTransform(ivec4(uvec2(0), _currentFrame->framebuffer->getSize()));
|
||||
batch.setViewportTransform(ivec4(uvec2(0), _compositeFramebuffer->getSize()));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
}
|
||||
});
|
||||
|
@ -726,7 +726,7 @@ bool OpenGLDisplayPlugin::beginFrameRender(uint32_t frameIndex) {
|
|||
}
|
||||
|
||||
ivec4 OpenGLDisplayPlugin::eyeViewport(Eye eye) const {
|
||||
uvec2 vpSize = _currentFrame->framebuffer->getSize();
|
||||
uvec2 vpSize = _compositeFramebuffer->getSize();
|
||||
vpSize.x /= 2;
|
||||
uvec2 vpPos;
|
||||
if (eye == Eye::Right) {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <gpu/Context.h>
|
||||
|
||||
#include "EntityTreeRenderer.h"
|
||||
#include "EntitiesRendererLogging.h"
|
||||
|
||||
const float METERS_TO_INCHES = 39.3701f;
|
||||
static uint32_t _currentWebCount { 0 };
|
||||
|
@ -37,6 +38,35 @@ static uint64_t MAX_NO_RENDER_INTERVAL = 30 * USECS_PER_SECOND;
|
|||
static int MAX_WINDOW_SIZE = 4096;
|
||||
static float OPAQUE_ALPHA_THRESHOLD = 0.99f;
|
||||
|
||||
void WebEntityAPIHelper::synthesizeKeyPress(QString key) {
|
||||
if (_renderableWebEntityItem) {
|
||||
_renderableWebEntityItem->synthesizeKeyPress(key);
|
||||
}
|
||||
}
|
||||
|
||||
void WebEntityAPIHelper::emitScriptEvent(const QVariant& message) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "emitScriptEvent", Qt::QueuedConnection, Q_ARG(QVariant, message));
|
||||
} else {
|
||||
emit scriptEventReceived(message);
|
||||
}
|
||||
}
|
||||
|
||||
void WebEntityAPIHelper::emitWebEvent(const QVariant& message) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "emitWebEvent", Qt::QueuedConnection, Q_ARG(QVariant, message));
|
||||
} else {
|
||||
// special case to handle raising and lowering the virtual keyboard
|
||||
if (message.type() == QVariant::String && message.toString() == "_RAISE_KEYBOARD" && _renderableWebEntityItem) {
|
||||
_renderableWebEntityItem->setKeyboardRaised(true);
|
||||
} else if (message.type() == QVariant::String && message.toString() == "_LOWER_KEYBOARD" && _renderableWebEntityItem) {
|
||||
_renderableWebEntityItem->setKeyboardRaised(false);
|
||||
} else {
|
||||
emit webEventReceived(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EntityItemPointer RenderableWebEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
EntityItemPointer entity{ new RenderableWebEntityItem(entityID) };
|
||||
entity->setProperties(properties);
|
||||
|
@ -46,9 +76,26 @@ EntityItemPointer RenderableWebEntityItem::factory(const EntityItemID& entityID,
|
|||
RenderableWebEntityItem::RenderableWebEntityItem(const EntityItemID& entityItemID) :
|
||||
WebEntityItem(entityItemID) {
|
||||
qDebug() << "Created web entity " << getID();
|
||||
|
||||
_touchDevice.setCapabilities(QTouchDevice::Position);
|
||||
_touchDevice.setType(QTouchDevice::TouchScreen);
|
||||
_touchDevice.setName("RenderableWebEntityItemTouchDevice");
|
||||
_touchDevice.setMaximumTouchPoints(4);
|
||||
|
||||
_webEntityAPIHelper = new WebEntityAPIHelper;
|
||||
_webEntityAPIHelper->setRenderableWebEntityItem(this);
|
||||
_webEntityAPIHelper->moveToThread(qApp->thread());
|
||||
|
||||
// forward web events to EntityScriptingInterface
|
||||
auto entities = DependencyManager::get<EntityScriptingInterface>();
|
||||
QObject::connect(_webEntityAPIHelper, &WebEntityAPIHelper::webEventReceived, [=](const QVariant& message) {
|
||||
emit entities->webEventReceived(entityItemID, message);
|
||||
});
|
||||
}
|
||||
|
||||
RenderableWebEntityItem::~RenderableWebEntityItem() {
|
||||
_webEntityAPIHelper->setRenderableWebEntityItem(nullptr);
|
||||
_webEntityAPIHelper->deleteLater();
|
||||
destroyWebSurface();
|
||||
qDebug() << "Destroyed web entity " << getID();
|
||||
}
|
||||
|
@ -60,6 +107,20 @@ bool RenderableWebEntityItem::buildWebSurface(EntityTreeRenderer* renderer) {
|
|||
}
|
||||
qDebug() << "Building web surface";
|
||||
|
||||
QString javaScriptToInject;
|
||||
QFile webChannelFile(":qtwebchannel/qwebchannel.js");
|
||||
QFile createGlobalEventBridgeFile(PathUtils::resourcesPath() + "/html/createGlobalEventBridge.js");
|
||||
if (webChannelFile.open(QFile::ReadOnly | QFile::Text) &&
|
||||
createGlobalEventBridgeFile.open(QFile::ReadOnly | QFile::Text)) {
|
||||
QString webChannelStr = QTextStream(&webChannelFile).readAll();
|
||||
QString createGlobalEventBridgeStr = QTextStream(&createGlobalEventBridgeFile).readAll();
|
||||
|
||||
// concatenate these js files
|
||||
javaScriptToInject = webChannelStr + createGlobalEventBridgeStr;
|
||||
} else {
|
||||
qCWarning(entitiesrenderer) << "unable to find qwebchannel.js or createGlobalEventBridge.js";
|
||||
}
|
||||
|
||||
++_currentWebCount;
|
||||
// Save the original GL context, because creating a QML surface will create a new context
|
||||
QOpenGLContext * currentContext = QOpenGLContext::currentContext();
|
||||
|
@ -67,10 +128,14 @@ bool RenderableWebEntityItem::buildWebSurface(EntityTreeRenderer* renderer) {
|
|||
_webSurface = new OffscreenQmlSurface();
|
||||
_webSurface->create(currentContext);
|
||||
_webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/controls/"));
|
||||
_webSurface->load("WebView.qml");
|
||||
_webSurface->load("WebView.qml", [&](QQmlContext* context, QObject* obj) {
|
||||
context->setContextProperty("eventBridgeJavaScriptToInject", QVariant(javaScriptToInject));
|
||||
});
|
||||
_webSurface->resume();
|
||||
_webSurface->getRootItem()->setProperty("eventBridge", QVariant::fromValue(_webEntityAPIHelper));
|
||||
_webSurface->getRootItem()->setProperty("url", _sourceUrl);
|
||||
_webSurface->getRootContext()->setContextProperty("desktop", QVariant());
|
||||
_webSurface->getRootContext()->setContextProperty("webEntity", _webEntityAPIHelper);
|
||||
_connection = QObject::connect(_webSurface, &OffscreenQmlSurface::textureUpdated, [&](GLuint textureId) {
|
||||
_texture = textureId;
|
||||
});
|
||||
|
@ -93,10 +158,14 @@ bool RenderableWebEntityItem::buildWebSurface(EntityTreeRenderer* renderer) {
|
|||
point.setState(Qt::TouchPointReleased);
|
||||
glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _dpi);
|
||||
QPointF windowPoint(windowPos.x, windowPos.y);
|
||||
point.setScenePos(windowPoint);
|
||||
point.setPos(windowPoint);
|
||||
QList<QTouchEvent::TouchPoint> touchPoints;
|
||||
touchPoints.push_back(point);
|
||||
QTouchEvent* touchEvent = new QTouchEvent(QEvent::TouchEnd, nullptr, Qt::NoModifier, Qt::TouchPointReleased, touchPoints);
|
||||
touchEvent->setWindow(_webSurface->getWindow());
|
||||
touchEvent->setDevice(&_touchDevice);
|
||||
touchEvent->setTarget(_webSurface->getRootItem());
|
||||
QCoreApplication::postEvent(_webSurface->getWindow(), touchEvent);
|
||||
}
|
||||
});
|
||||
|
@ -210,7 +279,6 @@ void RenderableWebEntityItem::handlePointerEvent(const PointerEvent& event) {
|
|||
|
||||
glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _dpi);
|
||||
QPointF windowPoint(windowPos.x, windowPos.y);
|
||||
|
||||
if (event.getType() == PointerEvent::Move) {
|
||||
// Forward a mouse move event to webSurface
|
||||
QMouseEvent* mouseEvent = new QMouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, Qt::NoButton, Qt::NoButton, Qt::NoModifier);
|
||||
|
@ -252,9 +320,9 @@ void RenderableWebEntityItem::handlePointerEvent(const PointerEvent& event) {
|
|||
touchPoints.push_back(point);
|
||||
|
||||
QTouchEvent* touchEvent = new QTouchEvent(type);
|
||||
touchEvent->setWindow(nullptr);
|
||||
touchEvent->setDevice(nullptr);
|
||||
touchEvent->setTarget(nullptr);
|
||||
touchEvent->setWindow(_webSurface->getWindow());
|
||||
touchEvent->setDevice(&_touchDevice);
|
||||
touchEvent->setTarget(_webSurface->getRootItem());
|
||||
touchEvent->setTouchPoints(touchPoints);
|
||||
touchEvent->setTouchPointStates(touchPointState);
|
||||
|
||||
|
@ -303,3 +371,63 @@ bool RenderableWebEntityItem::isTransparent() {
|
|||
float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
|
||||
return fadeRatio < OPAQUE_ALPHA_THRESHOLD;
|
||||
}
|
||||
|
||||
// UTF-8 encoded symbols
|
||||
static const uint8_t UPWARDS_WHITE_ARROW_FROM_BAR[] = { 0xE2, 0x87, 0xAA, 0x00 }; // shift
|
||||
static const uint8_t LEFT_ARROW[] = { 0xE2, 0x86, 0x90, 0x00 }; // backspace
|
||||
static const uint8_t LEFTWARD_WHITE_ARROW[] = { 0xE2, 0x87, 0xA6, 0x00 }; // left arrow
|
||||
static const uint8_t RIGHTWARD_WHITE_ARROW[] = { 0xE2, 0x87, 0xA8, 0x00 }; // right arrow
|
||||
static const uint8_t ASTERISIM[] = { 0xE2, 0x81, 0x82, 0x00 }; // symbols
|
||||
static const uint8_t RETURN_SYMBOL[] = { 0xE2, 0x8F, 0x8E, 0x00 }; // return
|
||||
static const char PUNCTUATION_STRING[] = "&123";
|
||||
static const char ALPHABET_STRING[] = "abc";
|
||||
|
||||
static bool equals(const QByteArray& byteArray, const uint8_t* ptr) {
|
||||
int i;
|
||||
for (i = 0; i < byteArray.size(); i++) {
|
||||
if ((char)ptr[i] != byteArray[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return ptr[i] == 0x00;
|
||||
}
|
||||
|
||||
void RenderableWebEntityItem::synthesizeKeyPress(QString key) {
|
||||
auto utf8Key = key.toUtf8();
|
||||
|
||||
int scanCode = (int)utf8Key[0];
|
||||
QString keyString = key;
|
||||
if (equals(utf8Key, UPWARDS_WHITE_ARROW_FROM_BAR) || equals(utf8Key, ASTERISIM) ||
|
||||
equals(utf8Key, (uint8_t*)PUNCTUATION_STRING) || equals(utf8Key, (uint8_t*)ALPHABET_STRING)) {
|
||||
return; // ignore
|
||||
} else if (equals(utf8Key, LEFT_ARROW)) {
|
||||
scanCode = Qt::Key_Backspace;
|
||||
keyString = "\x08";
|
||||
} else if (equals(utf8Key, RETURN_SYMBOL)) {
|
||||
scanCode = Qt::Key_Return;
|
||||
keyString = "\x0d";
|
||||
} else if (equals(utf8Key, LEFTWARD_WHITE_ARROW)) {
|
||||
scanCode = Qt::Key_Left;
|
||||
keyString = "";
|
||||
} else if (equals(utf8Key, RIGHTWARD_WHITE_ARROW)) {
|
||||
scanCode = Qt::Key_Right;
|
||||
keyString = "";
|
||||
}
|
||||
|
||||
QKeyEvent* pressEvent = new QKeyEvent(QEvent::KeyPress, scanCode, Qt::NoModifier, keyString);
|
||||
QKeyEvent* releaseEvent = new QKeyEvent(QEvent::KeyRelease, scanCode, Qt::NoModifier, keyString);
|
||||
QCoreApplication::postEvent(getEventHandler(), pressEvent);
|
||||
QCoreApplication::postEvent(getEventHandler(), releaseEvent);
|
||||
}
|
||||
|
||||
void RenderableWebEntityItem::emitScriptEvent(const QVariant& message) {
|
||||
_webEntityAPIHelper->emitScriptEvent(message);
|
||||
}
|
||||
|
||||
void RenderableWebEntityItem::setKeyboardRaised(bool raised) {
|
||||
|
||||
// raise the keyboard only while in HMD mode and it's being requested.
|
||||
bool value = AbstractViewStateInterface::instance()->isHMDMode() && raised;
|
||||
|
||||
_webSurface->getRootItem()->setProperty("keyboardRaised", QVariant(value));
|
||||
}
|
||||
|
|
|
@ -22,6 +22,27 @@ class OffscreenQmlSurface;
|
|||
class QWindow;
|
||||
class QObject;
|
||||
class EntityTreeRenderer;
|
||||
class RenderableWebEntityItem;
|
||||
|
||||
class WebEntityAPIHelper : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
void setRenderableWebEntityItem(RenderableWebEntityItem* renderableWebEntityItem) {
|
||||
_renderableWebEntityItem = renderableWebEntityItem;
|
||||
}
|
||||
Q_INVOKABLE void synthesizeKeyPress(QString key);
|
||||
|
||||
// event bridge
|
||||
public slots:
|
||||
void emitScriptEvent(const QVariant& scriptMessage);
|
||||
void emitWebEvent(const QVariant& webMessage);
|
||||
signals:
|
||||
void scriptEventReceived(const QVariant& message);
|
||||
void webEventReceived(const QVariant& message);
|
||||
|
||||
protected:
|
||||
RenderableWebEntityItem* _renderableWebEntityItem{ nullptr };
|
||||
};
|
||||
|
||||
class RenderableWebEntityItem : public WebEntityItem {
|
||||
public:
|
||||
|
@ -42,10 +63,16 @@ public:
|
|||
void update(const quint64& now) override;
|
||||
bool needsToCallUpdate() const override { return _webSurface != nullptr; }
|
||||
|
||||
virtual void emitScriptEvent(const QVariant& message) override;
|
||||
void setKeyboardRaised(bool raised);
|
||||
|
||||
SIMPLE_RENDERABLE();
|
||||
|
||||
virtual bool isTransparent() override;
|
||||
|
||||
public:
|
||||
void synthesizeKeyPress(QString key);
|
||||
|
||||
private:
|
||||
bool buildWebSurface(EntityTreeRenderer* renderer);
|
||||
void destroyWebSurface();
|
||||
|
@ -58,6 +85,8 @@ private:
|
|||
bool _pressed{ false };
|
||||
QTouchEvent _lastTouchEvent { QEvent::TouchUpdate };
|
||||
uint64_t _lastRenderTime{ 0 };
|
||||
QTouchDevice _touchDevice;
|
||||
WebEntityAPIHelper* _webEntityAPIHelper;
|
||||
|
||||
QMetaObject::Connection _mousePressConnection;
|
||||
QMetaObject::Connection _mouseReleaseConnection;
|
||||
|
@ -65,5 +94,4 @@ private:
|
|||
QMetaObject::Connection _hoverLeaveConnection;
|
||||
};
|
||||
|
||||
|
||||
#endif // hifi_RenderableWebEntityItem_h
|
||||
|
|
|
@ -456,6 +456,8 @@ public:
|
|||
bool isFading() const { return _isFading; }
|
||||
float getFadingRatio() const { return (isFading() ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f); }
|
||||
|
||||
virtual void emitScriptEvent(const QVariant& message) {}
|
||||
|
||||
protected:
|
||||
|
||||
void setSimulated(bool simulated) { _simulated = simulated; }
|
||||
|
|
|
@ -1289,6 +1289,17 @@ bool EntityScriptingInterface::wantsHandControllerPointerEvents(QUuid id) {
|
|||
return result;
|
||||
}
|
||||
|
||||
void EntityScriptingInterface::emitScriptEvent(const EntityItemID& entityID, const QVariant& message) {
|
||||
if (_entityTree) {
|
||||
_entityTree->withReadLock([&] {
|
||||
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID));
|
||||
if (entity) {
|
||||
entity->emitScriptEvent(message);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
float EntityScriptingInterface::calculateCost(float mass, float oldVelocity, float newVelocity) {
|
||||
return std::abs(mass * (newVelocity - oldVelocity));
|
||||
}
|
||||
|
@ -1305,3 +1316,4 @@ float EntityScriptingInterface::getCostMultiplier() {
|
|||
void EntityScriptingInterface::setCostMultiplier(float value) {
|
||||
costMultiplier = value;
|
||||
}
|
||||
|
||||
|
|
|
@ -205,6 +205,8 @@ public slots:
|
|||
|
||||
Q_INVOKABLE bool wantsHandControllerPointerEvents(QUuid id);
|
||||
|
||||
Q_INVOKABLE void emitScriptEvent(const EntityItemID& entityID, const QVariant& message);
|
||||
|
||||
signals:
|
||||
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
|
||||
|
||||
|
@ -232,6 +234,8 @@ signals:
|
|||
void clearingEntities();
|
||||
void debitEnergySource(float value);
|
||||
|
||||
void webEventReceived(const EntityItemID& entityItemID, const QVariant& message);
|
||||
|
||||
private:
|
||||
bool actionWorker(const QUuid& entityID, std::function<bool(EntitySimulationPointer, EntityItemPointer)> actor);
|
||||
bool setVoxels(QUuid entityID, std::function<bool(PolyVoxEntityItem&)> actor);
|
||||
|
|
|
@ -479,6 +479,7 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) {
|
|||
|
||||
auto rootContext = getRootContext();
|
||||
rootContext->setContextProperty("urlHandler", new UrlHandler());
|
||||
rootContext->setContextProperty("resourceDirectoryUrl", QUrl::fromLocalFile(PathUtils::resourcesPath()));
|
||||
}
|
||||
|
||||
void OffscreenQmlSurface::resize(const QSize& newSize_, bool forceResize) {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <QtCore/QDataStream>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtNetwork/QHostInfo>
|
||||
|
||||
|
@ -25,6 +26,7 @@
|
|||
|
||||
#include <LogHandler.h>
|
||||
#include <NumericalConstants.h>
|
||||
#include <SettingHandle.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <UUID.h>
|
||||
|
||||
|
@ -34,12 +36,14 @@
|
|||
#include "NetworkLogging.h"
|
||||
#include "udt/Packet.h"
|
||||
|
||||
static Setting::Handle<quint16> LIMITED_NODELIST_LOCAL_PORT("LimitedNodeList.LocalPort", 0);
|
||||
|
||||
const std::set<NodeType_t> SOLO_NODE_TYPES = {
|
||||
NodeType::AvatarMixer,
|
||||
NodeType::AudioMixer
|
||||
};
|
||||
|
||||
LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short dtlsListenPort) :
|
||||
LimitedNodeList::LimitedNodeList(int socketListenPort, int dtlsListenPort) :
|
||||
_sessionUUID(),
|
||||
_nodeHash(),
|
||||
_nodeMutex(QReadWriteLock::Recursive),
|
||||
|
@ -62,11 +66,11 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short
|
|||
}
|
||||
|
||||
qRegisterMetaType<ConnectionStep>("ConnectionStep");
|
||||
|
||||
_nodeSocket.bind(QHostAddress::AnyIPv4, socketListenPort);
|
||||
auto port = (socketListenPort != INVALID_PORT) ? socketListenPort : LIMITED_NODELIST_LOCAL_PORT.get();
|
||||
_nodeSocket.bind(QHostAddress::AnyIPv4, port);
|
||||
qCDebug(networking) << "NodeList socket is listening on" << _nodeSocket.localPort();
|
||||
|
||||
if (dtlsListenPort > 0) {
|
||||
if (dtlsListenPort != INVALID_PORT) {
|
||||
// only create the DTLS socket during constructor if a custom port is passed
|
||||
_dtlsSocket = new QUdpSocket(this);
|
||||
|
||||
|
@ -157,6 +161,18 @@ void LimitedNodeList::setPermissions(const NodePermissions& newPermissions) {
|
|||
}
|
||||
}
|
||||
|
||||
void LimitedNodeList::setSocketLocalPort(quint16 socketLocalPort) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "setSocketLocalPort", Qt::QueuedConnection,
|
||||
Q_ARG(quint16, socketLocalPort));
|
||||
return;
|
||||
}
|
||||
if (_nodeSocket.localPort() != socketLocalPort) {
|
||||
_nodeSocket.rebind(socketLocalPort);
|
||||
LIMITED_NODELIST_LOCAL_PORT.set(socketLocalPort);
|
||||
}
|
||||
}
|
||||
|
||||
QUdpSocket& LimitedNodeList::getDTLSSocket() {
|
||||
if (!_dtlsSocket) {
|
||||
// DTLS socket getter called but no DTLS socket exists, create it now
|
||||
|
@ -606,6 +622,12 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t
|
|||
});
|
||||
}
|
||||
|
||||
// Signal when a socket changes, so we can start the hole punch over.
|
||||
auto weakPtr = newNodePointer.toWeakRef(); // We don't want the lambda to hold a strong ref
|
||||
connect(newNodePointer.data(), &NetworkPeer::socketUpdated, this, [=] {
|
||||
emit nodeSocketUpdated(weakPtr);
|
||||
});
|
||||
|
||||
return newNodePointer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,8 @@
|
|||
#include "udt/Socket.h"
|
||||
#include "UUIDHasher.h"
|
||||
|
||||
const int INVALID_PORT = -1;
|
||||
|
||||
const quint64 NODE_SILENCE_THRESHOLD_MSECS = 5 * 1000;
|
||||
|
||||
extern const std::set<NodeType_t> SOLO_NODE_TYPES;
|
||||
|
@ -113,6 +115,8 @@ public:
|
|||
bool getThisNodeCanKick() const { return _permissions.can(NodePermissions::Permission::canKick); }
|
||||
|
||||
quint16 getSocketLocalPort() const { return _nodeSocket.localPort(); }
|
||||
Q_INVOKABLE void setSocketLocalPort(quint16 socketLocalPort);
|
||||
|
||||
QUdpSocket& getDTLSSocket();
|
||||
|
||||
PacketReceiver& getPacketReceiver() { return *_packetReceiver; }
|
||||
|
@ -250,6 +254,7 @@ signals:
|
|||
|
||||
void uuidChanged(const QUuid& ownerUUID, const QUuid& oldUUID);
|
||||
void nodeAdded(SharedNodePointer);
|
||||
void nodeSocketUpdated(SharedNodePointer);
|
||||
void nodeKilled(SharedNodePointer);
|
||||
void nodeActivated(SharedNodePointer);
|
||||
|
||||
|
@ -267,9 +272,9 @@ protected slots:
|
|||
void errorTestingLocalSocket();
|
||||
|
||||
protected:
|
||||
LimitedNodeList(unsigned short socketListenPort = 0, unsigned short dtlsListenPort = 0);
|
||||
LimitedNodeList(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton
|
||||
void operator=(LimitedNodeList const&); // Don't implement, needed to avoid copies of singleton
|
||||
LimitedNodeList(int socketListenPort = INVALID_PORT, int dtlsListenPort = INVALID_PORT);
|
||||
LimitedNodeList(LimitedNodeList const&) = delete; // Don't implement, needed to avoid copies of singleton
|
||||
void operator=(LimitedNodeList const&) = delete; // Don't implement, needed to avoid copies of singleton
|
||||
|
||||
qint64 sendPacket(std::unique_ptr<NLPacket> packet, const Node& destinationNode,
|
||||
const HifiSockAddr& overridenSockAddr);
|
||||
|
|
|
@ -63,6 +63,7 @@ void NetworkPeer::setPublicSocket(const HifiSockAddr& publicSocket) {
|
|||
|
||||
if (!wasOldSocketNull) {
|
||||
qCDebug(networking) << "Public socket change for node" << *this;
|
||||
emit socketUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -82,6 +83,7 @@ void NetworkPeer::setLocalSocket(const HifiSockAddr& localSocket) {
|
|||
|
||||
if (!wasOldSocketNull) {
|
||||
qCDebug(networking) << "Local socket change for node" << *this;
|
||||
emit socketUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -101,6 +103,7 @@ void NetworkPeer::setSymmetricSocket(const HifiSockAddr& symmetricSocket) {
|
|||
|
||||
if (!wasOldSocketNull) {
|
||||
qCDebug(networking) << "Symmetric socket change for node" << *this;
|
||||
emit socketUpdated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,9 +81,12 @@ public:
|
|||
public slots:
|
||||
void startPingTimer();
|
||||
void stopPingTimer();
|
||||
|
||||
signals:
|
||||
void pingTimerTimeout();
|
||||
void socketActivated(const HifiSockAddr& sockAddr);
|
||||
void socketUpdated();
|
||||
|
||||
protected:
|
||||
void setActiveSocket(HifiSockAddr* discoveredSocket);
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
const int KEEPALIVE_PING_INTERVAL_MS = 1000;
|
||||
|
||||
NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned short dtlsListenPort) :
|
||||
NodeList::NodeList(char newOwnerType, int socketListenPort, int dtlsListenPort) :
|
||||
LimitedNodeList(socketListenPort, dtlsListenPort),
|
||||
_ownerType(newOwnerType),
|
||||
_nodeTypesOfInterest(),
|
||||
|
@ -93,6 +93,7 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned
|
|||
|
||||
// anytime we get a new node we will want to attempt to punch to it
|
||||
connect(this, &LimitedNodeList::nodeAdded, this, &NodeList::startNodeHolePunch);
|
||||
connect(this, &LimitedNodeList::nodeSocketUpdated, this, &NodeList::startNodeHolePunch);
|
||||
|
||||
// anytime we get a new node we may need to re-send our set of ignored node IDs to it
|
||||
connect(this, &LimitedNodeList::nodeActivated, this, &NodeList::maybeSendIgnoreSetToNode);
|
||||
|
|
|
@ -116,10 +116,10 @@ private slots:
|
|||
void maybeSendIgnoreSetToNode(SharedNodePointer node);
|
||||
|
||||
private:
|
||||
NodeList() : LimitedNodeList(0, 0) { assert(false); } // Not implemented, needed for DependencyManager templates compile
|
||||
NodeList(char ownerType, unsigned short socketListenPort = 0, unsigned short dtlsListenPort = 0);
|
||||
NodeList(NodeList const&); // Don't implement, needed to avoid copies of singleton
|
||||
void operator=(NodeList const&); // Don't implement, needed to avoid copies of singleton
|
||||
NodeList() : LimitedNodeList(INVALID_PORT, INVALID_PORT) { assert(false); } // Not implemented, needed for DependencyManager templates compile
|
||||
NodeList(char ownerType, int socketListenPort = INVALID_PORT, int dtlsListenPort = INVALID_PORT);
|
||||
NodeList(NodeList const&) = delete; // Don't implement, needed to avoid copies of singleton
|
||||
void operator=(NodeList const&) = delete; // Don't implement, needed to avoid copies of singleton
|
||||
|
||||
void processDomainServerAuthRequest(const QByteArray& packet);
|
||||
void requestAuthForDomainServer();
|
||||
|
|
|
@ -63,10 +63,12 @@ void Socket::bind(const QHostAddress& address, quint16 port) {
|
|||
}
|
||||
|
||||
void Socket::rebind() {
|
||||
quint16 oldPort = _udpSocket.localPort();
|
||||
rebind(_udpSocket.localPort());
|
||||
}
|
||||
|
||||
void Socket::rebind(quint16 localPort) {
|
||||
_udpSocket.close();
|
||||
bind(QHostAddress::AnyIPv4, oldPort);
|
||||
bind(QHostAddress::AnyIPv4, localPort);
|
||||
}
|
||||
|
||||
void Socket::setSystemBufferSizes() {
|
||||
|
|
|
@ -61,8 +61,9 @@ public:
|
|||
qint64 writeDatagram(const QByteArray& datagram, const HifiSockAddr& sockAddr);
|
||||
|
||||
void bind(const QHostAddress& address, quint16 port = 0);
|
||||
void rebind(quint16 port);
|
||||
void rebind();
|
||||
|
||||
|
||||
void setPacketFilterOperator(PacketFilterOperator filterOperator) { _packetFilterOperator = filterOperator; }
|
||||
void setPacketHandler(PacketHandler handler) { _packetHandler = handler; }
|
||||
void setMessageHandler(MessageHandler handler) { _messageHandler = handler; }
|
||||
|
|
|
@ -48,6 +48,8 @@ public:
|
|||
|
||||
virtual void pushPostUpdateLambda(void* key, std::function<void()> func) = 0;
|
||||
|
||||
virtual bool isHMDMode() const = 0;
|
||||
|
||||
// FIXME - we shouldn't assume that there's a single instance of an AbstractViewStateInterface
|
||||
static AbstractViewStateInterface* instance();
|
||||
static void setInstance(AbstractViewStateInterface* instance);
|
||||
|
|
|
@ -705,7 +705,7 @@ void RenderDeferredLocals::run(const render::SceneContextPointer& sceneContext,
|
|||
static int frame = 0;
|
||||
frame++;
|
||||
|
||||
if (frame % 1000 == 0) {
|
||||
if (frame % 2000 == 0) {
|
||||
lightClusters->updateFrustum(viewFrustum);
|
||||
|
||||
lightClusters->updateVisibleLights(lightIndices);
|
||||
|
|
49
libraries/render-utils/src/LightClusterGrid.slh
Normal file
49
libraries/render-utils/src/LightClusterGrid.slh
Normal file
|
@ -0,0 +1,49 @@
|
|||
<!
|
||||
// LightCluserGrid.slh
|
||||
//
|
||||
// Created by Sam Gateau on 9/8/16.
|
||||
// Copyright 2013 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
|
||||
!>
|
||||
<@if not RENDER_LIGHT_CLUSTER_GRID_SLH@>
|
||||
<@def RENDER_LIGHT_CLUSTER_GRID_SLH@>
|
||||
|
||||
|
||||
|
||||
struct FrustumGrid {
|
||||
float frustumNear;
|
||||
float rangeNear;
|
||||
float rangeFar;
|
||||
float frustumFar;
|
||||
ivec3 dims;
|
||||
float spare;
|
||||
mat4 eyeToGridProj;
|
||||
mat4 worldToEyeMat;
|
||||
mat4 eyeToWorldMat;
|
||||
};
|
||||
|
||||
uniform frustumGridBuffer {
|
||||
FrustumGrid frustumGrid;
|
||||
};
|
||||
|
||||
float projection_getNear(mat4 projection) {
|
||||
float planeC = projection[2][3] + projection[2][2];
|
||||
float planeD = projection[3][2];
|
||||
return planeD / planeC;
|
||||
}
|
||||
float projection_getFar(mat4 projection) {
|
||||
//float planeA = projection[0][3] - projection[0][2]; All Zeros
|
||||
//float planeB = projection[1][3] - projection[1][2]; All Zeros
|
||||
float planeC = projection[2][3] - projection[2][2];
|
||||
float planeD = /*projection[3][3]*/ -projection[3][2];
|
||||
return planeD / planeC;
|
||||
}
|
||||
|
||||
// glsl / C++ compatible source as interface for FrustrumGrid
|
||||
<@include LightClusterGrid_shared.slh@>
|
||||
|
||||
// end of hybrid include
|
||||
|
||||
<@endif@>
|
92
libraries/render-utils/src/LightClusterGrid_shared.slh
Normal file
92
libraries/render-utils/src/LightClusterGrid_shared.slh
Normal file
|
@ -0,0 +1,92 @@
|
|||
// glsl / C++ compatible source as interface for FrustrumGrid
|
||||
|
||||
int frustumGrid_numClusters() {
|
||||
return frustumGrid.dims.x * frustumGrid.dims.y * frustumGrid.dims.z;
|
||||
}
|
||||
|
||||
|
||||
float frustumGrid_depthRamp(float linear) {
|
||||
// return linear;
|
||||
return linear * linear;
|
||||
}
|
||||
float frustumGrid_depthRampInverse(float volume) {
|
||||
// return volume;
|
||||
return sqrt(volume);
|
||||
}
|
||||
|
||||
vec3 frustumGrid_gridToVolume(vec3 pos, ivec3 dims) {
|
||||
vec3 gridScale = vec3(1.0, 1.0, 1.0) / vec3(dims);
|
||||
vec3 volumePos = pos * gridScale;
|
||||
volumePos.z = frustumGrid_depthRamp(volumePos.z);
|
||||
return volumePos;
|
||||
}
|
||||
|
||||
|
||||
vec3 frustumGrid_volumeToGrid(vec3 vpos, ivec3 dims) {
|
||||
vec3 gridPos = vec3(vpos.x, vpos.y, frustumGrid_depthRampInverse(vpos.z)) * vec3(dims);
|
||||
return gridPos;
|
||||
}
|
||||
|
||||
vec4 frustumGrid_volumeToClip(vec3 vpos, float rangeNear, float rangeFar) {
|
||||
vec3 ndcPos = vec3(-1.0 + 2.0 * vpos.x, -1.0 + 2.0 * vpos.y, vpos.z);
|
||||
float depth = rangeNear * (1 - ndcPos.z) + rangeFar * (ndcPos.z);
|
||||
vec4 clipPos = vec4(ndcPos.x * depth, ndcPos.y * depth, 1.0, depth);
|
||||
return clipPos;
|
||||
}
|
||||
|
||||
vec3 frustumGrid_clipToEye(vec4 clipPos, mat4 projection) {
|
||||
return vec3(
|
||||
(clipPos.x + projection[2][0] * clipPos.w) / projection[0][0],
|
||||
(clipPos.y + projection[2][1] * clipPos.w) / projection[1][1],
|
||||
-clipPos.w
|
||||
//, (clipPos.z - projection[3][3] * clipPos.w) / projection[3][2]
|
||||
);
|
||||
}
|
||||
|
||||
vec3 frustumGrid_volumeToEye(vec3 vpos, mat4 projection, float rangeNear, float rangeFar) {
|
||||
return frustumGrid_clipToEye(frustumGrid_volumeToClip(vpos, rangeNear, rangeFar), projection);
|
||||
}
|
||||
|
||||
|
||||
vec3 frustumGrid_eyeToVolume(vec3 epos, mat4 projection, float rangeNear, float rangeFar) {
|
||||
vec4 clipPos = vec4(epos.x * projection[0][0] + epos.z * projection[2][0],
|
||||
epos.y * projection[1][1] + epos.z * projection[2][1],
|
||||
epos.z * projection[2][2] + projection[2][3],
|
||||
-epos.z);
|
||||
vec4 ndcPos = clipPos / clipPos.w;
|
||||
|
||||
vec3 volumePos = vec3(0.5 * (ndcPos.x + 1.0), 0.5 * (ndcPos.y + 1.0), (clipPos.w - rangeNear) / (rangeFar - rangeNear));
|
||||
return volumePos;
|
||||
}
|
||||
|
||||
|
||||
vec3 frustumGrid_clusterPosToEye(ivec3 clusterPos, vec3 offset = vec3(0.5)) {
|
||||
|
||||
vec3 cvpos = vec3(clusterPos) + offset;
|
||||
|
||||
|
||||
vec3 volumePos = frustumGrid_gridToVolume(cvpos, frustumGrid.dims);
|
||||
|
||||
vec3 eyePos = frustumGrid_volumeToEye(volumePos, frustumGrid.eyeToGridProj, frustumGrid.rangeNear, frustumGrid.rangeFar);
|
||||
|
||||
return eyePos;
|
||||
}
|
||||
|
||||
|
||||
ivec3 frustumGrid_eyeToClusterPos(vec3 eyePos) {
|
||||
|
||||
vec3 volumePos = frustumGrid_eyeToVolume(eyePos, frustumGrid.eyeToGridProj, frustumGrid.rangeNear, frustumGrid.rangeFar);
|
||||
|
||||
vec3 gridPos = frustumGrid_volumeToGrid(volumePos, frustumGrid.dims);
|
||||
|
||||
|
||||
return ivec3(gridPos);
|
||||
}
|
||||
|
||||
vec4 frustumGrid_eyeToWorld(vec4 eyePos) {
|
||||
return frustumGrid.eyeToWorldMat * eyePos;
|
||||
}
|
||||
|
||||
// <@if 1@>
|
||||
// Trigger Scribe include
|
||||
// <@endif@> <!def that !> End C++ compatible
|
|
@ -12,11 +12,25 @@
|
|||
|
||||
|
||||
#include <gpu/Context.h>
|
||||
|
||||
#include <gpu/StandardShaderLib.h>
|
||||
|
||||
#include "lightClusters_drawGrid_vert.h"
|
||||
#include "lightClusters_drawGrid_frag.h"
|
||||
|
||||
//#include "lightClusters_drawClusterFromDepth_vert.h"
|
||||
#include "lightClusters_drawClusterFromDepth_frag.h"
|
||||
|
||||
enum LightClusterGridShader_MapSlot {
|
||||
DEFERRED_BUFFER_LINEAR_DEPTH_UNIT = 7,
|
||||
};
|
||||
|
||||
enum LightClusterGridShader_BufferSlot {
|
||||
LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT = 0,
|
||||
DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT,
|
||||
CAMERA_CORRECTION_BUFFER_SLOT,
|
||||
LIGHT_GPU_SLOT = render::ShapePipeline::Slot::LIGHT,
|
||||
LIGHT_INDEX_GPU_SLOT,
|
||||
};
|
||||
|
||||
#include "DeferredLightingEffect.h"
|
||||
|
@ -27,7 +41,7 @@ LightClusters::LightClusters() {
|
|||
void LightClusters::updateFrustum(const ViewFrustum& frustum) {
|
||||
_frustum = frustum;
|
||||
|
||||
_frustrumGridBuffer.edit().updateFrustrum(frustum);
|
||||
_frustumGridBuffer.edit().updateFrustum(frustum);
|
||||
}
|
||||
|
||||
void LightClusters::updateLightStage(const LightStagePointer& lightStage) {
|
||||
|
@ -57,7 +71,7 @@ const gpu::PipelinePointer DebugLightClusters::getDrawClusterGridPipeline() {
|
|||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("frustrumGridBuffer"), LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("frustumGridBuffer"), LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT));
|
||||
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
|
@ -75,26 +89,49 @@ const gpu::PipelinePointer DebugLightClusters::getDrawClusterGridPipeline() {
|
|||
return _drawClusterGrid;
|
||||
}
|
||||
|
||||
void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) {
|
||||
const gpu::PipelinePointer DebugLightClusters::getDrawClusterFromDepthPipeline() {
|
||||
if (!_drawClusterFromDepth) {
|
||||
// auto vs = gpu::Shader::createVertex(std::string(lightClusters_drawGrid_vert));
|
||||
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
|
||||
auto ps = gpu::Shader::createPixel(std::string(lightClusters_drawClusterFromDepth_frag));
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("frustumGridBuffer"), LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("linearZeyeMap"), DEFERRED_BUFFER_LINEAR_DEPTH_UNIT));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("cameraCorrectionBuffer"), CAMERA_CORRECTION_BUFFER_SLOT));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("deferredFrameTransformBuffer"), DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT));
|
||||
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
|
||||
// state->setDepthTest(true, false, gpu::LESS_EQUAL);
|
||||
|
||||
// Blend on transparent
|
||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||
|
||||
// Good to go add the brand new pipeline
|
||||
_drawClusterFromDepth = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
return _drawClusterFromDepth;
|
||||
}
|
||||
|
||||
void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs) {
|
||||
auto deferredLightingEffect = DependencyManager::get<DeferredLightingEffect>();
|
||||
auto lightClusters = deferredLightingEffect->getLightClusters();
|
||||
|
||||
|
||||
/* auto deferredTransform = inputs.get0();
|
||||
auto deferredTransform = inputs.get0();
|
||||
auto deferredFramebuffer = inputs.get1();
|
||||
auto lightingModel = inputs.get2();
|
||||
auto surfaceGeometryFramebuffer = inputs.get3();
|
||||
auto ssaoFramebuffer = inputs.get4();
|
||||
auto subsurfaceScatteringResource = inputs.get5();
|
||||
*/
|
||||
|
||||
auto args = renderContext->args;
|
||||
|
||||
|
||||
auto drawPipeline = getDrawClusterGridPipeline();
|
||||
|
||||
|
||||
gpu::Batch batch;
|
||||
|
||||
|
||||
// Assign the camera transform
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
glm::mat4 projMat;
|
||||
|
@ -108,15 +145,34 @@ void DebugLightClusters::run(const render::SceneContextPointer& sceneContext, co
|
|||
// Then the actual ClusterGrid attributes
|
||||
batch.setModelTransform(Transform());
|
||||
|
||||
batch.setUniformBuffer(LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, lightClusters->_frustrumGridBuffer);
|
||||
batch.setUniformBuffer(LIGHT_CLUSTER_GRID_FRUSTUM_GRID_SLOT, lightClusters->_frustumGridBuffer);
|
||||
|
||||
|
||||
// bind the one gpu::Pipeline we need
|
||||
batch.setPipeline(drawPipeline);
|
||||
|
||||
if (true) {
|
||||
batch.draw(gpu::LINES, 24, 0);
|
||||
// bind the one gpu::Pipeline we need
|
||||
batch.setPipeline(getDrawClusterGridPipeline());
|
||||
|
||||
auto dims = lightClusters->_frustumGridBuffer->dims;
|
||||
glm::ivec3 summedDims(dims.x*dims.y * dims.z, dims.x*dims.y, dims.x);
|
||||
batch.drawInstanced(summedDims.x, gpu::LINES, 24, 0);
|
||||
}
|
||||
|
||||
if (true) {
|
||||
batch.setPipeline(getDrawClusterFromDepthPipeline());
|
||||
batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, deferredTransform->getFrameTransformBuffer());
|
||||
|
||||
if (surfaceGeometryFramebuffer) {
|
||||
batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, surfaceGeometryFramebuffer->getLinearDepthTexture());
|
||||
}
|
||||
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4, 0);
|
||||
|
||||
// Probably not necessary in the long run because the gpu layer would unbound this texture if used as render target
|
||||
|
||||
batch.setResourceTexture(DEFERRED_BUFFER_LINEAR_DEPTH_UNIT, nullptr);
|
||||
batch.setUniformBuffer(DEFERRED_FRAME_TRANSFORM_BUFFER_SLOT, nullptr);
|
||||
}
|
||||
|
||||
args->_context->appendFrameBatch(batch);
|
||||
|
||||
|
|
|
@ -20,65 +20,33 @@
|
|||
class FrustumGrid {
|
||||
public:
|
||||
float _near { 0.1f };
|
||||
float _nearPrime { 1.0f };
|
||||
float _farPrime { 400.0f };
|
||||
float rangeNear { 1.0f };
|
||||
float rangeFar { 100.0f };
|
||||
float _far { 10000.0f };
|
||||
|
||||
glm::uvec3 _dims { 16, 16, 16 };
|
||||
glm::ivec3 dims { 8, 8, 8 };
|
||||
float spare;
|
||||
|
||||
glm::mat4 _eyeToGridProj;
|
||||
glm::mat4 _eyeToGridProjInv;
|
||||
glm::mat4 eyeToGridProj;
|
||||
glm::mat4 _worldToEyeMat;
|
||||
glm::mat4 _eyeToWorldMat;
|
||||
glm::mat4 eyeToWorldMat;
|
||||
|
||||
float viewToLinearDepth(float depth) const {
|
||||
float nDepth = -depth;
|
||||
float ldepth = (nDepth - _nearPrime) / (_farPrime - _nearPrime);
|
||||
|
||||
if (ldepth < 0.0f) {
|
||||
return (nDepth - _near) / (_nearPrime - _near) - 1.0f;
|
||||
}
|
||||
if (ldepth > 1.0f) {
|
||||
return (nDepth - _farPrime) / (_far - _farPrime) + 1.0f;
|
||||
}
|
||||
return ldepth;
|
||||
}
|
||||
|
||||
float linearToGridDepth(float depth) const {
|
||||
return depth / (float) _dims.z;
|
||||
}
|
||||
|
||||
int gridDepthToLayer(float gridDepth) const {
|
||||
return (int) gridDepth;
|
||||
}
|
||||
|
||||
glm::vec2 ndcToGridXY(const glm::vec3& ncpos) const {
|
||||
return 0.5f * glm::vec2((ncpos.x + 1.0f) / (float)_dims.x, (ncpos.y + 1.0f) / (float)_dims.y);
|
||||
}
|
||||
|
||||
glm::ivec3 viewToGridPos(const glm::vec3& pos) const {
|
||||
float z = linearToGridDepth(viewToLinearDepth(pos.z));
|
||||
|
||||
auto cpos = _eyeToGridProj * glm::vec4(pos, 1.0f);
|
||||
|
||||
glm::vec3 ncpos(cpos);
|
||||
ncpos /= cpos.w;
|
||||
|
||||
|
||||
return glm::ivec3(ndcToGridXY(ncpos), (int) linearToGridDepth(z));
|
||||
}
|
||||
|
||||
void updateFrustrum(const ViewFrustum& frustum) {
|
||||
_eyeToGridProj = frustum.evalProjectionMatrixRange(_nearPrime, _farPrime);
|
||||
_eyeToGridProjInv = glm::inverse(_eyeToGridProj);
|
||||
void updateFrustum(const ViewFrustum& frustum) {
|
||||
eyeToGridProj = frustum.evalProjectionMatrixRange(rangeNear, rangeFar);
|
||||
|
||||
Transform view;
|
||||
frustum.evalViewTransform(view);
|
||||
_eyeToWorldMat = view.getMatrix();
|
||||
eyeToWorldMat = view.getMatrix();
|
||||
_worldToEyeMat = view.getInverseMatrix();
|
||||
}
|
||||
|
||||
// Copy paste of the slh functions
|
||||
using vec3 = glm::vec3;
|
||||
using ivec3 = glm::ivec3;
|
||||
using mat4 = glm::mat4;
|
||||
#define frustumGrid (*this)
|
||||
#include "LightClusterGrid_shared.slh"
|
||||
|
||||
};
|
||||
|
||||
class LightClusters {
|
||||
|
@ -93,15 +61,13 @@ public:
|
|||
void updateVisibleLights(const LightStage::LightIndices& visibleLights);
|
||||
|
||||
|
||||
// FrustumGrid _grid;
|
||||
|
||||
ViewFrustum _frustum;
|
||||
|
||||
LightStagePointer _lightStage;
|
||||
|
||||
|
||||
|
||||
gpu::StructBuffer<FrustumGrid> _frustrumGridBuffer;
|
||||
gpu::StructBuffer<FrustumGrid> _frustumGridBuffer;
|
||||
|
||||
|
||||
gpu::BufferPointer _lightIndicesBuffer;
|
||||
|
@ -131,22 +97,30 @@ protected:
|
|||
int numDrawn { 0 };
|
||||
};
|
||||
|
||||
|
||||
#include "DeferredFrameTransform.h"
|
||||
#include "DeferredFramebuffer.h"
|
||||
#include "LightingModel.h"
|
||||
#include "SurfaceGeometryPass.h"
|
||||
|
||||
class DebugLightClusters {
|
||||
public:
|
||||
// using Inputs = render::VaryingSet6 < DeferredFrameTransformPointer, DeferredFramebufferPointer, LightingModelPointer, SurfaceGeometryFramebufferPointer, AmbientOcclusionFramebufferPointer, SubsurfaceScatteringResourcePointer>;
|
||||
using Inputs = render::VaryingSet4 < DeferredFrameTransformPointer, DeferredFramebufferPointer, LightingModelPointer, SurfaceGeometryFramebufferPointer>;
|
||||
using Config = DebugLightClustersConfig;
|
||||
using JobModel = render::Job::Model<DebugLightClusters, Config>;
|
||||
using JobModel = render::Job::ModelI<DebugLightClusters, Inputs, Config>;
|
||||
|
||||
DebugLightClusters();
|
||||
|
||||
void configure(const Config& config);
|
||||
|
||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs);
|
||||
|
||||
protected:
|
||||
gpu::BufferPointer _gridBuffer;
|
||||
gpu::PipelinePointer _drawClusterGrid;
|
||||
gpu::PipelinePointer _drawClusterFromDepth;
|
||||
const gpu::PipelinePointer getDrawClusterGridPipeline();
|
||||
const gpu::PipelinePointer getDrawClusterFromDepthPipeline();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -192,7 +192,8 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) {
|
|||
|
||||
// LIght Cluster Grid Debuging job
|
||||
{
|
||||
addJob<DebugLightClusters>("DebugLightClusters");
|
||||
const auto debugLightClustersInputs = DebugLightClusters::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, linearDepthTarget).hasVarying();
|
||||
addJob<DebugLightClusters>("DebugLightClusters", debugLightClustersInputs);
|
||||
}
|
||||
|
||||
// Status icon rendering job
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
// lightClusters_drawClusterFro Depth.slf
|
||||
//
|
||||
// Created by Sam Gateau on 9/8/2016.
|
||||
// Copyright 2015 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
|
||||
//
|
||||
|
||||
|
||||
// Everything about deferred buffer
|
||||
<@include DeferredBufferRead.slh@>
|
||||
|
||||
|
||||
<@include LightClusterGrid.slh@>
|
||||
|
||||
<@include gpu/Color.slh@>
|
||||
<$declareColorWheel()$>
|
||||
|
||||
|
||||
in vec4 varTexCoord0;
|
||||
out vec4 _fragColor;
|
||||
|
||||
void main(void) {
|
||||
|
||||
// Grab the fragment data from the uv
|
||||
vec2 texCoord = varTexCoord0.st;
|
||||
|
||||
float Zeye = texture(linearZeyeMap, texCoord).x;
|
||||
_fragColor = vec4(vec3(0.1 * (10 - Zeye)), 1.0);
|
||||
// return;
|
||||
|
||||
vec4 fragPosition = unpackDeferredPositionFromZeye(texCoord);
|
||||
|
||||
|
||||
// return;
|
||||
|
||||
ivec3 dims = frustumGrid.dims.xyz;
|
||||
|
||||
ivec3 summedDims = ivec3(dims.x * dims.y, dims.x, 1);
|
||||
|
||||
|
||||
vec3 eyePos = fragPosition.xyz;
|
||||
|
||||
// vec4 worldPos = frustumGrid_eyeToWorld(vec4(eyePos.xyz, 1.0));
|
||||
|
||||
ivec3 clusterPos = frustumGrid_eyeToClusterPos(eyePos);
|
||||
|
||||
|
||||
// standard transform
|
||||
// TransformCamera cam = getTransformCamera();
|
||||
// <$transformWorldToClipPos(cam, worldPos, gl_Position)$>
|
||||
|
||||
_fragColor = vec4(colorWheel(fract(float(clusterPos.z * summedDims.x + clusterPos.y * summedDims.y + clusterPos.x) / float(frustumGrid_numClusters()))), 0.9);
|
||||
_fragColor = vec4(abs(fract(eyePos * 0.5)), 0.9);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// lightClusters_drawClusterFrom Depth.slv
|
||||
// Vertex shader
|
||||
//
|
||||
// Created by Sam Gateau on 9/8/2016
|
||||
// Copyright 2015 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 gpu/Transform.slh@>
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
<@include LightClusterGrid.slh@>
|
||||
|
||||
<@include gpu/Color.slh@>
|
||||
<$declareColorWheel()$>
|
||||
|
||||
|
||||
|
||||
|
||||
out vec4 varColor;
|
||||
|
||||
|
||||
void main(void) {
|
||||
const vec4 UNIT_BOX[8] = vec4[8](
|
||||
vec4(0.0, 0.0, 0.0, 1.0),
|
||||
vec4(1.0, 0.0, 0.0, 1.0),
|
||||
vec4(0.0, 1.0, 0.0, 1.0),
|
||||
vec4(1.0, 1.0, 0.0, 1.0),
|
||||
vec4(0.0, 0.0, 1.0, 1.0),
|
||||
vec4(1.0, 0.0, 1.0, 1.0),
|
||||
vec4(0.0, 1.0, 1.0, 1.0),
|
||||
vec4(1.0, 1.0, 1.0, 1.0)
|
||||
);
|
||||
const int UNIT_BOX_LINE_INDICES[24] = int[24](
|
||||
0, 1,
|
||||
1, 3,
|
||||
3, 2,
|
||||
2, 0,
|
||||
4, 5,
|
||||
5, 7,
|
||||
7, 6,
|
||||
6, 4,
|
||||
2, 6,
|
||||
3, 7,
|
||||
0, 4,
|
||||
1, 5
|
||||
);
|
||||
vec4 pos = UNIT_BOX[UNIT_BOX_LINE_INDICES[gl_VertexID]];
|
||||
|
||||
ivec3 dims = frustumGrid.dims.xyz;
|
||||
|
||||
ivec3 summedDims = ivec3(dims.x * dims.y, dims.x, 1);
|
||||
|
||||
int layer = gl_InstanceID / summedDims.x;
|
||||
int offsetInLayer = gl_InstanceID % summedDims.x;
|
||||
ivec3 clusterPos = ivec3(offsetInLayer % summedDims.y, offsetInLayer / summedDims.y, layer);
|
||||
|
||||
|
||||
vec3 eyePos = frustumGrid_clusterPosToEye(clusterPos, vec3(0.05) + 0.9 * pos.xyz);
|
||||
vec4 worldPos = frustumGrid_eyeToWorld(vec4(eyePos.xyz, 1.0));
|
||||
|
||||
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
<$transformWorldToClipPos(cam, worldPos, gl_Position)$>
|
||||
|
||||
varColor = vec4(colorWheel(fract(float(gl_InstanceID) / float(frustumGrid_numClusters()))), 0.9);
|
||||
}
|
|
@ -13,39 +13,15 @@
|
|||
//
|
||||
|
||||
<@include gpu/Transform.slh@>
|
||||
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
<@include LightClusterGrid.slh@>
|
||||
|
||||
<@include gpu/Color.slh@>
|
||||
<$declareColorWheel()$>
|
||||
|
||||
|
||||
struct FrustrumGrid {
|
||||
vec4 nearFarRange;
|
||||
ivec4 dims;
|
||||
mat4 eyeToGridProj;
|
||||
mat4 eyeToGridProjInv;
|
||||
mat4 worldToEyeMat;
|
||||
mat4 eyeToWorldMat;
|
||||
};
|
||||
|
||||
uniform frustrumGridBuffer {
|
||||
FrustrumGrid frustrumGrid;
|
||||
};
|
||||
|
||||
float getProjectionNear(mat4 projection) {
|
||||
float planeC = projection[2][3] + projection[2][2];
|
||||
float planeD = projection[3][2];
|
||||
return planeD / planeC;
|
||||
}
|
||||
float getProjectionFar(mat4 projection) {
|
||||
//float planeA = projection[0][3] - projection[0][2];
|
||||
//float planeB = projection[1][3] - projection[1][2];
|
||||
float planeC = projection[2][3] - projection[2][2];
|
||||
float planeD = /*projection[3][3]*/ - projection[3][2];
|
||||
return planeD / planeC;
|
||||
}
|
||||
//uniform ivec4 inClusterLocation;
|
||||
|
||||
out vec4 varColor;
|
||||
|
||||
|
@ -77,35 +53,22 @@ void main(void) {
|
|||
);
|
||||
vec4 pos = UNIT_BOX[UNIT_BOX_LINE_INDICES[gl_VertexID]];
|
||||
|
||||
// pos.z -= 10.0f;
|
||||
vec3 cpos = vec3(1, 0, 1);
|
||||
ivec3 dims = frustumGrid.dims.xyz;
|
||||
|
||||
// float z = frustrumGrid.nearFarRange.y * (1 - pos.z) + frustrumGrid.nearFarRange.z * (pos.z);
|
||||
vec3 gridScale = vec3(0.5, 0.5, 1.0) / vec3(frustrumGrid.dims.xyz);
|
||||
ivec3 summedDims = ivec3(dims.x * dims.y, dims.x, 1);
|
||||
|
||||
vec3 cvpos = cpos + pos.xyz;
|
||||
|
||||
vec3 clusterStart = vec3(-1.0 + cvpos.x * gridScale.x, -1.0 + cvpos.y * gridScale.y, cvpos.z * gridScale.z);
|
||||
|
||||
float z = getProjectionNear(frustrumGrid.eyeToGridProj) * (1 - clusterStart.z) + getProjectionFar(frustrumGrid.eyeToGridProj) * (clusterStart.z);
|
||||
|
||||
vec4 eyePos = frustrumGrid.eyeToGridProjInv * (vec4(clusterStart.xy, 1.0, 1.0) * z);
|
||||
|
||||
eyePos.xyz *= eyePos.w;
|
||||
|
||||
vec4 worldPos = frustrumGrid.eyeToWorldMat * vec4(eyePos.xyz, 1.0);
|
||||
int layer = gl_InstanceID / summedDims.x;
|
||||
int offsetInLayer = gl_InstanceID % summedDims.x;
|
||||
ivec3 clusterPos = ivec3(offsetInLayer % summedDims.y, offsetInLayer / summedDims.y, layer);
|
||||
|
||||
|
||||
/*
|
||||
int cellIsEmpty = sign(inClusterLocation.w);
|
||||
ivec4 cellLocation = ivec4(inClusterLocation.xyz, (inClusterLocation.w < 0 ? -inClusterLocation.w : inClusterLocation.w));
|
||||
vec4 cellBound = evalBound(cellLocation);
|
||||
vec3 eyePos = frustumGrid_clusterPosToEye(clusterPos, vec3(0.05) + 0.9 * pos.xyz);
|
||||
vec4 worldPos = frustumGrid_eyeToWorld(vec4(eyePos.xyz, 1.0));
|
||||
|
||||
|
||||
pos.xyz = cellBound.xyz + vec3(cellBound.w) * pos.xyz;
|
||||
*/
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
<$transformWorldToClipPos(cam, worldPos, gl_Position)$>
|
||||
|
||||
varColor = vec4(colorWheel(fract(float(gl_VertexID) / 24.0)), 0.9);
|
||||
varColor = vec4(colorWheel(fract(float(gl_InstanceID) / float(frustumGrid_numClusters()))), 0.9);
|
||||
}
|
|
@ -189,6 +189,38 @@ protected:
|
|||
float _step { 0.1f };
|
||||
};
|
||||
|
||||
|
||||
class IntPreference : public TypedPreference<int> {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(float value READ getValue WRITE setValue NOTIFY valueChanged)
|
||||
Q_PROPERTY(float min READ getMin CONSTANT)
|
||||
Q_PROPERTY(float max READ getMax CONSTANT)
|
||||
Q_PROPERTY(float step READ getStep CONSTANT)
|
||||
|
||||
public:
|
||||
IntPreference(const QString& category, const QString& name, Getter getter, Setter setter)
|
||||
: TypedPreference(category, name, getter, setter) { }
|
||||
|
||||
float getMin() const { return _min; }
|
||||
void setMin(float min) { _min = min; };
|
||||
|
||||
float getMax() const { return _max; }
|
||||
void setMax(float max) { _max = max; };
|
||||
|
||||
float getStep() const { return _step; }
|
||||
void setStep(float step) { _step = step; };
|
||||
|
||||
signals:
|
||||
void valueChanged();
|
||||
|
||||
protected:
|
||||
void emitValueChanged() override { emit valueChanged(); }
|
||||
|
||||
int _min { std::numeric_limits<int>::min() };
|
||||
int _max { std::numeric_limits<int>::max() };
|
||||
int _step { 1 };
|
||||
};
|
||||
|
||||
class StringPreference : public TypedPreference<QString> {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString value READ getValue WRITE setValue NOTIFY valueChanged)
|
||||
|
@ -222,6 +254,15 @@ public:
|
|||
Type getType() override { return Spinner; }
|
||||
};
|
||||
|
||||
class IntSpinnerPreference : public IntPreference {
|
||||
Q_OBJECT
|
||||
public:
|
||||
IntSpinnerPreference(const QString& category, const QString& name, Getter getter, Setter setter)
|
||||
: IntPreference(category, name, getter, setter) { }
|
||||
|
||||
Type getType() override { return Spinner; }
|
||||
};
|
||||
|
||||
class EditPreference : public StringPreference {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString placeholderText READ getPlaceholderText CONSTANT)
|
||||
|
|
|
@ -2271,6 +2271,7 @@ function MyController(hand) {
|
|||
};
|
||||
} else {
|
||||
pointerEvent = this.touchingEnterPointerEvent;
|
||||
pointerEvent.type = "Release";
|
||||
pointerEvent.button = "Primary";
|
||||
pointerEvent.isPrimaryHeld = false;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
var RAD_TO_DEG = 180 / Math.PI;
|
||||
var X_AXIS = {x: 1, y: 0, z: 0};
|
||||
var Y_AXIS = {x: 0, y: 1, z: 0};
|
||||
var DEFAULT_DPI = 30;
|
||||
var DEFAULT_DPI = 32;
|
||||
var DEFAULT_WIDTH = 0.5;
|
||||
|
||||
var TABLET_URL = "https://s3.amazonaws.com/hifi-public/tony/tablet.fbx";
|
||||
|
|
|
@ -497,13 +497,17 @@ protected:
|
|||
_postUpdateLambdas[key] = func;
|
||||
}
|
||||
|
||||
bool isHMDMode() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
//"/-17.2049,-8.08629,-19.4153/0,0.881994,0,-0.47126"
|
||||
static void setup() {
|
||||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||
DependencyManager::registerInheritance<SpatialParentFinder, ParentFinder>();
|
||||
DependencyManager::set<AddressManager>();
|
||||
DependencyManager::set<NodeList>(NodeType::Agent, 0);
|
||||
DependencyManager::set<NodeList>(NodeType::Agent);
|
||||
DependencyManager::set<DeferredLightingEffect>();
|
||||
DependencyManager::set<ResourceCacheSharedItems>();
|
||||
DependencyManager::set<TextureCache>();
|
||||
|
|
|
@ -295,7 +295,7 @@ public:
|
|||
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
|
||||
//DependencyManager::registerInheritance<SpatialParentFinder, ParentFinder>();
|
||||
DependencyManager::set<AddressManager>();
|
||||
DependencyManager::set<NodeList>(NodeType::Agent, 0);
|
||||
DependencyManager::set<NodeList>(NodeType::Agent);
|
||||
DependencyManager::set<DeferredLightingEffect>();
|
||||
DependencyManager::set<ResourceCacheSharedItems>();
|
||||
DependencyManager::set<TextureCache>();
|
||||
|
|
Loading…
Reference in a new issue