overte-HifiExperiments/libraries/physics/src/ObjectConstraintBallSocket.cpp
2017-05-17 11:55:31 -07:00

244 lines
6.7 KiB
C++

//
// ObjectConstraintBallSocket.cpp
// libraries/physics/src
//
// Created by Seth Alves 2017-4-29
// Copyright 2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <LogHandler.h>
#include "QVariantGLM.h"
#include "EntityTree.h"
#include "ObjectConstraintBallSocket.h"
#include "PhysicsLogging.h"
const uint16_t ObjectConstraintBallSocket::constraintVersion = 1;
ObjectConstraintBallSocket::ObjectConstraintBallSocket(const QUuid& id, EntityItemPointer ownerEntity) :
ObjectConstraint(DYNAMIC_TYPE_BALL_SOCKET, id, ownerEntity),
_pivotInA(glm::vec3(0.0f)),
_pivotInB(glm::vec3(0.0f))
{
#if WANT_DEBUG
qCDebug(physics) << "ObjectConstraintBallSocket::ObjectConstraintBallSocket";
#endif
}
ObjectConstraintBallSocket::~ObjectConstraintBallSocket() {
#if WANT_DEBUG
qCDebug(physics) << "ObjectConstraintBallSocket::~ObjectConstraintBallSocket";
#endif
}
QList<btRigidBody*> ObjectConstraintBallSocket::getRigidBodies() {
QList<btRigidBody*> result;
result += getRigidBody();
QUuid otherEntityID;
withReadLock([&]{
otherEntityID = _otherID;
});
if (!otherEntityID.isNull()) {
result += getOtherRigidBody(otherEntityID);
}
return result;
}
void ObjectConstraintBallSocket::prepareForPhysicsSimulation() {
}
void ObjectConstraintBallSocket::updateBallSocket() {
btPoint2PointConstraint* constraint { nullptr };
withReadLock([&]{
constraint = static_cast<btPoint2PointConstraint*>(_constraint);
});
if (!constraint) {
return;
}
constraint->setPivotA(glmToBullet(_pivotInA));
constraint->setPivotB(glmToBullet(_pivotInB));
}
btTypedConstraint* ObjectConstraintBallSocket::getConstraint() {
btPoint2PointConstraint* constraint { nullptr };
QUuid otherEntityID;
glm::vec3 pivotInA;
glm::vec3 pivotInB;
withReadLock([&]{
constraint = static_cast<btPoint2PointConstraint*>(_constraint);
pivotInA = _pivotInA;
otherEntityID = _otherID;
pivotInB = _pivotInB;
});
if (constraint) {
return constraint;
}
static QString repeatedBallSocketNoRigidBody = LogHandler::getInstance().addRepeatedMessageRegex(
"ObjectConstraintBallSocket::getConstraint -- no rigidBody.*");
btRigidBody* rigidBodyA = getRigidBody();
if (!rigidBodyA) {
qCDebug(physics) << "ObjectConstraintBallSocket::getConstraint -- no rigidBodyA";
return nullptr;
}
if (!otherEntityID.isNull()) {
// This constraint is between two entities... find the other rigid body.
btRigidBody* rigidBodyB = getOtherRigidBody(otherEntityID);
if (!rigidBodyB) {
qCDebug(physics) << "ObjectConstraintBallSocket::getConstraint -- no rigidBodyB";
return nullptr;
}
constraint = new btPoint2PointConstraint(*rigidBodyA, *rigidBodyB, glmToBullet(pivotInA), glmToBullet(pivotInB));
} else {
// This constraint is between an entity and the world-frame.
constraint = new btPoint2PointConstraint(*rigidBodyA, glmToBullet(pivotInA));
}
withWriteLock([&]{
_constraint = constraint;
});
// if we don't wake up rigidBodyA, we may not send the dynamicData property over the network
forceBodyNonStatic();
activateBody();
updateBallSocket();
return constraint;
}
bool ObjectConstraintBallSocket::updateArguments(QVariantMap arguments) {
glm::vec3 pivotInA;
QUuid otherEntityID;
glm::vec3 pivotInB;
bool needUpdate = false;
bool somethingChanged = ObjectDynamic::updateArguments(arguments);
withReadLock([&]{
bool ok = true;
pivotInA = EntityDynamicInterface::extractVec3Argument("ball-socket constraint", arguments, "pivot", ok, false);
if (!ok) {
pivotInA = _pivotInA;
}
ok = true;
otherEntityID = QUuid(EntityDynamicInterface::extractStringArgument("ball-socket constraint",
arguments, "otherEntityID", ok, false));
if (!ok) {
otherEntityID = _otherID;
}
ok = true;
pivotInB = EntityDynamicInterface::extractVec3Argument("ball-socket constraint", arguments, "otherPivot", ok, false);
if (!ok) {
pivotInB = _pivotInB;
}
if (somethingChanged ||
pivotInA != _pivotInA ||
otherEntityID != _otherID ||
pivotInB != _pivotInB) {
// something changed
needUpdate = true;
}
});
if (needUpdate) {
withWriteLock([&] {
_pivotInA = pivotInA;
_otherID = otherEntityID;
_pivotInB = pivotInB;
_active = true;
auto ownerEntity = _ownerEntity.lock();
if (ownerEntity) {
ownerEntity->setDynamicDataDirty(true);
ownerEntity->setDynamicDataNeedsTransmit(true);
}
});
updateBallSocket();
}
return true;
}
QVariantMap ObjectConstraintBallSocket::getArguments() {
QVariantMap arguments = ObjectDynamic::getArguments();
withReadLock([&] {
arguments["pivot"] = glmToQMap(_pivotInA);
arguments["otherEntityID"] = _otherID;
arguments["otherPivot"] = glmToQMap(_pivotInB);
});
return arguments;
}
QByteArray ObjectConstraintBallSocket::serialize() const {
QByteArray serializedConstraintArguments;
QDataStream dataStream(&serializedConstraintArguments, QIODevice::WriteOnly);
dataStream << DYNAMIC_TYPE_BALL_SOCKET;
dataStream << getID();
dataStream << ObjectConstraintBallSocket::constraintVersion;
withReadLock([&] {
dataStream << localTimeToServerTime(_expires);
dataStream << _tag;
dataStream << _pivotInA;
dataStream << _otherID;
dataStream << _pivotInB;
});
return serializedConstraintArguments;
}
void ObjectConstraintBallSocket::deserialize(QByteArray serializedArguments) {
QDataStream dataStream(serializedArguments);
EntityDynamicType type;
dataStream >> type;
assert(type == getType());
QUuid id;
dataStream >> id;
assert(id == getID());
uint16_t serializationVersion;
dataStream >> serializationVersion;
if (serializationVersion != ObjectConstraintBallSocket::constraintVersion) {
assert(false);
return;
}
withWriteLock([&] {
quint64 serverExpires;
dataStream >> serverExpires;
_expires = serverTimeToLocalTime(serverExpires);
dataStream >> _tag;
dataStream >> _pivotInA;
dataStream >> _otherID;
dataStream >> _pivotInB;
_active = true;
});
}