From 10ce2cb3f0e0e61872ce11a0f1dd03620cd55899 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 21 Feb 2014 11:49:29 -0800 Subject: [PATCH] Working on sending the billboards over the network. --- assignment-client/src/avatars/AvatarMixer.cpp | 43 +++++++++++++++++++ .../src/avatars/AvatarMixerClientData.cpp | 3 +- .../src/avatars/AvatarMixerClientData.h | 6 +++ interface/src/Application.cpp | 5 +++ interface/src/avatar/MyAvatar.cpp | 22 +++++++--- interface/src/avatar/MyAvatar.h | 1 + libraries/avatars/src/AvatarData.cpp | 16 +++++++ libraries/avatars/src/AvatarData.h | 10 +++++ 8 files changed, 100 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 63bdccbab7..d7d11b78b0 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -123,6 +123,23 @@ void broadcastIdentityPacket() { } } +void broadcastBillboardPacket(const SharedNodePointer& node) { + +} + +void broadcastBillboardPackets() { + + NodeList* nodeList = NodeList::getInstance(); + + foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { + if (node->getLinkedData() && node->getType() == NodeType::Agent) { + AvatarMixerClientData* nodeData = static_cast(node->getLinkedData()); + broadcastBillboardPacket(node); + nodeData->setHasSentBillboardBetweenKeyFrames(false); + } + } +} + void AvatarMixer::nodeKilled(SharedNodePointer killedNode) { if (killedNode->getType() == NodeType::Agent && killedNode->getLinkedData()) { @@ -170,6 +187,23 @@ void AvatarMixer::readPendingDatagrams() { nodeList->broadcastToNodes(identityPacket, NodeSet() << NodeType::Agent); } } + break; + } + case PacketTypeAvatarBillboard: { + + // check if we have a matching node in our list + SharedNodePointer avatarNode = nodeList->sendingNodeForPacket(receivedPacket); + + if (avatarNode && avatarNode->getLinkedData()) { + AvatarMixerClientData* nodeData = static_cast(avatarNode->getLinkedData()); + if (nodeData->hasBillboardChangedAfterParsing(receivedPacket) + && !nodeData->hasSentBillboardBetweenKeyFrames()) { + // this avatar changed their billboard and we haven't sent a packet in this keyframe + broadcastBillboardPacket(avatarNode); + nodeData->setHasSentBillboardBetweenKeyFrames(true); + } + } + break; } case PacketTypeKillAvatar: { nodeList->processKillNode(receivedPacket); @@ -185,6 +219,7 @@ void AvatarMixer::readPendingDatagrams() { } const qint64 AVATAR_IDENTITY_KEYFRAME_MSECS = 5000; +const qint64 AVATAR_BILLBOARD_KEYFRAME_MSECS = 5000; void AvatarMixer::run() { commonInit(AVATAR_MIXER_LOGGING_NAME, NodeType::AvatarMixer); @@ -202,6 +237,9 @@ void AvatarMixer::run() { QElapsedTimer identityTimer; identityTimer.start(); + QElapsedTimer billboardTimer; + billboardTimer.start(); + while (!_isFinished) { QCoreApplication::processEvents(); @@ -219,6 +257,11 @@ void AvatarMixer::run() { // restart the timer so we do it again in AVATAR_IDENTITY_KEYFRAME_MSECS identityTimer.restart(); } + + if (billboardTimer.elapsed() >= AVATAR_BILLBOARD_KEYFRAME_MSECS) { + broadcastBillboardPackets(); + billboardTimer.restart(); + } int usecToSleep = usecTimestamp(&startTime) + (++nextFrame * AVATAR_DATA_SEND_INTERVAL_USECS) - usecTimestampNow(); diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index 0261613532..388d6f6488 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -9,7 +9,8 @@ #include "AvatarMixerClientData.h" AvatarMixerClientData::AvatarMixerClientData() : - _hasSentIdentityBetweenKeyFrames(false) + _hasSentIdentityBetweenKeyFrames(false), + _hasSentBillboardBetweenKeyFrames(false) { } diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index 8e046d9212..7240288306 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -21,9 +21,15 @@ public: bool hasSentIdentityBetweenKeyFrames() const { return _hasSentIdentityBetweenKeyFrames; } void setHasSentIdentityBetweenKeyFrames(bool hasSentIdentityBetweenKeyFrames) { _hasSentIdentityBetweenKeyFrames = hasSentIdentityBetweenKeyFrames; } + + bool hasSentBillboardBetweenKeyFrames() const { return _hasSentBillboardBetweenKeyFrames; } + void setHasSentBillboardBetweenKeyFrames(bool hasSentBillboardBetweenKeyFrames) + { _hasSentBillboardBetweenKeyFrames = hasSentBillboardBetweenKeyFrames; } + private: bool _hasSentIdentityBetweenKeyFrames; + bool _hasSentBillboardBetweenKeyFrames; }; #endif /* defined(__hifi__AvatarMixerClientData__) */ diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a71cedec70..35793cb730 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -255,6 +255,11 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : connect(identityPacketTimer, &QTimer::timeout, _myAvatar, &MyAvatar::sendIdentityPacket); identityPacketTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS); + // send the billboard packet for our avatar every few seconds + QTimer* billboardPacketTimer = new QTimer(); + connect(billboardPacketTimer, &QTimer::timeout, _myAvatar, &MyAvatar::sendBillboardPacket); + billboardPacketTimer->start(AVATAR_BILLBOARD_PACKET_SEND_INTERVAL_MSECS); + QString cachePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation); _networkAccessManager = new QNetworkAccessManager(this); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index f388f89701..61d1a8b8a8 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -9,6 +9,8 @@ #include #include +#include + #include #include @@ -335,11 +337,7 @@ void MyAvatar::simulate(float deltaTime) { _thrust = glm::vec3(0, 0, 0); // consider updating our billboard - if (!_billboardValid && _skeletonModel.isLoadedWithTextures() && getHead()->getFaceModel().isLoadedWithTextures()) { - QImage image = Application::getInstance()->renderAvatarBillboard(); - image.save("test.png"); - _billboardValid = true; - } + maybeUpdateBillboard(); } const float MAX_PITCH = 90.0f; @@ -1141,6 +1139,20 @@ void MyAvatar::updateChatCircle(float deltaTime) { _position = glm::mix(_position, targetPosition, APPROACH_RATE); } +void MyAvatar::maybeUpdateBillboard() { + if (_billboardValid || !(_skeletonModel.isLoadedWithTextures() && getHead()->getFaceModel().isLoadedWithTextures())) { + return; + } + QImage image = Application::getInstance()->renderAvatarBillboard(); + _billboard.clear(); + QBuffer buffer(&_billboard); + buffer.open(QIODevice::WriteOnly); + image.save(&buffer, "JPG"); + _billboardValid = true; + + sendBillboardPacket(); +} + void MyAvatar::setGravity(glm::vec3 gravity) { _gravity = gravity; getHead()->setGravity(_gravity); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index cbefd6ba0a..2b5be47419 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -133,6 +133,7 @@ private: void applyHardCollision(const glm::vec3& penetration, float elasticity, float damping); void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); void updateChatCircle(float deltaTime); + void maybeUpdateBillboard(); }; #endif diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 3c50f2622c..26c8abefea 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -305,6 +305,15 @@ QByteArray AvatarData::identityByteArray() { return identityData; } +bool AvatarData::hasBillboardChangedAfterParsing(const QByteArray& packet) { + QByteArray newBillboard = packet.mid(numBytesForPacketHeader(packet)); + if (newBillboard == _billboard) { + return false; + } + _billboard = newBillboard; + return true; +} + void AvatarData::setFaceModelURL(const QUrl& faceModelURL) { _faceModelURL = faceModelURL.isEmpty() ? DEFAULT_HEAD_MODEL_URL : faceModelURL; @@ -344,3 +353,10 @@ void AvatarData::sendIdentityPacket() { NodeList::getInstance()->broadcastToNodes(identityPacket, NodeSet() << NodeType::AvatarMixer); } + +void AvatarData::sendBillboardPacket() { + QByteArray billboardPacket = byteArrayWithPopulatedHeader(PacketTypeAvatarBillboard); + billboardPacket.append(_billboard); + + NodeList::getInstance()->broadcastToNodes(billboardPacket, NodeSet() << NodeType::AvatarMixer); +} diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 07c774d5e6..f597edcc3a 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -29,6 +29,7 @@ typedef unsigned long long quint64; #include #include +#include #include #include #include @@ -54,6 +55,7 @@ static const float MIN_AVATAR_SCALE = .005f; const float MAX_AUDIO_LOUDNESS = 1000.0; // close enough for mouth animation const int AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS = 1000; +const int AVATAR_BILLBOARD_PACKET_SEND_INTERVAL_MSECS = 5000; const QUrl DEFAULT_HEAD_MODEL_URL = QUrl("http://public.highfidelity.io/meshes/defaultAvatar_head.fst"); const QUrl DEFAULT_BODY_MODEL_URL = QUrl("http://public.highfidelity.io/meshes/defaultAvatar_body.fst"); @@ -151,6 +153,8 @@ public: bool hasIdentityChangedAfterParsing(const QByteArray& packet); QByteArray identityByteArray(); + bool hasBillboardChangedAfterParsing(const QByteArray& packet); + const QUrl& getFaceModelURL() const { return _faceModelURL; } QString getFaceModelURLString() const { return _faceModelURL.toString(); } const QUrl& getSkeletonModelURL() const { return _skeletonModelURL; } @@ -159,6 +163,9 @@ public: virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); virtual void setDisplayName(const QString& displayName); + void setBillboard(const QByteArray& billboard) { _billboard = billboard; } + const QByteArray& getBillboard() const { return _billboard; } + QString getFaceModelURLFromScript() const { return _faceModelURL.toString(); } void setFaceModelURLFromScript(const QString& faceModelString) { setFaceModelURL(faceModelString); } @@ -169,6 +176,7 @@ public: public slots: void sendIdentityPacket(); + void sendBillboardPacket(); protected: glm::vec3 _position; @@ -204,6 +212,8 @@ protected: float _displayNameTargetAlpha; float _displayNameAlpha; + QByteArray _billboard; + private: // privatize the copy constructor and assignment operator so they cannot be called AvatarData(const AvatarData&);