diff --git a/examples/sit.js b/examples/sit.js index 0f4b199855..072471aa30 100644 --- a/examples/sit.js +++ b/examples/sit.js @@ -89,7 +89,12 @@ var sittingDownAnimation = function(deltaTime) { var pos = { x: startPosition.x - 0.3 * factor, y: startPosition.y - 0.5 * factor, z: startPosition.z}; MyAvatar.position = pos; - } + } else { + Script.update.disconnect(sittingDownAnimation); + if (seat.model) { + MyAvatar.setModelReferential(seat.model.id); + } + } } var standingUpAnimation = function(deltaTime) { @@ -103,7 +108,10 @@ var standingUpAnimation = function(deltaTime) { var pos = { x: startPosition.x + 0.3 * (passedTime/animationLenght), y: startPosition.y + 0.5 * (passedTime/animationLenght), z: startPosition.z}; MyAvatar.position = pos; - } + } else { + Script.update.disconnect(standingUpAnimation); + + } } var goToSeatAnimation = function(deltaTime) { @@ -147,7 +155,8 @@ function standUp() { print("standUp sitting status: " + Settings.getValue(sittingSettingsHandle, false)); passedTime = 0.0; startPosition = MyAvatar.position; - try{ + MyAvatar.clearReferential(); + try{ Script.update.disconnect(sittingDownAnimation); } catch (e){} Script.update.connect(standingUpAnimation); @@ -197,8 +206,10 @@ Controller.mousePressEvent.connect(function(event) { var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); if (clickedOverlay == sitDownButton) { + seat.model = null; sitDown(); } else if (clickedOverlay == standUpButton) { + seat.model = null; standUp(); } else { var pickRay = Camera.computePickRay(event.x, event.y); @@ -214,6 +225,7 @@ Controller.mousePressEvent.connect(function(event) { model.properties.sittingPoints[i].indicator.position, model.properties.sittingPoints[i].indicator.scale / 2)) { clickedOnSeat = true; + seat.model = model; seat.position = model.properties.sittingPoints[i].indicator.position; seat.rotation = model.properties.sittingPoints[i].indicator.orientation; } @@ -355,6 +367,7 @@ Script.update.connect(update); Controller.keyPressEvent.connect(keyPressEvent); Script.scriptEnding.connect(function() { + MyAvatar.clearReferential(); for (var i = 0; i < pose.length; i++){ MyAvatar.clearJointData(pose[i].joint); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 05a4a08c48..7eb087c531 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2139,12 +2139,6 @@ void Application::update(float deltaTime) { _prioVR.update(deltaTime); } - { - PerformanceTimer perfTimer("myAvatar"); - updateMyAvatarLookAtPosition(); - updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes - } - // Dispatch input events _controllerScriptingInterface.updateInputControllers(); @@ -2176,6 +2170,12 @@ void Application::update(float deltaTime) { PerformanceTimer perfTimer("overlays"); _overlays.update(deltaTime); } + + { + PerformanceTimer perfTimer("myAvatar"); + updateMyAvatarLookAtPosition(); + updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes + } { PerformanceTimer perfTimer("emitSimulating"); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 27c4e39062..c9e03d15cc 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -27,6 +27,7 @@ #include "Hand.h" #include "Head.h" #include "Menu.h" +#include "ModelReferential.h" #include "Physics.h" #include "world.h" #include "devices/OculusManager.h" @@ -102,6 +103,31 @@ float Avatar::getLODDistance() const { void Avatar::simulate(float deltaTime) { PerformanceTimer perfTimer("simulate"); + + // update the avatar's position according to its referential + if (_referential) { + if (_referential->hasExtraData()) { + ModelTree* tree = Application::getInstance()->getModels()->getTree(); + switch (_referential->type()) { + case Referential::MODEL: + _referential = new ModelReferential(_referential, + tree, + this); + break; + case Referential::JOINT: + _referential = new JointReferential(_referential, + tree, + this); + break; + default: + qDebug() << "[WARNING] Avatar::simulate(): Unknown referential type."; + break; + } + } + + _referential->update(); + } + if (_scale != _targetScale) { setScale(_targetScale); } @@ -218,6 +244,9 @@ static TextRenderer* textRenderer(TextRendererType type) { } void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { + if (_referential) { + _referential->update(); + } if (glm::distance(Application::getInstance()->getAvatar()->getPosition(), _position) < 10.0f) { @@ -268,7 +297,7 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { float boundingRadius = getBillboardSize(); ViewFrustum* frustum = (renderMode == Avatar::SHADOW_RENDER_MODE) ? Application::getInstance()->getShadowViewFrustum() : Application::getInstance()->getViewFrustum(); - if (frustum->sphereInFrustum(_position, boundingRadius) == ViewFrustum::OUTSIDE) { + if (frustum->sphereInFrustum(getPosition(), boundingRadius) == ViewFrustum::OUTSIDE) { return; } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 6b7408309d..555a0f6d32 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -209,7 +209,7 @@ protected: virtual void renderAttachments(RenderMode renderMode); virtual void updateJointMappings(); - + private: bool _initialized; diff --git a/interface/src/avatar/ModelReferential.cpp b/interface/src/avatar/ModelReferential.cpp new file mode 100644 index 0000000000..d38abae70a --- /dev/null +++ b/interface/src/avatar/ModelReferential.cpp @@ -0,0 +1,189 @@ +// +// ModelReferential.cpp +// +// +// Created by Clement on 7/30/14. +// Copyright 2014 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 + +#include "ModelTree.h" +#include "../renderer/Model.h" + +#include "ModelReferential.h" + +ModelReferential::ModelReferential(Referential* referential, ModelTree* tree, AvatarData* avatar) : + Referential(MODEL, avatar), + _tree(tree) { + _translation = referential->getTranslation(); + _rotation = referential->getRotation(); + _scale = referential->getScale(); + unpackExtraData(reinterpret_cast(referential->getExtraData().data()), + referential->getExtraData().size()); + + if (!isValid()) { + qDebug() << "ModelReferential::copyConstructor(): Not Valid"; + return; + } + + const ModelItem* item = _tree->findModelByID(_modelID); + if (item != NULL) { + _refScale = item->getRadius(); + _refRotation = item->getModelRotation(); + _refPosition = item->getPosition() * (float)TREE_SCALE; + update(); + } +} + +ModelReferential::ModelReferential(uint32_t modelID, ModelTree* tree, AvatarData* avatar) : + Referential(MODEL, avatar), + _modelID(modelID), + _tree(tree) +{ + const ModelItem* item = _tree->findModelByID(_modelID); + if (!isValid() || item == NULL) { + qDebug() << "ModelReferential::constructor(): Not Valid"; + _isValid = false; + return; + } + + _refScale = item->getRadius(); + _refRotation = item->getModelRotation(); + _refPosition = item->getPosition() * (float)TREE_SCALE; + + glm::quat refInvRot = glm::inverse(_refRotation); + _scale = _avatar->getTargetScale() / _refScale; + _rotation = refInvRot * _avatar->getOrientation(); + _translation = refInvRot * (avatar->getPosition() - _refPosition) / _refScale; +} + +void ModelReferential::update() { + const ModelItem* item = _tree->findModelByID(_modelID); + if (!isValid() || item == NULL || _avatar == NULL) { + return; + } + + bool somethingChanged = false; + if (item->getRadius() != _refScale) { + _refScale = item->getRadius(); + _avatar->setTargetScale(_refScale * _scale, true); + somethingChanged = true; + } + if (item->getModelRotation() != _refRotation) { + _refRotation = item->getModelRotation(); + _avatar->setOrientation(_refRotation * _rotation, true); + somethingChanged = true; + } + if (item->getPosition() != _refPosition || somethingChanged) { + _refPosition = item->getPosition(); + _avatar->setPosition(_refPosition * (float)TREE_SCALE + _refRotation * (_translation * _refScale), true); + } +} + +int ModelReferential::packExtraData(unsigned char* destinationBuffer) const { + memcpy(destinationBuffer, &_modelID, sizeof(_modelID)); + return sizeof(_modelID); +} + +int ModelReferential::unpackExtraData(const unsigned char *sourceBuffer, int size) { + memcpy(&_modelID, sourceBuffer, sizeof(_modelID)); + return sizeof(_modelID); +} + +JointReferential::JointReferential(Referential* referential, ModelTree* tree, AvatarData* avatar) : + ModelReferential(referential, tree, avatar) +{ + _type = JOINT; + if (!isValid()) { + qDebug() << "JointReferential::copyConstructor(): Not Valid"; + return; + } + + const ModelItem* item = _tree->findModelByID(_modelID); + const Model* model = getModel(item); + if (!isValid() || model == NULL || _jointIndex >= model->getJointStateCount()) { + _refScale = item->getRadius(); + model->getJointRotationInWorldFrame(_jointIndex, _refRotation); + model->getJointPositionInWorldFrame(_jointIndex, _refPosition); + } + update(); +} + +JointReferential::JointReferential(uint32_t jointIndex, uint32_t modelID, ModelTree* tree, AvatarData* avatar) : + ModelReferential(modelID, tree, avatar), + _jointIndex(jointIndex) +{ + _type = JOINT; + const ModelItem* item = _tree->findModelByID(_modelID); + const Model* model = getModel(item); + if (!isValid() || model == NULL || _jointIndex >= model->getJointStateCount()) { + qDebug() << "JointReferential::constructor(): Not Valid"; + _isValid = false; + return; + } + + _refScale = item->getRadius(); + model->getJointRotationInWorldFrame(_jointIndex, _refRotation); + model->getJointPositionInWorldFrame(_jointIndex, _refPosition); + + glm::quat refInvRot = glm::inverse(_refRotation); + _scale = _avatar->getTargetScale() / _refScale; + _rotation = refInvRot * _avatar->getOrientation(); + _translation = refInvRot * (avatar->getPosition() - _refPosition) / _refScale; +} + +void JointReferential::update() { + const ModelItem* item = _tree->findModelByID(_modelID); + const Model* model = getModel(item); + if (!isValid() || model == NULL || _jointIndex >= model->getJointStateCount()) { + return; + } + + bool somethingChanged = false; + if (item->getRadius() != _refScale) { + _refScale = item->getRadius(); + _avatar->setTargetScale(_refScale * _scale, true); + somethingChanged = true; + } + if (item->getModelRotation() != _refRotation) { + model->getJointRotationInWorldFrame(_jointIndex, _refRotation); + _avatar->setOrientation(_refRotation * _rotation, true); + somethingChanged = true; + } + if (item->getPosition() != _refPosition || somethingChanged) { + model->getJointPositionInWorldFrame(_jointIndex, _refPosition); + _avatar->setPosition(_refPosition + _refRotation * (_translation * _refScale), true); + } +} + +const Model* JointReferential::getModel(const ModelItem* item) { + ModelItemFBXService* fbxService = _tree->getFBXService(); + if (item != NULL && fbxService != NULL) { + return fbxService->getModelForModelItem(*item); + } + return NULL; +} + +int JointReferential::packExtraData(unsigned char* destinationBuffer) const { + unsigned char* startPosition = destinationBuffer; + destinationBuffer += ModelReferential::packExtraData(destinationBuffer); + + memcpy(destinationBuffer, &_jointIndex, sizeof(_jointIndex)); + destinationBuffer += sizeof(_jointIndex); + + return destinationBuffer - startPosition; +} + +int JointReferential::unpackExtraData(const unsigned char *sourceBuffer, int size) { + const unsigned char* startPosition = sourceBuffer; + sourceBuffer += ModelReferential::unpackExtraData(sourceBuffer, size); + + memcpy(&_jointIndex, sourceBuffer, sizeof(_jointIndex)); + sourceBuffer += sizeof(_jointIndex); + + return sourceBuffer - startPosition; +} \ No newline at end of file diff --git a/interface/src/avatar/ModelReferential.h b/interface/src/avatar/ModelReferential.h new file mode 100644 index 0000000000..b3a718d728 --- /dev/null +++ b/interface/src/avatar/ModelReferential.h @@ -0,0 +1,48 @@ +// +// ModelReferential.h +// +// +// Created by Clement on 7/30/14. +// Copyright 2014 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_ModelReferential_h +#define hifi_ModelReferential_h + +#include + +class ModelTree; +class Model; + +class ModelReferential : public Referential { +public: + ModelReferential(Referential* ref, ModelTree* tree, AvatarData* avatar); + ModelReferential(uint32_t modelID, ModelTree* tree, AvatarData* avatar); + virtual void update(); + +protected: + virtual int packExtraData(unsigned char* destinationBuffer) const; + virtual int unpackExtraData(const unsigned char* sourceBuffer, int size); + + uint32_t _modelID; + ModelTree* _tree; +}; + +class JointReferential : public ModelReferential { +public: + JointReferential(Referential* ref, ModelTree* tree, AvatarData* avatar); + JointReferential(uint32_t jointIndex, uint32_t modelID, ModelTree* tree, AvatarData* avatar); + virtual void update(); + +protected: + const Model* getModel(const ModelItem* item); + virtual int packExtraData(unsigned char* destinationBuffer) const; + virtual int unpackExtraData(const unsigned char* sourceBuffer, int size); + + uint32_t _jointIndex; +}; + +#endif // hifi_ModelReferential_h \ No newline at end of file diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4d2d679956..a8dfe1feb6 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -32,6 +32,7 @@ #include "Audio.h" #include "Environment.h" #include "Menu.h" +#include "ModelReferential.h" #include "MyAvatar.h" #include "Physics.h" #include "devices/Faceshift.h" @@ -108,6 +109,10 @@ void MyAvatar::reset() { } void MyAvatar::update(float deltaTime) { + if (_referential) { + _referential->update(); + } + Head* head = getHead(); head->relaxLean(deltaTime); updateFromTrackers(deltaTime); @@ -444,6 +449,32 @@ glm::vec3 MyAvatar::getRightPalmPosition() { return rightHandPosition; } +void MyAvatar::clearReferential() { + changeReferential(NULL); +} + +bool MyAvatar::setModelReferential(int id) { + ModelTree* tree = Application::getInstance()->getModels()->getTree(); + changeReferential(new ModelReferential(id, tree, this)); + if (_referential->isValid()) { + return true; + } else { + changeReferential(NULL); + return false; + } +} + +bool MyAvatar::setJointReferential(int id, int jointIndex) { + ModelTree* tree = Application::getInstance()->getModels()->getTree(); + changeReferential(new JointReferential(jointIndex, id, tree, this)); + if (!_referential->isValid()) { + return true; + } else { + changeReferential(NULL); + return false; + } +} + void MyAvatar::setLocalGravity(glm::vec3 gravity) { _motionBehaviors |= AVATAR_MOTION_OBEY_LOCAL_GRAVITY; // Environmental and Local gravities are incompatible. Since Local is being set here diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 581044c522..4f2802a35a 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -18,6 +18,8 @@ #include "Avatar.h" +class ModelItemID; + enum AvatarHandState { HAND_STATE_NULL = 0, @@ -149,6 +151,10 @@ public slots: glm::vec3 getLeftPalmPosition(); glm::vec3 getRightPalmPosition(); + void clearReferential(); + bool setModelReferential(int id); + bool setJointReferential(int id, int jointIndex); + signals: void transformChanged(); diff --git a/interface/src/models/ModelTreeRenderer.cpp b/interface/src/models/ModelTreeRenderer.cpp index 78107db699..acbb373ffc 100644 --- a/interface/src/models/ModelTreeRenderer.cpp +++ b/interface/src/models/ModelTreeRenderer.cpp @@ -76,6 +76,10 @@ const FBXGeometry* ModelTreeRenderer::getGeometryForModel(const ModelItem& model return result; } +const Model* ModelTreeRenderer::getModelForModelItem(const ModelItem& modelItem) { + return getModel(modelItem); +} + Model* ModelTreeRenderer::getModel(const ModelItem& modelItem) { Model* model = NULL; diff --git a/interface/src/models/ModelTreeRenderer.h b/interface/src/models/ModelTreeRenderer.h index d69b85efe9..63363e4ce2 100644 --- a/interface/src/models/ModelTreeRenderer.h +++ b/interface/src/models/ModelTreeRenderer.h @@ -51,7 +51,7 @@ public: virtual void render(RenderMode renderMode = DEFAULT_RENDER_MODE); virtual const FBXGeometry* getGeometryForModel(const ModelItem& modelItem); - + virtual const Model* getModelForModelItem(const ModelItem& modelItem); /// clears the tree virtual void clear(); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index c3ea2f8b50..96a5f2425b 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -36,6 +36,7 @@ using namespace std; AvatarData::AvatarData() : _sessionUUID(), _handPosition(0,0,0), + _referential(NULL), _bodyYaw(-90.f), _bodyPitch(0.0f), _bodyRoll(0.0f), @@ -62,6 +63,59 @@ AvatarData::AvatarData() : AvatarData::~AvatarData() { delete _headData; delete _handData; + delete _referential; +} + +const glm::vec3& AvatarData::getPosition() { + if (_referential) { + _referential->update(); + } + return _position; +} + +void AvatarData::setPosition(const glm::vec3 position, bool overideReferential) { + if (!_referential || overideReferential) { + _position = position; + } +} + +glm::quat AvatarData::getOrientation() const { + if (_referential) { + _referential->update(); + } + + return glm::quat(glm::radians(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll))); +} + +void AvatarData::setOrientation(const glm::quat& orientation, bool overideReferential) { + if (!_referential || overideReferential) { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(orientation)); + _bodyPitch = eulerAngles.x; + _bodyYaw = eulerAngles.y; + _bodyRoll = eulerAngles.z; + } +} + +float AvatarData::getTargetScale() const { + if (_referential) { + _referential->update(); + } + + return _targetScale; +} + +void AvatarData::setTargetScale(float targetScale, bool overideReferential) { + if (!_referential || overideReferential) { + _targetScale = targetScale; + } +} + +void AvatarData::setClampedTargetScale(float targetScale, bool overideReferential) { + + targetScale = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE); + + setTargetScale(targetScale, overideReferential); + qDebug() << "Changed scale to " << _targetScale; } glm::vec3 AvatarData::getHandPosition() const { @@ -135,11 +189,21 @@ QByteArray AvatarData::toByteArray() { // hand state setSemiNibbleAt(bitItems,HAND_STATE_START_BIT,_handState); // faceshift state - if (_headData->_isFaceshiftConnected) { setAtBit(bitItems, IS_FACESHIFT_CONNECTED); } + if (_headData->_isFaceshiftConnected) { + setAtBit(bitItems, IS_FACESHIFT_CONNECTED); + } if (_isChatCirclingEnabled) { setAtBit(bitItems, IS_CHAT_CIRCLING_ENABLED); } + if (_referential != NULL && _referential->isValid()) { + setAtBit(bitItems, HAS_REFERENTIAL); + } *destinationBuffer++ = bitItems; + + // Add referential + if (_referential != NULL && _referential->isValid()) { + destinationBuffer += _referential->packReferential(destinationBuffer); + } // If it is connected, pack up the data if (_headData->_isFaceshiftConnected) { @@ -370,18 +434,32 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { } // 1 + chatMessageSize bytes { // bitFlags and face data - unsigned char bitItems = 0; - bitItems = (unsigned char)*sourceBuffer++; - + unsigned char bitItems = *sourceBuffer++; + // key state, stored as a semi-nibble in the bitItems _keyState = (KeyState)getSemiNibbleAt(bitItems,KEY_STATE_START_BIT); - // hand state, stored as a semi-nibble in the bitItems _handState = getSemiNibbleAt(bitItems,HAND_STATE_START_BIT); _headData->_isFaceshiftConnected = oneAtBit(bitItems, IS_FACESHIFT_CONNECTED); _isChatCirclingEnabled = oneAtBit(bitItems, IS_CHAT_CIRCLING_ENABLED); + bool hasReferential = oneAtBit(bitItems, HAS_REFERENTIAL); + // Referential + if (hasReferential) { + Referential* ref = new Referential(sourceBuffer, this); + if (_referential == NULL || + ref->version() != _referential->version()) { + changeReferential(ref); + } else { + delete ref; + } + _referential->update(); + } else if (_referential != NULL) { + changeReferential(NULL); + } + + if (_headData->_isFaceshiftConnected) { float leftEyeBlink, rightEyeBlink, averageLoudness, browAudioLift; minPossibleSize += sizeof(leftEyeBlink) + sizeof(rightEyeBlink) + sizeof(averageLoudness) + sizeof(browAudioLift); @@ -503,6 +581,15 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { return sourceBuffer - startPosition; } +bool AvatarData::hasReferential() { + return _referential != NULL; +} + +void AvatarData::changeReferential(Referential *ref) { + delete _referential; + _referential = ref; +} + void AvatarData::setJointData(int index, const glm::quat& rotation) { if (index == -1) { return; @@ -803,21 +890,6 @@ void AvatarData::setJointMappingsFromNetworkReply() { networkReply->deleteLater(); } -void AvatarData::setClampedTargetScale(float targetScale) { - - targetScale = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE); - - _targetScale = targetScale; - qDebug() << "Changed scale to " << _targetScale; -} - -void AvatarData::setOrientation(const glm::quat& orientation) { - glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(orientation)); - _bodyPitch = eulerAngles.x; - _bodyYaw = eulerAngles.y; - _bodyRoll = eulerAngles.z; -} - void AvatarData::sendIdentityPacket() { QByteArray identityPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarIdentity); identityPacket.append(identityByteArray()); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 8533b8b0e8..2971598c1d 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -49,6 +49,7 @@ typedef unsigned long long quint64; #include +#include "Referential.h" #include "HeadData.h" #include "HandData.h" @@ -80,7 +81,8 @@ const quint32 AVATAR_MOTION_SCRIPTABLE_BITS = const int KEY_STATE_START_BIT = 0; // 1st and 2nd bits const int HAND_STATE_START_BIT = 2; // 3rd and 4th bits const int IS_FACESHIFT_CONNECTED = 4; // 5th bit -const int IS_CHAT_CIRCLING_ENABLED = 5; +const int IS_CHAT_CIRCLING_ENABLED = 5; // 6th bit +const int HAS_REFERENTIAL = 6; // 7th bit static const float MAX_AVATAR_SCALE = 1000.f; static const float MIN_AVATAR_SCALE = .005f; @@ -141,8 +143,8 @@ public: const QUuid& getSessionUUID() { return _sessionUUID; } - const glm::vec3& getPosition() const { return _position; } - void setPosition(const glm::vec3 position) { _position = position; } + const glm::vec3& getPosition(); + void setPosition(const glm::vec3 position, bool overideReferential = false); glm::vec3 getHandPosition() const; void setHandPosition(const glm::vec3& handPosition); @@ -165,8 +167,8 @@ public: float getBodyRoll() const { return _bodyRoll; } void setBodyRoll(float bodyRoll) { _bodyRoll = bodyRoll; } - glm::quat getOrientation() const { return glm::quat(glm::radians(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll))); } - void setOrientation(const glm::quat& orientation); + glm::quat getOrientation() const; + void setOrientation(const glm::quat& orientation, bool overideReferential = false); glm::quat getHeadOrientation() const { return _headData->getOrientation(); } void setHeadOrientation(const glm::quat& orientation) { _headData->setOrientation(orientation); } @@ -188,9 +190,9 @@ public: void setAudioAverageLoudness(float value) { _headData->setAudioAverageLoudness(value); } // Scale - float getTargetScale() const { return _targetScale; } - void setTargetScale(float targetScale) { _targetScale = targetScale; } - void setClampedTargetScale(float targetScale); + float getTargetScale() const; + void setTargetScale(float targetScale, bool overideReferential = false); + void setClampedTargetScale(float targetScale, bool overideReferential = false); // Hand State Q_INVOKABLE void setHandState(char s) { _handState = s; } @@ -280,6 +282,8 @@ public: QElapsedTimer& getLastUpdateTimer() { return _lastUpdateTimer; } virtual float getBoundingRadius() const { return 1.f; } + + const Referential* getReferential() const { return _referential; } public slots: void sendIdentityPacket(); @@ -287,10 +291,14 @@ public slots: void setBillboardFromNetworkReply(); void setJointMappingsFromNetworkReply(); void setSessionUUID(const QUuid& id) { _sessionUUID = id; } + bool hasReferential(); + protected: QUuid _sessionUUID; glm::vec3 _position; glm::vec3 _handPosition; + + Referential* _referential; // Body rotation float _bodyYaw; // degrees @@ -340,6 +348,7 @@ protected: /// Loads the joint indices, names from the FST file (if any) virtual void updateJointMappings(); + void changeReferential(Referential* ref); private: // privatize the copy constructor and assignment operator so they cannot be called diff --git a/libraries/avatars/src/Referential.cpp b/libraries/avatars/src/Referential.cpp new file mode 100644 index 0000000000..a5a7e7e3e5 --- /dev/null +++ b/libraries/avatars/src/Referential.cpp @@ -0,0 +1,113 @@ +// +// Referential.cpp +// +// +// Created by Clement on 7/30/14. +// Copyright 2014 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 + +#include "AvatarData.h" +#include "Referential.h" + +Referential::Referential(Type type, AvatarData* avatar) : + _type(type), + _version(0), + _isValid(true), + _avatar(avatar) +{ + if (_avatar == NULL) { + _isValid = false; + return; + } + if (_avatar->hasReferential()) { + _version = _avatar->getReferential()->version() + 1; + } +} + +Referential::Referential(const unsigned char*& sourceBuffer, AvatarData* avatar) : + _isValid(false), + _avatar(avatar) +{ + // Since we can't return how many byte have been read + // We take a reference to the pointer as argument and increment the pointer ouself. + sourceBuffer += unpackReferential(sourceBuffer); + // The actual unpacking to the right referential type happens in Avatar::simulate() + // If subclassed, make sure to add a case there to unpack the new referential type correctly +} + +Referential::~Referential() { +} + +int Referential::packReferential(unsigned char* destinationBuffer) const { + const unsigned char* startPosition = destinationBuffer; + destinationBuffer += pack(destinationBuffer); + + unsigned char* sizePosition = destinationBuffer++; // Save a spot for the extra data size + char size = packExtraData(destinationBuffer); + *sizePosition = size; // write extra data size in saved spot here + destinationBuffer += size; + + return destinationBuffer - startPosition; +} + +int Referential::unpackReferential(const unsigned char* sourceBuffer) { + const unsigned char* startPosition = sourceBuffer; + sourceBuffer += unpack(sourceBuffer); + + char expectedSize = *sourceBuffer++; + char bytesRead = unpackExtraData(sourceBuffer, expectedSize); + _isValid = (bytesRead == expectedSize); + if (!_isValid) { + // Will occur if the new instance unpacking is of the wrong type + qDebug() << "[ERROR] Referential extra data overflow"; + } + sourceBuffer += expectedSize; + + return sourceBuffer - startPosition; +} + +int Referential::pack(unsigned char* destinationBuffer) const { + unsigned char* startPosition = destinationBuffer; + *destinationBuffer++ = (unsigned char)_type; + memcpy(destinationBuffer, &_version, sizeof(_version)); + destinationBuffer += sizeof(_version); + + destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, _translation, 0); + destinationBuffer += packOrientationQuatToBytes(destinationBuffer, _rotation); + destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, _scale, 0); + return destinationBuffer - startPosition; +} + +int Referential::unpack(const unsigned char* sourceBuffer) { + const unsigned char* startPosition = sourceBuffer; + _type = (Type)*sourceBuffer++; + if (_type < 0 || _type >= NUM_TYPE) { + _type = UNKNOWN; + } + memcpy(&_version, sourceBuffer, sizeof(_version)); + sourceBuffer += sizeof(_version); + + sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, _translation, 0); + sourceBuffer += unpackOrientationQuatFromBytes(sourceBuffer, _rotation); + sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((const int16_t*) sourceBuffer, &_scale, 0); + return sourceBuffer - startPosition; +} + +int Referential::packExtraData(unsigned char *destinationBuffer) const { + // Since we can't interpret that data, just store it in a buffer for later use. + memcpy(destinationBuffer, _extraDataBuffer.data(), _extraDataBuffer.size()); + return _extraDataBuffer.size(); +} + + +int Referential::unpackExtraData(const unsigned char* sourceBuffer, int size) { + _extraDataBuffer.clear(); + _extraDataBuffer.setRawData(reinterpret_cast(sourceBuffer), size); + return size; +} + diff --git a/libraries/avatars/src/Referential.h b/libraries/avatars/src/Referential.h new file mode 100644 index 0000000000..f24d66c160 --- /dev/null +++ b/libraries/avatars/src/Referential.h @@ -0,0 +1,75 @@ +// +// Referential.h +// +// +// Created by Clement on 7/30/14. +// Copyright 2014 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_Referential_h +#define hifi_Referential_h + +#include +#include + +class AvatarData; + +/// Stores and enforce the relative position of an avatar to a given referential (ie. model, joint, ...) +class Referential { +public: + enum Type { + UNKNOWN, + MODEL, + JOINT, + AVATAR, + + NUM_TYPE + }; + + Referential(const unsigned char*& sourceBuffer, AvatarData* avatar); + virtual ~Referential(); + + Type type() const { return _type; } + quint8 version() const { return _version; } + bool isValid() const { return _isValid; } + bool hasExtraData() const { return !_extraDataBuffer.isEmpty(); } + + glm::vec3 getTranslation() const { return _translation; } + glm::quat getRotation() const { return _rotation; } + float getScale() const {return _scale; } + QByteArray getExtraData() const { return _extraDataBuffer; } + + virtual void update() {} + int packReferential(unsigned char* destinationBuffer) const; + int unpackReferential(const unsigned char* sourceBuffer); + +protected: + Referential(Type type, AvatarData* avatar); + + // packs the base class data + int pack(unsigned char* destinationBuffer) const; + int unpack(const unsigned char* sourceBuffer); + // virtual functions that pack fthe extra data of subclasses (needs to be reimplemented in subclass) + virtual int packExtraData(unsigned char* destinationBuffer) const; + virtual int unpackExtraData(const unsigned char* sourceBuffer, int size); + + Type _type; + quint8 _version; + bool _isValid; + AvatarData* _avatar; + QByteArray _extraDataBuffer; + + glm::vec3 _refPosition; + glm::quat _refRotation; + float _refScale; + + glm::vec3 _translation; + glm::quat _rotation; + float _scale; +}; + + +#endif // hifi_Referential_h \ No newline at end of file diff --git a/libraries/models/src/ModelItem.h b/libraries/models/src/ModelItem.h index 3e3c46a12d..4a9a2af2c4 100644 --- a/libraries/models/src/ModelItem.h +++ b/libraries/models/src/ModelItem.h @@ -179,7 +179,6 @@ void ModelItemIDfromScriptValue(const QScriptValue &object, ModelItemID& propert /// ModelItem class - this is the actual model item class. class ModelItem { - public: ModelItem(); diff --git a/libraries/models/src/ModelTree.h b/libraries/models/src/ModelTree.h index e61cc6057e..9872e332ba 100644 --- a/libraries/models/src/ModelTree.h +++ b/libraries/models/src/ModelTree.h @@ -15,6 +15,8 @@ #include #include "ModelTreeElement.h" +class Model; + class NewlyCreatedModelHook { public: virtual void modelCreated(const ModelItem& newModel, const SharedNodePointer& senderNode) = 0; @@ -23,6 +25,7 @@ public: class ModelItemFBXService { public: virtual const FBXGeometry* getGeometryForModel(const ModelItem& modelItem) = 0; + virtual const Model* getModelForModelItem(const ModelItem& modelItem) = 0; }; class ModelTree : public Octree { @@ -80,6 +83,7 @@ public: void processEraseMessage(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode); void handleAddModelResponse(const QByteArray& packet); + ModelItemFBXService* getFBXService() const { return _fbxService; } void setFBXService(ModelItemFBXService* service) { _fbxService = service; } const FBXGeometry* getGeometryForModel(const ModelItem& modelItem) { return _fbxService ? _fbxService->getGeometryForModel(modelItem) : NULL; diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 57d1d7faac..2b8b9929e5 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -167,7 +167,7 @@ bool oneAtBit(unsigned char byte, int bitIndex) { } void setAtBit(unsigned char& byte, int bitIndex) { - byte += (1 << (7 - bitIndex)); + byte |= (1 << (7 - bitIndex)); } void clearAtBit(unsigned char& byte, int bitIndex) { @@ -176,7 +176,7 @@ void clearAtBit(unsigned char& byte, int bitIndex) { } } -int getSemiNibbleAt(unsigned char& byte, int bitIndex) { +int getSemiNibbleAt(unsigned char byte, int bitIndex) { return (byte >> (6 - bitIndex) & 3); // semi-nibbles store 00, 01, 10, or 11 } @@ -207,7 +207,7 @@ bool isBetween(int64_t value, int64_t max, int64_t min) { void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value) { //assert(value <= 3 && value >= 0); - byte += ((value & 3) << (6 - bitIndex)); // semi-nibbles store 00, 01, 10, or 11 + byte |= ((value & 3) << (6 - bitIndex)); // semi-nibbles store 00, 01, 10, or 11 } bool isInEnvironment(const char* environment) { @@ -496,7 +496,7 @@ int packFloatScalarToSignedTwoByteFixed(unsigned char* buffer, float scalar, int return sizeof(uint16_t); } -int unpackFloatScalarFromSignedTwoByteFixed(int16_t* byteFixedPointer, float* destinationPointer, int radix) { +int unpackFloatScalarFromSignedTwoByteFixed(const int16_t* byteFixedPointer, float* destinationPointer, int radix) { *destinationPointer = *byteFixedPointer / (float)(1 << radix); return sizeof(int16_t); } diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 6bb39f7e12..18494d48e4 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -82,7 +82,7 @@ int numberOfOnes(unsigned char byte); bool oneAtBit(unsigned char byte, int bitIndex); void setAtBit(unsigned char& byte, int bitIndex); void clearAtBit(unsigned char& byte, int bitIndex); -int getSemiNibbleAt(unsigned char& byte, int bitIndex); +int getSemiNibbleAt(unsigned char byte, int bitIndex); void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value); int getNthBit(unsigned char byte, int ordinal); /// determines the bit placement 0-7 of the ordinal set bit