Merge branch 'vr_menus' into infoview

This commit is contained in:
Brad Davis 2015-04-27 18:33:45 -07:00
commit 7bd8bbf565
26 changed files with 386 additions and 330 deletions

View file

@ -4,12 +4,16 @@ import "controls"
import "styles" import "styles"
Dialog { Dialog {
id: root
HifiConstants { id: hifi }
title: "Go to..." title: "Go to..."
objectName: "AddressBarDialog" objectName: "AddressBarDialog"
height: 128 contentImplicitWidth: addressBarDialog.implicitWidth
width: 512 contentImplicitHeight: addressBarDialog.implicitHeight
destroyOnCloseButton: false destroyOnCloseButton: false
onVisibleChanged: { onVisibleChanged: {
if (!visible) { if (!visible) {
reset(); reset();
@ -21,6 +25,11 @@ Dialog {
addressLine.forceActiveFocus(); addressLine.forceActiveFocus();
} }
} }
onParentChanged: {
if (enabled && visible) {
addressLine.forceActiveFocus();
}
}
function reset() { function reset() {
addressLine.text = "" addressLine.text = ""
@ -29,24 +38,26 @@ Dialog {
AddressBarDialog { AddressBarDialog {
id: addressBarDialog id: addressBarDialog
// The client area // The client area
anchors.fill: parent x: root.clientX
anchors.margins: parent.margins y: root.clientY
anchors.topMargin: parent.topMargin implicitWidth: 512
implicitHeight: border.height + hifi.layout.spacing * 4
Border { Border {
id: border
height: 64 height: 64
anchors.left: parent.left anchors.left: parent.left
anchors.leftMargin: 0 anchors.leftMargin: hifi.layout.spacing * 2
anchors.right: goButton.left anchors.right: goButton.left
anchors.rightMargin: 8 anchors.rightMargin: hifi.layout.spacing
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
TextInput { TextInput {
id: addressLine id: addressLine
anchors.fill: parent anchors.fill: parent
helperText: "domain, location, @user, /x,y,z" helperText: "domain, location, @user, /x,y,z"
anchors.margins: 8 anchors.margins: hifi.layout.spacing
onAccepted: { onAccepted: {
event.accepted event.accepted
addressBarDialog.loadAddress(addressLine.text) addressBarDialog.loadAddress(addressLine.text)
@ -59,7 +70,7 @@ Dialog {
width: 32 width: 32
height: 32 height: 32
anchors.right: parent.right anchors.right: parent.right
anchors.rightMargin: 8 anchors.rightMargin: hifi.layout.spacing * 2
source: "../images/address-bar-submit.svg" source: "../images/address-bar-submit.svg"
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter

View file

@ -60,9 +60,6 @@ Dialog {
anchors.margins: 8 anchors.margins: 8
KeyNavigation.tab: password KeyNavigation.tab: password
KeyNavigation.backtab: password KeyNavigation.backtab: password
onAccepted: {
password.forceActiveFocus()
}
} }
} }
@ -78,13 +75,6 @@ Dialog {
anchors.margins: 8 anchors.margins: 8
KeyNavigation.tab: username KeyNavigation.tab: username
KeyNavigation.backtab: username KeyNavigation.backtab: username
onAccepted: {
if (username.text == "") {
username.forceActiveFocus()
} else {
loginDialog.login(username.text, password.text)
}
}
onFocusChanged: { onFocusChanged: {
if (password.focus) { if (password.focus) {
password.selectAll() password.selectAll()
@ -187,4 +177,22 @@ Dialog {
} }
} }
} }
Keys.onPressed: {
switch(event.key) {
case Qt.Key_Enter:
case Qt.Key_Return:
if (username.activeFocus) {
event.accepted = true
password.forceActiveFocus()
} else if (password.activeFocus) {
event.accepted = true
if (username.text == "") {
username.forceActiveFocus()
} else {
loginDialog.login(username.text, password.text)
}
}
break;
}
}
} }

View file

@ -3,71 +3,51 @@ import QtQuick 2.2
import QtQuick.Controls 1.2 import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.2 import QtQuick.Dialogs 1.2
import "controls" import "controls"
import "styles"
Dialog { Dialog {
id: root id: root
property real spacing: 8 HifiConstants { id: hifi }
property real outerSpacing: 16 property real spacing: hifi.layout.spacing
property real outerSpacing: hifi.layout.spacing * 2
destroyOnCloseButton: true destroyOnCloseButton: true
destroyOnInvisible: true destroyOnInvisible: true
implicitHeight: content.implicitHeight + outerSpacing * 2 + 48 contentImplicitWidth: content.implicitWidth
implicitWidth: Math.min(200, Math.max(mainText.implicitWidth, content.buttonsRowImplicitWidth) + outerSpacing * 2); contentImplicitHeight: content.implicitHeight
onImplicitHeightChanged: root.height = implicitHeight
onImplicitWidthChanged: root.width = implicitWidth
function calculateImplicitWidth() {
if (buttons.visibleChildren.length < 2)
return;
var calcWidth = 0;
for (var i = 0; i < buttons.visibleChildren.length; ++i) {
calcWidth += Math.max(100, buttons.visibleChildren[i].implicitWidth) + root.spacing
}
content.buttonsRowImplicitWidth = outerSpacing + calcWidth + 48
}
Component.onCompleted: { Component.onCompleted: {
enabled = true enabled = true
} }
onEnabledChanged: { onParentChanged: {
if (enabled) { if (visible && enabled) {
root.forceActiveFocus(); forceActiveFocus();
} }
} }
Hifi.MessageDialog { Hifi.MessageDialog {
id: content id: content
clip: true clip: true
anchors.fill: parent
anchors.topMargin: parent.topMargin + root.outerSpacing
anchors.leftMargin: parent.margins + root.outerSpacing
anchors.rightMargin: parent.margins + root.outerSpacing
anchors.bottomMargin: parent.margins + root.outerSpacing
implicitHeight: contentColumn.implicitHeight + outerSpacing * 2
implicitWidth: Math.max(mainText.implicitWidth, buttonsRowImplicitWidth);
property real buttonsRowImplicitWidth: Screen.pixelDensity * 50
onImplicitWidthChanged: root.width = implicitWidth x: root.clientX
y: root.clientY
implicitHeight: contentColumn.implicitHeight + outerSpacing * 2
implicitWidth: mainText.implicitWidth + outerSpacing * 2
Component.onCompleted: { Component.onCompleted: {
root.title = title root.title = title
} }
onTitleChanged: { onTitleChanged: {
root.title = title root.title = title
} }
Column { Column {
anchors.fill: parent
anchors.margins: 8
id: contentColumn id: contentColumn
spacing: root.outerSpacing spacing: root.outerSpacing
anchors {
top: parent.top
left: parent.left
right: parent.right
}
Item { Item {
width: parent.width width: parent.width
@ -83,7 +63,7 @@ Dialog {
horizontalAlignment: Text.AlignLeft horizontalAlignment: Text.AlignLeft
color: iconColor() color: iconColor()
text: iconSymbol() text: iconSymbol()
function iconSymbol() { function iconSymbol() {
switch (content.icon) { switch (content.icon) {
case Hifi.MessageDialog.Information: case Hifi.MessageDialog.Information:
@ -262,7 +242,6 @@ Dialog {
onClicked: content.click(StandardButton.Help) onClicked: content.click(StandardButton.Help)
visible: content.standardButtons & StandardButton.Help visible: content.standardButtons & StandardButton.Help
} }
onVisibleChildrenChanged: root.calculateImplicitWidth()
} }
} }
@ -319,6 +298,7 @@ Dialog {
] ]
} }
Keys.onPressed: { Keys.onPressed: {
if (event.modifiers === Qt.ControlModifier) if (event.modifiers === Qt.ControlModifier)
switch (event.key) { switch (event.key) {

View file

@ -50,6 +50,7 @@ Hifi.VrMenu {
property var menuBuilder: Component { property var menuBuilder: Component {
Border { Border {
HifiConstants { id: hifi }
Component.onCompleted: { Component.onCompleted: {
menuDepth = root.models.length - 1 menuDepth = root.models.length - 1
if (menuDepth == 0) { if (menuDepth == 0) {
@ -64,207 +65,181 @@ Hifi.VrMenu {
border.color: hifi.colors.hifiBlue border.color: hifi.colors.hifiBlue
color: hifi.colors.window color: hifi.colors.window
property int menuDepth property int menuDepth
/* implicitHeight: listView.implicitHeight + 16
MouseArea { implicitWidth: listView.implicitWidth + 16
// Rectangle { anchors.fill: parent; color: "#7f0000FF"; visible: enabled }
anchors.fill: parent
onClicked: {
while (parent.menuDepth != root.models.length - 1) {
root.popColumn()
}
}
}
*/
ListView { Column {
spacing: 6
property int outerMargin: 8
property real minWidth: 0
anchors.fill: parent
anchors.margins: outerMargin
id: listView id: listView
height: root.height property real minWidth: 0
anchors {
onCountChanged: { top: parent.top
recalculateSize() topMargin: 8
left: parent.left
leftMargin: 8
right: parent.right
rightMargin: 8
} }
function recalculateSize() { Repeater {
var newHeight = 0 model: root.models[menuDepth]
var newWidth = minWidth; delegate: Loader {
for (var i = 0; i < children.length; ++i) { id: loader
var item = children[i]; sourceComponent: root.itemBuilder
if (!item.visible) { Binding {
continue target: loader.item
} property: "root"
newHeight += item.height value: root
when: loader.status == Loader.Ready
}
Binding {
target: loader.item
property: "source"
value: modelData
when: loader.status == Loader.Ready
}
Binding {
target: loader.item
property: "border"
value: listView.parent
when: loader.status == Loader.Ready
}
Binding {
target: loader.item
property: "listView"
value: listView
when: loader.status == Loader.Ready
}
} }
parent.height = newHeight + outerMargin * 2;
parent.width = newWidth + outerMargin * 2
}
highlight: Rectangle {
width: listView.minWidth - 32;
height: 32
color: hifi.colors.hifiBlue
y: (listView.currentItem) ? listView.currentItem.y : 0;
x: 32
Behavior on y {
NumberAnimation {
duration: 100
easing.type: Easing.InOutQuint
}
}
}
model: root.models[menuDepth]
delegate: Loader {
id: loader
sourceComponent: root.itemBuilder
Binding {
target: loader.item
property: "root"
value: root
when: loader.status == Loader.Ready
}
Binding {
target: loader.item
property: "source"
value: modelData
when: loader.status == Loader.Ready
}
Binding {
target: loader.item
property: "listView"
value: listView
when: loader.status == Loader.Ready
}
} }
} }
} }
} }
property var itemBuilder: Component { property var itemBuilder: Component {
Text { Item {
id: thisText
x: 32
property var source property var source
property var root property var root
property var listView property var listView
text: typedText() property var border
height: implicitHeight implicitHeight: row.implicitHeight + 4
width: implicitWidth implicitWidth: row.implicitWidth + label.height
color: source.enabled ? hifi.colors.text : hifi.colors.disabledText
enabled: source.enabled && source.visible
// FIXME uncommenting this line results in menus that have blank spots // FIXME uncommenting this line results in menus that have blank spots
// rather than having the correct size // rather than having the correct size
// visible: source.visible // visible: source.visible
Row {
onListViewChanged: { id: row
if (listView) { spacing: 4
listView.minWidth = Math.max(listView.minWidth, implicitWidth + 64); anchors {
listView.recalculateSize(); top: parent.top
topMargin: 2
} }
} FontAwesome {
id: check
size: label.height
text: checkText()
color: label.color
function checkText() {
if (!source || source.type != 1 || !source.checkable) {
return "";
}
onVisibleChanged: { // FIXME this works for native QML menus but I don't think it will
if (listView) { // for proxied QML menus
listView.recalculateSize(); if (source.exclusiveGroup) {
} return source.checked ? "\uF05D" : "\uF10C"
} }
return source.checked ? "\uF046" : "\uF096"
onImplicitWidthChanged: {
if (listView) {
listView.minWidth = Math.max(listView.minWidth, implicitWidth + 64);
listView.recalculateSize();
}
}
FontAwesome {
visible: source.type == 1 && source.checkable
x: -32
text: checkText();
color: parent.color
function checkText() {
if (source.type != 1) {
return;
} }
// FIXME this works for native QML menus but I don't think it will
// for proxied QML menus
if (source.exclusiveGroup) {
return source.checked ? "\uF05D" : "\uF10C"
}
return source.checked ? "\uF046" : "\uF096"
} }
} Text {
id: label
text: typedText()
color: source.enabled ? hifi.colors.text : hifi.colors.disabledText
enabled: source.enabled && source.visible
function typedText() {
if (source) {
switch(source.type) {
case 2:
return source.title;
case 1:
return source.text;
case 0:
return "-----"
}
}
return ""
}
}
} // row
FontAwesome { FontAwesome {
visible: source.type == 2 anchors {
x: listView.width - 32 - (hifi.layout.spacing * 2) top: row.top
text: "\uF0DA" }
color: parent.color id: tag
} size: label.height
width: implicitWidth
function typedText() { visible: source.type == 2
switch(source.type) { x: listView.width - width - 4
case 2: text: "\uF0DA"
return source.title; color: label.color
case 1: }
return source.text;
case 0:
return "-----"
}
}
MouseArea { MouseArea {
id: mouseArea anchors {
acceptedButtons: Qt.LeftButton top: parent.top
anchors.left: parent.left bottom: parent.bottom
anchors.leftMargin: -32 left: parent.left
anchors.bottom: parent.bottom right: tag.right
anchors.bottomMargin: 0 }
anchors.top: parent.top acceptedButtons: Qt.LeftButton
anchors.topMargin: 0 hoverEnabled: true
width: listView.width Rectangle {
hoverEnabled: true id: highlight
Timer { visible: false
id: timer anchors.fill: parent
interval: 1000 color: "#7f0e7077"
onTriggered: parent.select(); }
} Timer {
/* id: timer
* Uncomment below to have menus auto-popup interval: 1000
* onTriggered: parent.select();
* FIXME if we enabled timer based menu popup, either the timer has }
* to be very very short or after auto popup there has to be a small onEntered: {
* amount of time, or a test if the mouse has moved before a click /*
* will be accepted, otherwise it's too easy to accidently click on * Uncomment below to have menus auto-popup
* something immediately after the auto-popup appears underneath your *
* cursor * FIXME if we enabled timer based menu popup, either the timer has
* * to be very very short or after auto popup there has to be a small
*/ * amount of time, or a test if the mouse has moved before a click
//onEntered: { * will be accepted, otherwise it's too easy to accidently click on
// if (source.type == 2 && enabled) { * something immediately after the auto-popup appears underneath your
// timer.start() * cursor
// } *
//} */
//onExited: { //if (source.type == 2 && enabled) {
// timer.stop() // timer.start()
//} //}
onClicked: { highlight.visible = source.enabled
select(); }
} onExited: {
function select() { timer.stop()
timer.stop(); highlight.visible = false
var popped = false; }
while (columns.length - 1 > listView.parent.menuDepth) { onClicked: {
popColumn(); select();
popped = true; }
} function select() {
//timer.stop();
var popped = false;
while (columns.length - 1 > listView.parent.menuDepth) {
popColumn();
popped = true;
}
if (!popped || source.type != 1) { if (!popped || source.type != 1) {
parent.root.selectItem(parent.source); parent.root.selectItem(parent.source);
} }
} }
} }
} }

View file

@ -6,13 +6,15 @@ import "../styles"
Item { Item {
id: root id: root
HifiConstants { id: hifi } HifiConstants { id: hifi }
implicitHeight: 512 implicitHeight: contentImplicitHeight + titleBorder.height + hifi.styles.borderWidth
implicitWidth: 512 implicitWidth: contentImplicitWidth + hifi.styles.borderWidth * 2
property string title property string title
property int titleSize: titleBorder.height + 12 property int titleSize: titleBorder.height + 12
property string frameColor: hifi.colors.hifiBlue property string frameColor: hifi.colors.hifiBlue
property string backgroundColor: hifi.colors.dialogBackground property string backgroundColor: hifi.colors.dialogBackground
property bool active: false property bool active: false
property real contentImplicitWidth: 800
property real contentImplicitHeight: 800
property alias titleBorder: titleBorder property alias titleBorder: titleBorder
readonly property alias titleX: titleBorder.x readonly property alias titleX: titleBorder.x

View file

@ -182,8 +182,6 @@ const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::D
const QString DEFAULT_SCRIPTS_JS_URL = "http://s3.amazonaws.com/hifi-public/scripts/defaultScripts.js"; const QString DEFAULT_SCRIPTS_JS_URL = "http://s3.amazonaws.com/hifi-public/scripts/defaultScripts.js";
bool renderCollisionHulls = false;
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
class MyNativeEventFilter : public QAbstractNativeEventFilter { class MyNativeEventFilter : public QAbstractNativeEventFilter {
public: public:
@ -1314,11 +1312,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
break; break;
} }
case Qt::Key_Comma: {
renderCollisionHulls = !renderCollisionHulls;
break;
}
default: default:
event->ignore(); event->ignore();
break; break;
@ -3157,13 +3150,21 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
PerformanceTimer perfTimer("entities"); PerformanceTimer perfTimer("entities");
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::displaySide() ... entities..."); "Application::displaySide() ... entities...");
if (renderCollisionHulls) {
_entities.render(RenderArgs::DEBUG_RENDER_MODE, renderSide); RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE;
} else if (theCamera.getMode() == CAMERA_MODE_MIRROR) { RenderArgs::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE;
_entities.render(RenderArgs::MIRROR_RENDER_MODE, renderSide);
} else { if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls)) {
_entities.render(RenderArgs::DEFAULT_RENDER_MODE, renderSide); renderDebugFlags = (RenderArgs::DebugFlags) (renderDebugFlags | (int) RenderArgs::RENDER_DEBUG_HULLS);
} }
if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowOwned)) {
renderDebugFlags =
(RenderArgs::DebugFlags) (renderDebugFlags | (int) RenderArgs::RENDER_DEBUG_SIMULATION_OWNERSHIP);
}
if (theCamera.getMode() == CAMERA_MODE_MIRROR) {
renderMode = RenderArgs::MIRROR_RENDER_MODE;
}
_entities.render(renderMode, renderSide, renderDebugFlags);
} }
// render JS/scriptable overlays // render JS/scriptable overlays

View file

@ -548,6 +548,11 @@ Menu::Menu() {
statsRenderer.data(), statsRenderer.data(),
SLOT(toggleShowInjectedStreams())); SLOT(toggleShowInjectedStreams()));
MenuWrapper* physicsOptionsMenu = developerMenu->addMenu("Physics");
addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowOwned);
addCheckableActionToQMenuAndActionHash(physicsOptionsMenu, MenuOption::PhysicsShowHulls);
MenuWrapper* helpMenu = addMenu("Help"); MenuWrapper* helpMenu = addMenu("Help");
addActionToQMenuAndActionHash(helpMenu, MenuOption::EditEntitiesHelp, 0, qApp, SLOT(showEditEntitiesHelp())); addActionToQMenuAndActionHash(helpMenu, MenuOption::EditEntitiesHelp, 0, qApp, SLOT(showEditEntitiesHelp()));

View file

@ -216,6 +216,8 @@ namespace MenuOption {
const QString OnlyDisplayTopTen = "Only Display Top Ten"; const QString OnlyDisplayTopTen = "Only Display Top Ten";
const QString PackageModel = "Package Model..."; const QString PackageModel = "Package Model...";
const QString Pair = "Pair"; const QString Pair = "Pair";
const QString PhysicsShowOwned = "Highlight Simulation Ownership";
const QString PhysicsShowHulls = "Draw Collision Hulls";
const QString PipelineWarnings = "Log Render Pipeline Warnings"; const QString PipelineWarnings = "Log Render Pipeline Warnings";
const QString Preferences = "Preferences..."; const QString Preferences = "Preferences...";
const QString Quit = "Quit"; const QString Quit = "Quit";

View file

@ -90,7 +90,7 @@ void Overlays::renderHUD() {
RenderArgs args = { NULL, Application::getInstance()->getViewFrustum(), RenderArgs args = { NULL, Application::getInstance()->getViewFrustum(),
lodManager->getOctreeSizeScale(), lodManager->getOctreeSizeScale(),
lodManager->getBoundaryLevelAdjust(), lodManager->getBoundaryLevelAdjust(),
RenderArgs::DEFAULT_RENDER_MODE, RenderArgs::MONO, RenderArgs::DEFAULT_RENDER_MODE, RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
foreach(Overlay* thisOverlay, _overlaysHUD) { foreach(Overlay* thisOverlay, _overlaysHUD) {
@ -108,7 +108,10 @@ void Overlays::renderHUD() {
} }
} }
void Overlays::renderWorld(bool drawFront, RenderArgs::RenderMode renderMode, RenderArgs::RenderSide renderSide) { void Overlays::renderWorld(bool drawFront,
RenderArgs::RenderMode renderMode,
RenderArgs::RenderSide renderSide,
RenderArgs::DebugFlags renderDebugFlags) {
QReadLocker lock(&_lock); QReadLocker lock(&_lock);
if (_overlaysWorld.size() == 0) { if (_overlaysWorld.size() == 0) {
return; return;
@ -125,7 +128,7 @@ void Overlays::renderWorld(bool drawFront, RenderArgs::RenderMode renderMode, Re
RenderArgs args = { NULL, Application::getInstance()->getDisplayViewFrustum(), RenderArgs args = { NULL, Application::getInstance()->getDisplayViewFrustum(),
lodManager->getOctreeSizeScale(), lodManager->getOctreeSizeScale(),
lodManager->getBoundaryLevelAdjust(), lodManager->getBoundaryLevelAdjust(),
renderMode, renderSide, renderMode, renderSide, renderDebugFlags,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

View file

@ -54,7 +54,8 @@ public:
void init(); void init();
void update(float deltatime); void update(float deltatime);
void renderWorld(bool drawFront, RenderArgs::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE, void renderWorld(bool drawFront, RenderArgs::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE,
RenderArgs::RenderSide renderSide = RenderArgs::MONO); RenderArgs::RenderSide renderSide = RenderArgs::MONO,
RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE);
void renderHUD(); void renderHUD();
public slots: public slots:

View file

@ -383,7 +383,9 @@ void EntityTreeRenderer::leaveAllEntities() {
_lastAvatarPosition = _viewState->getAvatarPosition() + glm::vec3((float)TREE_SCALE); _lastAvatarPosition = _viewState->getAvatarPosition() + glm::vec3((float)TREE_SCALE);
} }
} }
void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::RenderSide renderSide) { void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode,
RenderArgs::RenderSide renderSide,
RenderArgs::DebugFlags renderDebugFlags) {
if (_tree && !_shuttingDown) { if (_tree && !_shuttingDown) {
Model::startScene(renderSide); Model::startScene(renderSide);
@ -391,8 +393,7 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::R
_viewState->getShadowViewFrustum() : _viewState->getCurrentViewFrustum(); _viewState->getShadowViewFrustum() : _viewState->getCurrentViewFrustum();
RenderArgs args = { this, frustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, renderSide, RenderArgs args = { this, frustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, renderSide,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; renderDebugFlags, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
_tree->lockForRead(); _tree->lockForRead();

View file

@ -58,7 +58,8 @@ public:
virtual void init(); virtual void init();
virtual void render(RenderArgs::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE, virtual void render(RenderArgs::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE,
RenderArgs::RenderSide renderSide = RenderArgs::MONO); RenderArgs::RenderSide renderSide = RenderArgs::MONO,
RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE);
virtual const FBXGeometry* getGeometryForEntity(const EntityItem* entityItem); virtual const FBXGeometry* getGeometryForEntity(const EntityItem* entityItem);
virtual const Model* getModelForEntityItem(const EntityItem* entityItem); virtual const Model* getModelForEntityItem(const EntityItem* entityItem);

View file

@ -118,8 +118,15 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
glm::vec3 position = getPosition(); glm::vec3 position = getPosition();
glm::vec3 dimensions = getDimensions(); glm::vec3 dimensions = getDimensions();
float size = glm::length(dimensions); float size = glm::length(dimensions);
if (drawAsModel) { bool highlightSimulationOwnership = false;
if (args->_debugFlags & RenderArgs::RENDER_DEBUG_SIMULATION_OWNERSHIP) {
auto nodeList = DependencyManager::get<NodeList>();
const QUuid& myNodeID = nodeList->getSessionUUID();
highlightSimulationOwnership = (getSimulatorID() == myNodeID);
}
if (drawAsModel && !highlightSimulationOwnership) {
remapTextures(); remapTextures();
glPushMatrix(); glPushMatrix();
{ {

View file

@ -308,6 +308,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
glm::vec3 savePosition = _position; glm::vec3 savePosition = _position;
glm::quat saveRotation = _rotation; glm::quat saveRotation = _rotation;
glm::vec3 saveVelocity = _velocity; glm::vec3 saveVelocity = _velocity;
glm::vec3 saveAngularVelocity = _angularVelocity;
glm::vec3 saveGravity = _gravity; glm::vec3 saveGravity = _gravity;
glm::vec3 saveAcceleration = _acceleration; glm::vec3 saveAcceleration = _acceleration;
@ -592,7 +593,10 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
#ifdef WANT_DEBUG #ifdef WANT_DEBUG
qCDebug(entities) << "skipTimeForward:" << skipTimeForward; qCDebug(entities) << "skipTimeForward:" << skipTimeForward;
#endif #endif
simulateKinematicMotion(skipTimeForward);
// we want to extrapolate the motion forward to compensate for packet travel time, but
// we don't want the side effect of flag setting.
simulateKinematicMotion(skipTimeForward, false);
} }
_lastSimulated = now; _lastSimulated = now;
} }
@ -607,6 +611,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
_position = savePosition; _position = savePosition;
_rotation = saveRotation; _rotation = saveRotation;
_velocity = saveVelocity; _velocity = saveVelocity;
_angularVelocity = saveAngularVelocity;
_gravity = saveGravity; _gravity = saveGravity;
_acceleration = saveAcceleration; _acceleration = saveAcceleration;
} }
@ -725,7 +730,7 @@ void EntityItem::simulate(const quint64& now) {
_lastSimulated = now; _lastSimulated = now;
} }
void EntityItem::simulateKinematicMotion(float timeElapsed) { void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) {
if (hasAngularVelocity()) { if (hasAngularVelocity()) {
// angular damping // angular damping
if (_angularDamping > 0.0f) { if (_angularDamping > 0.0f) {
@ -740,7 +745,7 @@ void EntityItem::simulateKinematicMotion(float timeElapsed) {
const float EPSILON_ANGULAR_VELOCITY_LENGTH = 0.0017453f; // 0.0017453 rad/sec = 0.1f degrees/sec const float EPSILON_ANGULAR_VELOCITY_LENGTH = 0.0017453f; // 0.0017453 rad/sec = 0.1f degrees/sec
if (angularSpeed < EPSILON_ANGULAR_VELOCITY_LENGTH) { if (angularSpeed < EPSILON_ANGULAR_VELOCITY_LENGTH) {
if (angularSpeed > 0.0f) { if (setFlags && angularSpeed > 0.0f) {
_dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE; _dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE;
} }
_angularVelocity = ENTITY_ITEM_ZERO_VEC3; _angularVelocity = ENTITY_ITEM_ZERO_VEC3;
@ -802,7 +807,7 @@ void EntityItem::simulateKinematicMotion(float timeElapsed) {
const float EPSILON_LINEAR_VELOCITY_LENGTH = 0.001f; // 1mm/sec const float EPSILON_LINEAR_VELOCITY_LENGTH = 0.001f; // 1mm/sec
if (speed < EPSILON_LINEAR_VELOCITY_LENGTH) { if (speed < EPSILON_LINEAR_VELOCITY_LENGTH) {
setVelocity(ENTITY_ITEM_ZERO_VEC3); setVelocity(ENTITY_ITEM_ZERO_VEC3);
if (speed > 0.0f) { if (setFlags && speed > 0.0f) {
_dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE; _dirtyFlags |= EntityItem::DIRTY_MOTION_TYPE;
} }
} else { } else {
@ -1080,6 +1085,7 @@ const float MIN_ALIGNMENT_DOT = 0.999999f;
const float MIN_VELOCITY_DELTA = 0.01f; const float MIN_VELOCITY_DELTA = 0.01f;
const float MIN_DAMPING_DELTA = 0.001f; const float MIN_DAMPING_DELTA = 0.001f;
const float MIN_GRAVITY_DELTA = 0.001f; const float MIN_GRAVITY_DELTA = 0.001f;
const float MIN_ACCELERATION_DELTA = 0.001f;
const float MIN_SPIN_DELTA = 0.0003f; const float MIN_SPIN_DELTA = 0.0003f;
void EntityItem::updatePositionInDomainUnits(const glm::vec3& value) { void EntityItem::updatePositionInDomainUnits(const glm::vec3& value) {
@ -1088,9 +1094,10 @@ void EntityItem::updatePositionInDomainUnits(const glm::vec3& value) {
} }
void EntityItem::updatePosition(const glm::vec3& value) { void EntityItem::updatePosition(const glm::vec3& value) {
if (glm::distance(_position, value) > MIN_POSITION_DELTA) { if (value != _position) {
auto distance = glm::distance(_position, value);
_dirtyFlags |= (distance > MIN_POSITION_DELTA) ? EntityItem::DIRTY_POSITION : EntityItem::DIRTY_PHYSICS_NO_WAKE;
_position = value; _position = value;
_dirtyFlags |= EntityItem::DIRTY_POSITION;
} }
} }
@ -1107,9 +1114,10 @@ void EntityItem::updateDimensions(const glm::vec3& value) {
} }
void EntityItem::updateRotation(const glm::quat& rotation) { void EntityItem::updateRotation(const glm::quat& rotation) {
if (glm::dot(_rotation, rotation) < MIN_ALIGNMENT_DOT) { if (rotation != _rotation) {
_rotation = rotation; auto alignmentDot = glm::abs(glm::dot(_rotation, rotation));
_dirtyFlags |= EntityItem::DIRTY_POSITION; _dirtyFlags |= (alignmentDot < MIN_ALIGNMENT_DOT) ? EntityItem::DIRTY_POSITION : EntityItem::DIRTY_PHYSICS_NO_WAKE;
_rotation = rotation;
} }
} }
@ -1166,21 +1174,28 @@ void EntityItem::updateGravityInDomainUnits(const glm::vec3& value) {
} }
void EntityItem::updateGravity(const glm::vec3& value) { void EntityItem::updateGravity(const glm::vec3& value) {
if ( glm::distance(_gravity, value) > MIN_GRAVITY_DELTA) { if (glm::distance(_gravity, value) > MIN_GRAVITY_DELTA) {
_gravity = value; _gravity = value;
_dirtyFlags |= EntityItem::DIRTY_VELOCITY; _dirtyFlags |= EntityItem::DIRTY_VELOCITY;
} }
} }
void EntityItem::updateAcceleration(const glm::vec3& value) { void EntityItem::updateAcceleration(const glm::vec3& value) {
_acceleration = value; if (glm::distance(_acceleration, value) > MIN_ACCELERATION_DELTA) {
_dirtyFlags |= EntityItem::DIRTY_VELOCITY; _acceleration = value;
_dirtyFlags |= EntityItem::DIRTY_VELOCITY;
}
} }
void EntityItem::updateAngularVelocity(const glm::vec3& value) { void EntityItem::updateAngularVelocity(const glm::vec3& value) {
if (glm::distance(_angularVelocity, value) > MIN_SPIN_DELTA) { auto distance = glm::distance(_angularVelocity, value);
_angularVelocity = value; if (distance > MIN_SPIN_DELTA) {
_dirtyFlags |= EntityItem::DIRTY_VELOCITY; _dirtyFlags |= EntityItem::DIRTY_VELOCITY;
if (glm::length(value) < MIN_SPIN_DELTA) {
_angularVelocity = ENTITY_ITEM_ZERO_VEC3;
} else {
_angularVelocity = value;
}
} }
} }

View file

@ -54,7 +54,8 @@ public:
DIRTY_MOTION_TYPE = 0x0010, DIRTY_MOTION_TYPE = 0x0010,
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
}; };
DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly
@ -132,7 +133,7 @@ public:
// perform linear extrapolation for SimpleEntitySimulation // perform linear extrapolation for SimpleEntitySimulation
void simulate(const quint64& now); void simulate(const quint64& now);
void simulateKinematicMotion(float timeElapsed); void simulateKinematicMotion(float timeElapsed, bool setFlags=true);
virtual bool needsToCallUpdate() const { return false; } virtual bool needsToCallUpdate() const { return false; }

View file

@ -380,9 +380,9 @@ int Octree::readElementData(OctreeElement* destinationElement, const unsigned ch
} }
// if this is the root, and there is more data to read, allow it to read it's element data... // if this is the root, and there is more data to read, allow it to read it's element data...
if (destinationElement == _rootElement && rootElementHasData() && (bytesLeftToRead - bytesRead) > 0) { if (destinationElement == _rootElement && rootElementHasData() && bytesLeftToRead > 0) {
// tell the element to read the subsequent data // tell the element to read the subsequent data
int rootDataSize = _rootElement->readElementDataFromBuffer(nodeData + bytesRead, bytesLeftToRead - bytesRead, args); int rootDataSize = _rootElement->readElementDataFromBuffer(nodeData + bytesRead, bytesLeftToRead, args);
bytesRead += rootDataSize; bytesRead += rootDataSize;
bytesLeftToRead -= rootDataSize; bytesLeftToRead -= rootDataSize;
} }

View file

@ -164,9 +164,11 @@ bool OctreeRenderer::renderOperation(OctreeElement* element, void* extraData) {
return false; return false;
} }
void OctreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::RenderSide renderSide) { void OctreeRenderer::render(RenderArgs::RenderMode renderMode,
RenderArgs::RenderSide renderSide,
RenderArgs::DebugFlags renderDebugFlags) {
RenderArgs args = { this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, renderSide, RenderArgs args = { this, _viewFrustum, getSizeScale(), getBoundaryLevelAdjust(), renderMode, renderSide,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; renderDebugFlags, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
if (_tree) { if (_tree) {
_tree->lockForRead(); _tree->lockForRead();
_tree->recurseTreeWithOperation(renderOperation, &args); _tree->recurseTreeWithOperation(renderOperation, &args);

View file

@ -52,7 +52,8 @@ public:
/// render the content of the octree /// render the content of the octree
virtual void render(RenderArgs::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE, virtual void render(RenderArgs::RenderMode renderMode = RenderArgs::DEFAULT_RENDER_MODE,
RenderArgs::RenderSide renderSide = RenderArgs::MONO); RenderArgs::RenderSide renderSide = RenderArgs::MONO,
RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE);
ViewFrustum* getViewFrustum() const { return _viewFrustum; } ViewFrustum* getViewFrustum() const { return _viewFrustum; }
void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; } void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; }

View file

@ -38,7 +38,8 @@ void EntityMotionState::enqueueOutgoingEntity(EntityItem* entity) {
EntityMotionState::EntityMotionState(EntityItem* entity) : EntityMotionState::EntityMotionState(EntityItem* entity) :
_entity(entity), _entity(entity),
_accelerationNearlyGravityCount(0), _accelerationNearlyGravityCount(0),
_shouldClaimSimulationOwnership(false) _shouldClaimSimulationOwnership(false),
_movingStepsWithoutSimulationOwner(0)
{ {
_type = MOTION_STATE_TYPE_ENTITY; _type = MOTION_STATE_TYPE_ENTITY;
assert(entity != NULL); assert(entity != NULL);
@ -108,11 +109,23 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
getVelocity(v); getVelocity(v);
_entity->setVelocity(v); _entity->setVelocity(v);
getAngularVelocity(v); glm::vec3 av;
_entity->setAngularVelocity(v); getAngularVelocity(av);
_entity->setAngularVelocity(av);
_entity->setLastSimulated(usecTimestampNow()); _entity->setLastSimulated(usecTimestampNow());
if (_entity->getSimulatorID().isNull() && isMoving()) {
// object is moving and has no owner. attempt to claim simulation ownership.
_movingStepsWithoutSimulationOwner++;
} else {
_movingStepsWithoutSimulationOwner = 0;
}
if (_movingStepsWithoutSimulationOwner > 4) { // XXX maybe meters from our characterController ?
setShouldClaimSimulationOwnership(true);
}
_outgoingPacketFlags = DIRTY_PHYSICS_FLAGS; _outgoingPacketFlags = DIRTY_PHYSICS_FLAGS;
EntityMotionState::enqueueOutgoingEntity(_entity); EntityMotionState::enqueueOutgoingEntity(_entity);
@ -126,7 +139,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
} }
void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t step) { void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t step) {
if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) { 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 = _entity->getPosition() - ObjectMotionState::getWorldOffset();
btTransform worldTrans; btTransform worldTrans;
@ -141,6 +154,10 @@ void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t step) {
updateObjectVelocities(); updateObjectVelocities();
} }
_sentStep = step; _sentStep = step;
if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) {
_body->activate();
}
} }
// TODO: entity support for friction and restitution // TODO: entity support for friction and restitution
@ -160,7 +177,6 @@ void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t step) {
_body->setMassProps(mass, inertia); _body->setMassProps(mass, inertia);
_body->updateInertiaTensor(); _body->updateInertiaTensor();
} }
_body->activate();
}; };
void EntityMotionState::updateObjectVelocities() { void EntityMotionState::updateObjectVelocities() {
@ -287,13 +303,14 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
QUuid simulatorID = _entity->getSimulatorID(); QUuid simulatorID = _entity->getSimulatorID();
if (getShouldClaimSimulationOwnership()) { if (getShouldClaimSimulationOwnership()) {
_entity->setSimulatorID(myNodeID);
properties.setSimulatorID(myNodeID); properties.setSimulatorID(myNodeID);
setShouldClaimSimulationOwnership(false); setShouldClaimSimulationOwnership(false);
} } else if (simulatorID == myNodeID && zeroSpeed && zeroSpin) {
// we are the simulator and the entity has stopped. give up "simulator" status
if (simulatorID == myNodeID && zeroSpeed && zeroSpin) { _entity->setSimulatorID(QUuid());
// we are the simulator and the object has stopped. give up "simulator" status properties.setSimulatorID(QUuid());
} else if (simulatorID == myNodeID && !_body->isActive()) {
// it's not active. don't keep simulation ownership.
_entity->setSimulatorID(QUuid()); _entity->setSimulatorID(QUuid());
properties.setSimulatorID(QUuid()); properties.setSimulatorID(QUuid());
} }

View file

@ -74,6 +74,7 @@ protected:
EntityItem* _entity; EntityItem* _entity;
quint8 _accelerationNearlyGravityCount; quint8 _accelerationNearlyGravityCount;
bool _shouldClaimSimulationOwnership; bool _shouldClaimSimulationOwnership;
quint32 _movingStepsWithoutSimulationOwner;
}; };
#endif // hifi_EntityMotionState_h #endif // hifi_EntityMotionState_h

View file

@ -119,8 +119,10 @@ void PhysicsEngine::entityChangedInternal(EntityItem* entity) {
assert(entity); assert(entity);
void* physicsInfo = entity->getPhysicsInfo(); void* physicsInfo = entity->getPhysicsInfo();
if (physicsInfo) { if (physicsInfo) {
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo); if ((entity->getDirtyFlags() & (HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS)) > 0) {
_incomingChanges.insert(motionState); ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
_incomingChanges.insert(motionState);
}
} else { } else {
// try to add this entity again (maybe something changed such that it will work this time) // try to add this entity again (maybe something changed such that it will work this time)
addEntity(entity); addEntity(entity);
@ -366,15 +368,46 @@ void PhysicsEngine::stepNonPhysicalKinematics(const quint64& now) {
} }
} }
void PhysicsEngine::computeCollisionEvents() {
BT_PROFILE("computeCollisionEvents"); void PhysicsEngine::doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB) {
assert(objectA);
assert(objectB);
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
QUuid myNodeID = nodeList->getSessionUUID(); QUuid myNodeID = nodeList->getSessionUUID();
const btCollisionObject* characterCollisionObject = const btCollisionObject* characterCollisionObject =
_characterController ? _characterController->getCollisionObject() : NULL; _characterController ? _characterController->getCollisionObject() : NULL;
assert(!myNodeID.isNull());
ObjectMotionState* a = static_cast<ObjectMotionState*>(objectA->getUserPointer());
ObjectMotionState* b = static_cast<ObjectMotionState*>(objectB->getUserPointer());
EntityItem* entityA = a ? a->getEntity() : NULL;
EntityItem* entityB = b ? b->getEntity() : NULL;
bool aIsDynamic = entityA && !objectA->isStaticOrKinematicObject();
bool bIsDynamic = entityB && !objectB->isStaticOrKinematicObject();
// collisions cause infectious spread of simulation-ownership. we also attempt to take
// ownership of anything that collides with our avatar.
if ((aIsDynamic && (entityA->getSimulatorID() == myNodeID)) ||
// (a && a->getShouldClaimSimulationOwnership()) ||
(objectA == characterCollisionObject)) {
if (bIsDynamic) {
b->setShouldClaimSimulationOwnership(true);
}
} else if ((bIsDynamic && (entityB->getSimulatorID() == myNodeID)) ||
// (b && b->getShouldClaimSimulationOwnership()) ||
(objectB == characterCollisionObject)) {
if (aIsDynamic) {
a->setShouldClaimSimulationOwnership(true);
}
}
}
void PhysicsEngine::computeCollisionEvents() {
BT_PROFILE("computeCollisionEvents");
// update all contacts every frame // update all contacts every frame
int numManifolds = _collisionDispatcher->getNumManifolds(); int numManifolds = _collisionDispatcher->getNumManifolds();
for (int i = 0; i < numManifolds; ++i) { for (int i = 0; i < numManifolds; ++i) {
@ -393,31 +426,12 @@ void PhysicsEngine::computeCollisionEvents() {
ObjectMotionState* a = static_cast<ObjectMotionState*>(objectA->getUserPointer()); ObjectMotionState* a = static_cast<ObjectMotionState*>(objectA->getUserPointer());
ObjectMotionState* b = static_cast<ObjectMotionState*>(objectB->getUserPointer()); ObjectMotionState* b = static_cast<ObjectMotionState*>(objectB->getUserPointer());
EntityItem* entityA = a ? a->getEntity() : NULL;
EntityItem* entityB = b ? b->getEntity() : NULL;
bool aIsDynamic = entityA && !objectA->isStaticOrKinematicObject();
bool bIsDynamic = entityB && !objectB->isStaticOrKinematicObject();
if (a || b) { if (a || b) {
// the manifold has up to 4 distinct points, but only extract info from the first // the manifold has up to 4 distinct points, but only extract info from the first
_contactMap[ContactKey(a, b)].update(_numContactFrames, contactManifold->getContactPoint(0), _originOffset); _contactMap[ContactKey(a, b)].update(_numContactFrames, contactManifold->getContactPoint(0), _originOffset);
} }
// collisions cause infectious spread of simulation-ownership. we also attempt to take
// ownership of anything that collides with our avatar. doOwnershipInfection(objectA, objectB);
if ((aIsDynamic && entityA->getSimulatorID() == myNodeID) ||
(a && a->getShouldClaimSimulationOwnership()) ||
(objectA == characterCollisionObject)) {
if (bIsDynamic) {
b->setShouldClaimSimulationOwnership(true);
}
}
if ((bIsDynamic && entityB->getSimulatorID() == myNodeID) ||
(b && b->getShouldClaimSimulationOwnership()) ||
(objectB == characterCollisionObject)) {
if (aIsDynamic) {
a->setShouldClaimSimulationOwnership(true);
}
}
} }
} }
@ -576,11 +590,9 @@ void PhysicsEngine::removeObjectFromBullet(ObjectMotionState* motionState) {
assert(motionState); assert(motionState);
btRigidBody* body = motionState->getRigidBody(); btRigidBody* body = motionState->getRigidBody();
// set the about-to-be-deleted entity active in order to wake up the island it's part of. this is done // wake up anything touching this object
// so that anything resting on top of it will fall. EntityItem* entityItem = motionState ? motionState->getEntity() : NULL;
// body->setActivationState(ACTIVE_TAG); bump(entityItem);
EntityItem* entity = static_cast<EntityMotionState*>(motionState)->getEntity();
bump(entity);
if (body) { if (body) {
const btCollisionShape* shape = body->getCollisionShape(); const btCollisionShape* shape = body->getCollisionShape();

View file

@ -89,16 +89,19 @@ public:
void dumpNextStats() { _dumpNextStats = true; } void dumpNextStats() { _dumpNextStats = true; }
void bump(EntityItem* bumpEntity);
private: private:
/// \param motionState pointer to Object's MotionState /// \param motionState pointer to Object's MotionState
void removeObjectFromBullet(ObjectMotionState* motionState); void removeObjectFromBullet(ObjectMotionState* motionState);
void removeContacts(ObjectMotionState* motionState); void removeContacts(ObjectMotionState* motionState);
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 updateObjectHard(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);
void bump(EntityItem* bumpEntity);
btClock _clock; btClock _clock;
btDefaultCollisionConfiguration* _collisionConfig = NULL; btDefaultCollisionConfiguration* _collisionConfig = NULL;

View file

@ -1947,14 +1947,14 @@ bool Model::renderInScene(float alpha, RenderArgs* args) {
return false; return false;
} }
if (args->_renderMode == RenderArgs::DEBUG_RENDER_MODE && _renderCollisionHull == false) { if (args->_debugFlags == RenderArgs::RENDER_DEBUG_HULLS && _renderCollisionHull == false) {
// turning collision hull rendering on // turning collision hull rendering on
_renderCollisionHull = true; _renderCollisionHull = true;
_nextGeometry = _collisionGeometry; _nextGeometry = _collisionGeometry;
_saveNonCollisionGeometry = _geometry; _saveNonCollisionGeometry = _geometry;
updateGeometry(); updateGeometry();
simulate(0.0, true); simulate(0.0, true);
} else if (args->_renderMode != RenderArgs::DEBUG_RENDER_MODE && _renderCollisionHull == true) { } else if (args->_debugFlags != RenderArgs::RENDER_DEBUG_HULLS && _renderCollisionHull == true) {
// turning collision hull rendering off // turning collision hull rendering off
_renderCollisionHull = false; _renderCollisionHull = false;
_nextGeometry = _saveNonCollisionGeometry; _nextGeometry = _saveNonCollisionGeometry;

View file

@ -17,16 +17,23 @@ class OctreeRenderer;
class RenderArgs { class RenderArgs {
public: public:
enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE, DEBUG_RENDER_MODE }; enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE };
enum RenderSide { MONO, STEREO_LEFT, STEREO_RIGHT }; enum RenderSide { MONO, STEREO_LEFT, STEREO_RIGHT };
enum DebugFlags {
RENDER_DEBUG_NONE=0,
RENDER_DEBUG_HULLS=1,
RENDER_DEBUG_SIMULATION_OWNERSHIP=2
};
OctreeRenderer* _renderer; OctreeRenderer* _renderer;
ViewFrustum* _viewFrustum; ViewFrustum* _viewFrustum;
float _sizeScale; float _sizeScale;
int _boundaryLevelAdjust; int _boundaryLevelAdjust;
RenderMode _renderMode; RenderMode _renderMode;
RenderSide _renderSide; RenderSide _renderSide;
DebugFlags _debugFlags;
int _elementsTouched; int _elementsTouched;
int _itemsRendered; int _itemsRendered;

View file

@ -124,9 +124,9 @@ void OffscreenUi::resize(const QSize& newSize) {
if (_quickWindow) { if (_quickWindow) {
_quickWindow->setGeometry(QRect(QPoint(), newSize)); _quickWindow->setGeometry(QRect(QPoint(), newSize));
_quickWindow->contentItem()->setSize(newSize);
} }
_quickWindow->contentItem()->setSize(newSize);
// Update our members // Update our members
if (_rootItem) { if (_rootItem) {

View file

@ -205,7 +205,7 @@ void QTestWindow::renderText() {
{ size.x + QUAD_OFFSET.x, QUAD_OFFSET.y }, { size.x + QUAD_OFFSET.x, QUAD_OFFSET.y },
{ size.x + QUAD_OFFSET.x, size.y + QUAD_OFFSET.y }, { size.x + QUAD_OFFSET.x, size.y + QUAD_OFFSET.y },
{ QUAD_OFFSET.x, size.y + QUAD_OFFSET.y }, { QUAD_OFFSET.x, size.y + QUAD_OFFSET.y },
}; };
QString str = QString::fromWCharArray(EXAMPLE_TEXT); QString str = QString::fromWCharArray(EXAMPLE_TEXT);
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {