mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-04-07 10:02:24 +02:00
Working on new-UI implementations of address bar and login
This commit is contained in:
parent
fe482b35ff
commit
d14d5f3d29
45 changed files with 1844 additions and 728 deletions
|
@ -92,8 +92,17 @@ else ()
|
|||
if (NOT QT_CMAKE_PREFIX_PATH)
|
||||
set(QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH})
|
||||
endif ()
|
||||
if (NOT QT_CMAKE_PREFIX_PATH)
|
||||
get_filename_component(QT_CMAKE_PREFIX_PATH "${Qt5_DIR}/.." REALPATH)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (WIN32)
|
||||
if (NOT EXISTS ${QT_CMAKE_PREFIX_PATH})
|
||||
message(FATAL_ERROR "Could not determine QT_CMAKE_PREFIX_PATH.")
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
# figure out where the qt dir is
|
||||
get_filename_component(QT_DIR "${QT_CMAKE_PREFIX_PATH}/../../" ABSOLUTE)
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ else ()
|
|||
list(REMOVE_ITEM INTERFACE_SRCS ${SPEECHRECOGNIZER_CPP})
|
||||
endif ()
|
||||
|
||||
find_package(Qt5 COMPONENTS Gui Multimedia Network OpenGL Script Svg WebKitWidgets)
|
||||
find_package(Qt5 COMPONENTS Gui Multimedia Network OpenGL Qml Quick Script Svg WebKitWidgets)
|
||||
|
||||
# grab the ui files in resources/ui
|
||||
file (GLOB_RECURSE QT_UI_FILES ui/*.ui)
|
||||
|
|
84
interface/resources/qml/AddressBarDialog.qml
Normal file
84
interface/resources/qml/AddressBarDialog.qml
Normal file
|
@ -0,0 +1,84 @@
|
|||
import Hifi 1.0
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Window 2.2
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
|
||||
AddressBarDialog {
|
||||
id: addressBarDialog
|
||||
objectName: "AddressBarDialog"
|
||||
SystemPalette { id: myPalette; colorGroup: SystemPalette.Active }
|
||||
height: 128
|
||||
width: 512
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible) {
|
||||
reset();
|
||||
} else {
|
||||
addressLine.focus = true
|
||||
addressLine.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
addressLine.focus = true
|
||||
addressLine.forceActiveFocus()
|
||||
}
|
||||
|
||||
function reset() {
|
||||
addressLine.text = ""
|
||||
goButton.source = "../images/address-bar-submit.svg"
|
||||
}
|
||||
|
||||
CustomDialog {
|
||||
id: dialog
|
||||
anchors.fill: parent
|
||||
title: "Go to..."
|
||||
|
||||
// The client area
|
||||
Item {
|
||||
id: item1
|
||||
anchors.fill: parent
|
||||
anchors.margins: parent.margins
|
||||
anchors.topMargin: parent.topMargin
|
||||
|
||||
CustomBorder {
|
||||
height: 64
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
anchors.right: goButton.left
|
||||
anchors.rightMargin: 8
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
CustomTextInput {
|
||||
id: addressLine
|
||||
anchors.fill: parent
|
||||
helperText: "domain, location, @user, /x,y,z"
|
||||
anchors.margins: 8
|
||||
onAccepted: {
|
||||
addressBarDialog.loadAddress(addressLine.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: goButton
|
||||
width: 32
|
||||
height: 32
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 8
|
||||
source: "../images/address-bar-submit.svg"
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
parent.source = "../images/address-bar-submit-active.svg"
|
||||
addressBarDialog.loadAddress(addressLine.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
12
interface/resources/qml/CustomBorder.qml
Normal file
12
interface/resources/qml/CustomBorder.qml
Normal file
|
@ -0,0 +1,12 @@
|
|||
import QtQuick 2.3
|
||||
|
||||
|
||||
Rectangle {
|
||||
SystemPalette { id: myPalette; colorGroup: SystemPalette.Active }
|
||||
property int margin: 5
|
||||
color: myPalette.window
|
||||
border.color: myPalette.dark
|
||||
border.width: 5
|
||||
radius: border.width * 2
|
||||
}
|
||||
|
23
interface/resources/qml/CustomButton.qml
Normal file
23
interface/resources/qml/CustomButton.qml
Normal file
|
@ -0,0 +1,23 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.3
|
||||
import QtQuick.Window 2.2
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
|
||||
Button {
|
||||
SystemPalette { id: myPalette; colorGroup: SystemPalette.Active }
|
||||
text: "Text"
|
||||
width: 128
|
||||
height: 64
|
||||
style: ButtonStyle {
|
||||
background: CustomBorder {
|
||||
anchors.fill: parent
|
||||
}
|
||||
label: CustomText {
|
||||
renderType: Text.NativeRendering
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: control.text
|
||||
color: control.enabled ? myPalette.text : myPalette.dark
|
||||
}
|
||||
}
|
||||
}
|
98
interface/resources/qml/CustomDialog.qml
Normal file
98
interface/resources/qml/CustomDialog.qml
Normal file
|
@ -0,0 +1,98 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Window 2.2
|
||||
import QtQuick.Dialogs 1.2
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
import "hifiConstants.js" as HifiConstants
|
||||
|
||||
Item {
|
||||
SystemPalette { id: myPalette; colorGroup: SystemPalette.Active }
|
||||
|
||||
id: dialog
|
||||
width: 256
|
||||
height: 256
|
||||
property rect clientArea: clientBorder
|
||||
property int topMargin: dialog.height - clientBorder.height + 8
|
||||
property int margins: 8
|
||||
property string title
|
||||
property int titleSize: titleBorder.height + 12
|
||||
property string frameColor: HifiConstants.color
|
||||
property string backgroundColor: myPalette.window
|
||||
property string headerBackgroundColor: myPalette.dark
|
||||
|
||||
CustomBorder {
|
||||
id: windowBorder
|
||||
anchors.fill: parent
|
||||
border.color: dialog.frameColor
|
||||
color: dialog.backgroundColor
|
||||
|
||||
CustomBorder {
|
||||
id: titleBorder
|
||||
height: 48
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
border.color: dialog.frameColor
|
||||
color: dialog.headerBackgroundColor
|
||||
|
||||
CustomText {
|
||||
id: titleText
|
||||
color: "white"
|
||||
text: dialog.title
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: titleDrag
|
||||
property int startX
|
||||
property int startY
|
||||
anchors.right: closeButton.left
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.rightMargin: 4
|
||||
drag {
|
||||
target: dialog.parent
|
||||
minimumX: 0
|
||||
minimumY: 0
|
||||
maximumX: dialog.parent.parent.width - dialog.parent.width
|
||||
maximumY: dialog.parent.parent.height - dialog.parent.height
|
||||
}
|
||||
}
|
||||
Image {
|
||||
id: closeButton
|
||||
x: 360
|
||||
height: 16
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 16
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 12
|
||||
source: "../styles/close.svg"
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
dialog.parent.destroy()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // header border
|
||||
|
||||
CustomBorder {
|
||||
id: clientBorder
|
||||
border.color: dialog.frameColor
|
||||
color: "#00000000"
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 0
|
||||
anchors.top: titleBorder.bottom
|
||||
anchors.topMargin: -titleBorder.border.width
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
} // client border
|
||||
} // window border
|
||||
}
|
7
interface/resources/qml/CustomText.qml
Normal file
7
interface/resources/qml/CustomText.qml
Normal file
|
@ -0,0 +1,7 @@
|
|||
import QtQuick 2.3
|
||||
|
||||
Text {
|
||||
font.family: "Helvetica"
|
||||
font.pointSize: 18
|
||||
}
|
||||
|
10
interface/resources/qml/CustomTextArea.qml
Normal file
10
interface/resources/qml/CustomTextArea.qml
Normal file
|
@ -0,0 +1,10 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
|
||||
TextArea {
|
||||
font.family: "Helvetica"
|
||||
font.pointSize: 18
|
||||
backgroundVisible: false
|
||||
readOnly: true
|
||||
}
|
||||
|
7
interface/resources/qml/CustomTextEdit.qml
Normal file
7
interface/resources/qml/CustomTextEdit.qml
Normal file
|
@ -0,0 +1,7 @@
|
|||
import QtQuick 2.3
|
||||
|
||||
TextEdit {
|
||||
font.family: "Helvetica"
|
||||
font.pointSize: 18
|
||||
}
|
||||
|
34
interface/resources/qml/CustomTextInput.qml
Normal file
34
interface/resources/qml/CustomTextInput.qml
Normal file
|
@ -0,0 +1,34 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
|
||||
TextInput {
|
||||
SystemPalette { id: myPalette; colorGroup: SystemPalette.Active }
|
||||
property string helperText: ""
|
||||
font.family: "Helvetica"
|
||||
font.pointSize: 18
|
||||
width: 256
|
||||
height: 64
|
||||
color: myPalette.text
|
||||
clip: true
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
|
||||
onTextChanged: {
|
||||
if (text == "") {
|
||||
helperText.visible = true;
|
||||
} else {
|
||||
helperText.visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: helperText
|
||||
anchors.fill: parent
|
||||
font.pointSize: parent.font.pointSize
|
||||
font.family: "Helvetica"
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
text: parent.helperText
|
||||
color: myPalette.dark
|
||||
clip: true
|
||||
}
|
||||
}
|
||||
|
8
interface/resources/qml/Icon.qml
Normal file
8
interface/resources/qml/Icon.qml
Normal file
|
@ -0,0 +1,8 @@
|
|||
import QtQuick 1.0
|
||||
|
||||
Image {
|
||||
id: icon
|
||||
width: 64
|
||||
height: 64
|
||||
source: "file.svg"
|
||||
}
|
24
interface/resources/qml/IconControl.qml
Normal file
24
interface/resources/qml/IconControl.qml
Normal file
|
@ -0,0 +1,24 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.3
|
||||
import QtQuick.Window 2.2
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
|
||||
Button {
|
||||
text: "Text"
|
||||
style: ButtonStyle {
|
||||
background: Item { anchors.fill: parent }
|
||||
label: Text {
|
||||
id: icon
|
||||
width: height
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
renderType: Text.NativeRendering
|
||||
font.family: iconFont.name
|
||||
font.pointSize: 18
|
||||
property alias unicode: icon.text
|
||||
FontLoader { id: iconFont; source: "/fonts/fontawesome-webfont.ttf"; }
|
||||
text: control.text
|
||||
color: control.enabled ? "white" : "dimgray"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
191
interface/resources/qml/LoginDialog.qml
Normal file
191
interface/resources/qml/LoginDialog.qml
Normal file
|
@ -0,0 +1,191 @@
|
|||
import Hifi 1.0
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Window 2.2
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
import "hifiConstants.js" as HifiConstants
|
||||
|
||||
LoginDialog {
|
||||
SystemPalette { id: myPalette; colorGroup: SystemPalette.Active }
|
||||
id: loginDialog
|
||||
objectName: "LoginDialog"
|
||||
height: 512
|
||||
width: 384
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible) {
|
||||
reset()
|
||||
} else {
|
||||
username.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
function reset() {
|
||||
username.text = ""
|
||||
password.text = ""
|
||||
loginDialog.statusText = ""
|
||||
}
|
||||
|
||||
CustomDialog {
|
||||
anchors.fill: parent
|
||||
title: "Login"
|
||||
Item {
|
||||
id: item1
|
||||
anchors.fill: parent
|
||||
anchors.margins: parent.margins
|
||||
anchors.topMargin: parent.topMargin
|
||||
Column {
|
||||
anchors.topMargin: 8
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
spacing: 8
|
||||
|
||||
Image {
|
||||
height: 64
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: 64
|
||||
source: "../images/hifi-logo.svg"
|
||||
}
|
||||
|
||||
CustomBorder {
|
||||
width: 304
|
||||
height: 64
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
CustomTextInput {
|
||||
id: username
|
||||
anchors.fill: parent
|
||||
helperText: "Username or Email"
|
||||
anchors.margins: 8
|
||||
KeyNavigation.tab: password
|
||||
KeyNavigation.backtab: password
|
||||
onAccepted: {
|
||||
password.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CustomBorder {
|
||||
width: 304
|
||||
height: 64
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
CustomTextInput {
|
||||
id: password
|
||||
anchors.fill: parent
|
||||
echoMode: TextInput.Password
|
||||
helperText: "Password"
|
||||
anchors.margins: 8
|
||||
KeyNavigation.tab: username
|
||||
KeyNavigation.backtab: username
|
||||
onAccepted: {
|
||||
if (username.text == "") {
|
||||
username.forceActiveFocus()
|
||||
} else {
|
||||
loginDialog.login(username.text, password.text)
|
||||
}
|
||||
}
|
||||
onFocusChanged: {
|
||||
if (password.focus) {
|
||||
password.selectAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CustomText {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
textFormat: Text.StyledText
|
||||
width: parent.width
|
||||
height: 96
|
||||
wrapMode: Text.WordWrap
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: loginDialog.statusText
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.bottomMargin: 5
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
Rectangle {
|
||||
width: 192
|
||||
height: 64
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
color: HifiConstants.color
|
||||
border.width: 0
|
||||
radius: 10
|
||||
|
||||
MouseArea {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 0
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
onClicked: {
|
||||
loginDialog.login(username.text, password.text)
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 8
|
||||
Image {
|
||||
id: loginIcon
|
||||
height: 32
|
||||
width: 32
|
||||
source: "../images/login.svg"
|
||||
}
|
||||
CustomText {
|
||||
text: "Login"
|
||||
color: "white"
|
||||
width: 64
|
||||
height: parent.height
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CustomText {
|
||||
width: parent.width
|
||||
height: 24
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
text:"Create Account"
|
||||
font.pointSize: 12
|
||||
font.bold: true
|
||||
color: HifiConstants.color
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
loginDialog.openUrl(loginDialog.rootUrl + "/signup")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CustomText {
|
||||
width: parent.width
|
||||
height: 24
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
font.pointSize: 12
|
||||
text: "Recover Password"
|
||||
color: HifiConstants.color
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
loginDialog.openUrl(loginDialog.rootUrl + "/users/password/new")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
14
interface/resources/qml/Root.qml
Normal file
14
interface/resources/qml/Root.qml
Normal file
|
@ -0,0 +1,14 @@
|
|||
import QtQuick 2.3
|
||||
import "componentCreation.js" as Creator
|
||||
|
||||
|
||||
Item {
|
||||
id: root
|
||||
width: 1280
|
||||
height: 720
|
||||
|
||||
function loadChild(url) {
|
||||
Creator.createObject(root, url)
|
||||
}
|
||||
}
|
||||
|
27
interface/resources/qml/componentCreation.js
Normal file
27
interface/resources/qml/componentCreation.js
Normal file
|
@ -0,0 +1,27 @@
|
|||
var component;
|
||||
var instance;
|
||||
var parent;
|
||||
|
||||
function createObject(parentObject, url) {
|
||||
parent = parentObject;
|
||||
component = Qt.createComponent(url);
|
||||
if (component.status == Component.Ready)
|
||||
finishCreation();
|
||||
else
|
||||
component.statusChanged.connect(finishCreation);
|
||||
}
|
||||
|
||||
function finishCreation() {
|
||||
if (component.status == Component.Ready) {
|
||||
instance = component.createObject(parent, {"x": 100, "y": 100});
|
||||
if (instance == null) {
|
||||
// Error Handling
|
||||
console.log("Error creating object");
|
||||
} else {
|
||||
instance.focus = true;
|
||||
}
|
||||
} else if (component.status == Component.Error) {
|
||||
// Error Handling
|
||||
console.log("Error loading component:", component.errorString());
|
||||
}
|
||||
}
|
4
interface/resources/qml/hifiConstants.js
Normal file
4
interface/resources/qml/hifiConstants.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
var color = "#0e7077"
|
||||
var Colors = {
|
||||
hifiBlue: "#0e7077"
|
||||
}
|
|
@ -137,6 +137,7 @@
|
|||
#include "ui/Snapshot.h"
|
||||
#include "ui/StandAloneJSConsole.h"
|
||||
#include "ui/Stats.h"
|
||||
#include "ui/AddressBarDialog.h"
|
||||
|
||||
// ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
|
||||
#if defined(Q_OS_WIN)
|
||||
|
@ -209,8 +210,12 @@ public:
|
|||
|
||||
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
|
||||
QString logMessage = LogHandler::getInstance().printMessage((LogMsgType) type, context, message);
|
||||
|
||||
|
||||
if (!logMessage.isEmpty()) {
|
||||
#ifdef Q_OS_WIN
|
||||
OutputDebugStringA(logMessage.toLocal8Bit().constData());
|
||||
OutputDebugStringA("\n");
|
||||
#endif
|
||||
Application::getInstance()->getLogger()->addMessage(qPrintable(logMessage + "\n"));
|
||||
}
|
||||
}
|
||||
|
@ -260,6 +265,7 @@ bool setupEssentials(int& argc, char** argv) {
|
|||
#endif
|
||||
auto discoverabilityManager = DependencyManager::set<DiscoverabilityManager>();
|
||||
auto sceneScriptingInterface = DependencyManager::set<SceneScriptingInterface>();
|
||||
auto offscreenUi = DependencyManager::set<OffscreenUi>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -316,8 +322,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
#ifdef Q_OS_WIN
|
||||
installNativeEventFilter(&MyNativeEventFilter::getInstance());
|
||||
#endif
|
||||
|
||||
|
||||
_logger = new FileLogger(this); // After setting organization name in order to get correct directory
|
||||
|
||||
qInstallMessageHandler(messageHandler);
|
||||
|
||||
QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "styles/Inconsolata.otf");
|
||||
|
@ -562,8 +570,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
#endif
|
||||
|
||||
this->installEventFilter(this);
|
||||
// The offscreen UI needs to intercept the mouse and keyboard
|
||||
// events coming from the onscreen window
|
||||
_glWidget->installEventFilter(
|
||||
DependencyManager::get<OffscreenUi>().data());
|
||||
}
|
||||
|
||||
|
||||
void Application::aboutToQuit() {
|
||||
emit beforeAboutToQuit();
|
||||
|
||||
|
@ -720,10 +733,35 @@ void Application::initializeGL() {
|
|||
|
||||
// update before the first render
|
||||
update(1.0f / _fps);
|
||||
|
||||
// The UI can't be created until the primary OpenGL
|
||||
// context is created, because it needs to share
|
||||
// texture resources
|
||||
initializeUi();
|
||||
|
||||
InfoView::showFirstTime(INFO_HELP_PATH);
|
||||
}
|
||||
|
||||
void Application::initializeUi() {
|
||||
AddressBarDialog::registerType();
|
||||
LoginDialog::registerType();
|
||||
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
offscreenUi->create(_glWidget->context()->contextHandle());
|
||||
offscreenUi->resize(_glWidget->size());
|
||||
offscreenUi->setProxyWindow(_window->windowHandle());
|
||||
auto rootQml = PathUtils::resourcesPath() + "qml/Root.qml";
|
||||
offscreenUi->loadQml(QUrl::fromLocalFile(rootQml));
|
||||
offscreenUi->setMouseTranslator([this](const QPointF& p){
|
||||
if (OculusManager::isConnected()) {
|
||||
glm::vec2 pos = _applicationOverlay.screenToOverlay(toGlm(p));
|
||||
return QPointF(pos.x, pos.y);
|
||||
}
|
||||
return QPointF(p);
|
||||
});
|
||||
offscreenUi->resume();
|
||||
}
|
||||
|
||||
void Application::paintGL() {
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
PerformanceTimer perfTimer("paintGL");
|
||||
|
@ -818,7 +856,7 @@ void Application::paintGL() {
|
|||
|
||||
{
|
||||
PerformanceTimer perfTimer("renderOverlay");
|
||||
_applicationOverlay.renderOverlay(true);
|
||||
_applicationOverlay.renderOverlay();
|
||||
_applicationOverlay.displayOverlayTexture();
|
||||
}
|
||||
}
|
||||
|
@ -863,6 +901,9 @@ void Application::resizeGL(int width, int height) {
|
|||
updateProjectionMatrix();
|
||||
glLoadIdentity();
|
||||
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
offscreenUi->resize(QSize(width, height));
|
||||
|
||||
// update Stats width
|
||||
// let's set horizontal offset to give stats some margin to mirror
|
||||
int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2;
|
||||
|
@ -911,6 +952,44 @@ bool Application::importSVOFromURL(const QString& urlString) {
|
|||
}
|
||||
|
||||
bool Application::event(QEvent* event) {
|
||||
switch (event->type()) {
|
||||
case QEvent::MouseMove:
|
||||
mouseMoveEvent((QMouseEvent*)event);
|
||||
return true;
|
||||
case QEvent::MouseButtonPress:
|
||||
mousePressEvent((QMouseEvent*)event);
|
||||
return true;
|
||||
case QEvent::MouseButtonRelease:
|
||||
mouseReleaseEvent((QMouseEvent*)event);
|
||||
return true;
|
||||
case QEvent::KeyPress:
|
||||
keyPressEvent((QKeyEvent*)event);
|
||||
return true;
|
||||
case QEvent::KeyRelease:
|
||||
keyReleaseEvent((QKeyEvent*)event);
|
||||
return true;
|
||||
case QEvent::FocusOut:
|
||||
focusOutEvent((QFocusEvent*)event);
|
||||
return true;
|
||||
case QEvent::TouchBegin:
|
||||
touchBeginEvent(static_cast<QTouchEvent*>(event));
|
||||
event->accept();
|
||||
return true;
|
||||
case QEvent::TouchEnd:
|
||||
touchEndEvent(static_cast<QTouchEvent*>(event));
|
||||
return true;
|
||||
case QEvent::TouchUpdate:
|
||||
touchUpdateEvent(static_cast<QTouchEvent*>(event));
|
||||
return true;
|
||||
case QEvent::Wheel:
|
||||
wheelEvent(static_cast<QWheelEvent*>(event));
|
||||
return true;
|
||||
case QEvent::Drop:
|
||||
dropEvent(static_cast<QDropEvent*>(event));
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// handle custom URL
|
||||
if (event->type() == QEvent::FileOpen) {
|
||||
|
@ -931,7 +1010,7 @@ bool Application::event(QEvent* event) {
|
|||
if (HFActionEvent::types().contains(event->type())) {
|
||||
_controllerScriptingInterface.handleMetaEvent(static_cast<HFMetaEvent*>(event));
|
||||
}
|
||||
|
||||
|
||||
return QApplication::event(event);
|
||||
}
|
||||
|
||||
|
@ -963,14 +1042,17 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
bool isShifted = event->modifiers().testFlag(Qt::ShiftModifier);
|
||||
bool isMeta = event->modifiers().testFlag(Qt::ControlModifier);
|
||||
bool isOption = event->modifiers().testFlag(Qt::AltModifier);
|
||||
bool isKeypad = event->modifiers().testFlag(Qt::KeypadModifier);
|
||||
switch (event->key()) {
|
||||
break;
|
||||
case Qt::Key_L:
|
||||
if (isShifted) {
|
||||
Menu::getInstance()->triggerOption(MenuOption::LodTools);
|
||||
} else if (isMeta) {
|
||||
if (isShifted && isMeta) {
|
||||
Menu::getInstance()->triggerOption(MenuOption::Log);
|
||||
}
|
||||
} else if (isMeta) {
|
||||
Menu::getInstance()->triggerOption(MenuOption::AddressBar);
|
||||
} else if (isShifted) {
|
||||
Menu::getInstance()->triggerOption(MenuOption::LodTools);
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_E:
|
||||
|
@ -1030,11 +1112,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_Return:
|
||||
case Qt::Key_Enter:
|
||||
Menu::getInstance()->triggerOption(MenuOption::AddressBar);
|
||||
break;
|
||||
|
||||
case Qt::Key_Backslash:
|
||||
Menu::getInstance()->triggerOption(MenuOption::Chat);
|
||||
break;
|
||||
|
@ -1494,6 +1571,17 @@ void Application::dropEvent(QDropEvent *event) {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::dragEnterEvent(QDragEnterEvent* event) {
|
||||
const QMimeData* mimeData = event->mimeData();
|
||||
foreach(QUrl url, mimeData->urls()) {
|
||||
auto urlString = url.toString();
|
||||
if (canAcceptURL(urlString)) {
|
||||
event->acceptProposedAction();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Application::acceptSnapshot(const QString& urlString) {
|
||||
QUrl url(urlString);
|
||||
QString snapshotPath = url.toLocalFile();
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <NetworkPacket.h>
|
||||
#include <NodeList.h>
|
||||
#include <OctreeQuery.h>
|
||||
#include <OffscreenUi.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <PhysicsEngine.h>
|
||||
#include <ScriptEngine.h>
|
||||
|
@ -151,6 +152,7 @@ public:
|
|||
void setPreviousScriptLocation(const QString& previousScriptLocation);
|
||||
void clearScriptsBeforeRunning();
|
||||
void initializeGL();
|
||||
void initializeUi();
|
||||
void paintGL();
|
||||
void resizeGL(int width, int height);
|
||||
|
||||
|
@ -170,6 +172,7 @@ public:
|
|||
|
||||
void wheelEvent(QWheelEvent* event);
|
||||
void dropEvent(QDropEvent *event);
|
||||
void dragEnterEvent(QDragEnterEvent *event);
|
||||
|
||||
bool event(QEvent* event);
|
||||
bool eventFilter(QObject* object, QEvent* event);
|
||||
|
|
|
@ -82,30 +82,6 @@ void GLCanvas::resizeGL(int width, int height) {
|
|||
Application::getInstance()->resizeGL(width, height);
|
||||
}
|
||||
|
||||
void GLCanvas::keyPressEvent(QKeyEvent* event) {
|
||||
Application::getInstance()->keyPressEvent(event);
|
||||
}
|
||||
|
||||
void GLCanvas::keyReleaseEvent(QKeyEvent* event) {
|
||||
Application::getInstance()->keyReleaseEvent(event);
|
||||
}
|
||||
|
||||
void GLCanvas::focusOutEvent(QFocusEvent* event) {
|
||||
Application::getInstance()->focusOutEvent(event);
|
||||
}
|
||||
|
||||
void GLCanvas::mouseMoveEvent(QMouseEvent* event) {
|
||||
Application::getInstance()->mouseMoveEvent(event);
|
||||
}
|
||||
|
||||
void GLCanvas::mousePressEvent(QMouseEvent* event) {
|
||||
Application::getInstance()->mousePressEvent(event);
|
||||
}
|
||||
|
||||
void GLCanvas::mouseReleaseEvent(QMouseEvent* event) {
|
||||
Application::getInstance()->mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
void GLCanvas::activeChanged(Qt::ApplicationState state) {
|
||||
switch (state) {
|
||||
case Qt::ApplicationActive:
|
||||
|
@ -151,40 +127,37 @@ void GLCanvas::throttleRender() {
|
|||
int updateTime = 0;
|
||||
bool GLCanvas::event(QEvent* event) {
|
||||
switch (event->type()) {
|
||||
case QEvent::MouseMove:
|
||||
case QEvent::MouseButtonPress:
|
||||
case QEvent::MouseButtonRelease:
|
||||
case QEvent::KeyPress:
|
||||
case QEvent::KeyRelease:
|
||||
case QEvent::FocusIn:
|
||||
case QEvent::FocusOut:
|
||||
case QEvent::Resize:
|
||||
case QEvent::TouchBegin:
|
||||
Application::getInstance()->touchBeginEvent(static_cast<QTouchEvent*>(event));
|
||||
event->accept();
|
||||
return true;
|
||||
case QEvent::TouchEnd:
|
||||
Application::getInstance()->touchEndEvent(static_cast<QTouchEvent*>(event));
|
||||
return true;
|
||||
case QEvent::TouchUpdate:
|
||||
Application::getInstance()->touchUpdateEvent(static_cast<QTouchEvent*>(event));
|
||||
return true;
|
||||
case QEvent::Wheel:
|
||||
case QEvent::DragEnter:
|
||||
case QEvent::Drop:
|
||||
if (QCoreApplication::sendEvent(QCoreApplication::instance(), event)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case QEvent::Paint:
|
||||
// Ignore paint events that occur after we've decided to quit
|
||||
if (Application::getInstance()->isAboutToQuit()) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QGLWidget::event(event);
|
||||
}
|
||||
|
||||
void GLCanvas::wheelEvent(QWheelEvent* event) {
|
||||
Application::getInstance()->wheelEvent(event);
|
||||
}
|
||||
|
||||
void GLCanvas::dragEnterEvent(QDragEnterEvent* event) {
|
||||
const QMimeData* mimeData = event->mimeData();
|
||||
foreach (QUrl url, mimeData->urls()) {
|
||||
auto urlString = url.toString();
|
||||
if (Application::getInstance()->canAcceptURL(urlString)) {
|
||||
event->acceptProposedAction();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLCanvas::dropEvent(QDropEvent* event) {
|
||||
Application::getInstance()->dropEvent(event);
|
||||
}
|
||||
|
||||
// Pressing Alt (and Meta) key alone activates the menubar because its style inherits the
|
||||
// SHMenuBarAltKeyNavigation from QWindowsStyle. This makes it impossible for a scripts to
|
||||
|
|
|
@ -40,23 +40,8 @@ protected:
|
|||
virtual void initializeGL();
|
||||
virtual void paintGL();
|
||||
virtual void resizeGL(int width, int height);
|
||||
|
||||
virtual void keyPressEvent(QKeyEvent* event);
|
||||
virtual void keyReleaseEvent(QKeyEvent* event);
|
||||
|
||||
virtual void focusOutEvent(QFocusEvent* event);
|
||||
|
||||
virtual void mouseMoveEvent(QMouseEvent* event);
|
||||
virtual void mousePressEvent(QMouseEvent* event);
|
||||
virtual void mouseReleaseEvent(QMouseEvent* event);
|
||||
|
||||
virtual bool event(QEvent* event);
|
||||
|
||||
virtual void wheelEvent(QWheelEvent* event);
|
||||
|
||||
virtual void dragEnterEvent(QDragEnterEvent *event);
|
||||
virtual void dropEvent(QDropEvent* event);
|
||||
|
||||
private slots:
|
||||
void activeChanged(Qt::ApplicationState state);
|
||||
void throttleRender();
|
||||
|
|
|
@ -97,7 +97,7 @@ Menu::Menu() {
|
|||
|
||||
addActionToQMenuAndActionHash(fileMenu,
|
||||
MenuOption::AddressBar,
|
||||
Qt::Key_Enter,
|
||||
Qt::CTRL | Qt::Key_L,
|
||||
dialogsManager.data(),
|
||||
SLOT(toggleAddressBar()));
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
|
@ -151,7 +151,8 @@ Menu::Menu() {
|
|||
connect(speechRecognizer.data(), SIGNAL(enabledUpdated(bool)), speechRecognizerAction, SLOT(setChecked(bool)));
|
||||
#endif
|
||||
|
||||
addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat, Qt::Key_Backslash,
|
||||
addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat,
|
||||
0, // QML Qt::Key_Backslash,
|
||||
dialogsManager.data(), SLOT(showIRCLink()));
|
||||
addActionToQMenuAndActionHash(toolsMenu, MenuOption::AddRemoveFriends, 0,
|
||||
qApp, SLOT(showFriendsWindow()));
|
||||
|
@ -194,7 +195,7 @@ Menu::Menu() {
|
|||
|
||||
addActionToQMenuAndActionHash(toolsMenu,
|
||||
MenuOption::ResetSensors,
|
||||
Qt::Key_Apostrophe,
|
||||
0, // QML Qt::Key_Apostrophe,
|
||||
qApp,
|
||||
SLOT(resetSensors()));
|
||||
|
||||
|
@ -207,17 +208,17 @@ Menu::Menu() {
|
|||
QMenu* avatarSizeMenu = avatarMenu->addMenu("Size");
|
||||
addActionToQMenuAndActionHash(avatarSizeMenu,
|
||||
MenuOption::IncreaseAvatarSize,
|
||||
Qt::Key_Plus,
|
||||
0, // QML Qt::Key_Plus,
|
||||
avatar,
|
||||
SLOT(increaseSize()));
|
||||
addActionToQMenuAndActionHash(avatarSizeMenu,
|
||||
MenuOption::DecreaseAvatarSize,
|
||||
Qt::Key_Minus,
|
||||
0, // QML Qt::Key_Minus,
|
||||
avatar,
|
||||
SLOT(decreaseSize()));
|
||||
addActionToQMenuAndActionHash(avatarSizeMenu,
|
||||
MenuOption::ResetAvatarSize,
|
||||
Qt::Key_Equal,
|
||||
0, // QML Qt::Key_Equal,
|
||||
avatar,
|
||||
SLOT(resetSize()));
|
||||
|
||||
|
@ -250,13 +251,17 @@ Menu::Menu() {
|
|||
qApp,
|
||||
SLOT(setFullscreen(bool)));
|
||||
#endif
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, Qt::Key_P, true,
|
||||
qApp,SLOT(cameraMenuChanged()));
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H, true);
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false,
|
||||
qApp, SLOT(cameraMenuChanged()));
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson,
|
||||
0, // QML Qt::Key_P,
|
||||
true, qApp, SLOT(cameraMenuChanged()));
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror,
|
||||
0, //QML Qt::SHIFT | Qt::Key_H,
|
||||
true);
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror,
|
||||
0, // QML Qt::Key_H,
|
||||
false, qApp, SLOT(cameraMenuChanged()));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, Qt::META | Qt::Key_H,
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, Qt::CTRL | Qt::SHIFT | Qt::Key_H,
|
||||
false,
|
||||
dialogsManager.data(),
|
||||
SLOT(hmdTools(bool)));
|
||||
|
@ -283,8 +288,12 @@ Menu::Menu() {
|
|||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::TurnWithHead, 0, false);
|
||||
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash);
|
||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L, qApp, SLOT(toggleLogDialog()));
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats,
|
||||
0); // QML Qt::Key_Slash);
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats);
|
||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::Log,
|
||||
Qt::CTRL | Qt::SHIFT | Qt::Key_L,
|
||||
qApp, SLOT(toggleLogDialog()));
|
||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0,
|
||||
dialogsManager.data(), SLOT(bandwidthDetails()));
|
||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0,
|
||||
|
@ -294,7 +303,9 @@ Menu::Menu() {
|
|||
QMenu* developerMenu = addMenu("Developer");
|
||||
|
||||
QMenu* renderOptionsMenu = developerMenu->addMenu("Render");
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere, Qt::SHIFT | Qt::Key_A, true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere,
|
||||
0, // QML Qt::SHIFT | Qt::Key_A,
|
||||
true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AmbientOcclusion);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DontFadeOnOctreeServerChanges);
|
||||
|
||||
|
@ -346,13 +357,16 @@ Menu::Menu() {
|
|||
resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionThird, 0, false));
|
||||
resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionQuarter, 0, false));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, Qt::Key_Asterisk, true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars,
|
||||
0, // QML Qt::Key_Asterisk,
|
||||
true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::EnableGlowEffect, 0, true,
|
||||
DependencyManager::get<GlowEffect>().data(), SLOT(toggleGlowEffect(bool)));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Wireframe, Qt::ALT | Qt::Key_W, false);
|
||||
addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, Qt::SHIFT | Qt::Key_L,
|
||||
dialogsManager.data(), SLOT(lodTools()));
|
||||
addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools,
|
||||
0, // QML Qt::SHIFT | Qt::Key_L,
|
||||
dialogsManager.data(), SLOT(lodTools()));
|
||||
|
||||
QMenu* avatarDebugMenu = developerMenu->addMenu("Avatar");
|
||||
|
||||
|
|
|
@ -114,8 +114,11 @@ void OculusManager::initSdk() {
|
|||
}
|
||||
|
||||
void OculusManager::shutdownSdk() {
|
||||
ovrHmd_Destroy(_ovrHmd);
|
||||
ovr_Shutdown();
|
||||
if (_ovrHmd) {
|
||||
ovrHmd_Destroy(_ovrHmd);
|
||||
_ovrHmd = nullptr;
|
||||
ovr_Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void OculusManager::init() {
|
||||
|
@ -124,6 +127,12 @@ void OculusManager::init() {
|
|||
#endif
|
||||
}
|
||||
|
||||
void OculusManager::deinit() {
|
||||
#ifdef OVR_DIRECT_MODE
|
||||
shutdownSdk();
|
||||
#endif
|
||||
}
|
||||
|
||||
void OculusManager::connect() {
|
||||
#ifndef OVR_DIRECT_MODE
|
||||
initSdk();
|
||||
|
@ -515,7 +524,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
|
|||
|
||||
// We only need to render the overlays to a texture once, then we just render the texture on the hemisphere
|
||||
// PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay()
|
||||
applicationOverlay.renderOverlay(true);
|
||||
applicationOverlay.renderOverlay();
|
||||
|
||||
//Bind our framebuffer object. If we are rendering the glow effect, we let the glow effect shader take care of it
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) {
|
||||
|
|
|
@ -51,6 +51,7 @@ class Text3DOverlay;
|
|||
class OculusManager {
|
||||
public:
|
||||
static void init();
|
||||
static void deinit();
|
||||
static void connect();
|
||||
static void disconnect();
|
||||
static bool isConnected();
|
||||
|
|
|
@ -103,7 +103,7 @@ void TV3DManager::display(Camera& whichCamera) {
|
|||
|
||||
// We only need to render the overlays to a texture once, then we just render the texture as a quad
|
||||
// PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay()
|
||||
applicationOverlay.renderOverlay(true);
|
||||
applicationOverlay.renderOverlay();
|
||||
|
||||
DependencyManager::get<GlowEffect>()->prepare();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
|
|
@ -112,6 +112,7 @@ int main(int argc, const char* argv[]) {
|
|||
exitCode = app.exec();
|
||||
}
|
||||
|
||||
OculusManager::deinit();
|
||||
#ifdef Q_OS_WIN
|
||||
ReleaseMutex(mutex);
|
||||
#endif
|
||||
|
|
|
@ -1,148 +1,50 @@
|
|||
//
|
||||
// AddressBarDialog.cpp
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Stojce Slavkovski on 9/22/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
// Created by Bradley Austin Davis on 2015/04/14
|
||||
// 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 "AddressBarDialog.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <PathUtils.h>
|
||||
|
||||
#include "AddressBarDialog.h"
|
||||
#include "DependencyManager.h"
|
||||
#include "AddressManager.h"
|
||||
#include "Application.h"
|
||||
#include "MainWindow.h"
|
||||
|
||||
const QString ADDRESSBAR_GO_BUTTON_ICON = "images/address-bar-submit.svg";
|
||||
const QString ADDRESSBAR_GO_BUTTON_ACTIVE_ICON = "images/address-bar-submit-active.svg";
|
||||
QML_DIALOG_DEF(AddressBarDialog)
|
||||
|
||||
AddressBarDialog::AddressBarDialog(QWidget* parent) :
|
||||
FramelessDialog(parent, 0, FramelessDialog::POSITION_TOP)
|
||||
{
|
||||
setAttribute(Qt::WA_DeleteOnClose, false);
|
||||
setupUI();
|
||||
|
||||
AddressBarDialog::AddressBarDialog(QQuickItem *parent) : QQuickItem(parent) {
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
|
||||
connect(addressManager.data(), &AddressManager::lookupResultIsOffline, this, &AddressBarDialog::displayAddressOfflineMessage);
|
||||
connect(addressManager.data(), &AddressManager::lookupResultIsNotFound, this, &AddressBarDialog::displayAddressNotFoundMessage);
|
||||
connect(addressManager.data(), &AddressManager::lookupResultsFinished, this, &AddressBarDialog::hide);
|
||||
}
|
||||
|
||||
void AddressBarDialog::setupUI() {
|
||||
|
||||
const QString DIALOG_STYLESHEET = "font-family: Helvetica, Arial, sans-serif;";
|
||||
const QString ADDRESSBAR_PLACEHOLDER = "Go to: domain, location, @user, /x,y,z";
|
||||
const QString ADDRESSBAR_STYLESHEET = "padding: 5px 10px; font-size: 20px;";
|
||||
|
||||
const int ADDRESSBAR_MIN_WIDTH = 200;
|
||||
const int ADDRESSBAR_MAX_WIDTH = 615;
|
||||
const int ADDRESSBAR_HEIGHT = 42;
|
||||
const int ADDRESSBAR_STRETCH = 60;
|
||||
|
||||
const int BUTTON_SPACER_SIZE = 5;
|
||||
const int DEFAULT_SPACER_SIZE = 20;
|
||||
const int ADDRESS_LAYOUT_RIGHT_MARGIN = 10;
|
||||
|
||||
const int GO_BUTTON_SIZE = 42;
|
||||
const int CLOSE_BUTTON_SIZE = 16;
|
||||
const QString CLOSE_BUTTON_ICON = "styles/close.svg";
|
||||
|
||||
const int DIALOG_HEIGHT = 62;
|
||||
const int DIALOG_INITIAL_WIDTH = 560;
|
||||
|
||||
QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
setSizePolicy(sizePolicy);
|
||||
setMinimumSize(QSize(DIALOG_INITIAL_WIDTH, DIALOG_HEIGHT));
|
||||
setMaximumHeight(DIALOG_HEIGHT);
|
||||
setStyleSheet(DIALOG_STYLESHEET);
|
||||
|
||||
_verticalLayout = new QVBoxLayout(this);
|
||||
_verticalLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
_addressLayout = new QHBoxLayout();
|
||||
_addressLayout->setContentsMargins(0, 0, ADDRESS_LAYOUT_RIGHT_MARGIN, 0);
|
||||
|
||||
_leftSpacer = new QSpacerItem(DEFAULT_SPACER_SIZE,
|
||||
DEFAULT_SPACER_SIZE,
|
||||
QSizePolicy::MinimumExpanding,
|
||||
QSizePolicy::Minimum);
|
||||
|
||||
_addressLayout->addItem(_leftSpacer);
|
||||
|
||||
_addressLineEdit = new QLineEdit(this);
|
||||
_addressLineEdit->setAttribute(Qt::WA_MacShowFocusRect, 0);
|
||||
_addressLineEdit->setPlaceholderText(ADDRESSBAR_PLACEHOLDER);
|
||||
QSizePolicy sizePolicyLineEdit(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
sizePolicyLineEdit.setHorizontalStretch(ADDRESSBAR_STRETCH);
|
||||
_addressLineEdit->setSizePolicy(sizePolicyLineEdit);
|
||||
_addressLineEdit->setMinimumSize(QSize(ADDRESSBAR_MIN_WIDTH, ADDRESSBAR_HEIGHT));
|
||||
_addressLineEdit->setMaximumSize(QSize(ADDRESSBAR_MAX_WIDTH, ADDRESSBAR_HEIGHT));
|
||||
_addressLineEdit->setStyleSheet(ADDRESSBAR_STYLESHEET);
|
||||
_addressLayout->addWidget(_addressLineEdit);
|
||||
|
||||
_buttonSpacer = new QSpacerItem(BUTTON_SPACER_SIZE, BUTTON_SPACER_SIZE, QSizePolicy::Fixed, QSizePolicy::Minimum);
|
||||
_addressLayout->addItem(_buttonSpacer);
|
||||
|
||||
_goButton = new QPushButton(this);
|
||||
_goButton->setSizePolicy(sizePolicy);
|
||||
_goButton->setMinimumSize(QSize(GO_BUTTON_SIZE, GO_BUTTON_SIZE));
|
||||
_goButton->setMaximumSize(QSize(GO_BUTTON_SIZE, GO_BUTTON_SIZE));
|
||||
_goButton->setIcon(QIcon(PathUtils::resourcesPath() + ADDRESSBAR_GO_BUTTON_ICON));
|
||||
_goButton->setIconSize(QSize(GO_BUTTON_SIZE, GO_BUTTON_SIZE));
|
||||
_goButton->setDefault(true);
|
||||
_goButton->setFlat(true);
|
||||
_addressLayout->addWidget(_goButton);
|
||||
|
||||
_rightSpacer = new QSpacerItem(DEFAULT_SPACER_SIZE,
|
||||
DEFAULT_SPACER_SIZE,
|
||||
QSizePolicy::MinimumExpanding,
|
||||
QSizePolicy::Minimum);
|
||||
|
||||
_addressLayout->addItem(_rightSpacer);
|
||||
|
||||
_closeButton = new QPushButton(this);
|
||||
_closeButton->setSizePolicy(sizePolicy);
|
||||
_closeButton->setMinimumSize(QSize(CLOSE_BUTTON_SIZE, CLOSE_BUTTON_SIZE));
|
||||
_closeButton->setMaximumSize(QSize(CLOSE_BUTTON_SIZE, CLOSE_BUTTON_SIZE));
|
||||
QIcon icon(PathUtils::resourcesPath() + CLOSE_BUTTON_ICON);
|
||||
_closeButton->setIcon(icon);
|
||||
_closeButton->setIconSize(QSize(CLOSE_BUTTON_SIZE, CLOSE_BUTTON_SIZE));
|
||||
_closeButton->setFlat(true);
|
||||
_addressLayout->addWidget(_closeButton, 0, Qt::AlignRight);
|
||||
|
||||
_verticalLayout->addLayout(_addressLayout);
|
||||
|
||||
connect(_goButton, &QPushButton::clicked, this, &AddressBarDialog::accept);
|
||||
connect(_closeButton, &QPushButton::clicked, this, &QDialog::close);
|
||||
void AddressBarDialog::hide() {
|
||||
setEnabled(false);
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
void AddressBarDialog::showEvent(QShowEvent* event) {
|
||||
_goButton->setIcon(QIcon(PathUtils::resourcesPath() + ADDRESSBAR_GO_BUTTON_ICON));
|
||||
_addressLineEdit->setText(QString());
|
||||
_addressLineEdit->setFocus();
|
||||
FramelessDialog::showEvent(event);
|
||||
}
|
||||
|
||||
void AddressBarDialog::accept() {
|
||||
if (!_addressLineEdit->text().isEmpty()) {
|
||||
_goButton->setIcon(QIcon(PathUtils::resourcesPath() + ADDRESSBAR_GO_BUTTON_ACTIVE_ICON));
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
connect(addressManager.data(), &AddressManager::lookupResultsFinished, this, &QDialog::hide);
|
||||
addressManager->handleLookupString(_addressLineEdit->text());
|
||||
void AddressBarDialog::loadAddress(const QString & address) {
|
||||
qDebug() << "Called LoadAddress with address " << address;
|
||||
if (!address.isEmpty()) {
|
||||
DependencyManager::get<AddressManager>()->handleLookupString(address);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO port to a QML based message box
|
||||
void AddressBarDialog::displayAddressOfflineMessage() {
|
||||
QMessageBox::information(Application::getInstance()->getWindow(), "Address offline",
|
||||
"That user or place is currently offline.");
|
||||
QMessageBox::information(nullptr, "Address offline",
|
||||
"That user or place is currently offline.");
|
||||
}
|
||||
|
||||
// TODO port to a QML based message box
|
||||
void AddressBarDialog::displayAddressNotFoundMessage() {
|
||||
QMessageBox::information(Application::getInstance()->getWindow(), "Address not found",
|
||||
"There is no address information for that user or place.");
|
||||
}
|
||||
QMessageBox::information(nullptr, "Address not found",
|
||||
"There is no address information for that user or place.");
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
//
|
||||
// AddressBarDialog.h
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Stojce Slavkovski on 9/22/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
// Created by Bradley Austin Davis on 2015/04/14
|
||||
// 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
|
||||
|
@ -12,36 +11,25 @@
|
|||
#ifndef hifi_AddressBarDialog_h
|
||||
#define hifi_AddressBarDialog_h
|
||||
|
||||
#include "FramelessDialog.h"
|
||||
#pragma once
|
||||
#include <QQuickItem>
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QHBoxLayout>
|
||||
#include <QSpacerItem>
|
||||
#include <QVBoxLayout>
|
||||
#include "OffscreenUi.h"
|
||||
|
||||
class AddressBarDialog : public FramelessDialog {
|
||||
class AddressBarDialog : public QQuickItem
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_DIALOG_DECL
|
||||
|
||||
public:
|
||||
AddressBarDialog(QWidget* parent);
|
||||
|
||||
private:
|
||||
void setupUI();
|
||||
void showEvent(QShowEvent* event);
|
||||
|
||||
QVBoxLayout *_verticalLayout;
|
||||
QHBoxLayout *_addressLayout;
|
||||
QSpacerItem *_leftSpacer;
|
||||
QSpacerItem *_rightSpacer;
|
||||
QSpacerItem *_buttonSpacer;
|
||||
QPushButton *_goButton;
|
||||
QPushButton *_closeButton;
|
||||
QLineEdit *_addressLineEdit;
|
||||
|
||||
private slots:
|
||||
void accept();
|
||||
AddressBarDialog(QQuickItem *parent = 0);
|
||||
|
||||
protected:
|
||||
void displayAddressOfflineMessage();
|
||||
void displayAddressNotFoundMessage();
|
||||
void hide();
|
||||
|
||||
Q_INVOKABLE void loadAddress(const QString & address);
|
||||
};
|
||||
|
||||
#endif // hifi_AddressBarDialog_h
|
||||
#endif
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <GLMHelpers.h>
|
||||
#include <PathUtils.h>
|
||||
#include <PerfStat.h>
|
||||
#include <OffscreenUi.h>
|
||||
|
||||
#include "AudioClient.h"
|
||||
#include "audio/AudioIOStatsRenderer.h"
|
||||
|
@ -161,13 +162,27 @@ ApplicationOverlay::ApplicationOverlay() :
|
|||
_domainStatusBorder = geometryCache->allocateID();
|
||||
_magnifierBorder = geometryCache->allocateID();
|
||||
|
||||
// Once we move UI rendering and screen rendering to different
|
||||
// threads, we need to use a sync object to deteremine when
|
||||
// the current UI texture is no longer being read from, and only
|
||||
// then release it back to the UI for re-use
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [&](GLuint textureId) {
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
offscreenUi->lockTexture(textureId);
|
||||
assert(!glGetError());
|
||||
std::swap(_newUiTexture, textureId);
|
||||
if (textureId) {
|
||||
offscreenUi->releaseTexture(textureId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ApplicationOverlay::~ApplicationOverlay() {
|
||||
}
|
||||
|
||||
// Renders the overlays either to a texture or to the screen
|
||||
void ApplicationOverlay::renderOverlay(bool renderToTexture) {
|
||||
void ApplicationOverlay::renderOverlay() {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()");
|
||||
Overlays& overlays = qApp->getOverlays();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
|
@ -183,11 +198,9 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) {
|
|||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
if (renderToTexture) {
|
||||
_overlays.buildFramebufferObject();
|
||||
_overlays.bind();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
_overlays.buildFramebufferObject();
|
||||
_overlays.bind();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glPushMatrix(); {
|
||||
const float NEAR_CLIP = -10000;
|
||||
|
@ -218,9 +231,25 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) {
|
|||
glEnable(GL_LIGHTING);
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||
|
||||
if (renderToTexture) {
|
||||
_overlays.release();
|
||||
_overlays.release();
|
||||
}
|
||||
|
||||
// A quick and dirty solution for compositing the old overlay
|
||||
// texture with the new one
|
||||
template <typename F>
|
||||
void with_each_texture(GLuint a, GLuint b, F f) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
if (a) {
|
||||
glBindTexture(GL_TEXTURE_2D, a);
|
||||
f();
|
||||
}
|
||||
if (b) {
|
||||
glBindTexture(GL_TEXTURE_2D, b);
|
||||
f();
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
// Draws the FBO texture for the screen
|
||||
|
@ -229,30 +258,24 @@ void ApplicationOverlay::displayOverlayTexture() {
|
|||
return;
|
||||
}
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
_overlays.bindTexture();
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix(); {
|
||||
glLoadIdentity();
|
||||
glOrtho(0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight(), 0, -1.0, 1.0);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
glm::vec2 topLeft(0.0f, 0.0f);
|
||||
glm::vec2 bottomRight(glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight());
|
||||
glm::vec2 texCoordTopLeft(0.0f, 1.0f);
|
||||
glm::vec2 texCoordBottomRight(1.0f, 0.0f);
|
||||
if (_alpha < 1.0) {
|
||||
glEnable(GL_BLEND);
|
||||
}
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
|
||||
glm::vec4(1.0f, 1.0f, 1.0f, _alpha));
|
||||
|
||||
with_each_texture(_overlays.getTexture(), _newUiTexture, [&] {
|
||||
static const glm::vec2 topLeft(-1, 1);
|
||||
static const glm::vec2 bottomRight(1, -1);
|
||||
static const glm::vec2 texCoordTopLeft(0.0f, 1.0f);
|
||||
static const glm::vec2 texCoordBottomRight(1.0f, 0.0f);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
|
||||
glm::vec4(1.0f, 1.0f, 1.0f, _alpha));
|
||||
});
|
||||
} glPopMatrix();
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
// Draws the FBO texture for Oculus rift.
|
||||
|
@ -260,10 +283,7 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
|
|||
if (_alpha == 0.0f) {
|
||||
return;
|
||||
}
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
_overlays.bindTexture();
|
||||
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
@ -271,8 +291,8 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
|
|||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_GREATER, 0.01f);
|
||||
|
||||
|
||||
|
||||
|
||||
//Update and draw the magnifiers
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
const glm::quat& orientation = myAvatar->getOrientation();
|
||||
|
@ -303,8 +323,9 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
|
|||
//Render magnifier, but dont show border for mouse magnifier
|
||||
glm::vec2 projection = screenToOverlay(glm::vec2(_reticlePosition[MOUSE].x(),
|
||||
_reticlePosition[MOUSE].y()));
|
||||
|
||||
renderMagnifier(projection, _magSizeMult[i], i != MOUSE);
|
||||
with_each_texture(_overlays.getTexture(), _newUiTexture, [&] {
|
||||
renderMagnifier(projection, _magSizeMult[i], i != MOUSE);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -319,12 +340,15 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
|
|||
|
||||
_overlays.buildVBO(_textureFov, _textureAspectRatio, 80, 80);
|
||||
}
|
||||
_overlays.render();
|
||||
|
||||
with_each_texture(_overlays.getTexture(), _newUiTexture, [&] {
|
||||
_overlays.render();
|
||||
});
|
||||
|
||||
if (!Application::getInstance()->isMouseHidden()) {
|
||||
renderPointersOculus(myAvatar->getDefaultEyePosition());
|
||||
}
|
||||
glDepthMask(GL_TRUE);
|
||||
_overlays.releaseTexture();
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||
|
@ -341,14 +365,10 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as
|
|||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
const glm::vec3& viewMatrixTranslation = qApp->getViewMatrixTranslation();
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||
_overlays.bindTexture();
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
|
@ -382,13 +402,15 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as
|
|||
GLfloat y = -halfQuadHeight;
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(glm::vec3(x, y + quadHeight, -distance),
|
||||
with_each_texture(_overlays.getTexture(), _newUiTexture, [&] {
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(glm::vec3(x, y + quadHeight, -distance),
|
||||
glm::vec3(x + quadWidth, y + quadHeight, -distance),
|
||||
glm::vec3(x + quadWidth, y, -distance),
|
||||
glm::vec3(x, y, -distance),
|
||||
glm::vec2(0.0f, 1.0f), glm::vec2(1.0f, 1.0f),
|
||||
glm::vec2(1.0f, 0.0f), glm::vec2(0.0f, 0.0f),
|
||||
overlayColor);
|
||||
});
|
||||
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
if (_crosshairTexture == 0) {
|
||||
|
@ -993,14 +1015,6 @@ void ApplicationOverlay::TexturedHemisphere::release() {
|
|||
_framebufferObject->release();
|
||||
}
|
||||
|
||||
void ApplicationOverlay::TexturedHemisphere::bindTexture() {
|
||||
glBindTexture(GL_TEXTURE_2D, _framebufferObject->texture());
|
||||
}
|
||||
|
||||
void ApplicationOverlay::TexturedHemisphere::releaseTexture() {
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
void ApplicationOverlay::TexturedHemisphere::buildVBO(const float fov,
|
||||
const float aspectRatio,
|
||||
const int slices,
|
||||
|
@ -1099,14 +1113,14 @@ void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject() {
|
|||
}
|
||||
|
||||
_framebufferObject = new QOpenGLFramebufferObject(size, QOpenGLFramebufferObject::Depth);
|
||||
bindTexture();
|
||||
glBindTexture(GL_TEXTURE_2D, getTexture());
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
GLfloat borderColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
|
||||
releaseTexture();
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
//Renders a hemisphere with texture coordinates.
|
||||
|
@ -1137,6 +1151,10 @@ void ApplicationOverlay::TexturedHemisphere::render() {
|
|||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
GLuint ApplicationOverlay::TexturedHemisphere::getTexture() {
|
||||
return _framebufferObject->texture();
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationOverlay::directionToSpherical(glm::vec3 direction) const {
|
||||
glm::vec2 result;
|
||||
// Compute yaw
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
ApplicationOverlay();
|
||||
~ApplicationOverlay();
|
||||
|
||||
void renderOverlay(bool renderToTexture = false);
|
||||
void renderOverlay();
|
||||
void displayOverlayTexture();
|
||||
void displayOverlayTextureOculus(Camera& whichCamera);
|
||||
void displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov);
|
||||
|
@ -75,8 +75,7 @@ private:
|
|||
|
||||
void bind();
|
||||
void release();
|
||||
void bindTexture();
|
||||
void releaseTexture();
|
||||
GLuint getTexture();
|
||||
|
||||
void buildFramebufferObject();
|
||||
void buildVBO(const float fov, const float aspectRatio, const int slices, const int stacks);
|
||||
|
@ -122,6 +121,9 @@ private:
|
|||
float _trailingAudioLoudness;
|
||||
|
||||
GLuint _crosshairTexture;
|
||||
// TODO, move divide up the rendering, displaying and input handling
|
||||
// facilities of this class
|
||||
GLuint _newUiTexture{ 0 };
|
||||
|
||||
int _reticleQuad;
|
||||
int _magnifierQuad;
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "DialogsManager.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <AccountManager.h>
|
||||
|
@ -28,14 +30,9 @@
|
|||
#include "PreferencesDialog.h"
|
||||
#include "ScriptEditorWindow.h"
|
||||
|
||||
#include "DialogsManager.h"
|
||||
|
||||
void DialogsManager::toggleAddressBar() {
|
||||
maybeCreateDialog(_addressBarDialog);
|
||||
|
||||
if (!_addressBarDialog->isVisible()) {
|
||||
_addressBarDialog->show();
|
||||
}
|
||||
AddressBarDialog::toggle();
|
||||
}
|
||||
|
||||
void DialogsManager::toggleDiskCacheEditor() {
|
||||
|
@ -44,13 +41,11 @@ void DialogsManager::toggleDiskCacheEditor() {
|
|||
}
|
||||
|
||||
void DialogsManager::toggleLoginDialog() {
|
||||
maybeCreateDialog(_loginDialog);
|
||||
_loginDialog->toggleQAction();
|
||||
LoginDialog::toggleAction();
|
||||
}
|
||||
|
||||
void DialogsManager::showLoginDialog() {
|
||||
maybeCreateDialog(_loginDialog);
|
||||
_loginDialog->showLoginForCurrentDomain();
|
||||
LoginDialog::show();
|
||||
}
|
||||
|
||||
void DialogsManager::octreeStatsDetails() {
|
||||
|
@ -170,3 +165,4 @@ void DialogsManager::showIRCLink() {
|
|||
|
||||
_ircInfoBox->raise();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,166 +0,0 @@
|
|||
//
|
||||
// FramelessDialog.cpp
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Stojce Slavkovski on 2/20/14.
|
||||
// Copyright 2014 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 <QScreen>
|
||||
#include <QWindow>
|
||||
|
||||
#include <PathUtils.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "FramelessDialog.h"
|
||||
#include "Menu.h"
|
||||
|
||||
const int RESIZE_HANDLE_WIDTH = 7;
|
||||
|
||||
FramelessDialog::FramelessDialog(QWidget *parent, Qt::WindowFlags flags, Position position) :
|
||||
QDialog(parent, flags | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint),
|
||||
_allowResize(true),
|
||||
_isResizing(false),
|
||||
_resizeInitialWidth(0),
|
||||
_selfHidden(false),
|
||||
_position(position),
|
||||
_hideOnBlur(true) {
|
||||
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
// handle rezize and move events
|
||||
parentWidget()->installEventFilter(this);
|
||||
|
||||
// handle minimize, restore and focus events
|
||||
Application::getInstance()->installEventFilter(this);
|
||||
}
|
||||
|
||||
bool FramelessDialog::eventFilter(QObject* sender, QEvent* event) {
|
||||
switch (event->type()) {
|
||||
case QEvent::Move:
|
||||
if (sender == parentWidget()) {
|
||||
resizeAndPosition(false);
|
||||
}
|
||||
break;
|
||||
case QEvent::Resize:
|
||||
if (sender == parentWidget()) {
|
||||
resizeAndPosition(false);
|
||||
}
|
||||
break;
|
||||
case QEvent::WindowStateChange:
|
||||
if (_hideOnBlur && parentWidget()->isMinimized()) {
|
||||
if (isVisible()) {
|
||||
_selfHidden = true;
|
||||
setHidden(true);
|
||||
}
|
||||
} else if (_selfHidden) {
|
||||
_selfHidden = false;
|
||||
setHidden(false);
|
||||
}
|
||||
break;
|
||||
case QEvent::ApplicationDeactivate:
|
||||
// hide on minimize and focus lost
|
||||
if (_hideOnBlur && isVisible()) {
|
||||
_selfHidden = true;
|
||||
setHidden(true);
|
||||
}
|
||||
break;
|
||||
case QEvent::ApplicationActivate:
|
||||
if (_selfHidden) {
|
||||
_selfHidden = false;
|
||||
setHidden(false);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FramelessDialog::setStyleSheetFile(const QString& fileName) {
|
||||
QFile globalStyleSheet(PathUtils::resourcesPath() + "styles/global.qss");
|
||||
QFile styleSheet(PathUtils::resourcesPath() + fileName);
|
||||
if (styleSheet.open(QIODevice::ReadOnly) && globalStyleSheet.open(QIODevice::ReadOnly) ) {
|
||||
QDir::setCurrent(PathUtils::resourcesPath());
|
||||
setStyleSheet(globalStyleSheet.readAll() + styleSheet.readAll());
|
||||
}
|
||||
}
|
||||
|
||||
void FramelessDialog::showEvent(QShowEvent* event) {
|
||||
resizeAndPosition();
|
||||
QDialog::showEvent(event);
|
||||
}
|
||||
|
||||
void FramelessDialog::resizeAndPosition(bool resizeParent) {
|
||||
QRect parentGeometry = Application::getInstance()->getDesirableApplicationGeometry();
|
||||
QSize parentSize = parentGeometry.size();
|
||||
|
||||
// keep full app height or width depending on position
|
||||
if (_position == POSITION_LEFT || _position == POSITION_RIGHT) {
|
||||
setFixedHeight(parentSize.height());
|
||||
} else {
|
||||
setFixedWidth(parentSize.width());
|
||||
}
|
||||
|
||||
// resize parrent if width is smaller than this dialog
|
||||
if (resizeParent && parentSize.width() < size().width()) {
|
||||
parentWidget()->resize(size().width(), parentSize.height());
|
||||
}
|
||||
|
||||
if (_position == POSITION_LEFT || _position == POSITION_TOP) {
|
||||
// move to upper left corner
|
||||
move(parentGeometry.topLeft());
|
||||
} else if (_position == POSITION_RIGHT) {
|
||||
// move to upper right corner
|
||||
QPoint pos = parentGeometry.topRight();
|
||||
pos.setX(pos.x() - size().width());
|
||||
move(pos);
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
|
||||
void FramelessDialog::mousePressEvent(QMouseEvent* mouseEvent) {
|
||||
if (_allowResize && mouseEvent->button() == Qt::LeftButton) {
|
||||
if (_position == POSITION_LEFT || _position == POSITION_RIGHT) {
|
||||
bool hitLeft = (_position == POSITION_LEFT) && (abs(mouseEvent->pos().x() - size().width()) < RESIZE_HANDLE_WIDTH);
|
||||
bool hitRight = (_position == POSITION_RIGHT) && (mouseEvent->pos().x() < RESIZE_HANDLE_WIDTH);
|
||||
if (hitLeft || hitRight) {
|
||||
_isResizing = true;
|
||||
_resizeInitialWidth = size().width();
|
||||
setCursor(Qt::SizeHorCursor);
|
||||
}
|
||||
} else {
|
||||
bool hitTop = (_position == POSITION_TOP) && (abs(mouseEvent->pos().y() - size().height()) < RESIZE_HANDLE_WIDTH);
|
||||
if (hitTop) {
|
||||
_isResizing = true;
|
||||
_resizeInitialWidth = size().height();
|
||||
setCursor(Qt::SizeHorCursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FramelessDialog::mouseReleaseEvent(QMouseEvent* mouseEvent) {
|
||||
unsetCursor();
|
||||
_isResizing = false;
|
||||
}
|
||||
|
||||
void FramelessDialog::mouseMoveEvent(QMouseEvent* mouseEvent) {
|
||||
if (_isResizing) {
|
||||
if (_position == POSITION_LEFT) {
|
||||
resize(mouseEvent->pos().x(), size().height());
|
||||
} else if (_position == POSITION_RIGHT) {
|
||||
setUpdatesEnabled(false);
|
||||
resize(_resizeInitialWidth - mouseEvent->pos().x(), size().height());
|
||||
resizeAndPosition();
|
||||
_resizeInitialWidth = size().width();
|
||||
setUpdatesEnabled(true);
|
||||
} else if (_position == POSITION_TOP) {
|
||||
resize(size().width(), mouseEvent->pos().y());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
//
|
||||
// FramelessDialog.h
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Stojce Slavkovski on 2/20/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
#ifndef hifi_FramelessDialog_h
|
||||
#define hifi_FramelessDialog_h
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class FramelessDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Position { POSITION_LEFT, POSITION_RIGHT, POSITION_TOP };
|
||||
|
||||
FramelessDialog(QWidget* parent, Qt::WindowFlags flags = 0, Position position = POSITION_LEFT);
|
||||
void setStyleSheetFile(const QString& fileName);
|
||||
void setAllowResize(bool allowResize) { _allowResize = allowResize; }
|
||||
bool getAllowResize() { return _allowResize; }
|
||||
void setHideOnBlur(bool hideOnBlur) { _hideOnBlur = hideOnBlur; }
|
||||
bool getHideOnBlur() { return _hideOnBlur; }
|
||||
void resizeAndPosition(bool resizeParent = true);
|
||||
|
||||
protected:
|
||||
virtual void mouseMoveEvent(QMouseEvent* mouseEvent);
|
||||
virtual void mousePressEvent(QMouseEvent* mouseEvent);
|
||||
virtual void mouseReleaseEvent(QMouseEvent* mouseEvent);
|
||||
virtual void showEvent(QShowEvent* event);
|
||||
|
||||
bool eventFilter(QObject* sender, QEvent* event);
|
||||
|
||||
private:
|
||||
bool _allowResize;
|
||||
bool _isResizing;
|
||||
int _resizeInitialWidth;
|
||||
bool _selfHidden; ///< true when the dialog itself because of a window event (deactivation or minimization)
|
||||
Position _position;
|
||||
bool _hideOnBlur;
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_FramelessDialog_h
|
|
@ -1,120 +1,35 @@
|
|||
//
|
||||
//
|
||||
// LoginDialog.cpp
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Ryan Huffman on 4/23/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
// Created by Bradley Austin Davis on 2015/04/14
|
||||
// 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 <QWidget>
|
||||
#include <QPushButton>
|
||||
#include <QPixmap>
|
||||
|
||||
#include <NetworkingConstants.h>
|
||||
#include <PathUtils.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "Menu.h"
|
||||
#include "AccountManager.h"
|
||||
#include "ui_loginDialog.h"
|
||||
#include "LoginDialog.h"
|
||||
#include "UIUtil.h"
|
||||
|
||||
const QString CREATE_ACCOUNT_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/signup";
|
||||
const QString FORGOT_PASSWORD_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/users/password/new";
|
||||
#include "DependencyManager.h"
|
||||
#include "AccountManager.h"
|
||||
#include "Menu.h"
|
||||
#include <NetworkingConstants.h>
|
||||
|
||||
LoginDialog::LoginDialog(QWidget* parent) :
|
||||
FramelessDialog(parent, 0, FramelessDialog::POSITION_TOP),
|
||||
_ui(new Ui::LoginDialog) {
|
||||
|
||||
_ui->setupUi(this);
|
||||
reset();
|
||||
|
||||
setAttribute(Qt::WA_DeleteOnClose, false);
|
||||
QML_DIALOG_DEF(LoginDialog)
|
||||
|
||||
LoginDialog::LoginDialog(QQuickItem *parent) : QQuickItem(parent), _rootUrl(NetworkingConstants::METAVERSE_SERVER_URL.toString()) {
|
||||
connect(&AccountManager::getInstance(), &AccountManager::loginComplete,
|
||||
this, &LoginDialog::handleLoginCompleted);
|
||||
this, &LoginDialog::handleLoginCompleted);
|
||||
connect(&AccountManager::getInstance(), &AccountManager::loginFailed,
|
||||
this, &LoginDialog::handleLoginFailed);
|
||||
connect(_ui->loginButton, &QPushButton::clicked,
|
||||
this, &LoginDialog::handleLoginClicked);
|
||||
connect(_ui->closeButton, &QPushButton::clicked,
|
||||
this, &LoginDialog::close);
|
||||
|
||||
UIUtil::scaleWidgetFontSizes(this);
|
||||
_ui->accountLabel->setText(_ui->accountLabel->text().arg(CREATE_ACCOUNT_URL, FORGOT_PASSWORD_URL));
|
||||
|
||||
// Initialize toggle connection
|
||||
toggleQAction();
|
||||
};
|
||||
|
||||
LoginDialog::~LoginDialog() {
|
||||
delete _ui;
|
||||
};
|
||||
|
||||
void LoginDialog::reset() {
|
||||
_ui->errorLabel->hide();
|
||||
_ui->emailLineEdit->setFocus();
|
||||
_ui->logoLabel->setPixmap(QPixmap(PathUtils::resourcesPath() + "images/hifi-logo.svg"));
|
||||
_ui->loginButton->setIcon(QIcon(PathUtils::resourcesPath() + "images/login.svg"));
|
||||
_ui->closeButton->setIcon(QIcon(PathUtils::resourcesPath() + "images/close.svg"));
|
||||
_ui->infoLabel->setVisible(false);
|
||||
_ui->errorLabel->setVisible(false);
|
||||
|
||||
_ui->emailLineEdit->setText("");
|
||||
_ui->passwordLineEdit->setText("");
|
||||
_ui->loginArea->setDisabled(false);
|
||||
this, &LoginDialog::handleLoginFailed);
|
||||
}
|
||||
|
||||
void LoginDialog::handleLoginCompleted(const QUrl& authURL) {
|
||||
reset();
|
||||
close();
|
||||
};
|
||||
|
||||
void LoginDialog::handleLoginFailed() {
|
||||
_ui->infoLabel->setVisible(false);
|
||||
_ui->errorLabel->setVisible(true);
|
||||
|
||||
_ui->errorLabel->show();
|
||||
_ui->loginArea->setDisabled(false);
|
||||
|
||||
// Move focus to password and select the entire line
|
||||
_ui->passwordLineEdit->setFocus();
|
||||
_ui->passwordLineEdit->setSelection(0, _ui->emailLineEdit->maxLength());
|
||||
};
|
||||
|
||||
void LoginDialog::handleLoginClicked() {
|
||||
// If the email or password inputs are empty, move focus to them, otherwise attempt to login.
|
||||
if (_ui->emailLineEdit->text().isEmpty()) {
|
||||
_ui->emailLineEdit->setFocus();
|
||||
} else if (_ui->passwordLineEdit->text().isEmpty()) {
|
||||
_ui->passwordLineEdit->setFocus();
|
||||
} else {
|
||||
_ui->infoLabel->setVisible(true);
|
||||
_ui->errorLabel->setVisible(false);
|
||||
|
||||
_ui->loginArea->setDisabled(true);
|
||||
AccountManager::getInstance().requestAccessToken(_ui->emailLineEdit->text(), _ui->passwordLineEdit->text());
|
||||
}
|
||||
};
|
||||
|
||||
void LoginDialog::moveEvent(QMoveEvent* event) {
|
||||
// Modal dialogs seemed to get repositioned automatically. Combat this by moving the window if needed.
|
||||
resizeAndPosition();
|
||||
};
|
||||
|
||||
|
||||
void LoginDialog::toggleQAction() {
|
||||
void LoginDialog::toggleAction() {
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
QAction* loginAction = Menu::getInstance()->getActionForOption(MenuOption::Login);
|
||||
Q_CHECK_PTR(loginAction);
|
||||
|
||||
disconnect(loginAction, 0, 0, 0);
|
||||
|
||||
|
||||
if (accountManager.isLoggedIn()) {
|
||||
// change the menu item to logout
|
||||
loginAction->setText("Logout " + accountManager.getAccountInfo().getUsername());
|
||||
|
@ -122,11 +37,40 @@ void LoginDialog::toggleQAction() {
|
|||
} else {
|
||||
// change the menu item to login
|
||||
loginAction->setText("Login");
|
||||
connect(loginAction, &QAction::triggered, this, &LoginDialog::showLoginForCurrentDomain);
|
||||
connect(loginAction, &QAction::triggered, &LoginDialog::show);
|
||||
}
|
||||
}
|
||||
|
||||
void LoginDialog::showLoginForCurrentDomain() {
|
||||
show();
|
||||
resizeAndPosition(false);
|
||||
void LoginDialog::handleLoginCompleted(const QUrl& authURL) {
|
||||
setEnabled(false);
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
void LoginDialog::handleLoginFailed() {
|
||||
setStatusText("<font color = \"#267077\">Invalid username or password.< / font>");
|
||||
}
|
||||
|
||||
void LoginDialog::setStatusText(const QString &a) {
|
||||
if (a != _statusText) {
|
||||
_statusText = a;
|
||||
emit statusTextChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString LoginDialog::statusText() const {
|
||||
return _statusText;
|
||||
}
|
||||
|
||||
QString LoginDialog::rootUrl() const {
|
||||
return _rootUrl;
|
||||
}
|
||||
|
||||
void LoginDialog::login(const QString & username, const QString & password) {
|
||||
qDebug() << "Attempting to login " << username;
|
||||
setStatusText("Authenticating...");
|
||||
AccountManager::getInstance().requestAccessToken(username, password);
|
||||
}
|
||||
|
||||
void LoginDialog::openUrl(const QString & url) {
|
||||
qDebug() << url;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
//
|
||||
// LoginDialog.h
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Ryan Huffman on 4/23/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
// Created by Bradley Austin Davis on 2015/04/14
|
||||
// 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
|
||||
|
@ -12,35 +11,41 @@
|
|||
#ifndef hifi_LoginDialog_h
|
||||
#define hifi_LoginDialog_h
|
||||
|
||||
#include <QObject>
|
||||
#include "FramelessDialog.h"
|
||||
#pragma once
|
||||
#include <QQuickItem>
|
||||
|
||||
namespace Ui {
|
||||
class LoginDialog;
|
||||
}
|
||||
#include "OffscreenUi.h"
|
||||
|
||||
class LoginDialog : public FramelessDialog {
|
||||
class LoginDialog : public QQuickItem
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_DIALOG_DECL
|
||||
|
||||
Q_PROPERTY(QString statusText READ statusText WRITE setStatusText NOTIFY statusTextChanged)
|
||||
Q_PROPERTY(QString rootUrl READ rootUrl)
|
||||
|
||||
public:
|
||||
LoginDialog(QWidget* parent);
|
||||
~LoginDialog();
|
||||
static void toggleAction();
|
||||
|
||||
public slots:
|
||||
void toggleQAction();
|
||||
void showLoginForCurrentDomain();
|
||||
|
||||
protected slots:
|
||||
void reset();
|
||||
void handleLoginClicked();
|
||||
LoginDialog(QQuickItem *parent = 0);
|
||||
|
||||
void setStatusText(const QString & a);
|
||||
QString statusText() const;
|
||||
|
||||
QString rootUrl() const;
|
||||
|
||||
signals:
|
||||
void statusTextChanged();
|
||||
|
||||
protected:
|
||||
void handleLoginCompleted(const QUrl& authURL);
|
||||
void handleLoginFailed();
|
||||
|
||||
protected:
|
||||
void moveEvent(QMoveEvent* event);
|
||||
|
||||
Q_INVOKABLE void login(const QString & username, const QString & password);
|
||||
Q_INVOKABLE void openUrl(const QString & url);
|
||||
private:
|
||||
Ui::LoginDialog* _ui = nullptr;
|
||||
QString _statusText;
|
||||
const QString _rootUrl;
|
||||
};
|
||||
|
||||
#endif // hifi_LoginDialog_h
|
||||
|
|
|
@ -6,7 +6,7 @@ AUTOSCRIBE_SHADER_LIB(gpu model)
|
|||
qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc")
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Widgets OpenGL Network Script)
|
||||
setup_hifi_library(Widgets OpenGL Network Qml Quick Script)
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
|
|
98
libraries/render-utils/src/FboCache.cpp
Normal file
98
libraries/render-utils/src/FboCache.cpp
Normal file
|
@ -0,0 +1,98 @@
|
|||
//
|
||||
// OffscreenGlCanvas.cpp
|
||||
// interface/src/renderer
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2014/04/09.
|
||||
// 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 "FboCache.h"
|
||||
|
||||
#include <QOpenGLFramebufferObject>
|
||||
#include <QDebug>
|
||||
#include "ThreadHelpers.h"
|
||||
|
||||
FboCache::FboCache() {
|
||||
// Why do we even HAVE that lever?
|
||||
}
|
||||
|
||||
void FboCache::lockTexture(int texture) {
|
||||
withLock(_lock, [&] {
|
||||
Q_ASSERT(_fboMap.count(texture));
|
||||
if (!_fboLocks.count(texture)) {
|
||||
Q_ASSERT(_readyFboQueue.front()->texture() == texture);
|
||||
_readyFboQueue.pop_front();
|
||||
_fboLocks[texture] = 1;
|
||||
} else {
|
||||
_fboLocks[texture]++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void FboCache::releaseTexture(int texture) {
|
||||
withLock(_lock, [&] {
|
||||
Q_ASSERT(_fboMap.count(texture));
|
||||
Q_ASSERT(_fboLocks.count(texture));
|
||||
int newLockCount = --_fboLocks[texture];
|
||||
if (!newLockCount) {
|
||||
auto fbo = _fboMap[texture].data();
|
||||
if (fbo->size() != _size) {
|
||||
// Move the old FBO to the destruction queue.
|
||||
// We can't destroy the FBO here because we might
|
||||
// not be on the right thread or have the context active
|
||||
_destroyFboQueue.push_back(_fboMap[texture]);
|
||||
_fboMap.remove(texture);
|
||||
} else {
|
||||
_readyFboQueue.push_back(fbo);
|
||||
}
|
||||
_fboLocks.remove(texture);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QOpenGLFramebufferObject* FboCache::getReadyFbo() {
|
||||
QOpenGLFramebufferObject* result = nullptr;
|
||||
withLock(_lock, [&] {
|
||||
// Delete any FBOs queued for deletion
|
||||
_destroyFboQueue.clear();
|
||||
|
||||
if (_readyFboQueue.empty()) {
|
||||
qDebug() << "Building new offscreen FBO number " << _fboMap.size() + 1;
|
||||
result = new QOpenGLFramebufferObject(_size, QOpenGLFramebufferObject::CombinedDepthStencil);
|
||||
_fboMap[result->texture()] = QSharedPointer<QOpenGLFramebufferObject>(result);
|
||||
_readyFboQueue.push_back(result);
|
||||
} else {
|
||||
result = _readyFboQueue.front();
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void FboCache::setSize(const QSize & newSize) {
|
||||
if (_size == newSize) {
|
||||
return;
|
||||
}
|
||||
_size = newSize;
|
||||
withLock(_lock, [&] {
|
||||
// Clear out any fbos with the old id
|
||||
_readyFboQueue.clear();
|
||||
|
||||
QSet<int> outdatedFbos;
|
||||
// FBOs that are locked will be removed as they are unlocked
|
||||
foreach(int texture, _fboMap.keys()) {
|
||||
if (!_fboLocks.count(texture)) {
|
||||
outdatedFbos.insert(texture);
|
||||
}
|
||||
}
|
||||
// Implicitly deletes the FBO via the shared pointer destruction mechanism
|
||||
foreach(int texture, outdatedFbos) {
|
||||
_fboMap.remove(texture);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
50
libraries/render-utils/src/FboCache.h
Normal file
50
libraries/render-utils/src/FboCache.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
//
|
||||
// OffscreenGlCanvas.h
|
||||
// interface/src/renderer
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2014/04/09.
|
||||
// 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
|
||||
//
|
||||
#pragma once
|
||||
#ifndef hifi_FboCache_h
|
||||
#define hifi_FboCache_h
|
||||
|
||||
#include <QOpenGLContext>
|
||||
#include <QOffscreenSurface>
|
||||
#include <QQueue>
|
||||
#include <QMap>
|
||||
#include <QSharedPointer>
|
||||
|
||||
class QOpenGLFramebufferObject;
|
||||
|
||||
class FboCache : public QObject {
|
||||
public:
|
||||
FboCache();
|
||||
|
||||
// setSize() and getReadyFbo() must consitently be called from only a single
|
||||
// thread. Additionally, it is the caller's responsibility to ensure that
|
||||
// the appropriate OpenGL context is active when doing so.
|
||||
|
||||
// Important.... textures are sharable resources, but FBOs ARE NOT.
|
||||
void setSize(const QSize & newSize);
|
||||
QOpenGLFramebufferObject* getReadyFbo();
|
||||
|
||||
// These operations are thread safe and require no OpenGL context. They manipulate the
|
||||
// internal locks and pointers but execute no OpenGL opreations.
|
||||
void lockTexture(int texture);
|
||||
void releaseTexture(int texture);
|
||||
|
||||
protected:
|
||||
QMap<int, QSharedPointer<QOpenGLFramebufferObject>> _fboMap;
|
||||
QMap<int, int> _fboLocks;
|
||||
QQueue<QOpenGLFramebufferObject*> _readyFboQueue;
|
||||
QQueue<QSharedPointer<QOpenGLFramebufferObject>> _destroyFboQueue;
|
||||
QMutex _lock;
|
||||
QSize _size;
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_FboCache_h
|
43
libraries/render-utils/src/OffscreenGlCanvas.cpp
Normal file
43
libraries/render-utils/src/OffscreenGlCanvas.cpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// OffscreenGlCanvas.cpp
|
||||
// interface/src/renderer
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2014/04/09.
|
||||
// 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 "OffscreenGlCanvas.h"
|
||||
|
||||
OffscreenGlCanvas::OffscreenGlCanvas() {
|
||||
}
|
||||
|
||||
void OffscreenGlCanvas::create(QOpenGLContext * sharedContext) {
|
||||
QSurfaceFormat format;
|
||||
format.setDepthBufferSize(16);
|
||||
format.setStencilBufferSize(8);
|
||||
format.setMajorVersion(4);
|
||||
format.setMinorVersion(1);
|
||||
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile);
|
||||
|
||||
_context.setFormat(format);
|
||||
if (nullptr != sharedContext) {
|
||||
_context.setShareContext(sharedContext);
|
||||
}
|
||||
_context.create();
|
||||
|
||||
_offscreenSurface.setFormat(_context.format());
|
||||
_offscreenSurface.create();
|
||||
}
|
||||
|
||||
bool OffscreenGlCanvas::makeCurrent() {
|
||||
return _context.makeCurrent(&_offscreenSurface);
|
||||
}
|
||||
|
||||
void OffscreenGlCanvas::doneCurrent() {
|
||||
_context.doneCurrent();
|
||||
}
|
||||
|
31
libraries/render-utils/src/OffscreenGlCanvas.h
Normal file
31
libraries/render-utils/src/OffscreenGlCanvas.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// OffscreenGlCanvas.h
|
||||
// interface/src/renderer
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2014/04/09.
|
||||
// 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
|
||||
//
|
||||
#pragma once
|
||||
#ifndef hifi_OffscreenGlCanvas_h
|
||||
#define hifi_OffscreenGlCanvas_h
|
||||
|
||||
#include <QOpenGLContext>
|
||||
#include <QOffscreenSurface>
|
||||
|
||||
class OffscreenGlCanvas : public QObject {
|
||||
public:
|
||||
OffscreenGlCanvas();
|
||||
void create(QOpenGLContext * sharedContext = nullptr);
|
||||
bool makeCurrent();
|
||||
void doneCurrent();
|
||||
|
||||
protected:
|
||||
QOpenGLContext _context;
|
||||
QOffscreenSurface _offscreenSurface;
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_OffscreenGlCanvas_h
|
325
libraries/render-utils/src/OffscreenUi.cpp
Normal file
325
libraries/render-utils/src/OffscreenUi.cpp
Normal file
|
@ -0,0 +1,325 @@
|
|||
#include "OffscreenUi.h"
|
||||
#include <QOpenGLFramebufferObject>
|
||||
#include <QOpenGLDebugLogger>
|
||||
#include <QGLWidget>
|
||||
|
||||
OffscreenUi::OffscreenUi() {
|
||||
}
|
||||
|
||||
OffscreenUi::~OffscreenUi() {
|
||||
// Make sure the context is current while doing cleanup. Note that we use the
|
||||
// offscreen surface here because passing 'this' at this point is not safe: the
|
||||
// underlying platform window may already be destroyed. To avoid all the trouble, use
|
||||
// another surface that is valid for sure.
|
||||
makeCurrent();
|
||||
|
||||
// Delete the render control first since it will free the scenegraph resources.
|
||||
// Destroy the QQuickWindow only afterwards.
|
||||
delete _renderControl;
|
||||
|
||||
delete _qmlComponent;
|
||||
delete _quickWindow;
|
||||
delete _qmlEngine;
|
||||
|
||||
doneCurrent();
|
||||
}
|
||||
|
||||
void OffscreenUi::create(QOpenGLContext * shareContext) {
|
||||
OffscreenGlCanvas::create(shareContext);
|
||||
|
||||
makeCurrent();
|
||||
|
||||
// Create a QQuickWindow that is associated with out render control. Note that this
|
||||
// window never gets created or shown, meaning that it will never get an underlying
|
||||
// native (platform) window.
|
||||
QQuickWindow::setDefaultAlphaBuffer(true);
|
||||
_quickWindow = new QQuickWindow(_renderControl);
|
||||
_quickWindow->setColor(QColor(255, 255, 255, 0));
|
||||
_quickWindow->setFlags(_quickWindow->flags() | static_cast<Qt::WindowFlags>(Qt::WA_TranslucentBackground));
|
||||
// Create a QML engine.
|
||||
_qmlEngine = new QQmlEngine;
|
||||
if (!_qmlEngine->incubationController())
|
||||
_qmlEngine->setIncubationController(_quickWindow->incubationController());
|
||||
|
||||
// When Quick says there is a need to render, we will not render immediately. Instead,
|
||||
// a timer with a small interval is used to get better performance.
|
||||
_updateTimer.setSingleShot(true);
|
||||
_updateTimer.setInterval(5);
|
||||
connect(&_updateTimer, &QTimer::timeout, this, &OffscreenUi::updateQuick);
|
||||
|
||||
// Now hook up the signals. For simplicy we don't differentiate between
|
||||
// renderRequested (only render is needed, no sync) and sceneChanged (polish and sync
|
||||
// is needed too).
|
||||
connect(_renderControl, &QQuickRenderControl::renderRequested, this, &OffscreenUi::requestRender);
|
||||
connect(_renderControl, &QQuickRenderControl::sceneChanged, this, &OffscreenUi::requestUpdate);
|
||||
connect(_quickWindow, &QQuickWindow::focusObjectChanged, this, [this](QObject *object){
|
||||
OffscreenUi * p = this;
|
||||
qDebug() << "Focus changed to " << object;
|
||||
});
|
||||
_quickWindow->focusObject();
|
||||
|
||||
_qmlComponent = new QQmlComponent(_qmlEngine);
|
||||
|
||||
// Initialize the render control and our OpenGL resources.
|
||||
makeCurrent();
|
||||
_renderControl->initialize(&_context);
|
||||
}
|
||||
|
||||
void OffscreenUi::resize(const QSize & newSize) {
|
||||
makeCurrent();
|
||||
|
||||
// Clear out any fbos with the old size
|
||||
_fboCache.setSize(newSize);
|
||||
|
||||
// Update our members
|
||||
if (_rootItem) {
|
||||
_rootItem->setSize(newSize);
|
||||
}
|
||||
|
||||
if (_quickWindow) {
|
||||
_quickWindow->setGeometry(QRect(QPoint(), newSize));
|
||||
}
|
||||
|
||||
doneCurrent();
|
||||
}
|
||||
|
||||
QQmlContext * OffscreenUi::qmlContext() {
|
||||
if (nullptr == _rootItem) {
|
||||
return _qmlComponent->creationContext();
|
||||
}
|
||||
return QQmlEngine::contextForObject(_rootItem);
|
||||
}
|
||||
|
||||
void OffscreenUi::loadQml(const QUrl & qmlSource, std::function<void(QQmlContext*)> f) {
|
||||
_qmlComponent->loadUrl(qmlSource);
|
||||
if (_qmlComponent->isLoading())
|
||||
connect(_qmlComponent, &QQmlComponent::statusChanged, this, &OffscreenUi::finishQmlLoad);
|
||||
else
|
||||
finishQmlLoad();
|
||||
}
|
||||
|
||||
void OffscreenUi::requestUpdate() {
|
||||
_polish = true;
|
||||
if (!_updateTimer.isActive())
|
||||
_updateTimer.start();
|
||||
}
|
||||
|
||||
void OffscreenUi::requestRender() {
|
||||
if (!_updateTimer.isActive())
|
||||
_updateTimer.start();
|
||||
}
|
||||
|
||||
void OffscreenUi::finishQmlLoad() {
|
||||
disconnect(_qmlComponent, &QQmlComponent::statusChanged, this, &OffscreenUi::finishQmlLoad);
|
||||
if (_qmlComponent->isError()) {
|
||||
QList<QQmlError> errorList = _qmlComponent->errors();
|
||||
foreach(const QQmlError &error, errorList) {
|
||||
qWarning() << error.url() << error.line() << error;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
QObject *rootObject = _qmlComponent->create();
|
||||
if (_qmlComponent->isError()) {
|
||||
QList<QQmlError> errorList = _qmlComponent->errors();
|
||||
foreach(const QQmlError &error, errorList)
|
||||
qWarning() << error.url() << error.line() << error;
|
||||
qFatal("Unable to finish loading QML");
|
||||
return;
|
||||
}
|
||||
|
||||
_rootItem = qobject_cast<QQuickItem *>(rootObject);
|
||||
if (!_rootItem) {
|
||||
qWarning("run: Not a QQuickItem");
|
||||
delete rootObject;
|
||||
qFatal("Unable to find root QQuickItem");
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure we can assign focus to the root item (critical for
|
||||
// supporting keyboard shortcuts)
|
||||
_rootItem->setFlag(QQuickItem::ItemIsFocusScope, true);
|
||||
// The root item is ready. Associate it with the window.
|
||||
_rootItem->setParentItem(_quickWindow->contentItem());
|
||||
_rootItem->setSize(_quickWindow->renderTargetSize());
|
||||
qDebug() << "Finished setting up QML provider";
|
||||
}
|
||||
|
||||
|
||||
void OffscreenUi::updateQuick() {
|
||||
if (_paused) {
|
||||
return;
|
||||
}
|
||||
if (!makeCurrent())
|
||||
return;
|
||||
|
||||
// Polish, synchronize and render the next frame (into our fbo). In this example
|
||||
// everything happens on the same thread and therefore all three steps are performed
|
||||
// in succession from here. In a threaded setup the render() call would happen on a
|
||||
// separate thread.
|
||||
if (_polish) {
|
||||
_renderControl->polishItems();
|
||||
_renderControl->sync();
|
||||
_polish = false;
|
||||
}
|
||||
|
||||
QOpenGLFramebufferObject* fbo = _fboCache.getReadyFbo();
|
||||
|
||||
_quickWindow->setRenderTarget(fbo);
|
||||
fbo->bind();
|
||||
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
_renderControl->render();
|
||||
|
||||
Q_ASSERT(!glGetError());
|
||||
|
||||
_quickWindow->resetOpenGLState();
|
||||
|
||||
QOpenGLFramebufferObject::bindDefault();
|
||||
// Force completion of all the operations before we emit the texture as being ready for use
|
||||
glFinish();
|
||||
|
||||
emit textureUpdated(fbo->texture());
|
||||
}
|
||||
|
||||
QPointF OffscreenUi::mapWindowToUi(const QPointF & p, QObject * dest) {
|
||||
vec2 sourceSize;
|
||||
if (dynamic_cast<QWidget*>(dest)) {
|
||||
sourceSize = toGlm(((QWidget*)dest)->size());
|
||||
} else if (dynamic_cast<QWindow*>(dest)) {
|
||||
sourceSize = toGlm(((QWindow*)dest)->size());
|
||||
}
|
||||
vec2 pos = toGlm(p);
|
||||
pos /= sourceSize;
|
||||
pos *= vec2(toGlm(_quickWindow->renderTargetSize()));
|
||||
return QPointF(pos.x, pos.y);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
//
|
||||
// Event handling customization
|
||||
//
|
||||
|
||||
bool OffscreenUi::eventFilter(QObject * dest, QEvent * e) {
|
||||
// Only intercept events while we're in an active state
|
||||
if (_paused) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't intercept our own events, or we enter an infinite recursion
|
||||
if (dest == _quickWindow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (e->type()) {
|
||||
case QEvent::Resize:
|
||||
{
|
||||
QResizeEvent * re = (QResizeEvent *)e;
|
||||
QGLWidget * widget = dynamic_cast<QGLWidget*>(dest);
|
||||
if (widget) {
|
||||
this->resize(re->size());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
case QEvent::KeyPress:
|
||||
case QEvent::KeyRelease:
|
||||
{
|
||||
e->ignore();
|
||||
if (QApplication::sendEvent(_quickWindow, e)) {
|
||||
return e->isAccepted();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case QEvent::Wheel:
|
||||
{
|
||||
QWheelEvent * we = (QWheelEvent*)e;
|
||||
QWheelEvent mappedEvent(mapWindowToUi(we->pos(), dest), we->delta(), we->buttons(), we->modifiers(), we->orientation());
|
||||
QCoreApplication::sendEvent(_quickWindow, &mappedEvent);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
// Fall through
|
||||
case QEvent::MouseButtonDblClick:
|
||||
case QEvent::MouseButtonPress:
|
||||
case QEvent::MouseButtonRelease:
|
||||
case QEvent::MouseMove:
|
||||
{
|
||||
QMouseEvent * me = (QMouseEvent *)e;
|
||||
QPointF originalPos = me->localPos();
|
||||
QPointF transformedPos = _mouseTranslator(originalPos);
|
||||
QMouseEvent mappedEvent(e->type(), mapWindowToUi(transformedPos, dest), me->screenPos(), me->button(), me->buttons(), me->modifiers());
|
||||
QCoreApplication::sendEvent(_quickWindow, &mappedEvent);
|
||||
return QObject::event(e);
|
||||
}
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void OffscreenUi::lockTexture(int texture) {
|
||||
_fboCache.lockTexture(texture);
|
||||
}
|
||||
|
||||
void OffscreenUi::releaseTexture(int texture) {
|
||||
_fboCache.releaseTexture(texture);
|
||||
}
|
||||
|
||||
void OffscreenUi::pause() {
|
||||
_paused = true;
|
||||
}
|
||||
|
||||
void OffscreenUi::resume() {
|
||||
_paused = false;
|
||||
requestRender();
|
||||
}
|
||||
|
||||
bool OffscreenUi::isPaused() const {
|
||||
return _paused;
|
||||
}
|
||||
|
||||
void OffscreenUi::setProxyWindow(QWindow * window) {
|
||||
_renderControl->_renderWindow = window;
|
||||
}
|
||||
|
||||
void OffscreenUi::show(const QUrl & url, const QString & name) {
|
||||
QQuickItem * item = _rootItem->findChild<QQuickItem*>(name);
|
||||
if (nullptr != item) {
|
||||
item->setEnabled(true);
|
||||
item->setVisible(true);
|
||||
} else {
|
||||
load(url);
|
||||
}
|
||||
}
|
||||
|
||||
void OffscreenUi::toggle(const QUrl & url, const QString & name) {
|
||||
QQuickItem * item = _rootItem->findChild<QQuickItem*>(name);
|
||||
// First load?
|
||||
if (nullptr == item) {
|
||||
load(url);
|
||||
return;
|
||||
}
|
||||
|
||||
// Toggle the visibity AND the enabled flag (otherwise invisible
|
||||
// dialogs can still swallow keyboard input)
|
||||
bool newFlag = !item->isVisible();
|
||||
item->setVisible(newFlag);
|
||||
item->setEnabled(newFlag);
|
||||
}
|
||||
|
||||
|
||||
void OffscreenUi::load(const QUrl & url) {
|
||||
QVariant returnedValue;
|
||||
QVariant msg = url;
|
||||
QMetaObject::invokeMethod(_rootItem, "loadChild",
|
||||
Q_RETURN_ARG(QVariant, returnedValue),
|
||||
Q_ARG(QVariant, msg));
|
||||
qDebug() << "QML function returned:" << returnedValue.toString();
|
||||
}
|
||||
|
136
libraries/render-utils/src/OffscreenUi.h
Normal file
136
libraries/render-utils/src/OffscreenUi.h
Normal file
|
@ -0,0 +1,136 @@
|
|||
//
|
||||
// OffscreenUi.h
|
||||
// interface/src/entities
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2015-04-04
|
||||
// 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
|
||||
//
|
||||
#pragma once
|
||||
#ifndef hifi_OffscreenUi_h
|
||||
#define hifi_OffscreenUi_h
|
||||
|
||||
|
||||
#include <QOpenGLContext>
|
||||
#include <QOffscreenSurface>
|
||||
#include <QQmlEngine>
|
||||
#include <QQmlComponent>
|
||||
#include <QQuickItem>
|
||||
#include <QQuickWindow>
|
||||
#include <QQuickRenderControl>
|
||||
#include <QQuickImageProvider>
|
||||
#include <GLMHelpers.h>
|
||||
#include <ThreadHelpers.h>
|
||||
#include <QQueue>
|
||||
#include <QTimer>
|
||||
#include <QApplication>
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <DependencyManager.h>
|
||||
|
||||
#include "FboCache.h"
|
||||
#include "OffscreenGlCanvas.h"
|
||||
|
||||
#define QML_DIALOG_DECL \
|
||||
private: \
|
||||
static const QString NAME; \
|
||||
static const QUrl QML; \
|
||||
public: \
|
||||
static void registerType(); \
|
||||
static void show(); \
|
||||
static void toggle(); \
|
||||
private:
|
||||
|
||||
#define QML_DIALOG_DEF(x) \
|
||||
const QUrl x::QML = #x ".qml"; \
|
||||
const QString x::NAME = #x; \
|
||||
\
|
||||
void x::registerType() { \
|
||||
qmlRegisterType<x>("Hifi", 1, 0, NAME.toLocal8Bit().constData()); \
|
||||
} \
|
||||
\
|
||||
void x::show() { \
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>(); \
|
||||
offscreenUi->show(QML, NAME); \
|
||||
} \
|
||||
\
|
||||
void x::toggle() { \
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>(); \
|
||||
offscreenUi->toggle(QML, NAME); \
|
||||
}
|
||||
|
||||
|
||||
class OffscreenUi : public OffscreenGlCanvas, public Dependency {
|
||||
Q_OBJECT
|
||||
|
||||
class QMyQuickRenderControl : public QQuickRenderControl {
|
||||
protected:
|
||||
QWindow * renderWindow(QPoint * offset) Q_DECL_OVERRIDE{
|
||||
if (nullptr == _renderWindow) {
|
||||
return QQuickRenderControl::renderWindow(offset);
|
||||
}
|
||||
if (nullptr != offset) {
|
||||
offset->rx() = offset->ry() = 0;
|
||||
}
|
||||
return _renderWindow;
|
||||
}
|
||||
|
||||
private:
|
||||
QWindow * _renderWindow{ nullptr };
|
||||
friend class OffscreenUi;
|
||||
};
|
||||
|
||||
public:
|
||||
using MouseTranslator = std::function < QPointF(const QPointF &) > ;
|
||||
OffscreenUi();
|
||||
virtual ~OffscreenUi();
|
||||
void create(QOpenGLContext * context);
|
||||
void resize(const QSize & size);
|
||||
void loadQml(const QUrl & qmlSource, std::function<void(QQmlContext*)> f = [](QQmlContext*) {});
|
||||
void load(const QUrl & url);
|
||||
void show(const QUrl & url, const QString & name);
|
||||
void toggle(const QUrl & url, const QString & name);
|
||||
|
||||
QQmlContext * qmlContext();
|
||||
|
||||
void pause();
|
||||
void resume();
|
||||
bool isPaused() const;
|
||||
void setProxyWindow(QWindow * window);
|
||||
QPointF mapWindowToUi(const QPointF & p, QObject * dest);
|
||||
virtual bool eventFilter(QObject * dest, QEvent * e);
|
||||
void setMouseTranslator(MouseTranslator mt) {
|
||||
_mouseTranslator = mt;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
private slots:
|
||||
void updateQuick();
|
||||
void finishQmlLoad();
|
||||
|
||||
public slots:
|
||||
void requestUpdate();
|
||||
void requestRender();
|
||||
void lockTexture(int texture);
|
||||
void releaseTexture(int texture);
|
||||
|
||||
signals:
|
||||
void textureUpdated(GLuint texture);
|
||||
|
||||
private:
|
||||
QMyQuickRenderControl *_renderControl{ new QMyQuickRenderControl };
|
||||
QQuickWindow *_quickWindow{ nullptr };
|
||||
QQmlEngine *_qmlEngine{ nullptr };
|
||||
QQmlComponent *_qmlComponent{ nullptr };
|
||||
QQuickItem * _rootItem{ nullptr };
|
||||
QTimer _updateTimer;
|
||||
FboCache _fboCache;
|
||||
bool _polish{ true };
|
||||
bool _paused{ true };
|
||||
MouseTranslator _mouseTranslator{ [](const QPointF & p) { return p; } };
|
||||
};
|
||||
|
||||
#endif
|
|
@ -15,4 +15,54 @@
|
|||
/// Renders a quad from (-1, -1, 0) to (1, 1, 0) with texture coordinates from (sMin, tMin) to (sMax, tMax).
|
||||
void renderFullscreenQuad(float sMin = 0.0f, float sMax = 1.0f, float tMin = 0.0f, float tMax = 1.0f);
|
||||
|
||||
template <typename F, GLenum matrix>
|
||||
void withMatrixPush(F f) {
|
||||
glMatrixMode(matrix);
|
||||
glPushMatrix();
|
||||
f();
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void withProjectionPush(F f) {
|
||||
withMatrixPush<GL_PROJECTION>(f);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void withProjectionIdentity(F f) {
|
||||
withProjectionPush([&] {
|
||||
glLoadIdentity();
|
||||
f();
|
||||
});
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void withProjectionMatrix(GLfloat * matrix, F f) {
|
||||
withProjectionPush([&] {
|
||||
glLoadMatrixf(matrix);
|
||||
f();
|
||||
});
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void withModelviewPush(F f) {
|
||||
withMatrixPush<GL_MODELVIEW>(f);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void withModelviewIdentity(F f) {
|
||||
withModelviewPush([&] {
|
||||
glLoadIdentity();
|
||||
f();
|
||||
});
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void withModelviewMatrix(GLfloat * matrix, F f) {
|
||||
withModelviewPush([&] {
|
||||
glLoadMatrixf(matrix);
|
||||
f();
|
||||
});
|
||||
}
|
||||
|
||||
#endif // hifi_RenderUtil_h
|
||||
|
|
|
@ -17,6 +17,17 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
// Bring the most commonly used GLM types into the default namespace
|
||||
using glm::ivec3;
|
||||
using glm::ivec2;
|
||||
using glm::uvec2;
|
||||
using glm::mat3;
|
||||
using glm::mat4;
|
||||
using glm::vec2;
|
||||
using glm::vec3;
|
||||
using glm::vec4;
|
||||
using glm::quat;
|
||||
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtGui/QMatrix4x4>
|
||||
#include <QtGui/QColor>
|
||||
|
|
13
libraries/shared/src/ThreadHelpers.h
Normal file
13
libraries/shared/src/ThreadHelpers.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
#include <exception>
|
||||
|
||||
template <typename L, typename F>
|
||||
void withLock(L lock, F function) {
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void withLock(QMutex & lock, F function) {
|
||||
QMutexLocker locker(&lock);
|
||||
function();
|
||||
}
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "TextRenderer.h"
|
||||
#include "MatrixStack.h"
|
||||
#include "OffscreenUi.h"
|
||||
|
||||
#include <QWindow>
|
||||
#include <QFile>
|
||||
|
@ -21,9 +22,11 @@
|
|||
#include <QOpenGLBuffer>
|
||||
#include <QOpenGLShaderProgram>
|
||||
#include <QResizeEvent>
|
||||
#include <QLoggingCategory>
|
||||
#include <QOpenGLTexture>
|
||||
#include <QOpenGLVertexArrayObject>
|
||||
#include <QApplication>
|
||||
#include <QOpenGLDebugLogger>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <glm/glm.hpp>
|
||||
|
@ -66,99 +69,143 @@ public:
|
|||
};
|
||||
|
||||
// Create a simple OpenGL window that renders text in various ways
|
||||
class QTestWindow: public QWindow {
|
||||
class QTestWindow : public QWindow {
|
||||
Q_OBJECT
|
||||
QOpenGLContext * _context;
|
||||
|
||||
QOpenGLContext * _context{ nullptr };
|
||||
QSize _size;
|
||||
TextRenderer* _textRenderer[4];
|
||||
RateCounter fps;
|
||||
OffscreenUi _offscreenUi;
|
||||
int testQmlTexture{ 0 };
|
||||
//ProgramPtr _planeProgam;
|
||||
//ShapeWrapperPtr _planeShape;
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent * ev) override {
|
||||
QWindow::resizeEvent(ev);
|
||||
_size = ev->size();
|
||||
resizeGl();
|
||||
}
|
||||
|
||||
void resizeGl() {
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, _size.width(), _size.height(), 0, 1, -1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glViewport(0, 0, _size.width(), _size.height());
|
||||
void renderText();
|
||||
void renderQml();
|
||||
|
||||
private:
|
||||
void resizeWindow(const QSize & size) {
|
||||
_size = size;
|
||||
_offscreenUi.resize(_size);
|
||||
}
|
||||
|
||||
public:
|
||||
QTestWindow();
|
||||
virtual ~QTestWindow() {
|
||||
QTestWindow() {
|
||||
setSurfaceType(QSurface::OpenGLSurface);
|
||||
|
||||
QSurfaceFormat format;
|
||||
// Qt Quick may need a depth and stencil buffer. Always make sure these are available.
|
||||
format.setDepthBufferSize(16);
|
||||
format.setStencilBufferSize(8);
|
||||
format.setVersion(4, 5);
|
||||
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile);
|
||||
format.setOption(QSurfaceFormat::DebugContext);
|
||||
|
||||
setFormat(format);
|
||||
|
||||
_context = new QOpenGLContext;
|
||||
_context->setFormat(format);
|
||||
_context->create();
|
||||
|
||||
show();
|
||||
makeCurrent();
|
||||
|
||||
{
|
||||
QOpenGLDebugLogger *logger = new QOpenGLDebugLogger(this);
|
||||
logger->initialize(); // initializes in the current context, i.e. ctx
|
||||
logger->enableMessages();
|
||||
connect(logger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage & debugMessage) {
|
||||
qDebug() << debugMessage;
|
||||
});
|
||||
// logger->startLogging(QOpenGLDebugLogger::SynchronousLogging);
|
||||
}
|
||||
qDebug() << (const char*)glGetString(GL_VERSION);
|
||||
|
||||
#ifdef WIN32
|
||||
glewExperimental = true;
|
||||
GLenum err = glewInit();
|
||||
if (GLEW_OK != err) {
|
||||
/* Problem: glewInit failed, something is seriously wrong. */
|
||||
const GLubyte * errStr = glewGetErrorString(err);
|
||||
qDebug("Error: %s\n", errStr);
|
||||
}
|
||||
qDebug("Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
|
||||
|
||||
if (wglewGetExtension("WGL_EXT_swap_control")) {
|
||||
int swapInterval = wglGetSwapIntervalEXT();
|
||||
qDebug("V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF"));
|
||||
}
|
||||
glGetError();
|
||||
#endif
|
||||
|
||||
_textRenderer[0] = TextRenderer::getInstance(SANS_FONT_FAMILY, 12, false);
|
||||
_textRenderer[1] = TextRenderer::getInstance(SERIF_FONT_FAMILY, 12, false,
|
||||
TextRenderer::SHADOW_EFFECT);
|
||||
_textRenderer[2] = TextRenderer::getInstance(MONO_FONT_FAMILY, 48, -1,
|
||||
false, TextRenderer::OUTLINE_EFFECT);
|
||||
_textRenderer[3] = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, 24);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glClearColor(0.2f, 0.2f, 0.2f, 1);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
_offscreenUi.create(_context);
|
||||
// FIXME, need to switch to a QWindow for mouse and keyboard input to work
|
||||
_offscreenUi.setProxyWindow(this);
|
||||
// "#0e7077"
|
||||
setFramePosition(QPoint(-1000, 0));
|
||||
resize(QSize(800, 600));
|
||||
|
||||
static const QString f("/Users/bdavis/Git/hifi/interface/resources/qml/Root.qml");
|
||||
_offscreenUi.loadQml(QUrl::fromLocalFile(f));
|
||||
connect(&_offscreenUi, &OffscreenUi::textureUpdated, this, [&](int textureId) {
|
||||
_offscreenUi.lockTexture(textureId);
|
||||
assert(!glGetError());
|
||||
GLuint oldTexture = testQmlTexture;
|
||||
testQmlTexture = textureId;
|
||||
if (oldTexture) {
|
||||
_offscreenUi.releaseTexture(oldTexture);
|
||||
}
|
||||
});
|
||||
installEventFilter(&_offscreenUi);
|
||||
_offscreenUi.resume();
|
||||
}
|
||||
|
||||
virtual ~QTestWindow() {
|
||||
}
|
||||
|
||||
void draw();
|
||||
void makeCurrent() {
|
||||
_context->makeCurrent(this);
|
||||
}
|
||||
|
||||
void draw();
|
||||
protected:
|
||||
|
||||
void resizeEvent(QResizeEvent * ev) override {
|
||||
resizeWindow(ev->size());
|
||||
}
|
||||
|
||||
|
||||
void keyPressEvent(QKeyEvent *event) {
|
||||
switch (event->key()) {
|
||||
case Qt::Key_Slash:
|
||||
qDebug() << "Foo";
|
||||
_offscreenUi.load(QString("Login.qml"));
|
||||
break;
|
||||
}
|
||||
QWindow::keyPressEvent(event);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#ifndef SERIF_FONT_FAMILY
|
||||
#define SERIF_FONT_FAMILY "Times New Roman"
|
||||
#endif
|
||||
|
||||
QTestWindow::QTestWindow() {
|
||||
setSurfaceType(QSurface::OpenGLSurface);
|
||||
|
||||
QSurfaceFormat format;
|
||||
// Qt Quick may need a depth and stencil buffer. Always make sure these are available.
|
||||
format.setDepthBufferSize(16);
|
||||
format.setStencilBufferSize(8);
|
||||
format.setVersion(3, 2);
|
||||
format.setProfile(
|
||||
QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile);
|
||||
setFormat(format);
|
||||
|
||||
_context = new QOpenGLContext;
|
||||
_context->setFormat(format);
|
||||
_context->create();
|
||||
|
||||
show();
|
||||
makeCurrent();
|
||||
qDebug() << (const char*) glGetString(GL_VERSION);
|
||||
|
||||
#ifdef WIN32
|
||||
glewExperimental = true;
|
||||
GLenum err = glewInit();
|
||||
if (GLEW_OK != err) {
|
||||
/* Problem: glewInit failed, something is seriously wrong. */
|
||||
const GLubyte * errStr = glewGetErrorString(err);
|
||||
qDebug("Error: %s\n", errStr);
|
||||
}
|
||||
qDebug("Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
|
||||
|
||||
if (wglewGetExtension("WGL_EXT_swap_control")) {
|
||||
int swapInterval = wglGetSwapIntervalEXT();
|
||||
qDebug("V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF"));
|
||||
}
|
||||
glGetError();
|
||||
#endif
|
||||
|
||||
setFramePosition(QPoint(100, -900));
|
||||
resize(QSize(800, 600));
|
||||
_size = QSize(800, 600);
|
||||
|
||||
_textRenderer[0] = TextRenderer::getInstance(SANS_FONT_FAMILY, 12, false);
|
||||
_textRenderer[1] = TextRenderer::getInstance(SERIF_FONT_FAMILY, 12, false,
|
||||
TextRenderer::SHADOW_EFFECT);
|
||||
_textRenderer[2] = TextRenderer::getInstance(MONO_FONT_FAMILY, 48, -1,
|
||||
false, TextRenderer::OUTLINE_EFFECT);
|
||||
_textRenderer[3] = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, 24);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glClearColor(0.2f, 0.2f, 0.2f, 1);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
resizeGl();
|
||||
}
|
||||
|
||||
static const wchar_t * EXAMPLE_TEXT = L"Hello";
|
||||
//static const wchar_t * EXAMPLE_TEXT = L"\xC1y Hello 1.0\ny\xC1 line 2\n\xC1y";
|
||||
static const glm::uvec2 QUAD_OFFSET(10, 10);
|
||||
|
@ -166,14 +213,21 @@ static const glm::uvec2 QUAD_OFFSET(10, 10);
|
|||
static const glm::vec3 COLORS[4] = { { 1.0, 1.0, 1.0 }, { 0.5, 1.0, 0.5 }, {
|
||||
1.0, 0.5, 0.5 }, { 0.5, 0.5, 1.0 } };
|
||||
|
||||
void QTestWindow::draw() {
|
||||
makeCurrent();
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
void QTestWindow::renderText() {
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, _size.width(), _size.height(), 0, 1, -1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
const glm::uvec2 size = glm::uvec2(_size.width() / 2, _size.height() / 2);
|
||||
const glm::uvec2 offsets[4] = { { QUAD_OFFSET.x, QUAD_OFFSET.y }, { size.x
|
||||
+ QUAD_OFFSET.x, QUAD_OFFSET.y }, { size.x + QUAD_OFFSET.x, size.y
|
||||
+ QUAD_OFFSET.y }, { QUAD_OFFSET.x, size.y + QUAD_OFFSET.y }, };
|
||||
|
||||
const glm::uvec2 offsets[4] = {
|
||||
{ QUAD_OFFSET.x, QUAD_OFFSET.y },
|
||||
{ size.x + QUAD_OFFSET.x, QUAD_OFFSET.y },
|
||||
{ size.x + QUAD_OFFSET.x, size.y + QUAD_OFFSET.y },
|
||||
{ QUAD_OFFSET.x, size.y + QUAD_OFFSET.y },
|
||||
};
|
||||
|
||||
QString str = QString::fromWCharArray(EXAMPLE_TEXT);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
|
@ -200,17 +254,57 @@ void QTestWindow::draw() {
|
|||
glm::vec4(COLORS[i], 1.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QTestWindow::renderQml() {
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
if (testQmlTexture > 0) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, testQmlTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
glBegin(GL_QUADS);
|
||||
{
|
||||
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex2f(-1, -1);
|
||||
glTexCoord2f(0, 1);
|
||||
glVertex2f(-1, 1);
|
||||
glTexCoord2f(1, 1);
|
||||
glVertex2f(1, 1);
|
||||
glTexCoord2f(1, 0);
|
||||
glVertex2f(1, -1);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void QTestWindow::draw() {
|
||||
makeCurrent();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glViewport(0, 0, _size.width(), _size.height());
|
||||
|
||||
renderText();
|
||||
//renderQml();
|
||||
|
||||
_context->swapBuffers(this);
|
||||
glFinish();
|
||||
|
||||
fps.increment();
|
||||
if (fps.elapsed() >= 2.0f) {
|
||||
qDebug() << "FPS: " << fps.rate();
|
||||
//qDebug() << "FPS: " << fps.rate();
|
||||
fps.reset();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
QApplication app(argc, argv);
|
||||
//QLoggingCategory::setFilterRules("qt.quick.mouse.debug = true");
|
||||
QTestWindow window;
|
||||
QTimer timer;
|
||||
timer.setInterval(1);
|
||||
|
|
Loading…
Reference in a new issue