mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-06-06 12:51:50 +02:00
Merge branch 'vr_menus' into infoview
Conflicts: tests/ui/src/main.cpp
This commit is contained in:
commit
9836ffed97
36 changed files with 429 additions and 1267 deletions
10
BUILD.md
10
BUILD.md
|
@ -1,7 +1,7 @@
|
||||||
###Dependencies
|
###Dependencies
|
||||||
|
|
||||||
* [cmake](http://www.cmake.org/cmake/resources/software.html) ~> 2.8.12.2
|
* [cmake](http://www.cmake.org/cmake/resources/software.html) ~> 2.8.12.2
|
||||||
* [Qt](http://qt-project.org/downloads) ~> 5.3.2
|
* [Qt](http://www.qt.io/download-open-source) ~> 5.4.1
|
||||||
* [OpenSSL](https://www.openssl.org/related/binaries.html) ~> 1.0.1g
|
* [OpenSSL](https://www.openssl.org/related/binaries.html) ~> 1.0.1g
|
||||||
* IMPORTANT: OpenSSL 1.0.1g is critical to avoid a security vulnerability.
|
* IMPORTANT: OpenSSL 1.0.1g is critical to avoid a security vulnerability.
|
||||||
* [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional)
|
* [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional)
|
||||||
|
@ -37,12 +37,12 @@ Hifi uses CMake to generate build files and project files for your platform.
|
||||||
####Qt
|
####Qt
|
||||||
In order for CMake to find the Qt5 find modules, you will need to set an ENV variable pointing to your Qt installation.
|
In order for CMake to find the Qt5 find modules, you will need to set an ENV variable pointing to your Qt installation.
|
||||||
|
|
||||||
For example, a Qt5 5.3.2 installation to /usr/local/qt5 would require that QT_CMAKE_PREFIX_PATH be set with the following command. This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment).
|
For example, a Qt5 5.4.1 installation to /usr/local/qt5 would require that QT_CMAKE_PREFIX_PATH be set with the following command. This can either be entered directly into your shell session before you build or in your shell profile (e.g.: ~/.bash_profile, ~/.bashrc, ~/.zshrc - this depends on your shell and environment).
|
||||||
|
|
||||||
The path it needs to be set to will depend on where and how Qt5 was installed. e.g.
|
The path it needs to be set to will depend on where and how Qt5 was installed. e.g.
|
||||||
|
|
||||||
export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.3.2/clang_64/lib/cmake/
|
export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.4.1/clang_64/lib/cmake/
|
||||||
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.3.2/lib/cmake
|
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.4.1/lib/cmake
|
||||||
export QT_CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake
|
export QT_CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake
|
||||||
|
|
||||||
####Generating build files
|
####Generating build files
|
||||||
|
@ -57,7 +57,7 @@ Any variables that need to be set for CMake to find dependencies can be set as E
|
||||||
|
|
||||||
For example, to pass the QT_CMAKE_PREFIX_PATH variable during build file generation:
|
For example, to pass the QT_CMAKE_PREFIX_PATH variable during build file generation:
|
||||||
|
|
||||||
cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.3.2/lib/cmake
|
cmake .. -DQT_CMAKE_PREFIX_PATH=/usr/local/qt/5.4.1/lib/cmake
|
||||||
|
|
||||||
####Finding Dependencies
|
####Finding Dependencies
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ Please read the [general build guide](BUILD.md) for information on dependencies
|
||||||
|
|
||||||
We have a [homebrew formulas repository](https://github.com/highfidelity/homebrew-formulas) that you can use/tap to install some of the dependencies. In the code block above qt5 is installed from a formula in this repository.
|
We have a [homebrew formulas repository](https://github.com/highfidelity/homebrew-formulas) that you can use/tap to install some of the dependencies. In the code block above qt5 is installed from a formula in this repository.
|
||||||
|
|
||||||
*Our [qt5 homebrew formula](https://raw.github.com/highfidelity/homebrew-formulas/master/qt5.rb) is for a patched version of Qt 5.3.x stable that removes wireless network scanning that can reduce real-time audio performance. We recommended you use this formula to install Qt.*
|
*Our [qt5 homebrew formula](https://raw.github.com/highfidelity/homebrew-formulas/master/qt5.rb) is for a patched version of Qt 5.4.x stable that removes wireless network scanning that can reduce real-time audio performance. We recommended you use this formula to install Qt.*
|
||||||
|
|
||||||
###Xcode
|
###Xcode
|
||||||
If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles.
|
If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles.
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -325,7 +325,6 @@ Dialog {
|
||||||
|
|
||||||
case Qt.Key_Enter:
|
case Qt.Key_Enter:
|
||||||
case Qt.Key_Return:
|
case Qt.Key_Return:
|
||||||
console.log("Accepting");
|
|
||||||
event.accepted = true
|
event.accepted = true
|
||||||
content.accept()
|
content.accept()
|
||||||
break
|
break
|
||||||
|
|
115
interface/resources/qml/TestMenu.qml
Normal file
115
interface/resources/qml/TestMenu.qml
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
import QtQuick 2.4
|
||||||
|
import QtQuick.Controls 1.3
|
||||||
|
import Hifi 1.0
|
||||||
|
|
||||||
|
// Currently for testing a pure QML replacement menu
|
||||||
|
Item {
|
||||||
|
Item {
|
||||||
|
objectName: "AllActions"
|
||||||
|
Action {
|
||||||
|
id: aboutApp
|
||||||
|
objectName: "HifiAction_" + MenuConstants.AboutApp
|
||||||
|
text: qsTr("About Interface")
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// File Menu
|
||||||
|
//
|
||||||
|
Action {
|
||||||
|
id: login
|
||||||
|
objectName: "HifiAction_" + MenuConstants.Login
|
||||||
|
text: qsTr("Login")
|
||||||
|
}
|
||||||
|
Action {
|
||||||
|
id: quit
|
||||||
|
objectName: "HifiAction_" + MenuConstants.Quit
|
||||||
|
text: qsTr("Quit")
|
||||||
|
//shortcut: StandardKey.Quit
|
||||||
|
shortcut: "Ctrl+Q"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Edit menu
|
||||||
|
//
|
||||||
|
Action {
|
||||||
|
id: undo
|
||||||
|
text: "Undo"
|
||||||
|
shortcut: StandardKey.Undo
|
||||||
|
}
|
||||||
|
|
||||||
|
Action {
|
||||||
|
id: redo
|
||||||
|
text: "Redo"
|
||||||
|
shortcut: StandardKey.Redo
|
||||||
|
}
|
||||||
|
|
||||||
|
Action {
|
||||||
|
id: animations
|
||||||
|
objectName: "HifiAction_" + MenuConstants.Animations
|
||||||
|
text: qsTr("Animations...")
|
||||||
|
}
|
||||||
|
Action {
|
||||||
|
id: attachments
|
||||||
|
text: qsTr("Attachments...")
|
||||||
|
}
|
||||||
|
Action {
|
||||||
|
id: explode
|
||||||
|
text: qsTr("Explode on quit")
|
||||||
|
checkable: true
|
||||||
|
checked: true
|
||||||
|
}
|
||||||
|
Action {
|
||||||
|
id: freeze
|
||||||
|
text: qsTr("Freeze on quit")
|
||||||
|
checkable: true
|
||||||
|
checked: false
|
||||||
|
}
|
||||||
|
ExclusiveGroup {
|
||||||
|
Action {
|
||||||
|
id: visibleToEveryone
|
||||||
|
objectName: "HifiAction_" + MenuConstants.VisibleToEveryone
|
||||||
|
text: qsTr("Everyone")
|
||||||
|
checkable: true
|
||||||
|
checked: true
|
||||||
|
}
|
||||||
|
Action {
|
||||||
|
id: visibleToFriends
|
||||||
|
objectName: "HifiAction_" + MenuConstants.VisibleToFriends
|
||||||
|
text: qsTr("Friends")
|
||||||
|
checkable: true
|
||||||
|
}
|
||||||
|
Action {
|
||||||
|
id: visibleToNoOne
|
||||||
|
objectName: "HifiAction_" + MenuConstants.VisibleToNoOne
|
||||||
|
text: qsTr("No one")
|
||||||
|
checkable: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Menu {
|
||||||
|
objectName: "rootMenu";
|
||||||
|
Menu {
|
||||||
|
title: "File"
|
||||||
|
MenuItem { action: login }
|
||||||
|
MenuItem { action: explode }
|
||||||
|
MenuItem { action: freeze }
|
||||||
|
MenuItem { action: quit }
|
||||||
|
}
|
||||||
|
Menu {
|
||||||
|
title: "Tools"
|
||||||
|
Menu {
|
||||||
|
title: "I Am Visible To"
|
||||||
|
MenuItem { action: visibleToEveryone }
|
||||||
|
MenuItem { action: visibleToFriends }
|
||||||
|
MenuItem { action: visibleToNoOne }
|
||||||
|
}
|
||||||
|
MenuItem { action: animations }
|
||||||
|
}
|
||||||
|
Menu {
|
||||||
|
title: "Help"
|
||||||
|
MenuItem { action: aboutApp }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -128,13 +128,16 @@ Hifi.VrMenu {
|
||||||
// visible: source.visible
|
// visible: source.visible
|
||||||
Row {
|
Row {
|
||||||
id: row
|
id: row
|
||||||
spacing: 4
|
spacing: 2
|
||||||
anchors {
|
anchors {
|
||||||
top: parent.top
|
top: parent.top
|
||||||
topMargin: 2
|
topMargin: 2
|
||||||
}
|
}
|
||||||
|
Spacer { size: 4 }
|
||||||
FontAwesome {
|
FontAwesome {
|
||||||
id: check
|
id: check
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
y: 2
|
||||||
size: label.height
|
size: label.height
|
||||||
text: checkText()
|
text: checkText()
|
||||||
color: label.color
|
color: label.color
|
||||||
|
@ -191,6 +194,7 @@ Hifi.VrMenu {
|
||||||
bottom: parent.bottom
|
bottom: parent.bottom
|
||||||
left: parent.left
|
left: parent.left
|
||||||
right: tag.right
|
right: tag.right
|
||||||
|
rightMargin: -4
|
||||||
}
|
}
|
||||||
acceptedButtons: Qt.LeftButton
|
acceptedButtons: Qt.LeftButton
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
@ -263,7 +267,6 @@ Hifi.VrMenu {
|
||||||
function popColumn() {
|
function popColumn() {
|
||||||
if (columns.length > 0) {
|
if (columns.length > 0) {
|
||||||
var curColumn = columns.pop();
|
var curColumn = columns.pop();
|
||||||
console.log(curColumn);
|
|
||||||
curColumn.visible = false;
|
curColumn.visible = false;
|
||||||
curColumn.destroy();
|
curColumn.destroy();
|
||||||
models.pop();
|
models.pop();
|
||||||
|
|
|
@ -92,6 +92,7 @@ DialogBase {
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
width: 16
|
width: 16
|
||||||
height: 16
|
height: 16
|
||||||
|
z: 1000
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
onPressed: {
|
onPressed: {
|
||||||
startX = mouseX
|
startX = mouseX
|
||||||
|
@ -143,4 +144,15 @@ DialogBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Keys.onPressed: {
|
||||||
|
switch(event.key) {
|
||||||
|
case Qt.Key_W:
|
||||||
|
if (event.modifiers == Qt.ControlModifier) {
|
||||||
|
event.accepted = true
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,11 +22,13 @@ Item {
|
||||||
readonly property alias titleWidth: titleBorder.width
|
readonly property alias titleWidth: titleBorder.width
|
||||||
readonly property alias titleHeight: titleBorder.height
|
readonly property alias titleHeight: titleBorder.height
|
||||||
|
|
||||||
|
// readonly property real borderWidth: hifi.styles.borderWidth
|
||||||
|
readonly property real borderWidth: 0
|
||||||
property alias clientBorder: clientBorder
|
property alias clientBorder: clientBorder
|
||||||
readonly property real clientX: clientBorder.x + hifi.styles.borderWidth
|
readonly property real clientX: clientBorder.x + borderWidth
|
||||||
readonly property real clientY: clientBorder.y + hifi.styles.borderWidth
|
readonly property real clientY: clientBorder.y + borderWidth
|
||||||
readonly property real clientWidth: clientBorder.width - hifi.styles.borderWidth * 2
|
readonly property real clientWidth: clientBorder.width - borderWidth * 2
|
||||||
readonly property real clientHeight: clientBorder.height - hifi.styles.borderWidth * 2
|
readonly property real clientHeight: clientBorder.height - borderWidth * 2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Window decorations, with a title bar and frames
|
* Window decorations, with a title bar and frames
|
||||||
|
@ -35,6 +37,7 @@ Item {
|
||||||
id: windowBorder
|
id: windowBorder
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
border.color: root.frameColor
|
border.color: root.frameColor
|
||||||
|
border.width: 0
|
||||||
color: "#00000000"
|
color: "#00000000"
|
||||||
|
|
||||||
Border {
|
Border {
|
||||||
|
@ -43,11 +46,13 @@ Item {
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
border.color: root.frameColor
|
border.color: root.frameColor
|
||||||
|
border.width: 0
|
||||||
clip: true
|
clip: true
|
||||||
color: root.active ?
|
color: root.active ?
|
||||||
hifi.colors.activeWindow.headerBackground :
|
hifi.colors.activeWindow.headerBackground :
|
||||||
hifi.colors.inactiveWindow.headerBackground
|
hifi.colors.inactiveWindow.headerBackground
|
||||||
|
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
id: titleText
|
id: titleText
|
||||||
color: root.active ?
|
color: root.active ?
|
||||||
|
@ -60,8 +65,26 @@ Item {
|
||||||
}
|
}
|
||||||
} // header border
|
} // header border
|
||||||
|
|
||||||
|
// These two rectangles hide the curves between the title area
|
||||||
|
// and the client area
|
||||||
|
Rectangle {
|
||||||
|
y: titleBorder.height - titleBorder.radius
|
||||||
|
height: titleBorder.radius
|
||||||
|
width: titleBorder.width
|
||||||
|
color: titleBorder.color
|
||||||
|
visible: borderWidth == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
y: titleBorder.height
|
||||||
|
width: clientBorder.width
|
||||||
|
height: clientBorder.radius
|
||||||
|
color: clientBorder.color
|
||||||
|
}
|
||||||
|
|
||||||
Border {
|
Border {
|
||||||
id: clientBorder
|
id: clientBorder
|
||||||
|
border.width: 0
|
||||||
border.color: root.frameColor
|
border.color: root.frameColor
|
||||||
color: root.backgroundColor
|
color: root.backgroundColor
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
@ -69,7 +92,6 @@ Item {
|
||||||
anchors.topMargin: -titleBorder.border.width
|
anchors.topMargin: -titleBorder.border.width
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
clip: true
|
|
||||||
} // client border
|
} // client border
|
||||||
} // window border
|
} // window border
|
||||||
|
|
||||||
|
|
|
@ -13,14 +13,14 @@ Original.TextInput {
|
||||||
font.family: hifi.fonts.fontFamily
|
font.family: hifi.fonts.fontFamily
|
||||||
font.pointSize: hifi.fonts.fontSize
|
font.pointSize: hifi.fonts.fontSize
|
||||||
|
|
||||||
|
/*
|
||||||
Original.Rectangle {
|
Original.Rectangle {
|
||||||
// Render the rectangle as background
|
// Render the rectangle as background
|
||||||
z: -1
|
z: -1
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: hifi.colors.inputBackground
|
color: hifi.colors.inputBackground
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
Text {
|
Text {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
font.pointSize: parent.font.pointSize
|
font.pointSize: parent.font.pointSize
|
||||||
|
|
|
@ -766,6 +766,7 @@ void Application::initializeUi() {
|
||||||
AddressBarDialog::registerType();
|
AddressBarDialog::registerType();
|
||||||
LoginDialog::registerType();
|
LoginDialog::registerType();
|
||||||
MessageDialog::registerType();
|
MessageDialog::registerType();
|
||||||
|
VrMenu::registerType();
|
||||||
|
|
||||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||||
offscreenUi->create(_glWidget->context()->contextHandle());
|
offscreenUi->create(_glWidget->context()->contextHandle());
|
||||||
|
@ -774,6 +775,8 @@ void Application::initializeUi() {
|
||||||
offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
|
offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
|
||||||
offscreenUi->load("Root.qml");
|
offscreenUi->load("Root.qml");
|
||||||
offscreenUi->load("RootMenu.qml");
|
offscreenUi->load("RootMenu.qml");
|
||||||
|
VrMenu::load();
|
||||||
|
VrMenu::executeQueuedLambdas();
|
||||||
offscreenUi->setMouseTranslator([this](const QPointF& p){
|
offscreenUi->setMouseTranslator([this](const QPointF& p){
|
||||||
if (OculusManager::isConnected()) {
|
if (OculusManager::isConnected()) {
|
||||||
glm::vec2 pos = _applicationOverlay.screenToOverlay(toGlm(p));
|
glm::vec2 pos = _applicationOverlay.screenToOverlay(toGlm(p));
|
||||||
|
@ -4441,7 +4444,6 @@ void Application::checkSkeleton() {
|
||||||
|
|
||||||
_myAvatar->useBodyURL(DEFAULT_BODY_MODEL_URL, "Default");
|
_myAvatar->useBodyURL(DEFAULT_BODY_MODEL_URL, "Default");
|
||||||
} else {
|
} else {
|
||||||
_myAvatar->updateCharacterController();
|
|
||||||
_physicsEngine.setCharacterController(_myAvatar->getCharacterController());
|
_physicsEngine.setCharacterController(_myAvatar->getCharacterController());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -975,7 +975,9 @@ bool Menu::menuItemExists(const QString& menu, const QString& menuitem) {
|
||||||
|
|
||||||
|
|
||||||
MenuWrapper::MenuWrapper(QMenu* menu) : _realMenu(menu) {
|
MenuWrapper::MenuWrapper(QMenu* menu) : _realMenu(menu) {
|
||||||
VrMenu::instance()->addMenu(menu);
|
VrMenu::executeOrQueue([=](VrMenu* vrMenu) {
|
||||||
|
vrMenu->addMenu(menu);
|
||||||
|
});
|
||||||
_backMap[menu] = this;
|
_backMap[menu] = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -997,18 +999,24 @@ void MenuWrapper::addSeparator() {
|
||||||
|
|
||||||
void MenuWrapper::addAction(QAction* action) {
|
void MenuWrapper::addAction(QAction* action) {
|
||||||
_realMenu->addAction(action);
|
_realMenu->addAction(action);
|
||||||
VrMenu::instance()->addAction(_realMenu, action);
|
VrMenu::executeOrQueue([=](VrMenu* vrMenu) {
|
||||||
|
vrMenu->addAction(_realMenu, action);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QAction* MenuWrapper::addAction(const QString& menuName) {
|
QAction* MenuWrapper::addAction(const QString& menuName) {
|
||||||
QAction* action = _realMenu->addAction(menuName);
|
QAction* action = _realMenu->addAction(menuName);
|
||||||
VrMenu::instance()->addAction(_realMenu, action);
|
VrMenu::executeOrQueue([=](VrMenu* vrMenu) {
|
||||||
|
vrMenu->addAction(_realMenu, action);
|
||||||
|
});
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
QAction* MenuWrapper::addAction(const QString& menuName, const QObject* receiver, const char* member, const QKeySequence& shortcut) {
|
QAction* MenuWrapper::addAction(const QString& menuName, const QObject* receiver, const char* member, const QKeySequence& shortcut) {
|
||||||
QAction* action = _realMenu->addAction(menuName, receiver, member, shortcut);
|
QAction* action = _realMenu->addAction(menuName, receiver, member, shortcut);
|
||||||
VrMenu::instance()->addAction(_realMenu, action);
|
VrMenu::executeOrQueue([=](VrMenu* vrMenu) {
|
||||||
|
vrMenu->addAction(_realMenu, action);
|
||||||
|
});
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1018,7 +1026,9 @@ void MenuWrapper::removeAction(QAction* action) {
|
||||||
|
|
||||||
void MenuWrapper::insertAction(QAction* before, QAction* action) {
|
void MenuWrapper::insertAction(QAction* before, QAction* action) {
|
||||||
_realMenu->insertAction(before, action);
|
_realMenu->insertAction(before, action);
|
||||||
VrMenu::instance()->insertAction(before, action);
|
VrMenu::executeOrQueue([=](VrMenu* vrMenu) {
|
||||||
|
vrMenu->insertAction(before, action);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<QMenu*, MenuWrapper*> MenuWrapper::_backMap;
|
QHash<QMenu*, MenuWrapper*> MenuWrapper::_backMap;
|
||||||
|
|
|
@ -1058,3 +1058,20 @@ void Avatar::setShowDisplayName(bool showDisplayName) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// virtual
|
||||||
|
void Avatar::rebuildSkeletonBody() {
|
||||||
|
/* TODO: implement this and remove override from MyAvatar (when we have AvatarMotionStates working)
|
||||||
|
if (_motionState) {
|
||||||
|
// compute localAABox
|
||||||
|
const CapsuleShape& capsule = _skeletonModel.getBoundingShape();
|
||||||
|
float radius = capsule.getRadius();
|
||||||
|
float height = 2.0f * (capsule.getHalfHeight() + radius);
|
||||||
|
glm::vec3 corner(-radius, -0.5f * height, -radius);
|
||||||
|
corner += _skeletonModel.getBoundingShapeOffset();
|
||||||
|
glm::vec3 scale(2.0f * radius, height, 2.0f * radius);
|
||||||
|
//_characterController.setLocalBoundingBox(corner, scale);
|
||||||
|
_motionState->setBoundingBox(corner, scale);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -162,6 +162,8 @@ public:
|
||||||
// (otherwise floating point error will cause problems at large positions).
|
// (otherwise floating point error will cause problems at large positions).
|
||||||
void applyPositionDelta(const glm::vec3& delta);
|
void applyPositionDelta(const glm::vec3& delta);
|
||||||
|
|
||||||
|
virtual void rebuildSkeletonBody();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void collisionWithAvatar(const QUuid& myUUID, const QUuid& theirUUID, const CollisionInfo& collision);
|
void collisionWithAvatar(const QUuid& myUUID, const QUuid& theirUUID, const CollisionInfo& collision);
|
||||||
|
|
||||||
|
@ -228,6 +230,8 @@ private:
|
||||||
static int _jointConesID;
|
static int _jointConesID;
|
||||||
|
|
||||||
int _voiceSphereID;
|
int _voiceSphereID;
|
||||||
|
|
||||||
|
//AvatarMotionState* _motionState = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_Avatar_h
|
#endif // hifi_Avatar_h
|
||||||
|
|
|
@ -59,7 +59,7 @@ private:
|
||||||
|
|
||||||
AvatarSharedPointer newSharedAvatar();
|
AvatarSharedPointer newSharedAvatar();
|
||||||
|
|
||||||
// virtual override
|
// virtual overrides
|
||||||
AvatarHash::iterator erase(const AvatarHash::iterator& iterator);
|
AvatarHash::iterator erase(const AvatarHash::iterator& iterator);
|
||||||
|
|
||||||
QVector<AvatarSharedPointer> _avatarFades;
|
QVector<AvatarSharedPointer> _avatarFades;
|
||||||
|
|
|
@ -987,6 +987,13 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName) {
|
void MyAvatar::useFullAvatarURL(const QUrl& fullAvatarURL, const QString& modelName) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "useFullAvatarURL", Qt::BlockingQueuedConnection,
|
||||||
|
Q_ARG(const QUrl&, fullAvatarURL),
|
||||||
|
Q_ARG(const QString&, modelName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_useFullAvatar = true;
|
_useFullAvatar = true;
|
||||||
|
|
||||||
if (_fullAvatarURLFromPreferences != fullAvatarURL) {
|
if (_fullAvatarURLFromPreferences != fullAvatarURL) {
|
||||||
|
@ -1019,6 +1026,15 @@ void MyAvatar::useBodyURL(const QUrl& bodyURL, const QString& modelName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, const QString& headName, const QString& bodyName) {
|
void MyAvatar::useHeadAndBodyURLs(const QUrl& headURL, const QUrl& bodyURL, const QString& headName, const QString& bodyName) {
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "useFullAvatarURL", Qt::BlockingQueuedConnection,
|
||||||
|
Q_ARG(const QUrl&, headURL),
|
||||||
|
Q_ARG(const QUrl&, bodyURL),
|
||||||
|
Q_ARG(const QString&, headName),
|
||||||
|
Q_ARG(const QString&, bodyName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_useFullAvatar = false;
|
_useFullAvatar = false;
|
||||||
|
|
||||||
if (_headURLFromPreferences != headURL) {
|
if (_headURLFromPreferences != headURL) {
|
||||||
|
@ -1079,7 +1095,7 @@ glm::vec3 MyAvatar::getSkeletonPosition() const {
|
||||||
return Avatar::getPosition();
|
return Avatar::getPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::updateCharacterController() {
|
void MyAvatar::rebuildSkeletonBody() {
|
||||||
// compute localAABox
|
// compute localAABox
|
||||||
const CapsuleShape& capsule = _skeletonModel.getBoundingShape();
|
const CapsuleShape& capsule = _skeletonModel.getBoundingShape();
|
||||||
float radius = capsule.getRadius();
|
float radius = capsule.getRadius();
|
||||||
|
|
|
@ -138,7 +138,6 @@ public:
|
||||||
virtual glm::vec3 getSkeletonPosition() const;
|
virtual glm::vec3 getSkeletonPosition() const;
|
||||||
void updateLocalAABox();
|
void updateLocalAABox();
|
||||||
DynamicCharacterController* getCharacterController() { return &_characterController; }
|
DynamicCharacterController* getCharacterController() { return &_characterController; }
|
||||||
void updateCharacterController();
|
|
||||||
|
|
||||||
void clearJointAnimationPriorities();
|
void clearJointAnimationPriorities();
|
||||||
|
|
||||||
|
@ -193,6 +192,8 @@ public slots:
|
||||||
void saveRecording(QString filename);
|
void saveRecording(QString filename);
|
||||||
void loadLastRecording();
|
void loadLastRecording();
|
||||||
|
|
||||||
|
virtual void rebuildSkeletonBody();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void transformChanged();
|
void transformChanged();
|
||||||
|
|
||||||
|
|
|
@ -40,13 +40,14 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) :
|
||||||
_clampedFootPosition(0.0f),
|
_clampedFootPosition(0.0f),
|
||||||
_headClipDistance(DEFAULT_NEAR_CLIP)
|
_headClipDistance(DEFAULT_NEAR_CLIP)
|
||||||
{
|
{
|
||||||
|
assert(_owningAvatar);
|
||||||
}
|
}
|
||||||
|
|
||||||
SkeletonModel::~SkeletonModel() {
|
SkeletonModel::~SkeletonModel() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonModel::setJointStates(QVector<JointState> states) {
|
void SkeletonModel::initJointStates(QVector<JointState> states) {
|
||||||
Model::setJointStates(states);
|
Model::initJointStates(states);
|
||||||
|
|
||||||
// Determine the default eye position for avatar scale = 1.0
|
// Determine the default eye position for avatar scale = 1.0
|
||||||
int headJointIndex = _geometry->getFBXGeometry().headJointIndex;
|
int headJointIndex = _geometry->getFBXGeometry().headJointIndex;
|
||||||
|
@ -83,6 +84,7 @@ void SkeletonModel::setJointStates(QVector<JointState> states) {
|
||||||
_headClipDistance = -(meshExtents.minimum.z / _scale.z - _defaultEyeModelPosition.z);
|
_headClipDistance = -(meshExtents.minimum.z / _scale.z - _defaultEyeModelPosition.z);
|
||||||
_headClipDistance = std::max(_headClipDistance, DEFAULT_NEAR_CLIP);
|
_headClipDistance = std::max(_headClipDistance, DEFAULT_NEAR_CLIP);
|
||||||
|
|
||||||
|
_owningAvatar->rebuildSkeletonBody();
|
||||||
emit skeletonLoaded();
|
emit skeletonLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ public:
|
||||||
SkeletonModel(Avatar* owningAvatar, QObject* parent = NULL);
|
SkeletonModel(Avatar* owningAvatar, QObject* parent = NULL);
|
||||||
~SkeletonModel();
|
~SkeletonModel();
|
||||||
|
|
||||||
void setJointStates(QVector<JointState> states);
|
virtual void initJointStates(QVector<JointState> states);
|
||||||
|
|
||||||
void simulate(float deltaTime, bool fullUpdate = true);
|
void simulate(float deltaTime, bool fullUpdate = true);
|
||||||
|
|
||||||
|
|
|
@ -680,6 +680,17 @@ void EntityItem::setMass(float mass) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const float DEFAULT_ENTITY_RESTITUTION = 0.5f;
|
||||||
|
const float DEFAULT_ENTITY_FRICTION = 0.5f;
|
||||||
|
|
||||||
|
float EntityItem::getRestitution() const {
|
||||||
|
return DEFAULT_ENTITY_RESTITUTION;
|
||||||
|
}
|
||||||
|
|
||||||
|
float EntityItem::getFriction() const {
|
||||||
|
return DEFAULT_ENTITY_FRICTION;
|
||||||
|
}
|
||||||
|
|
||||||
void EntityItem::simulate(const quint64& now) {
|
void EntityItem::simulate(const quint64& now) {
|
||||||
if (_lastSimulated == 0) {
|
if (_lastSimulated == 0) {
|
||||||
_lastSimulated = now;
|
_lastSimulated = now;
|
||||||
|
@ -840,11 +851,11 @@ glm::mat4 EntityItem::getWorldToEntityMatrix() const {
|
||||||
return glm::inverse(getEntityToWorldMatrix());
|
return glm::inverse(getEntityToWorldMatrix());
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 EntityItem::entityToWorld(const glm::vec3 point) const {
|
glm::vec3 EntityItem::entityToWorld(const glm::vec3& point) const {
|
||||||
return glm::vec3(getEntityToWorldMatrix() * glm::vec4(point, 1.0f));
|
return glm::vec3(getEntityToWorldMatrix() * glm::vec4(point, 1.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 EntityItem::worldToEntity(const glm::vec3 point) const {
|
glm::vec3 EntityItem::worldToEntity(const glm::vec3& point) const {
|
||||||
return glm::vec3(getWorldToEntityMatrix() * glm::vec4(point, 1.0f));
|
return glm::vec3(getWorldToEntityMatrix() * glm::vec4(point, 1.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1164,7 +1175,7 @@ void EntityItem::updateVelocity(const glm::vec3& value) {
|
||||||
void EntityItem::updateDamping(float value) {
|
void EntityItem::updateDamping(float value) {
|
||||||
if (fabsf(_damping - value) > MIN_DAMPING_DELTA) {
|
if (fabsf(_damping - value) > MIN_DAMPING_DELTA) {
|
||||||
_damping = glm::clamp(value, 0.0f, 1.0f);
|
_damping = glm::clamp(value, 0.0f, 1.0f);
|
||||||
_dirtyFlags |= EntityItem::DIRTY_VELOCITY;
|
_dirtyFlags |= EntityItem::DIRTY_MATERIAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1202,7 +1213,7 @@ void EntityItem::updateAngularVelocity(const glm::vec3& value) {
|
||||||
void EntityItem::updateAngularDamping(float value) {
|
void EntityItem::updateAngularDamping(float value) {
|
||||||
if (fabsf(_angularDamping - value) > MIN_DAMPING_DELTA) {
|
if (fabsf(_angularDamping - value) > MIN_DAMPING_DELTA) {
|
||||||
_angularDamping = glm::clamp(value, 0.0f, 1.0f);
|
_angularDamping = glm::clamp(value, 0.0f, 1.0f);
|
||||||
_dirtyFlags |= EntityItem::DIRTY_VELOCITY;
|
_dirtyFlags |= EntityItem::DIRTY_MATERIAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,8 @@ public:
|
||||||
DIRTY_SHAPE = 0x0020,
|
DIRTY_SHAPE = 0x0020,
|
||||||
DIRTY_LIFETIME = 0x0040,
|
DIRTY_LIFETIME = 0x0040,
|
||||||
DIRTY_UPDATEABLE = 0x0080,
|
DIRTY_UPDATEABLE = 0x0080,
|
||||||
DIRTY_PHYSICS_NO_WAKE = 0x0100 // we want to update values in physics engine without "waking" the object up
|
DIRTY_MATERIAL = 0x00100,
|
||||||
|
DIRTY_PHYSICS_NO_WAKE = 0x0200 // we want to update values in physics engine without "waking" the object up
|
||||||
};
|
};
|
||||||
|
|
||||||
DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly
|
DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly
|
||||||
|
@ -174,7 +175,7 @@ public:
|
||||||
|
|
||||||
float getDensity() const { return _density; }
|
float getDensity() const { return _density; }
|
||||||
|
|
||||||
const glm::vec3 getVelocity() const { return _velocity; } /// get velocity in meters
|
const glm::vec3& getVelocity() const { return _velocity; } /// get velocity in meters
|
||||||
void setVelocity(const glm::vec3& value) { _velocity = value; } /// velocity in meters
|
void setVelocity(const glm::vec3& value) { _velocity = value; } /// velocity in meters
|
||||||
bool hasVelocity() const { return _velocity != ENTITY_ITEM_ZERO_VEC3; }
|
bool hasVelocity() const { return _velocity != ENTITY_ITEM_ZERO_VEC3; }
|
||||||
|
|
||||||
|
@ -182,13 +183,16 @@ public:
|
||||||
void setGravity(const glm::vec3& value) { _gravity = value; } /// gravity in meters
|
void setGravity(const glm::vec3& value) { _gravity = value; } /// gravity in meters
|
||||||
bool hasGravity() const { return _gravity != ENTITY_ITEM_ZERO_VEC3; }
|
bool hasGravity() const { return _gravity != ENTITY_ITEM_ZERO_VEC3; }
|
||||||
|
|
||||||
const glm::vec3 getAcceleration() const { return _acceleration; } /// get acceleration in meters/second/second
|
const glm::vec3& getAcceleration() const { return _acceleration; } /// get acceleration in meters/second/second
|
||||||
void setAcceleration(const glm::vec3& value) { _acceleration = value; } /// acceleration in meters/second/second
|
void setAcceleration(const glm::vec3& value) { _acceleration = value; } /// acceleration in meters/second/second
|
||||||
bool hasAcceleration() const { return _acceleration != ENTITY_ITEM_ZERO_VEC3; }
|
bool hasAcceleration() const { return _acceleration != ENTITY_ITEM_ZERO_VEC3; }
|
||||||
|
|
||||||
float getDamping() const { return _damping; }
|
float getDamping() const { return _damping; }
|
||||||
void setDamping(float value) { _damping = value; }
|
void setDamping(float value) { _damping = value; }
|
||||||
|
|
||||||
|
float getRestitution() const;
|
||||||
|
float getFriction() const;
|
||||||
|
|
||||||
// lifetime related properties.
|
// lifetime related properties.
|
||||||
float getLifetime() const { return _lifetime; } /// get the lifetime in seconds for the entity
|
float getLifetime() const { return _lifetime; } /// get the lifetime in seconds for the entity
|
||||||
void setLifetime(float value) { _lifetime = value; } /// set the lifetime in seconds for the entity
|
void setLifetime(float value) { _lifetime = value; } /// set the lifetime in seconds for the entity
|
||||||
|
@ -298,8 +302,8 @@ public:
|
||||||
|
|
||||||
glm::mat4 getEntityToWorldMatrix() const;
|
glm::mat4 getEntityToWorldMatrix() const;
|
||||||
glm::mat4 getWorldToEntityMatrix() const;
|
glm::mat4 getWorldToEntityMatrix() const;
|
||||||
glm::vec3 worldToEntity(const glm::vec3 point) const;
|
glm::vec3 worldToEntity(const glm::vec3& point) const;
|
||||||
glm::vec3 entityToWorld(const glm::vec3 point) const;
|
glm::vec3 entityToWorld(const glm::vec3& point) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "LightEntityItem.h"
|
#include "LightEntityItem.h"
|
||||||
#include "ModelEntityItem.h"
|
#include "ModelEntityItem.h"
|
||||||
#include "ZoneEntityItem.h"
|
#include "ZoneEntityItem.h"
|
||||||
|
#include "EntitiesLogging.h"
|
||||||
|
|
||||||
|
|
||||||
EntityScriptingInterface::EntityScriptingInterface() :
|
EntityScriptingInterface::EntityScriptingInterface() :
|
||||||
|
@ -78,19 +79,27 @@ EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& pro
|
||||||
|
|
||||||
EntityItemProperties propertiesWithSimID = properties;
|
EntityItemProperties propertiesWithSimID = properties;
|
||||||
|
|
||||||
EntityItemID id(NEW_ENTITY, creatorTokenID, false );
|
EntityItemID id(NEW_ENTITY, creatorTokenID, false);
|
||||||
|
|
||||||
// If we have a local entity tree set, then also update it.
|
// If we have a local entity tree set, then also update it.
|
||||||
|
bool success = true;
|
||||||
if (_entityTree) {
|
if (_entityTree) {
|
||||||
_entityTree->lockForWrite();
|
_entityTree->lockForWrite();
|
||||||
EntityItem* entity = _entityTree->addEntity(id, propertiesWithSimID);
|
EntityItem* entity = _entityTree->addEntity(id, propertiesWithSimID);
|
||||||
// This Node is creating a new object. If it's in motion, set this Node as the simulator.
|
if (entity) {
|
||||||
setSimId(propertiesWithSimID, entity);
|
// This Node is creating a new object. If it's in motion, set this Node as the simulator.
|
||||||
|
setSimId(propertiesWithSimID, entity);
|
||||||
|
} else {
|
||||||
|
qCDebug(entities) << "script failed to add new Entity to local Octree";
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
_entityTree->unlock();
|
_entityTree->unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
// queue the packet
|
// queue the packet
|
||||||
queueEntityMessage(PacketTypeEntityAddOrEdit, id, propertiesWithSimID);
|
if (success) {
|
||||||
|
queueEntityMessage(PacketTypeEntityAddOrEdit, id, propertiesWithSimID);
|
||||||
|
}
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,6 +192,14 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro
|
||||||
EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||||
EntityItem* result = NULL;
|
EntityItem* result = NULL;
|
||||||
|
|
||||||
|
if (getIsClient()) {
|
||||||
|
// if our Node isn't allowed to create entities in this domain, don't try.
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
if (!nodeList->getThisNodeCanRez()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: This method is used in the client and the server tree. In the client, it's possible to create EntityItems
|
// NOTE: This method is used in the client and the server tree. In the client, it's possible to create EntityItems
|
||||||
// that do not yet have known IDs. In the server tree however we don't want to have entities without known IDs.
|
// that do not yet have known IDs. In the server tree however we don't want to have entities without known IDs.
|
||||||
bool recordCreationTime = false;
|
bool recordCreationTime = false;
|
||||||
|
|
|
@ -94,7 +94,7 @@ void DynamicCharacterController::preStep(btCollisionWorld* collisionWorld) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DynamicCharacterController::playerStep(btCollisionWorld* dynaWorld,btScalar dt) {
|
void DynamicCharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) {
|
||||||
btVector3 actualVelocity = _rigidBody->getLinearVelocity();
|
btVector3 actualVelocity = _rigidBody->getLinearVelocity();
|
||||||
btScalar actualSpeed = actualVelocity.length();
|
btScalar actualSpeed = actualVelocity.length();
|
||||||
|
|
||||||
|
@ -315,10 +315,10 @@ void DynamicCharacterController::updateShapeIfNecessary() {
|
||||||
float mass = 1.0f;
|
float mass = 1.0f;
|
||||||
btVector3 inertia(1.0f, 1.0f, 1.0f);
|
btVector3 inertia(1.0f, 1.0f, 1.0f);
|
||||||
_rigidBody = new btRigidBody(mass, NULL, _shape, inertia);
|
_rigidBody = new btRigidBody(mass, NULL, _shape, inertia);
|
||||||
_rigidBody->setSleepingThresholds (0.0f, 0.0f);
|
_rigidBody->setSleepingThresholds(0.0f, 0.0f);
|
||||||
_rigidBody->setAngularFactor (0.0f);
|
_rigidBody->setAngularFactor(0.0f);
|
||||||
_rigidBody->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()),
|
_rigidBody->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()),
|
||||||
glmToBullet(_avatarData->getPosition())));
|
glmToBullet(_avatarData->getPosition())));
|
||||||
if (_isHovering) {
|
if (_isHovering) {
|
||||||
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f));
|
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -51,7 +51,7 @@ EntityMotionState::~EntityMotionState() {
|
||||||
_entity = NULL;
|
_entity = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
MotionType EntityMotionState::computeMotionType() const {
|
MotionType EntityMotionState::computeObjectMotionType() const {
|
||||||
if (_entity->getCollisionsWillMove()) {
|
if (_entity->getCollisionsWillMove()) {
|
||||||
return MOTION_TYPE_DYNAMIC;
|
return MOTION_TYPE_DYNAMIC;
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ void EntityMotionState::stepKinematicSimulation(quint64 now) {
|
||||||
// which is different from physical kinematic motion (inside getWorldTransform())
|
// which is different from physical kinematic motion (inside getWorldTransform())
|
||||||
// which steps in physics simulation time.
|
// which steps in physics simulation time.
|
||||||
_entity->simulate(now);
|
_entity->simulate(now);
|
||||||
// TODO: we can't use ObjectMotionState::measureAcceleration() here because the entity
|
// TODO: we can't use measureBodyAcceleration() here because the entity
|
||||||
// has no RigidBody and the timestep is a little bit out of sync with the physics simulation anyway.
|
// has no RigidBody and the timestep is a little bit out of sync with the physics simulation anyway.
|
||||||
// Hence we must manually measure kinematic velocity and acceleration.
|
// Hence we must manually measure kinematic velocity and acceleration.
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ void EntityMotionState::getWorldTransform(btTransform& worldTrans) const {
|
||||||
// This callback is invoked by the physics simulation at the end of each simulation step...
|
// This callback is invoked by the physics simulation at the end of each simulation step...
|
||||||
// iff the corresponding RigidBody is DYNAMIC and has moved.
|
// iff the corresponding RigidBody is DYNAMIC and has moved.
|
||||||
void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
|
void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
|
||||||
measureAcceleration();
|
measureBodyAcceleration();
|
||||||
_entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset());
|
_entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset());
|
||||||
_entity->setRotation(bulletToGLM(worldTrans.getRotation()));
|
_entity->setRotation(bulletToGLM(worldTrans.getRotation()));
|
||||||
|
|
||||||
|
@ -138,20 +138,20 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t step) {
|
void EntityMotionState::updateBodyEasy(uint32_t flags, uint32_t step) {
|
||||||
if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY | EntityItem::DIRTY_PHYSICS_NO_WAKE)) {
|
if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY | EntityItem::DIRTY_PHYSICS_NO_WAKE)) {
|
||||||
if (flags & EntityItem::DIRTY_POSITION) {
|
if (flags & EntityItem::DIRTY_POSITION) {
|
||||||
_sentPosition = _entity->getPosition() - ObjectMotionState::getWorldOffset();
|
_sentPosition = getObjectPosition() - ObjectMotionState::getWorldOffset();
|
||||||
btTransform worldTrans;
|
btTransform worldTrans;
|
||||||
worldTrans.setOrigin(glmToBullet(_sentPosition));
|
worldTrans.setOrigin(glmToBullet(_sentPosition));
|
||||||
|
|
||||||
_sentRotation = _entity->getRotation();
|
_sentRotation = getObjectRotation();
|
||||||
worldTrans.setRotation(glmToBullet(_sentRotation));
|
worldTrans.setRotation(glmToBullet(_sentRotation));
|
||||||
|
|
||||||
_body->setWorldTransform(worldTrans);
|
_body->setWorldTransform(worldTrans);
|
||||||
}
|
}
|
||||||
if (flags & EntityItem::DIRTY_VELOCITY) {
|
if (flags & EntityItem::DIRTY_VELOCITY) {
|
||||||
updateObjectVelocities();
|
updateBodyVelocities();
|
||||||
}
|
}
|
||||||
_sentStep = step;
|
_sentStep = step;
|
||||||
|
|
||||||
|
@ -160,54 +160,54 @@ void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t step) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: entity support for friction and restitution
|
if (flags & EntityItem::DIRTY_MATERIAL) {
|
||||||
//_restitution = _entity->getRestitution();
|
updateBodyMaterialProperties();
|
||||||
_body->setRestitution(_restitution);
|
}
|
||||||
//_friction = _entity->getFriction();
|
|
||||||
_body->setFriction(_friction);
|
|
||||||
|
|
||||||
_linearDamping = _entity->getDamping();
|
|
||||||
_angularDamping = _entity->getAngularDamping();
|
|
||||||
_body->setDamping(_linearDamping, _angularDamping);
|
|
||||||
|
|
||||||
if (flags & EntityItem::DIRTY_MASS) {
|
if (flags & EntityItem::DIRTY_MASS) {
|
||||||
float mass = _entity->computeMass();
|
ShapeInfo shapeInfo;
|
||||||
|
_entity->computeShapeInfo(shapeInfo);
|
||||||
|
float mass = computeObjectMass(shapeInfo);
|
||||||
btVector3 inertia(0.0f, 0.0f, 0.0f);
|
btVector3 inertia(0.0f, 0.0f, 0.0f);
|
||||||
_body->getCollisionShape()->calculateLocalInertia(mass, inertia);
|
_body->getCollisionShape()->calculateLocalInertia(mass, inertia);
|
||||||
_body->setMassProps(mass, inertia);
|
_body->setMassProps(mass, inertia);
|
||||||
_body->updateInertiaTensor();
|
_body->updateInertiaTensor();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
void EntityMotionState::updateObjectVelocities() {
|
void EntityMotionState::updateBodyMaterialProperties() {
|
||||||
|
_body->setRestitution(getObjectRestitution());
|
||||||
|
_body->setFriction(getObjectFriction());
|
||||||
|
_body->setDamping(fabsf(btMin(getObjectLinearDamping(), 1.0f)), fabsf(btMin(getObjectAngularDamping(), 1.0f)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityMotionState::updateBodyVelocities() {
|
||||||
if (_body) {
|
if (_body) {
|
||||||
_sentVelocity = _entity->getVelocity();
|
_sentVelocity = getObjectLinearVelocity();
|
||||||
setVelocity(_sentVelocity);
|
setBodyVelocity(_sentVelocity);
|
||||||
|
|
||||||
_sentAngularVelocity = _entity->getAngularVelocity();
|
_sentAngularVelocity = getObjectAngularVelocity();
|
||||||
setAngularVelocity(_sentAngularVelocity);
|
setBodyAngularVelocity(_sentAngularVelocity);
|
||||||
|
|
||||||
_sentGravity = _entity->getGravity();
|
_sentGravity = getObjectGravity();
|
||||||
setGravity(_sentGravity);
|
setBodyGravity(_sentGravity);
|
||||||
|
|
||||||
_body->setActivationState(ACTIVE_TAG);
|
_body->setActivationState(ACTIVE_TAG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityMotionState::computeShapeInfo(ShapeInfo& shapeInfo) {
|
void EntityMotionState::computeObjectShapeInfo(ShapeInfo& shapeInfo) {
|
||||||
if (_entity->isReadyToComputeShape()) {
|
if (_entity->isReadyToComputeShape()) {
|
||||||
_entity->computeShapeInfo(shapeInfo);
|
_entity->computeShapeInfo(shapeInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float EntityMotionState::computeMass(const ShapeInfo& shapeInfo) const {
|
float EntityMotionState::computeObjectMass(const ShapeInfo& shapeInfo) const {
|
||||||
return _entity->computeMass();
|
return _entity->computeMass();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) {
|
bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) {
|
||||||
bool baseResult = this->ObjectMotionState::shouldSendUpdate(simulationFrame);
|
if (!ObjectMotionState::shouldSendUpdate(simulationFrame)) {
|
||||||
|
|
||||||
if (!baseResult) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,12 +31,11 @@ public:
|
||||||
static void setOutgoingEntityList(QSet<EntityItem*>* list);
|
static void setOutgoingEntityList(QSet<EntityItem*>* list);
|
||||||
static void enqueueOutgoingEntity(EntityItem* entity);
|
static void enqueueOutgoingEntity(EntityItem* entity);
|
||||||
|
|
||||||
EntityMotionState() = delete; // prevent compiler from making default ctor
|
|
||||||
EntityMotionState(EntityItem* item);
|
EntityMotionState(EntityItem* item);
|
||||||
virtual ~EntityMotionState();
|
virtual ~EntityMotionState();
|
||||||
|
|
||||||
/// \return MOTION_TYPE_DYNAMIC or MOTION_TYPE_STATIC based on params set in EntityItem
|
/// \return MOTION_TYPE_DYNAMIC or MOTION_TYPE_STATIC based on params set in EntityItem
|
||||||
virtual MotionType computeMotionType() const;
|
virtual MotionType computeObjectMotionType() const;
|
||||||
|
|
||||||
virtual void updateKinematicState(uint32_t substep);
|
virtual void updateKinematicState(uint32_t substep);
|
||||||
virtual void stepKinematicSimulation(quint64 now);
|
virtual void stepKinematicSimulation(quint64 now);
|
||||||
|
@ -50,11 +49,12 @@ public:
|
||||||
virtual void setWorldTransform(const btTransform& worldTrans);
|
virtual void setWorldTransform(const btTransform& worldTrans);
|
||||||
|
|
||||||
// these relay incoming values to the RigidBody
|
// these relay incoming values to the RigidBody
|
||||||
virtual void updateObjectEasy(uint32_t flags, uint32_t step);
|
virtual void updateBodyEasy(uint32_t flags, uint32_t step);
|
||||||
virtual void updateObjectVelocities();
|
virtual void updateBodyMaterialProperties();
|
||||||
|
virtual void updateBodyVelocities();
|
||||||
|
|
||||||
virtual void computeShapeInfo(ShapeInfo& shapeInfo);
|
virtual void computeObjectShapeInfo(ShapeInfo& shapeInfo);
|
||||||
virtual float computeMass(const ShapeInfo& shapeInfo) const;
|
virtual float computeObjectMass(const ShapeInfo& shapeInfo) const;
|
||||||
|
|
||||||
virtual bool shouldSendUpdate(uint32_t simulationFrame);
|
virtual bool shouldSendUpdate(uint32_t simulationFrame);
|
||||||
virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t step);
|
virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t step);
|
||||||
|
@ -70,6 +70,17 @@ public:
|
||||||
virtual void setShouldClaimSimulationOwnership(bool value) { _shouldClaimSimulationOwnership = value; }
|
virtual void setShouldClaimSimulationOwnership(bool value) { _shouldClaimSimulationOwnership = value; }
|
||||||
virtual bool getShouldClaimSimulationOwnership() { return _shouldClaimSimulationOwnership; }
|
virtual bool getShouldClaimSimulationOwnership() { return _shouldClaimSimulationOwnership; }
|
||||||
|
|
||||||
|
virtual float getObjectRestitution() const { return _entity->getRestitution(); }
|
||||||
|
virtual float getObjectFriction() const { return _entity->getFriction(); }
|
||||||
|
virtual float getObjectLinearDamping() const { return _entity->getDamping(); }
|
||||||
|
virtual float getObjectAngularDamping() const { return _entity->getAngularDamping(); }
|
||||||
|
|
||||||
|
virtual const glm::vec3& getObjectPosition() const { return _entity->getPosition(); }
|
||||||
|
virtual const glm::quat& getObjectRotation() const { return _entity->getRotation(); }
|
||||||
|
virtual const glm::vec3& getObjectLinearVelocity() const { return _entity->getVelocity(); }
|
||||||
|
virtual const glm::vec3& getObjectAngularVelocity() const { return _entity->getAngularVelocity(); }
|
||||||
|
virtual const glm::vec3& getObjectGravity() const { return _entity->getGravity(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
EntityItem* _entity;
|
EntityItem* _entity;
|
||||||
quint8 _accelerationNearlyGravityCount;
|
quint8 _accelerationNearlyGravityCount;
|
||||||
|
|
|
@ -36,17 +36,13 @@ const glm::vec3& ObjectMotionState::getWorldOffset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
uint32_t _simulationStep = 0;
|
uint32_t _worldSimulationStep = 0;
|
||||||
void ObjectMotionState::setSimulationStep(uint32_t step) {
|
void ObjectMotionState::setWorldSimulationStep(uint32_t step) {
|
||||||
assert(step > _simulationStep);
|
assert(step > _worldSimulationStep);
|
||||||
_simulationStep = step;
|
_worldSimulationStep = step;
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectMotionState::ObjectMotionState() :
|
ObjectMotionState::ObjectMotionState() :
|
||||||
_friction(DEFAULT_FRICTION),
|
|
||||||
_restitution(DEFAULT_RESTITUTION),
|
|
||||||
_linearDamping(0.0f),
|
|
||||||
_angularDamping(0.0f),
|
|
||||||
_motionType(MOTION_TYPE_STATIC),
|
_motionType(MOTION_TYPE_STATIC),
|
||||||
_body(NULL),
|
_body(NULL),
|
||||||
_sentMoving(false),
|
_sentMoving(false),
|
||||||
|
@ -69,52 +65,36 @@ ObjectMotionState::~ObjectMotionState() {
|
||||||
assert(_body == NULL);
|
assert(_body == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectMotionState::measureAcceleration() {
|
void ObjectMotionState::measureBodyAcceleration() {
|
||||||
// try to manually measure the true acceleration of the object
|
// try to manually measure the true acceleration of the object
|
||||||
uint32_t numSubsteps = _simulationStep - _lastSimulationStep;
|
uint32_t numSubsteps = _worldSimulationStep - _lastSimulationStep;
|
||||||
if (numSubsteps > 0) {
|
if (numSubsteps > 0) {
|
||||||
float dt = ((float)numSubsteps * PHYSICS_ENGINE_FIXED_SUBSTEP);
|
float dt = ((float)numSubsteps * PHYSICS_ENGINE_FIXED_SUBSTEP);
|
||||||
float invDt = 1.0f / dt;
|
float invDt = 1.0f / dt;
|
||||||
_lastSimulationStep = _simulationStep;
|
_lastSimulationStep = _worldSimulationStep;
|
||||||
|
|
||||||
// Note: the integration equation for velocity uses damping: v1 = (v0 + a * dt) * (1 - D)^dt
|
// Note: the integration equation for velocity uses damping: v1 = (v0 + a * dt) * (1 - D)^dt
|
||||||
// hence the equation for acceleration is: a = (v1 / (1 - D)^dt - v0) / dt
|
// hence the equation for acceleration is: a = (v1 / (1 - D)^dt - v0) / dt
|
||||||
glm::vec3 velocity = bulletToGLM(_body->getLinearVelocity());
|
glm::vec3 velocity = bulletToGLM(_body->getLinearVelocity());
|
||||||
_measuredAcceleration = (velocity / powf(1.0f - _linearDamping, dt) - _lastVelocity) * invDt;
|
_measuredAcceleration = (velocity / powf(1.0f - _body->getLinearDamping(), dt) - _lastVelocity) * invDt;
|
||||||
_lastVelocity = velocity;
|
_lastVelocity = velocity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectMotionState::resetMeasuredAcceleration() {
|
void ObjectMotionState::resetMeasuredBodyAcceleration() {
|
||||||
_lastSimulationStep = _simulationStep;
|
_lastSimulationStep = _worldSimulationStep;
|
||||||
_lastVelocity = bulletToGLM(_body->getLinearVelocity());
|
_lastVelocity = bulletToGLM(_body->getLinearVelocity());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectMotionState::setFriction(float friction) {
|
void ObjectMotionState::setBodyVelocity(const glm::vec3& velocity) const {
|
||||||
_friction = btMax(btMin(fabsf(friction), MAX_FRICTION), 0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ObjectMotionState::setRestitution(float restitution) {
|
|
||||||
_restitution = btMax(btMin(fabsf(restitution), 1.0f), 0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ObjectMotionState::setLinearDamping(float damping) {
|
|
||||||
_linearDamping = btMax(btMin(fabsf(damping), 1.0f), 0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ObjectMotionState::setAngularDamping(float damping) {
|
|
||||||
_angularDamping = btMax(btMin(fabsf(damping), 1.0f), 0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ObjectMotionState::setVelocity(const glm::vec3& velocity) const {
|
|
||||||
_body->setLinearVelocity(glmToBullet(velocity));
|
_body->setLinearVelocity(glmToBullet(velocity));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectMotionState::setAngularVelocity(const glm::vec3& velocity) const {
|
void ObjectMotionState::setBodyAngularVelocity(const glm::vec3& velocity) const {
|
||||||
_body->setAngularVelocity(glmToBullet(velocity));
|
_body->setAngularVelocity(glmToBullet(velocity));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectMotionState::setGravity(const glm::vec3& gravity) const {
|
void ObjectMotionState::setBodyGravity(const glm::vec3& gravity) const {
|
||||||
_body->setGravity(glmToBullet(gravity));
|
_body->setGravity(glmToBullet(gravity));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +161,7 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationStep) {
|
||||||
// compute position error
|
// compute position error
|
||||||
if (glm::length2(_sentVelocity) > 0.0f) {
|
if (glm::length2(_sentVelocity) > 0.0f) {
|
||||||
_sentVelocity += _sentAcceleration * dt;
|
_sentVelocity += _sentAcceleration * dt;
|
||||||
_sentVelocity *= powf(1.0f - _linearDamping, dt);
|
_sentVelocity *= powf(1.0f - _body->getLinearDamping(), dt);
|
||||||
_sentPosition += dt * _sentVelocity;
|
_sentPosition += dt * _sentVelocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,7 +186,7 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationStep) {
|
||||||
|
|
||||||
if (glm::length2(_sentAngularVelocity) > 0.0f) {
|
if (glm::length2(_sentAngularVelocity) > 0.0f) {
|
||||||
// compute rotation error
|
// compute rotation error
|
||||||
float attenuation = powf(1.0f - _angularDamping, dt);
|
float attenuation = powf(1.0f - _body->getAngularDamping(), dt);
|
||||||
_sentAngularVelocity *= attenuation;
|
_sentAngularVelocity *= attenuation;
|
||||||
|
|
||||||
// Bullet caps the effective rotation velocity inside its rotation integration step, therefore
|
// Bullet caps the effective rotation velocity inside its rotation integration step, therefore
|
||||||
|
|
|
@ -36,7 +36,7 @@ enum MotionStateType {
|
||||||
// and re-added to the physics engine and "easy" which just updates the body properties.
|
// and re-added to the physics engine and "easy" which just updates the body properties.
|
||||||
const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_MOTION_TYPE | EntityItem::DIRTY_SHAPE);
|
const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_MOTION_TYPE | EntityItem::DIRTY_SHAPE);
|
||||||
const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY |
|
const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY |
|
||||||
EntityItem::DIRTY_MASS | EntityItem::DIRTY_COLLISION_GROUP);
|
EntityItem::DIRTY_MASS | EntityItem::DIRTY_COLLISION_GROUP | EntityItem::DIRTY_MATERIAL);
|
||||||
|
|
||||||
// These are the set of incoming flags that the PhysicsEngine needs to hear about:
|
// These are the set of incoming flags that the PhysicsEngine needs to hear about:
|
||||||
const uint32_t DIRTY_PHYSICS_FLAGS = HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS;
|
const uint32_t DIRTY_PHYSICS_FLAGS = HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS;
|
||||||
|
@ -59,32 +59,30 @@ public:
|
||||||
static void setWorldOffset(const glm::vec3& offset);
|
static void setWorldOffset(const glm::vec3& offset);
|
||||||
static const glm::vec3& getWorldOffset();
|
static const glm::vec3& getWorldOffset();
|
||||||
|
|
||||||
static void setSimulationStep(uint32_t step);
|
// The WorldSimulationStep is a cached copy of number of SubSteps of the simulation, used for local time measurements.
|
||||||
|
static void setWorldSimulationStep(uint32_t step);
|
||||||
|
|
||||||
ObjectMotionState();
|
ObjectMotionState();
|
||||||
~ObjectMotionState();
|
~ObjectMotionState();
|
||||||
|
|
||||||
void measureAcceleration();
|
void measureBodyAcceleration();
|
||||||
void resetMeasuredAcceleration();
|
void resetMeasuredBodyAcceleration();
|
||||||
|
|
||||||
// An EASY update does not require the object to be removed and then reinserted into the PhysicsEngine
|
// An EASY update does not require the object to be removed and then reinserted into the PhysicsEngine
|
||||||
virtual void updateObjectEasy(uint32_t flags, uint32_t frame) = 0;
|
virtual void updateBodyEasy(uint32_t flags, uint32_t frame) = 0;
|
||||||
virtual void updateObjectVelocities() = 0;
|
|
||||||
|
virtual void updateBodyMaterialProperties() = 0;
|
||||||
|
virtual void updateBodyVelocities() = 0;
|
||||||
|
|
||||||
MotionStateType getType() const { return _type; }
|
MotionStateType getType() const { return _type; }
|
||||||
virtual MotionType getMotionType() const { return _motionType; }
|
virtual MotionType getMotionType() const { return _motionType; }
|
||||||
|
|
||||||
virtual void computeShapeInfo(ShapeInfo& info) = 0;
|
virtual void computeObjectShapeInfo(ShapeInfo& info) = 0;
|
||||||
virtual float computeMass(const ShapeInfo& shapeInfo) const = 0;
|
virtual float computeObjectMass(const ShapeInfo& shapeInfo) const = 0;
|
||||||
|
|
||||||
void setFriction(float friction);
|
void setBodyVelocity(const glm::vec3& velocity) const;
|
||||||
void setRestitution(float restitution);
|
void setBodyAngularVelocity(const glm::vec3& velocity) const;
|
||||||
void setLinearDamping(float damping);
|
void setBodyGravity(const glm::vec3& gravity) const;
|
||||||
void setAngularDamping(float damping);
|
|
||||||
|
|
||||||
void setVelocity(const glm::vec3& velocity) const;
|
|
||||||
void setAngularVelocity(const glm::vec3& velocity) const;
|
|
||||||
void setGravity(const glm::vec3& gravity) const;
|
|
||||||
|
|
||||||
void getVelocity(glm::vec3& velocityOut) const;
|
void getVelocity(glm::vec3& velocityOut) const;
|
||||||
void getAngularVelocity(glm::vec3& angularVelocityOut) const;
|
void getAngularVelocity(glm::vec3& angularVelocityOut) const;
|
||||||
|
@ -97,7 +95,7 @@ public:
|
||||||
virtual bool shouldSendUpdate(uint32_t simulationStep);
|
virtual bool shouldSendUpdate(uint32_t simulationStep);
|
||||||
virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame) = 0;
|
virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame) = 0;
|
||||||
|
|
||||||
virtual MotionType computeMotionType() const = 0;
|
virtual MotionType computeObjectMotionType() const = 0;
|
||||||
|
|
||||||
virtual void updateKinematicState(uint32_t substep) = 0;
|
virtual void updateKinematicState(uint32_t substep) = 0;
|
||||||
|
|
||||||
|
@ -117,18 +115,26 @@ public:
|
||||||
virtual void setShouldClaimSimulationOwnership(bool value) { }
|
virtual void setShouldClaimSimulationOwnership(bool value) { }
|
||||||
virtual bool getShouldClaimSimulationOwnership() { return false; }
|
virtual bool getShouldClaimSimulationOwnership() { return false; }
|
||||||
|
|
||||||
|
// These pure virtual methods must be implemented for each MotionState type
|
||||||
|
// and make it possible to implement more complicated methods in this base class.
|
||||||
|
|
||||||
|
virtual float getObjectRestitution() const = 0;
|
||||||
|
virtual float getObjectFriction() const = 0;
|
||||||
|
virtual float getObjectLinearDamping() const = 0;
|
||||||
|
virtual float getObjectAngularDamping() const = 0;
|
||||||
|
|
||||||
|
virtual const glm::vec3& getObjectPosition() const = 0;
|
||||||
|
virtual const glm::quat& getObjectRotation() const = 0;
|
||||||
|
virtual const glm::vec3& getObjectLinearVelocity() const = 0;
|
||||||
|
virtual const glm::vec3& getObjectAngularVelocity() const = 0;
|
||||||
|
virtual const glm::vec3& getObjectGravity() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setRigidBody(btRigidBody* body);
|
void setRigidBody(btRigidBody* body);
|
||||||
|
|
||||||
MotionStateType _type = MOTION_STATE_TYPE_UNKNOWN;
|
MotionStateType _type = MOTION_STATE_TYPE_UNKNOWN; // type of MotionState
|
||||||
|
|
||||||
// TODO: move these materials properties outside of ObjectMotionState
|
MotionType _motionType; // type of motion: KINEMATIC, DYNAMIC, or STATIC
|
||||||
float _friction;
|
|
||||||
float _restitution;
|
|
||||||
float _linearDamping;
|
|
||||||
float _angularDamping;
|
|
||||||
|
|
||||||
MotionType _motionType;
|
|
||||||
|
|
||||||
btRigidBody* _body;
|
btRigidBody* _body;
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "ShapeInfoUtil.h"
|
#include "ShapeInfoUtil.h"
|
||||||
#include "PhysicsHelpers.h"
|
#include "PhysicsHelpers.h"
|
||||||
#include "ThreadSafeDynamicsWorld.h"
|
#include "ThreadSafeDynamicsWorld.h"
|
||||||
|
#include "PhysicsLogging.h"
|
||||||
|
|
||||||
static uint32_t _numSubsteps;
|
static uint32_t _numSubsteps;
|
||||||
|
|
||||||
|
@ -172,9 +173,9 @@ void PhysicsEngine::relayIncomingChangesToSimulation() {
|
||||||
if (flags & HARD_DIRTY_PHYSICS_FLAGS) {
|
if (flags & HARD_DIRTY_PHYSICS_FLAGS) {
|
||||||
// a HARD update requires the body be pulled out of physics engine, changed, then reinserted
|
// a HARD update requires the body be pulled out of physics engine, changed, then reinserted
|
||||||
// but it also handles all EASY changes
|
// but it also handles all EASY changes
|
||||||
bool success = updateObjectHard(body, motionState, flags);
|
bool success = updateBodyHard(body, motionState, flags);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
// NOTE: since updateObjectHard() failed we know that motionState has been removed
|
// NOTE: since updateBodyHard() failed we know that motionState has been removed
|
||||||
// from simulation and body has been deleted. Depending on what else has changed
|
// from simulation and body has been deleted. Depending on what else has changed
|
||||||
// we might need to remove motionState altogether...
|
// we might need to remove motionState altogether...
|
||||||
if (flags & EntityItem::DIRTY_VELOCITY) {
|
if (flags & EntityItem::DIRTY_VELOCITY) {
|
||||||
|
@ -194,10 +195,10 @@ void PhysicsEngine::relayIncomingChangesToSimulation() {
|
||||||
} else if (flags) {
|
} else if (flags) {
|
||||||
// an EASY update does NOT require that the body be pulled out of physics engine
|
// an EASY update does NOT require that the body be pulled out of physics engine
|
||||||
// hence the MotionState has all the knowledge and authority to perform the update.
|
// hence the MotionState has all the knowledge and authority to perform the update.
|
||||||
motionState->updateObjectEasy(flags, _numSubsteps);
|
motionState->updateBodyEasy(flags, _numSubsteps);
|
||||||
}
|
}
|
||||||
if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) {
|
if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) {
|
||||||
motionState->resetMeasuredAcceleration();
|
motionState->resetMeasuredBodyAcceleration();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// the only way we should ever get here (motionState exists but no body) is when the object
|
// the only way we should ever get here (motionState exists but no body) is when the object
|
||||||
|
@ -207,7 +208,7 @@ void PhysicsEngine::relayIncomingChangesToSimulation() {
|
||||||
// it is possible that the changes are such that the object can now be added to the physical simulation
|
// it is possible that the changes are such that the object can now be added to the physical simulation
|
||||||
if (flags & EntityItem::DIRTY_SHAPE) {
|
if (flags & EntityItem::DIRTY_SHAPE) {
|
||||||
ShapeInfo shapeInfo;
|
ShapeInfo shapeInfo;
|
||||||
motionState->computeShapeInfo(shapeInfo);
|
motionState->computeObjectShapeInfo(shapeInfo);
|
||||||
btCollisionShape* shape = _shapeManager.getShape(shapeInfo);
|
btCollisionShape* shape = _shapeManager.getShape(shapeInfo);
|
||||||
if (shape) {
|
if (shape) {
|
||||||
addObject(shapeInfo, shape, motionState);
|
addObject(shapeInfo, shape, motionState);
|
||||||
|
@ -341,7 +342,7 @@ void PhysicsEngine::stepSimulation() {
|
||||||
// lock on the tree before we re-lock ourselves.
|
// lock on the tree before we re-lock ourselves.
|
||||||
//
|
//
|
||||||
// TODO: untangle these lock sequences.
|
// TODO: untangle these lock sequences.
|
||||||
ObjectMotionState::setSimulationStep(_numSubsteps);
|
ObjectMotionState::setWorldSimulationStep(_numSubsteps);
|
||||||
_entityTree->lockForWrite();
|
_entityTree->lockForWrite();
|
||||||
lock();
|
lock();
|
||||||
_dynamicsWorld->synchronizeMotionStates();
|
_dynamicsWorld->synchronizeMotionStates();
|
||||||
|
@ -498,7 +499,7 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap
|
||||||
btVector3 inertia(0.0f, 0.0f, 0.0f);
|
btVector3 inertia(0.0f, 0.0f, 0.0f);
|
||||||
float mass = 0.0f;
|
float mass = 0.0f;
|
||||||
btRigidBody* body = NULL;
|
btRigidBody* body = NULL;
|
||||||
switch(motionState->computeMotionType()) {
|
switch(motionState->computeObjectMotionType()) {
|
||||||
case MOTION_TYPE_KINEMATIC: {
|
case MOTION_TYPE_KINEMATIC: {
|
||||||
body = new btRigidBody(mass, motionState, shape, inertia);
|
body = new btRigidBody(mass, motionState, shape, inertia);
|
||||||
body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
|
body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
|
||||||
|
@ -511,13 +512,13 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MOTION_TYPE_DYNAMIC: {
|
case MOTION_TYPE_DYNAMIC: {
|
||||||
mass = motionState->computeMass(shapeInfo);
|
mass = motionState->computeObjectMass(shapeInfo);
|
||||||
shape->calculateLocalInertia(mass, inertia);
|
shape->calculateLocalInertia(mass, inertia);
|
||||||
body = new btRigidBody(mass, motionState, shape, inertia);
|
body = new btRigidBody(mass, motionState, shape, inertia);
|
||||||
body->updateInertiaTensor();
|
body->updateInertiaTensor();
|
||||||
motionState->setRigidBody(body);
|
motionState->setRigidBody(body);
|
||||||
motionState->setKinematic(false, _numSubsteps);
|
motionState->setKinematic(false, _numSubsteps);
|
||||||
motionState->updateObjectVelocities();
|
motionState->updateBodyVelocities();
|
||||||
// NOTE: Bullet will deactivate any object whose velocity is below these thresholds for longer than 2 seconds.
|
// NOTE: Bullet will deactivate any object whose velocity is below these thresholds for longer than 2 seconds.
|
||||||
// (the 2 seconds is determined by: static btRigidBody::gDeactivationTime
|
// (the 2 seconds is determined by: static btRigidBody::gDeactivationTime
|
||||||
const float DYNAMIC_LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec
|
const float DYNAMIC_LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec
|
||||||
|
@ -540,11 +541,10 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
body->setFlags(BT_DISABLE_WORLD_GRAVITY);
|
body->setFlags(BT_DISABLE_WORLD_GRAVITY);
|
||||||
body->setRestitution(motionState->_restitution);
|
motionState->updateBodyMaterialProperties();
|
||||||
body->setFriction(motionState->_friction);
|
|
||||||
body->setDamping(motionState->_linearDamping, motionState->_angularDamping);
|
|
||||||
_dynamicsWorld->addRigidBody(body);
|
_dynamicsWorld->addRigidBody(body);
|
||||||
motionState->resetMeasuredAcceleration();
|
motionState->resetMeasuredBodyAcceleration();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsEngine::bump(EntityItem* bumpEntity) {
|
void PhysicsEngine::bump(EntityItem* bumpEntity) {
|
||||||
|
@ -608,8 +608,8 @@ void PhysicsEngine::removeObjectFromBullet(ObjectMotionState* motionState) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// private
|
// private
|
||||||
bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) {
|
bool PhysicsEngine::updateBodyHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) {
|
||||||
MotionType newType = motionState->computeMotionType();
|
MotionType newType = motionState->computeObjectMotionType();
|
||||||
|
|
||||||
// pull body out of physics engine
|
// pull body out of physics engine
|
||||||
_dynamicsWorld->removeRigidBody(body);
|
_dynamicsWorld->removeRigidBody(body);
|
||||||
|
@ -621,7 +621,7 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio
|
||||||
// get new shape
|
// get new shape
|
||||||
btCollisionShape* oldShape = body->getCollisionShape();
|
btCollisionShape* oldShape = body->getCollisionShape();
|
||||||
ShapeInfo shapeInfo;
|
ShapeInfo shapeInfo;
|
||||||
motionState->computeShapeInfo(shapeInfo);
|
motionState->computeObjectShapeInfo(shapeInfo);
|
||||||
btCollisionShape* newShape = _shapeManager.getShape(shapeInfo);
|
btCollisionShape* newShape = _shapeManager.getShape(shapeInfo);
|
||||||
if (!newShape) {
|
if (!newShape) {
|
||||||
// FAIL! we are unable to support these changes!
|
// FAIL! we are unable to support these changes!
|
||||||
|
@ -640,7 +640,7 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio
|
||||||
_shapeManager.releaseShape(oldShape);
|
_shapeManager.releaseShape(oldShape);
|
||||||
|
|
||||||
// compute mass properties
|
// compute mass properties
|
||||||
float mass = motionState->computeMass(shapeInfo);
|
float mass = motionState->computeObjectMass(shapeInfo);
|
||||||
btVector3 inertia(0.0f, 0.0f, 0.0f);
|
btVector3 inertia(0.0f, 0.0f, 0.0f);
|
||||||
body->getCollisionShape()->calculateLocalInertia(mass, inertia);
|
body->getCollisionShape()->calculateLocalInertia(mass, inertia);
|
||||||
body->setMassProps(mass, inertia);
|
body->setMassProps(mass, inertia);
|
||||||
|
@ -653,7 +653,7 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio
|
||||||
}
|
}
|
||||||
bool easyUpdate = flags & EASY_DIRTY_PHYSICS_FLAGS;
|
bool easyUpdate = flags & EASY_DIRTY_PHYSICS_FLAGS;
|
||||||
if (easyUpdate) {
|
if (easyUpdate) {
|
||||||
motionState->updateObjectEasy(flags, _numSubsteps);
|
motionState->updateBodyEasy(flags, _numSubsteps);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the motion parameters
|
// update the motion parameters
|
||||||
|
@ -675,8 +675,8 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio
|
||||||
if (! (flags & EntityItem::DIRTY_MASS)) {
|
if (! (flags & EntityItem::DIRTY_MASS)) {
|
||||||
// always update mass properties when going dynamic (unless it's already been done above)
|
// always update mass properties when going dynamic (unless it's already been done above)
|
||||||
ShapeInfo shapeInfo;
|
ShapeInfo shapeInfo;
|
||||||
motionState->computeShapeInfo(shapeInfo);
|
motionState->computeObjectShapeInfo(shapeInfo);
|
||||||
float mass = motionState->computeMass(shapeInfo);
|
float mass = motionState->computeObjectMass(shapeInfo);
|
||||||
btVector3 inertia(0.0f, 0.0f, 0.0f);
|
btVector3 inertia(0.0f, 0.0f, 0.0f);
|
||||||
body->getCollisionShape()->calculateLocalInertia(mass, inertia);
|
body->getCollisionShape()->calculateLocalInertia(mass, inertia);
|
||||||
body->setMassProps(mass, inertia);
|
body->setMassProps(mass, inertia);
|
||||||
|
|
|
@ -39,8 +39,8 @@ public:
|
||||||
ContactKey(void* a, void* b) : _a(a), _b(b) {}
|
ContactKey(void* a, void* b) : _a(a), _b(b) {}
|
||||||
bool operator<(const ContactKey& other) const { return _a < other._a || (_a == other._a && _b < other._b); }
|
bool operator<(const ContactKey& other) const { return _a < other._a || (_a == other._a && _b < other._b); }
|
||||||
bool operator==(const ContactKey& other) const { return _a == other._a && _b == other._b; }
|
bool operator==(const ContactKey& other) const { return _a == other._a && _b == other._b; }
|
||||||
void* _a;
|
void* _a; // EntityMotionState pointer
|
||||||
void* _b;
|
void* _b; // EntityMotionState pointer
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<ContactKey, ContactInfo> ContactMap;
|
typedef std::map<ContactKey, ContactInfo> ContactMap;
|
||||||
|
@ -100,7 +100,7 @@ private:
|
||||||
void doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB);
|
void doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB);
|
||||||
|
|
||||||
// return 'true' of update was successful
|
// return 'true' of update was successful
|
||||||
bool updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags);
|
bool updateBodyHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags);
|
||||||
void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags);
|
void updateObjectEasy(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags);
|
||||||
|
|
||||||
btClock _clock;
|
btClock _clock;
|
||||||
|
|
|
@ -426,12 +426,12 @@ bool Model::updateGeometry() {
|
||||||
_dilatedTextures.clear();
|
_dilatedTextures.clear();
|
||||||
_geometry = geometry;
|
_geometry = geometry;
|
||||||
_meshGroupsKnown = false;
|
_meshGroupsKnown = false;
|
||||||
setJointStates(newJointStates);
|
initJointStates(newJointStates);
|
||||||
needToRebuild = true;
|
needToRebuild = true;
|
||||||
} else if (_jointStates.isEmpty()) {
|
} else if (_jointStates.isEmpty()) {
|
||||||
const FBXGeometry& fbxGeometry = geometry->getFBXGeometry();
|
const FBXGeometry& fbxGeometry = geometry->getFBXGeometry();
|
||||||
if (fbxGeometry.joints.size() > 0) {
|
if (fbxGeometry.joints.size() > 0) {
|
||||||
setJointStates(createJointStates(fbxGeometry));
|
initJointStates(createJointStates(fbxGeometry));
|
||||||
needToRebuild = true;
|
needToRebuild = true;
|
||||||
}
|
}
|
||||||
} else if (!geometry->isLoaded()) {
|
} else if (!geometry->isLoaded()) {
|
||||||
|
@ -469,7 +469,7 @@ bool Model::updateGeometry() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
void Model::setJointStates(QVector<JointState> states) {
|
void Model::initJointStates(QVector<JointState> states) {
|
||||||
_jointStates = states;
|
_jointStates = states;
|
||||||
initJointTransforms();
|
initJointTransforms();
|
||||||
|
|
||||||
|
|
|
@ -244,7 +244,7 @@ protected:
|
||||||
// returns 'true' if needs fullUpdate after geometry change
|
// returns 'true' if needs fullUpdate after geometry change
|
||||||
bool updateGeometry();
|
bool updateGeometry();
|
||||||
|
|
||||||
virtual void setJointStates(QVector<JointState> states);
|
virtual void initJointStates(QVector<JointState> states);
|
||||||
|
|
||||||
void setScaleInternal(const glm::vec3& scale);
|
void setScaleInternal(const glm::vec3& scale);
|
||||||
void scaleToFit();
|
void scaleToFit();
|
||||||
|
|
|
@ -19,19 +19,10 @@
|
||||||
|
|
||||||
|
|
||||||
QString& PathUtils::resourcesPath() {
|
QString& PathUtils::resourcesPath() {
|
||||||
#ifdef DEBUG
|
|
||||||
static QString staticResourcePath;
|
|
||||||
if (staticResourcePath.isEmpty()) {
|
|
||||||
QDir path(__FILE__);
|
|
||||||
path.cdUp();
|
|
||||||
staticResourcePath = path.cleanPath(path.absoluteFilePath("../../../interface/resources/")) + "/";
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/../Resources/";
|
static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/../Resources/";
|
||||||
#else
|
#else
|
||||||
static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/resources/";
|
static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/resources/";
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return staticResourcePath;
|
return staticResourcePath;
|
||||||
|
|
|
@ -426,7 +426,6 @@ void OffscreenUi::toggle(const QUrl& url, const QString& name, std::function<voi
|
||||||
item = _rootItem->findChild<QQuickItem*>(name);
|
item = _rootItem->findChild<QQuickItem*>(name);
|
||||||
}
|
}
|
||||||
if (item) {
|
if (item) {
|
||||||
qDebug() << "Turning item " << !item->isEnabled();
|
|
||||||
item->setEnabled(!item->isEnabled());
|
item->setEnabled(!item->isEnabled());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ private:
|
||||||
qmlObject->setUserData(USER_DATA_ID, this);
|
qmlObject->setUserData(USER_DATA_ID, this);
|
||||||
qmlObject->setObjectName(uuid.toString());
|
qmlObject->setObjectName(uuid.toString());
|
||||||
// Make sure we can find it again in the future
|
// Make sure we can find it again in the future
|
||||||
Q_ASSERT(VrMenu::instance()->findMenuObject(uuid.toString()));
|
Q_ASSERT(VrMenu::_instance->findMenuObject(uuid.toString()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -57,14 +57,25 @@ HIFI_QML_DEF_LAMBDA(VrMenu, [&](QQmlContext* context, QObject* newItem) {
|
||||||
});
|
});
|
||||||
|
|
||||||
VrMenu* VrMenu::_instance{ nullptr };
|
VrMenu* VrMenu::_instance{ nullptr };
|
||||||
|
static QQueue<std::function<void(VrMenu*)>> queuedLambdas;
|
||||||
|
|
||||||
VrMenu* VrMenu::instance() {
|
void VrMenu::executeOrQueue(std::function<void(VrMenu*)> f) {
|
||||||
if (!_instance) {
|
if (_instance) {
|
||||||
VrMenu::registerType();
|
foreach(std::function<void(VrMenu*)> priorLambda, queuedLambdas) {
|
||||||
VrMenu::load();
|
priorLambda(_instance);
|
||||||
Q_ASSERT(_instance);
|
}
|
||||||
|
f(_instance);
|
||||||
|
} else {
|
||||||
|
queuedLambdas.push_back(f);
|
||||||
}
|
}
|
||||||
return _instance;
|
}
|
||||||
|
|
||||||
|
void VrMenu::executeQueuedLambdas() {
|
||||||
|
Q_ASSERT(_instance);
|
||||||
|
foreach(std::function<void(VrMenu*)> f, queuedLambdas) {
|
||||||
|
f(_instance);
|
||||||
|
}
|
||||||
|
queuedLambdas.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
VrMenu::VrMenu(QQuickItem* parent) : QQuickItem(parent) {
|
VrMenu::VrMenu(QQuickItem* parent) : QQuickItem(parent) {
|
||||||
|
@ -72,6 +83,7 @@ VrMenu::VrMenu(QQuickItem* parent) : QQuickItem(parent) {
|
||||||
this->setEnabled(false);
|
this->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// QML helper functions
|
// QML helper functions
|
||||||
QObject* addMenu(QObject* parent, const QString& text) {
|
QObject* addMenu(QObject* parent, const QString& text) {
|
||||||
// FIXME add more checking here to ensure no name conflicts
|
// FIXME add more checking here to ensure no name conflicts
|
||||||
|
|
|
@ -26,7 +26,8 @@ class VrMenu : public QQuickItem {
|
||||||
HIFI_QML_DECL_LAMBDA
|
HIFI_QML_DECL_LAMBDA
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static VrMenu* instance();
|
static void executeOrQueue(std::function<void(VrMenu*)> f);
|
||||||
|
static void executeQueuedLambdas();
|
||||||
VrMenu(QQuickItem* parent = nullptr);
|
VrMenu(QQuickItem* parent = nullptr);
|
||||||
void addMenu(QMenu* menu);
|
void addMenu(QMenu* menu);
|
||||||
void addAction(QMenu* parent, QAction* action);
|
void addAction(QMenu* parent, QAction* action);
|
||||||
|
|
|
@ -358,7 +358,7 @@ public:
|
||||||
#else
|
#else
|
||||||
offscreenUi->setBaseUrl(QUrl::fromLocalFile(getQmlDir()));
|
offscreenUi->setBaseUrl(QUrl::fromLocalFile(getQmlDir()));
|
||||||
offscreenUi->load(QUrl("TestRoot.qml"));
|
offscreenUi->load(QUrl("TestRoot.qml"));
|
||||||
offscreenUi->load(QUrl("InterfaceMenu.qml"));
|
offscreenUi->load(QUrl("TestMenu.qml"));
|
||||||
// Requires a root menu to have been loaded before it can load
|
// Requires a root menu to have been loaded before it can load
|
||||||
VrMenu::load();
|
VrMenu::load();
|
||||||
#endif
|
#endif
|
||||||
|
@ -481,7 +481,7 @@ void QTestWindow::renderQml() {
|
||||||
|
|
||||||
|
|
||||||
const char * LOG_FILTER_RULES = R"V0G0N(
|
const char * LOG_FILTER_RULES = R"V0G0N(
|
||||||
*.debug=false
|
hifi.offscreen.focus.debug=false
|
||||||
qt.quick.mouse.debug=false
|
qt.quick.mouse.debug=false
|
||||||
)V0G0N";
|
)V0G0N";
|
||||||
|
|
||||||
|
@ -495,7 +495,7 @@ qt.quick.mouse.debug=false
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
QGuiApplication app(argc, argv);
|
QGuiApplication app(argc, argv);
|
||||||
// QLoggingCategory::setFilterRules(LOG_FILTER_RULES);
|
QLoggingCategory::setFilterRules(LOG_FILTER_RULES);
|
||||||
QTestWindow window;
|
QTestWindow window;
|
||||||
app.exec();
|
app.exec();
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in a new issue