Merge branch 'vr_menus' into infoview

Conflicts:
	tests/ui/src/main.cpp
This commit is contained in:
Brad Davis 2015-04-28 01:17:51 -07:00
commit 9836ffed97
36 changed files with 429 additions and 1267 deletions

View file

@ -1,7 +1,7 @@
###Dependencies
* [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
* IMPORTANT: OpenSSL 1.0.1g is critical to avoid a security vulnerability.
* [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
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.
export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.3.2/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/qt/5.4.1/clang_64/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
####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:
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

View file

@ -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.
*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
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

View file

@ -325,7 +325,6 @@ Dialog {
case Qt.Key_Enter:
case Qt.Key_Return:
console.log("Accepting");
event.accepted = true
content.accept()
break

View 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 }
}
}
}

View file

@ -128,13 +128,16 @@ Hifi.VrMenu {
// visible: source.visible
Row {
id: row
spacing: 4
spacing: 2
anchors {
top: parent.top
topMargin: 2
}
Spacer { size: 4 }
FontAwesome {
id: check
verticalAlignment: Text.AlignVCenter
y: 2
size: label.height
text: checkText()
color: label.color
@ -191,6 +194,7 @@ Hifi.VrMenu {
bottom: parent.bottom
left: parent.left
right: tag.right
rightMargin: -4
}
acceptedButtons: Qt.LeftButton
hoverEnabled: true
@ -263,23 +267,22 @@ Hifi.VrMenu {
function popColumn() {
if (columns.length > 0) {
var curColumn = columns.pop();
console.log(curColumn);
curColumn.visible = false;
curColumn.destroy();
models.pop();
}
}
if (columns.length == 0) {
enabled = false;
return;
}
}
curColumn = lastColumn();
curColumn.enabled = true;
curColumn.opacity = 1.0;
curColumn.forceActiveFocus();
}
function selectItem(source) {
switch (source.type) {
case 2:
@ -317,7 +320,7 @@ Hifi.VrMenu {
root.popColumn();
} else {
root.enabled = false;
}
}
}
}
}

View file

@ -92,6 +92,7 @@ DialogBase {
anchors.bottom: parent.bottom
width: 16
height: 16
z: 1000
hoverEnabled: true
onPressed: {
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;
}
}
}

View file

@ -22,11 +22,13 @@ Item {
readonly property alias titleWidth: titleBorder.width
readonly property alias titleHeight: titleBorder.height
// readonly property real borderWidth: hifi.styles.borderWidth
readonly property real borderWidth: 0
property alias clientBorder: clientBorder
readonly property real clientX: clientBorder.x + hifi.styles.borderWidth
readonly property real clientY: clientBorder.y + hifi.styles.borderWidth
readonly property real clientWidth: clientBorder.width - hifi.styles.borderWidth * 2
readonly property real clientHeight: clientBorder.height - hifi.styles.borderWidth * 2
readonly property real clientX: clientBorder.x + borderWidth
readonly property real clientY: clientBorder.y + borderWidth
readonly property real clientWidth: clientBorder.width - borderWidth * 2
readonly property real clientHeight: clientBorder.height - borderWidth * 2
/*
* Window decorations, with a title bar and frames
@ -35,6 +37,7 @@ Item {
id: windowBorder
anchors.fill: parent
border.color: root.frameColor
border.width: 0
color: "#00000000"
Border {
@ -43,11 +46,13 @@ Item {
anchors.right: parent.right
anchors.left: parent.left
border.color: root.frameColor
border.width: 0
clip: true
color: root.active ?
hifi.colors.activeWindow.headerBackground :
hifi.colors.inactiveWindow.headerBackground
Text {
id: titleText
color: root.active ?
@ -60,8 +65,26 @@ Item {
}
} // 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 {
id: clientBorder
border.width: 0
border.color: root.frameColor
color: root.backgroundColor
anchors.bottom: parent.bottom
@ -69,7 +92,6 @@ Item {
anchors.topMargin: -titleBorder.border.width
anchors.right: parent.right
anchors.left: parent.left
clip: true
} // client border
} // window border

View file

@ -13,14 +13,14 @@ Original.TextInput {
font.family: hifi.fonts.fontFamily
font.pointSize: hifi.fonts.fontSize
/*
Original.Rectangle {
// Render the rectangle as background
z: -1
anchors.fill: parent
color: hifi.colors.inputBackground
}
*/
Text {
anchors.fill: parent
font.pointSize: parent.font.pointSize

View file

@ -766,6 +766,7 @@ void Application::initializeUi() {
AddressBarDialog::registerType();
LoginDialog::registerType();
MessageDialog::registerType();
VrMenu::registerType();
auto offscreenUi = DependencyManager::get<OffscreenUi>();
offscreenUi->create(_glWidget->context()->contextHandle());
@ -774,6 +775,8 @@ void Application::initializeUi() {
offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
offscreenUi->load("Root.qml");
offscreenUi->load("RootMenu.qml");
VrMenu::load();
VrMenu::executeQueuedLambdas();
offscreenUi->setMouseTranslator([this](const QPointF& p){
if (OculusManager::isConnected()) {
glm::vec2 pos = _applicationOverlay.screenToOverlay(toGlm(p));
@ -4441,7 +4444,6 @@ void Application::checkSkeleton() {
_myAvatar->useBodyURL(DEFAULT_BODY_MODEL_URL, "Default");
} else {
_myAvatar->updateCharacterController();
_physicsEngine.setCharacterController(_myAvatar->getCharacterController());
}
}

View file

@ -975,7 +975,9 @@ bool Menu::menuItemExists(const QString& menu, const QString& menuitem) {
MenuWrapper::MenuWrapper(QMenu* menu) : _realMenu(menu) {
VrMenu::instance()->addMenu(menu);
VrMenu::executeOrQueue([=](VrMenu* vrMenu) {
vrMenu->addMenu(menu);
});
_backMap[menu] = this;
}
@ -997,18 +999,24 @@ void MenuWrapper::addSeparator() {
void MenuWrapper::addAction(QAction* action) {
_realMenu->addAction(action);
VrMenu::instance()->addAction(_realMenu, action);
VrMenu::executeOrQueue([=](VrMenu* vrMenu) {
vrMenu->addAction(_realMenu, action);
});
}
QAction* MenuWrapper::addAction(const QString& menuName) {
QAction* action = _realMenu->addAction(menuName);
VrMenu::instance()->addAction(_realMenu, action);
VrMenu::executeOrQueue([=](VrMenu* vrMenu) {
vrMenu->addAction(_realMenu, action);
});
return action;
}
QAction* MenuWrapper::addAction(const QString& menuName, const QObject* receiver, const char* member, const QKeySequence& shortcut) {
QAction* action = _realMenu->addAction(menuName, receiver, member, shortcut);
VrMenu::instance()->addAction(_realMenu, action);
VrMenu::executeOrQueue([=](VrMenu* vrMenu) {
vrMenu->addAction(_realMenu, action);
});
return action;
}
@ -1018,7 +1026,9 @@ void MenuWrapper::removeAction(QAction* action) {
void MenuWrapper::insertAction(QAction* before, QAction* action) {
_realMenu->insertAction(before, action);
VrMenu::instance()->insertAction(before, action);
VrMenu::executeOrQueue([=](VrMenu* vrMenu) {
vrMenu->insertAction(before, action);
});
}
QHash<QMenu*, MenuWrapper*> MenuWrapper::_backMap;

View file

@ -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);
}
*/
}

View file

@ -162,6 +162,8 @@ public:
// (otherwise floating point error will cause problems at large positions).
void applyPositionDelta(const glm::vec3& delta);
virtual void rebuildSkeletonBody();
signals:
void collisionWithAvatar(const QUuid& myUUID, const QUuid& theirUUID, const CollisionInfo& collision);
@ -228,6 +230,8 @@ private:
static int _jointConesID;
int _voiceSphereID;
//AvatarMotionState* _motionState = nullptr;
};
#endif // hifi_Avatar_h

View file

@ -59,7 +59,7 @@ private:
AvatarSharedPointer newSharedAvatar();
// virtual override
// virtual overrides
AvatarHash::iterator erase(const AvatarHash::iterator& iterator);
QVector<AvatarSharedPointer> _avatarFades;

View file

@ -987,6 +987,13 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
}
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;
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) {
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;
if (_headURLFromPreferences != headURL) {
@ -1079,7 +1095,7 @@ glm::vec3 MyAvatar::getSkeletonPosition() const {
return Avatar::getPosition();
}
void MyAvatar::updateCharacterController() {
void MyAvatar::rebuildSkeletonBody() {
// compute localAABox
const CapsuleShape& capsule = _skeletonModel.getBoundingShape();
float radius = capsule.getRadius();

View file

@ -138,7 +138,6 @@ public:
virtual glm::vec3 getSkeletonPosition() const;
void updateLocalAABox();
DynamicCharacterController* getCharacterController() { return &_characterController; }
void updateCharacterController();
void clearJointAnimationPriorities();
@ -192,6 +191,8 @@ public slots:
void stopRecording();
void saveRecording(QString filename);
void loadLastRecording();
virtual void rebuildSkeletonBody();
signals:
void transformChanged();

View file

@ -40,13 +40,14 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) :
_clampedFootPosition(0.0f),
_headClipDistance(DEFAULT_NEAR_CLIP)
{
assert(_owningAvatar);
}
SkeletonModel::~SkeletonModel() {
}
void SkeletonModel::setJointStates(QVector<JointState> states) {
Model::setJointStates(states);
void SkeletonModel::initJointStates(QVector<JointState> states) {
Model::initJointStates(states);
// Determine the default eye position for avatar scale = 1.0
int headJointIndex = _geometry->getFBXGeometry().headJointIndex;
@ -83,6 +84,7 @@ void SkeletonModel::setJointStates(QVector<JointState> states) {
_headClipDistance = -(meshExtents.minimum.z / _scale.z - _defaultEyeModelPosition.z);
_headClipDistance = std::max(_headClipDistance, DEFAULT_NEAR_CLIP);
_owningAvatar->rebuildSkeletonBody();
emit skeletonLoaded();
}

View file

@ -28,7 +28,7 @@ public:
SkeletonModel(Avatar* owningAvatar, QObject* parent = NULL);
~SkeletonModel();
void setJointStates(QVector<JointState> states);
virtual void initJointStates(QVector<JointState> states);
void simulate(float deltaTime, bool fullUpdate = true);

View file

@ -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) {
if (_lastSimulated == 0) {
_lastSimulated = now;
@ -840,11 +851,11 @@ glm::mat4 EntityItem::getWorldToEntityMatrix() const {
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));
}
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));
}
@ -1164,7 +1175,7 @@ void EntityItem::updateVelocity(const glm::vec3& value) {
void EntityItem::updateDamping(float value) {
if (fabsf(_damping - value) > MIN_DAMPING_DELTA) {
_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) {
if (fabsf(_angularDamping - value) > MIN_DAMPING_DELTA) {
_angularDamping = glm::clamp(value, 0.0f, 1.0f);
_dirtyFlags |= EntityItem::DIRTY_VELOCITY;
_dirtyFlags |= EntityItem::DIRTY_MATERIAL;
}
}

View file

@ -55,7 +55,8 @@ public:
DIRTY_SHAPE = 0x0020,
DIRTY_LIFETIME = 0x0040,
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
@ -174,7 +175,7 @@ public:
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
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
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
bool hasAcceleration() const { return _acceleration != ENTITY_ITEM_ZERO_VEC3; }
float getDamping() const { return _damping; }
void setDamping(float value) { _damping = value; }
float getRestitution() const;
float getFriction() const;
// lifetime related properties.
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
@ -298,8 +302,8 @@ public:
glm::mat4 getEntityToWorldMatrix() const;
glm::mat4 getWorldToEntityMatrix() const;
glm::vec3 worldToEntity(const glm::vec3 point) const;
glm::vec3 entityToWorld(const glm::vec3 point) const;
glm::vec3 worldToEntity(const glm::vec3& point) const;
glm::vec3 entityToWorld(const glm::vec3& point) const;
protected:

View file

@ -16,6 +16,7 @@
#include "LightEntityItem.h"
#include "ModelEntityItem.h"
#include "ZoneEntityItem.h"
#include "EntitiesLogging.h"
EntityScriptingInterface::EntityScriptingInterface() :
@ -78,19 +79,27 @@ EntityItemID EntityScriptingInterface::addEntity(const EntityItemProperties& pro
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.
bool success = true;
if (_entityTree) {
_entityTree->lockForWrite();
EntityItem* entity = _entityTree->addEntity(id, propertiesWithSimID);
// This Node is creating a new object. If it's in motion, set this Node as the simulator.
setSimId(propertiesWithSimID, entity);
if (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();
}
// queue the packet
queueEntityMessage(PacketTypeEntityAddOrEdit, id, propertiesWithSimID);
if (success) {
queueEntityMessage(PacketTypeEntityAddOrEdit, id, propertiesWithSimID);
}
return id;
}

View file

@ -192,6 +192,14 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro
EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItemProperties& properties) {
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
// 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;

View file

@ -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();
btScalar actualSpeed = actualVelocity.length();
@ -315,10 +315,10 @@ void DynamicCharacterController::updateShapeIfNecessary() {
float mass = 1.0f;
btVector3 inertia(1.0f, 1.0f, 1.0f);
_rigidBody = new btRigidBody(mass, NULL, _shape, inertia);
_rigidBody->setSleepingThresholds (0.0f, 0.0f);
_rigidBody->setAngularFactor (0.0f);
_rigidBody->setSleepingThresholds(0.0f, 0.0f);
_rigidBody->setAngularFactor(0.0f);
_rigidBody->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()),
glmToBullet(_avatarData->getPosition())));
glmToBullet(_avatarData->getPosition())));
if (_isHovering) {
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f));
} else {

View file

@ -51,7 +51,7 @@ EntityMotionState::~EntityMotionState() {
_entity = NULL;
}
MotionType EntityMotionState::computeMotionType() const {
MotionType EntityMotionState::computeObjectMotionType() const {
if (_entity->getCollisionsWillMove()) {
return MOTION_TYPE_DYNAMIC;
}
@ -68,7 +68,7 @@ void EntityMotionState::stepKinematicSimulation(quint64 now) {
// which is different from physical kinematic motion (inside getWorldTransform())
// which steps in physics simulation time.
_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.
// 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...
// iff the corresponding RigidBody is DYNAMIC and has moved.
void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
measureAcceleration();
measureBodyAcceleration();
_entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset());
_entity->setRotation(bulletToGLM(worldTrans.getRotation()));
@ -138,20 +138,20 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
#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) {
_sentPosition = _entity->getPosition() - ObjectMotionState::getWorldOffset();
_sentPosition = getObjectPosition() - ObjectMotionState::getWorldOffset();
btTransform worldTrans;
worldTrans.setOrigin(glmToBullet(_sentPosition));
_sentRotation = _entity->getRotation();
_sentRotation = getObjectRotation();
worldTrans.setRotation(glmToBullet(_sentRotation));
_body->setWorldTransform(worldTrans);
}
if (flags & EntityItem::DIRTY_VELOCITY) {
updateObjectVelocities();
updateBodyVelocities();
}
_sentStep = step;
@ -160,54 +160,54 @@ void EntityMotionState::updateObjectEasy(uint32_t flags, uint32_t step) {
}
}
// TODO: entity support for friction and restitution
//_restitution = _entity->getRestitution();
_body->setRestitution(_restitution);
//_friction = _entity->getFriction();
_body->setFriction(_friction);
_linearDamping = _entity->getDamping();
_angularDamping = _entity->getAngularDamping();
_body->setDamping(_linearDamping, _angularDamping);
if (flags & EntityItem::DIRTY_MATERIAL) {
updateBodyMaterialProperties();
}
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);
_body->getCollisionShape()->calculateLocalInertia(mass, inertia);
_body->setMassProps(mass, inertia);
_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) {
_sentVelocity = _entity->getVelocity();
setVelocity(_sentVelocity);
_sentVelocity = getObjectLinearVelocity();
setBodyVelocity(_sentVelocity);
_sentAngularVelocity = _entity->getAngularVelocity();
setAngularVelocity(_sentAngularVelocity);
_sentAngularVelocity = getObjectAngularVelocity();
setBodyAngularVelocity(_sentAngularVelocity);
_sentGravity = _entity->getGravity();
setGravity(_sentGravity);
_sentGravity = getObjectGravity();
setBodyGravity(_sentGravity);
_body->setActivationState(ACTIVE_TAG);
}
}
void EntityMotionState::computeShapeInfo(ShapeInfo& shapeInfo) {
void EntityMotionState::computeObjectShapeInfo(ShapeInfo& shapeInfo) {
if (_entity->isReadyToComputeShape()) {
_entity->computeShapeInfo(shapeInfo);
}
}
float EntityMotionState::computeMass(const ShapeInfo& shapeInfo) const {
float EntityMotionState::computeObjectMass(const ShapeInfo& shapeInfo) const {
return _entity->computeMass();
}
bool EntityMotionState::shouldSendUpdate(uint32_t simulationFrame) {
bool baseResult = this->ObjectMotionState::shouldSendUpdate(simulationFrame);
if (!baseResult) {
if (!ObjectMotionState::shouldSendUpdate(simulationFrame)) {
return false;
}

View file

@ -31,12 +31,11 @@ public:
static void setOutgoingEntityList(QSet<EntityItem*>* list);
static void enqueueOutgoingEntity(EntityItem* entity);
EntityMotionState() = delete; // prevent compiler from making default ctor
EntityMotionState(EntityItem* item);
virtual ~EntityMotionState();
/// \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 stepKinematicSimulation(quint64 now);
@ -50,11 +49,12 @@ public:
virtual void setWorldTransform(const btTransform& worldTrans);
// these relay incoming values to the RigidBody
virtual void updateObjectEasy(uint32_t flags, uint32_t step);
virtual void updateObjectVelocities();
virtual void updateBodyEasy(uint32_t flags, uint32_t step);
virtual void updateBodyMaterialProperties();
virtual void updateBodyVelocities();
virtual void computeShapeInfo(ShapeInfo& shapeInfo);
virtual float computeMass(const ShapeInfo& shapeInfo) const;
virtual void computeObjectShapeInfo(ShapeInfo& shapeInfo);
virtual float computeObjectMass(const ShapeInfo& shapeInfo) const;
virtual bool shouldSendUpdate(uint32_t simulationFrame);
virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t step);
@ -70,6 +70,17 @@ public:
virtual void setShouldClaimSimulationOwnership(bool value) { _shouldClaimSimulationOwnership = value; }
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:
EntityItem* _entity;
quint8 _accelerationNearlyGravityCount;

View file

@ -36,17 +36,13 @@ const glm::vec3& ObjectMotionState::getWorldOffset() {
}
// static
uint32_t _simulationStep = 0;
void ObjectMotionState::setSimulationStep(uint32_t step) {
assert(step > _simulationStep);
_simulationStep = step;
uint32_t _worldSimulationStep = 0;
void ObjectMotionState::setWorldSimulationStep(uint32_t step) {
assert(step > _worldSimulationStep);
_worldSimulationStep = step;
}
ObjectMotionState::ObjectMotionState() :
_friction(DEFAULT_FRICTION),
_restitution(DEFAULT_RESTITUTION),
_linearDamping(0.0f),
_angularDamping(0.0f),
_motionType(MOTION_TYPE_STATIC),
_body(NULL),
_sentMoving(false),
@ -69,52 +65,36 @@ ObjectMotionState::~ObjectMotionState() {
assert(_body == NULL);
}
void ObjectMotionState::measureAcceleration() {
void ObjectMotionState::measureBodyAcceleration() {
// try to manually measure the true acceleration of the object
uint32_t numSubsteps = _simulationStep - _lastSimulationStep;
uint32_t numSubsteps = _worldSimulationStep - _lastSimulationStep;
if (numSubsteps > 0) {
float dt = ((float)numSubsteps * PHYSICS_ENGINE_FIXED_SUBSTEP);
float invDt = 1.0f / dt;
_lastSimulationStep = _simulationStep;
_lastSimulationStep = _worldSimulationStep;
// 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
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;
}
}
void ObjectMotionState::resetMeasuredAcceleration() {
_lastSimulationStep = _simulationStep;
void ObjectMotionState::resetMeasuredBodyAcceleration() {
_lastSimulationStep = _worldSimulationStep;
_lastVelocity = bulletToGLM(_body->getLinearVelocity());
}
void ObjectMotionState::setFriction(float friction) {
_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 {
void ObjectMotionState::setBodyVelocity(const glm::vec3& velocity) const {
_body->setLinearVelocity(glmToBullet(velocity));
}
void ObjectMotionState::setAngularVelocity(const glm::vec3& velocity) const {
void ObjectMotionState::setBodyAngularVelocity(const glm::vec3& velocity) const {
_body->setAngularVelocity(glmToBullet(velocity));
}
void ObjectMotionState::setGravity(const glm::vec3& gravity) const {
void ObjectMotionState::setBodyGravity(const glm::vec3& gravity) const {
_body->setGravity(glmToBullet(gravity));
}
@ -181,7 +161,7 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationStep) {
// compute position error
if (glm::length2(_sentVelocity) > 0.0f) {
_sentVelocity += _sentAcceleration * dt;
_sentVelocity *= powf(1.0f - _linearDamping, dt);
_sentVelocity *= powf(1.0f - _body->getLinearDamping(), dt);
_sentPosition += dt * _sentVelocity;
}
@ -206,7 +186,7 @@ bool ObjectMotionState::shouldSendUpdate(uint32_t simulationStep) {
if (glm::length2(_sentAngularVelocity) > 0.0f) {
// compute rotation error
float attenuation = powf(1.0f - _angularDamping, dt);
float attenuation = powf(1.0f - _body->getAngularDamping(), dt);
_sentAngularVelocity *= attenuation;
// Bullet caps the effective rotation velocity inside its rotation integration step, therefore

View file

@ -36,7 +36,7 @@ enum MotionStateType {
// 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 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:
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 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();
void measureAcceleration();
void resetMeasuredAcceleration();
void measureBodyAcceleration();
void resetMeasuredBodyAcceleration();
// 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 updateObjectVelocities() = 0;
virtual void updateBodyEasy(uint32_t flags, uint32_t frame) = 0;
virtual void updateBodyMaterialProperties() = 0;
virtual void updateBodyVelocities() = 0;
MotionStateType getType() const { return _type; }
virtual MotionType getMotionType() const { return _motionType; }
virtual void computeShapeInfo(ShapeInfo& info) = 0;
virtual float computeMass(const ShapeInfo& shapeInfo) const = 0;
virtual void computeObjectShapeInfo(ShapeInfo& info) = 0;
virtual float computeObjectMass(const ShapeInfo& shapeInfo) const = 0;
void setFriction(float friction);
void setRestitution(float restitution);
void setLinearDamping(float damping);
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 setBodyVelocity(const glm::vec3& velocity) const;
void setBodyAngularVelocity(const glm::vec3& velocity) const;
void setBodyGravity(const glm::vec3& gravity) const;
void getVelocity(glm::vec3& velocityOut) const;
void getAngularVelocity(glm::vec3& angularVelocityOut) const;
@ -97,7 +95,7 @@ public:
virtual bool shouldSendUpdate(uint32_t simulationStep);
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;
@ -117,18 +115,26 @@ public:
virtual void setShouldClaimSimulationOwnership(bool value) { }
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:
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
float _friction;
float _restitution;
float _linearDamping;
float _angularDamping;
MotionType _motionType;
MotionType _motionType; // type of motion: KINEMATIC, DYNAMIC, or STATIC
btRigidBody* _body;

View file

@ -15,6 +15,7 @@
#include "ShapeInfoUtil.h"
#include "PhysicsHelpers.h"
#include "ThreadSafeDynamicsWorld.h"
#include "PhysicsLogging.h"
static uint32_t _numSubsteps;
@ -172,9 +173,9 @@ void PhysicsEngine::relayIncomingChangesToSimulation() {
if (flags & HARD_DIRTY_PHYSICS_FLAGS) {
// a HARD update requires the body be pulled out of physics engine, changed, then reinserted
// but it also handles all EASY changes
bool success = updateObjectHard(body, motionState, flags);
bool success = updateBodyHard(body, motionState, flags);
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
// we might need to remove motionState altogether...
if (flags & EntityItem::DIRTY_VELOCITY) {
@ -194,10 +195,10 @@ void PhysicsEngine::relayIncomingChangesToSimulation() {
} else if (flags) {
// 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.
motionState->updateObjectEasy(flags, _numSubsteps);
motionState->updateBodyEasy(flags, _numSubsteps);
}
if (flags & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY)) {
motionState->resetMeasuredAcceleration();
motionState->resetMeasuredBodyAcceleration();
}
} else {
// 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
if (flags & EntityItem::DIRTY_SHAPE) {
ShapeInfo shapeInfo;
motionState->computeShapeInfo(shapeInfo);
motionState->computeObjectShapeInfo(shapeInfo);
btCollisionShape* shape = _shapeManager.getShape(shapeInfo);
if (shape) {
addObject(shapeInfo, shape, motionState);
@ -341,7 +342,7 @@ void PhysicsEngine::stepSimulation() {
// lock on the tree before we re-lock ourselves.
//
// TODO: untangle these lock sequences.
ObjectMotionState::setSimulationStep(_numSubsteps);
ObjectMotionState::setWorldSimulationStep(_numSubsteps);
_entityTree->lockForWrite();
lock();
_dynamicsWorld->synchronizeMotionStates();
@ -498,7 +499,7 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap
btVector3 inertia(0.0f, 0.0f, 0.0f);
float mass = 0.0f;
btRigidBody* body = NULL;
switch(motionState->computeMotionType()) {
switch(motionState->computeObjectMotionType()) {
case MOTION_TYPE_KINEMATIC: {
body = new btRigidBody(mass, motionState, shape, inertia);
body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
@ -511,13 +512,13 @@ void PhysicsEngine::addObject(const ShapeInfo& shapeInfo, btCollisionShape* shap
break;
}
case MOTION_TYPE_DYNAMIC: {
mass = motionState->computeMass(shapeInfo);
mass = motionState->computeObjectMass(shapeInfo);
shape->calculateLocalInertia(mass, inertia);
body = new btRigidBody(mass, motionState, shape, inertia);
body->updateInertiaTensor();
motionState->setRigidBody(body);
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.
// (the 2 seconds is determined by: static btRigidBody::gDeactivationTime
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->setRestitution(motionState->_restitution);
body->setFriction(motionState->_friction);
body->setDamping(motionState->_linearDamping, motionState->_angularDamping);
motionState->updateBodyMaterialProperties();
_dynamicsWorld->addRigidBody(body);
motionState->resetMeasuredAcceleration();
motionState->resetMeasuredBodyAcceleration();
}
void PhysicsEngine::bump(EntityItem* bumpEntity) {
@ -608,8 +608,8 @@ void PhysicsEngine::removeObjectFromBullet(ObjectMotionState* motionState) {
}
// private
bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) {
MotionType newType = motionState->computeMotionType();
bool PhysicsEngine::updateBodyHard(btRigidBody* body, ObjectMotionState* motionState, uint32_t flags) {
MotionType newType = motionState->computeObjectMotionType();
// pull body out of physics engine
_dynamicsWorld->removeRigidBody(body);
@ -621,7 +621,7 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio
// get new shape
btCollisionShape* oldShape = body->getCollisionShape();
ShapeInfo shapeInfo;
motionState->computeShapeInfo(shapeInfo);
motionState->computeObjectShapeInfo(shapeInfo);
btCollisionShape* newShape = _shapeManager.getShape(shapeInfo);
if (!newShape) {
// FAIL! we are unable to support these changes!
@ -640,7 +640,7 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio
_shapeManager.releaseShape(oldShape);
// compute mass properties
float mass = motionState->computeMass(shapeInfo);
float mass = motionState->computeObjectMass(shapeInfo);
btVector3 inertia(0.0f, 0.0f, 0.0f);
body->getCollisionShape()->calculateLocalInertia(mass, inertia);
body->setMassProps(mass, inertia);
@ -653,7 +653,7 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio
}
bool easyUpdate = flags & EASY_DIRTY_PHYSICS_FLAGS;
if (easyUpdate) {
motionState->updateObjectEasy(flags, _numSubsteps);
motionState->updateBodyEasy(flags, _numSubsteps);
}
// update the motion parameters
@ -675,8 +675,8 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio
if (! (flags & EntityItem::DIRTY_MASS)) {
// always update mass properties when going dynamic (unless it's already been done above)
ShapeInfo shapeInfo;
motionState->computeShapeInfo(shapeInfo);
float mass = motionState->computeMass(shapeInfo);
motionState->computeObjectShapeInfo(shapeInfo);
float mass = motionState->computeObjectMass(shapeInfo);
btVector3 inertia(0.0f, 0.0f, 0.0f);
body->getCollisionShape()->calculateLocalInertia(mass, inertia);
body->setMassProps(mass, inertia);

View file

@ -39,8 +39,8 @@ public:
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 && _b == other._b; }
void* _a;
void* _b;
void* _a; // EntityMotionState pointer
void* _b; // EntityMotionState pointer
};
typedef std::map<ContactKey, ContactInfo> ContactMap;
@ -100,7 +100,7 @@ private:
void doOwnershipInfection(const btCollisionObject* objectA, const btCollisionObject* objectB);
// 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);
btClock _clock;

View file

@ -426,12 +426,12 @@ bool Model::updateGeometry() {
_dilatedTextures.clear();
_geometry = geometry;
_meshGroupsKnown = false;
setJointStates(newJointStates);
initJointStates(newJointStates);
needToRebuild = true;
} else if (_jointStates.isEmpty()) {
const FBXGeometry& fbxGeometry = geometry->getFBXGeometry();
if (fbxGeometry.joints.size() > 0) {
setJointStates(createJointStates(fbxGeometry));
initJointStates(createJointStates(fbxGeometry));
needToRebuild = true;
}
} else if (!geometry->isLoaded()) {
@ -469,7 +469,7 @@ bool Model::updateGeometry() {
}
// virtual
void Model::setJointStates(QVector<JointState> states) {
void Model::initJointStates(QVector<JointState> states) {
_jointStates = states;
initJointTransforms();

View file

@ -244,7 +244,7 @@ protected:
// returns 'true' if needs fullUpdate after geometry change
bool updateGeometry();
virtual void setJointStates(QVector<JointState> states);
virtual void initJointStates(QVector<JointState> states);
void setScaleInternal(const glm::vec3& scale);
void scaleToFit();

View file

@ -19,19 +19,10 @@
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
static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/../Resources/";
#else
static QString staticResourcePath = QCoreApplication::applicationDirPath() + "/resources/";
#endif
#endif
return staticResourcePath;

View file

@ -426,7 +426,6 @@ void OffscreenUi::toggle(const QUrl& url, const QString& name, std::function<voi
item = _rootItem->findChild<QQuickItem*>(name);
}
if (item) {
qDebug() << "Turning item " << !item->isEnabled();
item->setEnabled(!item->isEnabled());
}
}

View file

@ -42,7 +42,7 @@ private:
qmlObject->setUserData(USER_DATA_ID, this);
qmlObject->setObjectName(uuid.toString());
// 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 };
static QQueue<std::function<void(VrMenu*)>> queuedLambdas;
VrMenu* VrMenu::instance() {
if (!_instance) {
VrMenu::registerType();
VrMenu::load();
Q_ASSERT(_instance);
void VrMenu::executeOrQueue(std::function<void(VrMenu*)> f) {
if (_instance) {
foreach(std::function<void(VrMenu*)> priorLambda, queuedLambdas) {
priorLambda(_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) {
@ -72,6 +83,7 @@ VrMenu::VrMenu(QQuickItem* parent) : QQuickItem(parent) {
this->setEnabled(false);
}
// QML helper functions
QObject* addMenu(QObject* parent, const QString& text) {
// FIXME add more checking here to ensure no name conflicts

View file

@ -26,7 +26,8 @@ class VrMenu : public QQuickItem {
HIFI_QML_DECL_LAMBDA
public:
static VrMenu* instance();
static void executeOrQueue(std::function<void(VrMenu*)> f);
static void executeQueuedLambdas();
VrMenu(QQuickItem* parent = nullptr);
void addMenu(QMenu* menu);
void addAction(QMenu* parent, QAction* action);

View file

@ -358,7 +358,7 @@ public:
#else
offscreenUi->setBaseUrl(QUrl::fromLocalFile(getQmlDir()));
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
VrMenu::load();
#endif
@ -481,7 +481,7 @@ void QTestWindow::renderQml() {
const char * LOG_FILTER_RULES = R"V0G0N(
*.debug=false
hifi.offscreen.focus.debug=false
qt.quick.mouse.debug=false
)V0G0N";
@ -495,7 +495,7 @@ qt.quick.mouse.debug=false
int main(int argc, char** argv) {
QGuiApplication app(argc, argv);
// QLoggingCategory::setFilterRules(LOG_FILTER_RULES);
QLoggingCategory::setFilterRules(LOG_FILTER_RULES);
QTestWindow window;
app.exec();
return 0;