make action-factory interface and subclass it in Interface. this allows an action to use avatar data. the login the AvatarActionHold is still bogus.

This commit is contained in:
Seth Alves 2015-06-10 12:04:44 -07:00
parent b1a209b9db
commit 3dcc6c9b8c
19 changed files with 413 additions and 58 deletions

View file

@ -100,6 +100,7 @@
#include "ModelPackager.h"
#include "Util.h"
#include "InterfaceLogging.h"
#include "InterfaceActionFactory.h"
#include "avatar/AvatarManager.h"
@ -257,6 +258,7 @@ bool setupEssentials(int& argc, char** argv) {
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
DependencyManager::registerInheritance<AvatarHashMap, AvatarManager>();
DependencyManager::registerInheritance<EntityActionFactoryInterface, InterfaceActionFactory>();
Setting::init();
@ -293,7 +295,8 @@ bool setupEssentials(int& argc, char** argv) {
auto discoverabilityManager = DependencyManager::set<DiscoverabilityManager>();
auto sceneScriptingInterface = DependencyManager::set<SceneScriptingInterface>();
auto offscreenUi = DependencyManager::set<OffscreenUi>();
auto pathUtils = DependencyManager::set<PathUtils>();
auto pathUtils = DependencyManager::set<PathUtils>();
auto actionFactory = DependencyManager::set<InterfaceActionFactory>();
return true;
}

View file

@ -0,0 +1,49 @@
//
// InterfaceActionFactory.cpp
// libraries/entities/src
//
// Created by Seth Alves on 2015-6-2
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <avatar/AvatarActionHold.h>
#include <ObjectActionPullToPoint.h>
#include <ObjectActionSpring.h>
#include "InterfaceActionFactory.h"
EntityActionPointer InterfaceActionFactory::factory(EntitySimulation* simulation,
EntityActionType type,
QUuid id,
EntityItemPointer ownerEntity,
QVariantMap arguments) {
EntityActionPointer action = nullptr;
switch (type) {
case ACTION_TYPE_NONE:
return nullptr;
case ACTION_TYPE_PULL_TO_POINT:
action = (EntityActionPointer) new ObjectActionPullToPoint(id, ownerEntity);
break;
case ACTION_TYPE_SPRING:
action = (EntityActionPointer) new ObjectActionSpring(id, ownerEntity);
break;
case ACTION_TYPE_HOLD:
action = (EntityActionPointer) new AvatarActionHold(id, ownerEntity);
break;
}
bool ok = action->updateArguments(arguments);
if (ok) {
ownerEntity->addAction(simulation, action);
return action;
}
action = nullptr;
return action;
}

View file

@ -0,0 +1,28 @@
//
// InterfaceActionFactory.cpp
// interface/src/
//
// Created by Seth Alves on 2015-6-10
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_InterfaceActionFactory_h
#define hifi_InterfaceActionFactory_h
#include "EntityActionFactoryInterface.h"
class InterfaceActionFactory : public EntityActionFactoryInterface {
public:
InterfaceActionFactory() : EntityActionFactoryInterface() { }
virtual ~InterfaceActionFactory() { }
virtual EntityActionPointer factory(EntitySimulation* simulation,
EntityActionType type,
QUuid id,
EntityItemPointer ownerEntity,
QVariantMap arguments);
};
#endif // hifi_InterfaceActionFactory_h

View file

@ -0,0 +1,111 @@
//
// AvatarActionHold.cpp
// interface/src/avatar/
//
// Created by Seth Alves 2015-6-9
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "avatar/MyAvatar.h"
#include "avatar/AvatarManager.h"
#include "AvatarActionHold.h"
AvatarActionHold::AvatarActionHold(QUuid id, EntityItemPointer ownerEntity) :
ObjectAction(id, ownerEntity) {
#if WANT_DEBUG
qDebug() << "AvatarActionHold::AvatarActionHold";
#endif
}
AvatarActionHold::~AvatarActionHold() {
#if WANT_DEBUG
qDebug() << "AvatarActionHold::~AvatarActionHold";
#endif
}
void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
// handle the linear part
if (_linearOffsetSet) {
}
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
glm::vec3 palmPosition = myAvatar->getRightPalmPosition();
glm::vec3 position = getPosition();
glm::vec3 positionalTarget = palmPosition + _linearOffset;
glm::vec3 offset = positionalTarget - position;
float offsetLength = glm::length(offset);
float speed = offsetLength / _timeScale;
if (offsetLength > IGNORE_POSITION_DELTA) {
glm::vec3 newVelocity = glm::normalize(offset) * speed;
setLinearVelocity(newVelocity);
} else {
setLinearVelocity(glm::vec3(0.0f));
}
// handle rotation
if (_angularOffsetSet) {
glm::quat bodyRotation = getRotation();
// if qZero and qOne are too close to each other, we can get NaN for angle.
auto alignmentDot = glm::dot(bodyRotation, _angularOffset);
const float almostOne = 0.99999;
if (glm::abs(alignmentDot) < almostOne) {
glm::quat target = _angularOffset;
if (alignmentDot < 0) {
target = -target;
}
glm::quat qZeroInverse = glm::inverse(bodyRotation);
glm::quat deltaQ = target * qZeroInverse;
glm::vec3 axis = glm::axis(deltaQ);
float angle = glm::angle(deltaQ);
if (isNaN(angle)) {
qDebug() << "AvatarActionHold::updateAction angle =" << angle
<< "body-rotation =" << bodyRotation.x << bodyRotation.y << bodyRotation.z << bodyRotation.w
<< "target-rotation ="
<< target.x << target.y << target.z<< target.w;
}
assert(!isNaN(angle));
glm::vec3 newAngularVelocity = (angle / _timeScale) * glm::normalize(axis);
setAngularVelocity(newAngularVelocity);
} else {
setAngularVelocity(glm::vec3(0.0f));
}
}
}
bool AvatarActionHold::updateArguments(QVariantMap arguments) {
// targets are required, spring-constants are optional
bool ptOk = true;
glm::vec3 linearOffset =
EntityActionInterface::extractVec3Argument("spring action", arguments, "targetPosition", ptOk, false);
bool rtOk = true;
glm::quat angularOffset =
EntityActionInterface::extractQuatArgument("spring action", arguments, "targetRotation", rtOk, false);
lockForWrite();
_linearOffsetSet = _angularOffsetSet = false;
if (ptOk) {
_linearOffset = linearOffset;
_linearOffsetSet = true;
}
if (rtOk) {
_angularOffset = angularOffset;
_angularOffsetSet = true;
}
_active = true;
unlock();
return true;
}

View file

@ -0,0 +1,39 @@
//
// AvatarActionHold.h
// interface/src/avatar/
//
// Created by Seth Alves 2015-6-9
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_AvatarActionHold_h
#define hifi_AvatarActionHold_h
#include <QUuid>
#include <EntityItem.h>
#include <ObjectAction.h>
class AvatarActionHold : public ObjectAction {
public:
AvatarActionHold(QUuid id, EntityItemPointer ownerEntity);
virtual ~AvatarActionHold();
virtual bool updateArguments(QVariantMap arguments);
virtual void updateActionWorker(float deltaTimeStep);
private:
glm::vec3 _linearOffset;
bool _linearOffsetSet;
glm::quat _angularOffset;
bool _angularOffsetSet;
float _timeScale = 0.01;
};
#endif // hifi_AvatarActionHold_h

View file

@ -0,0 +1,33 @@
//
// EntityActionFactoryInterface.cpp
// libraries/entities/src
//
// Created by Seth Alves on 2015-6-2
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_EntityActionFactoryInterface_h
#define hifi_EntityActionFactoryInterface_h
#include <DependencyManager.h>
#include "EntityActionInterface.h"
class EntityActionFactoryInterface : public QObject, public Dependency {
Q_OBJECT
SINGLETON_DEPENDENCY
public:
EntityActionFactoryInterface() { }
virtual ~EntityActionFactoryInterface() { }
virtual EntityActionPointer factory(EntitySimulation* simulation,
EntityActionType type,
QUuid id,
EntityItemPointer ownerEntity,
QVariantMap arguments) { assert(false); }
};
#endif // hifi_EntityActionFactoryInterface_h

View file

@ -38,6 +38,8 @@ QString EntityActionInterface::actionTypeToString(EntityActionType actionType) {
return "pullToPoint";
case ACTION_TYPE_SPRING:
return "spring";
case ACTION_TYPE_HOLD:
return "hold";
}
assert(false);
return "none";

View file

@ -14,13 +14,16 @@
#include <QUuid>
#include "EntityItem.h"
class EntitySimulation;
enum EntityActionType {
// keep these synchronized with actionTypeFromString and actionTypeToString
ACTION_TYPE_NONE,
ACTION_TYPE_PULL_TO_POINT,
ACTION_TYPE_SPRING
ACTION_TYPE_SPRING,
ACTION_TYPE_HOLD
};
@ -40,6 +43,14 @@ public:
static QString actionTypeToString(EntityActionType actionType);
protected:
virtual glm::vec3 getPosition() = 0;
virtual void setPosition(glm::vec3 position) = 0;
virtual glm::quat getRotation() = 0;
virtual void setRotation(glm::quat rotation) = 0;
virtual glm::vec3 getLinearVelocity() = 0;
virtual void setLinearVelocity(glm::vec3 linearVelocity) = 0;
virtual glm::vec3 getAngularVelocity() = 0;
virtual void setAngularVelocity(glm::vec3 angularVelocity) = 0;
static glm::vec3 extractVec3Argument (QString objectName, QVariantMap arguments,
QString argumentName, bool& ok, bool required = true);
@ -49,6 +60,7 @@ protected:
QString argumentName, bool& ok, bool required = true);
};
typedef std::shared_ptr<EntityActionInterface> EntityActionPointer;
#endif // hifi_EntityActionInterface_h

View file

@ -28,13 +28,16 @@
#include "EntityItemID.h"
#include "EntityItemProperties.h"
#include "EntityItemPropertiesDefaults.h"
#include "EntityActionInterface.h"
#include "EntityTypes.h"
class EntitySimulation;
class EntityTreeElement;
class EntityTreeElementExtraEncodeData;
class EntityActionInterface;
typedef std::shared_ptr<EntityActionInterface> EntityActionPointer;
namespace render {
class Scene;
class PendingChanges;

View file

@ -17,6 +17,8 @@
#include "ZoneEntityItem.h"
#include "EntitiesLogging.h"
#include "EntitySimulation.h"
#include "EntityActionInterface.h"
#include "EntityActionFactoryInterface.h"
#include "EntityScriptingInterface.h"
@ -491,12 +493,13 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString,
const QUuid& entityID,
const QVariantMap& arguments) {
QUuid actionID = QUuid::createUuid();
auto actionFactory = DependencyManager::get<EntityActionFactoryInterface>();
bool success = actionWorker(entityID, [&](EntitySimulation* simulation, EntityItemPointer entity) {
EntityActionType actionType = EntityActionInterface::actionTypeFromString(actionTypeString);
if (actionType == ACTION_TYPE_NONE) {
return false;
}
if (simulation->actionFactory(actionType, actionID, entity, arguments)) {
if (actionFactory->factory(simulation, actionType, actionID, entity, arguments)) {
return true;
}
return false;

View file

@ -18,6 +18,7 @@
#include <PerfStat.h>
#include "EntityActionInterface.h"
#include "EntityItem.h"
#include "EntityTree.h"
@ -56,10 +57,6 @@ public:
friend class EntityTree;
virtual EntityActionPointer actionFactory(EntityActionType type,
QUuid id,
EntityItemPointer ownerEntity,
QVariantMap arguments) { return nullptr; }
virtual void addAction(EntityActionPointer action) { _actionsToAdd += action; }
virtual void removeAction(const QUuid actionID) { _actionsToRemove += actionID; }
virtual void removeActions(QList<QUuid> actionIDsToRemove) { _actionsToRemove += actionIDsToRemove; }

View file

@ -35,15 +35,9 @@ void ObjectAction::updateAction(btCollisionWorld* collisionWorld, btScalar delta
// don't risk hanging the thread running the physics simulation
return;
}
void* physicsInfo = _ownerEntity->getPhysicsInfo();
if (physicsInfo) {
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
btRigidBody* rigidBody = motionState->getRigidBody();
if (rigidBody) {
updateActionWorker(collisionWorld, deltaTimeStep, motionState, rigidBody);
}
}
updateActionWorker(deltaTimeStep);
unlock();
}
@ -53,3 +47,87 @@ void ObjectAction::debugDraw(btIDebugDraw* debugDrawer) {
void ObjectAction::removeFromSimulation(EntitySimulation* simulation) const {
simulation->removeAction(_id);
}
btRigidBody* ObjectAction::getRigidBody() {
if (!_ownerEntity) {
return nullptr;
}
void* physicsInfo = _ownerEntity->getPhysicsInfo();
if (!physicsInfo) {
return nullptr;
}
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
return motionState->getRigidBody();
}
glm::vec3 ObjectAction::getPosition() {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return glm::vec3(0.0f);
}
return bulletToGLM(rigidBody->getCenterOfMassPosition());
}
void ObjectAction::setPosition(glm::vec3 position) {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return;
}
// XXX
// void setWorldTransform (const btTransform &worldTrans)
assert(false);
rigidBody->activate();
}
glm::quat ObjectAction::getRotation() {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return glm::quat(0.0f, 0.0f, 0.0f, 1.0f);
}
return bulletToGLM(rigidBody->getOrientation());
}
void ObjectAction::setRotation(glm::quat rotation) {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return;
}
// XXX
// void setWorldTransform (const btTransform &worldTrans)
assert(false);
rigidBody->activate();
}
glm::vec3 ObjectAction::getLinearVelocity() {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return glm::vec3(0.0f);
}
return bulletToGLM(rigidBody->getLinearVelocity());
}
void ObjectAction::setLinearVelocity(glm::vec3 linearVelocity) {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return;
}
rigidBody->setLinearVelocity(glmToBullet(glm::vec3(0.0f)));
rigidBody->activate();
}
glm::vec3 ObjectAction::getAngularVelocity() {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return glm::vec3(0.0f);
}
return bulletToGLM(rigidBody->getAngularVelocity());
}
void ObjectAction::setAngularVelocity(glm::vec3 angularVelocity) {
auto rigidBody = getRigidBody();
if (!rigidBody) {
return;
}
rigidBody->setAngularVelocity(glmToBullet(angularVelocity));
rigidBody->activate();
}

View file

@ -18,8 +18,10 @@
#include <btBulletDynamicsCommon.h>
#include <EntityItem.h>
#include "ObjectMotionState.h"
#include "BulletUtil.h"
#include "EntityActionInterface.h"
class ObjectAction : public btActionInterface, public EntityActionInterface {
@ -34,8 +36,7 @@ public:
virtual bool updateArguments(QVariantMap arguments) { return false; }
// this is called from updateAction and should be overridden by subclasses
virtual void updateActionWorker(btCollisionWorld* collisionWorld, btScalar deltaTimeStep,
ObjectMotionState* motionState, btRigidBody* rigidBody) {}
virtual void updateActionWorker(float deltaTimeStep) {}
// these are from btActionInterface
virtual void updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep);
@ -46,6 +47,16 @@ private:
QReadWriteLock _lock;
protected:
btRigidBody* getRigidBody();
virtual glm::vec3 getPosition();
virtual void setPosition(glm::vec3 position);
virtual glm::quat getRotation();
virtual void setRotation(glm::quat rotation);
virtual glm::vec3 getLinearVelocity();
virtual void setLinearVelocity(glm::vec3 linearVelocity);
virtual glm::vec3 getAngularVelocity();
virtual void setAngularVelocity(glm::vec3 angularVelocity);
bool tryLockForRead() { return _lock.tryLockForRead(); }
void lockForWrite() { _lock.lockForWrite(); }
void unlock() { _lock.unlock(); }

View file

@ -24,8 +24,17 @@ ObjectActionPullToPoint::~ObjectActionPullToPoint() {
#endif
}
void ObjectActionPullToPoint::updateActionWorker(btCollisionWorld* collisionWorld, btScalar deltaTimeStep,
ObjectMotionState* motionState, btRigidBody* rigidBody) {
void ObjectActionPullToPoint::updateActionWorker(btScalar deltaTimeStep) {
void* physicsInfo = _ownerEntity->getPhysicsInfo();
if (!physicsInfo) {
return;
}
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
btRigidBody* rigidBody = motionState->getRigidBody();
if (!rigidBody) {
return;
}
glm::vec3 offset = _target - bulletToGLM(rigidBody->getCenterOfMassPosition());
float offsetLength = glm::length(offset);
if (offsetLength > IGNORE_POSITION_DELTA) {

View file

@ -23,8 +23,7 @@ public:
virtual ~ObjectActionPullToPoint();
virtual bool updateArguments(QVariantMap arguments);
virtual void updateActionWorker(btCollisionWorld* collisionWorld, btScalar deltaTimeStep,
ObjectMotionState* motionState, btRigidBody* rigidBody);
virtual void updateActionWorker(float deltaTimeStep);
private:

View file

@ -24,8 +24,17 @@ ObjectActionSpring::~ObjectActionSpring() {
#endif
}
void ObjectActionSpring::updateActionWorker(btCollisionWorld* collisionWorld, btScalar deltaTimeStep,
ObjectMotionState* motionState, btRigidBody* rigidBody) {
void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) {
void* physicsInfo = _ownerEntity->getPhysicsInfo();
if (!physicsInfo) {
return;
}
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
btRigidBody* rigidBody = motionState->getRigidBody();
if (!rigidBody) {
return;
}
// handle the linear part
if (_positionalTargetSet) {
glm::vec3 offset = _positionalTarget - bulletToGLM(rigidBody->getCenterOfMassPosition());

View file

@ -23,8 +23,7 @@ public:
virtual ~ObjectActionSpring();
virtual bool updateArguments(QVariantMap arguments);
virtual void updateActionWorker(btCollisionWorld* collisionWorld, btScalar deltaTimeStep,
ObjectMotionState* motionState, btRigidBody* rigidBody);
virtual void updateActionWorker(float deltaTimeStep);
private:

View file

@ -9,11 +9,11 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "PhysicsHelpers.h"
#include "PhysicsLogging.h"
#include "ShapeManager.h"
#include "ObjectActionPullToPoint.h"
#include "ObjectActionSpring.h"
#include "PhysicalEntitySimulation.h"
@ -235,32 +235,6 @@ void PhysicalEntitySimulation::handleCollisionEvents(CollisionEvents& collisionE
}
}
EntityActionPointer PhysicalEntitySimulation::actionFactory(EntityActionType type,
QUuid id,
EntityItemPointer ownerEntity,
QVariantMap arguments) {
EntityActionPointer action = nullptr;
switch (type) {
case ACTION_TYPE_NONE:
return nullptr;
case ACTION_TYPE_PULL_TO_POINT:
action = (EntityActionPointer) new ObjectActionPullToPoint(id, ownerEntity);
break;
case ACTION_TYPE_SPRING:
action = (EntityActionPointer) new ObjectActionSpring(id, ownerEntity);
break;
}
bool ok = action->updateArguments(arguments);
if (ok) {
ownerEntity->addAction(this, action);
return action;
}
action = nullptr;
return action;
}
void PhysicalEntitySimulation::applyActionChanges() {
if (_physicsEngine) {
foreach (EntityActionPointer actionToAdd, _actionsToAdd) {

View file

@ -32,10 +32,6 @@ public:
void init(EntityTree* tree, PhysicsEngine* engine, EntityEditPacketSender* packetSender);
virtual EntityActionPointer actionFactory(EntityActionType type,
QUuid id,
EntityItemPointer ownerEntity,
QVariantMap arguments);
virtual void applyActionChanges();
protected: // only called by EntitySimulation