From e5959a555faa2ab053df140af0160bc67af4c7a0 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 14 Sep 2015 15:44:43 -0700 Subject: [PATCH 001/401] Move assertion in AssetRequest below error checking If the request had an error then there is no reason the assertion should be true. --- libraries/networking/src/AssetRequest.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index c0e5f0b6f2..45e925389d 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -76,8 +76,6 @@ void AssetRequest::start() { auto assetClient = DependencyManager::get(); assetClient->getAsset(_hash, _extension, start, end, [this, start, end](bool responseReceived, AssetServerError serverError, const QByteArray& data) { - Q_ASSERT(data.size() == (end - start)); - if (!responseReceived) { _error = NetworkError; } else if (serverError != AssetServerError::NoError) { @@ -93,6 +91,7 @@ void AssetRequest::start() { break; } } else { + Q_ASSERT(data.size() == (end - start)); // we need to check the hash of the received data to make sure it matches what we expect if (hashData(data).toHex() == _hash) { From 7682ab00e33f84ac65f9183e50a8258923c225af Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 29 Sep 2015 14:24:35 -0700 Subject: [PATCH 002/401] Add ReceivedMessage and receive progress --- assignment-client/src/Agent.cpp | 34 +- assignment-client/src/Agent.h | 8 +- assignment-client/src/AssignmentClient.cpp | 10 +- assignment-client/src/AssignmentClient.h | 4 +- .../src/AssignmentClientMonitor.cpp | 8 +- .../src/AssignmentClientMonitor.h | 2 +- assignment-client/src/AssignmentFactory.cpp | 14 +- assignment-client/src/AssignmentFactory.h | 2 +- assignment-client/src/assets/AssetServer.cpp | 28 +- assignment-client/src/assets/AssetServer.h | 9 +- .../src/assets/SendAssetTask.cpp | 16 +- assignment-client/src/assets/SendAssetTask.h | 4 +- .../src/assets/UploadAssetTask.cpp | 6 +- .../src/assets/UploadAssetTask.h | 6 +- assignment-client/src/audio/AudioMixer.cpp | 14 +- assignment-client/src/audio/AudioMixer.h | 6 +- .../src/audio/AudioMixerClientData.cpp | 24 +- .../src/audio/AudioMixerClientData.h | 2 +- assignment-client/src/avatars/AvatarMixer.cpp | 20 +- assignment-client/src/avatars/AvatarMixer.h | 10 +- .../src/avatars/AvatarMixerClientData.cpp | 6 +- .../src/avatars/AvatarMixerClientData.h | 2 +- .../src/entities/EntityServer.cpp | 8 +- assignment-client/src/entities/EntityServer.h | 4 +- .../octree/OctreeInboundPacketProcessor.cpp | 40 +-- .../src/octree/OctreeInboundPacketProcessor.h | 2 +- .../src/octree/OctreeQueryNode.cpp | 6 +- .../src/octree/OctreeQueryNode.h | 2 +- assignment-client/src/octree/OctreeServer.cpp | 16 +- assignment-client/src/octree/OctreeServer.h | 8 +- domain-server/src/DomainGatekeeper.cpp | 34 +- domain-server/src/DomainGatekeeper.h | 8 +- domain-server/src/DomainServer.cpp | 32 +- domain-server/src/DomainServer.h | 8 +- .../src/DomainServerSettingsManager.cpp | 6 +- .../src/DomainServerSettingsManager.h | 4 +- interface/src/Application.cpp | 15 +- interface/src/Application.h | 6 +- .../src/octree/OctreePacketProcessor.cpp | 36 ++- interface/src/octree/OctreePacketProcessor.h | 5 +- libraries/audio-client/src/AudioClient.cpp | 20 +- libraries/audio-client/src/AudioClient.h | 8 +- libraries/audio-client/src/AudioIOStats.cpp | 9 +- libraries/audio-client/src/AudioIOStats.h | 2 +- libraries/audio/src/InboundAudioStream.cpp | 18 +- libraries/audio/src/InboundAudioStream.h | 3 +- libraries/avatars/src/AvatarData.cpp | 11 +- libraries/avatars/src/AvatarData.h | 4 +- libraries/avatars/src/AvatarHashMap.cpp | 28 +- libraries/avatars/src/AvatarHashMap.h | 8 +- .../src/EntityTreeRenderer.cpp | 4 +- .../src/EntityTreeRenderer.h | 2 +- .../entities/src/EntityEditPacketSender.cpp | 4 +- .../entities/src/EntityEditPacketSender.h | 2 +- libraries/entities/src/EntityTree.cpp | 22 +- libraries/entities/src/EntityTree.h | 6 +- .../entities/src/EntityTreeHeadlessViewer.cpp | 4 +- .../entities/src/EntityTreeHeadlessViewer.h | 2 +- libraries/networking/src/AssetClient.cpp | 66 ++-- libraries/networking/src/AssetClient.h | 18 +- libraries/networking/src/AssetRequest.cpp | 2 + libraries/networking/src/Assignment.cpp | 8 +- libraries/networking/src/Assignment.h | 4 +- libraries/networking/src/DomainHandler.cpp | 19 +- libraries/networking/src/DomainHandler.h | 9 +- libraries/networking/src/LimitedNodeList.cpp | 27 +- libraries/networking/src/LimitedNodeList.h | 11 +- libraries/networking/src/NLPacketList.cpp | 1 + libraries/networking/src/NLPacketList.h | 9 +- libraries/networking/src/Node.cpp | 4 + libraries/networking/src/Node.h | 2 + libraries/networking/src/NodeData.h | 3 +- libraries/networking/src/NodeList.cpp | 62 ++-- libraries/networking/src/NodeList.h | 21 +- libraries/networking/src/PacketReceiver.cpp | 302 +++++++----------- libraries/networking/src/PacketReceiver.h | 30 +- libraries/networking/src/ReceivedMessage.cpp | 86 +++++ libraries/networking/src/ReceivedMessage.h | 102 ++++++ .../src/ReceivedPacketProcessor.cpp | 6 +- .../networking/src/ReceivedPacketProcessor.h | 6 +- .../networking/src/ThreadedAssignment.cpp | 4 +- libraries/networking/src/ThreadedAssignment.h | 4 +- libraries/networking/src/udt/Connection.cpp | 31 +- libraries/networking/src/udt/Connection.h | 3 + libraries/networking/src/udt/PacketList.cpp | 6 +- libraries/networking/src/udt/PacketList.h | 4 +- libraries/networking/src/udt/Socket.cpp | 12 +- libraries/networking/src/udt/Socket.h | 5 +- libraries/octree/src/JurisdictionListener.cpp | 8 +- libraries/octree/src/JurisdictionListener.h | 2 +- libraries/octree/src/JurisdictionMap.cpp | 18 +- libraries/octree/src/JurisdictionMap.h | 2 +- libraries/octree/src/JurisdictionSender.cpp | 4 +- libraries/octree/src/JurisdictionSender.h | 2 +- libraries/octree/src/Octree.h | 2 +- .../octree/src/OctreeEditPacketSender.cpp | 6 +- libraries/octree/src/OctreeEditPacketSender.h | 2 +- libraries/octree/src/OctreeHeadlessViewer.cpp | 4 +- libraries/octree/src/OctreeHeadlessViewer.h | 2 +- libraries/octree/src/OctreeQuery.cpp | 4 +- libraries/octree/src/OctreeQuery.h | 2 +- libraries/octree/src/OctreeRenderer.cpp | 30 +- libraries/octree/src/OctreeRenderer.h | 2 +- libraries/octree/src/OctreeSceneStats.cpp | 14 +- libraries/octree/src/OctreeSceneStats.h | 4 +- 105 files changed, 911 insertions(+), 696 deletions(-) create mode 100644 libraries/networking/src/ReceivedMessage.cpp create mode 100644 libraries/networking/src/ReceivedMessage.h diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index d9109703cb..b6bc2c8d01 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -33,8 +33,8 @@ static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 10; -Agent::Agent(NLPacket& packet) : - ThreadedAssignment(packet), +Agent::Agent(ReceivedMessage& message) : + ThreadedAssignment(message), _entityEditSender(), _receivedAudioStream(AudioConstants::NETWORK_FRAME_SAMPLES_STEREO, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, InboundAudioStream::Settings(0, false, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, false, @@ -57,46 +57,46 @@ Agent::Agent(NLPacket& packet) : packetReceiver.registerListener(PacketType::Jurisdiction, this, "handleJurisdictionPacket"); } -void Agent::handleOctreePacket(QSharedPointer packet, SharedNodePointer senderNode) { - auto packetType = packet->getType(); +void Agent::handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode) { + auto packetType = message->getType(); if (packetType == PacketType::OctreeStats) { - int statsMessageLength = OctreeHeadlessViewer::parseOctreeStats(packet, senderNode); - if (packet->getPayloadSize() > statsMessageLength) { + int statsMessageLength = OctreeHeadlessViewer::parseOctreeStats(message, senderNode); + if (message->getPayloadSize() > statsMessageLength) { // pull out the piggybacked packet and create a new QSharedPointer for it - int piggyBackedSizeWithHeader = packet->getPayloadSize() - statsMessageLength; + int piggyBackedSizeWithHeader = message->getPayloadSize() - statsMessageLength; auto buffer = std::unique_ptr(new char[piggyBackedSizeWithHeader]); - memcpy(buffer.get(), packet->getPayload() + statsMessageLength, piggyBackedSizeWithHeader); + memcpy(buffer.get(), message->getPayload() + statsMessageLength, piggyBackedSizeWithHeader); - auto newPacket = NLPacket::fromReceivedPacket(std::move(buffer), piggyBackedSizeWithHeader, packet->getSenderSockAddr()); - packet = QSharedPointer(newPacket.release()); + auto newPacket = NLPacket::fromReceivedPacket(std::move(buffer), piggyBackedSizeWithHeader, message->getSenderSockAddr()); + message = QSharedPointer(new ReceivedMessage(*newPacket)); } else { return; // bail since no piggyback data } - packetType = packet->getType(); + packetType = message->getType(); } // fall through to piggyback message if (packetType == PacketType::EntityData || packetType == PacketType::EntityErase) { - _entityViewer.processDatagram(*packet, senderNode); + _entityViewer.processDatagram(*message, senderNode); } } -void Agent::handleJurisdictionPacket(QSharedPointer packet, SharedNodePointer senderNode) { +void Agent::handleJurisdictionPacket(QSharedPointer message, SharedNodePointer senderNode) { NodeType_t nodeType; - packet->peekPrimitive(&nodeType); + message->peekPrimitive(&nodeType); // PacketType_JURISDICTION, first byte is the node type... if (nodeType == NodeType::EntityServer) { DependencyManager::get()->getJurisdictionListener()-> - queueReceivedPacket(packet, senderNode); + queueReceivedPacket(message, senderNode); } } -void Agent::handleAudioPacket(QSharedPointer packet) { - _receivedAudioStream.parseData(*packet); +void Agent::handleAudioPacket(QSharedPointer message) { + _receivedAudioStream.parseData(*message); _lastReceivedAudioLoudness = _receivedAudioStream.getNextOutputFrameLoudness(); diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index ab000015d5..56411c9390 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -36,7 +36,7 @@ class Agent : public ThreadedAssignment { Q_PROPERTY(bool isListeningToAudioStream READ isListeningToAudioStream WRITE setIsListeningToAudioStream) Q_PROPERTY(float lastReceivedAudioLoudness READ getLastReceivedAudioLoudness) public: - Agent(NLPacket& packet); + Agent(ReceivedMessage& message); void setIsAvatar(bool isAvatar); bool isAvatar() const { return _isAvatar; } @@ -55,9 +55,9 @@ public slots: void playAvatarSound(Sound* avatarSound) { setAvatarSound(avatarSound); } private slots: - void handleAudioPacket(QSharedPointer packet); - void handleOctreePacket(QSharedPointer packet, SharedNodePointer senderNode); - void handleJurisdictionPacket(QSharedPointer packet, SharedNodePointer senderNode); + void handleAudioPacket(QSharedPointer packet); + void handleOctreePacket(QSharedPointer packet, SharedNodePointer senderNode); + void handleJurisdictionPacket(QSharedPointer message, SharedNodePointer senderNode); void sendPingRequests(); void processAgentAvatarAndAudio(float deltaTime); diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index f4f98114d0..c3609d7a4b 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -223,11 +223,11 @@ void AssignmentClient::sendAssignmentRequest() { } } -void AssignmentClient::handleCreateAssignmentPacket(QSharedPointer packet) { +void AssignmentClient::handleCreateAssignmentPacket(QSharedPointer message) { qDebug() << "Received a PacketType::CreateAssignment - attempting to unpack."; // construct the deployed assignment from the packet data - _currentAssignment = AssignmentFactory::unpackAssignment(*packet); + _currentAssignment = AssignmentFactory::unpackAssignment(*message); if (_currentAssignment) { qDebug() << "Received an assignment -" << *_currentAssignment; @@ -236,7 +236,7 @@ void AssignmentClient::handleCreateAssignmentPacket(QSharedPointer pac // switch our DomainHandler hostname and port to whoever sent us the assignment - nodeList->getDomainHandler().setSockAddr(packet->getSenderSockAddr(), _assignmentServerHostname); + nodeList->getDomainHandler().setSockAddr(message->getSenderSockAddr(), _assignmentServerHostname); nodeList->getDomainHandler().setAssignmentUUID(_currentAssignment->getUUID()); qDebug() << "Destination IP for assignment is" << nodeList->getDomainHandler().getIP().toString(); @@ -271,8 +271,8 @@ void AssignmentClient::handleCreateAssignmentPacket(QSharedPointer pac } } -void AssignmentClient::handleStopNodePacket(QSharedPointer packet) { - const HifiSockAddr& senderSockAddr = packet->getSenderSockAddr(); +void AssignmentClient::handleStopNodePacket(QSharedPointer message) { + const HifiSockAddr& senderSockAddr = message->getSenderSockAddr(); if (senderSockAddr.getAddress() == QHostAddress::LocalHost || senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) { diff --git a/assignment-client/src/AssignmentClient.h b/assignment-client/src/AssignmentClient.h index 9d2c816861..0ca1e71c2b 100644 --- a/assignment-client/src/AssignmentClient.h +++ b/assignment-client/src/AssignmentClient.h @@ -38,8 +38,8 @@ public slots: void aboutToQuit(); private slots: - void handleCreateAssignmentPacket(QSharedPointer packet); - void handleStopNodePacket(QSharedPointer packet); + void handleCreateAssignmentPacket(QSharedPointer message); + void handleStopNodePacket(QSharedPointer message); private: void setUpStatusToMonitor(); diff --git a/assignment-client/src/AssignmentClientMonitor.cpp b/assignment-client/src/AssignmentClientMonitor.cpp index 58cf3c49f3..6c3fef1f00 100644 --- a/assignment-client/src/AssignmentClientMonitor.cpp +++ b/assignment-client/src/AssignmentClientMonitor.cpp @@ -206,14 +206,14 @@ void AssignmentClientMonitor::checkSpares() { } } -void AssignmentClientMonitor::handleChildStatusPacket(QSharedPointer packet) { +void AssignmentClientMonitor::handleChildStatusPacket(QSharedPointer message) { // read out the sender ID - QUuid senderID = QUuid::fromRfc4122(packet->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + QUuid senderID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); auto nodeList = DependencyManager::get(); SharedNodePointer matchingNode = nodeList->nodeWithUUID(senderID); - const HifiSockAddr& senderSockAddr = packet->getSenderSockAddr(); + const HifiSockAddr& senderSockAddr = message->getSenderSockAddr(); AssignmentClientChildData* childData = nullptr; @@ -249,7 +249,7 @@ void AssignmentClientMonitor::handleChildStatusPacket(QSharedPointer p // get child's assignment type out of the packet quint8 assignmentType; - packet->readPrimitive(&assignmentType); + message->readPrimitive(&assignmentType); childData->setChildType((Assignment::Type) assignmentType); diff --git a/assignment-client/src/AssignmentClientMonitor.h b/assignment-client/src/AssignmentClientMonitor.h index 93fc9361ad..7ea7c3e274 100644 --- a/assignment-client/src/AssignmentClientMonitor.h +++ b/assignment-client/src/AssignmentClientMonitor.h @@ -36,7 +36,7 @@ public: private slots: void checkSpares(); void childProcessFinished(); - void handleChildStatusPacket(QSharedPointer packet); + void handleChildStatusPacket(QSharedPointer message); public slots: void aboutToQuit(); diff --git a/assignment-client/src/AssignmentFactory.cpp b/assignment-client/src/AssignmentFactory.cpp index cacc523ebd..3445e443e7 100644 --- a/assignment-client/src/AssignmentFactory.cpp +++ b/assignment-client/src/AssignmentFactory.cpp @@ -18,24 +18,24 @@ #include "entities/EntityServer.h" #include "assets/AssetServer.h" -ThreadedAssignment* AssignmentFactory::unpackAssignment(NLPacket& packet) { +ThreadedAssignment* AssignmentFactory::unpackAssignment(ReceivedMessage& message) { quint8 packedType; - packet.peekPrimitive(&packedType); + message.peekPrimitive(&packedType); Assignment::Type unpackedType = (Assignment::Type) packedType; switch (unpackedType) { case Assignment::AudioMixerType: - return new AudioMixer(packet); + return new AudioMixer(message); case Assignment::AvatarMixerType: - return new AvatarMixer(packet); + return new AvatarMixer(message); case Assignment::AgentType: - return new Agent(packet); + return new Agent(message); case Assignment::EntityServerType: - return new EntityServer(packet); + return new EntityServer(message); case Assignment::AssetServerType: - return new AssetServer(packet); + return new AssetServer(message); default: return NULL; } diff --git a/assignment-client/src/AssignmentFactory.h b/assignment-client/src/AssignmentFactory.h index 3c1fef99ef..6eeabb8f46 100644 --- a/assignment-client/src/AssignmentFactory.h +++ b/assignment-client/src/AssignmentFactory.h @@ -16,7 +16,7 @@ class AssignmentFactory { public: - static ThreadedAssignment* unpackAssignment(NLPacket& packet); + static ThreadedAssignment* unpackAssignment(ReceivedMessage& packet); }; #endif // hifi_AssignmentFactory_h diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index b8cf6b2e01..da1addf174 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -27,8 +27,8 @@ const QString ASSET_SERVER_LOGGING_TARGET_NAME = "asset-server"; -AssetServer::AssetServer(NLPacket& packet) : - ThreadedAssignment(packet), +AssetServer::AssetServer(ReceivedMessage& message) : + ThreadedAssignment(message), _taskPool(this) { @@ -84,20 +84,20 @@ void AssetServer::run() { } } -void AssetServer::handleAssetGetInfo(QSharedPointer packet, SharedNodePointer senderNode) { +void AssetServer::handleAssetGetInfo(QSharedPointer message, SharedNodePointer senderNode) { QByteArray assetHash; MessageID messageID; uint8_t extensionLength; - if (packet->getPayloadSize() < qint64(SHA256_HASH_LENGTH + sizeof(messageID) + sizeof(extensionLength))) { + if (message->getPayloadSize() < qint64(SHA256_HASH_LENGTH + sizeof(messageID) + sizeof(extensionLength))) { qDebug() << "ERROR bad file request"; return; } - packet->readPrimitive(&messageID); - assetHash = packet->readWithoutCopy(SHA256_HASH_LENGTH); - packet->readPrimitive(&extensionLength); - QByteArray extension = packet->read(extensionLength); + message->readPrimitive(&messageID); + assetHash = message->readWithoutCopy(SHA256_HASH_LENGTH); + message->readPrimitive(&extensionLength); + QByteArray extension = message->read(extensionLength); auto replyPacket = NLPacket::create(PacketType::AssetGetInfoReply); @@ -122,26 +122,26 @@ void AssetServer::handleAssetGetInfo(QSharedPointer packet, SharedNode nodeList->sendPacket(std::move(replyPacket), *senderNode); } -void AssetServer::handleAssetGet(QSharedPointer packet, SharedNodePointer senderNode) { +void AssetServer::handleAssetGet(QSharedPointer message, SharedNodePointer senderNode) { auto minSize = qint64(sizeof(MessageID) + SHA256_HASH_LENGTH + sizeof(uint8_t) + sizeof(DataOffset) + sizeof(DataOffset)); - if (packet->getPayloadSize() < minSize) { + if (message->getPayloadSize() < minSize) { qDebug() << "ERROR bad file request"; return; } // Queue task - auto task = new SendAssetTask(packet, senderNode, _resourcesDirectory); + auto task = new SendAssetTask(message, senderNode, _resourcesDirectory); _taskPool.start(task); } -void AssetServer::handleAssetUpload(QSharedPointer packetList, SharedNodePointer senderNode) { +void AssetServer::handleAssetUpload(QSharedPointer message, SharedNodePointer senderNode) { if (senderNode->getCanRez()) { qDebug() << "Starting an UploadAssetTask for upload from" << uuidStringWithoutCurlyBraces(senderNode->getUUID()); - auto task = new UploadAssetTask(packetList, senderNode, _resourcesDirectory); + auto task = new UploadAssetTask(message, senderNode, _resourcesDirectory); _taskPool.start(task); } else { // this is a node the domain told us is not allowed to rez entities @@ -151,7 +151,7 @@ void AssetServer::handleAssetUpload(QSharedPointer packetList, Sha auto permissionErrorPacket = NLPacket::create(PacketType::AssetUploadReply, sizeof(MessageID) + sizeof(AssetServerError)); MessageID messageID; - packetList->readPrimitive(&messageID); + message->readPrimitive(&messageID); // write the message ID and a permission denied error permissionErrorPacket->writePrimitive(messageID); diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 09144660ec..fe83ce92a6 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -18,19 +18,20 @@ #include #include "AssetUtils.h" +#include "ReceivedMessage.h" class AssetServer : public ThreadedAssignment { Q_OBJECT public: - AssetServer(NLPacket& packet); + AssetServer(ReceivedMessage& message); public slots: void run(); private slots: - void handleAssetGetInfo(QSharedPointer packet, SharedNodePointer senderNode); - void handleAssetGet(QSharedPointer packet, SharedNodePointer senderNode); - void handleAssetUpload(QSharedPointer packetList, SharedNodePointer senderNode); + void handleAssetGetInfo(QSharedPointer packet, SharedNodePointer senderNode); + void handleAssetGet(QSharedPointer packet, SharedNodePointer senderNode); + void handleAssetUpload(QSharedPointer packetList, SharedNodePointer senderNode); void sendStatsPacket(); diff --git a/assignment-client/src/assets/SendAssetTask.cpp b/assignment-client/src/assets/SendAssetTask.cpp index 9211aa1256..35f4ad1801 100644 --- a/assignment-client/src/assets/SendAssetTask.cpp +++ b/assignment-client/src/assets/SendAssetTask.cpp @@ -22,9 +22,9 @@ #include "AssetUtils.h" -SendAssetTask::SendAssetTask(QSharedPointer packet, const SharedNodePointer& sendToNode, const QDir& resourcesDir) : +SendAssetTask::SendAssetTask(QSharedPointer message, const SharedNodePointer& sendToNode, const QDir& resourcesDir) : QRunnable(), - _packet(packet), + _message(message), _senderNode(sendToNode), _resourcesDir(resourcesDir) { @@ -36,16 +36,16 @@ void SendAssetTask::run() { uint8_t extensionLength; DataOffset start, end; - _packet->readPrimitive(&messageID); - QByteArray assetHash = _packet->read(SHA256_HASH_LENGTH); - _packet->readPrimitive(&extensionLength); - QByteArray extension = _packet->read(extensionLength); + _message->readPrimitive(&messageID); + QByteArray assetHash = _message->read(SHA256_HASH_LENGTH); + _message->readPrimitive(&extensionLength); + QByteArray extension = _message->read(extensionLength); // `start` and `end` indicate the range of data to retrieve for the asset identified by `assetHash`. // `start` is inclusive, `end` is exclusive. Requesting `start` = 1, `end` = 10 will retrieve 9 bytes of data, // starting at index 1. - _packet->readPrimitive(&start); - _packet->readPrimitive(&end); + _message->readPrimitive(&start); + _message->readPrimitive(&end); QString hexHash = assetHash.toHex(); diff --git a/assignment-client/src/assets/SendAssetTask.h b/assignment-client/src/assets/SendAssetTask.h index 4e1a35b3fe..9fef8662d4 100644 --- a/assignment-client/src/assets/SendAssetTask.h +++ b/assignment-client/src/assets/SendAssetTask.h @@ -25,12 +25,12 @@ class NLPacket; class SendAssetTask : public QRunnable { public: - SendAssetTask(QSharedPointer packet, const SharedNodePointer& sendToNode, const QDir& resourcesDir); + SendAssetTask(QSharedPointer message, const SharedNodePointer& sendToNode, const QDir& resourcesDir); void run(); private: - QSharedPointer _packet; + QSharedPointer _message; SharedNodePointer _senderNode; QDir _resourcesDir; }; diff --git a/assignment-client/src/assets/UploadAssetTask.cpp b/assignment-client/src/assets/UploadAssetTask.cpp index 1acca295b4..114fd20320 100644 --- a/assignment-client/src/assets/UploadAssetTask.cpp +++ b/assignment-client/src/assets/UploadAssetTask.cpp @@ -19,9 +19,9 @@ #include -UploadAssetTask::UploadAssetTask(QSharedPointer packetList, SharedNodePointer senderNode, +UploadAssetTask::UploadAssetTask(QSharedPointer receivedMessage, SharedNodePointer senderNode, const QDir& resourcesDir) : - _packetList(packetList), + _receivedMessage(receivedMessage), _senderNode(senderNode), _resourcesDir(resourcesDir) { @@ -29,7 +29,7 @@ UploadAssetTask::UploadAssetTask(QSharedPointer packetList, Shared } void UploadAssetTask::run() { - auto data = _packetList->getMessage(); + auto data = _receivedMessage->getMessage(); QBuffer buffer { &data }; buffer.open(QIODevice::ReadOnly); diff --git a/assignment-client/src/assets/UploadAssetTask.h b/assignment-client/src/assets/UploadAssetTask.h index c310bfc948..aa7beccd5c 100644 --- a/assignment-client/src/assets/UploadAssetTask.h +++ b/assignment-client/src/assets/UploadAssetTask.h @@ -19,17 +19,19 @@ #include #include +#include "ReceivedMessage.h" + class NLPacketList; class Node; class UploadAssetTask : public QRunnable { public: - UploadAssetTask(QSharedPointer packetList, QSharedPointer senderNode, const QDir& resourcesDir); + UploadAssetTask(QSharedPointer message, QSharedPointer senderNode, const QDir& resourcesDir); void run(); private: - QSharedPointer _packetList; + QSharedPointer _receivedMessage; QSharedPointer _senderNode; QDir _resourcesDir; }; diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 1d8908845f..e09564634c 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -74,8 +74,8 @@ bool AudioMixer::shouldMute(float quietestFrame) { return (quietestFrame > _noiseMutingThreshold); } -AudioMixer::AudioMixer(NLPacket& packet) : - ThreadedAssignment(packet), +AudioMixer::AudioMixer(ReceivedMessage& message) : + ThreadedAssignment(message), _trailingSleepRatio(1.0f), _minAudibilityThreshold(LOUDNESS_TO_DISTANCE_RATIO / 2.0f), _performanceThrottlingRatio(0.0f), @@ -541,17 +541,17 @@ void AudioMixer::sendAudioEnvironmentPacket(SharedNodePointer node) { } } -void AudioMixer::handleNodeAudioPacket(QSharedPointer packet, SharedNodePointer sendingNode) { - DependencyManager::get()->updateNodeWithDataFromPacket(packet, sendingNode); +void AudioMixer::handleNodeAudioPacket(QSharedPointer message, SharedNodePointer sendingNode) { + DependencyManager::get()->updateNodeWithDataFromPacket(message, sendingNode); } -void AudioMixer::handleMuteEnvironmentPacket(QSharedPointer packet, SharedNodePointer sendingNode) { +void AudioMixer::handleMuteEnvironmentPacket(QSharedPointer message, SharedNodePointer sendingNode) { auto nodeList = DependencyManager::get(); if (sendingNode->getCanAdjustLocks()) { - auto newPacket = NLPacket::create(PacketType::MuteEnvironment, packet->getPayloadSize()); + auto newPacket = NLPacket::create(PacketType::MuteEnvironment, message->getPayloadSize()); // Copy payload - newPacket->write(packet->getPayload(), packet->getPayloadSize()); + newPacket->write(message->getPayload(), message->getPayloadSize()); nodeList->eachNode([&](const SharedNodePointer& node){ if (node->getType() == NodeType::Agent && node->getActiveSocket() && diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 9e7a010f61..581a887947 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -28,7 +28,7 @@ const int READ_DATAGRAMS_STATS_WINDOW_SECONDS = 30; class AudioMixer : public ThreadedAssignment { Q_OBJECT public: - AudioMixer(NLPacket& packet); + AudioMixer(ReceivedMessage& message); void deleteLater() { qDebug() << "DELETE LATER CALLED?"; QObject::deleteLater(); } public slots: @@ -40,8 +40,8 @@ public slots: static const InboundAudioStream::Settings& getStreamSettings() { return _streamSettings; } private slots: - void handleNodeAudioPacket(QSharedPointer packet, SharedNodePointer sendingNode); - void handleMuteEnvironmentPacket(QSharedPointer packet, SharedNodePointer sendingNode); + void handleNodeAudioPacket(QSharedPointer packet, SharedNodePointer sendingNode); + void handleMuteEnvironmentPacket(QSharedPointer packet, SharedNodePointer sendingNode); private: /// adds one stream to the mix for a listening node diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 4fc5a3785f..63ee88f2ef 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -49,18 +49,18 @@ AvatarAudioStream* AudioMixerClientData::getAvatarAudioStream() const { return NULL; } -int AudioMixerClientData::parseData(NLPacket& packet) { - PacketType packetType = packet.getType(); +int AudioMixerClientData::parseData(ReceivedMessage& message) { + PacketType packetType = message.getType(); if (packetType == PacketType::AudioStreamStats) { // skip over header, appendFlag, and num stats packed - packet.seek(sizeof(quint8) + sizeof(quint16)); + message.seek(sizeof(quint8) + sizeof(quint16)); // read the downstream audio stream stats - packet.readPrimitive(&_downstreamAudioStreamStats); + message.readPrimitive(&_downstreamAudioStreamStats); - return packet.pos(); + return message.pos(); } else { PositionalAudioStream* matchingStream = NULL; @@ -74,10 +74,10 @@ int AudioMixerClientData::parseData(NLPacket& packet) { // we don't have a mic stream yet, so add it // read the channel flag to see if our stream is stereo or not - packet.seek(sizeof(quint16)); + message.seek(sizeof(quint16)); quint8 channelFlag; - packet.readPrimitive(&channelFlag); + message.readPrimitive(&channelFlag); bool isStereo = channelFlag == 1; @@ -89,11 +89,11 @@ int AudioMixerClientData::parseData(NLPacket& packet) { // this is injected audio // grab the stream identifier for this injected audio - packet.seek(sizeof(quint16)); - QUuid streamIdentifier = QUuid::fromRfc4122(packet.readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + message.seek(sizeof(quint16)); + QUuid streamIdentifier = QUuid::fromRfc4122(message.readWithoutCopy(NUM_BYTES_RFC4122_UUID)); bool isStereo; - packet.readPrimitive(&isStereo); + message.readPrimitive(&isStereo); if (!_audioStreams.contains(streamIdentifier)) { // we don't have this injected stream yet, so add it @@ -105,9 +105,9 @@ int AudioMixerClientData::parseData(NLPacket& packet) { } // seek to the beginning of the packet so that the next reader is in the right spot - packet.seek(0); + message.seek(0); - return matchingStream->parseData(packet); + return matchingStream->parseData(message); } return 0; } diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index 20bcaf5627..17b2fecd12 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -42,7 +42,7 @@ public: const QHash& getAudioStreams() const { return _audioStreams; } AvatarAudioStream* getAvatarAudioStream() const; - int parseData(NLPacket& packet); + int parseData(ReceivedMessage& message); void checkBuffersBeforeFrameSend(); diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 833b53b729..0a4dc386a8 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -33,8 +33,8 @@ const QString AVATAR_MIXER_LOGGING_NAME = "avatar-mixer"; const int AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 60; const unsigned int AVATAR_DATA_SEND_INTERVAL_MSECS = (1.0f / (float) AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND) * 1000; -AvatarMixer::AvatarMixer(NLPacket& packet) : - ThreadedAssignment(packet), +AvatarMixer::AvatarMixer(ReceivedMessage& message) : + ThreadedAssignment(message), _broadcastThread(), _lastFrameTimestamp(QDateTime::currentMSecsSinceEpoch()), _trailingSleepRatio(1.0f), @@ -424,19 +424,19 @@ void AvatarMixer::nodeKilled(SharedNodePointer killedNode) { } } -void AvatarMixer::handleAvatarDataPacket(QSharedPointer packet, SharedNodePointer senderNode) { +void AvatarMixer::handleAvatarDataPacket(QSharedPointer message, SharedNodePointer senderNode) { auto nodeList = DependencyManager::get(); - nodeList->updateNodeWithDataFromPacket(packet, senderNode); + nodeList->updateNodeWithDataFromPacket(message, senderNode); } -void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer packet, SharedNodePointer senderNode) { +void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer message, SharedNodePointer senderNode) { if (senderNode->getLinkedData()) { AvatarMixerClientData* nodeData = dynamic_cast(senderNode->getLinkedData()); if (nodeData != nullptr) { AvatarData& avatar = nodeData->getAvatar(); // parse the identity packet and update the change timestamp if appropriate - if (avatar.hasIdentityChangedAfterParsing(*packet)) { + if (avatar.hasIdentityChangedAfterParsing(message->getMessage())) { QMutexLocker nodeDataLocker(&nodeData->getMutex()); nodeData->setIdentityChangeTimestamp(QDateTime::currentMSecsSinceEpoch()); } @@ -444,13 +444,13 @@ void AvatarMixer::handleAvatarIdentityPacket(QSharedPointer packet, Sh } } -void AvatarMixer::handleAvatarBillboardPacket(QSharedPointer packet, SharedNodePointer senderNode) { +void AvatarMixer::handleAvatarBillboardPacket(QSharedPointer message, SharedNodePointer senderNode) { AvatarMixerClientData* nodeData = dynamic_cast(senderNode->getLinkedData()); if (nodeData) { AvatarData& avatar = nodeData->getAvatar(); // parse the billboard packet and update the change timestamp if appropriate - if (avatar.hasBillboardChangedAfterParsing(*packet)) { + if (avatar.hasBillboardChangedAfterParsing(message->getMessage())) { QMutexLocker nodeDataLocker(&nodeData->getMutex()); nodeData->setBillboardChangeTimestamp(QDateTime::currentMSecsSinceEpoch()); } @@ -458,8 +458,8 @@ void AvatarMixer::handleAvatarBillboardPacket(QSharedPointer packet, S } } -void AvatarMixer::handleKillAvatarPacket(QSharedPointer packet) { - DependencyManager::get()->processKillNode(*packet); +void AvatarMixer::handleKillAvatarPacket(QSharedPointer message) { + DependencyManager::get()->processKillNode(*message); } void AvatarMixer::sendStatsPacket() { diff --git a/assignment-client/src/avatars/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h index 67fdbf5285..e2d878996a 100644 --- a/assignment-client/src/avatars/AvatarMixer.h +++ b/assignment-client/src/avatars/AvatarMixer.h @@ -21,7 +21,7 @@ class AvatarMixer : public ThreadedAssignment { Q_OBJECT public: - AvatarMixer(NLPacket& packet); + AvatarMixer(ReceivedMessage& message); ~AvatarMixer(); public slots: /// runs the avatar mixer @@ -32,10 +32,10 @@ public slots: void sendStatsPacket(); private slots: - void handleAvatarDataPacket(QSharedPointer packet, SharedNodePointer senderNode); - void handleAvatarIdentityPacket(QSharedPointer packet, SharedNodePointer senderNode); - void handleAvatarBillboardPacket(QSharedPointer packet, SharedNodePointer senderNode); - void handleKillAvatarPacket(QSharedPointer packet); + void handleAvatarDataPacket(QSharedPointer packet, SharedNodePointer senderNode); + void handleAvatarIdentityPacket(QSharedPointer message, SharedNodePointer senderNode); + void handleAvatarBillboardPacket(QSharedPointer message, SharedNodePointer senderNode); + void handleKillAvatarPacket(QSharedPointer message); private: void broadcastAvatarData(); diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index 0a9be20691..a085724317 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -13,12 +13,12 @@ #include "AvatarMixerClientData.h" -int AvatarMixerClientData::parseData(NLPacket& packet) { +int AvatarMixerClientData::parseData(ReceivedMessage& message) { // pull the sequence number from the data first - packet.readPrimitive(&_lastReceivedSequenceNumber); + message.readPrimitive(&_lastReceivedSequenceNumber); // compute the offset to the data payload - return _avatar.parseDataFromBuffer(packet.readWithoutCopy(packet.bytesLeftToRead())); + return _avatar.parseDataFromBuffer(message.readWithoutCopy(message.getBytesLeftToRead())); } bool AvatarMixerClientData::checkAndSetHasReceivedFirstPackets() { diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index e68a54c265..822495fffd 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -32,7 +32,7 @@ const QString INBOUND_AVATAR_DATA_STATS_KEY = "inbound_av_data_kbps"; class AvatarMixerClientData : public NodeData { Q_OBJECT public: - int parseData(NLPacket& packet); + int parseData(ReceivedMessage& message) override; AvatarData& getAvatar() { return _avatar; } bool checkAndSetHasReceivedFirstPackets(); diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index bdd5728246..078e74f3fc 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -21,8 +21,8 @@ const char* MODEL_SERVER_NAME = "Entity"; const char* MODEL_SERVER_LOGGING_TARGET_NAME = "entity-server"; const char* LOCAL_MODELS_PERSIST_FILE = "resources/models.svo"; -EntityServer::EntityServer(NLPacket& packet) : - OctreeServer(packet), +EntityServer::EntityServer(ReceivedMessage& message) : + OctreeServer(message), _entitySimulation(NULL) { auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); @@ -40,9 +40,9 @@ EntityServer::~EntityServer() { tree->removeNewlyCreatedHook(this); } -void EntityServer::handleEntityPacket(QSharedPointer packet, SharedNodePointer senderNode) { +void EntityServer::handleEntityPacket(QSharedPointer message, SharedNodePointer senderNode) { if (_octreeInboundPacketProcessor) { - _octreeInboundPacketProcessor->queueReceivedPacket(packet, senderNode); + _octreeInboundPacketProcessor->queueReceivedPacket(message, senderNode); } } diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h index 065834cbc2..21b08d2e31 100644 --- a/assignment-client/src/entities/EntityServer.h +++ b/assignment-client/src/entities/EntityServer.h @@ -22,7 +22,7 @@ class EntityServer : public OctreeServer, public NewlyCreatedEntityHook { Q_OBJECT public: - EntityServer(NLPacket& packet); + EntityServer(ReceivedMessage& message); ~EntityServer(); // Subclasses must implement these methods @@ -50,7 +50,7 @@ protected: virtual OctreePointer createTree() override; private slots: - void handleEntityPacket(QSharedPointer packet, SharedNodePointer senderNode); + void handleEntityPacket(QSharedPointer message, SharedNodePointer senderNode); private: EntitySimulation* _entitySimulation; diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp index 92c08152f7..cee1d9ba0f 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp @@ -74,7 +74,7 @@ void OctreeInboundPacketProcessor::midProcess() { } } -void OctreeInboundPacketProcessor::processPacket(QSharedPointer packet, SharedNodePointer sendingNode) { +void OctreeInboundPacketProcessor::processPacket(QSharedPointer message, SharedNodePointer sendingNode) { if (_shuttingDown) { qDebug() << "OctreeInboundPacketProcessor::processPacket() while shutting down... ignoring incoming packet"; return; @@ -84,22 +84,22 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer packet if (debugProcessPacket) { qDebug("OctreeInboundPacketProcessor::processPacket() payload=%p payloadLength=%lld", - packet->getPayload(), - packet->getPayloadSize()); + message->getPayload(), + message->getPayloadSize()); } // Ask our tree subclass if it can handle the incoming packet... - PacketType packetType = packet->getType(); + PacketType packetType = message->getType(); if (_myServer->getOctree()->handlesEditPacketType(packetType)) { PerformanceWarning warn(debugProcessPacket, "processPacket KNOWN TYPE", debugProcessPacket); _receivedPacketCount++; unsigned short int sequence; - packet->readPrimitive(&sequence); + message->readPrimitive(&sequence); quint64 sentAt; - packet->readPrimitive(&sentAt); + message->readPrimitive(&sentAt); quint64 arrivedAt = usecTimestampNow(); if (sentAt > arrivedAt) { @@ -117,7 +117,7 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer packet if (debugProcessPacket || _myServer->wantsDebugReceiving()) { qDebug() << "PROCESSING THREAD: got '" << packetType << "' packet - " << _receivedPacketCount << " command from client"; - qDebug() << " receivedBytes=" << packet->getDataSize(); + qDebug() << " receivedBytes=" << message->getDataSize(); qDebug() << " sequence=" << sequence; qDebug() << " sentAt=" << sentAt << " usecs"; qDebug() << " arrivedAt=" << arrivedAt << " usecs"; @@ -131,29 +131,29 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer packet qDebug() << " numBytesPacketHeader=" << NLPacket::totalHeaderSize(packetType); qDebug() << " sizeof(sequence)=" << sizeof(sequence); qDebug() << " sizeof(sentAt)=" << sizeof(sentAt); - qDebug() << " atByte (in payload)=" << packet->pos(); - qDebug() << " payload size=" << packet->getPayloadSize(); + qDebug() << " atByte (in payload)=" << message->pos(); + qDebug() << " payload size=" << message->getPayloadSize(); - if (!packet->bytesLeftToRead()) { + if (!message->getBytesLeftToRead()) { qDebug() << " ----- UNEXPECTED ---- got a packet without any edit details!!!! --------"; } } const unsigned char* editData = nullptr; - while (packet->bytesLeftToRead() > 0) { + while (message->getBytesLeftToRead() > 0) { - editData = reinterpret_cast(packet->getPayload() + packet->pos()); + editData = reinterpret_cast(message->getPayload() + message->pos()); - int maxSize = packet->bytesLeftToRead(); + int maxSize = message->getBytesLeftToRead(); if (debugProcessPacket) { qDebug() << " --- inside while loop ---"; qDebug() << " maxSize=" << maxSize; qDebug("OctreeInboundPacketProcessor::processPacket() %hhu " "payload=%p payloadLength=%lld editData=%p payloadPosition=%lld maxSize=%d", - packetType, packet->getPayload(), packet->getPayloadSize(), editData, - packet->pos(), maxSize); + packetType, message->getPayload(), message->getPayloadSize(), editData, + message->pos(), maxSize); } quint64 startProcess, startLock = usecTimestampNow(); @@ -161,7 +161,7 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer packet _myServer->getOctree()->withWriteLock([&] { startProcess = usecTimestampNow(); editDataBytesRead = - _myServer->getOctree()->processEditPacketData(*packet, editData, maxSize, sendingNode); + _myServer->getOctree()->processEditPacketData(*message, editData, maxSize, sendingNode); }); quint64 endProcess = usecTimestampNow(); @@ -177,12 +177,12 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer packet lockWaitTime += thisLockWaitTime; // skip to next edit record in the packet - packet->seek(packet->pos() + editDataBytesRead); + message->seek(message->pos() + editDataBytesRead); if (debugProcessPacket) { qDebug() << " editDataBytesRead=" << editDataBytesRead; - qDebug() << " AFTER processEditPacketData payload position=" << packet->pos(); - qDebug() << " AFTER processEditPacketData payload size=" << packet->getPayloadSize(); + qDebug() << " AFTER processEditPacketData payload position=" << message->pos(); + qDebug() << " AFTER processEditPacketData payload size=" << message->getPayloadSize(); } } @@ -190,7 +190,7 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer packet if (debugProcessPacket) { qDebug("OctreeInboundPacketProcessor::processPacket() DONE LOOPING FOR %hhu " "payload=%p payloadLength=%lld editData=%p payloadPosition=%lld", - packetType, packet->getPayload(), packet->getPayloadSize(), editData, packet->pos()); + packetType, message->getPayload(), message->getPayloadSize(), editData, message->pos()); } // Make sure our Node and NodeList knows we've heard from this node. diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.h b/assignment-client/src/octree/OctreeInboundPacketProcessor.h index 3ddb76b3fa..4d4b61706f 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.h +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.h @@ -78,7 +78,7 @@ public: protected: - virtual void processPacket(QSharedPointer packet, SharedNodePointer sendingNode); + virtual void processPacket(QSharedPointer message, SharedNodePointer sendingNode); virtual unsigned long getMaxWait() const; virtual void preProcess(); diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index f70ff62f91..bc7f14c225 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -375,11 +375,11 @@ const NLPacket* OctreeQueryNode::getNextNackedPacket() { return nullptr; } -void OctreeQueryNode::parseNackPacket(NLPacket& packet) { +void OctreeQueryNode::parseNackPacket(ReceivedMessage& message) { // read sequence numbers - while (packet.bytesLeftToRead()) { + while (message.getBytesLeftToRead()) { OCTREE_PACKET_SEQUENCE sequenceNumber; - packet.readPrimitive(&sequenceNumber); + message.readPrimitive(&sequenceNumber); _nackedSequenceNumbers.enqueue(sequenceNumber); } } diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 0c691a06a2..43e90c39e5 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -108,7 +108,7 @@ public: OCTREE_PACKET_SEQUENCE getSequenceNumber() const { return _sequenceNumber; } - void parseNackPacket(NLPacket& packet); + void parseNackPacket(ReceivedMessage& message); bool hasNextNackedPacket() const; const NLPacket* getNextNackedPacket(); diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index ee0403d57b..471a7c6eb6 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -210,8 +210,8 @@ void OctreeServer::trackProcessWaitTime(float time) { _averageProcessWaitTime.updateAverage(time); } -OctreeServer::OctreeServer(NLPacket& packet) : - ThreadedAssignment(packet), +OctreeServer::OctreeServer(ReceivedMessage& message) : + ThreadedAssignment(message), _argc(0), _argv(NULL), _parsedArgV(NULL), @@ -809,12 +809,12 @@ void OctreeServer::parsePayload() { } } -void OctreeServer::handleOctreeQueryPacket(QSharedPointer packet, SharedNodePointer senderNode) { +void OctreeServer::handleOctreeQueryPacket(QSharedPointer message, SharedNodePointer senderNode) { if (!_isFinished) { // If we got a query packet, then we're talking to an agent, and we // need to make sure we have it in our nodeList. auto nodeList = DependencyManager::get(); - nodeList->updateNodeWithDataFromPacket(packet, senderNode); + nodeList->updateNodeWithDataFromPacket(message, senderNode); OctreeQueryNode* nodeData = dynamic_cast(senderNode->getLinkedData()); if (nodeData && !nodeData->isOctreeSendThreadInitalized()) { @@ -823,17 +823,17 @@ void OctreeServer::handleOctreeQueryPacket(QSharedPointer packet, Shar } } -void OctreeServer::handleOctreeDataNackPacket(QSharedPointer packet, SharedNodePointer senderNode) { +void OctreeServer::handleOctreeDataNackPacket(QSharedPointer message, SharedNodePointer senderNode) { // If we got a nack packet, then we're talking to an agent, and we // need to make sure we have it in our nodeList. OctreeQueryNode* nodeData = dynamic_cast(senderNode->getLinkedData()); if (nodeData) { - nodeData->parseNackPacket(*packet); + nodeData->parseNackPacket(*message); } } -void OctreeServer::handleJurisdictionRequestPacket(QSharedPointer packet, SharedNodePointer senderNode) { - _jurisdictionSender->queueReceivedPacket(packet, senderNode); +void OctreeServer::handleJurisdictionRequestPacket(QSharedPointer message, SharedNodePointer senderNode) { + _jurisdictionSender->queueReceivedPacket(message, senderNode); } bool OctreeServer::readOptionBool(const QString& optionName, const QJsonObject& settingsSectionObject, bool& result) { diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index b8e4a5c261..5941d945ef 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -32,7 +32,7 @@ const int DEFAULT_PACKETS_PER_INTERVAL = 2000; // some 120,000 packets per secon class OctreeServer : public ThreadedAssignment, public HTTPRequestHandler { Q_OBJECT public: - OctreeServer(NLPacket& packet); + OctreeServer(ReceivedMessage& message); ~OctreeServer(); /// allows setting of run arguments @@ -126,9 +126,9 @@ public slots: void sendStatsPacket(); private slots: - void handleOctreeQueryPacket(QSharedPointer packet, SharedNodePointer senderNode); - void handleOctreeDataNackPacket(QSharedPointer packet, SharedNodePointer senderNode); - void handleJurisdictionRequestPacket(QSharedPointer packet, SharedNodePointer senderNode); + void handleOctreeQueryPacket(QSharedPointer message, SharedNodePointer senderNode); + void handleOctreeDataNackPacket(QSharedPointer message, SharedNodePointer senderNode); + void handleJurisdictionRequestPacket(QSharedPointer message, SharedNodePointer senderNode); protected: virtual OctreePointer createTree() = 0; diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index 90b22ffdd8..1048d2665e 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -50,15 +50,15 @@ const NodeSet STATICALLY_ASSIGNED_NODES = NodeSet() << NodeType::AudioMixer << NodeType::AvatarMixer << NodeType::EntityServer << NodeType::AssetServer; -void DomainGatekeeper::processConnectRequestPacket(QSharedPointer packet) { - if (packet->getPayloadSize() == 0) { +void DomainGatekeeper::processConnectRequestPacket(QSharedPointer message) { + if (message->getPayloadSize() == 0) { return; } - QDataStream packetStream(packet.data()); + QDataStream packetStream(message->getMessage()); // read a NodeConnectionData object from the packet so we can pass around this data while we're inspecting it - NodeConnectionData nodeConnection = NodeConnectionData::fromDataStream(packetStream, packet->getSenderSockAddr()); + NodeConnectionData nodeConnection = NodeConnectionData::fromDataStream(packetStream, message->getSenderSockAddr()); if (nodeConnection.localSockAddr.isNull() || nodeConnection.publicSockAddr.isNull()) { qDebug() << "Unexpected data received for node local socket or public socket. Will not allow connection."; @@ -71,7 +71,7 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointer pack if (!VALID_NODE_TYPES.contains(nodeConnection.nodeType)) { qDebug() << "Received an invalid node type with connect request. Will not allow connection from" - << nodeConnection.senderSockAddr; + << nodeConnection.senderSockAddr << ": " << nodeConnection.nodeType; return; } @@ -86,11 +86,11 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointer pack QString username; QByteArray usernameSignature; - if (packet->bytesLeftToRead() > 0) { + if (message->getBytesLeftToRead() > 0) { // read username from packet packetStream >> username; - if (packet->bytesLeftToRead() > 0) { + if (message->getBytesLeftToRead() > 0) { // read user signature from packet packetStream >> usernameSignature; } @@ -102,14 +102,14 @@ void DomainGatekeeper::processConnectRequestPacket(QSharedPointer pack if (node) { // set the sending sock addr and node interest set on this node DomainServerNodeData* nodeData = reinterpret_cast(node->getLinkedData()); - nodeData->setSendingSockAddr(packet->getSenderSockAddr()); + nodeData->setSendingSockAddr(message->getSenderSockAddr()); nodeData->setNodeInterestSet(nodeConnection.interestList.toSet()); // signal that we just connected a node so the DomainServer can get it a list // and broadcast its presence right away emit connectedNode(node); } else { - qDebug() << "Refusing connection from node at" << packet->getSenderSockAddr(); + qDebug() << "Refusing connection from node at" << message->getSenderSockAddr(); } } @@ -571,10 +571,10 @@ void DomainGatekeeper::handlePeerPingTimeout() { } } -void DomainGatekeeper::processICEPeerInformationPacket(QSharedPointer packet) { +void DomainGatekeeper::processICEPeerInformationPacket(QSharedPointer message) { // loop through the packet and pull out network peers // any peer we don't have we add to the hash, otherwise we update - QDataStream iceResponseStream(packet.data()); + QDataStream iceResponseStream(message->getMessage()); NetworkPeer* receivedPeer = new NetworkPeer; iceResponseStream >> *receivedPeer; @@ -599,15 +599,15 @@ void DomainGatekeeper::processICEPeerInformationPacket(QSharedPointer } } -void DomainGatekeeper::processICEPingPacket(QSharedPointer packet) { +void DomainGatekeeper::processICEPingPacket(QSharedPointer message) { auto limitedNodeList = DependencyManager::get(); - auto pingReplyPacket = limitedNodeList->constructICEPingReplyPacket(*packet, limitedNodeList->getSessionUUID()); + auto pingReplyPacket = limitedNodeList->constructICEPingReplyPacket(*message, limitedNodeList->getSessionUUID()); - limitedNodeList->sendPacket(std::move(pingReplyPacket), packet->getSenderSockAddr()); + limitedNodeList->sendPacket(std::move(pingReplyPacket), message->getSenderSockAddr()); } -void DomainGatekeeper::processICEPingReplyPacket(QSharedPointer packet) { - QDataStream packetStream(packet.data()); +void DomainGatekeeper::processICEPingReplyPacket(QSharedPointer message) { + QDataStream packetStream(message->getMessage()); QUuid nodeUUID; packetStream >> nodeUUID; @@ -616,6 +616,6 @@ void DomainGatekeeper::processICEPingReplyPacket(QSharedPointer packet if (sendingPeer) { // we had this NetworkPeer in our connecting list - add the right sock addr to our connected list - sendingPeer->activateMatchingOrNewSymmetricSocket(packet->getSenderSockAddr()); + sendingPeer->activateMatchingOrNewSymmetricSocket(message->getSenderSockAddr()); } } diff --git a/domain-server/src/DomainGatekeeper.h b/domain-server/src/DomainGatekeeper.h index 857b4419da..2fc4be380c 100644 --- a/domain-server/src/DomainGatekeeper.h +++ b/domain-server/src/DomainGatekeeper.h @@ -41,10 +41,10 @@ public: void removeICEPeer(const QUuid& peerUUID) { _icePeers.remove(peerUUID); } public slots: - void processConnectRequestPacket(QSharedPointer packet); - void processICEPingPacket(QSharedPointer packet); - void processICEPingReplyPacket(QSharedPointer packet); - void processICEPeerInformationPacket(QSharedPointer packet); + void processConnectRequestPacket(QSharedPointer message); + void processICEPingPacket(QSharedPointer message); + void processICEPingReplyPacket(QSharedPointer message); + void processICEPeerInformationPacket(QSharedPointer message); void publicKeyJSONCallback(QNetworkReply& requestReply); diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 48bb9bed62..80529ac116 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -572,10 +572,10 @@ void DomainServer::populateDefaultStaticAssignmentsExcludingTypes(const QSet packet, SharedNodePointer sendingNode) { +void DomainServer::processListRequestPacket(QSharedPointer message, SharedNodePointer sendingNode) { - QDataStream packetStream(packet.data()); - NodeConnectionData nodeRequestData = NodeConnectionData::fromDataStream(packetStream, packet->getSenderSockAddr(), false); + QDataStream packetStream(message->getMessage()); + NodeConnectionData nodeRequestData = NodeConnectionData::fromDataStream(packetStream, message->getSenderSockAddr(), false); // update this node's sockets in case they have changed sendingNode->setPublicSocket(nodeRequestData.publicSockAddr); @@ -585,7 +585,7 @@ void DomainServer::processListRequestPacket(QSharedPointer packet, Sha DomainServerNodeData* nodeData = reinterpret_cast(sendingNode->getLinkedData()); nodeData->setNodeInterestSet(nodeRequestData.interestList.toSet()); - sendDomainListToNode(sendingNode, packet->getSenderSockAddr()); + sendDomainListToNode(sendingNode, message->getSenderSockAddr()); } unsigned int DomainServer::countConnectedUsers() { @@ -758,9 +758,9 @@ void DomainServer::broadcastNewNode(const SharedNodePointer& addedNode) { ); } -void DomainServer::processRequestAssignmentPacket(QSharedPointer packet) { +void DomainServer::processRequestAssignmentPacket(QSharedPointer message) { // construct the requested assignment from the packet data - Assignment requestAssignment(*packet); + Assignment requestAssignment(*message); // Suppress these for Assignment::AgentType to once per 5 seconds static QElapsedTimer noisyMessageTimer; @@ -778,14 +778,14 @@ void DomainServer::processRequestAssignmentPacket(QSharedPointer packe static QString repeatedMessage = LogHandler::getInstance().addOnlyOnceMessageRegex ("Received a request for assignment type [^ ]+ from [^ ]+"); qDebug() << "Received a request for assignment type" << requestAssignment.getType() - << "from" << packet->getSenderSockAddr(); + << "from" << message->getSenderSockAddr(); noisyMessageTimer.restart(); } SharedAssignmentPointer assignmentToDeploy = deployableAssignmentForRequest(requestAssignment); if (assignmentToDeploy) { - qDebug() << "Deploying assignment -" << *assignmentToDeploy.data() << "- to" << packet->getSenderSockAddr(); + qDebug() << "Deploying assignment -" << *assignmentToDeploy.data() << "- to" << message->getSenderSockAddr(); // give this assignment out, either the type matches or the requestor said they will take any static std::unique_ptr assignmentPacket; @@ -806,7 +806,7 @@ void DomainServer::processRequestAssignmentPacket(QSharedPointer packe assignmentStream << uniqueAssignment; auto limitedNodeList = DependencyManager::get(); - limitedNodeList->sendUnreliablePacket(*assignmentPacket, packet->getSenderSockAddr()); + limitedNodeList->sendUnreliablePacket(*assignmentPacket, message->getSenderSockAddr()); // give the information for that deployed assignment to the gatekeeper so it knows to that that node // in when it comes back around @@ -818,7 +818,7 @@ void DomainServer::processRequestAssignmentPacket(QSharedPointer packe static QString repeatedMessage = LogHandler::getInstance().addOnlyOnceMessageRegex ("Unable to fulfill assignment request of type [^ ]+ from [^ ]+"); qDebug() << "Unable to fulfill assignment request of type" << requestAssignment.getType() - << "from" << packet->getSenderSockAddr(); + << "from" << message->getSenderSockAddr(); noisyMessageTimer.restart(); } } @@ -987,7 +987,7 @@ void DomainServer::sendHeartbeatToIceServer() { DependencyManager::get()->sendHeartbeatToIceServer(_iceServerSocket); } -void DomainServer::processNodeJSONStatsPacket(QSharedPointer packetList, SharedNodePointer sendingNode) { +void DomainServer::processNodeJSONStatsPacket(QSharedPointer packetList, SharedNodePointer sendingNode) { auto nodeData = dynamic_cast(sendingNode->getLinkedData()); if (nodeData) { nodeData->updateJSONStats(packetList->getMessage()); @@ -1753,17 +1753,17 @@ void DomainServer::addStaticAssignmentsToQueue() { } } -void DomainServer::processPathQueryPacket(QSharedPointer packet) { +void DomainServer::processPathQueryPacket(QSharedPointer message) { // this is a query for the viewpoint resulting from a path // first pull the query path from the packet // figure out how many bytes the sender said this path is quint16 numPathBytes; - packet->readPrimitive(&numPathBytes); + message->readPrimitive(&numPathBytes); - if (numPathBytes <= packet->bytesLeftToRead()) { + if (numPathBytes <= message->getBytesLeftToRead()) { // the number of path bytes makes sense for the sent packet - pull out the path - QString pathQuery = QString::fromUtf8(packet->getPayload() + packet->pos(), numPathBytes); + QString pathQuery = QString::fromUtf8(message->getPayload() + message->pos(), numPathBytes); // our settings contain paths that start with a leading slash, so make sure this query has that if (!pathQuery.startsWith("/")) { @@ -1811,7 +1811,7 @@ void DomainServer::processPathQueryPacket(QSharedPointer packet) { // send off the packet - see if we can associate this outbound data to a particular node // TODO: does this senderSockAddr always work for a punched DS client? - nodeList->sendPacket(std::move(pathResponsePacket), packet->getSenderSockAddr()); + nodeList->sendPacket(std::move(pathResponsePacket), message->getSenderSockAddr()); } } diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index df42bf3ad9..b3358a8328 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -56,10 +56,10 @@ public slots: void restart(); - void processRequestAssignmentPacket(QSharedPointer packet); - void processListRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode); - void processNodeJSONStatsPacket(QSharedPointer packetList, SharedNodePointer sendingNode); - void processPathQueryPacket(QSharedPointer packet); + void processRequestAssignmentPacket(QSharedPointer packet); + void processListRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode); + void processNodeJSONStatsPacket(QSharedPointer packetList, SharedNodePointer sendingNode); + void processPathQueryPacket(QSharedPointer packet); private slots: void aboutToQuit(); diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index f650089486..82be8e1415 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -67,9 +67,9 @@ DomainServerSettingsManager::DomainServerSettingsManager() : QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection); } -void DomainServerSettingsManager::processSettingsRequestPacket(QSharedPointer packet) { +void DomainServerSettingsManager::processSettingsRequestPacket(QSharedPointer message) { Assignment::Type type; - packet->readPrimitive(&type); + message->readPrimitive(&type); QJsonObject responseObject = responseObjectForType(QString::number(type)); auto json = QJsonDocument(responseObject).toJson(); @@ -79,7 +79,7 @@ void DomainServerSettingsManager::processSettingsRequestPacket(QSharedPointerwrite(json); auto nodeList = DependencyManager::get(); - nodeList->sendPacketList(std::move(packetList), packet->getSenderSockAddr()); + nodeList->sendPacketList(std::move(packetList), message->getSenderSockAddr()); } void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList) { diff --git a/domain-server/src/DomainServerSettingsManager.h b/domain-server/src/DomainServerSettingsManager.h index 321f7b7214..7f71a89da5 100644 --- a/domain-server/src/DomainServerSettingsManager.h +++ b/domain-server/src/DomainServerSettingsManager.h @@ -18,7 +18,7 @@ #include #include -#include +#include const QString SETTINGS_PATHS_KEY = "paths"; @@ -42,7 +42,7 @@ public: QVariantMap& getSettingsMap() { return _configMap.getMergedConfig(); } private slots: - void processSettingsRequestPacket(QSharedPointer packet); + void processSettingsRequestPacket(QSharedPointer message); private: QJsonObject responseObjectForType(const QString& typeValue, bool isAuthenticated = false); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9a6e2fff4d..6201236f02 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3654,12 +3654,11 @@ void Application::domainChanged(const QString& domainHostname) { _domainConnectionRefusals.clear(); } -void Application::handleDomainConnectionDeniedPacket(QSharedPointer packet) { +void Application::handleDomainConnectionDeniedPacket(QSharedPointer message) { // Read deny reason from packet quint16 reasonSize; - packet->readPrimitive(&reasonSize); - QString reason = QString::fromUtf8(packet->getPayload() + packet->pos(), reasonSize); - packet->seek(packet->pos() + reasonSize); + message->readPrimitive(&reasonSize); + QString reason = QString::fromUtf8(message->readWithoutCopy(reasonSize)); // output to the log so the user knows they got a denied connection request // and check and signal for an access token so that we can make sure they are logged in @@ -3746,7 +3745,7 @@ void Application::nodeKilled(SharedNodePointer node) { } } -void Application::trackIncomingOctreePacket(NLPacket& packet, SharedNodePointer sendingNode, bool wasStatsPacket) { +void Application::trackIncomingOctreePacket(ReceivedMessage& message, SharedNodePointer sendingNode, bool wasStatsPacket) { // Attempt to identify the sender from its address. if (sendingNode) { @@ -3756,13 +3755,13 @@ void Application::trackIncomingOctreePacket(NLPacket& packet, SharedNodePointer _octreeServerSceneStats.withWriteLock([&] { if (_octreeServerSceneStats.find(nodeUUID) != _octreeServerSceneStats.end()) { OctreeSceneStats& stats = _octreeServerSceneStats[nodeUUID]; - stats.trackIncomingOctreePacket(packet, wasStatsPacket, sendingNode->getClockSkewUsec()); + stats.trackIncomingOctreePacket(message, wasStatsPacket, sendingNode->getClockSkewUsec()); } }); } } -int Application::processOctreeStats(NLPacket& packet, SharedNodePointer sendingNode) { +int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode) { // But, also identify the sender, and keep track of the contained jurisdiction root for this server // parse the incoming stats datas stick it in a temporary object for now, while we @@ -3774,7 +3773,7 @@ int Application::processOctreeStats(NLPacket& packet, SharedNodePointer sendingN // now that we know the node ID, let's add these stats to the stats for that node... _octreeServerSceneStats.withWriteLock([&] { OctreeSceneStats& octreeStats = _octreeServerSceneStats[nodeUUID]; - statsMessageLength = octreeStats.unpackFromPacket(packet); + statsMessageLength = octreeStats.unpackFromPacket(message); // see if this is the first we've heard of this node... NodeToJurisdictionMap* jurisdiction = NULL; diff --git a/interface/src/Application.h b/interface/src/Application.h index a2125e7e09..f590c41e7b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -314,7 +314,7 @@ private slots: void activeChanged(Qt::ApplicationState state); void domainSettingsReceived(const QJsonObject& domainSettingsObject); - void handleDomainConnectionDeniedPacket(QSharedPointer packet); + void handleDomainConnectionDeniedPacket(QSharedPointer message); void notifyPacketVersionMismatch(); @@ -380,8 +380,8 @@ private: bool importSVOFromURL(const QString& urlString); - int processOctreeStats(NLPacket& packet, SharedNodePointer sendingNode); - void trackIncomingOctreePacket(NLPacket& packet, SharedNodePointer sendingNode, bool wasStatsPacket); + int processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode); + void trackIncomingOctreePacket(ReceivedMessage& message, SharedNodePointer sendingNode, bool wasStatsPacket); void resizeEvent(QResizeEvent* size); diff --git a/interface/src/octree/OctreePacketProcessor.cpp b/interface/src/octree/OctreePacketProcessor.cpp index 2fa0267dc6..1538c4eb65 100644 --- a/interface/src/octree/OctreePacketProcessor.cpp +++ b/interface/src/octree/OctreePacketProcessor.cpp @@ -23,11 +23,11 @@ OctreePacketProcessor::OctreePacketProcessor() { this, "handleOctreePacket"); } -void OctreePacketProcessor::handleOctreePacket(QSharedPointer packet, SharedNodePointer senderNode) { - queueReceivedPacket(packet, senderNode); +void OctreePacketProcessor::handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode) { + queueReceivedPacket(message, senderNode); } -void OctreePacketProcessor::processPacket(QSharedPointer packet, SharedNodePointer sendingNode) { +void OctreePacketProcessor::processPacket(QSharedPointer message, SharedNodePointer sendingNode) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "OctreePacketProcessor::processPacket()"); @@ -39,41 +39,43 @@ void OctreePacketProcessor::processPacket(QSharedPointer packet, Share bool wasStatsPacket = false; - PacketType octreePacketType = packet->getType(); + PacketType octreePacketType = message->getType(); // note: PacketType_OCTREE_STATS can have PacketType_VOXEL_DATA // immediately following them inside the same packet. So, we process the PacketType_OCTREE_STATS first // then process any remaining bytes as if it was another packet if (octreePacketType == PacketType::OctreeStats) { - int statsMessageLength = qApp->processOctreeStats(*packet, sendingNode); + int statsMessageLength = qApp->processOctreeStats(*message, sendingNode); wasStatsPacket = true; - int piggybackBytes = packet->getPayloadSize() - statsMessageLength; + int piggybackBytes = message->getPayloadSize() - statsMessageLength; if (piggybackBytes) { // construct a new packet from the piggybacked one auto buffer = std::unique_ptr(new char[piggybackBytes]); - memcpy(buffer.get(), packet->getPayload() + statsMessageLength, piggybackBytes); + memcpy(buffer.get(), message->getPayload() + statsMessageLength, piggybackBytes); + qDebug() << "Got piggyback, read " << piggybackBytes << " bytes"; - auto newPacket = NLPacket::fromReceivedPacket(std::move(buffer), piggybackBytes, packet->getSenderSockAddr()); - packet = QSharedPointer(newPacket.release()); + auto newPacket = NLPacket::fromReceivedPacket(std::move(buffer), piggybackBytes, message->getSenderSockAddr()); + message = QSharedPointer(new ReceivedMessage(*newPacket.release())); } else { // Note... stats packets don't have sequence numbers, so we don't want to send those to trackIncomingVoxelPacket() return; // bail since no piggyback data } } // fall through to piggyback message - PacketType packetType = packet->getType(); + PacketType packetType = message->getType(); // check version of piggyback packet against expected version - if (packet->getVersion() != versionForPacketType(packet->getType())) { + if (message->getVersion() != versionForPacketType(message->getType())) { static QMultiMap versionDebugSuppressMap; - const QUuid& senderUUID = packet->getSourceID(); + const QUuid& senderUUID = message->getSourceID(); if (!versionDebugSuppressMap.contains(senderUUID, packetType)) { + qDebug() << "Was stats packet? " << wasStatsPacket; qDebug() << "OctreePacketProcessor - piggyback packet version mismatch on" << packetType << "- Sender" - << senderUUID << "sent" << (int) packet->getVersion() << "but" + << senderUUID << "sent" << (int) message->getVersion() << "but" << (int) versionForPacketType(packetType) << "expected."; emit packetVersionMismatch(); @@ -83,21 +85,21 @@ void OctreePacketProcessor::processPacket(QSharedPointer packet, Share return; // bail since piggyback version doesn't match } - qApp->trackIncomingOctreePacket(*packet, sendingNode, wasStatsPacket); + qApp->trackIncomingOctreePacket(*message, sendingNode, wasStatsPacket); // seek back to beginning of packet after tracking - packet->seek(0); + message->seek(0); switch(packetType) { case PacketType::EntityErase: { if (DependencyManager::get()->shouldRenderEntities()) { - qApp->getEntities()->processEraseMessage(*packet, sendingNode); + qApp->getEntities()->processEraseMessage(*message, sendingNode); } } break; case PacketType::EntityData: { if (DependencyManager::get()->shouldRenderEntities()) { - qApp->getEntities()->processDatagram(*packet, sendingNode); + qApp->getEntities()->processDatagram(*message, sendingNode); } } break; diff --git a/interface/src/octree/OctreePacketProcessor.h b/interface/src/octree/OctreePacketProcessor.h index 47ebdc73bc..d04cab3584 100644 --- a/interface/src/octree/OctreePacketProcessor.h +++ b/interface/src/octree/OctreePacketProcessor.h @@ -13,6 +13,7 @@ #define hifi_OctreePacketProcessor_h #include +#include /// Handles processing of incoming voxel packets for the interface application. As with other ReceivedPacketProcessor classes /// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket() @@ -25,9 +26,9 @@ signals: void packetVersionMismatch(); protected: - virtual void processPacket(QSharedPointer packet, SharedNodePointer sendingNode); + virtual void processPacket(QSharedPointer message, SharedNodePointer sendingNode) override; private slots: - void handleOctreePacket(QSharedPointer packet, SharedNodePointer senderNode); + void handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode); }; #endif // hifi_OctreePacketProcessor_h diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index b528b67745..1aa20a8ef6 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -489,24 +489,24 @@ void AudioClient::stop() { } } -void AudioClient::handleAudioEnvironmentDataPacket(QSharedPointer packet) { +void AudioClient::handleAudioEnvironmentDataPacket(QSharedPointer message) { char bitset; - packet->readPrimitive(&bitset); + message->readPrimitive(&bitset); bool hasReverb = oneAtBit(bitset, HAS_REVERB_BIT); if (hasReverb) { float reverbTime, wetLevel; - packet->readPrimitive(&reverbTime); - packet->readPrimitive(&wetLevel); + message->readPrimitive(&reverbTime); + message->readPrimitive(&wetLevel); _receivedAudioStream.setReverb(reverbTime, wetLevel); } else { _receivedAudioStream.clearReverb(); } } -void AudioClient::handleAudioDataPacket(QSharedPointer packet) { +void AudioClient::handleAudioDataPacket(QSharedPointer message) { auto nodeList = DependencyManager::get(); nodeList->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::ReceiveFirstAudioPacket); @@ -520,11 +520,11 @@ void AudioClient::handleAudioDataPacket(QSharedPointer packet) { } // Audio output must exist and be correctly set up if we're going to process received audio - _receivedAudioStream.parseData(*packet); + _receivedAudioStream.parseData(*message); } } -void AudioClient::handleNoisyMutePacket(QSharedPointer packet) { +void AudioClient::handleNoisyMutePacket(QSharedPointer message) { if (!_muted) { toggleMute(); @@ -533,12 +533,12 @@ void AudioClient::handleNoisyMutePacket(QSharedPointer packet) { } } -void AudioClient::handleMuteEnvironmentPacket(QSharedPointer packet) { +void AudioClient::handleMuteEnvironmentPacket(QSharedPointer message) { glm::vec3 position; float radius; - packet->readPrimitive(&position); - packet->readPrimitive(&radius); + message->readPrimitive(&position); + message->readPrimitive(&radius); emit muteEnvironmentRequested(position, radius); } diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index e699ee9266..08b75e27ce 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -140,10 +140,10 @@ public slots: void start(); void stop(); - void handleAudioEnvironmentDataPacket(QSharedPointer packet); - void handleAudioDataPacket(QSharedPointer packet); - void handleNoisyMutePacket(QSharedPointer packet); - void handleMuteEnvironmentPacket(QSharedPointer packet); + void handleAudioEnvironmentDataPacket(QSharedPointer message); + void handleAudioDataPacket(QSharedPointer message); + void handleNoisyMutePacket(QSharedPointer message); + void handleMuteEnvironmentPacket(QSharedPointer message); void sendDownstreamAudioStatsPacket() { _stats.sendDownstreamAudioStatsPacket(); } void handleAudioInput(); diff --git a/libraries/audio-client/src/AudioIOStats.cpp b/libraries/audio-client/src/AudioIOStats.cpp index 0ad6860b5a..6896c7fd6b 100644 --- a/libraries/audio-client/src/AudioIOStats.cpp +++ b/libraries/audio-client/src/AudioIOStats.cpp @@ -63,11 +63,12 @@ void AudioIOStats::sentPacket() { _lastSentAudioPacket = now; } } -void AudioIOStats::processStreamStatsPacket(QSharedPointer packet, SharedNodePointer sendingNode) { + +void AudioIOStats::processStreamStatsPacket(QSharedPointer message, SharedNodePointer sendingNode) { // parse the appendFlag, clear injected audio stream stats if 0 quint8 appendFlag; - packet->readPrimitive(&appendFlag); + message->readPrimitive(&appendFlag); if (!appendFlag) { _mixerInjectedStreamStatsMap.clear(); @@ -75,12 +76,12 @@ void AudioIOStats::processStreamStatsPacket(QSharedPointer packet, Sha // parse the number of stream stats structs to follow quint16 numStreamStats; - packet->readPrimitive(&numStreamStats); + message->readPrimitive(&numStreamStats); // parse the stream stats AudioStreamStats streamStats; for (quint16 i = 0; i < numStreamStats; i++) { - packet->readPrimitive(&streamStats); + message->readPrimitive(&streamStats); if (streamStats._streamType == PositionalAudioStream::Microphone) { _mixerAvatarStreamStats = streamStats; diff --git a/libraries/audio-client/src/AudioIOStats.h b/libraries/audio-client/src/AudioIOStats.h index 11f1d74185..2745deac2c 100644 --- a/libraries/audio-client/src/AudioIOStats.h +++ b/libraries/audio-client/src/AudioIOStats.h @@ -45,7 +45,7 @@ public: void sendDownstreamAudioStatsPacket(); public slots: - void processStreamStatsPacket(QSharedPointer packet, SharedNodePointer sendingNode); + void processStreamStatsPacket(QSharedPointer message, SharedNodePointer sendingNode); private: MixedProcessedAudioStream* _receivedAudioStream; diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index 3363bb7196..f2aa91aae1 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -98,22 +98,22 @@ void InboundAudioStream::perSecondCallbackForUpdatingStats() { _timeGapStatsForStatsPacket.currentIntervalComplete(); } -int InboundAudioStream::parseData(NLPacket& packet) { +int InboundAudioStream::parseData(ReceivedMessage& message) { // parse sequence number and track it quint16 sequence; - packet.readPrimitive(&sequence); + message.readPrimitive(&sequence); SequenceNumberStats::ArrivalInfo arrivalInfo = _incomingSequenceNumberStats.sequenceNumberReceived(sequence, - packet.getSourceID()); + message.getSourceID()); packetReceivedUpdateTimingStats(); int networkSamples; // parse the info after the seq number and before the audio data (the stream properties) - int prePropertyPosition = packet.pos(); - int propertyBytes = parseStreamProperties(packet.getType(), packet.readWithoutCopy(packet.bytesLeftToRead()), networkSamples); - packet.seek(prePropertyPosition + propertyBytes); + int prePropertyPosition = message.pos(); + int propertyBytes = parseStreamProperties(message.getType(), message.readWithoutCopy(message.getBytesLeftToRead()), networkSamples); + message.seek(prePropertyPosition + propertyBytes); // handle this packet based on its arrival status. switch (arrivalInfo._status) { @@ -128,10 +128,10 @@ int InboundAudioStream::parseData(NLPacket& packet) { } case SequenceNumberStats::OnTime: { // Packet is on time; parse its data to the ringbuffer - if (packet.getType() == PacketType::SilentAudioFrame) { + if (message.getType() == PacketType::SilentAudioFrame) { writeDroppableSilentSamples(networkSamples); } else { - parseAudioData(packet.getType(), packet.readWithoutCopy(packet.bytesLeftToRead()), networkSamples); + parseAudioData(message.getType(), message.readWithoutCopy(message.getBytesLeftToRead()), networkSamples); } break; } @@ -161,7 +161,7 @@ int InboundAudioStream::parseData(NLPacket& packet) { framesAvailableChanged(); - return packet.pos(); + return message.pos(); } int InboundAudioStream::parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) { diff --git a/libraries/audio/src/InboundAudioStream.h b/libraries/audio/src/InboundAudioStream.h index 5dfb75272b..28cb1307e6 100644 --- a/libraries/audio/src/InboundAudioStream.h +++ b/libraries/audio/src/InboundAudioStream.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "AudioRingBuffer.h" @@ -107,7 +108,7 @@ public: virtual void resetStats(); void clearBuffer(); - virtual int parseData(NLPacket& packet); + virtual int parseData(ReceivedMessage& packet) override; int popFrames(int maxFrames, bool allOrNothing, bool starveIfNoFramesPopped = true); int popSamples(int maxSamples, bool allOrNothing, bool starveIfNoSamplesPopped = true); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index a9ff9541ea..6cf0a2a478 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1153,8 +1153,8 @@ void AvatarData::clearJointsData() { } } -bool AvatarData::hasIdentityChangedAfterParsing(NLPacket& packet) { - QDataStream packetStream(&packet); +bool AvatarData::hasIdentityChangedAfterParsing(const QByteArray& data) { + QDataStream packetStream(data); QUuid avatarUUID; QUrl faceModelURL, skeletonModelURL; @@ -1198,12 +1198,11 @@ QByteArray AvatarData::identityByteArray() { return identityData; } -bool AvatarData::hasBillboardChangedAfterParsing(NLPacket& packet) { - QByteArray newBillboard = packet.readAll(); - if (newBillboard == _billboard) { +bool AvatarData::hasBillboardChangedAfterParsing(const QByteArray& data) { + if (data == _billboard) { return false; } - _billboard = newBillboard; + _billboard = data; return true; } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index e4022fd474..a583f72d5f 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -278,10 +278,10 @@ public: const HeadData* getHeadData() const { return _headData; } const HandData* getHandData() const { return _handData; } - bool hasIdentityChangedAfterParsing(NLPacket& packet); + bool hasIdentityChangedAfterParsing(const QByteArray& data); QByteArray identityByteArray(); - bool hasBillboardChangedAfterParsing(NLPacket& packet); + bool hasBillboardChangedAfterParsing(const QByteArray& data); const QUrl& getFaceModelURL() const { return _faceModelURL; } QString getFaceModelURLString() const { return _faceModelURL.toString(); } diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index 520bb34887..0a46fec3bc 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -48,16 +48,16 @@ AvatarSharedPointer AvatarHashMap::addAvatar(const QUuid& sessionUUID, const QWe return avatar; } -void AvatarHashMap::processAvatarDataPacket(QSharedPointer packet, SharedNodePointer sendingNode) { +void AvatarHashMap::processAvatarDataPacket(QSharedPointer message, SharedNodePointer sendingNode) { // enumerate over all of the avatars in this packet // only add them if mixerWeakPointer points to something (meaning that mixer is still around) - while (packet->bytesLeftToRead()) { - QUuid sessionUUID = QUuid::fromRfc4122(packet->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + while (message->getBytesLeftToRead()) { + QUuid sessionUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); - int positionBeforeRead = packet->pos(); + int positionBeforeRead = message->pos(); - QByteArray byteArray = packet->readWithoutCopy(packet->bytesLeftToRead()); + QByteArray byteArray = message->readWithoutCopy(message->getBytesLeftToRead()); if (sessionUUID != _lastOwnerSessionUUID) { AvatarSharedPointer avatar = _avatarHash.value(sessionUUID); @@ -67,19 +67,19 @@ void AvatarHashMap::processAvatarDataPacket(QSharedPointer packet, Sha // have the matching (or new) avatar parse the data from the packet int bytesRead = avatar->parseDataFromBuffer(byteArray); - packet->seek(positionBeforeRead + bytesRead); + message->seek(positionBeforeRead + bytesRead); } else { // create a dummy AvatarData class to throw this data on the ground AvatarData dummyData; int bytesRead = dummyData.parseDataFromBuffer(byteArray); - packet->seek(positionBeforeRead + bytesRead); + message->seek(positionBeforeRead + bytesRead); } } } -void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer packet, SharedNodePointer sendingNode) { +void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer message, SharedNodePointer sendingNode) { // setup a data stream to parse the packet - QDataStream identityStream(packet.data()); + QDataStream identityStream(message->getMessage()); QUuid sessionUUID; @@ -113,23 +113,23 @@ void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer packet, } } -void AvatarHashMap::processAvatarBillboardPacket(QSharedPointer packet, SharedNodePointer sendingNode) { - QUuid sessionUUID = QUuid::fromRfc4122(packet->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); +void AvatarHashMap::processAvatarBillboardPacket(QSharedPointer message, SharedNodePointer sendingNode) { + QUuid sessionUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); AvatarSharedPointer avatar = _avatarHash.value(sessionUUID); if (!avatar) { avatar = addAvatar(sessionUUID, sendingNode); } - QByteArray billboard = packet->read(packet->bytesLeftToRead()); + QByteArray billboard = message->read(message->getBytesLeftToRead()); if (avatar->getBillboard() != billboard) { avatar->setBillboard(billboard); } } -void AvatarHashMap::processKillAvatar(QSharedPointer packet, SharedNodePointer sendingNode) { +void AvatarHashMap::processKillAvatar(QSharedPointer message, SharedNodePointer sendingNode) { // read the node id - QUuid sessionUUID = QUuid::fromRfc4122(packet->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + QUuid sessionUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); removeAvatar(sessionUUID); } diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h index 804233b76a..2a93e71768 100644 --- a/libraries/avatars/src/AvatarHashMap.h +++ b/libraries/avatars/src/AvatarHashMap.h @@ -39,10 +39,10 @@ public slots: private slots: void sessionUUIDChanged(const QUuid& sessionUUID, const QUuid& oldUUID); - void processAvatarDataPacket(QSharedPointer packet, SharedNodePointer sendingNode); - void processAvatarIdentityPacket(QSharedPointer packet, SharedNodePointer sendingNode); - void processAvatarBillboardPacket(QSharedPointer packet, SharedNodePointer sendingNode); - void processKillAvatar(QSharedPointer packet, SharedNodePointer sendingNode); + void processAvatarDataPacket(QSharedPointer message, SharedNodePointer sendingNode); + void processAvatarIdentityPacket(QSharedPointer message, SharedNodePointer sendingNode); + void processAvatarBillboardPacket(QSharedPointer message, SharedNodePointer sendingNode); + void processKillAvatar(QSharedPointer message, SharedNodePointer sendingNode); protected: AvatarHashMap(); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index fb9ab6563b..dfa4f19aed 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -408,8 +408,8 @@ int EntityTreeRenderer::getBoundaryLevelAdjust() const { } -void EntityTreeRenderer::processEraseMessage(NLPacket& packet, const SharedNodePointer& sourceNode) { - std::static_pointer_cast(_tree)->processEraseMessage(packet, sourceNode); +void EntityTreeRenderer::processEraseMessage(ReceivedMessage& message, const SharedNodePointer& sourceNode) { + std::static_pointer_cast(_tree)->processEraseMessage(message, sourceNode); } Model* EntityTreeRenderer::allocateModel(const QString& url, const QString& collisionUrl) { diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 08ff1ac296..7c53a916d1 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -49,7 +49,7 @@ public: EntityTreePointer getTree() { return std::static_pointer_cast(_tree); } - void processEraseMessage(NLPacket& packet, const SharedNodePointer& sourceNode); + void processEraseMessage(ReceivedMessage& message, const SharedNodePointer& sourceNode); virtual void init(); diff --git a/libraries/entities/src/EntityEditPacketSender.cpp b/libraries/entities/src/EntityEditPacketSender.cpp index 05bb558767..91f21659ec 100644 --- a/libraries/entities/src/EntityEditPacketSender.cpp +++ b/libraries/entities/src/EntityEditPacketSender.cpp @@ -23,9 +23,9 @@ EntityEditPacketSender::EntityEditPacketSender() { packetReceiver.registerDirectListener(PacketType::EntityEditNack, this, "processEntityEditNackPacket"); } -void EntityEditPacketSender::processEntityEditNackPacket(QSharedPointer packet, SharedNodePointer sendingNode) { +void EntityEditPacketSender::processEntityEditNackPacket(QSharedPointer message, SharedNodePointer sendingNode) { if (_shouldProcessNack) { - processNackPacket(*packet, sendingNode); + processNackPacket(*message, sendingNode); } } diff --git a/libraries/entities/src/EntityEditPacketSender.h b/libraries/entities/src/EntityEditPacketSender.h index 0932ec2af1..ec90473643 100644 --- a/libraries/entities/src/EntityEditPacketSender.h +++ b/libraries/entities/src/EntityEditPacketSender.h @@ -35,7 +35,7 @@ public: virtual void adjustEditPacketForClockSkew(PacketType type, QByteArray& buffer, int clockSkew); public slots: - void processEntityEditNackPacket(QSharedPointer packet, SharedNodePointer sendingNode); + void processEntityEditNackPacket(QSharedPointer message, SharedNodePointer sendingNode); void toggleNackPackets() { _shouldProcessNack = !_shouldProcessNack; } private: diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index c4c02d364f..0f76f76094 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -564,7 +564,7 @@ EntityItemPointer EntityTree::findEntityByEntityItemID(const EntityItemID& entit return foundEntity; } -int EntityTree::processEditPacketData(NLPacket& packet, const unsigned char* editData, int maxLength, +int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode) { if (!getIsServer()) { @@ -574,7 +574,7 @@ int EntityTree::processEditPacketData(NLPacket& packet, const unsigned char* edi int processedBytes = 0; // we handle these types of "edit" packets - switch (packet.getType()) { + switch (message.getType()) { case PacketType::EntityErase: { QByteArray dataByteArray = QByteArray::fromRawData(reinterpret_cast(editData), maxLength); processedBytes = processEraseMessageDetails(dataByteArray, senderNode); @@ -606,7 +606,7 @@ int EntityTree::processEditPacketData(NLPacket& packet, const unsigned char* edi startLookup = usecTimestampNow(); EntityItemPointer existingEntity = findEntityByEntityItemID(entityItemID); endLookup = usecTimestampNow(); - if (existingEntity && packet.getType() == PacketType::EntityEdit) { + if (existingEntity && message.getType() == PacketType::EntityEdit) { // if the EntityItem exists, then update it startLogging = usecTimestampNow(); if (wantEditLogging()) { @@ -620,7 +620,7 @@ int EntityTree::processEditPacketData(NLPacket& packet, const unsigned char* edi existingEntity->markAsChangedOnServer(); endUpdate = usecTimestampNow(); _totalUpdates++; - } else if (packet.getType() == PacketType::EntityAdd) { + } else if (message.getType() == PacketType::EntityAdd) { if (senderNode->getCanRez()) { // this is a new entity... assign a new entityID properties.setCreated(properties.getLastEdited()); @@ -648,7 +648,7 @@ int EntityTree::processEditPacketData(NLPacket& packet, const unsigned char* edi } else { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("^Add or Edit failed.*"); - qCDebug(entities) << "Add or Edit failed." << packet.getType() << existingEntity.get(); + qCDebug(entities) << "Add or Edit failed." << message.getType() << existingEntity.get(); } } @@ -847,24 +847,24 @@ void EntityTree::forgetEntitiesDeletedBefore(quint64 sinceTime) { // TODO: consider consolidating processEraseMessageDetails() and processEraseMessage() -int EntityTree::processEraseMessage(NLPacket& packet, const SharedNodePointer& sourceNode) { +int EntityTree::processEraseMessage(ReceivedMessage& message, const SharedNodePointer& sourceNode) { withWriteLock([&] { - packet.seek(sizeof(OCTREE_PACKET_FLAGS) + sizeof(OCTREE_PACKET_SEQUENCE) + sizeof(OCTREE_PACKET_SENT_TIME)); + message.seek(sizeof(OCTREE_PACKET_FLAGS) + sizeof(OCTREE_PACKET_SEQUENCE) + sizeof(OCTREE_PACKET_SENT_TIME)); uint16_t numberOfIDs = 0; // placeholder for now - packet.readPrimitive(&numberOfIDs); + message.readPrimitive(&numberOfIDs); if (numberOfIDs > 0) { QSet entityItemIDsToDelete; for (size_t i = 0; i < numberOfIDs; i++) { - if (NUM_BYTES_RFC4122_UUID > packet.bytesLeftToRead()) { + if (NUM_BYTES_RFC4122_UUID > message.getBytesLeftToRead()) { qCDebug(entities) << "EntityTree::processEraseMessage().... bailing because not enough bytes in buffer"; break; // bail to prevent buffer overflow } - QUuid entityID = QUuid::fromRfc4122(packet.readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + QUuid entityID = QUuid::fromRfc4122(message.readWithoutCopy(NUM_BYTES_RFC4122_UUID)); EntityItemID entityItemID(entityID); entityItemIDsToDelete << entityItemID; @@ -877,7 +877,7 @@ int EntityTree::processEraseMessage(NLPacket& packet, const SharedNodePointer& s deleteEntities(entityItemIDsToDelete, true, true); } }); - return packet.pos(); + return message.pos(); } // This version skips over the header diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index dd1ee01969..f9f8cca2f6 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -77,8 +77,8 @@ public: virtual bool canProcessVersion(PacketVersion thisVersion) const { return thisVersion >= VERSION_ENTITIES_USE_METERS_AND_RADIANS; } virtual bool handlesEditPacketType(PacketType packetType) const; - virtual int processEditPacketData(NLPacket& packet, const unsigned char* editData, int maxLength, - const SharedNodePointer& senderNode); + virtual int processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength, + const SharedNodePointer& senderNode) override; virtual bool rootElementHasData() const { return true; } @@ -144,7 +144,7 @@ public: bool& hasMore); void forgetEntitiesDeletedBefore(quint64 sinceTime); - int processEraseMessage(NLPacket& packet, const SharedNodePointer& sourceNode); + int processEraseMessage(ReceivedMessage& message, const SharedNodePointer& sourceNode); int processEraseMessageDetails(const QByteArray& buffer, const SharedNodePointer& sourceNode); EntityItemFBXService* getFBXService() const { return _fbxService; } diff --git a/libraries/entities/src/EntityTreeHeadlessViewer.cpp b/libraries/entities/src/EntityTreeHeadlessViewer.cpp index bdb35f8547..149f92adad 100644 --- a/libraries/entities/src/EntityTreeHeadlessViewer.cpp +++ b/libraries/entities/src/EntityTreeHeadlessViewer.cpp @@ -39,6 +39,6 @@ void EntityTreeHeadlessViewer::update() { } } -void EntityTreeHeadlessViewer::processEraseMessage(NLPacket& packet, const SharedNodePointer& sourceNode) { - std::static_pointer_cast(_tree)->processEraseMessage(packet, sourceNode); +void EntityTreeHeadlessViewer::processEraseMessage(ReceivedMessage& message, const SharedNodePointer& sourceNode) { + std::static_pointer_cast(_tree)->processEraseMessage(message, sourceNode); } diff --git a/libraries/entities/src/EntityTreeHeadlessViewer.h b/libraries/entities/src/EntityTreeHeadlessViewer.h index 9964c47b49..40e428b655 100644 --- a/libraries/entities/src/EntityTreeHeadlessViewer.h +++ b/libraries/entities/src/EntityTreeHeadlessViewer.h @@ -38,7 +38,7 @@ public: EntityTreePointer getTree() { return std::static_pointer_cast(_tree); } - void processEraseMessage(NLPacket& packet, const SharedNodePointer& sourceNode); + void processEraseMessage(ReceivedMessage& message, const SharedNodePointer& sourceNode); virtual void init(); diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 87af2a5cf8..623d1d86eb 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -38,9 +38,9 @@ AssetClient::AssetClient() { auto nodeList = DependencyManager::get(); auto& packetReceiver = nodeList->getPacketReceiver(); - packetReceiver.registerListener(PacketType::AssetGetInfoReply, this, "handleAssetGetInfoReply"); - packetReceiver.registerMessageListener(PacketType::AssetGetReply, this, "handleAssetGetReply"); - packetReceiver.registerListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply"); + packetReceiver.registerMessageListener(PacketType::AssetGetInfoReply, this, "handleAssetGetInfoReply"); + packetReceiver.registerMessageListener(PacketType::AssetGetReply, this, "handleAssetGetReply", true); + packetReceiver.registerMessageListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply"); connect(nodeList.data(), &LimitedNodeList::nodeKilled, this, &AssetClient::handleNodeKilled); } @@ -105,7 +105,7 @@ AssetUpload* AssetClient::createUpload(const QString& filename) { } bool AssetClient::getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, - ReceivedAssetCallback callback) { + ReceivedAssetCallback callback, ProgressCallback progressCallback) { if (hash.length() != SHA256_HASH_HEX_LENGTH) { qCWarning(asset_client) << "Invalid hash size"; return false; @@ -136,7 +136,7 @@ bool AssetClient::getAsset(const QString& hash, const QString& extension, DataOf nodeList->sendPacket(std::move(packet), *assetServer); - _pendingRequests[assetServer][messageID] = callback; + _pendingRequests[assetServer][messageID] = { callback, progressCallback }; return true; } @@ -169,18 +169,18 @@ bool AssetClient::getAssetInfo(const QString& hash, const QString& extension, Ge return false; } -void AssetClient::handleAssetGetInfoReply(QSharedPointer packet, SharedNodePointer senderNode) { +void AssetClient::handleAssetGetInfoReply(QSharedPointer message, SharedNodePointer senderNode) { MessageID messageID; - packet->readPrimitive(&messageID); - auto assetHash = packet->read(SHA256_HASH_LENGTH); + message->readPrimitive(&messageID); + auto assetHash = message->read(SHA256_HASH_LENGTH); AssetServerError error; - packet->readPrimitive(&error); + message->readPrimitive(&error); AssetInfo info { assetHash.toHex(), 0 }; if (error == AssetServerError::NoError) { - packet->readPrimitive(&info.size); + message->readPrimitive(&info.size); } // Check if we have any pending requests for this node @@ -203,25 +203,24 @@ void AssetClient::handleAssetGetInfoReply(QSharedPointer packet, Share } } -void AssetClient::handleAssetGetReply(QSharedPointer packetList, SharedNodePointer senderNode) { - QByteArray data = packetList->getMessage(); - QBuffer packet { &data }; - packet.open(QIODevice::ReadOnly); +void AssetClient::handleAssetGetReply(QSharedPointer message, SharedNodePointer senderNode) { - auto assetHash = packet.read(SHA256_HASH_LENGTH); + + + auto assetHash = message->read(SHA256_HASH_LENGTH); qCDebug(asset_client) << "Got reply for asset: " << assetHash.toHex(); MessageID messageID; - packet.read(reinterpret_cast(&messageID), sizeof(messageID)); + message->readPrimitive(&messageID); AssetServerError error; - packet.read(reinterpret_cast(&error), sizeof(AssetServerError)); - QByteArray assetData; + message->readPrimitive(&error); + // QByteArray assetData; + + DataOffset length = 0; if (!error) { - DataOffset length; - packet.read(reinterpret_cast(&length), sizeof(DataOffset)); - data = packet.read(length); + message->readPrimitive(&length); } else { qCWarning(asset_client) << "Failure getting asset: " << error; } @@ -236,8 +235,19 @@ void AssetClient::handleAssetGetReply(QSharedPointer packetList, S // Check if we have this pending request auto requestIt = messageCallbackMap.find(messageID); if (requestIt != messageCallbackMap.end()) { - auto callback = requestIt->second; - callback(true, error, data); + auto& callbacks = requestIt->second; + + if (message->isComplete()) { + callbacks.completeCallback(true, error, message->readAll()); + } else { + connect(message.data(), &ReceivedMessage::progress, this, [this, length, message, callbacks](ReceivedMessage* msg) { + //qDebug() << "Progress: " << msg->getDataSize(); + callbacks.progressCallback(msg->getDataSize(), length); + }); + connect(message.data(), &ReceivedMessage::completed, this, [this, message, error, callbacks](ReceivedMessage* msg) { + callbacks.completeCallback(true, error, message->readAll()); + }); + } messageCallbackMap.erase(requestIt); } @@ -272,19 +282,19 @@ bool AssetClient::uploadAsset(const QByteArray& data, const QString& extension, return false; } -void AssetClient::handleAssetUploadReply(QSharedPointer packet, SharedNodePointer senderNode) { +void AssetClient::handleAssetUploadReply(QSharedPointer message, SharedNodePointer senderNode) { MessageID messageID; - packet->readPrimitive(&messageID); + message->readPrimitive(&messageID); AssetServerError error; - packet->readPrimitive(&error); + message->readPrimitive(&error); QString hashString; if (error) { qCWarning(asset_client) << "Error uploading file to asset server"; } else { - auto hash = packet->read(SHA256_HASH_LENGTH); + auto hash = message->read(SHA256_HASH_LENGTH); hashString = hash.toHex(); qCDebug(asset_client) << "Successfully uploaded asset to asset-server - SHA256 hash is " << hashString; @@ -319,7 +329,7 @@ void AssetClient::handleNodeKilled(SharedNodePointer node) { auto messageMapIt = _pendingRequests.find(node); if (messageMapIt != _pendingRequests.end()) { for (const auto& value : messageMapIt->second) { - value.second(false, AssetServerError::NoError, QByteArray()); + value.second.completeCallback(false, AssetServerError::NoError, QByteArray()); } messageMapIt->second.clear(); } diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index 9b82e63b58..f8a0d16ef8 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -21,6 +21,7 @@ #include "LimitedNodeList.h" #include "NLPacket.h" #include "Node.h" +#include "ReceivedMessage.h" class AssetRequest; class AssetUpload; @@ -34,6 +35,7 @@ using ReceivedAssetCallback = std::function; using UploadResultCallback = std::function; +using ProgressCallback = std::function; class AssetClient : public QObject, public Dependency { @@ -47,19 +49,25 @@ public: Q_INVOKABLE AssetUpload* createUpload(const QString& filename); private slots: - void handleAssetGetInfoReply(QSharedPointer packet, SharedNodePointer senderNode); - void handleAssetGetReply(QSharedPointer packetList, SharedNodePointer senderNode); - void handleAssetUploadReply(QSharedPointer packet, SharedNodePointer senderNode); + void handleAssetGetInfoReply(QSharedPointer message, SharedNodePointer senderNode); + void handleAssetGetReply(QSharedPointer message, SharedNodePointer senderNode); + void handleAssetUploadReply(QSharedPointer message, SharedNodePointer senderNode); void handleNodeKilled(SharedNodePointer node); private: bool getAssetInfo(const QString& hash, const QString& extension, GetInfoCallback callback); - bool getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, ReceivedAssetCallback callback); + bool getAsset(const QString& hash, const QString& extension, DataOffset start, DataOffset end, + ReceivedAssetCallback callback, ProgressCallback progressCallback); bool uploadAsset(const QByteArray& data, const QString& extension, UploadResultCallback callback); + struct GetAssetCallbacks { + ReceivedAssetCallback completeCallback; + ProgressCallback progressCallback; + }; + static MessageID _currentID; - std::unordered_map> _pendingRequests; + std::unordered_map> _pendingRequests; std::unordered_map> _pendingInfoRequests; std::unordered_map> _pendingUploads; diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 121b4cd4fd..953d1590a4 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -124,6 +124,8 @@ void AssetRequest::start() { _state = Finished; emit finished(this); + }, [this](qint64 totalReceived, qint64 total) { + emit progress(totalReceived, total); }); }); } diff --git a/libraries/networking/src/Assignment.cpp b/libraries/networking/src/Assignment.cpp index 66c6bf2a2c..f933786fcb 100644 --- a/libraries/networking/src/Assignment.cpp +++ b/libraries/networking/src/Assignment.cpp @@ -66,20 +66,20 @@ Assignment::Assignment(Assignment::Command command, Assignment::Type type, const } } -Assignment::Assignment(NLPacket& packet) : +Assignment::Assignment(ReceivedMessage& message) : _pool(), _location(GlobalLocation), _payload(), _walletUUID(), _nodeVersion() { - if (packet.getType() == PacketType::RequestAssignment) { + if (message.getType() == PacketType::RequestAssignment) { _command = Assignment::RequestCommand; - } else if (packet.getType() == PacketType::CreateAssignment) { + } else if (message.getType() == PacketType::CreateAssignment) { _command = Assignment::CreateCommand; } - QDataStream packetStream(&packet); + QDataStream packetStream(message.getMessage()); packetStream >> *this; } diff --git a/libraries/networking/src/Assignment.h b/libraries/networking/src/Assignment.h index ee3d9cb5fd..b382cd4ca8 100644 --- a/libraries/networking/src/Assignment.h +++ b/libraries/networking/src/Assignment.h @@ -14,6 +14,8 @@ #include +#include "ReceivedMessage.h" + #include "NodeList.h" const int MAX_PAYLOAD_BYTES = 1024; @@ -61,7 +63,7 @@ public: /// Constructs an Assignment from a network packet /// \param packet the packet to un-pack the assignment from - Assignment(NLPacket& packet); + Assignment(ReceivedMessage& packet); void setUUID(const QUuid& uuid) { _uuid = uuid; } const QUuid& getUUID() const { return _uuid; } diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index df024b361d..944675b552 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -251,21 +251,22 @@ void DomainHandler::requestDomainSettings() { } } -void DomainHandler::processSettingsPacketList(QSharedPointer packetList) { +void DomainHandler::processSettingsPacketList(QSharedPointer packetList) { + qCDebug(networking) << "Got settings!! " << packetList->getMessage().size(); auto data = packetList->getMessage(); - _settingsObject = QJsonDocument::fromJson(data).object(); - qCDebug(networking) << "Received domain settings: \n" << QString(data); + _settingsObject = QJsonDocument::fromJson(data).object(); + // reset failed settings requests to 0, we got them _failedSettingsRequests = 0; emit settingsReceived(_settingsObject); } -void DomainHandler::processICEPingReplyPacket(QSharedPointer packet) { - const HifiSockAddr& senderSockAddr = packet->getSenderSockAddr(); +void DomainHandler::processICEPingReplyPacket(QSharedPointer message) { + const HifiSockAddr& senderSockAddr = message->getSenderSockAddr(); qCDebug(networking) << "Received reply from domain-server on" << senderSockAddr; if (getIP().isNull()) { @@ -282,10 +283,10 @@ void DomainHandler::processICEPingReplyPacket(QSharedPointer packet) { } } -void DomainHandler::processDTLSRequirementPacket(QSharedPointer dtlsRequirementPacket) { +void DomainHandler::processDTLSRequirementPacket(QSharedPointer message) { // figure out the port that the DS wants us to use for us to talk to them with DTLS unsigned short dtlsPort; - dtlsRequirementPacket->readPrimitive(&dtlsPort); + message->readPrimitive(&dtlsPort); qCDebug(networking) << "domain-server DTLS port changed to" << dtlsPort << "- Enabling DTLS."; @@ -294,14 +295,14 @@ void DomainHandler::processDTLSRequirementPacket(QSharedPointer dtlsRe // initializeDTLSSession(); } -void DomainHandler::processICEResponsePacket(QSharedPointer icePacket) { +void DomainHandler::processICEResponsePacket(QSharedPointer message) { if (_icePeer.hasSockets()) { qDebug() << "Received an ICE peer packet for domain-server but we already have sockets. Not processing."; // bail on processing this packet if our ice peer doesn't have sockets return; } - QDataStream iceResponseStream(icePacket.data()); + QDataStream iceResponseStream(message->getMessage()); iceResponseStream >> _icePeer; diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index 9dd4254c30..a48f81b271 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -24,6 +24,7 @@ #include "NLPacket.h" #include "NLPacketList.h" #include "Node.h" +#include "ReceivedMessage.h" const unsigned short DEFAULT_DOMAIN_SERVER_PORT = 40102; const unsigned short DEFAULT_DOMAIN_SERVER_DTLS_PORT = 40103; @@ -87,10 +88,10 @@ public slots: void setHostnameAndPort(const QString& hostname, quint16 port = DEFAULT_DOMAIN_SERVER_PORT); void setIceServerHostnameAndID(const QString& iceServerHostname, const QUuid& id); - void processSettingsPacketList(QSharedPointer packetList); - void processICEPingReplyPacket(QSharedPointer packet); - void processDTLSRequirementPacket(QSharedPointer dtlsRequirementPacket); - void processICEResponsePacket(QSharedPointer icePacket); + void processSettingsPacketList(QSharedPointer packetList); + void processICEPingReplyPacket(QSharedPointer message); + void processDTLSRequirementPacket(QSharedPointer dtlsRequirementPacket); + void processICEResponsePacket(QSharedPointer icePacket); private slots: void completedHostnameLookup(const QHostInfo& hostInfo); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 75d42f55cb..91cff1ad0b 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -60,10 +60,6 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short if (firstCall) { NodeType::init(); - // register the SharedNodePointer meta-type for signals/slots - qRegisterMetaType>(); - qRegisterMetaType(); - firstCall = false; } @@ -99,6 +95,11 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short _packetReceiver->handleVerifiedPacket(std::move(packet)); } ); + _nodeSocket.setPendingMessageHandler( + [this](std::unique_ptr packet) { + _packetReceiver->handleVerifiedMessagePacket(std::move(packet)); + } + ); _nodeSocket.setPacketListHandler( [this](std::unique_ptr packetList) { _packetReceiver->handleVerifiedPacketList(std::move(packetList)); @@ -392,7 +393,7 @@ qint64 LimitedNodeList::sendPacket(std::unique_ptr packet, const Node& return sendPacket(std::move(packet), destinationSockAddr, destinationNode.getConnectionSecret()); } -int LimitedNodeList::updateNodeWithDataFromPacket(QSharedPointer packet, SharedNodePointer sendingNode) { +int LimitedNodeList::updateNodeWithDataFromPacket(QSharedPointer message, SharedNodePointer sendingNode) { QMutexLocker locker(&sendingNode->getMutex()); NodeData* linkedData = sendingNode->getLinkedData(); @@ -402,7 +403,7 @@ int LimitedNodeList::updateNodeWithDataFromPacket(QSharedPointer packe if (linkedData) { QMutexLocker linkedDataLocker(&linkedData->getMutex()); - return linkedData->parseData(*packet); + return linkedData->parseData(*message); } return 0; @@ -459,9 +460,9 @@ void LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID) { } } -void LimitedNodeList::processKillNode(NLPacket& packet) { +void LimitedNodeList::processKillNode(ReceivedMessage& message) { // read the node id - QUuid nodeUUID = QUuid::fromRfc4122(packet.readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + QUuid nodeUUID = QUuid::fromRfc4122(message.readWithoutCopy(NUM_BYTES_RFC4122_UUID)); // kill the node with this UUID, if it exists killNodeWithUUID(nodeUUID); @@ -524,11 +525,11 @@ std::unique_ptr LimitedNodeList::constructPingPacket(PingType_t pingTy return pingPacket; } -std::unique_ptr LimitedNodeList::constructPingReplyPacket(NLPacket& pingPacket) { +std::unique_ptr LimitedNodeList::constructPingReplyPacket(ReceivedMessage& message) { PingType_t typeFromOriginalPing; quint64 timeFromOriginalPing; - pingPacket.readPrimitive(&typeFromOriginalPing); - pingPacket.readPrimitive(&timeFromOriginalPing); + message.readPrimitive(&typeFromOriginalPing); + message.readPrimitive(&timeFromOriginalPing); int packetSize = sizeof(PingType_t) + sizeof(quint64) + sizeof(quint64); auto replyPacket = NLPacket::create(PacketType::PingReply, packetSize); @@ -549,11 +550,11 @@ std::unique_ptr LimitedNodeList::constructICEPingPacket(PingType_t pin return icePingPacket; } -std::unique_ptr LimitedNodeList::constructICEPingReplyPacket(NLPacket& pingPacket, const QUuid& iceID) { +std::unique_ptr LimitedNodeList::constructICEPingReplyPacket(ReceivedMessage& message, const QUuid& iceID) { // pull out the ping type so we can reply back with that PingType_t pingType; - memcpy(&pingType, pingPacket.getPayload() + NUM_BYTES_RFC4122_UUID, sizeof(PingType_t)); + memcpy(&pingType, message.getPayload() + NUM_BYTES_RFC4122_UUID, sizeof(PingType_t)); int packetSize = NUM_BYTES_RFC4122_UUID + sizeof(PingType_t); auto icePingReplyPacket = NLPacket::create(PacketType::ICEPingReply, packetSize); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index 2488b0cf8c..54eef12752 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -37,8 +37,9 @@ #include "DomainHandler.h" #include "Node.h" #include "NLPacket.h" -#include "PacketReceiver.h" #include "NLPacketList.h" +#include "PacketReceiver.h" +#include "ReceivedMessage.h" #include "udt/PacketHeaders.h" #include "udt/Socket.h" #include "UUIDHasher.h" @@ -144,9 +145,9 @@ public: const HifiSockAddr& getLocalSockAddr() const { return _localSockAddr; } const HifiSockAddr& getSTUNSockAddr() const { return _stunSockAddr; } - void processKillNode(NLPacket& packet); + void processKillNode(ReceivedMessage& message); - int updateNodeWithDataFromPacket(QSharedPointer packet, SharedNodePointer matchingNode); + int updateNodeWithDataFromPacket(QSharedPointer packet, SharedNodePointer matchingNode); unsigned int broadcastToNodes(std::unique_ptr packet, const NodeSet& destinationNodeTypes); SharedNodePointer soloNodeOfType(NodeType_t nodeType); @@ -155,10 +156,10 @@ public: void resetPacketStats(); std::unique_ptr constructPingPacket(PingType_t pingType = PingType::Agnostic); - std::unique_ptr constructPingReplyPacket(NLPacket& pingPacket); + std::unique_ptr constructPingReplyPacket(ReceivedMessage& message); std::unique_ptr constructICEPingPacket(PingType_t pingType, const QUuid& iceID); - std::unique_ptr constructICEPingReplyPacket(NLPacket& pingPacket, const QUuid& iceID); + std::unique_ptr constructICEPingReplyPacket(ReceivedMessage& message, const QUuid& iceID); void sendHeartbeatToIceServer(const HifiSockAddr& iceServerSockAddr); void sendPeerQueryToIceServer(const HifiSockAddr& iceServerSockAddr, const QUuid& clientID, const QUuid& peerID); diff --git a/libraries/networking/src/NLPacketList.cpp b/libraries/networking/src/NLPacketList.cpp index 318fb037a1..c6bea33d86 100644 --- a/libraries/networking/src/NLPacketList.cpp +++ b/libraries/networking/src/NLPacketList.cpp @@ -44,6 +44,7 @@ NLPacketList::NLPacketList(PacketList&& other) : PacketList(std::move(other)) { auto nlPacket = static_cast(_packets.front().get()); _sourceID = nlPacket->getSourceID(); _packetType = nlPacket->getType(); + _packetVersion = nlPacket->getVersion(); } } diff --git a/libraries/networking/src/NLPacketList.h b/libraries/networking/src/NLPacketList.h index c705e6ece3..250d15dbb9 100644 --- a/libraries/networking/src/NLPacketList.h +++ b/libraries/networking/src/NLPacketList.h @@ -21,20 +21,25 @@ public: static std::unique_ptr create(PacketType packetType, QByteArray extendedHeader = QByteArray(), bool isReliable = false, bool isOrdered = false); - static std::unique_ptr fromPacketList(std::unique_ptr); + static std::unique_ptr fromPacketList(std::unique_ptr); + PacketVersion getVersion() const { return _packetVersion; } const QUuid& getSourceID() const { return _sourceID; } private: NLPacketList(PacketType packetType, QByteArray extendedHeader = QByteArray(), bool isReliable = false, bool isOrdered = false); - NLPacketList(PacketList&& packetList); + NLPacketList(udt::PacketList&& packetList); NLPacketList(const NLPacketList& other) = delete; NLPacketList& operator=(const NLPacketList& other) = delete; virtual std::unique_ptr createPacket(); + + PacketVersion _packetVersion; QUuid _sourceID; }; +Q_DECLARE_METATYPE(QSharedPointer) + #endif // hifi_PacketList_h diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 5fea670dd0..421b76f471 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -22,6 +22,10 @@ const QString UNKNOWN_NodeType_t_NAME = "Unknown"; +static int NodePtrMetaTypeId = qRegisterMetaType("Node*"); +static int sharedPtrNodeMetaTypeId = qRegisterMetaType>("QSharedPointer"); +static int sharedNodePtrMetaTypeId = qRegisterMetaType("SharedNodePointer"); + namespace NodeType { QHash TypeNameHash; } diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 38d6678ba5..663684fe9d 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -85,6 +85,8 @@ private: bool _canRez; }; +Q_DECLARE_METATYPE(Node*) + typedef QSharedPointer SharedNodePointer; Q_DECLARE_METATYPE(SharedNodePointer) diff --git a/libraries/networking/src/NodeData.h b/libraries/networking/src/NodeData.h index 78ef446938..7a214cd240 100644 --- a/libraries/networking/src/NodeData.h +++ b/libraries/networking/src/NodeData.h @@ -17,6 +17,7 @@ #include #include "NLPacket.h" +#include "ReceivedMessage.h" class Node; @@ -25,7 +26,7 @@ class NodeData : public QObject { public: NodeData(); virtual ~NodeData() = 0; - virtual int parseData(NLPacket& packet) { return 0; } + virtual int parseData(ReceivedMessage& message) { return 0; } QMutex& getMutex() { return _mutex; } diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index b262904c63..00d6a503a7 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -121,16 +121,16 @@ qint64 NodeList::sendStatsToDomainServer(const QJsonObject& statsObject) { return sendStats(statsObject, _domainHandler.getSockAddr()); } -void NodeList::timePingReply(QSharedPointer packet, const SharedNodePointer& sendingNode) { +void NodeList::timePingReply(ReceivedMessage& message, const SharedNodePointer& sendingNode) { PingType_t pingType; quint64 ourOriginalTime, othersReplyTime; - packet->seek(0); + message.seek(0); - packet->readPrimitive(&pingType); - packet->readPrimitive(&ourOriginalTime); - packet->readPrimitive(&othersReplyTime); + message.readPrimitive(&pingType); + message.readPrimitive(&ourOriginalTime); + message.readPrimitive(&othersReplyTime); quint64 now = usecTimestampNow(); int pingTime = now - ourOriginalTime; @@ -159,11 +159,11 @@ void NodeList::timePingReply(QSharedPointer packet, const SharedNodePo } } -void NodeList::processPingPacket(QSharedPointer packet, SharedNodePointer sendingNode) { +void NodeList::processPingPacket(QSharedPointer message, SharedNodePointer sendingNode) { // send back a reply - auto replyPacket = constructPingReplyPacket(*packet); - const HifiSockAddr& senderSockAddr = packet->getSenderSockAddr(); + auto replyPacket = constructPingReplyPacket(*message); + const HifiSockAddr& senderSockAddr = message->getSenderSockAddr(); sendPacket(std::move(replyPacket), *sendingNode, senderSockAddr); // If we don't have a symmetric socket for this node and this socket doesn't match @@ -176,18 +176,18 @@ void NodeList::processPingPacket(QSharedPointer packet, SharedNodePoin } } -void NodeList::processPingReplyPacket(QSharedPointer packet, SharedNodePointer sendingNode) { +void NodeList::processPingReplyPacket(QSharedPointer message, SharedNodePointer sendingNode) { // activate the appropriate socket for this node, if not yet updated - activateSocketFromNodeCommunication(packet, sendingNode); + activateSocketFromNodeCommunication(*message, sendingNode); // set the ping time for this node for stat collection - timePingReply(packet, sendingNode); + timePingReply(*message, sendingNode); } -void NodeList::processICEPingPacket(QSharedPointer packet) { +void NodeList::processICEPingPacket(QSharedPointer message) { // send back a reply - auto replyPacket = constructICEPingReplyPacket(*packet, _domainHandler.getICEClientID()); - sendPacket(std::move(replyPacket), packet->getSenderSockAddr()); + auto replyPacket = constructICEPingReplyPacket(*message, _domainHandler.getICEClientID()); + sendPacket(std::move(replyPacket), message->getSenderSockAddr()); } void NodeList::reset() { @@ -364,34 +364,34 @@ void NodeList::sendDSPathQuery(const QString& newPath) { } } -void NodeList::processDomainServerPathResponse(QSharedPointer packet) { +void NodeList::processDomainServerPathResponse(QSharedPointer message) { // This is a response to a path query we theoretically made. // In the future we may want to check that this was actually from our DS and for a query we actually made. // figure out how many bytes the path query is quint16 numPathBytes; - packet->readPrimitive(&numPathBytes); + message->readPrimitive(&numPathBytes); // pull the path from the packet - if (packet->bytesLeftToRead() < numPathBytes) { + if (message->getBytesLeftToRead() < numPathBytes) { qCDebug(networking) << "Could not read query path from DomainServerPathQueryResponse. Bailing."; return; } - QString pathQuery = QString::fromUtf8(packet->getPayload() + packet->pos(), numPathBytes); - packet->seek(packet->pos() + numPathBytes); + QString pathQuery = QString::fromUtf8(message->getPayload() + message->pos(), numPathBytes); + message->seek(message->pos() + numPathBytes); // figure out how many bytes the viewpoint is quint16 numViewpointBytes; - packet->readPrimitive(&numViewpointBytes); + message->readPrimitive(&numViewpointBytes); - if (packet->bytesLeftToRead() < numViewpointBytes) { + if (message->getBytesLeftToRead() < numViewpointBytes) { qCDebug(networking) << "Could not read resulting viewpoint from DomainServerPathQueryReponse. Bailing"; return; } // pull the viewpoint from the packet - QString viewpoint = QString::fromUtf8(packet->getPayload() + packet->pos(), numViewpointBytes); + QString viewpoint = QString::fromUtf8(message->getPayload() + message->pos(), numViewpointBytes); // Hand it off to the AddressManager so it can handle it as a relative viewpoint if (DependencyManager::get()->goToViewpointForPath(viewpoint, pathQuery)) { @@ -453,17 +453,17 @@ void NodeList::pingPunchForDomainServer() { } } -void NodeList::processDomainServerConnectionTokenPacket(QSharedPointer packet) { +void NodeList::processDomainServerConnectionTokenPacket(QSharedPointer message) { if (_domainHandler.getSockAddr().isNull()) { // refuse to process this packet if we aren't currently connected to the DS return; } // read in the connection token from the packet, then send domain-server checkin - _domainHandler.setConnectionToken(QUuid::fromRfc4122(packet->readWithoutCopy(NUM_BYTES_RFC4122_UUID))); + _domainHandler.setConnectionToken(QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID))); sendDomainServerCheckIn(); } -void NodeList::processDomainServerList(QSharedPointer packet) { +void NodeList::processDomainServerList(QSharedPointer message) { if (_domainHandler.getSockAddr().isNull()) { // refuse to process this packet if we aren't currently connected to the DS return; @@ -474,7 +474,7 @@ void NodeList::processDomainServerList(QSharedPointer packet) { DependencyManager::get()->flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::ReceiveDSList); - QDataStream packetStream(packet.data()); + QDataStream packetStream(message->getMessage()); // grab the domain's ID from the beginning of the packet QUuid domainUUID; @@ -500,14 +500,14 @@ void NodeList::processDomainServerList(QSharedPointer packet) { setThisNodeCanRez((bool) thisNodeCanRez); // pull each node in the packet - while (packetStream.device()->pos() < packet->getPayloadSize()) { + while (packetStream.device()->pos() < message->getPayloadSize()) { parseNodeFromPacketStream(packetStream); } } -void NodeList::processDomainServerAddedNode(QSharedPointer packet) { +void NodeList::processDomainServerAddedNode(QSharedPointer message) { // setup a QDataStream - QDataStream packetStream(packet.data()); + QDataStream packetStream(message->getMessage()); // use our shared method to pull out the new node parseNodeFromPacketStream(packetStream); @@ -599,9 +599,9 @@ void NodeList::handleNodePingTimeout() { } } -void NodeList::activateSocketFromNodeCommunication(QSharedPointer packet, const SharedNodePointer& sendingNode) { +void NodeList::activateSocketFromNodeCommunication(ReceivedMessage& message, const SharedNodePointer& sendingNode) { // deconstruct this ping packet to see if it is a public or local reply - QDataStream packetStream(packet.data()); + QDataStream packetStream(message.getMessage()); quint8 pingType; packetStream >> pingType; diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 3aae3e3dfc..a517c79d29 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -39,6 +39,7 @@ const int MAX_SILENT_DOMAIN_SERVER_CHECK_INS = 5; using NodePacketPair = std::pair>; using NodeSharedPacketPair = std::pair>; +using NodeSharedReceivedMessagePair = std::pair>; class Application; class Assignment; @@ -62,8 +63,6 @@ public: void addSetOfNodeTypesToNodeInterestSet(const NodeSet& setOfNodeTypes); void resetNodeInterestSet() { _nodeTypesOfInterest.clear(); } - void processReceivedPacket(std::unique_ptr, HifiSockAddr senderSockAddr); - void setAssignmentServerSocket(const HifiSockAddr& serverSocket) { _assignmentServerSocket = serverSocket; } void sendAssignment(Assignment& assignment); @@ -72,16 +71,16 @@ public slots: void sendDomainServerCheckIn(); void handleDSPathQuery(const QString& newPath); - void processDomainServerList(QSharedPointer packet); - void processDomainServerAddedNode(QSharedPointer packet); - void processDomainServerPathResponse(QSharedPointer packet); + void processDomainServerList(QSharedPointer message); + void processDomainServerAddedNode(QSharedPointer message); + void processDomainServerPathResponse(QSharedPointer message); - void processDomainServerConnectionTokenPacket(QSharedPointer packet); + void processDomainServerConnectionTokenPacket(QSharedPointer message); - void processPingPacket(QSharedPointer packet, SharedNodePointer sendingNode); - void processPingReplyPacket(QSharedPointer packet, SharedNodePointer sendingNode); + void processPingPacket(QSharedPointer message, SharedNodePointer sendingNode); + void processPingReplyPacket(QSharedPointer message, SharedNodePointer sendingNode); - void processICEPingPacket(QSharedPointer packet); + void processICEPingPacket(QSharedPointer message); signals: void limitOfSilentDomainCheckInsReached(); private slots: @@ -100,8 +99,8 @@ private: void processDomainServerAuthRequest(const QByteArray& packet); void requestAuthForDomainServer(); - void activateSocketFromNodeCommunication(QSharedPointer packet, const SharedNodePointer& sendingNode); - void timePingReply(QSharedPointer packet, const SharedNodePointer& sendingNode); + void activateSocketFromNodeCommunication(ReceivedMessage& message, const SharedNodePointer& sendingNode); + void timePingReply(ReceivedMessage& message, const SharedNodePointer& sendingNode); void sendDSPathQuery(const QString& newPath); diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 9d25724f6c..a95ba12047 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -19,10 +19,10 @@ #include "NodeList.h" #include "SharedUtil.h" -Q_DECLARE_METATYPE(QSharedPointer); PacketReceiver::PacketReceiver(QObject* parent) : QObject(parent) { qRegisterMetaType>(); qRegisterMetaType>(); + qRegisterMetaType>(); } bool PacketReceiver::registerListenerForTypes(PacketTypeList types, QObject* listener, const char* slot) { @@ -94,22 +94,24 @@ void PacketReceiver::registerDirectListenerForTypes(PacketTypeList types, } } -bool PacketReceiver::registerMessageListener(PacketType type, QObject* listener, const char* slot) { +bool PacketReceiver::registerMessageListener(PacketType type, QObject* listener, const char* slot, + bool deliverPending) { Q_ASSERT_X(listener, "PacketReceiver::registerMessageListener", "No object to register"); Q_ASSERT_X(slot, "PacketReceiver::registerMessageListener", "No slot to register"); - + QMetaMethod matchingMethod = matchingMethodForListener(type, listener, slot); if (matchingMethod.isValid()) { QMutexLocker locker(&_packetListenerLock); - if (_packetListListenerMap.contains(type)) { + if (_messageListenerMap.contains(type)) { qCWarning(networking) << "Registering a packet listener for packet type" << type << "that will remove a previously registered listener"; } // add the mapping - _packetListListenerMap[type] = ObjectMethodPair(QPointer(listener), matchingMethod); + _messageListenerMap[type] = { QPointer(listener), matchingMethod, deliverPending }; + return true; } else { return false; @@ -123,6 +125,7 @@ bool PacketReceiver::registerListener(PacketType type, QObject* listener, const QMetaMethod matchingMethod = matchingMethodForListener(type, listener, slot); if (matchingMethod.isValid()) { + qDebug() << "Found: " << matchingMethod.methodSignature(); registerVerifiedListener(type, listener, matchingMethod); return true; } else { @@ -137,25 +140,25 @@ QMetaMethod PacketReceiver::matchingMethodForListener(PacketType type, QObject* // normalize the slot with the expected parameters static const QString SIGNATURE_TEMPLATE("%1(%2)"); - static const QString NON_SOURCED_PACKET_LISTENER_PARAMETERS = "QSharedPointer"; - static const QString NON_SOURCED_PACKETLIST_LISTENER_PARAMETERS = "QSharedPointer"; + // static const QString NON_SOURCED_PACKET_LISTENER_PARAMETERS = "QSharedPointer"; + static const QString NON_SOURCED_PACKETLIST_LISTENER_PARAMETERS = "QSharedPointer"; QSet possibleSignatures { - SIGNATURE_TEMPLATE.arg(slot, NON_SOURCED_PACKET_LISTENER_PARAMETERS), + // SIGNATURE_TEMPLATE.arg(slot, NON_SOURCED_PACKET_LISTENER_PARAMETERS), SIGNATURE_TEMPLATE.arg(slot, NON_SOURCED_PACKETLIST_LISTENER_PARAMETERS) }; if (!NON_SOURCED_PACKETS.contains(type)) { - static const QString SOURCED_PACKET_LISTENER_PARAMETERS = "QSharedPointer,QSharedPointer"; - static const QString TYPEDEF_SOURCED_PACKET_LISTENER_PARAMETERS = "QSharedPointer,SharedNodePointer"; - static const QString SOURCED_PACKETLIST_LISTENER_PARAMETERS = "QSharedPointer,QSharedPointer"; - static const QString TYPEDEF_SOURCED_PACKETLIST_LISTENER_PARAMETERS = "QSharedPointer,SharedNodePointer"; + // static const QString SOURCED_PACKET_LISTENER_PARAMETERS = "QSharedPointer,QSharedPointer"; + // static const QString TYPEDEF_SOURCED_PACKET_LISTENER_PARAMETERS = "QSharedPointer,SharedNodePointer"; + static const QString SOURCED_PACKETLIST_LISTENER_PARAMETERS = "QSharedPointer,QSharedPointer"; + static const QString TYPEDEF_SOURCED_PACKETLIST_LISTENER_PARAMETERS = "QSharedPointer,SharedNodePointer"; // a sourced packet must take the shared pointer to the packet but optionally could include // a shared pointer to the node - possibleSignatures << SIGNATURE_TEMPLATE.arg(slot, TYPEDEF_SOURCED_PACKET_LISTENER_PARAMETERS); - possibleSignatures << SIGNATURE_TEMPLATE.arg(slot, SOURCED_PACKET_LISTENER_PARAMETERS); + // possibleSignatures << SIGNATURE_TEMPLATE.arg(slot, TYPEDEF_SOURCED_PACKET_LISTENER_PARAMETERS); + // possibleSignatures << SIGNATURE_TEMPLATE.arg(slot, SOURCED_PACKET_LISTENER_PARAMETERS); possibleSignatures << SIGNATURE_TEMPLATE.arg(slot, TYPEDEF_SOURCED_PACKETLIST_LISTENER_PARAMETERS); possibleSignatures << SIGNATURE_TEMPLATE.arg(slot, SOURCED_PACKETLIST_LISTENER_PARAMETERS); } @@ -196,13 +199,13 @@ void PacketReceiver::registerVerifiedListener(PacketType type, QObject* object, Q_ASSERT_X(object, "PacketReceiver::registerVerifiedListener", "No object to register"); QMutexLocker locker(&_packetListenerLock); - if (_packetListenerMap.contains(type)) { + if (_messageListenerMap.contains(type)) { qCWarning(networking) << "Registering a packet listener for packet type" << type << "that will remove a previously registered listener"; } // add the mapping - _packetListenerMap[type] = ObjectMethodPair(QPointer(object), slot); + _messageListenerMap[type] = { QPointer(object), slot, false }; } void PacketReceiver::unregisterListener(QObject* listener) { @@ -213,33 +216,63 @@ void PacketReceiver::unregisterListener(QObject* listener) { // TODO: replace the two while loops below with a replace_if on the vector (once we move to Message everywhere) - // clear any registrations for this listener in _packetListenerMap - auto it = _packetListenerMap.begin(); + // clear any registrations for this listener in _messageListenerMap + auto it = _messageListenerMap.begin(); - while (it != _packetListenerMap.end()) { - if (it.value().first == listener) { - it = _packetListenerMap.erase(it); + while (it != _messageListenerMap.end()) { + if (it.value().object == listener) { + it = _messageListenerMap.erase(it); } else { ++it; } } - - // clear any registrations for this listener in _packetListListener - auto listIt = _packetListListenerMap.begin(); - - while (listIt != _packetListListenerMap.end()) { - if (listIt.value().first == listener) { - listIt = _packetListListenerMap.erase(listIt); - } else { - ++listIt; - } - } } QMutexLocker directConnectSetLocker(&_directConnectSetMutex); _directlyConnectedObjects.remove(listener); } +void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { + // if we're supposed to drop this packet then break out here + if (_shouldDropPackets) { + return; + } + + auto nodeList = DependencyManager::get(); + + // setup an NLPacket from the packet we were passed + auto nlPacket = NLPacket::fromBase(std::move(packet)); + auto receivedMessage = QSharedPointer(new ReceivedMessage(*nlPacket.get())); + + handleVerifiedMessage(receivedMessage, true); +} + +void PacketReceiver::handleVerifiedMessagePacket(std::unique_ptr packet) { + qDebug() << "Got message packet"; + auto nlPacket = NLPacket::fromBase(std::move(packet)); + _inPacketCount += 1; + _inByteCount += nlPacket->size(); + auto key = std::pair(nlPacket->getSenderSockAddr(), nlPacket->getMessageNumber()); + auto it = _pendingMessages.find(key); + QSharedPointer message; + if (it == _pendingMessages.end()) { + // Create message + message = QSharedPointer(new ReceivedMessage(*nlPacket.release())); + if (!message->isComplete()) { + _pendingMessages[key] = message; + } + handleVerifiedMessage(message, true); + } else { + message = it->second; + message->appendPacket(std::move(nlPacket)); + + if (message->isComplete()) { + _pendingMessages.erase(it); + handleVerifiedMessage(message, false); + } + } +} + void PacketReceiver::handleVerifiedPacketList(std::unique_ptr packetList) { // if we're supposed to drop this packet then break out here if (_shouldDropPackets) { @@ -248,82 +281,95 @@ void PacketReceiver::handleVerifiedPacketList(std::unique_ptr p // setup an NLPacketList from the PacketList we were passed auto nlPacketList = NLPacketList::fromPacketList(std::move(packetList)); + auto receivedMessage = QSharedPointer(new ReceivedMessage(*nlPacketList.release())); + + handleVerifiedMessage(receivedMessage, true); +} + +void PacketReceiver::handleVerifiedMessage(QSharedPointer receivedMessage, bool justReceived) { auto nodeList = DependencyManager::get(); - _inPacketCount += nlPacketList->getNumPackets(); - _inByteCount += nlPacketList->getDataSize(); + _inPacketCount += receivedMessage->getNumPackets(); + _inByteCount += receivedMessage->size(); SharedNodePointer matchingNode; - if (!nlPacketList->getSourceID().isNull()) { - matchingNode = nodeList->nodeWithUUID(nlPacketList->getSourceID()); + if (!receivedMessage->getSourceID().isNull()) { + matchingNode = nodeList->nodeWithUUID(receivedMessage->getSourceID()); } QMutexLocker packetListenerLocker(&_packetListenerLock); bool listenerIsDead = false; - auto it = _packetListListenerMap.find(nlPacketList->getType()); - - if (it != _packetListListenerMap.end() && it->second.isValid()) { - + auto it = _messageListenerMap.find(receivedMessage->getType()); + + if (it != _messageListenerMap.end() && it->method.isValid()) { + auto listener = it.value(); - - if (listener.first) { + + if ((listener.deliverPending && !justReceived) || (!listener.deliverPending && !receivedMessage->isComplete())) { + return; + } + + if (listener.object) { bool success = false; - + Qt::ConnectionType connectionType; // check if this is a directly connected listener { QMutexLocker directConnectLocker(&_directConnectSetMutex); - connectionType = _directlyConnectedObjects.contains(listener.first) ? Qt::DirectConnection : Qt::AutoConnection; + connectionType = _directlyConnectedObjects.contains(listener.object) ? Qt::DirectConnection : Qt::AutoConnection; } - PacketType packetType = nlPacketList->getType(); + PacketType packetType = receivedMessage->getType(); if (matchingNode) { - emit dataReceived(matchingNode->getType(), nlPacketList->getDataSize()); - QMetaMethod metaMethod = listener.second; + emit dataReceived(matchingNode->getType(), receivedMessage->size()); + matchingNode->recordBytesReceived(receivedMessage->size()); + Node* n = matchingNode.data(); + auto addr = n->getActiveSocket(); + + QMetaMethod metaMethod = listener.method; + + // qDebug() << "Got verified packet list: " << QString(receivedMessage->getMessage()); static const QByteArray QSHAREDPOINTER_NODE_NORMALIZED = QMetaObject::normalizedType("QSharedPointer"); static const QByteArray SHARED_NODE_NORMALIZED = QMetaObject::normalizedType("SharedNodePointer"); // one final check on the QPointer before we go to invoke - if (listener.first) { + if (listener.object) { if (metaMethod.parameterTypes().contains(SHARED_NODE_NORMALIZED)) { - success = metaMethod.invoke(listener.first, + success = metaMethod.invoke(listener.object, connectionType, - Q_ARG(QSharedPointer, - QSharedPointer(nlPacketList.release())), + Q_ARG(QSharedPointer, receivedMessage), Q_ARG(SharedNodePointer, matchingNode)); } else if (metaMethod.parameterTypes().contains(QSHAREDPOINTER_NODE_NORMALIZED)) { - success = metaMethod.invoke(listener.first, + success = metaMethod.invoke(listener.object, connectionType, - Q_ARG(QSharedPointer, - QSharedPointer(nlPacketList.release())), + Q_ARG(QSharedPointer, receivedMessage), Q_ARG(QSharedPointer, matchingNode)); } else { - success = metaMethod.invoke(listener.first, + success = metaMethod.invoke(listener.object, connectionType, - Q_ARG(QSharedPointer, - QSharedPointer(nlPacketList.release()))); + Q_ARG(QSharedPointer, receivedMessage)); } } else { listenerIsDead = true; } } else { - emit dataReceived(NodeType::Unassigned, nlPacketList->getDataSize()); + // qDebug() << "Got verified unsourced packet list: " << QString(nlPacketList->getMessage()); + emit dataReceived(NodeType::Unassigned, receivedMessage->size()); // one final check on the QPointer before we invoke - if (listener.first) { - success = listener.second.invoke(listener.first, - Q_ARG(QSharedPointer, - QSharedPointer(nlPacketList.release()))); + if (listener.object) { + success = listener.method.invoke(listener.object, + Q_ARG(QSharedPointer, receivedMessage)); } else { listenerIsDead = true; } @@ -332,7 +378,7 @@ void PacketReceiver::handleVerifiedPacketList(std::unique_ptr p if (!success) { qCDebug(networking).nospace() << "Error delivering packet " << packetType << " to listener " - << listener.first << "::" << qPrintable(listener.second.methodSignature()); + << listener.object << "::" << qPrintable(listener.method.methodSignature()); } } else { @@ -340,139 +386,21 @@ void PacketReceiver::handleVerifiedPacketList(std::unique_ptr p } if (listenerIsDead) { - qCDebug(networking).nospace() << "Listener for packet " << nlPacketList->getType() + qCDebug(networking).nospace() << "Listener for packet " << receivedMessage->getType() << " has been destroyed. Removing from listener map."; - it = _packetListListenerMap.erase(it); + it = _messageListenerMap.erase(it); // if it exists, remove the listener from _directlyConnectedObjects { QMutexLocker directConnectLocker(&_directConnectSetMutex); - _directlyConnectedObjects.remove(listener.first); + _directlyConnectedObjects.remove(listener.object); } } - } else if (it == _packetListListenerMap.end()) { - qCWarning(networking) << "No listener found for packet type" << nlPacketList->getType(); + } else if (it == _messageListenerMap.end()) { + qCWarning(networking) << "No listener found for packet type" << receivedMessage->getType(); // insert a dummy listener so we don't print this again - _packetListListenerMap.insert(nlPacketList->getType(), { nullptr, QMetaMethod() }); - } -} - -void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { - - // if we're supposed to drop this packet then break out here - if (_shouldDropPackets) { - return; - } - - auto nodeList = DependencyManager::get(); - - // setup an NLPacket from the packet we were passed - auto nlPacket = NLPacket::fromBase(std::move(packet)); - - _inPacketCount++; - _inByteCount += nlPacket->getDataSize(); - - SharedNodePointer matchingNode; - - if (!nlPacket->getSourceID().isNull()) { - matchingNode = nodeList->nodeWithUUID(nlPacket->getSourceID()); - } - - QMutexLocker packetListenerLocker(&_packetListenerLock); - - bool listenerIsDead = false; - - auto it = _packetListenerMap.find(nlPacket->getType()); - - if (it != _packetListenerMap.end() && it->second.isValid()) { - - auto listener = it.value(); - - if (listener.first) { - - bool success = false; - - // check if this is a directly connected listener - QMutexLocker directConnectSetLocker(&_directConnectSetMutex); - Qt::ConnectionType connectionType = - _directlyConnectedObjects.contains(listener.first) ? Qt::DirectConnection : Qt::AutoConnection; - directConnectSetLocker.unlock(); - - PacketType packetType = nlPacket->getType(); - - if (matchingNode) { - emit dataReceived(matchingNode->getType(), nlPacket->getDataSize()); - matchingNode->recordBytesReceived(nlPacket->getDataSize()); - - QMetaMethod metaMethod = listener.second; - - static const QByteArray QSHAREDPOINTER_NODE_NORMALIZED = QMetaObject::normalizedType("QSharedPointer"); - static const QByteArray SHARED_NODE_NORMALIZED = QMetaObject::normalizedType("SharedNodePointer"); - - // one final check on the QPointer before we go to invoke - if (listener.first) { - if (metaMethod.parameterTypes().contains(SHARED_NODE_NORMALIZED)) { - success = metaMethod.invoke(listener.first, - connectionType, - Q_ARG(QSharedPointer, - QSharedPointer(nlPacket.release())), - Q_ARG(SharedNodePointer, matchingNode)); - - } else if (metaMethod.parameterTypes().contains(QSHAREDPOINTER_NODE_NORMALIZED)) { - success = metaMethod.invoke(listener.first, - connectionType, - Q_ARG(QSharedPointer, - QSharedPointer(nlPacket.release())), - Q_ARG(QSharedPointer, matchingNode)); - - } else { - success = metaMethod.invoke(listener.first, - connectionType, - Q_ARG(QSharedPointer, - QSharedPointer(nlPacket.release()))); - } - } else { - listenerIsDead = true; - } - } else { - emit dataReceived(NodeType::Unassigned, nlPacket->getDataSize()); - - // one final check on the QPointer before we invoke - if (listener.first) { - success = listener.second.invoke(listener.first, - Q_ARG(QSharedPointer, - QSharedPointer(nlPacket.release()))); - } else { - listenerIsDead = true; - } - - } - - if (!success) { - qCDebug(networking).nospace() << "Error delivering packet " << packetType << " to listener " - << listener.first << "::" << qPrintable(listener.second.methodSignature()); - } - - } else { - listenerIsDead = true; - } - - if (listenerIsDead) { - qCDebug(networking).nospace() << "Listener for packet " << nlPacket->getType() - << " has been destroyed. Removing from listener map."; - it = _packetListenerMap.erase(it); - - // if it exists, remove the listener from _directlyConnectedObjects - QMutexLocker locker(&_directConnectSetMutex); - _directlyConnectedObjects.remove(listener.first); - } - - } else if (it == _packetListenerMap.end()) { - qCWarning(networking) << "No listener found for packet type" << nlPacket->getType(); - - // insert a dummy listener so we don't print this again - _packetListenerMap.insert(nlPacket->getType(), { nullptr, QMetaMethod() }); + _messageListenerMap.insert(receivedMessage->getType(), { nullptr, QMetaMethod(), false }); } } diff --git a/libraries/networking/src/PacketReceiver.h b/libraries/networking/src/PacketReceiver.h index 1c6f9e73d2..b27abdc084 100644 --- a/libraries/networking/src/PacketReceiver.h +++ b/libraries/networking/src/PacketReceiver.h @@ -14,6 +14,7 @@ #define hifi_PacketReceiver_h #include +#include #include #include @@ -24,11 +25,21 @@ #include "NLPacket.h" #include "NLPacketList.h" +#include "ReceivedMessage.h" #include "udt/PacketHeaders.h" class EntityEditPacketSender; class OctreePacketProcessor; +namespace std { + template <> + struct hash> { + size_t operator()(const std::pair& pair) const { + return hash()(pair.first) ^ hash()(pair.second); + } + }; +} + class PacketReceiver : public QObject { Q_OBJECT public: @@ -47,17 +58,26 @@ public: void resetCounters() { _inPacketCount = 0; _inByteCount = 0; } bool registerListenerForTypes(PacketTypeList types, QObject* listener, const char* slot); - bool registerMessageListener(PacketType type, QObject* listener, const char* slot); + bool registerMessageListener(PacketType type, QObject* listener, const char* slot, bool deliverPending = false); bool registerListener(PacketType type, QObject* listener, const char* slot); void unregisterListener(QObject* listener); void handleVerifiedPacket(std::unique_ptr packet); void handleVerifiedPacketList(std::unique_ptr packetList); + void handleVerifiedMessage(QSharedPointer message, bool justReceived); + + void handleVerifiedMessagePacket(std::unique_ptr message); signals: void dataReceived(quint8 channelType, int bytes); private: + struct Listener { + QPointer object; + QMetaMethod method; + bool deliverPending; + }; + // these are brutal hacks for now - ideally GenericThread / ReceivedPacketProcessor // should be changed to have a true event loop and be able to handle our QMetaMethod::invoke void registerDirectListenerForTypes(PacketTypeList types, QObject* listener, const char* slot); @@ -65,18 +85,18 @@ private: QMetaMethod matchingMethodForListener(PacketType type, QObject* object, const char* slot) const; void registerVerifiedListener(PacketType type, QObject* listener, const QMetaMethod& slot); - - using ObjectMethodPair = std::pair, QMetaMethod>; QMutex _packetListenerLock; // TODO: replace the two following hashes with an std::vector once we switch Packet/PacketList to Message - QHash _packetListenerMap; - QHash _packetListListenerMap; + // QHash _packetListenerMap; + QHash _messageListenerMap; int _inPacketCount = 0; int _inByteCount = 0; bool _shouldDropPackets = false; QMutex _directConnectSetMutex; QSet _directlyConnectedObjects; + + std::unordered_map, QSharedPointer> _pendingMessages; friend class EntityEditPacketSender; friend class OctreePacketProcessor; diff --git a/libraries/networking/src/ReceivedMessage.cpp b/libraries/networking/src/ReceivedMessage.cpp new file mode 100644 index 0000000000..c9140d87a9 --- /dev/null +++ b/libraries/networking/src/ReceivedMessage.cpp @@ -0,0 +1,86 @@ +// +// ReceivedMessage.cpp +// libraries/networking/src +// +// Created by Ryan Huffman on 2015/09/17 +// 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 "ReceivedMessage.h" + +#include "QSharedPointer" + +static int receivedMessageMetaTypeId = qRegisterMetaType("ReceivedMessage*"); +static int sharedPtrReceivedMessageMetaTypeId = qRegisterMetaType>("QSharedPointer"); + +ReceivedMessage::ReceivedMessage(const NLPacketList& packetList) + : _data(packetList.getMessage()), + _sourceID(packetList.getSourceID()), + _numPackets(packetList.getNumPackets()), + _packetType(packetList.getType()), + _packetVersion(packetList.getVersion()), + _senderSockAddr(packetList.getSenderSockAddr()) +{ +} + +ReceivedMessage::ReceivedMessage(NLPacket& packet) + : _data(packet.readAll()), + _sourceID(packet.getSourceID()), + _numPackets(1), + _packetType(packet.getType()), + _packetVersion(packet.getVersion()), + _senderSockAddr(packet.getSenderSockAddr()), + _isComplete(packet.getPacketPosition() == NLPacket::ONLY) +{ +} + +void ReceivedMessage::appendPacket(std::unique_ptr packet) { + ++_numPackets; + + _data.append(packet->getPayload(), packet->getPayloadSize()); + emit progress(this); + if (packet->getPacketPosition() == NLPacket::PacketPosition::LAST) { + _isComplete = true; + emit completed(this); + } +} + +qint64 ReceivedMessage::peek(char* data, qint64 size) { + memcpy(data, _data.constData() + _position, size); + return size; +} + +qint64 ReceivedMessage::read(char* data, qint64 size) { + memcpy(data, _data.constData() + _position, size); + _position += size; + return size; +} + +QByteArray ReceivedMessage::peek(qint64 size) { + return _data.mid(_position, size); +} + +QByteArray ReceivedMessage::read(qint64 size) { + auto data = _data.mid(_position, size); + _position += size; + return data; +} + +QByteArray ReceivedMessage::readAll() { + return read(getBytesLeftToRead()); +} + +QByteArray ReceivedMessage::readWithoutCopy(qint64 size) { + QByteArray data { QByteArray::fromRawData(_data.constData() + _position, size) }; + _position += size; + return data; +} + +void ReceivedMessage::onComplete() { + _isComplete = true; + emit completed(this); +} diff --git a/libraries/networking/src/ReceivedMessage.h b/libraries/networking/src/ReceivedMessage.h new file mode 100644 index 0000000000..bd92205d5a --- /dev/null +++ b/libraries/networking/src/ReceivedMessage.h @@ -0,0 +1,102 @@ +// +// ReceivedMessage.h +// libraries/networking/src +// +// Created by Ryan Huffman on 2015/09/15 +// 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_ReceivedMessage_h +#define hifi_ReceivedMessage_h + +#include +#include + +#include +#include + +#include "NLPacketList.h" + +class ReceivedMessage : public QObject { + Q_OBJECT +public: + ReceivedMessage(const NLPacketList& packetList); + ReceivedMessage(NLPacket& packet); + + const char* getPayload() const { return _data.constData(); } + QByteArray getMessage() const { return _data; } + PacketType getType() const { return _packetType; } + PacketVersion getVersion() const { return _packetVersion; } + + void appendPacket(std::unique_ptr packet); + + bool isComplete() const { return _isComplete; } + + const QUuid& getSourceID() const { return _sourceID; } + const HifiSockAddr& getSenderSockAddr() { return _senderSockAddr; } + + void seek(qint64 position) { _position = position; } + qint64 pos() const { return _position; } + qint64 size() const { return _data.size(); } + + // Get the number of packets that were used to send this message + qint64 getNumPackets() const { return _numPackets; } + + qint64 getDataSize() const { return _data.size(); } + qint64 getPayloadSize() const { return _data.size(); } + + qint64 getBytesLeftToRead() const { return _data.size() - _position; } + + qint64 peek(char* data, qint64 size); + qint64 read(char* data, qint64 size); + + QByteArray peek(qint64 size); + QByteArray read(qint64 size); + QByteArray readAll(); + + // This will return a QByteArray referencing the underlying data _without_ refcounting that data. + // Be careful when using this method, only use it when the lifetime of the returned QByteArray will not + // exceed that of the ReceivedMessage. + QByteArray readWithoutCopy(qint64 size); + + template qint64 peekPrimitive(T* data); + template qint64 readPrimitive(T* data); + +signals: + void progress(ReceivedMessage*); + void completed(ReceivedMessage*); + +private slots: + void onComplete(); + +private: + QByteArray _data; + QUuid _sourceID; + qint64 _numPackets; + PacketType _packetType; + PacketVersion _packetVersion; + qint64 _position { 0 }; + HifiSockAddr _senderSockAddr; + + // Total size of message, including UDT headers. Does not include UDP headers. + qint64 _totalDataSize; + + std::atomic _isComplete { true }; +}; + +Q_DECLARE_METATYPE(ReceivedMessage*) +Q_DECLARE_METATYPE(QSharedPointer) + +template qint64 ReceivedMessage::peekPrimitive(T* data) { + return peek(reinterpret_cast(data), sizeof(T)); +} + +template qint64 ReceivedMessage::readPrimitive(T* data) { + return read(reinterpret_cast(data), sizeof(T)); +} + +#endif diff --git a/libraries/networking/src/ReceivedPacketProcessor.cpp b/libraries/networking/src/ReceivedPacketProcessor.cpp index cc516bdbbd..762b51126c 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.cpp +++ b/libraries/networking/src/ReceivedPacketProcessor.cpp @@ -24,9 +24,9 @@ void ReceivedPacketProcessor::terminating() { _hasPackets.wakeAll(); } -void ReceivedPacketProcessor::queueReceivedPacket(QSharedPointer packet, SharedNodePointer sendingNode) { +void ReceivedPacketProcessor::queueReceivedPacket(QSharedPointer message, SharedNodePointer sendingNode) { lock(); - _packets.push_back({ sendingNode, packet }); + _packets.push_back({ sendingNode, message }); _nodePacketCounts[sendingNode->getUUID()]++; _lastWindowIncomingPackets++; unlock(); @@ -66,7 +66,7 @@ bool ReceivedPacketProcessor::process() { } lock(); - std::list currentPackets; + std::list currentPackets; currentPackets.swap(_packets); unlock(); diff --git a/libraries/networking/src/ReceivedPacketProcessor.h b/libraries/networking/src/ReceivedPacketProcessor.h index db75c9c4d1..3a0e93ee09 100644 --- a/libraries/networking/src/ReceivedPacketProcessor.h +++ b/libraries/networking/src/ReceivedPacketProcessor.h @@ -23,7 +23,7 @@ public: ReceivedPacketProcessor(); /// Add packet from network receive thread to the processing queue. - void queueReceivedPacket(QSharedPointer packet, SharedNodePointer sendingNode); + void queueReceivedPacket(QSharedPointer message, SharedNodePointer sendingNode); /// Are there received packets waiting to be processed bool hasPacketsToProcess() const { return _packets.size() > 0; } @@ -58,7 +58,7 @@ protected: /// Callback for processing of recieved packets. Implement this to process the incoming packets. /// \param SharedNodePointer& sendingNode the node that sent this packet /// \param QByteArray& the packet to be processed - virtual void processPacket(QSharedPointer packet, SharedNodePointer sendingNode) = 0; + virtual void processPacket(QSharedPointer message, SharedNodePointer sendingNode) = 0; /// Implements generic processing behavior for this thread. virtual bool process(); @@ -76,7 +76,7 @@ protected: virtual void postProcess() { } protected: - std::list _packets; + std::list _packets; QHash _nodePacketCounts; QWaitCondition _hasPackets; diff --git a/libraries/networking/src/ThreadedAssignment.cpp b/libraries/networking/src/ThreadedAssignment.cpp index 0422c03297..bed07d86a4 100644 --- a/libraries/networking/src/ThreadedAssignment.cpp +++ b/libraries/networking/src/ThreadedAssignment.cpp @@ -18,8 +18,8 @@ #include "ThreadedAssignment.h" -ThreadedAssignment::ThreadedAssignment(NLPacket& packet) : - Assignment(packet), +ThreadedAssignment::ThreadedAssignment(ReceivedMessage& message) : + Assignment(message), _isFinished(false) { diff --git a/libraries/networking/src/ThreadedAssignment.h b/libraries/networking/src/ThreadedAssignment.h index 9ff3b34add..b20002c21d 100644 --- a/libraries/networking/src/ThreadedAssignment.h +++ b/libraries/networking/src/ThreadedAssignment.h @@ -14,12 +14,14 @@ #include +#include "ReceivedMessage.h" + #include "Assignment.h" class ThreadedAssignment : public Assignment { Q_OBJECT public: - ThreadedAssignment(NLPacket& packet); + ThreadedAssignment(ReceivedMessage& message); ~ThreadedAssignment() { stop(); } void setFinished(bool isFinished); diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 639b2990ec..39d9fb3c0c 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -130,19 +130,17 @@ void Connection::queueReceivedMessagePacket(std::unique_ptr packet) { Q_ASSERT(packet->isPartOfMessage()); auto messageNumber = packet->getMessageNumber(); - PendingReceivedMessage& pendingMessage = _pendingReceivedMessages[messageNumber]; + auto& pendingMessage = _pendingReceivedMessages[messageNumber]; pendingMessage.enqueuePacket(std::move(packet)); - if (pendingMessage.isComplete()) { - // All messages have been received, create PacketList - auto packetList = PacketList::fromReceivedPackets(std::move(pendingMessage._packets)); - - _pendingReceivedMessages.erase(messageNumber); + while (pendingMessage.hasAvailablePackets()) { + auto packet = pendingMessage.removeNextPacket(); + _parentSocket->pendingMessageReceived(std::move(packet)); + } - if (_parentSocket) { - _parentSocket->messageReceived(std::move(packetList)); - } + if (pendingMessage.isComplete()) { + _pendingReceivedMessages.erase(messageNumber); } } @@ -877,3 +875,18 @@ void PendingReceivedMessage::enqueuePacket(std::unique_ptr packet) { _packets.insert(it.base(), std::move(packet)); } + +bool PendingReceivedMessage::hasAvailablePackets() const { + return _packets.size() > 0 + && _nextPartNumber == _packets.front()->getMessagePartNumber(); +} + +std::unique_ptr PendingReceivedMessage::removeNextPacket() { + if (hasAvailablePackets()) { + _nextPartNumber++; + auto p = std::move(_packets.front()); + _packets.pop_front(); + return p; + } + return std::unique_ptr(); +} diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 7f9978c326..d37439b6de 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -38,11 +38,14 @@ class PendingReceivedMessage { public: void enqueuePacket(std::unique_ptr packet); bool isComplete() const { return _hasLastPacket && _numPackets == _packets.size(); } + bool hasAvailablePackets() const; + std::unique_ptr removeNextPacket(); std::list> _packets; private: bool _hasLastPacket { false }; + Packet::MessagePartNumber _nextPartNumber = 0; unsigned int _numPackets { 0 }; }; diff --git a/libraries/networking/src/udt/PacketList.cpp b/libraries/networking/src/udt/PacketList.cpp index 332603a8b9..ca4dd68a6d 100644 --- a/libraries/networking/src/udt/PacketList.cpp +++ b/libraries/networking/src/udt/PacketList.cpp @@ -50,6 +50,10 @@ PacketList::PacketList(PacketList&& other) : { } +HifiSockAddr PacketList::getSenderSockAddr() const { + return _packets.size() > 0 ? _packets.front().get()->getSenderSockAddr() : HifiSockAddr(); +} + void PacketList::startSegment() { _segmentStartIndex = _currentPacket ? _currentPacket->pos() : _extendedHeader.size(); } @@ -117,7 +121,7 @@ void PacketList::closeCurrentPacket(bool shouldSendEmpty) { } } -QByteArray PacketList::getMessage() { +QByteArray PacketList::getMessage() const { size_t sizeBytes = 0; for (const auto& packet : _packets) { diff --git a/libraries/networking/src/udt/PacketList.h b/libraries/networking/src/udt/PacketList.h index a6bee9f5eb..2c6c14f42f 100644 --- a/libraries/networking/src/udt/PacketList.h +++ b/libraries/networking/src/udt/PacketList.h @@ -42,12 +42,14 @@ public: int getNumPackets() const { return _packets.size() + (_currentPacket ? 1 : 0); } size_t getDataSize() const; size_t getMessageSize() const; - QByteArray getMessage(); + QByteArray getMessage() const; QByteArray getExtendedHeader() const { return _extendedHeader; } void startSegment(); void endSegment(); + + HifiSockAddr getSenderSockAddr() const; void closeCurrentPacket(bool shouldSendEmpty = false); diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 6d4a834879..101c251bed 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -20,6 +20,7 @@ #include "ControlPacket.h" #include "Packet.h" #include "../NLPacket.h" +#include "../NLPacketList.h" #include "PacketList.h" using namespace udt; @@ -123,8 +124,9 @@ qint64 Socket::writePacketList(std::unique_ptr packetList, const Hif // because Qt can't invoke with the unique_ptr we have to release it here and re-construct in writeReliablePacketList if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "writeReliablePacketList", Qt::QueuedConnection, - Q_ARG(PacketList*, packetList.release()), + auto ptr = packetList.release(); + QMetaObject::invokeMethod(this, "writeReliablePacketList", Qt::AutoConnection, + Q_ARG(PacketList*, ptr), Q_ARG(HifiSockAddr, sockAddr)); } else { writeReliablePacketList(packetList.release(), sockAddr); @@ -216,6 +218,12 @@ void Socket::messageReceived(std::unique_ptr packetList) { } } +void Socket::pendingMessageReceived(std::unique_ptr packet) { + if (_pendingMessageHandler) { + _pendingMessageHandler(std::move(packet)); + } +} + void Socket::readPendingDatagrams() { int packetSizeWithHeader = -1; while ((packetSizeWithHeader = _udpSocket.pendingDatagramSize()) != -1) { diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 68fcb483b0..1cb729b8c2 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -32,7 +32,6 @@ class UDTTest; namespace udt { class BasePacket; -class ControlSender; class Packet; class PacketList; class SequenceNumber; @@ -42,6 +41,7 @@ using PacketFilterOperator = std::function; using BasePacketHandler = std::function)>; using PacketHandler = std::function)>; using PacketListHandler = std::function)>; +using PendingMessageHandler = std::function)>; class Socket : public QObject { Q_OBJECT @@ -66,6 +66,7 @@ public: void setPacketFilterOperator(PacketFilterOperator filterOperator) { _packetFilterOperator = filterOperator; } void setPacketHandler(PacketHandler handler) { _packetHandler = handler; } void setPacketListHandler(PacketListHandler handler) { _packetListHandler = handler; } + void setPendingMessageHandler(PendingMessageHandler handler) { _pendingMessageHandler = handler; } void addUnfilteredHandler(const HifiSockAddr& senderSockAddr, BasePacketHandler handler) { _unfilteredHandlers[senderSockAddr] = handler; } @@ -73,6 +74,7 @@ public: void setCongestionControlFactory(std::unique_ptr ccFactory); void messageReceived(std::unique_ptr packetList); + void pendingMessageReceived(std::unique_ptr packet); StatsVector sampleStatsForAllConnections(); @@ -101,6 +103,7 @@ private: PacketFilterOperator _packetFilterOperator; PacketHandler _packetHandler; PacketListHandler _packetListHandler; + PendingMessageHandler _pendingMessageHandler; std::unordered_map _unfilteredHandlers; std::unordered_map _unreliableSequenceNumbers; diff --git a/libraries/octree/src/JurisdictionListener.cpp b/libraries/octree/src/JurisdictionListener.cpp index 4979972c8a..dbbd146f4e 100644 --- a/libraries/octree/src/JurisdictionListener.cpp +++ b/libraries/octree/src/JurisdictionListener.cpp @@ -58,11 +58,11 @@ bool JurisdictionListener::queueJurisdictionRequest() { return isStillRunning(); } -void JurisdictionListener::processPacket(QSharedPointer packet, SharedNodePointer sendingNode) { - if (packet->getType() == PacketType::Jurisdiction) { +void JurisdictionListener::processPacket(QSharedPointer message, SharedNodePointer sendingNode) { + if (message->getType() == PacketType::Jurisdiction) { JurisdictionMap map; - map.unpackFromPacket(*packet); - _jurisdictions[packet->getSourceID()] = map; + map.unpackFromPacket(*message); + _jurisdictions[message->getSourceID()] = map; } } diff --git a/libraries/octree/src/JurisdictionListener.h b/libraries/octree/src/JurisdictionListener.h index 02fce896f5..0c713ca27f 100644 --- a/libraries/octree/src/JurisdictionListener.h +++ b/libraries/octree/src/JurisdictionListener.h @@ -47,7 +47,7 @@ public slots: protected: /// Callback for processing of received packets. Will process any queued PacketType::_JURISDICTION and update the /// jurisdiction map member variable - virtual void processPacket(QSharedPointer packet, SharedNodePointer sendingNode); + virtual void processPacket(QSharedPointer messsage, SharedNodePointer sendingNode) override; private: NodeToJurisdictionMap _jurisdictions; diff --git a/libraries/octree/src/JurisdictionMap.cpp b/libraries/octree/src/JurisdictionMap.cpp index 255652a3cc..2b38a98bf6 100644 --- a/libraries/octree/src/JurisdictionMap.cpp +++ b/libraries/octree/src/JurisdictionMap.cpp @@ -298,28 +298,28 @@ std::unique_ptr JurisdictionMap::packIntoPacket() { return packet; } -int JurisdictionMap::unpackFromPacket(NLPacket& packet) { +int JurisdictionMap::unpackFromPacket(ReceivedMessage& message) { clear(); // read the root jurisdiction int bytes = 0; - packet.readPrimitive(&bytes); + message.readPrimitive(&bytes); - if (bytes > 0 && bytes <= packet.bytesLeftToRead()) { + if (bytes > 0 && bytes <= message.getBytesLeftToRead()) { _rootOctalCode = new unsigned char[bytes]; - packet.read(reinterpret_cast(_rootOctalCode), bytes); + message.read(reinterpret_cast(_rootOctalCode), bytes); // if and only if there's a root jurisdiction, also include the end nodes int endNodeCount = 0; - packet.readPrimitive(&endNodeCount); + message.readPrimitive(&endNodeCount); for (int i = 0; i < endNodeCount; i++) { int bytes = 0; - packet.readPrimitive(&bytes); + message.readPrimitive(&bytes); - if (bytes <= packet.bytesLeftToRead()) { + if (bytes <= message.getBytesLeftToRead()) { unsigned char* endNodeCode = new unsigned char[bytes]; - packet.read(reinterpret_cast(endNodeCode), bytes); + message.read(reinterpret_cast(endNodeCode), bytes); // if the endNodeCode was 0 length then don't add it if (bytes > 0) { @@ -329,5 +329,5 @@ int JurisdictionMap::unpackFromPacket(NLPacket& packet) { } } - return packet.pos(); // excludes header + return message.pos(); // excludes header } diff --git a/libraries/octree/src/JurisdictionMap.h b/libraries/octree/src/JurisdictionMap.h index 7cf7ebe6a9..3f415efba8 100644 --- a/libraries/octree/src/JurisdictionMap.h +++ b/libraries/octree/src/JurisdictionMap.h @@ -56,7 +56,7 @@ public: void copyContents(unsigned char* rootCodeIn, const std::vector& endNodesIn); - int unpackFromPacket(NLPacket& packet); + int unpackFromPacket(ReceivedMessage& message); std::unique_ptr packIntoPacket(); /// Available to pack an empty or unknown jurisdiction into a network packet, used when no JurisdictionMap is available diff --git a/libraries/octree/src/JurisdictionSender.cpp b/libraries/octree/src/JurisdictionSender.cpp index e408982eed..ed3d59cebc 100644 --- a/libraries/octree/src/JurisdictionSender.cpp +++ b/libraries/octree/src/JurisdictionSender.cpp @@ -28,8 +28,8 @@ JurisdictionSender::JurisdictionSender(JurisdictionMap* map, NodeType_t type) : JurisdictionSender::~JurisdictionSender() { } -void JurisdictionSender::processPacket(QSharedPointer packet, SharedNodePointer sendingNode) { - if (packet->getType() == PacketType::JurisdictionRequest) { +void JurisdictionSender::processPacket(QSharedPointer message, SharedNodePointer sendingNode) { + if (message->getType() == PacketType::JurisdictionRequest) { lockRequestingNodes(); _nodesRequestingJurisdictions.push(sendingNode->getUUID()); unlockRequestingNodes(); diff --git a/libraries/octree/src/JurisdictionSender.h b/libraries/octree/src/JurisdictionSender.h index dd0ff44a11..a0a3b5b4dd 100644 --- a/libraries/octree/src/JurisdictionSender.h +++ b/libraries/octree/src/JurisdictionSender.h @@ -38,7 +38,7 @@ public: void setNodeType(NodeType_t type) { _nodeType = type; } protected: - virtual void processPacket(QSharedPointer packet, SharedNodePointer sendingNode); + virtual void processPacket(QSharedPointer message, SharedNodePointer sendingNode) override; /// Locks all the resources of the thread. void lockRequestingNodes() { _requestingNodeMutex.lock(); } diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index dececf1456..c9fa615973 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -236,7 +236,7 @@ public: return thisVersion == versionForPacketType(expectedDataPacketType()); } virtual PacketVersion expectedVersion() const { return versionForPacketType(expectedDataPacketType()); } virtual bool handlesEditPacketType(PacketType packetType) const { return false; } - virtual int processEditPacketData(NLPacket& packet, const unsigned char* editData, int maxLength, + virtual int processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength, const SharedNodePointer& sourceNode) { return 0; } virtual bool recurseChildrenWithData() const { return true; } diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index 495effc825..df53a0f873 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -339,7 +339,7 @@ bool OctreeEditPacketSender::process() { return PacketSender::process(); } -void OctreeEditPacketSender::processNackPacket(NLPacket& packet, SharedNodePointer sendingNode) { +void OctreeEditPacketSender::processNackPacket(ReceivedMessage& message, SharedNodePointer sendingNode) { // parse sending node from packet, retrieve packet history for that node // if packet history doesn't exist for the sender node (somehow), bail @@ -350,9 +350,9 @@ void OctreeEditPacketSender::processNackPacket(NLPacket& packet, SharedNodePoint const SentPacketHistory& sentPacketHistory = _sentPacketHistories[sendingNode->getUUID()]; // read sequence numbers and queue packets for resend - while (packet.bytesLeftToRead() > 0) { + while (message.getBytesLeftToRead() > 0) { unsigned short int sequenceNumber; - packet.readPrimitive(&sequenceNumber); + message.readPrimitive(&sequenceNumber); // retrieve packet from history const NLPacket* packet = sentPacketHistory.getPacket(sequenceNumber); diff --git a/libraries/octree/src/OctreeEditPacketSender.h b/libraries/octree/src/OctreeEditPacketSender.h index d8761e6161..12cb03fcd8 100644 --- a/libraries/octree/src/OctreeEditPacketSender.h +++ b/libraries/octree/src/OctreeEditPacketSender.h @@ -77,7 +77,7 @@ public: virtual char getMyNodeType() const = 0; virtual void adjustEditPacketForClockSkew(PacketType type, QByteArray& buffer, int clockSkew) { } - void processNackPacket(NLPacket& packet, SharedNodePointer sendingNode); + void processNackPacket(ReceivedMessage& message, SharedNodePointer sendingNode); public slots: void nodeKilled(SharedNodePointer node); diff --git a/libraries/octree/src/OctreeHeadlessViewer.cpp b/libraries/octree/src/OctreeHeadlessViewer.cpp index 88a77a4c53..22a66c4cdc 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.cpp +++ b/libraries/octree/src/OctreeHeadlessViewer.cpp @@ -231,10 +231,10 @@ void OctreeHeadlessViewer::queryOctree() { } -int OctreeHeadlessViewer::parseOctreeStats(QSharedPointer packet, SharedNodePointer sourceNode) { +int OctreeHeadlessViewer::parseOctreeStats(QSharedPointer message, SharedNodePointer sourceNode) { OctreeSceneStats temp; - int statsMessageLength = temp.unpackFromPacket(*packet); + int statsMessageLength = temp.unpackFromPacket(*message); // TODO: actually do something with these stats, like expose them to JS... diff --git a/libraries/octree/src/OctreeHeadlessViewer.h b/libraries/octree/src/OctreeHeadlessViewer.h index 605db15cd2..a895b99861 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.h +++ b/libraries/octree/src/OctreeHeadlessViewer.h @@ -37,7 +37,7 @@ public: void setJurisdictionListener(JurisdictionListener* jurisdictionListener) { _jurisdictionListener = jurisdictionListener; } - static int parseOctreeStats(QSharedPointer packet, SharedNodePointer sourceNode); + static int parseOctreeStats(QSharedPointer message, SharedNodePointer sourceNode); static void trackIncomingOctreePacket(const QByteArray& packet, const SharedNodePointer& sendingNode, bool wasStatsPacket); public slots: diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index e8beb0404c..9472ce465b 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -64,9 +64,9 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { } // called on the other nodes - assigns it to my views of the others -int OctreeQuery::parseData(NLPacket& packet) { +int OctreeQuery::parseData(ReceivedMessage& message) { - const unsigned char* startPosition = reinterpret_cast(packet.getPayload()); + const unsigned char* startPosition = reinterpret_cast(message.getPayload()); const unsigned char* sourceBuffer = startPosition; // camera details diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index 86474ffc02..9a10beb6d1 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -48,7 +48,7 @@ public: virtual ~OctreeQuery() {} int getBroadcastData(unsigned char* destinationBuffer); - int parseData(NLPacket& packet); + int parseData(ReceivedMessage& message) override; // getters for camera details const glm::vec3& getCameraPosition() const { return _cameraPosition; } diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp index b7be4cf3e7..526ecb2d8a 100644 --- a/libraries/octree/src/OctreeRenderer.cpp +++ b/libraries/octree/src/OctreeRenderer.cpp @@ -41,7 +41,7 @@ void OctreeRenderer::setTree(OctreePointer newTree) { _tree = newTree; } -void OctreeRenderer::processDatagram(NLPacket& packet, SharedNodePointer sourceNode) { +void OctreeRenderer::processDatagram(ReceivedMessage& message, SharedNodePointer sourceNode) { bool extraDebugging = false; if (extraDebugging) { @@ -56,19 +56,19 @@ void OctreeRenderer::processDatagram(NLPacket& packet, SharedNodePointer sourceN bool showTimingDetails = false; // Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showTimingDetails, "OctreeRenderer::processDatagram()", showTimingDetails); - if (packet.getType() == getExpectedPacketType()) { + if (message.getType() == getExpectedPacketType()) { PerformanceWarning warn(showTimingDetails, "OctreeRenderer::processDatagram expected PacketType", showTimingDetails); // if we are getting inbound packets, then our tree is also viewing, and we should remember that fact. _tree->setIsViewing(true); OCTREE_PACKET_FLAGS flags; - packet.readPrimitive(&flags); + message.readPrimitive(&flags); OCTREE_PACKET_SEQUENCE sequence; - packet.readPrimitive(&sequence); + message.readPrimitive(&sequence); OCTREE_PACKET_SENT_TIME sentAt; - packet.readPrimitive(&sentAt); + message.readPrimitive(&sentAt); bool packetIsColored = oneAtBit(flags, PACKET_IS_COLOR_BIT); bool packetIsCompressed = oneAtBit(flags, PACKET_IS_COMPRESSED_BIT); @@ -83,7 +83,7 @@ void OctreeRenderer::processDatagram(NLPacket& packet, SharedNodePointer sourceN qCDebug(octree, "OctreeRenderer::processDatagram() ... Got Packet Section" " color:%s compressed:%s sequence: %u flight:%d usec size:%lld data:%lld", debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed), - sequence, flightTime, packet.getDataSize(), packet.bytesLeftToRead()); + sequence, flightTime, message.getDataSize(), message.getBytesLeftToRead()); } _packetsInLastWindow++; @@ -95,28 +95,28 @@ void OctreeRenderer::processDatagram(NLPacket& packet, SharedNodePointer sourceN quint64 totalUncompress = 0; quint64 totalReadBitsteam = 0; - const QUuid& sourceUUID = packet.getSourceID(); + const QUuid& sourceUUID = message.getSourceID(); int subsection = 1; bool error = false; - while (packet.bytesLeftToRead() > 0 && !error) { + while (message.getBytesLeftToRead() > 0 && !error) { if (packetIsCompressed) { - if (packet.bytesLeftToRead() > (qint64) sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE)) { - packet.readPrimitive(§ionLength); + if (message.getBytesLeftToRead() > (qint64) sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE)) { + message.readPrimitive(§ionLength); } else { sectionLength = 0; error = true; } } else { - sectionLength = packet.bytesLeftToRead(); + sectionLength = message.getBytesLeftToRead(); } if (sectionLength) { // ask the VoxelTree to read the bitstream into the tree ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, - sourceUUID, sourceNode, false, packet.getVersion()); + sourceUUID, sourceNode, false, message.getVersion()); quint64 startUncompress, startLock = usecTimestampNow(); quint64 startReadBitsteam, endReadBitsteam; // FIXME STUTTER - there may be an opportunity to bump this lock outside of the @@ -125,14 +125,14 @@ void OctreeRenderer::processDatagram(NLPacket& packet, SharedNodePointer sourceN startUncompress = usecTimestampNow(); OctreePacketData packetData(packetIsCompressed); - packetData.loadFinalizedContent(reinterpret_cast(packet.getPayload() + packet.pos()), + packetData.loadFinalizedContent(reinterpret_cast(message.getPayload() + message.pos()), sectionLength); if (extraDebugging) { qCDebug(octree, "OctreeRenderer::processDatagram() ... Got Packet Section" " color:%s compressed:%s sequence: %u flight:%d usec size:%lld data:%lld" " subsection:%d sectionLength:%d uncompressed:%d", debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed), - sequence, flightTime, packet.getDataSize(), packet.bytesLeftToRead(), subsection, sectionLength, + sequence, flightTime, message.getDataSize(), message.getBytesLeftToRead(), subsection, sectionLength, packetData.getUncompressedSize()); } @@ -148,7 +148,7 @@ void OctreeRenderer::processDatagram(NLPacket& packet, SharedNodePointer sourceN }); // seek forwards in packet - packet.seek(packet.pos() + sectionLength); + message.seek(message.pos() + sectionLength); elementsPerPacket += args.elementsPerPacket; entitiesPerPacket += args.entitiesPerPacket; diff --git a/libraries/octree/src/OctreeRenderer.h b/libraries/octree/src/OctreeRenderer.h index e2d97f0484..b5126ab6e6 100644 --- a/libraries/octree/src/OctreeRenderer.h +++ b/libraries/octree/src/OctreeRenderer.h @@ -45,7 +45,7 @@ public: virtual void setTree(OctreePointer newTree); /// process incoming data - virtual void processDatagram(NLPacket& packet, SharedNodePointer sourceNode); + virtual void processDatagram(ReceivedMessage& message, SharedNodePointer sourceNode); /// initialize and GPU/rendering related resources virtual void init(); diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index 22352fbe3b..716db7a2ed 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -443,7 +443,7 @@ int OctreeSceneStats::packIntoPacket() { return _statsPacket->getPayloadSize(); } -int OctreeSceneStats::unpackFromPacket(NLPacket& packet) { +int OctreeSceneStats::unpackFromPacket(ReceivedMessage& packet) { packet.readPrimitive(&_start); packet.readPrimitive(&_end); packet.readPrimitive(&_elapsed); @@ -748,17 +748,17 @@ const char* OctreeSceneStats::getItemValue(Item item) { return _itemValueBuffer; } -void OctreeSceneStats::trackIncomingOctreePacket(NLPacket& packet, bool wasStatsPacket, int nodeClockSkewUsec) { +void OctreeSceneStats::trackIncomingOctreePacket(ReceivedMessage& message, bool wasStatsPacket, int nodeClockSkewUsec) { const bool wantExtraDebugging = false; // skip past the flags - packet.seek(sizeof(OCTREE_PACKET_FLAGS)); + message.seek(sizeof(OCTREE_PACKET_FLAGS)); OCTREE_PACKET_SEQUENCE sequence; - packet.readPrimitive(&sequence); + message.readPrimitive(&sequence); OCTREE_PACKET_SENT_TIME sentAt; - packet.readPrimitive(&sentAt); + message.readPrimitive(&sentAt); //bool packetIsColored = oneAtBit(flags, PACKET_IS_COLOR_BIT); //bool packetIsCompressed = oneAtBit(flags, PACKET_IS_COMPRESSED_BIT); @@ -790,8 +790,8 @@ void OctreeSceneStats::trackIncomingOctreePacket(NLPacket& packet, bool wasStats // track packets here... _incomingPacket++; - _incomingBytes += packet.getDataSize(); + _incomingBytes += message.getDataSize(); if (!wasStatsPacket) { - _incomingWastedBytes += (udt::MAX_PACKET_SIZE - packet.getDataSize()); + _incomingWastedBytes += (udt::MAX_PACKET_SIZE - message.getDataSize()); } } diff --git a/libraries/octree/src/OctreeSceneStats.h b/libraries/octree/src/OctreeSceneStats.h index bdb4ef206a..7e50e42020 100644 --- a/libraries/octree/src/OctreeSceneStats.h +++ b/libraries/octree/src/OctreeSceneStats.h @@ -95,7 +95,7 @@ public: int packIntoPacket(); /// Unpack the details of the statistics from a network packet - int unpackFromPacket(NLPacket& packet); + int unpackFromPacket(ReceivedMessage& packet); /// Indicates that a scene has been completed and the statistics are ready to be sent bool isReadyToSend() const { return _isReadyToSend; } @@ -161,7 +161,7 @@ public: quint64 getLastFullTotalBytes() const { return _lastFullTotalBytes; } // Used in client implementations to track individual octree packets - void trackIncomingOctreePacket(NLPacket& packet, bool wasStatsPacket, int nodeClockSkewUsec); + void trackIncomingOctreePacket(ReceivedMessage& message, bool wasStatsPacket, int nodeClockSkewUsec); quint32 getIncomingPackets() const { return _incomingPacket; } quint64 getIncomingBytes() const { return _incomingBytes; } From 9ddcfdf94d8940b32df8670b6737ee02b9873047 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 16 Oct 2015 09:21:10 -0700 Subject: [PATCH 003/401] Cleanup PacketReceier and ReceivedMessage --- assignment-client/src/Agent.cpp | 6 +- assignment-client/src/assets/AssetServer.cpp | 6 +- assignment-client/src/audio/AudioMixer.cpp | 4 +- .../src/audio/AudioMixerClientData.cpp | 2 +- .../octree/OctreeInboundPacketProcessor.cpp | 24 +++---- domain-server/src/DomainGatekeeper.cpp | 2 +- domain-server/src/DomainServer.cpp | 4 +- .../src/octree/OctreePacketProcessor.cpp | 4 +- libraries/audio/src/InboundAudioStream.cpp | 4 +- libraries/avatars/src/AvatarHashMap.cpp | 2 +- libraries/entities/src/EntityTree.cpp | 2 +- libraries/networking/src/AssetClient.cpp | 8 +-- libraries/networking/src/LimitedNodeList.cpp | 7 +- libraries/networking/src/NodeList.cpp | 10 +-- libraries/networking/src/PacketReceiver.cpp | 69 ++++++------------- libraries/networking/src/PacketReceiver.h | 11 +-- libraries/networking/src/ReceivedMessage.h | 13 ++-- libraries/octree/src/JurisdictionMap.cpp | 2 +- libraries/octree/src/OctreeQuery.cpp | 2 +- libraries/octree/src/OctreeRenderer.cpp | 8 +-- libraries/octree/src/OctreeSceneStats.cpp | 6 +- 21 files changed, 83 insertions(+), 113 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index b6bc2c8d01..9a3896f0ac 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -63,12 +63,12 @@ void Agent::handleOctreePacket(QSharedPointer message, SharedNo if (packetType == PacketType::OctreeStats) { int statsMessageLength = OctreeHeadlessViewer::parseOctreeStats(message, senderNode); - if (message->getPayloadSize() > statsMessageLength) { + if (message->getSize() > statsMessageLength) { // pull out the piggybacked packet and create a new QSharedPointer for it - int piggyBackedSizeWithHeader = message->getPayloadSize() - statsMessageLength; + int piggyBackedSizeWithHeader = message->getSize() - statsMessageLength; auto buffer = std::unique_ptr(new char[piggyBackedSizeWithHeader]); - memcpy(buffer.get(), message->getPayload() + statsMessageLength, piggyBackedSizeWithHeader); + memcpy(buffer.get(), message->getRawMessage() + statsMessageLength, piggyBackedSizeWithHeader); auto newPacket = NLPacket::fromReceivedPacket(std::move(buffer), piggyBackedSizeWithHeader, message->getSenderSockAddr()); message = QSharedPointer(new ReceivedMessage(*newPacket)); diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index da1addf174..2f9e7ee1e6 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -40,7 +40,7 @@ AssetServer::AssetServer(ReceivedMessage& message) : auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListener(PacketType::AssetGet, this, "handleAssetGet"); packetReceiver.registerListener(PacketType::AssetGetInfo, this, "handleAssetGetInfo"); - packetReceiver.registerMessageListener(PacketType::AssetUpload, this, "handleAssetUpload"); + packetReceiver.registerListener(PacketType::AssetUpload, this, "handleAssetUpload"); } void AssetServer::run() { @@ -89,7 +89,7 @@ void AssetServer::handleAssetGetInfo(QSharedPointer message, Sh MessageID messageID; uint8_t extensionLength; - if (message->getPayloadSize() < qint64(SHA256_HASH_LENGTH + sizeof(messageID) + sizeof(extensionLength))) { + if (message->getSize() < qint64(SHA256_HASH_LENGTH + sizeof(messageID) + sizeof(extensionLength))) { qDebug() << "ERROR bad file request"; return; } @@ -126,7 +126,7 @@ void AssetServer::handleAssetGet(QSharedPointer message, Shared auto minSize = qint64(sizeof(MessageID) + SHA256_HASH_LENGTH + sizeof(uint8_t) + sizeof(DataOffset) + sizeof(DataOffset)); - if (message->getPayloadSize() < minSize) { + if (message->getSize() < minSize) { qDebug() << "ERROR bad file request"; return; } diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index e09564634c..1cc686039f 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -549,9 +549,9 @@ void AudioMixer::handleMuteEnvironmentPacket(QSharedPointer mes auto nodeList = DependencyManager::get(); if (sendingNode->getCanAdjustLocks()) { - auto newPacket = NLPacket::create(PacketType::MuteEnvironment, message->getPayloadSize()); + auto newPacket = NLPacket::create(PacketType::MuteEnvironment, message->getSize()); // Copy payload - newPacket->write(message->getPayload(), message->getPayloadSize()); + newPacket->write(message->getRawMessage(), message->getSize()); nodeList->eachNode([&](const SharedNodePointer& node){ if (node->getType() == NodeType::Agent && node->getActiveSocket() && diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 63ee88f2ef..729e9fa633 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -60,7 +60,7 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { // read the downstream audio stream stats message.readPrimitive(&_downstreamAudioStreamStats); - return message.pos(); + return message.getPosition(); } else { PositionalAudioStream* matchingStream = NULL; diff --git a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp index cee1d9ba0f..ce67fdb030 100644 --- a/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp +++ b/assignment-client/src/octree/OctreeInboundPacketProcessor.cpp @@ -84,8 +84,8 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer if (debugProcessPacket) { qDebug("OctreeInboundPacketProcessor::processPacket() payload=%p payloadLength=%lld", - message->getPayload(), - message->getPayloadSize()); + message->getRawMessage(), + message->getSize()); } // Ask our tree subclass if it can handle the incoming packet... @@ -117,7 +117,7 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer if (debugProcessPacket || _myServer->wantsDebugReceiving()) { qDebug() << "PROCESSING THREAD: got '" << packetType << "' packet - " << _receivedPacketCount << " command from client"; - qDebug() << " receivedBytes=" << message->getDataSize(); + qDebug() << " receivedBytes=" << message->getSize(); qDebug() << " sequence=" << sequence; qDebug() << " sentAt=" << sentAt << " usecs"; qDebug() << " arrivedAt=" << arrivedAt << " usecs"; @@ -131,8 +131,8 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer qDebug() << " numBytesPacketHeader=" << NLPacket::totalHeaderSize(packetType); qDebug() << " sizeof(sequence)=" << sizeof(sequence); qDebug() << " sizeof(sentAt)=" << sizeof(sentAt); - qDebug() << " atByte (in payload)=" << message->pos(); - qDebug() << " payload size=" << message->getPayloadSize(); + qDebug() << " atByte (in payload)=" << message->getPosition(); + qDebug() << " payload size=" << message->getSize(); if (!message->getBytesLeftToRead()) { qDebug() << " ----- UNEXPECTED ---- got a packet without any edit details!!!! --------"; @@ -143,7 +143,7 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer while (message->getBytesLeftToRead() > 0) { - editData = reinterpret_cast(message->getPayload() + message->pos()); + editData = reinterpret_cast(message->getRawMessage() + message->getPosition()); int maxSize = message->getBytesLeftToRead(); @@ -152,8 +152,8 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer qDebug() << " maxSize=" << maxSize; qDebug("OctreeInboundPacketProcessor::processPacket() %hhu " "payload=%p payloadLength=%lld editData=%p payloadPosition=%lld maxSize=%d", - packetType, message->getPayload(), message->getPayloadSize(), editData, - message->pos(), maxSize); + packetType, message->getRawMessage(), message->getSize(), editData, + message->getPosition(), maxSize); } quint64 startProcess, startLock = usecTimestampNow(); @@ -177,12 +177,12 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer lockWaitTime += thisLockWaitTime; // skip to next edit record in the packet - message->seek(message->pos() + editDataBytesRead); + message->seek(message->getPosition() + editDataBytesRead); if (debugProcessPacket) { qDebug() << " editDataBytesRead=" << editDataBytesRead; - qDebug() << " AFTER processEditPacketData payload position=" << message->pos(); - qDebug() << " AFTER processEditPacketData payload size=" << message->getPayloadSize(); + qDebug() << " AFTER processEditPacketData payload position=" << message->getPosition(); + qDebug() << " AFTER processEditPacketData payload size=" << message->getSize(); } } @@ -190,7 +190,7 @@ void OctreeInboundPacketProcessor::processPacket(QSharedPointer if (debugProcessPacket) { qDebug("OctreeInboundPacketProcessor::processPacket() DONE LOOPING FOR %hhu " "payload=%p payloadLength=%lld editData=%p payloadPosition=%lld", - packetType, message->getPayload(), message->getPayloadSize(), editData, message->pos()); + packetType, message->getRawMessage(), message->getSize(), editData, message->getPosition()); } // Make sure our Node and NodeList knows we've heard from this node. diff --git a/domain-server/src/DomainGatekeeper.cpp b/domain-server/src/DomainGatekeeper.cpp index 1048d2665e..714d840baa 100644 --- a/domain-server/src/DomainGatekeeper.cpp +++ b/domain-server/src/DomainGatekeeper.cpp @@ -51,7 +51,7 @@ const NodeSet STATICALLY_ASSIGNED_NODES = NodeSet() << NodeType::AudioMixer << NodeType::AssetServer; void DomainGatekeeper::processConnectRequestPacket(QSharedPointer message) { - if (message->getPayloadSize() == 0) { + if (message->getSize() == 0) { return; } diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 80529ac116..ec8ad16ae8 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -267,7 +267,7 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) { packetReceiver.registerListener(PacketType::RequestAssignment, this, "processRequestAssignmentPacket"); packetReceiver.registerListener(PacketType::DomainListRequest, this, "processListRequestPacket"); packetReceiver.registerListener(PacketType::DomainServerPathQuery, this, "processPathQueryPacket"); - packetReceiver.registerMessageListener(PacketType::NodeJsonStats, this, "processNodeJSONStatsPacket"); + packetReceiver.registerListener(PacketType::NodeJsonStats, this, "processNodeJSONStatsPacket"); // NodeList won't be available to the settings manager when it is created, so call registerListener here packetReceiver.registerListener(PacketType::DomainSettingsRequest, &_settingsManager, "processSettingsRequestPacket"); @@ -1763,7 +1763,7 @@ void DomainServer::processPathQueryPacket(QSharedPointer messag if (numPathBytes <= message->getBytesLeftToRead()) { // the number of path bytes makes sense for the sent packet - pull out the path - QString pathQuery = QString::fromUtf8(message->getPayload() + message->pos(), numPathBytes); + QString pathQuery = QString::fromUtf8(message->getRawMessage() + message->getPosition(), numPathBytes); // our settings contain paths that start with a leading slash, so make sure this query has that if (!pathQuery.startsWith("/")) { diff --git a/interface/src/octree/OctreePacketProcessor.cpp b/interface/src/octree/OctreePacketProcessor.cpp index 1538c4eb65..b565bdfd88 100644 --- a/interface/src/octree/OctreePacketProcessor.cpp +++ b/interface/src/octree/OctreePacketProcessor.cpp @@ -48,12 +48,12 @@ void OctreePacketProcessor::processPacket(QSharedPointer messag int statsMessageLength = qApp->processOctreeStats(*message, sendingNode); wasStatsPacket = true; - int piggybackBytes = message->getPayloadSize() - statsMessageLength; + int piggybackBytes = message->getSize() - statsMessageLength; if (piggybackBytes) { // construct a new packet from the piggybacked one auto buffer = std::unique_ptr(new char[piggybackBytes]); - memcpy(buffer.get(), message->getPayload() + statsMessageLength, piggybackBytes); + memcpy(buffer.get(), message->getRawMessage() + statsMessageLength, piggybackBytes); qDebug() << "Got piggyback, read " << piggybackBytes << " bytes"; auto newPacket = NLPacket::fromReceivedPacket(std::move(buffer), piggybackBytes, message->getSenderSockAddr()); diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index f2aa91aae1..8b32ada296 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -111,7 +111,7 @@ int InboundAudioStream::parseData(ReceivedMessage& message) { int networkSamples; // parse the info after the seq number and before the audio data (the stream properties) - int prePropertyPosition = message.pos(); + int prePropertyPosition = message.getPosition(); int propertyBytes = parseStreamProperties(message.getType(), message.readWithoutCopy(message.getBytesLeftToRead()), networkSamples); message.seek(prePropertyPosition + propertyBytes); @@ -161,7 +161,7 @@ int InboundAudioStream::parseData(ReceivedMessage& message) { framesAvailableChanged(); - return message.pos(); + return message.getPosition(); } int InboundAudioStream::parseStreamProperties(PacketType type, const QByteArray& packetAfterSeqNum, int& numAudioSamples) { diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index 0a46fec3bc..8befede6c8 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -55,7 +55,7 @@ void AvatarHashMap::processAvatarDataPacket(QSharedPointer mess while (message->getBytesLeftToRead()) { QUuid sessionUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); - int positionBeforeRead = message->pos(); + int positionBeforeRead = message->getPosition(); QByteArray byteArray = message->readWithoutCopy(message->getBytesLeftToRead()); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 0f76f76094..99331774a8 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -877,7 +877,7 @@ int EntityTree::processEraseMessage(ReceivedMessage& message, const SharedNodePo deleteEntities(entityItemIDsToDelete, true, true); } }); - return message.pos(); + return message.getPosition(); } // This version skips over the header diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 623d1d86eb..ecf138ba5f 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -38,9 +38,9 @@ AssetClient::AssetClient() { auto nodeList = DependencyManager::get(); auto& packetReceiver = nodeList->getPacketReceiver(); - packetReceiver.registerMessageListener(PacketType::AssetGetInfoReply, this, "handleAssetGetInfoReply"); - packetReceiver.registerMessageListener(PacketType::AssetGetReply, this, "handleAssetGetReply", true); - packetReceiver.registerMessageListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply"); + packetReceiver.registerListener(PacketType::AssetGetInfoReply, this, "handleAssetGetInfoReply"); + packetReceiver.registerListener(PacketType::AssetGetReply, this, "handleAssetGetReply", true); + packetReceiver.registerListener(PacketType::AssetUploadReply, this, "handleAssetUploadReply"); connect(nodeList.data(), &LimitedNodeList::nodeKilled, this, &AssetClient::handleNodeKilled); } @@ -242,7 +242,7 @@ void AssetClient::handleAssetGetReply(QSharedPointer message, S } else { connect(message.data(), &ReceivedMessage::progress, this, [this, length, message, callbacks](ReceivedMessage* msg) { //qDebug() << "Progress: " << msg->getDataSize(); - callbacks.progressCallback(msg->getDataSize(), length); + callbacks.progressCallback(msg->getSize(), length); }); connect(message.data(), &ReceivedMessage::completed, this, [this, message, error, callbacks](ReceivedMessage* msg) { callbacks.completeCallback(true, error, message->readAll()); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 91cff1ad0b..0827252599 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -100,11 +100,6 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short _packetReceiver->handleVerifiedMessagePacket(std::move(packet)); } ); - _nodeSocket.setPacketListHandler( - [this](std::unique_ptr packetList) { - _packetReceiver->handleVerifiedPacketList(std::move(packetList)); - } - ); // set our isPacketVerified method as the verify operator for the udt::Socket using std::placeholders::_1; @@ -554,7 +549,7 @@ std::unique_ptr LimitedNodeList::constructICEPingReplyPacket(ReceivedM // pull out the ping type so we can reply back with that PingType_t pingType; - memcpy(&pingType, message.getPayload() + NUM_BYTES_RFC4122_UUID, sizeof(PingType_t)); + memcpy(&pingType, message.getRawMessage() + NUM_BYTES_RFC4122_UUID, sizeof(PingType_t)); int packetSize = NUM_BYTES_RFC4122_UUID + sizeof(PingType_t); auto icePingReplyPacket = NLPacket::create(PacketType::ICEPingReply, packetSize); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 00d6a503a7..ddec52aa2f 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -98,7 +98,7 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned packetReceiver.registerListener(PacketType::ICEPing, this, "processICEPingPacket"); packetReceiver.registerListener(PacketType::DomainServerAddedNode, this, "processDomainServerAddedNode"); packetReceiver.registerListener(PacketType::DomainServerConnectionToken, this, "processDomainServerConnectionTokenPacket"); - packetReceiver.registerMessageListener(PacketType::DomainSettings, &_domainHandler, "processSettingsPacketList"); + packetReceiver.registerListener(PacketType::DomainSettings, &_domainHandler, "processSettingsPacketList"); packetReceiver.registerListener(PacketType::ICEServerPeerInformation, &_domainHandler, "processICEResponsePacket"); packetReceiver.registerListener(PacketType::DomainServerRequireDTLS, &_domainHandler, "processDTLSRequirementPacket"); packetReceiver.registerListener(PacketType::ICEPingReply, &_domainHandler, "processICEPingReplyPacket"); @@ -378,8 +378,8 @@ void NodeList::processDomainServerPathResponse(QSharedPointer m return; } - QString pathQuery = QString::fromUtf8(message->getPayload() + message->pos(), numPathBytes); - message->seek(message->pos() + numPathBytes); + QString pathQuery = QString::fromUtf8(message->getRawMessage() + message->getPosition(), numPathBytes); + message->seek(message->getPosition() + numPathBytes); // figure out how many bytes the viewpoint is quint16 numViewpointBytes; @@ -391,7 +391,7 @@ void NodeList::processDomainServerPathResponse(QSharedPointer m } // pull the viewpoint from the packet - QString viewpoint = QString::fromUtf8(message->getPayload() + message->pos(), numViewpointBytes); + QString viewpoint = QString::fromUtf8(message->getRawMessage() + message->getPosition(), numViewpointBytes); // Hand it off to the AddressManager so it can handle it as a relative viewpoint if (DependencyManager::get()->goToViewpointForPath(viewpoint, pathQuery)) { @@ -500,7 +500,7 @@ void NodeList::processDomainServerList(QSharedPointer message) setThisNodeCanRez((bool) thisNodeCanRez); // pull each node in the packet - while (packetStream.device()->pos() < message->getPayloadSize()) { + while (packetStream.device()->pos() < message->getSize()) { parseNodeFromPacketStream(packetStream); } } diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index a95ba12047..1b2a966b70 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -94,7 +94,7 @@ void PacketReceiver::registerDirectListenerForTypes(PacketTypeList types, } } -bool PacketReceiver::registerMessageListener(PacketType type, QObject* listener, const char* slot, +bool PacketReceiver::registerListener(PacketType type, QObject* listener, const char* slot, bool deliverPending) { Q_ASSERT_X(listener, "PacketReceiver::registerMessageListener", "No object to register"); Q_ASSERT_X(slot, "PacketReceiver::registerMessageListener", "No slot to register"); @@ -102,22 +102,15 @@ bool PacketReceiver::registerMessageListener(PacketType type, QObject* listener, QMetaMethod matchingMethod = matchingMethodForListener(type, listener, slot); if (matchingMethod.isValid()) { - QMutexLocker locker(&_packetListenerLock); - - if (_messageListenerMap.contains(type)) { - qCWarning(networking) << "Registering a packet listener for packet type" << type - << "that will remove a previously registered listener"; - } - - // add the mapping - _messageListenerMap[type] = { QPointer(listener), matchingMethod, deliverPending }; - + qDebug() << "Found: " << matchingMethod.methodSignature(); + registerVerifiedListener(type, listener, matchingMethod); return true; } else { return false; } } +/* bool PacketReceiver::registerListener(PacketType type, QObject* listener, const char* slot) { Q_ASSERT_X(listener, "PacketReceiver::registerListener", "No object to register"); Q_ASSERT_X(slot, "PacketReceiver::registerListener", "No slot to register"); @@ -132,6 +125,7 @@ bool PacketReceiver::registerListener(PacketType type, QObject* listener, const return false; } } +*/ QMetaMethod PacketReceiver::matchingMethodForListener(PacketType type, QObject* object, const char* slot) const { Q_ASSERT_X(object, "PacketReceiver::matchingMethodForListener", "No object to call"); @@ -140,27 +134,20 @@ QMetaMethod PacketReceiver::matchingMethodForListener(PacketType type, QObject* // normalize the slot with the expected parameters static const QString SIGNATURE_TEMPLATE("%1(%2)"); - // static const QString NON_SOURCED_PACKET_LISTENER_PARAMETERS = "QSharedPointer"; - static const QString NON_SOURCED_PACKETLIST_LISTENER_PARAMETERS = "QSharedPointer"; + static const QString NON_SOURCED_MESSAGE_LISTENER_PARAMETERS = "QSharedPointer"; QSet possibleSignatures { - // SIGNATURE_TEMPLATE.arg(slot, NON_SOURCED_PACKET_LISTENER_PARAMETERS), - SIGNATURE_TEMPLATE.arg(slot, NON_SOURCED_PACKETLIST_LISTENER_PARAMETERS) + SIGNATURE_TEMPLATE.arg(slot, NON_SOURCED_MESSAGE_LISTENER_PARAMETERS) }; if (!NON_SOURCED_PACKETS.contains(type)) { - // static const QString SOURCED_PACKET_LISTENER_PARAMETERS = "QSharedPointer,QSharedPointer"; - // static const QString TYPEDEF_SOURCED_PACKET_LISTENER_PARAMETERS = "QSharedPointer,SharedNodePointer"; - static const QString SOURCED_PACKETLIST_LISTENER_PARAMETERS = "QSharedPointer,QSharedPointer"; - static const QString TYPEDEF_SOURCED_PACKETLIST_LISTENER_PARAMETERS = "QSharedPointer,SharedNodePointer"; + static const QString SOURCED_MESSAGE_LISTENER_PARAMETERS = "QSharedPointer,QSharedPointer"; + static const QString TYPEDEF_SOURCED_MESSAGE_LISTENER_PARAMETERS = "QSharedPointer,SharedNodePointer"; - // a sourced packet must take the shared pointer to the packet but optionally could include + // a sourced packet must take the shared pointer to the ReceivedMessage but optionally could include // a shared pointer to the node - - // possibleSignatures << SIGNATURE_TEMPLATE.arg(slot, TYPEDEF_SOURCED_PACKET_LISTENER_PARAMETERS); - // possibleSignatures << SIGNATURE_TEMPLATE.arg(slot, SOURCED_PACKET_LISTENER_PARAMETERS); - possibleSignatures << SIGNATURE_TEMPLATE.arg(slot, TYPEDEF_SOURCED_PACKETLIST_LISTENER_PARAMETERS); - possibleSignatures << SIGNATURE_TEMPLATE.arg(slot, SOURCED_PACKETLIST_LISTENER_PARAMETERS); + possibleSignatures << SIGNATURE_TEMPLATE.arg(slot, TYPEDEF_SOURCED_MESSAGE_LISTENER_PARAMETERS); + possibleSignatures << SIGNATURE_TEMPLATE.arg(slot, SOURCED_MESSAGE_LISTENER_PARAMETERS); } int methodIndex = -1; @@ -244,17 +231,22 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { auto nlPacket = NLPacket::fromBase(std::move(packet)); auto receivedMessage = QSharedPointer(new ReceivedMessage(*nlPacket.get())); + _inPacketCount += 1; + _inByteCount += nlPacket->size(); + handleVerifiedMessage(receivedMessage, true); } void PacketReceiver::handleVerifiedMessagePacket(std::unique_ptr packet) { - qDebug() << "Got message packet"; auto nlPacket = NLPacket::fromBase(std::move(packet)); + _inPacketCount += 1; _inByteCount += nlPacket->size(); + auto key = std::pair(nlPacket->getSenderSockAddr(), nlPacket->getMessageNumber()); auto it = _pendingMessages.find(key); QSharedPointer message; + if (it == _pendingMessages.end()) { // Create message message = QSharedPointer(new ReceivedMessage(*nlPacket.release())); @@ -273,26 +265,9 @@ void PacketReceiver::handleVerifiedMessagePacket(std::unique_ptr pa } } -void PacketReceiver::handleVerifiedPacketList(std::unique_ptr packetList) { - // if we're supposed to drop this packet then break out here - if (_shouldDropPackets) { - return; - } - - // setup an NLPacketList from the PacketList we were passed - auto nlPacketList = NLPacketList::fromPacketList(std::move(packetList)); - auto receivedMessage = QSharedPointer(new ReceivedMessage(*nlPacketList.release())); - - handleVerifiedMessage(receivedMessage, true); -} - void PacketReceiver::handleVerifiedMessage(QSharedPointer receivedMessage, bool justReceived) { - auto nodeList = DependencyManager::get(); - _inPacketCount += receivedMessage->getNumPackets(); - _inByteCount += receivedMessage->size(); - SharedNodePointer matchingNode; if (!receivedMessage->getSourceID().isNull()) { @@ -328,14 +303,12 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer recei PacketType packetType = receivedMessage->getType(); if (matchingNode) { - emit dataReceived(matchingNode->getType(), receivedMessage->size()); - matchingNode->recordBytesReceived(receivedMessage->size()); + emit dataReceived(matchingNode->getType(), receivedMessage->getSize()); + matchingNode->recordBytesReceived(receivedMessage->getSize()); Node* n = matchingNode.data(); auto addr = n->getActiveSocket(); QMetaMethod metaMethod = listener.method; - - // qDebug() << "Got verified packet list: " << QString(receivedMessage->getMessage()); static const QByteArray QSHAREDPOINTER_NODE_NORMALIZED = QMetaObject::normalizedType("QSharedPointer"); static const QByteArray SHARED_NODE_NORMALIZED = QMetaObject::normalizedType("SharedNodePointer"); @@ -364,7 +337,7 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer recei } } else { // qDebug() << "Got verified unsourced packet list: " << QString(nlPacketList->getMessage()); - emit dataReceived(NodeType::Unassigned, receivedMessage->size()); + emit dataReceived(NodeType::Unassigned, receivedMessage->getSize()); // one final check on the QPointer before we invoke if (listener.object) { diff --git a/libraries/networking/src/PacketReceiver.h b/libraries/networking/src/PacketReceiver.h index b27abdc084..4a3f32f99c 100644 --- a/libraries/networking/src/PacketReceiver.h +++ b/libraries/networking/src/PacketReceiver.h @@ -57,15 +57,14 @@ public: void resetCounters() { _inPacketCount = 0; _inByteCount = 0; } + // If deliverPending is false, ReceivedMessage will only be delivered once all packets for the message have + // been received. If deliverPending is true, ReceivedMessage will be delivered as soon as the first packet + // for the message is received. + bool registerListener(PacketType type, QObject* listener, const char* slot, bool deliverPending = false); bool registerListenerForTypes(PacketTypeList types, QObject* listener, const char* slot); - bool registerMessageListener(PacketType type, QObject* listener, const char* slot, bool deliverPending = false); - bool registerListener(PacketType type, QObject* listener, const char* slot); void unregisterListener(QObject* listener); void handleVerifiedPacket(std::unique_ptr packet); - void handleVerifiedPacketList(std::unique_ptr packetList); - void handleVerifiedMessage(QSharedPointer message, bool justReceived); - void handleVerifiedMessagePacket(std::unique_ptr message); signals: @@ -78,6 +77,8 @@ private: bool deliverPending; }; + void handleVerifiedMessage(QSharedPointer message, bool justReceived); + // these are brutal hacks for now - ideally GenericThread / ReceivedPacketProcessor // should be changed to have a true event loop and be able to handle our QMetaMethod::invoke void registerDirectListenerForTypes(PacketTypeList types, QObject* listener, const char* slot); diff --git a/libraries/networking/src/ReceivedMessage.h b/libraries/networking/src/ReceivedMessage.h index bd92205d5a..8ab254e8e4 100644 --- a/libraries/networking/src/ReceivedMessage.h +++ b/libraries/networking/src/ReceivedMessage.h @@ -27,8 +27,9 @@ public: ReceivedMessage(const NLPacketList& packetList); ReceivedMessage(NLPacket& packet); - const char* getPayload() const { return _data.constData(); } QByteArray getMessage() const { return _data; } + const char* getRawMessage() const { return _data.constData(); } + PacketType getType() const { return _packetType; } PacketVersion getVersion() const { return _packetVersion; } @@ -39,18 +40,18 @@ public: const QUuid& getSourceID() const { return _sourceID; } const HifiSockAddr& getSenderSockAddr() { return _senderSockAddr; } - void seek(qint64 position) { _position = position; } - qint64 pos() const { return _position; } - qint64 size() const { return _data.size(); } + qint64 getPosition() const { return _position; } + //qint64 size() const { return _data.size(); } // Get the number of packets that were used to send this message qint64 getNumPackets() const { return _numPackets; } - qint64 getDataSize() const { return _data.size(); } - qint64 getPayloadSize() const { return _data.size(); } + qint64 getSize() const { return _data.size(); } qint64 getBytesLeftToRead() const { return _data.size() - _position; } + void seek(qint64 position) { _position = position; } + qint64 peek(char* data, qint64 size); qint64 read(char* data, qint64 size); diff --git a/libraries/octree/src/JurisdictionMap.cpp b/libraries/octree/src/JurisdictionMap.cpp index 2b38a98bf6..d473b3973e 100644 --- a/libraries/octree/src/JurisdictionMap.cpp +++ b/libraries/octree/src/JurisdictionMap.cpp @@ -329,5 +329,5 @@ int JurisdictionMap::unpackFromPacket(ReceivedMessage& message) { } } - return message.pos(); // excludes header + return message.getPosition(); // excludes header } diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index 9472ce465b..2b2c53e355 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -66,7 +66,7 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { // called on the other nodes - assigns it to my views of the others int OctreeQuery::parseData(ReceivedMessage& message) { - const unsigned char* startPosition = reinterpret_cast(message.getPayload()); + const unsigned char* startPosition = reinterpret_cast(message.getRawMessage()); const unsigned char* sourceBuffer = startPosition; // camera details diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp index 526ecb2d8a..8a8353ee1d 100644 --- a/libraries/octree/src/OctreeRenderer.cpp +++ b/libraries/octree/src/OctreeRenderer.cpp @@ -83,7 +83,7 @@ void OctreeRenderer::processDatagram(ReceivedMessage& message, SharedNodePointer qCDebug(octree, "OctreeRenderer::processDatagram() ... Got Packet Section" " color:%s compressed:%s sequence: %u flight:%d usec size:%lld data:%lld", debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed), - sequence, flightTime, message.getDataSize(), message.getBytesLeftToRead()); + sequence, flightTime, message.getSize(), message.getBytesLeftToRead()); } _packetsInLastWindow++; @@ -125,14 +125,14 @@ void OctreeRenderer::processDatagram(ReceivedMessage& message, SharedNodePointer startUncompress = usecTimestampNow(); OctreePacketData packetData(packetIsCompressed); - packetData.loadFinalizedContent(reinterpret_cast(message.getPayload() + message.pos()), + packetData.loadFinalizedContent(reinterpret_cast(message.getRawMessage() + message.getPosition()), sectionLength); if (extraDebugging) { qCDebug(octree, "OctreeRenderer::processDatagram() ... Got Packet Section" " color:%s compressed:%s sequence: %u flight:%d usec size:%lld data:%lld" " subsection:%d sectionLength:%d uncompressed:%d", debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed), - sequence, flightTime, message.getDataSize(), message.getBytesLeftToRead(), subsection, sectionLength, + sequence, flightTime, message.getSize(), message.getBytesLeftToRead(), subsection, sectionLength, packetData.getUncompressedSize()); } @@ -148,7 +148,7 @@ void OctreeRenderer::processDatagram(ReceivedMessage& message, SharedNodePointer }); // seek forwards in packet - message.seek(message.pos() + sectionLength); + message.seek(message.getPosition() + sectionLength); elementsPerPacket += args.elementsPerPacket; entitiesPerPacket += args.entitiesPerPacket; diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index 716db7a2ed..7b45eacf5c 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -550,7 +550,7 @@ int OctreeSceneStats::unpackFromPacket(ReceivedMessage& packet) { float calculatedBPV = total == 0 ? 0 : (_bytes * 8) / total; _bitsPerOctreeAverage.updateAverage(calculatedBPV); - return packet.pos(); // excludes header! + return packet.getPosition(); // excludes header! } @@ -790,8 +790,8 @@ void OctreeSceneStats::trackIncomingOctreePacket(ReceivedMessage& message, bool // track packets here... _incomingPacket++; - _incomingBytes += message.getDataSize(); + _incomingBytes += message.getSize(); if (!wasStatsPacket) { - _incomingWastedBytes += (udt::MAX_PACKET_SIZE - message.getDataSize()); + _incomingWastedBytes += (udt::MAX_PACKET_SIZE - message.getSize()); } } From 7977f4640dc53c8226dc6be969775acedee7c78b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 18 Oct 2015 07:27:22 -0700 Subject: [PATCH 004/401] new class: SpatiallyNestable --- libraries/shared/src/SpatiallyNestable.cpp | 37 +++++++++++++++++ libraries/shared/src/SpatiallyNestable.h | 47 ++++++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 libraries/shared/src/SpatiallyNestable.cpp create mode 100644 libraries/shared/src/SpatiallyNestable.h diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp new file mode 100644 index 0000000000..5e14f398ea --- /dev/null +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -0,0 +1,37 @@ +// +// SpatiallyNestable.cpp +// libraries/shared/src/ +// +// Created by Seth Alves on 2015-10-18 +// 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 "SpatiallyNestable.h" + +SpatiallyNestable::SpatiallyNestable() : + _transform() { +} + + +const glm::vec3& SpatiallyNestable::getPosition() const { + return _transform.getTranslation(); +} + +void SpatiallyNestable::setPosition(const glm::vec3& position) { + _transform.setTranslation(position); +} + +const glm::quat& SpatiallyNestable::getOrientation() const { + return _transform.getRotation(); +} + +void SpatiallyNestable::setOrientation(const glm::quat& orientation) { + _transform.setRotation(orientation); +} + +const Transform& SpatiallyNestable::getTransform() const { + return _transform; +} diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h new file mode 100644 index 0000000000..dd57f27477 --- /dev/null +++ b/libraries/shared/src/SpatiallyNestable.h @@ -0,0 +1,47 @@ +// +// SpatiallyNestable.h +// libraries/shared/src/ +// +// Created by Seth Alves on 2015-10-18 +// 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_SpatiallyNestable_h +#define hifi_SpatiallyNestable_h + +#include + +#include "Transform.h" + + +class SpatiallyNestable; +typedef std::weak_ptr SpatiallyNestableWeakPointer; +typedef std::shared_ptr SpatiallyNestablePointer; + +class SpatiallyNestable { + +public: + SpatiallyNestable(); + virtual ~SpatiallyNestable() { } + + virtual const glm::vec3& getPosition() const; + virtual void setPosition(const glm::vec3& position); + virtual const glm::quat& getOrientation() const; + virtual void setOrientation(const glm::quat& orientation); + virtual const Transform& getTransform() const; + +protected: + Transform _transform; + + QUuid _parentID; // what is this thing's transform relative to? + int _parentJointIndex; // which joint of the parent is this relative to? + + SpatiallyNestableWeakPointer _parent; + QVector _children; +}; + + +#endif // hifi_SpatiallyNestable_h From 275e77d29e2a258eed2ea286398107bb983ed660 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 18 Oct 2015 07:51:00 -0700 Subject: [PATCH 005/401] remove old-style avatar referentials --- interface/src/Menu.cpp | 6 +- interface/src/avatar/Avatar.cpp | 28 ---- interface/src/avatar/ModelReferential.cpp | 192 ---------------------- interface/src/avatar/ModelReferential.h | 48 ------ interface/src/avatar/MyAvatar.cpp | 31 ---- interface/src/avatar/MyAvatar.h | 4 - libraries/avatars/src/AvatarData.cpp | 79 +++------ libraries/avatars/src/AvatarData.h | 10 +- libraries/avatars/src/Referential.cpp | 109 ------------ libraries/avatars/src/Referential.h | 73 -------- libraries/entities/src/EntityItem.cpp | 12 -- libraries/entities/src/EntityItem.h | 33 +--- 12 files changed, 31 insertions(+), 594 deletions(-) delete mode 100644 interface/src/avatar/ModelReferential.cpp delete mode 100644 interface/src/avatar/ModelReferential.h delete mode 100644 libraries/avatars/src/Referential.cpp delete mode 100644 libraries/avatars/src/Referential.h diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 008694717f..c6f5bace3a 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -369,9 +369,9 @@ Menu::Menu() { auto& atpMigrator = ATPAssetMigrator::getInstance(); atpMigrator.setDialogParent(this); - QAction* assetMigration = addActionToQMenuAndActionHash(assetDeveloperMenu, MenuOption::AssetMigration, - 0, &atpMigrator, - SLOT(loadEntityServerFile())); + /*QAction* assetMigration =*/ addActionToQMenuAndActionHash(assetDeveloperMenu, MenuOption::AssetMigration, + 0, &atpMigrator, + SLOT(loadEntityServerFile())); MenuWrapper* avatarDebugMenu = developerMenu->addMenu("Avatar"); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 9f4e7ee3cf..432149d907 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -38,7 +38,6 @@ #include "Hand.h" #include "Head.h" #include "Menu.h" -#include "ModelReferential.h" #include "Physics.h" #include "Recorder.h" #include "Util.h" @@ -150,30 +149,6 @@ 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()) { - EntityTreePointer tree = qApp->getEntities()->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: - qCDebug(interfaceapp) << "[WARNING] Avatar::simulate(): Unknown referential type."; - break; - } - } - - _referential->update(); - } - if (_scale != _targetScale) { setScale(_targetScale); } @@ -329,9 +304,6 @@ void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptrupdate(); - } auto& batch = *renderArgs->_batch; diff --git a/interface/src/avatar/ModelReferential.cpp b/interface/src/avatar/ModelReferential.cpp deleted file mode 100644 index 18c5e36e7a..0000000000 --- a/interface/src/avatar/ModelReferential.cpp +++ /dev/null @@ -1,192 +0,0 @@ -// -// 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 -#include - -#include "InterfaceLogging.h" -#include "ModelReferential.h" - -ModelReferential::ModelReferential(Referential* referential, EntityTreePointer tree, AvatarData* avatar) : - Referential(MODEL, avatar), - _tree(tree) -{ - _translation = referential->getTranslation(); - _rotation = referential->getRotation(); - unpackExtraData(reinterpret_cast(referential->getExtraData().data()), - referential->getExtraData().size()); - - if (!isValid()) { - qCDebug(interfaceapp) << "ModelReferential::copyConstructor(): Not Valid"; - return; - } - - EntityItemPointer item = _tree->findEntityByID(_entityID); - if (item != NULL) { - _lastRefDimension = item->getDimensions(); - _refRotation = item->getRotation(); - _refPosition = item->getPosition(); - update(); - } -} - -ModelReferential::ModelReferential(const QUuid& entityID, EntityTreePointer tree, AvatarData* avatar) : - Referential(MODEL, avatar), - _entityID(entityID), - _tree(tree) -{ - EntityItemPointer item = _tree->findEntityByID(_entityID); - if (!isValid() || item == NULL) { - qCDebug(interfaceapp) << "ModelReferential::constructor(): Not Valid"; - _isValid = false; - return; - } - - _lastRefDimension = item->getDimensions(); - _refRotation = item->getRotation(); - _refPosition = item->getPosition(); - - glm::quat refInvRot = glm::inverse(_refRotation); - _rotation = refInvRot * _avatar->getOrientation(); - _translation = refInvRot * (avatar->getPosition() - _refPosition); -} - -void ModelReferential::update() { - EntityItemPointer item = _tree->findEntityByID(_entityID); - if (!isValid() || item == NULL || _avatar == NULL) { - return; - } - - bool somethingChanged = false; - if (item->getDimensions() != _lastRefDimension) { - glm::vec3 oldDimension = _lastRefDimension; - _lastRefDimension = item->getDimensions(); - _translation *= _lastRefDimension / oldDimension; - somethingChanged = true; - } - if (item->getRotation() != _refRotation) { - _refRotation = item->getRotation(); - _avatar->setOrientation(_refRotation * _rotation, true); - somethingChanged = true; - } - if (item->getPosition() != _refPosition || somethingChanged) { - _refPosition = item->getPosition(); - _avatar->setPosition(_refPosition + _refRotation * _translation, true); - } -} - -int ModelReferential::packExtraData(unsigned char* destinationBuffer) const { - QByteArray encodedEntityID = _entityID.toRfc4122(); - memcpy(destinationBuffer, encodedEntityID.constData(), encodedEntityID.size()); - return encodedEntityID.size(); -} - -int ModelReferential::unpackExtraData(const unsigned char *sourceBuffer, int size) { - QByteArray encodedEntityID((const char*)sourceBuffer, NUM_BYTES_RFC4122_UUID); - _entityID = QUuid::fromRfc4122(encodedEntityID); - return NUM_BYTES_RFC4122_UUID; -} - -JointReferential::JointReferential(Referential* referential, EntityTreePointer tree, AvatarData* avatar) : - ModelReferential(referential, tree, avatar) -{ - _type = JOINT; - if (!isValid()) { - qCDebug(interfaceapp) << "JointReferential::copyConstructor(): Not Valid"; - return; - } - - EntityItemPointer item = _tree->findEntityByID(_entityID); - const Model* model = getModel(item); - if (isValid() && model != NULL && _jointIndex < (uint32_t)(model->getJointStateCount())) { - _lastRefDimension = item->getDimensions(); - model->getJointRotationInWorldFrame(_jointIndex, _refRotation); - model->getJointPositionInWorldFrame(_jointIndex, _refPosition); - } - update(); -} - -JointReferential::JointReferential(uint32_t jointIndex, const QUuid& entityID, EntityTreePointer tree, AvatarData* avatar) : - ModelReferential(entityID, tree, avatar), - _jointIndex(jointIndex) -{ - _type = JOINT; - EntityItemPointer item = _tree->findEntityByID(_entityID); - const Model* model = getModel(item); - if (!isValid() || model == NULL || _jointIndex >= (uint32_t)(model->getJointStateCount())) { - qCDebug(interfaceapp) << "JointReferential::constructor(): Not Valid"; - _isValid = false; - return; - } - - _lastRefDimension = item->getDimensions(); - model->getJointRotationInWorldFrame(_jointIndex, _refRotation); - model->getJointPositionInWorldFrame(_jointIndex, _refPosition); - - glm::quat refInvRot = glm::inverse(_refRotation); - _rotation = refInvRot * _avatar->getOrientation(); - // BUG! _refPosition is in domain units, but avatar is in meters - _translation = refInvRot * (avatar->getPosition() - _refPosition); -} - -void JointReferential::update() { - EntityItemPointer item = _tree->findEntityByID(_entityID); - const Model* model = getModel(item); - if (!isValid() || model == NULL || _jointIndex >= (uint32_t)(model->getJointStateCount())) { - return; - } - - bool somethingChanged = false; - if (item->getDimensions() != _lastRefDimension) { - glm::vec3 oldDimension = _lastRefDimension; - _lastRefDimension = item->getDimensions(); - _translation *= _lastRefDimension / oldDimension; - somethingChanged = true; - } - if (item->getRotation() != _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, true); - } -} - -const Model* JointReferential::getModel(EntityItemPointer item) { - EntityItemFBXService* fbxService = _tree->getFBXService(); - if (item != NULL && fbxService != NULL) { - return fbxService->getModelForEntityItem(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; -} diff --git a/interface/src/avatar/ModelReferential.h b/interface/src/avatar/ModelReferential.h deleted file mode 100644 index 810db4b8e5..0000000000 --- a/interface/src/avatar/ModelReferential.h +++ /dev/null @@ -1,48 +0,0 @@ -// -// 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 EntityTree; -class Model; - -class ModelReferential : public Referential { -public: - ModelReferential(Referential* ref, EntityTreePointer tree, AvatarData* avatar); - ModelReferential(const QUuid& entityID, EntityTreePointer tree, AvatarData* avatar); - virtual void update(); - -protected: - virtual int packExtraData(unsigned char* destinationBuffer) const; - virtual int unpackExtraData(const unsigned char* sourceBuffer, int size); - - QUuid _entityID; - EntityTreePointer _tree; -}; - -class JointReferential : public ModelReferential { -public: - JointReferential(Referential* ref, EntityTreePointer tree, AvatarData* avatar); - JointReferential(uint32_t jointIndex, const QUuid& entityID, EntityTreePointer tree, AvatarData* avatar); - virtual void update(); - -protected: - const Model* getModel(EntityItemPointer item); - virtual int packExtraData(unsigned char* destinationBuffer) const; - virtual int unpackExtraData(const unsigned char* sourceBuffer, int size); - - uint32_t _jointIndex; -}; - -#endif // hifi_ModelReferential_h diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5920543dca..3f6a6a1e77 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -43,7 +43,6 @@ #include "AvatarManager.h" #include "Environment.h" #include "Menu.h" -#include "ModelReferential.h" #include "MyAvatar.h" #include "Physics.h" #include "Recorder.h" @@ -209,10 +208,6 @@ void MyAvatar::update(float deltaTime) { _goToPending = false; } - if (_referential) { - _referential->update(); - } - Head* head = getHead(); head->relaxLean(deltaTime); updateFromTrackers(deltaTime); @@ -540,32 +535,6 @@ void MyAvatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { } } -void MyAvatar::clearReferential() { - changeReferential(NULL); -} - -bool MyAvatar::setModelReferential(const QUuid& id) { - EntityTreePointer tree = qApp->getEntities()->getTree(); - changeReferential(new ModelReferential(id, tree, this)); - if (_referential->isValid()) { - return true; - } else { - changeReferential(NULL); - return false; - } -} - -bool MyAvatar::setJointReferential(const QUuid& id, int jointIndex) { - EntityTreePointer tree = qApp->getEntities()->getTree(); - changeReferential(new JointReferential(jointIndex, id, tree, this)); - if (!_referential->isValid()) { - return true; - } else { - changeReferential(NULL); - return false; - } -} - bool MyAvatar::isRecording() { if (!_recorder) { return false; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 7347419fee..0c3b415177 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -199,10 +199,6 @@ public slots: Q_INVOKABLE void updateMotionBehaviorFromMenu(); - void clearReferential(); - bool setModelReferential(const QUuid& id); - bool setJointReferential(const QUuid& id, int jointIndex); - bool isRecording(); qint64 recorderElapsed(); void startRecording(); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index a698c6f374..a4d506a748 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -40,7 +40,6 @@ AvatarData::AvatarData() : _sessionUUID(), _position(0.0f), _handPosition(0.0f), - _referential(NULL), _bodyYaw(-90.0f), _bodyPitch(0.0f), _bodyRoll(0.0f), @@ -68,7 +67,6 @@ AvatarData::AvatarData() : AvatarData::~AvatarData() { delete _headData; delete _handData; - delete _referential; } // We cannot have a file-level variable (const or otherwise) in the header if it uses PathUtils, because that references Application, which will not yet initialized. @@ -82,40 +80,29 @@ const QUrl& AvatarData::defaultFullAvatarModelUrl() { } const glm::vec3& AvatarData::getPosition() const { - if (_referential) { - _referential->update(); - } return _position; } -void AvatarData::setPosition(const glm::vec3 position, bool overideReferential) { - if (!_referential || overideReferential) { - _position = position; - } +void AvatarData::setPosition(const glm::vec3 position) { + _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; - } +void AvatarData::setOrientation(const glm::quat& orientation) { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(orientation)); + _bodyPitch = eulerAngles.x; + _bodyYaw = eulerAngles.y; + _bodyRoll = eulerAngles.z; } // There are a number of possible strategies for this set of tools through endRender, below. void AvatarData::nextAttitude(glm::vec3 position, glm::quat orientation) { avatarLock.lock(); - setPosition(position, true); - setOrientation(orientation, true); + setPosition(position); + setOrientation(orientation); avatarLock.unlock(); } void AvatarData::startCapture() { @@ -145,31 +132,25 @@ void AvatarData::endRenderRun() { void AvatarData::startRender() { glm::vec3 pos = getPosition(); glm::quat rot = getOrientation(); - setPosition(_nextPosition, true); - setOrientation(_nextOrientation, true); + setPosition(_nextPosition); + setOrientation(_nextOrientation); updateAttitude(); _nextPosition = pos; _nextOrientation = rot; } void AvatarData::endRender() { - setPosition(_nextPosition, true); - setOrientation(_nextOrientation, true); + setPosition(_nextPosition); + setOrientation(_nextOrientation); updateAttitude(); _nextAllowed = true; } float AvatarData::getTargetScale() const { - if (_referential) { - _referential->update(); - } - return _targetScale; } void AvatarData::setTargetScale(float targetScale, bool overideReferential) { - if (!_referential || overideReferential) { - _targetScale = targetScale; - } + _targetScale = targetScale; } void AvatarData::setClampedTargetScale(float targetScale, bool overideReferential) { @@ -246,14 +227,14 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { setAtBit(bitItems, IS_EYE_TRACKER_CONNECTED); } // referential state - if (_referential != NULL && _referential->isValid()) { - setAtBit(bitItems, HAS_REFERENTIAL); + if (false) { + setAtBit(bitItems, HAS_REFERENTIAL); // XXX leaving this for later use } *destinationBuffer++ = bitItems; - // Add referential - if (_referential != NULL && _referential->isValid()) { - destinationBuffer += _referential->packReferential(destinationBuffer); + // XXX leaving this for later use + if (false) { + // destinationBuffer += _referential->packReferential(destinationBuffer); } // If it is connected, pack up the data @@ -572,21 +553,10 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { _headData->_isEyeTrackerConnected = oneAtBit(bitItems, IS_EYE_TRACKER_CONNECTED); bool hasReferential = oneAtBit(bitItems, HAS_REFERENTIAL); - // Referential + // XXX leaving this for later use 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->_isFaceTrackerConnected) { float leftEyeBlink, rightEyeBlink, averageLoudness, browAudioLift; minPossibleSize += sizeof(leftEyeBlink) + sizeof(rightEyeBlink) + sizeof(averageLoudness) + sizeof(browAudioLift); @@ -779,10 +749,6 @@ int AvatarData::getReceiveRate() const { return lrint(1.0f / _averageBytesReceived.getEventDeltaAverage()); } -bool AvatarData::hasReferential() { - return _referential != NULL; -} - bool AvatarData::isPlaying() { return _player && _player->isPlaying(); } @@ -946,11 +912,6 @@ void AvatarData::stopPlaying() { } } -void AvatarData::changeReferential(Referential* ref) { - delete _referential; - _referential = ref; -} - void AvatarData::setJointData(int index, const glm::quat& rotation, const glm::vec3& translation) { if (index == -1) { return; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 3abd63bf63..8f5416e4fd 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -57,7 +57,6 @@ typedef unsigned long long quint64; #include "PathUtils.h" #include "Player.h" #include "Recorder.h" -#include "Referential.h" using AvatarSharedPointer = std::shared_ptr; using AvatarWeakPointer = std::weak_ptr; @@ -174,7 +173,7 @@ public: const QUuid& getSessionUUID() const { return _sessionUUID; } const glm::vec3& getPosition() const; - virtual void setPosition(const glm::vec3 position, bool overideReferential = false); + virtual void setPosition(const glm::vec3 position); glm::vec3 getHandPosition() const; void setHandPosition(const glm::vec3& handPosition); @@ -199,7 +198,7 @@ public: void setBodyRoll(float bodyRoll) { _bodyRoll = bodyRoll; } glm::quat getOrientation() const; - virtual void setOrientation(const glm::quat& orientation, bool overideReferential = false); + virtual void setOrientation(const glm::quat& orientation); void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time. void startCapture(); // start/end of the period in which the latest values are about to be captured for camera, etc. @@ -319,7 +318,6 @@ public: void setOwningAvatarMixer(const QWeakPointer& owningAvatarMixer) { _owningAvatarMixer = owningAvatarMixer; } const AABox& getLocalAABox() const { return _localAABox; } - const Referential* getReferential() const { return _referential; } int getUsecsSinceLastUpdate() const { return _averageBytesReceived.getUsecsSinceLastEvent(); } int getAverageBytesReceivedPerSecond() const; @@ -339,7 +337,6 @@ public slots: void setBillboardFromNetworkReply(); void setJointMappingsFromNetworkReply(); void setSessionUUID(const QUuid& sessionUUID) { _sessionUUID = sessionUUID; } - bool hasReferential(); bool isPlaying(); bool isPaused(); @@ -369,8 +366,6 @@ protected: glm::vec3 _position = START_LOCATION; glm::vec3 _handPosition; - Referential* _referential; - // Body rotation float _bodyYaw; // degrees float _bodyPitch; // degrees @@ -421,7 +416,6 @@ protected: /// Loads the joint indices, names from the FST file (if any) virtual void updateJointMappings(); - void changeReferential(Referential* ref); glm::vec3 _velocity; glm::vec3 _targetVelocity; diff --git a/libraries/avatars/src/Referential.cpp b/libraries/avatars/src/Referential.cpp deleted file mode 100644 index 0683580093..0000000000 --- a/libraries/avatars/src/Referential.cpp +++ /dev/null @@ -1,109 +0,0 @@ -// -// 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 "AvatarLogging.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 - qCDebug(avatars) << "[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); - return destinationBuffer - startPosition; -} - -int Referential::unpack(const unsigned char* sourceBuffer) { - const unsigned char* startPosition = sourceBuffer; - _type = (Type)*sourceBuffer++; - if (_type < 0 || _type >= NUM_TYPES) { - _type = UNKNOWN; - } - memcpy(&_version, sourceBuffer, sizeof(_version)); - sourceBuffer += sizeof(_version); - - sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, _translation, 0); - sourceBuffer += unpackOrientationQuatFromBytes(sourceBuffer, _rotation); - 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.append(reinterpret_cast(sourceBuffer), size); - return size; -} - diff --git a/libraries/avatars/src/Referential.h b/libraries/avatars/src/Referential.h deleted file mode 100644 index 70edecda62..0000000000 --- a/libraries/avatars/src/Referential.h +++ /dev/null @@ -1,73 +0,0 @@ -// -// 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_TYPES - }; - - 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; } - 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; // position of object in world-frame - glm::quat _refRotation; // rotation of object in world-frame - glm::vec3 _lastRefDimension; // dimension of object when _translation was last computed - - glm::vec3 _translation; // offset of avatar in object local-frame - glm::quat _rotation; // rotation of avatar in object local-frame -}; - - -#endif // hifi_Referential_h diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 5b262b273b..d58c26e72c 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -46,7 +46,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _lastEditedFromRemoteInRemoteTime(0), _created(UNKNOWN_CREATED_TIME), _changedOnServer(0), - _transform(), _glowLevel(ENTITY_ITEM_DEFAULT_GLOW_LEVEL), _localRenderAlpha(ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA), _density(ENTITY_ITEM_DEFAULT_DENSITY), @@ -1516,7 +1515,6 @@ bool EntityItem::addAction(EntitySimulation* simulation, EntityActionPointer act } bool EntityItem::addActionInternal(EntitySimulation* simulation, EntityActionPointer action) { - assertLocked(); assert(action); assert(simulation); auto actionOwnerEntity = action->getOwnerEntity().lock(); @@ -1570,7 +1568,6 @@ bool EntityItem::removeAction(EntitySimulation* simulation, const QUuid& actionI } bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulation* simulation) { - assertWriteLocked(); _previouslyDeletedActions.insert(actionID, usecTimestampNow()); if (_objectActions.contains(actionID)) { if (!simulation) { @@ -1615,7 +1612,6 @@ bool EntityItem::clearActions(EntitySimulation* simulation) { void EntityItem::deserializeActions() { - assertUnlocked(); withWriteLock([&] { deserializeActionsInternal(); }); @@ -1623,8 +1619,6 @@ void EntityItem::deserializeActions() { void EntityItem::deserializeActionsInternal() { - assertWriteLocked(); - quint64 now = usecTimestampNow(); if (!_element) { @@ -1704,7 +1698,6 @@ void EntityItem::deserializeActionsInternal() { } void EntityItem::checkWaitingToRemove(EntitySimulation* simulation) { - assertLocked(); foreach(QUuid actionID, _actionsToRemove) { removeActionInternal(actionID, simulation); } @@ -1712,14 +1705,12 @@ void EntityItem::checkWaitingToRemove(EntitySimulation* simulation) { } void EntityItem::setActionData(QByteArray actionData) { - assertUnlocked(); withWriteLock([&] { setActionDataInternal(actionData); }); } void EntityItem::setActionDataInternal(QByteArray actionData) { - assertWriteLocked(); if (_allActionsDataCache != actionData) { _allActionsDataCache = actionData; deserializeActionsInternal(); @@ -1728,8 +1719,6 @@ void EntityItem::setActionDataInternal(QByteArray actionData) { } void EntityItem::serializeActions(bool& success, QByteArray& result) const { - assertLocked(); - if (_objectActions.size() == 0) { success = true; result.clear(); @@ -1771,7 +1760,6 @@ const QByteArray EntityItem::getActionDataInternal() const { const QByteArray EntityItem::getActionData() const { QByteArray result; - assertUnlocked(); withReadLock([&] { result = getActionDataInternal(); }); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index f438e3f28b..e85112d4ef 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "EntityItemID.h" #include "EntityItemPropertiesDefaults.h" @@ -71,31 +72,10 @@ const float ACTIVATION_ANGULAR_VELOCITY_DELTA = 0.03f; #define debugTimeOnly(T) qPrintable(QString("%1").arg(T, 16, 10)) #define debugTreeVector(V) V << "[" << V << " in meters ]" -//#if DEBUG -// #define assertLocked() assert(isLocked()) -//#else -// #define assertLocked() -//#endif -// -//#if DEBUG -// #define assertWriteLocked() assert(isWriteLocked()) -//#else -// #define assertWriteLocked() -//#endif -// -//#if DEBUG -// #define assertUnlocked() assert(isUnlocked()) -//#else -// #define assertUnlocked() -//#endif -#define assertLocked() -#define assertUnlocked() -#define assertWriteLocked() - /// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate /// one directly, instead you must only construct one of it's derived classes with additional features. -class EntityItem : public std::enable_shared_from_this, public ReadWriteLockable { +class EntityItem : public std::enable_shared_from_this, public SpatiallyNestable, public ReadWriteLockable { // These two classes manage lists of EntityItem pointers and must be able to cleanup pointers when an EntityItem is deleted. // To make the cleanup robust each EntityItem has backpointers to its manager classes (which are only ever set/cleared by // the managers themselves, hence they are fiends) whose NULL status can be used to determine which managers still need to @@ -208,11 +188,11 @@ public: inline void setTransform(const Transform& transform) { _transform = transform; requiresRecalcBoxes(); } /// Position in meters (-TREE_SCALE - TREE_SCALE) - inline const glm::vec3& getPosition() const { return _transform.getTranslation(); } - inline void setPosition(const glm::vec3& value) { _transform.setTranslation(value); requiresRecalcBoxes(); } + virtual const glm::vec3& getPosition() const { return SpatiallyNestable::getPosition(); } + virtual void setPosition(const glm::vec3& value) { SpatiallyNestable::setPosition(value); requiresRecalcBoxes(); } - inline const glm::quat& getRotation() const { return _transform.getRotation(); } - inline void setRotation(const glm::quat& rotation) { _transform.setRotation(rotation); requiresRecalcBoxes(); } + virtual const glm::quat& getRotation() const { return SpatiallyNestable::getOrientation(); } + virtual void setRotation(const glm::quat& rotation) { SpatiallyNestable::setOrientation(rotation); requiresRecalcBoxes(); } inline void requiresRecalcBoxes() { _recalcAABox = true; _recalcMinAACube = true; _recalcMaxAACube = true; } @@ -428,7 +408,6 @@ protected: quint64 _created; quint64 _changedOnServer; - Transform _transform; mutable AABox _cachedAABox; mutable AACube _maxAACube; mutable AACube _minAACube; From 37923e81bbc26db526fd0fe59a7d39faffe18911 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 18 Oct 2015 08:18:10 -0700 Subject: [PATCH 006/401] make SpatiallyNestable::_transform private --- libraries/entities/src/EntityItem.cpp | 8 ++++---- libraries/entities/src/EntityItem.h | 5 ++--- libraries/shared/src/SpatiallyNestable.cpp | 12 ++++++++++++ libraries/shared/src/SpatiallyNestable.h | 18 +++++++++++++++--- 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index d58c26e72c..3c3f7fd0f1 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -79,9 +79,9 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _simulated(false) { // explicitly set transform parts to set dirty flags used by batch rendering - _transform.setTranslation(ENTITY_ITEM_DEFAULT_POSITION); - _transform.setRotation(ENTITY_ITEM_DEFAULT_ROTATION); - _transform.setScale(ENTITY_ITEM_DEFAULT_DIMENSIONS); + setPosition(ENTITY_ITEM_DEFAULT_POSITION); + setRotation(ENTITY_ITEM_DEFAULT_ROTATION); + setScale(ENTITY_ITEM_DEFAULT_DIMENSIONS); quint64 now = usecTimestampNow(); _lastSimulated = now; _lastUpdated = now; @@ -1176,7 +1176,7 @@ void EntityItem::setDimensions(const glm::vec3& value) { if (value.x <= 0.0f || value.y <= 0.0f || value.z <= 0.0f) { return; } - _transform.setScale(value); + setScale(value); requiresRecalcBoxes(); } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index e85112d4ef..4d56b92171 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -184,8 +184,7 @@ public: const Transform getTransformToCenter() const; void setTranformToCenter(const Transform& transform); - inline const Transform& getTransform() const { return _transform; } - inline void setTransform(const Transform& transform) { _transform = transform; requiresRecalcBoxes(); } + virtual void setTransform(const Transform& transform) { SpatiallyNestable::setTransform(transform); requiresRecalcBoxes(); } /// Position in meters (-TREE_SCALE - TREE_SCALE) virtual const glm::vec3& getPosition() const { return SpatiallyNestable::getPosition(); } @@ -204,7 +203,7 @@ public: void setDescription(QString value) { _description = value; } /// Dimensions in meters (0.0 - TREE_SCALE) - inline const glm::vec3& getDimensions() const { return _transform.getScale(); } + inline const glm::vec3& getDimensions() const { return getScale(); } virtual void setDimensions(const glm::vec3& value); float getGlowLevel() const { return _glowLevel; } diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 5e14f398ea..a3e427caa8 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -35,3 +35,15 @@ void SpatiallyNestable::setOrientation(const glm::quat& orientation) { const Transform& SpatiallyNestable::getTransform() const { return _transform; } + +void SpatiallyNestable::setTransform(const Transform& transform) { + _transform = transform; +} + +const glm::vec3& SpatiallyNestable::getScale() const { + return _transform.getScale(); +} + +void SpatiallyNestable::setScale(const glm::vec3& scale) { + _transform.setScale(scale); +} diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index dd57f27477..294450a980 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -27,20 +27,32 @@ public: SpatiallyNestable(); virtual ~SpatiallyNestable() { } + // world frame + virtual const Transform& getTransform() const; + virtual void setTransform(const Transform& transform); + virtual const glm::vec3& getPosition() const; virtual void setPosition(const glm::vec3& position); + virtual const glm::quat& getOrientation() const; virtual void setOrientation(const glm::quat& orientation); - virtual const Transform& getTransform() const; + + virtual const glm::vec3& getScale() const; + virtual void setScale(const glm::vec3& scale); + + // model frame + // ... + protected: - Transform _transform; - QUuid _parentID; // what is this thing's transform relative to? int _parentJointIndex; // which joint of the parent is this relative to? SpatiallyNestableWeakPointer _parent; QVector _children; + +private: + Transform _transform; }; From a78f2a95777603a0764da4cc7bca92ba973d652c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 18 Oct 2015 09:48:46 -0700 Subject: [PATCH 007/401] have avatar make use of SpatiallyNestable --- interface/src/Application.cpp | 4 +- interface/src/avatar/Avatar.cpp | 74 +++++++++---------- interface/src/avatar/Avatar.h | 5 +- interface/src/avatar/AvatarManager.cpp | 2 +- interface/src/avatar/Hand.cpp | 2 +- interface/src/avatar/MyAvatar.cpp | 29 ++++---- interface/src/ui/ApplicationCompositor.cpp | 2 +- interface/src/ui/PreferencesDialog.cpp | 2 +- interface/src/ui/overlays/OverlaysPayload.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 70 +++++++++++------- libraries/avatars/src/AvatarData.h | 29 +++----- 11 files changed, 112 insertions(+), 109 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1b6be53876..9b5b83492c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1136,7 +1136,7 @@ void Application::paintGL() { * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)) * hmdRotation); glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix()); _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + glm::vec3(0, _raiseMirror * myAvatar->getScale(), 0) + + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))) * hmdOffset); @@ -1144,7 +1144,7 @@ void Application::paintGL() { _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + glm::vec3(0, _raiseMirror * myAvatar->getScale(), 0) + + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); } diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 432149d907..92493ab23f 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -90,7 +90,6 @@ Avatar::Avatar(RigPointer rig) : _angularAcceleration(0.0f), _lastOrientation(), _leanScale(0.5f), - _scale(1.0f), _worldUpDirection(DEFAULT_UP_DIRECTION), _moving(false), _initialized(false), @@ -100,6 +99,7 @@ Avatar::Avatar(RigPointer rig) : // we may have been created in the network thread, but we live in the main thread moveToThread(qApp->thread()); + setAvatarScale(1.0f); // give the pointer to our head to inherited _headData variable from AvatarData _headData = static_cast(new Head(this)); _handData = static_cast(new Hand(this)); @@ -124,12 +124,12 @@ void Avatar::init() { glm::vec3 Avatar::getChestPosition() const { // for now, let's just assume that the "chest" is halfway between the root and the neck glm::vec3 neckPosition; - return _skeletonModel.getNeckPosition(neckPosition) ? (_position + neckPosition) * 0.5f : _position; + return _skeletonModel.getNeckPosition(neckPosition) ? (getPosition() + neckPosition) * 0.5f : getPosition(); } glm::vec3 Avatar::getNeckPosition() const { glm::vec3 neckPosition; - return _skeletonModel.getNeckPosition(neckPosition) ? neckPosition : _position; + return _skeletonModel.getNeckPosition(neckPosition) ? neckPosition : getPosition(); } @@ -143,14 +143,14 @@ AABox Avatar::getBounds() const { float Avatar::getLODDistance() const { return DependencyManager::get()->getAvatarLODDistanceMultiplier() * - glm::distance(qApp->getCamera()->getPosition(), _position) / _scale; + glm::distance(qApp->getCamera()->getPosition(), getPosition()) / getAvatarScale(); } void Avatar::simulate(float deltaTime) { PerformanceTimer perfTimer("simulate"); - if (_scale != _targetScale) { - setScale(_targetScale); + if (getAvatarScale() != _targetScale) { + setAvatarScale(_targetScale); } // update the billboard render flag @@ -165,7 +165,7 @@ void Avatar::simulate(float deltaTime) { // simple frustum check float boundingRadius = getBillboardSize(); - bool inViewFrustum = qApp->getViewFrustum()->sphereInFrustum(_position, boundingRadius) != + bool inViewFrustum = qApp->getViewFrustum()->sphereInFrustum(getPosition(), boundingRadius) != ViewFrustum::OUTSIDE; { @@ -189,11 +189,11 @@ void Avatar::simulate(float deltaTime) { } { PerformanceTimer perfTimer("head"); - glm::vec3 headPosition = _position; + glm::vec3 headPosition = getPosition(); _skeletonModel.getHeadPosition(headPosition); Head* head = getHead(); head->setPosition(headPosition); - head->setScale(_scale); + head->setScale(getAvatarScale()); head->simulate(deltaTime, false, _shouldRenderBillboard); } } @@ -226,7 +226,7 @@ bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) { glm::vec3 theirLookAt = dynamic_pointer_cast(avatar)->getHead()->getLookAtPosition(); glm::vec3 myEyePosition = getHead()->getEyePosition(); - return glm::distance(theirLookAt, myEyePosition) <= (HEAD_SPHERE_RADIUS * getScale()); + return glm::distance(theirLookAt, myEyePosition) <= (HEAD_SPHERE_RADIUS * getAvatarScale()); } void Avatar::slamPosition(const glm::vec3& newPosition) { @@ -237,7 +237,7 @@ void Avatar::slamPosition(const glm::vec3& newPosition) { } void Avatar::applyPositionDelta(const glm::vec3& delta) { - _position += delta; + setPosition(getPosition() + delta); _positionDeltaAccumulator += delta; } @@ -307,7 +307,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { auto& batch = *renderArgs->_batch; - if (glm::distance(DependencyManager::get()->getMyAvatar()->getPosition(), _position) < 10.0f) { + if (glm::distance(DependencyManager::get()->getMyAvatar()->getPosition(), getPosition()) < 10.0f) { auto geometryCache = DependencyManager::get(); auto deferredLighting = DependencyManager::get(); @@ -405,7 +405,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { const float BASE_LIGHT_DISTANCE = 2.0f; const float LIGHT_EXPONENT = 1.0f; const float LIGHT_CUTOFF = glm::radians(80.0f); - float distance = BASE_LIGHT_DISTANCE * _scale; + float distance = BASE_LIGHT_DISTANCE * getAvatarScale(); glm::vec3 position = glm::mix(_skeletonModel.getTranslation(), getHead()->getFaceModel().getTranslation(), 0.9f); glm::quat orientation = getOrientation(); foreach (const AvatarManager::LocalLight& light, DependencyManager::get()->getLocalLights()) { @@ -435,7 +435,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { static const float INDICATOR_OFFSET = 0.22f; static const float INDICATOR_RADIUS = 0.03f; static const glm::vec4 LOOK_AT_INDICATOR_COLOR = { 0.8f, 0.0f, 0.0f, 0.75f }; - glm::vec3 position = glm::vec3(_position.x, getDisplayNamePosition().y + INDICATOR_OFFSET, _position.z); + glm::vec3 position = glm::vec3(getPosition().x, getDisplayNamePosition().y + INDICATOR_OFFSET, getPosition().z); Transform transform; transform.setTranslation(position); transform.postScale(INDICATOR_RADIUS); @@ -467,7 +467,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { } DependencyManager::get()->renderSolidSphereInstance(batch, - Transform(transform).postScale(eyeDiameter * _scale / 2.0f + RADIUS_INCREMENT), + Transform(transform).postScale(eyeDiameter * getAvatarScale() / 2.0f + RADIUS_INCREMENT), glm::vec4(LOOKING_AT_ME_COLOR, alpha)); position = getHead()->getRightEyePosition(); @@ -477,7 +477,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { eyeDiameter = DEFAULT_EYE_DIAMETER; } DependencyManager::get()->renderSolidSphereInstance(batch, - Transform(transform).postScale(eyeDiameter * _scale / 2.0f + RADIUS_INCREMENT), + Transform(transform).postScale(eyeDiameter * getAvatarScale() / 2.0f + RADIUS_INCREMENT), glm::vec4(LOOKING_AT_ME_COLOR, alpha)); } @@ -507,7 +507,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { Transform transform; - transform.setTranslation(_position); + transform.setTranslation(getPosition()); transform.setScale(height); transform.postScale(sphereRadius); DependencyManager::get()->renderSolidSphereInstance(batch, @@ -610,9 +610,9 @@ void Avatar::simulateAttachments(float deltaTime) { glm::quat jointRotation; if (_skeletonModel.getJointPositionInWorldFrame(jointIndex, jointPosition) && _skeletonModel.getJointCombinedRotation(jointIndex, jointRotation)) { - model->setTranslation(jointPosition + jointRotation * attachment.translation * _scale); + model->setTranslation(jointPosition + jointRotation * attachment.translation * getAvatarScale()); model->setRotation(jointRotation * attachment.rotation); - model->setScaleToFit(true, _scale * attachment.scale, true); // hack to force rescale + model->setScaleToFit(true, getAvatarScale() * attachment.scale, true); // hack to force rescale model->setSnapModelToCenter(false); // hack to force resnap model->setSnapModelToCenter(true); model->simulate(deltaTime); @@ -639,14 +639,14 @@ void Avatar::renderBillboard(RenderArgs* renderArgs) { } // rotate about vertical to face the camera glm::quat rotation = getOrientation(); - glm::vec3 cameraVector = glm::inverse(rotation) * (qApp->getCamera()->getPosition() - _position); + glm::vec3 cameraVector = glm::inverse(rotation) * (qApp->getCamera()->getPosition() - getPosition()); rotation = rotation * glm::angleAxis(atan2f(-cameraVector.x, -cameraVector.z), glm::vec3(0.0f, 1.0f, 0.0f)); // compute the size from the billboard camera parameters and scale float size = getBillboardSize(); Transform transform; - transform.setTranslation(_position); + transform.setTranslation(getPosition()); transform.setRotation(rotation); transform.setScale(size); @@ -663,7 +663,7 @@ void Avatar::renderBillboard(RenderArgs* renderArgs) { } float Avatar::getBillboardSize() const { - return _scale * BILLBOARD_DISTANCE * glm::tan(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f)); + return getAvatarScale() * BILLBOARD_DISTANCE * glm::tan(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f)); } #ifdef DEBUG @@ -700,7 +700,7 @@ glm::vec3 Avatar::getDisplayNamePosition() const { DEBUG_VALUE("_position =", _position); DEBUG_VALUE("billboardSize =", billboardSize); - namePosition = _position + bodyUpDirection * (billboardSize * HEAD_PROPORTION); + namePosition = getPosition() + bodyUpDirection * (billboardSize * HEAD_PROPORTION); } if (glm::any(glm::isnan(namePosition)) || glm::any(glm::isinf(namePosition))) { @@ -803,7 +803,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, co } void Avatar::setSkeletonOffset(const glm::vec3& offset) { - const float MAX_OFFSET_LENGTH = _scale * 0.5f; + const float MAX_OFFSET_LENGTH = getAvatarScale() * 0.5f; float offsetLength = glm::length(offset); if (offsetLength > MAX_OFFSET_LENGTH) { _skeletonOffset = (MAX_OFFSET_LENGTH / offsetLength) * offset; @@ -816,7 +816,7 @@ glm::vec3 Avatar::getSkeletonPosition() const { // The avatar is rotated PI about the yAxis, so we have to correct for it // to get the skeleton offset contribution in the world-frame. const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - return _position + getOrientation() * FLIP * _skeletonOffset; + return getPosition() + getOrientation() * FLIP * _skeletonOffset; } QVector Avatar::getJointRotations() const { @@ -941,7 +941,7 @@ void Avatar::setJointModelPositionAndOrientation(const QString& name, glm::vec3 void Avatar::scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const { //Scale a world space vector as if it was relative to the position - positionToScale = _position + _scale * (positionToScale - _position); + positionToScale = getPosition() + getAvatarScale() * (positionToScale - getPosition()); } void Avatar::setFaceModelURL(const QUrl& faceModelURL) { @@ -981,7 +981,7 @@ void Avatar::setAttachmentData(const QVector& attachmentData) { for (int i = 0; i < attachmentData.size(); i++) { _attachmentModels[i]->setURL(attachmentData.at(i).modelURL); _attachmentModels[i]->setSnapModelToCenter(true); - _attachmentModels[i]->setScaleToFit(true, _scale * _attachmentData.at(i).scale); + _attachmentModels[i]->setScaleToFit(true, getAvatarScale() * _attachmentData.at(i).scale); } } @@ -1000,12 +1000,12 @@ int Avatar::parseDataFromBuffer(const QByteArray& buffer) { } // change in position implies movement - glm::vec3 oldPosition = _position; + glm::vec3 oldPosition = getPosition(); int bytesRead = AvatarData::parseDataFromBuffer(buffer); const float MOVE_DISTANCE_THRESHOLD = 0.001f; - _moving = glm::distance(oldPosition, _position) > MOVE_DISTANCE_THRESHOLD; + _moving = glm::distance(oldPosition, getPosition()) > MOVE_DISTANCE_THRESHOLD; if (_moving && _motionState) { _motionState->addDirtyFlags(Simulation::DIRTY_POSITION); } @@ -1068,12 +1068,12 @@ void Avatar::renderJointConnectingCone(gpu::Batch& batch, glm::vec3 position1, g } } -void Avatar::setScale(float scale) { - _scale = scale; - - if (_targetScale * (1.0f - RESCALING_TOLERANCE) < _scale && - _scale < _targetScale * (1.0f + RESCALING_TOLERANCE)) { - _scale = _targetScale; +void Avatar::setAvatarScale(float scale) { + if (_targetScale * (1.0f - RESCALING_TOLERANCE) < scale && + scale < _targetScale * (1.0f + RESCALING_TOLERANCE)) { + setScale(glm::vec3(_targetScale)); + } else { + setScale(glm::vec3(scale)); } } @@ -1088,7 +1088,7 @@ float Avatar::getHeadHeight() const { // HACK: We have a really odd case when fading out for some models where this value explodes float result = extents.maximum.y - extents.minimum.y; - if (result >= 0.0f && result < 100.0f * _scale ) { + if (result >= 0.0f && result < 100.0f * getAvatarScale() ) { return result; } } @@ -1096,7 +1096,7 @@ float Avatar::getHeadHeight() const { extents = _skeletonModel.getMeshExtents(); glm::vec3 neckPosition; if (!extents.isEmpty() && extents.isValid() && _skeletonModel.getNeckPosition(neckPosition)) { - return extents.maximum.y / 2.0f - neckPosition.y + _position.y; + return extents.maximum.y / 2.0f - neckPosition.y + getPosition().y; } const float DEFAULT_HEAD_HEIGHT = 0.25f; diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 9a46a145c2..2b7d27b2e3 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -103,7 +103,7 @@ public: const SkeletonModel& getSkeletonModel() const { return _skeletonModel; } const QVector& getAttachmentModels() const { return _attachmentModels; } glm::vec3 getChestPosition() const; - float getScale() const { return _scale; } + float getAvatarScale() const { return getScale().y; } const Head* getHead() const { return static_cast(_headData); } Head* getHead() { return static_cast(_headData); } Hand* getHand() { return static_cast(_handData); } @@ -207,7 +207,6 @@ protected: glm::quat _lastOrientation; float _leanScale; - float _scale; glm::vec3 _worldUpDirection; float _stringLength; bool _moving; ///< set when position is changing @@ -219,7 +218,7 @@ protected: glm::vec3 getBodyUpDirection() const { return getOrientation() * IDENTITY_UP; } glm::vec3 getBodyFrontDirection() const { return getOrientation() * IDENTITY_FRONT; } glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const; - void setScale(float scale); + void setAvatarScale(float scale); void measureMotionDerivatives(float deltaTime); float getSkeletonHeight() const; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 5f0ac435e0..f42cdc200b 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -151,7 +151,7 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { while (fadingIterator != _avatarFades.end()) { auto avatar = std::static_pointer_cast(*fadingIterator); avatar->startUpdate(); - avatar->setTargetScale(avatar->getScale() * SHRINK_RATE, true); + avatar->setTargetScale(avatar->getAvatarScale() * SHRINK_RATE, true); if (avatar->getTargetScale() < MIN_FADE_SCALE) { avatar->removeFromScene(*fadingIterator, scene, pendingChanges); fadingIterator = _avatarFades.erase(fadingIterator); diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 0eeb7222b6..a8d09aff69 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -43,7 +43,7 @@ void Hand::simulate(float deltaTime, bool isMine) { void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) { float avatarScale = 1.0f; if (_owningAvatar) { - avatarScale = _owningAvatar->getScale(); + avatarScale = _owningAvatar->getAvatarScale(); } const float alpha = 1.0f; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 3f6a6a1e77..8b9d89eeaa 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -129,11 +129,11 @@ QByteArray MyAvatar::toByteArray(bool cullSmallChanges, bool sendAll) { CameraMode mode = qApp->getCamera()->getMode(); if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) { // fake the avatar position that is sent up to the AvatarMixer - glm::vec3 oldPosition = _position; - _position = getSkeletonPosition(); + glm::vec3 oldPosition = getPosition(); + setPosition(getSkeletonPosition()); QByteArray array = AvatarData::toByteArray(cullSmallChanges, sendAll); // copy the correct position back - _position = oldPosition; + setPosition(oldPosition); return array; } return AvatarData::toByteArray(cullSmallChanges, sendAll); @@ -228,9 +228,9 @@ void MyAvatar::simulate(float deltaTime) { _player->play(); } - if (_scale != _targetScale) { - float scale = (1.0f - SMOOTHING_RATIO) * _scale + SMOOTHING_RATIO * _targetScale; - setScale(scale); + if (getAvatarScale() != _targetScale) { + float scale = (1.0f - SMOOTHING_RATIO) * getAvatarScale() + SMOOTHING_RATIO * _targetScale; + setAvatarScale(scale); } { @@ -277,10 +277,10 @@ void MyAvatar::simulate(float deltaTime) { Head* head = getHead(); glm::vec3 headPosition; if (!_skeletonModel.getHeadPosition(headPosition)) { - headPosition = _position; + headPosition = getPosition(); } head->setPosition(headPosition); - head->setScale(_scale); + head->setScale(getAvatarScale()); head->simulate(deltaTime, true); } @@ -846,7 +846,7 @@ void MyAvatar::loadData() { _leanScale = loadSetting(settings, "leanScale", 0.05f); _targetScale = loadSetting(settings, "scale", 1.0f); - setScale(_scale); + setAvatarScale(getAvatarScale()); _animGraphUrl = settings.value("animGraphURL", "").toString(); _fullAvatarURLFromPreferences = settings.value("fullAvatarURL", AvatarData::defaultFullAvatarModelUrl()).toUrl(); @@ -992,7 +992,8 @@ void MyAvatar::updateLookAtTargetAvatar() { bool isCurrentTarget = avatar->getIsLookAtTarget(); float distanceTo = glm::length(avatar->getHead()->getEyePosition() - cameraPosition); avatar->setIsLookAtTarget(false); - if (!avatar->isMyAvatar() && avatar->isInitialized() && (distanceTo < GREATEST_LOOKING_AT_DISTANCE * getScale())) { + if (!avatar->isMyAvatar() && avatar->isInitialized() && + (distanceTo < GREATEST_LOOKING_AT_DISTANCE * getAvatarScale())) { float angleTo = glm::angle(lookForward, glm::normalize(avatar->getHead()->getEyePosition() - cameraPosition)); if (angleTo < (smallestAngleTo * (isCurrentTarget ? KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR : 1.0f))) { _lookAtTargetAvatar = avatarPointer; @@ -1228,7 +1229,7 @@ glm::vec3 MyAvatar::getSkeletonPosition() const { // The avatar is rotated PI about the yAxis, so we have to correct for it // to get the skeleton offset contribution in the world-frame. const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - return _position + getOrientation() * FLIP * _skeletonOffset; + return getPosition() + getOrientation() * FLIP * _skeletonOffset; } return Avatar::getPosition(); } @@ -1464,7 +1465,7 @@ const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f; bool MyAvatar::cameraInsideHead() const { const Head* head = getHead(); const glm::vec3 cameraPosition = qApp->getCamera()->getPosition(); - return glm::length(cameraPosition - head->getEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * _scale); + return glm::length(cameraPosition - head->getEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getAvatarScale()); } bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const { @@ -1618,11 +1619,11 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe if (isHovering) { // we're flying --> complex acceleration curve with high max speed float motorSpeed = glm::length(_keyboardMotorVelocity); - float finalMaxMotorSpeed = _scale * MAX_KEYBOARD_MOTOR_SPEED; + float finalMaxMotorSpeed = getAvatarScale() * MAX_KEYBOARD_MOTOR_SPEED; float speedGrowthTimescale = 2.0f; float speedIncreaseFactor = 1.8f; motorSpeed *= 1.0f + glm::clamp(deltaTime / speedGrowthTimescale , 0.0f, 1.0f) * speedIncreaseFactor; - const float maxBoostSpeed = _scale * MAX_BOOST_SPEED; + const float maxBoostSpeed = getAvatarScale() * MAX_BOOST_SPEED; if (motorSpeed < maxBoostSpeed) { // an active keyboard motor should never be slower than this float boostCoefficient = (maxBoostSpeed - motorSpeed) / maxBoostSpeed; diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index 4e5dd0da0c..c6164978ef 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -416,7 +416,7 @@ bool ApplicationCompositor::calculateRayUICollisionPoint(const glm::vec3& positi glm::vec3 relativeDirection = glm::normalize(inverseOrientation * direction); float t; - if (raySphereIntersect(relativeDirection, relativePosition, _oculusUIRadius * myAvatar->getScale(), &t)){ + if (raySphereIntersect(relativeDirection, relativePosition, _oculusUIRadius * myAvatar->getAvatarScale(), &t)){ result = position + direction * t; return true; } diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 4ba248c76c..3a222ce15a 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -189,7 +189,7 @@ void PreferencesDialog::loadPreferences() { ui.leanScaleSpin->setValue(myAvatar->getLeanScale()); - ui.avatarScaleSpin->setValue(myAvatar->getScale()); + ui.avatarScaleSpin->setValue(myAvatar->getAvatarScale()); ui.avatarAnimationEdit->setText(myAvatar->getAnimGraphUrl()); ui.maxOctreePPSSpin->setValue(qApp->getMaxOctreePacketsPerSecond()); diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp index 02d432ea81..1b1c48c3ca 100644 --- a/interface/src/ui/overlays/OverlaysPayload.cpp +++ b/interface/src/ui/overlays/OverlaysPayload.cpp @@ -68,7 +68,7 @@ namespace render { glm::vec3 myAvatarPosition = avatar->getPosition(); float angle = glm::degrees(glm::angle(myAvatarRotation)); glm::vec3 axis = glm::axis(myAvatarRotation); - float myAvatarScale = avatar->getScale(); + float myAvatarScale = avatar->getAvatarScale(); Transform transform = Transform(); transform.setTranslation(myAvatarPosition); transform.setRotation(glm::angleAxis(angle, axis)); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index a4d506a748..6f4c89abe7 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -38,11 +38,7 @@ const glm::vec3 DEFAULT_LOCAL_AABOX_SCALE(1.0f); AvatarData::AvatarData() : _sessionUUID(), - _position(0.0f), _handPosition(0.0f), - _bodyYaw(-90.0f), - _bodyPitch(0.0f), - _bodyRoll(0.0f), _targetScale(1.0f), _handState(0), _keyState(NO_KEY_DOWN), @@ -61,7 +57,9 @@ AvatarData::AvatarData() : _targetVelocity(0.0f), _localAABox(DEFAULT_LOCAL_AABOX_CORNER, DEFAULT_LOCAL_AABOX_SCALE) { - + setBodyPitch(0.0f); + setBodyYaw(-90.0f); + setBodyRoll(0.0f); } AvatarData::~AvatarData() { @@ -79,23 +77,37 @@ const QUrl& AvatarData::defaultFullAvatarModelUrl() { return _defaultFullAvatarModelUrl; } -const glm::vec3& AvatarData::getPosition() const { - return _position; +float AvatarData::getBodyYaw() const { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + return eulerAngles.y; } -void AvatarData::setPosition(const glm::vec3 position) { - _position = position; +void AvatarData::setBodyYaw(float bodyYaw) { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + eulerAngles.y = bodyYaw; + setOrientation(glm::quat(glm::radians(eulerAngles))); } -glm::quat AvatarData::getOrientation() const { - return glm::quat(glm::radians(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll))); +float AvatarData::getBodyPitch() const { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + return eulerAngles.x; } -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::setBodyPitch(float bodyPitch) { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + eulerAngles.x = bodyPitch; + setOrientation(glm::quat(glm::radians(eulerAngles))); +} + +float AvatarData::getBodyRoll() const { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + return eulerAngles.z; +} + +void AvatarData::setBodyRoll(float bodyRoll) { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + eulerAngles.z = bodyRoll; + setOrientation(glm::quat(glm::radians(eulerAngles))); } // There are a number of possible strategies for this set of tools through endRender, below. @@ -162,12 +174,12 @@ void AvatarData::setClampedTargetScale(float targetScale, bool overideReferentia } glm::vec3 AvatarData::getHandPosition() const { - return getOrientation() * _handPosition + _position; + return getOrientation() * _handPosition + getPosition(); } void AvatarData::setHandPosition(const glm::vec3& handPosition) { // store relative to position/orientation - _handPosition = glm::inverse(getOrientation()) * (handPosition - _position); + _handPosition = glm::inverse(getOrientation()) * (handPosition - getPosition()); } QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { @@ -188,13 +200,14 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { unsigned char* destinationBuffer = reinterpret_cast(avatarDataByteArray.data()); unsigned char* startPosition = destinationBuffer; - memcpy(destinationBuffer, &_position, sizeof(_position)); - destinationBuffer += sizeof(_position); + const glm::vec3& position = getPosition(); + memcpy(destinationBuffer, &position, sizeof(position)); + destinationBuffer += sizeof(position); - // Body rotation (NOTE: This needs to become a quaternion to save two bytes) - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _bodyYaw); - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _bodyPitch); - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _bodyRoll); + // Body rotation + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, getBodyYaw()); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, getBodyPitch()); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, getBodyRoll()); // Body scale destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _targetScale); @@ -487,11 +500,12 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { } return maxAvailableSize; } - if (_bodyYaw != yaw || _bodyPitch != pitch || _bodyRoll != roll) { + + // TODO is this safe? will the floats not exactly match? + if (getBodyYaw() != yaw || getBodyPitch() != pitch || getBodyRoll() != roll) { _hasNewJointRotations = true; - _bodyYaw = yaw; - _bodyPitch = pitch; - _bodyRoll = roll; + glm::vec3 eulerAngles(pitch, yaw, roll); + setOrientation(glm::quat(glm::radians(eulerAngles))); } // scale diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 8f5416e4fd..a7d216be6d 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -50,6 +50,7 @@ typedef unsigned long long quint64; #include #include #include +#include #include "AABox.h" #include "HandData.h" @@ -134,7 +135,7 @@ class QDataStream; class AttachmentData; class JointData; -class AvatarData : public QObject { +class AvatarData : public QObject, public SpatiallyNestable { Q_OBJECT Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) @@ -172,9 +173,6 @@ public: const QUuid& getSessionUUID() const { return _sessionUUID; } - const glm::vec3& getPosition() const; - virtual void setPosition(const glm::vec3 position); - glm::vec3 getHandPosition() const; void setHandPosition(const glm::vec3& handPosition); @@ -189,16 +187,13 @@ public: /// \return number of bytes parsed virtual int parseDataFromBuffer(const QByteArray& buffer); - // Body Rotation (degrees) - float getBodyYaw() const { return _bodyYaw; } - void setBodyYaw(float bodyYaw) { _bodyYaw = bodyYaw; } - float getBodyPitch() const { return _bodyPitch; } - void setBodyPitch(float bodyPitch) { _bodyPitch = bodyPitch; } - float getBodyRoll() const { return _bodyRoll; } - void setBodyRoll(float bodyRoll) { _bodyRoll = bodyRoll; } - - glm::quat getOrientation() const; - virtual void setOrientation(const glm::quat& orientation); + // Body Rotation (degrees) + float getBodyYaw() const; + void setBodyYaw(float bodyYaw); + float getBodyPitch() const; + void setBodyPitch(float bodyPitch); + float getBodyRoll() const; + void setBodyRoll(float bodyRoll); void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time. void startCapture(); // start/end of the period in which the latest values are about to be captured for camera, etc. @@ -363,13 +358,7 @@ public slots: protected: QUuid _sessionUUID; - glm::vec3 _position = START_LOCATION; glm::vec3 _handPosition; - - // Body rotation - float _bodyYaw; // degrees - float _bodyPitch; // degrees - float _bodyRoll; // degrees glm::vec3 _nextPosition {}; glm::quat _nextOrientation {}; From bc99ef778cb16c94fb48875e30eb5940db6238ae Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 20 Oct 2015 12:04:29 -0700 Subject: [PATCH 008/401] change how render engine is told about model position changes --- interface/src/Application.cpp | 140 +++++++++--------- interface/src/avatar/Avatar.cpp | 44 +++--- interface/src/avatar/Avatar.h | 3 + interface/src/avatar/AvatarManager.cpp | 26 ++-- interface/src/avatar/AvatarUpdate.cpp | 10 +- libraries/avatars/src/AvatarData.cpp | 58 ++------ libraries/avatars/src/AvatarData.h | 22 +-- .../render-utils/src/MeshPartPayload.cpp | 22 ++- libraries/render-utils/src/MeshPartPayload.h | 10 +- libraries/render-utils/src/Model.cpp | 62 +++++--- libraries/render-utils/src/Model.h | 11 +- 11 files changed, 213 insertions(+), 195 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9b5b83492c..cab189e7a0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1086,75 +1086,77 @@ void Application::paintGL() { { PerformanceTimer perfTimer("CameraUpdates"); - auto myAvatar = getMyAvatar(); - - myAvatar->startCapture(); - if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { - Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN); - Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !(myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN)); - cameraMenuChanged(); - } - - // The render mode is default or mirror if the camera is in mirror mode, assigned further below - renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE; - - // Always use the default eye position, not the actual head eye position. - // Using the latter will cause the camera to wobble with idle animations, - // or with changes from the face tracker - if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { - if (isHMDMode()) { - mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); - _myCamera.setPosition(extractTranslation(camMat)); - _myCamera.setRotation(glm::quat_cast(camMat)); - } else { - _myCamera.setPosition(myAvatar->getDefaultEyePosition()); - _myCamera.setRotation(myAvatar->getHead()->getCameraOrientation()); + myAvatar->withReadLock([&] { + if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { + Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, + myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN); + Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, + !(myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN)); + cameraMenuChanged(); } - } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { - if (isHMDMode()) { - auto hmdWorldMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); - _myCamera.setRotation(glm::normalize(glm::quat_cast(hmdWorldMat))); - auto worldBoomOffset = myAvatar->getOrientation() * (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f)); - _myCamera.setPosition(extractTranslation(hmdWorldMat) + worldBoomOffset); - } else { - _myCamera.setRotation(myAvatar->getHead()->getOrientation()); - if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { - _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + _myCamera.getRotation() - * (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f))); + + // The render mode is default or mirror if the camera is in mirror mode, assigned further below + renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE; + + // Always use the default eye position, not the actual head eye position. + // Using the latter will cause the camera to wobble with idle animations, + // or with changes from the face tracker + if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { + if (isHMDMode()) { + mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); + _myCamera.setPosition(extractTranslation(camMat)); + _myCamera.setRotation(glm::quat_cast(camMat)); } else { - _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + myAvatar->getOrientation() - * (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f))); + _myCamera.setPosition(myAvatar->getDefaultEyePosition()); + _myCamera.setRotation(myAvatar->getHead()->getCameraOrientation()); } + } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { + if (isHMDMode()) { + auto hmdWorldMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); + _myCamera.setRotation(glm::normalize(glm::quat_cast(hmdWorldMat))); + auto worldBoomOffset = myAvatar->getOrientation() * + (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f)); + _myCamera.setPosition(extractTranslation(hmdWorldMat) + worldBoomOffset); + } else { + _myCamera.setRotation(myAvatar->getHead()->getOrientation()); + if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + _myCamera.getRotation() * + (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f))); + } else { + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + myAvatar->getOrientation() * + (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f))); + } + } + } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { + if (isHMDMode()) { + glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix()); + _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() + * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)) * hmdRotation); + glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix()); + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) + + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * + glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror + + (myAvatar->getOrientation() * + glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))) * hmdOffset); + } else { + _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() + * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) + + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * + glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); + } + renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; } - } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { - if (isHMDMode()) { - glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix()); - _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() - * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)) * hmdRotation); - glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix()); - _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) - + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * - glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror - + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))) * hmdOffset); - } else { - _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() - * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); - _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) - + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * - glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); + // Update camera position + if (!isHMDMode()) { + _myCamera.update(1.0f / _fps); } - renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; - } - // Update camera position - if (!isHMDMode()) { - _myCamera.update(1.0f / _fps); - } - myAvatar->endCapture(); + }); } // Primary rendering pass @@ -3386,9 +3388,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se // FIXME: This preRender call is temporary until we create a separate render::scene for the mirror rendering. // Then we can move this logic into the Avatar::simulate call. auto myAvatar = getMyAvatar(); - myAvatar->startRender(); - myAvatar->preRender(renderArgs); - myAvatar->endRender(); + myAvatar->withReadLock([&] { + myAvatar->preRender(renderArgs); + }); activeRenderingThread = QThread::currentThread(); @@ -3502,9 +3504,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se _renderEngine->setRenderContext(renderContext); // Before the deferred pass, let's try to use the render engine - myAvatar->startRenderRun(); - _renderEngine->run(); - myAvatar->endRenderRun(); + myAvatar->withReadLock([&] { + _renderEngine->run(); + }); auto engineRC = _renderEngine->getRenderContext(); sceneInterface->setEngineFeedOpaqueItems(engineRC->_numFeedOpaqueItems); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 92493ab23f..c70c1a5501 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -303,8 +303,6 @@ void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptr_batch; if (glm::distance(DependencyManager::get()->getMyAvatar()->getPosition(), getPosition()) < 10.0f) { @@ -375,7 +373,6 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { } if (frustum->sphereInFrustum(getPosition(), boundingRadius) == ViewFrustum::OUTSIDE) { - endRender(); return; } @@ -529,7 +526,6 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { renderDisplayName(batch, frustum, textPosition); } } - endRender(); } glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { @@ -993,23 +989,25 @@ void Avatar::setBillboard(const QByteArray& billboard) { } int Avatar::parseDataFromBuffer(const QByteArray& buffer) { - startUpdate(); - if (!_initialized) { - // now that we have data for this Avatar we are go for init - init(); - } + int bytesRead; - // change in position implies movement - glm::vec3 oldPosition = getPosition(); + withWriteLock([&] { + if (!_initialized) { + // now that we have data for this Avatar we are go for init + init(); + } - int bytesRead = AvatarData::parseDataFromBuffer(buffer); + // change in position implies movement + glm::vec3 oldPosition = getPosition(); - const float MOVE_DISTANCE_THRESHOLD = 0.001f; - _moving = glm::distance(oldPosition, getPosition()) > MOVE_DISTANCE_THRESHOLD; - if (_moving && _motionState) { - _motionState->addDirtyFlags(Simulation::DIRTY_POSITION); - } - endUpdate(); + bytesRead = AvatarData::parseDataFromBuffer(buffer); + + const float MOVE_DISTANCE_THRESHOLD = 0.001f; + _moving = glm::distance(oldPosition, getPosition()) > MOVE_DISTANCE_THRESHOLD; + if (_moving && _motionState) { + _motionState->addDirtyFlags(Simulation::DIRTY_POSITION); + } + }); return bytesRead; } @@ -1201,3 +1199,13 @@ glm::quat Avatar::getRightPalmRotation() { getSkeletonModel().getJointRotationInWorldFrame(getSkeletonModel().getRightHandJointIndex(), rightRotation); return rightRotation; } + +void Avatar::setPosition(const glm::vec3& position) { + AvatarData::setPosition(position); + updateAttitude(); +} + +void Avatar::setOrientation(const glm::quat& orientation) { + AvatarData::setOrientation(orientation); + updateAttitude(); +} diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 2b7d27b2e3..2366e79c5b 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -174,6 +174,9 @@ public: void setMotionState(AvatarMotionState* motionState) { _motionState = motionState; } AvatarMotionState* getMotionState() { return _motionState; } + virtual void setPosition(const glm::vec3& position); + virtual void setOrientation(const glm::quat& orientation); + public slots: glm::vec3 getLeftPalmPosition(); glm::vec3 getLeftPalmVelocity(); diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index f42cdc200b..16e136f9d1 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -129,9 +129,9 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { _avatarFades.push_back(avatarIterator.value()); avatarIterator = _avatarHash.erase(avatarIterator); } else { - avatar->startUpdate(); - avatar->simulate(deltaTime); - avatar->endUpdate(); + avatar->withWriteLock([&] { + avatar->simulate(deltaTime); + }); ++avatarIterator; } } @@ -150,16 +150,16 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { render::PendingChanges pendingChanges; while (fadingIterator != _avatarFades.end()) { auto avatar = std::static_pointer_cast(*fadingIterator); - avatar->startUpdate(); - avatar->setTargetScale(avatar->getAvatarScale() * SHRINK_RATE, true); - if (avatar->getTargetScale() < MIN_FADE_SCALE) { - avatar->removeFromScene(*fadingIterator, scene, pendingChanges); - fadingIterator = _avatarFades.erase(fadingIterator); - } else { - avatar->simulate(deltaTime); - ++fadingIterator; - } - avatar->endUpdate(); + avatar->withWriteLock([&] { + avatar->setTargetScale(avatar->getAvatarScale() * SHRINK_RATE, true); + if (avatar->getTargetScale() < MIN_FADE_SCALE) { + avatar->removeFromScene(*fadingIterator, scene, pendingChanges); + fadingIterator = _avatarFades.erase(fadingIterator); + } else { + avatar->simulate(deltaTime); + ++fadingIterator; + } + }); } scene->enqueuePendingChanges(pendingChanges); } diff --git a/interface/src/avatar/AvatarUpdate.cpp b/interface/src/avatar/AvatarUpdate.cpp index acdb251950..a32948f598 100644 --- a/interface/src/avatar/AvatarUpdate.cpp +++ b/interface/src/avatar/AvatarUpdate.cpp @@ -56,11 +56,11 @@ bool AvatarUpdate::process() { //gets current lookat data, removes missing avatars, etc. manager->updateOtherAvatars(deltaSeconds); - myAvatar->startUpdate(); - qApp->updateMyAvatarLookAtPosition(); - // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes - manager->updateMyAvatar(deltaSeconds); - myAvatar->endUpdate(); + myAvatar->withWriteLock([&] { + qApp->updateMyAvatarLookAtPosition(); + // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes + manager->updateMyAvatar(deltaSeconds); + }); if (!isThreaded()) { return true; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 6f4c89abe7..9b2967cf5d 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -110,51 +110,25 @@ void AvatarData::setBodyRoll(float bodyRoll) { setOrientation(glm::quat(glm::radians(eulerAngles))); } +void AvatarData::setPosition(const glm::vec3& position) { + withWriteLock([&] { + SpatiallyNestable::setPosition(position); + }); +} + +void AvatarData::setOrientation(const glm::quat& orientation) { + withWriteLock([&] { + SpatiallyNestable::setOrientation(orientation); + }); +} + // There are a number of possible strategies for this set of tools through endRender, below. void AvatarData::nextAttitude(glm::vec3 position, glm::quat orientation) { - avatarLock.lock(); - setPosition(position); - setOrientation(orientation); - avatarLock.unlock(); -} -void AvatarData::startCapture() { - avatarLock.lock(); - assert(_nextAllowed); - _nextAllowed = false; - _nextPosition = getPosition(); - _nextOrientation = getOrientation(); -} -void AvatarData::endCapture() { - avatarLock.unlock(); -} -void AvatarData::startUpdate() { - avatarLock.lock(); -} -void AvatarData::endUpdate() { - avatarLock.unlock(); -} -void AvatarData::startRenderRun() { - // I'd like to get rid of this and just (un)lock at (end-)startRender. - // But somehow that causes judder in rotations. - avatarLock.lock(); -} -void AvatarData::endRenderRun() { - avatarLock.unlock(); -} -void AvatarData::startRender() { - glm::vec3 pos = getPosition(); - glm::quat rot = getOrientation(); - setPosition(_nextPosition); - setOrientation(_nextOrientation); + withWriteLock([&] { + SpatiallyNestable::setPosition(position); + SpatiallyNestable::setOrientation(orientation); + }); updateAttitude(); - _nextPosition = pos; - _nextOrientation = rot; -} -void AvatarData::endRender() { - setPosition(_nextPosition); - setOrientation(_nextOrientation); - updateAttitude(); - _nextAllowed = true; } float AvatarData::getTargetScale() const { diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index a7d216be6d..9f8224caf8 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -44,13 +44,13 @@ typedef unsigned long long quint64; #include #include #include -#include #include #include #include #include #include +#include #include "AABox.h" #include "HandData.h" @@ -59,6 +59,7 @@ typedef unsigned long long quint64; #include "Player.h" #include "Recorder.h" + using AvatarSharedPointer = std::shared_ptr; using AvatarWeakPointer = std::weak_ptr; using AvatarHash = QHash; @@ -135,7 +136,7 @@ class QDataStream; class AttachmentData; class JointData; -class AvatarData : public QObject, public SpatiallyNestable { +class AvatarData : public QObject, public ReadWriteLockable, public SpatiallyNestable { Q_OBJECT Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) @@ -195,15 +196,10 @@ public: float getBodyRoll() const; void setBodyRoll(float bodyRoll); + virtual void setPosition(const glm::vec3& position); + virtual void setOrientation(const glm::quat& orientation); + void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time. - void startCapture(); // start/end of the period in which the latest values are about to be captured for camera, etc. - void endCapture(); - void startUpdate(); // start/end of update iteration - void endUpdate(); - void startRender(); // start/end of rendering of this object - void startRenderRun(); // start/end of entire scene. - void endRenderRun(); - void endRender(); virtual void updateAttitude() {} // Tell skeleton mesh about changes glm::quat getHeadOrientation() const { return _headData->getOrientation(); } @@ -360,10 +356,6 @@ protected: QUuid _sessionUUID; glm::vec3 _handPosition; - glm::vec3 _nextPosition {}; - glm::quat _nextOrientation {}; - bool _nextAllowed {true}; - // Body scale float _targetScale; @@ -413,8 +405,6 @@ protected: SimpleMovingAverage _averageBytesReceived; - QMutex avatarLock; // Name is redundant, but it aids searches. - private: static QUrl _defaultFullAvatarModelUrl; // privatize the copy constructor and assignment operator so they cannot be called diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 80327b7e54..294bf015e0 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -39,9 +39,14 @@ namespace render { using namespace render; -MeshPartPayload::MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex) : - model(model), meshIndex(meshIndex), partIndex(partIndex), _shapeID(shapeIndex) -{ +MeshPartPayload::MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, + glm::vec3 position, glm::quat orientation) : + model(model), + meshIndex(meshIndex), + partIndex(partIndex), + _shapeID(shapeIndex), + _modelPosition(position), + _modelOrientation(orientation) { initCache(); } @@ -66,6 +71,11 @@ void MeshPartPayload::initCache() { } +void MeshPartPayload::updateModelLocation(glm::vec3 position, glm::quat orientation) { + _modelPosition = position; + _modelOrientation = orientation; +} + render::ItemKey MeshPartPayload::getKey() const { ItemKey::Builder builder; builder.withTypeShape(); @@ -91,7 +101,7 @@ render::ItemKey MeshPartPayload::getKey() const { render::Item::Bound MeshPartPayload::getBound() const { // NOTE: we can't cache this bounds because we need to handle the case of a moving // entity or mesh part. - return model->getPartBounds(meshIndex, partIndex); + return model->getPartBounds(meshIndex, partIndex, _modelPosition, _modelOrientation); } void MeshPartPayload::drawCall(gpu::Batch& batch) const { @@ -222,7 +232,7 @@ void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locati transform = Transform(state.clusterMatrices[0]); } } - transform.preTranslate(model->_translation); + transform.preTranslate(_modelPosition); batch.setModelTransform(transform); } @@ -247,7 +257,7 @@ void MeshPartPayload::render(RenderArgs* args) const { } // Back to model to update the cluster matrices right now - model->updateClusterMatrices(); + model->updateClusterMatrices(_modelPosition, _modelOrientation); const FBXMesh& mesh = geometry.meshes.at(meshIndex); diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 51e577e7c7..b29d9510d1 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -24,7 +24,7 @@ class Model; class MeshPartPayload { public: - MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex); + MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, glm::vec3 position, glm::quat orientation); typedef render::Payload Payload; typedef Payload::DataPointer Pointer; @@ -33,7 +33,11 @@ public: int meshIndex; int partIndex; int _shapeID; - + glm::vec3 _modelPosition; + glm::quat _modelOrientation; + + void updateModelLocation(glm::vec3 position, glm::quat orientation); + // Render Item interface render::ItemKey getKey() const; render::Item::Bound getBound() const; @@ -63,4 +67,4 @@ namespace render { template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args); } -#endif // hifi_MeshPartPayload_h \ No newline at end of file +#endif // hifi_MeshPartPayload_h diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 38f5ffdabe..9c3b8adc17 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -73,13 +73,16 @@ Model::~Model() { AbstractViewStateInterface* Model::_viewState = NULL; + void Model::setTranslation(const glm::vec3& translation) { _translation = translation; + enqueueLocationChange(); } - + void Model::setRotation(const glm::quat& rotation) { _rotation = rotation; -} + enqueueLocationChange(); +} void Model::setScale(const glm::vec3& scale) { setScaleInternal(scale); @@ -107,6 +110,20 @@ void Model::setOffset(const glm::vec3& offset) { _snappedToRegistrationPoint = false; } +void Model::enqueueLocationChange() { + render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); + + render::PendingChanges pendingChanges; + foreach (auto itemID, _renderItems.keys()) { + pendingChanges.updateItem(itemID, [=](MeshPartPayload& data) { + data.updateModelLocation(_translation, _rotation); + data.model->_needsUpdateClusterMatrices = true; + }); + } + + scene->enqueuePendingChanges(pendingChanges); +} + QVector Model::createJointStates(const FBXGeometry& geometry) { QVector jointStates; for (int i = 0; i < geometry.joints.size(); ++i) { @@ -378,7 +395,7 @@ void Model::recalculateMeshBoxes(bool pickAgainstTriangles) { _calculatedMeshPartBoxes.clear(); for (int i = 0; i < numberOfMeshes; i++) { const FBXMesh& mesh = geometry.meshes.at(i); - Extents scaledMeshExtents = calculateScaledOffsetExtents(mesh.meshExtents); + Extents scaledMeshExtents = calculateScaledOffsetExtents(mesh.meshExtents, _translation, _rotation); _calculatedMeshBoxes[i] = AABox(scaledMeshExtents); @@ -659,7 +676,8 @@ Extents Model::getUnscaledMeshExtents() const { return scaledExtents; } -Extents Model::calculateScaledOffsetExtents(const Extents& extents) const { +Extents Model::calculateScaledOffsetExtents(const Extents& extents, + glm::vec3 modelPosition, glm::quat modelOrientation) const { // we need to include any fst scaling, translation, and rotation, which is captured in the offset matrix glm::vec3 minimum = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(extents.minimum, 1.0f)); glm::vec3 maximum = glm::vec3(_geometry->getFBXGeometry().offset * glm::vec4(extents.maximum, 1.0f)); @@ -667,17 +685,17 @@ Extents Model::calculateScaledOffsetExtents(const Extents& extents) const { Extents scaledOffsetExtents = { ((minimum + _offset) * _scale), ((maximum + _offset) * _scale) }; - Extents rotatedExtents = scaledOffsetExtents.getRotated(_rotation); + Extents rotatedExtents = scaledOffsetExtents.getRotated(modelOrientation); - Extents translatedExtents = { rotatedExtents.minimum + _translation, - rotatedExtents.maximum + _translation }; + Extents translatedExtents = { rotatedExtents.minimum + modelPosition, + rotatedExtents.maximum + modelPosition }; return translatedExtents; } /// Returns the world space equivalent of some box in model space. -AABox Model::calculateScaledOffsetAABox(const AABox& box) const { - return AABox(calculateScaledOffsetExtents(Extents(box))); +AABox Model::calculateScaledOffsetAABox(const AABox& box, glm::vec3 modelPosition, glm::quat modelOrientation) const { + return AABox(calculateScaledOffsetExtents(Extents(box), modelPosition, modelOrientation)); } glm::vec3 Model::calculateScaledOffsetPoint(const glm::vec3& point) const { @@ -971,7 +989,7 @@ void Model::simulateInternal(float deltaTime) { glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; updateRig(deltaTime, parentTransform); } -void Model::updateClusterMatrices() { +void Model::updateClusterMatrices(glm::vec3 modelPosition, glm::quat modelOrientation) { PerformanceTimer perfTimer("Model::updateClusterMatrices"); if (!_needsUpdateClusterMatrices) { @@ -985,7 +1003,7 @@ void Model::updateClusterMatrices() { glm::vec4(0.0f, 0.0f, 0.0f, 1.0f)); auto cauterizeMatrix = _rig->getJointTransform(geometry.neckJointIndex) * zeroScale; - glm::mat4 modelToWorld = glm::mat4_cast(_rotation); + glm::mat4 modelToWorld = glm::mat4_cast(modelOrientation); for (int i = 0; i < _meshStates.size(); i++) { MeshState& state = _meshStates[i]; const FBXMesh& mesh = geometry.meshes.at(i); @@ -1007,16 +1025,21 @@ void Model::updateClusterMatrices() { // Once computed the cluster matrices, update the buffer(s) if (mesh.clusters.size() > 1) { if (!state.clusterBuffer) { - state.clusterBuffer = std::make_shared(state.clusterMatrices.size() * sizeof(glm::mat4), (const gpu::Byte*) state.clusterMatrices.constData()); + state.clusterBuffer = std::make_shared(state.clusterMatrices.size() * sizeof(glm::mat4), + (const gpu::Byte*) state.clusterMatrices.constData()); } else { - state.clusterBuffer->setSubData(0, state.clusterMatrices.size() * sizeof(glm::mat4), (const gpu::Byte*) state.clusterMatrices.constData()); + state.clusterBuffer->setSubData(0, state.clusterMatrices.size() * sizeof(glm::mat4), + (const gpu::Byte*) state.clusterMatrices.constData()); } if (!_cauterizeBoneSet.empty() && (state.cauterizedClusterMatrices.size() > 1)) { if (!state.cauterizedClusterBuffer) { - state.cauterizedClusterBuffer = std::make_shared(state.cauterizedClusterMatrices.size() * sizeof(glm::mat4), (const gpu::Byte*) state.cauterizedClusterMatrices.constData()); + state.cauterizedClusterBuffer = + std::make_shared(state.cauterizedClusterMatrices.size() * sizeof(glm::mat4), + (const gpu::Byte*) state.cauterizedClusterMatrices.constData()); } else { - state.cauterizedClusterBuffer->setSubData(0, state.cauterizedClusterMatrices.size() * sizeof(glm::mat4), (const gpu::Byte*) state.cauterizedClusterMatrices.constData()); + state.cauterizedClusterBuffer->setSubData(0, state.cauterizedClusterMatrices.size() * sizeof(glm::mat4), + (const gpu::Byte*) state.cauterizedClusterMatrices.constData()); } } } @@ -1109,7 +1132,7 @@ void Model::deleteGeometry() { _blendedBlendshapeCoefficients.clear(); } -AABox Model::getPartBounds(int meshIndex, int partIndex) { +AABox Model::getPartBounds(int meshIndex, int partIndex, glm::vec3 modelPosition, glm::quat modelOrientation) { if (!_geometry || !_geometry->isLoaded()) { return AABox(); @@ -1120,7 +1143,7 @@ AABox Model::getPartBounds(int meshIndex, int partIndex) { bool isSkinned = state.clusterMatrices.size() > 1; if (isSkinned) { // if we're skinned return the entire mesh extents because we can't know for sure our clusters don't move us - return calculateScaledOffsetAABox(_geometry->getFBXGeometry().meshExtents); + return calculateScaledOffsetAABox(_geometry->getFBXGeometry().meshExtents, modelPosition, modelOrientation); } } if (_geometry->getFBXGeometry().meshes.size() > meshIndex) { @@ -1138,7 +1161,7 @@ AABox Model::getPartBounds(int meshIndex, int partIndex) { // // If we not skinned use the bounds of the subMesh for all it's parts const FBXMesh& mesh = _geometry->getFBXGeometry().meshes.at(meshIndex); - return calculateScaledOffsetExtents(mesh.meshExtents); + return calculateScaledOffsetExtents(mesh.meshExtents, modelPosition, modelOrientation); } return AABox(); } @@ -1164,7 +1187,7 @@ void Model::segregateMeshGroups() { // Create the render payloads int totalParts = mesh.parts.size(); for (int partIndex = 0; partIndex < totalParts; partIndex++) { - _renderItemsSet << std::make_shared(this, i, partIndex, shapeID); + _renderItemsSet << std::make_shared(this, i, partIndex, shapeID, _translation, _rotation); shapeID++; } } @@ -1184,6 +1207,7 @@ bool Model::initWhenReady(render::ScenePointer scene) { _renderItems.insert(item, renderPayload); pendingChanges.resetItem(item, renderPayload); pendingChanges.updateItem(item, [&](MeshPartPayload& data) { + data.updateModelLocation(_translation, _rotation); data.model->_needsUpdateClusterMatrices = true; }); } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index e3a9ce9ac3..68468642da 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -86,7 +86,8 @@ public: bool isVisible() const { return _isVisible; } - AABox getPartBounds(int meshIndex, int partIndex); + void updateRenderItems(); + AABox getPartBounds(int meshIndex, int partIndex, glm::vec3 modelPosition, glm::quat modelOrientation); bool maybeStartBlender(); @@ -109,7 +110,7 @@ public: bool getSnapModelToRegistrationPoint() { return _snapModelToRegistrationPoint; } virtual void simulate(float deltaTime, bool fullUpdate = true); - void updateClusterMatrices(); + void updateClusterMatrices(glm::vec3 modelPosition, glm::quat modelOrientation); /// Returns a reference to the shared geometry. const QSharedPointer& getGeometry() const { return _geometry; } @@ -183,6 +184,8 @@ public: void setScale(const glm::vec3& scale); const glm::vec3& getScale() const { return _scale; } + void enqueueLocationChange(); + /// enables/disables scale to fit behavior, the model will be automatically scaled to the specified largest dimension bool getIsScaledToFit() const { return _scaledToFit; } /// is model scaled to fit const glm::vec3& getScaleToFitDimensions() const { return _scaleToFitDimensions; } /// the dimensions model is scaled to @@ -210,10 +213,10 @@ protected: Extents getUnscaledMeshExtents() const; /// Returns the scaled equivalent of some extents in model space. - Extents calculateScaledOffsetExtents(const Extents& extents) const; + Extents calculateScaledOffsetExtents(const Extents& extents, glm::vec3 modelPosition, glm::quat modelOrientation) const; /// Returns the world space equivalent of some box in model space. - AABox calculateScaledOffsetAABox(const AABox& box) const; + AABox calculateScaledOffsetAABox(const AABox& box, glm::vec3 modelPosition, glm::quat modelOrientation) const; /// Returns the scaled equivalent of a point in model space. glm::vec3 calculateScaledOffsetPoint(const glm::vec3& point) const; From 8d4d4a555c15f130b43c693dc0af451c36fce72d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 20 Oct 2015 15:56:24 -0700 Subject: [PATCH 009/401] Add kinematicGrab option in handControllerGrab.js --- examples/controllers/handControllerGrab.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index d2ad2aa4be..a586188f8b 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -497,7 +497,8 @@ function MyController(hand, triggerAction) { timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, relativePosition: this.offsetPosition, relativeRotation: this.offsetRotation, - lifetime: ACTION_LIFETIME + lifetime: ACTION_LIFETIME, + kinematic: (grabbableData.kinematicGrab && (grabbableData.kinematicGrab === true)) }); if (this.actionID === NULL_ACTION_ID) { this.actionID = null; From c67eafffba8c0398dc3098a1e75cce8907d64a04 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 20 Oct 2015 16:59:03 -0700 Subject: [PATCH 010/401] Add pitching.js --- examples/pitching.js | 365 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 365 insertions(+) create mode 100644 examples/pitching.js diff --git a/examples/pitching.js b/examples/pitching.js new file mode 100644 index 0000000000..046113cbc3 --- /dev/null +++ b/examples/pitching.js @@ -0,0 +1,365 @@ +//var PITCH_THUNK_SOUND_URL = "file:///C:/Users/Ryan/Downloads/323725__reitanna__thunk.wav"; +var PITCH_THUNK_SOUND_URL = "file:///C:/Users/Ryan/Downloads/thunk.wav"; +var PITCH_THUNK_SOUND_URL = "http://hifi-public.s3.amazonaws.com/sounds/ping_pong_gun/pong_sound.wav"; +var pitchSound = SoundCache.getSound(PITCH_THUNK_SOUND_URL, false); + +function info(message) { + print("[INFO] " + message); +} + +function error(message) { + print("[ERROR] " + message); +} + +var PITCHING_MACHINE_URL = "atp:87d4879530b698741ecc45f6f31789aac11f7865a2c3bec5fe9b061a182c80d4.fbx"; +var PITCHING_MACHINE_OUTPUT_OFFSET_PCT = { + x: 0.0, + y: 0.25, + z: -1.05, +}; +var PITCHING_MACHINE_PROPERTIES = { + name: "Pitching Machine", + type: "Model", + position: { + x: 0, + y: 0.8, + z: -22.3, + }, + velocity: { + x: 0, + y: -0.01, + z: 0 + }, + gravity: { + x: 0.0, + y: -9.8, + z: 0.0 + }, + registrationPoint: { + x: 0.5, + y: 0.5, + z: 0.5, + }, + rotation: Quat.fromPitchYawRollDegrees(0, 180, 0), + modelURL: PITCHING_MACHINE_URL, + dimensions: { + x: 0.4, + y: 0.61, + z: 0.39 + }, + collisionsWillMove: false, + shapeType: "Box", +}; +PITCHING_MACHINE_PROPERTIES.dimensions = Vec3.multiply(2.5, PITCHING_MACHINE_PROPERTIES.dimensions); + + +var PITCH_RATE = 5000; + +var BASEBALL_MODEL_URL = "atp:7185099f1f650600ca187222573a88200aeb835454bd2f578f12c7fb4fd190fa.fbx"; +var BASEBALL_SPEED = 2.7; +var BASEBALL_RADIUS = 0.07468; +var BASEBALL_PROPERTIES = { + name: "Baseball", + type: "Model", + modelURL: BASEBALL_MODEL_URL, + shapeType: "Sphere", + position: { + x: 0, + y: 0, + z: 0 + }, + dimensions: { + x: BASEBALL_RADIUS, + y: BASEBALL_RADIUS, + z: BASEBALL_RADIUS + }, + collisionsWillMove: true, + angularVelocity: { + x: 17.0, + y: 0, + z: -8.0, + }, + angularDamping: 0.0, + damping: 0.0, + restitution: 0.5, + friction: 0.0, + lifetime: 20, + collisionSoundURL: PITCH_THUNK_SOUND_URL, + gravity: { + x: 0, + y: 0,//-9.8, + z: 0 + } +}; + + +var pitchingMachineID = Entities.addEntity(PITCHING_MACHINE_PROPERTIES); + +var pitchFromPosition = { x: 0, y: 1.0, z: 0 }; +var pitchDirection = { x: 0, y: 0, z: 1 }; + +function shallowCopy(obj) { + var copy = {} + for (var key in obj) { + copy[key] = obj[key]; + } + return copy; +} + +function randomInt(low, high) { + return low + (Math.random() * (high - low)); +} + +var ACCELERATION_SPREAD = 10.15; + +function createBaseball(position, velocity, ballScale) { + var properties = shallowCopy(BASEBALL_PROPERTIES); + properties.position = position; + properties.velocity = velocity; + properties.acceleration = { + x: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), + y: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), + z: 0.0, + }; + properties.dimensions = Vec3.multiply(ballScale, properties.dimensions); + var entityID = Entities.addEntity(properties); + Script.addEventHandler(entityID, "collisionWithEntity", buildBaseballHitCallback(entityID)); + if (false && Math.random() < 0.5) { + for (var i = 0; i < 50; i++) { + Script.setTimeout(function() { + Entities.editEntity(entityID, { + gravity: { + x: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), + y: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), + z: 0.0, + } + }) + }, i * 100); + } + } + return entityID; +} + +var buildBaseballHitCallback = function(entityID) { + var f = function(entityA, entityB, collision) { + var properties = Entities.getEntityProperties(entityID, ['position', 'velocity']); + var line = new InfiniteLine(properties.position, { red: 255, green: 128, blue: 89 }); + var lastPosition = properties.position; + Vec3.print("Velocity", properties.velocity); + Vec3.print("VelocityChange", collision.velocityChange); + Script.setInterval(function() { + var properties = Entities.getEntityProperties(entityID, ['position']); + if (Vec3.distance(properties.position, lastPosition)) { + line.enqueuePoint(properties.position); + lastPosition = properties.position; + } + }, 50); + Entities.editEntity(entityID, { + velocity: Vec3.multiply(3, properties.velocity), + gravity: { + x: 0, + y: -2.8, + z: 0 + } + }); + print("Baseball hit!"); + Script.removeEventHandler(entityID, "collisionWithEntity", f); + }; + return f; +} + + +function vec3Mult(a, b) { + return { + x: a.x * b.x, + y: a.y * b.y, + z: a.z * b.z, + }; +} + +var injector = null; +function pitchBall() { + var machineProperties = Entities.getEntityProperties(pitchingMachineID, ["dimensions", "position", "rotation"]); + var pitchFromPositionBase = machineProperties.position; + var pitchFromOffset = vec3Mult(machineProperties.dimensions, PITCHING_MACHINE_OUTPUT_OFFSET_PCT); + pitchFromOffset = Vec3.multiplyQbyV(machineProperties.rotation, pitchFromOffset); + var pitchFromPosition = Vec3.sum(pitchFromPositionBase, pitchFromOffset); + var pitchDirection = Quat.getFront(machineProperties.rotation); + var ballScale = machineProperties.dimensions.x / PITCHING_MACHINE_PROPERTIES.dimensions.x; + print("Creating baseball"); + var ballEntityID = createBaseball(pitchFromPosition, Vec3.multiply(BASEBALL_SPEED, pitchDirection), ballScale); + if (!injector) { + injector = Audio.playSound(pitchSound, { + position: pitchFromPosition, + volume: 1.0 + }); + } else { + injector.restart(); + } +} + +Script.scriptEnding.connect(function() { + Entities.deleteEntity(pitchingMachineID); +}) + +Script.setInterval(pitchBall, PITCH_RATE); + + + + +/****************************************************************************** + * PolyLine + *****************************************************************************/ +var LINE_DIMENSIONS = { x: 2000, y: 2000, z: 2000 }; +var MAX_LINE_LENGTH = 40; // This must be 2 or greater; +var PolyLine = function(position, color, defaultStrokeWidth) { + //info("Creating polyline"); + //Vec3.print("New line at", position); + this.position = position; + this.color = color; + this.defaultStrokeWidth = 0.10; + this.points = [ + { x: 0, y: 0, z: 0 }, + ]; + this.strokeWidths = [ + this.defaultStrokeWidth, + ] + this.normals = [ + { x: 1, y: 0, z: 0 }, + ] + this.entityID = Entities.addEntity({ + type: "PolyLine", + position: position, + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths, + dimensions: LINE_DIMENSIONS, + color: color, + lifetime: 20, + }); +}; + +PolyLine.prototype.enqueuePoint = function(position) { + if (this.isFull()) { + error("Hit max PolyLine size"); + return; + } + + //Vec3.print("pos", position); + //info("Number of points: " + this.points.length); + + position = Vec3.subtract(position, this.position); + this.points.push(position); + this.normals.push({ x: 1, y: 0, z: 0 }); + this.strokeWidths.push(this.defaultStrokeWidth); + Entities.editEntity(this.entityID, { + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths, + }); +}; + +PolyLine.prototype.dequeuePoint = function() { + if (this.points.length == 0) { + error("Hit min PolyLine size"); + return; + } + + this.points = this.points.slice(1); + this.normals = this.normals.slice(1); + this.strokeWidths = this.strokeWidths.slice(1); + + Entities.editEntity(this.entityID, { + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths, + }); +}; + +PolyLine.prototype.getFirstPoint = function() { + return Vec3.sum(this.position, this.points[0]); +}; + +PolyLine.prototype.getLastPoint = function() { + return Vec3.sum(this.position, this.points[this.points.length - 1]); +}; + +PolyLine.prototype.getSize = function() { + return this.points.length; +} + +PolyLine.prototype.isFull = function() { + return this.points.length >= MAX_LINE_LENGTH; +}; + +PolyLine.prototype.destroy = function() { + Entities.deleteEntity(this.entityID); + this.points = []; +}; + + +/****************************************************************************** + * InfiniteLine + *****************************************************************************/ +InfiniteLine = function(position, color) { + this.position = position; + this.color = color; + this.lines = [new PolyLine(position, color)]; + this.size = 0; +}; + +InfiniteLine.prototype.enqueuePoint = function(position) { + var currentLine; + + if (this.lines.length == 0) { + currentLine = new PolyLine(position, this.color); + this.lines.push(currentLine); + } else { + currentLine = this.lines[this.lines.length - 1]; + } + + if (currentLine.isFull()) { + //info("Current line is full, creating new line"); + //Vec3.print("Last line is", currentLine.getLastPoint()); + //Vec3.print("New line is", position); + var newLine = new PolyLine(currentLine.getLastPoint(), this.color); + this.lines.push(newLine); + currentLine = newLine; + } + + currentLine.enqueuePoint(position); + + ++this.size; +}; + +InfiniteLine.prototype.dequeuePoint = function() { + if (this.lines.length == 0) { + error("Trying to dequeue from InfiniteLine when no points are left"); + return; + } + + var lastLine = this.lines[0]; + lastLine.dequeuePoint(); + + if (lastLine.getSize() <= 1) { + this.lines = this.lines.slice(1); + } + + --this.size; +}; + +InfiniteLine.prototype.getFirstPoint = function() { + return this.lines.length > 0 ? this.lines[0].getFirstPoint() : null; +}; + +InfiniteLine.prototype.getLastPoint = function() { + return this.lines.length > 0 ? this.lines[lines.length - 1].getLastPoint() : null; +}; + +InfiniteLine.prototype.destroy = function() { + for (var i = 0; i < this.lines.length; ++i) { + this.lines[i].destroy(); + } + + this.size = 0; +}; From 014e62e25a2766cdc8261a9ba0f778c4f8758f51 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 20 Oct 2015 17:11:37 -0700 Subject: [PATCH 011/401] allow assignment client to use AssetClient for ATP downloads --- assignment-client/src/Agent.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index d9109703cb..fb9b2a94a0 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -42,7 +43,8 @@ Agent::Agent(NLPacket& packet) : DEFAULT_WINDOW_SECONDS_FOR_DESIRED_REDUCTION, false)) { DependencyManager::get()->setPacketSender(&_entityEditSender); - + + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -110,11 +112,12 @@ void Agent::run() { ThreadedAssignment::commonInit(AGENT_LOGGING_NAME, NodeType::Agent); auto nodeList = DependencyManager::get(); - nodeList->addSetOfNodeTypesToNodeInterestSet(NodeSet() - << NodeType::AudioMixer - << NodeType::AvatarMixer - << NodeType::EntityServer - ); + nodeList->addSetOfNodeTypesToNodeInterestSet({ + NodeType::AudioMixer, + NodeType::AvatarMixer, + NodeType::EntityServer, + NodeType::AssetServer + }); _pingTimer = new QTimer(this); connect(_pingTimer, SIGNAL(timeout()), SLOT(sendPingRequests())); From 21903b746cb3e9f02214bbc9028b341cd8063884 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 21 Oct 2015 10:06:51 -0700 Subject: [PATCH 012/401] CP --- examples/baseballEntityScript.js | 0 examples/libraries/walkApi.js | 1884 ++++++++++++------------ examples/map.js~ | 323 ++++ examples/pitching.js | 6 +- examples/toys/flashlight/flashlight.js | 536 +++---- examples/walk.js | 906 ++++++------ 6 files changed, 1990 insertions(+), 1665 deletions(-) create mode 100644 examples/baseballEntityScript.js create mode 100644 examples/map.js~ diff --git a/examples/baseballEntityScript.js b/examples/baseballEntityScript.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/libraries/walkApi.js b/examples/libraries/walkApi.js index d1192deee7..7f5070f5d0 100644 --- a/examples/libraries/walkApi.js +++ b/examples/libraries/walkApi.js @@ -1,943 +1,943 @@ -// -// walkApi.js -// version 1.3 -// -// Created by David Wooldridge, June 2015 -// Copyright © 2014 - 2015 High Fidelity, Inc. -// -// Exposes API for use by walk.js version 1.2+. -// -// Editing tools for animation data files available here: https://github.com/DaveDubUK/walkTools -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -// included here to ensure walkApi.js can be used as an API, separate from walk.js -Script.include("./libraries/walkConstants.js"); - -Avatar = function() { - // if Hydras are connected, the only way to enable use is to never set any arm joint rotation - this.hydraCheck = function() { - // function courtesy of Thijs Wenker (frisbee.js) - var numberOfButtons = Controller.getNumberOfButtons(); - var numberOfTriggers = Controller.getNumberOfTriggers(); - var numberOfSpatialControls = Controller.getNumberOfSpatialControls(); - const HYDRA_BUTTONS = 12; - const HYDRA_TRIGGERS = 2; - const HYDRA_CONTROLLERS_PER_TRIGGER = 2; - var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers; - if (numberOfButtons == HYDRA_BUTTONS && - numberOfTriggers == HYDRA_TRIGGERS && - controllersPerTrigger == HYDRA_CONTROLLERS_PER_TRIGGER) { - print('walk.js info: Razer Hydra detected. Setting arms free (not controlled by script)'); - return true; - } else { - print('walk.js info: Razer Hydra not detected. Arms will be controlled by script.'); - return false; - } - } - // settings - this.headFree = true; - this.armsFree = this.hydraCheck(); // automatically sets true to enable Hydra support - temporary fix - this.makesFootStepSounds = false; - this.blenderPreRotations = false; // temporary fix - this.animationSet = undefined; // currently just one animation set - this.setAnimationSet = function(animationSet) { - this.animationSet = animationSet; - switch (animationSet) { - case 'standardMale': - this.selectedIdle = walkAssets.getAnimationDataFile("MaleIdle"); - this.selectedWalk = walkAssets.getAnimationDataFile("MaleWalk"); - this.selectedWalkBackwards = walkAssets.getAnimationDataFile("MaleWalkBackwards"); - this.selectedSideStepLeft = walkAssets.getAnimationDataFile("MaleSideStepLeft"); - this.selectedSideStepRight = walkAssets.getAnimationDataFile("MaleSideStepRight"); - this.selectedWalkBlend = walkAssets.getAnimationDataFile("WalkBlend"); - this.selectedHover = walkAssets.getAnimationDataFile("MaleHover"); - this.selectedFly = walkAssets.getAnimationDataFile("MaleFly"); - this.selectedFlyBackwards = walkAssets.getAnimationDataFile("MaleFlyBackwards"); - this.selectedFlyDown = walkAssets.getAnimationDataFile("MaleFlyDown"); - this.selectedFlyUp = walkAssets.getAnimationDataFile("MaleFlyUp"); - this.selectedFlyBlend = walkAssets.getAnimationDataFile("FlyBlend"); - this.currentAnimation = this.selectedIdle; - return; - } - } - this.setAnimationSet('standardMale'); - - // calibration - this.calibration = { - hipsToFeet: 1, - strideLength: this.selectedWalk.calibration.strideLength - } - this.distanceFromSurface = 0; - this.calibrate = function() { - // Triple check: measurements are taken three times to ensure accuracy - the first result is often too large - const MAX_ATTEMPTS = 3; - var attempts = MAX_ATTEMPTS; - var extraAttempts = 0; - do { - for (joint in walkAssets.animationReference.joints) { - var IKChain = walkAssets.animationReference.joints[joint].IKChain; - - // only need to zero right leg IK chain and hips - if (IKChain === "RightLeg" || joint === "Hips" ) { - MyAvatar.setJointRotation(joint, Quat.fromPitchYawRollDegrees(0, 0, 0)); - } - } - this.calibration.hipsToFeet = MyAvatar.getJointPosition("Hips").y - MyAvatar.getJointPosition("RightToeBase").y; - - // maybe measuring before Blender pre-rotations have been applied? - if (this.calibration.hipsToFeet < 0 && this.blenderPreRotations) { - this.calibration.hipsToFeet *= -1; - } - - if (this.calibration.hipsToFeet === 0 && extraAttempts < 100) { - attempts++; - extraAttempts++;// Interface can sometimes report zero for hips to feet. if so, we try again. - } - } while (attempts-- > 1) - - // just in case - if (this.calibration.hipsToFeet <= 0 || isNaN(this.calibration.hipsToFeet)) { - this.calibration.hipsToFeet = 1; - print('walk.js error: Unable to get a non-zero measurement for the avatar hips to feet measure. Hips to feet set to default value ('+ - this.calibration.hipsToFeet.toFixed(3)+'m). This will cause some foot sliding. If your avatar has only just appeared, it is recommended that you re-load the walk script.'); - } else { - print('walk.js info: Hips to feet calibrated to '+this.calibration.hipsToFeet.toFixed(3)+'m'); - } - } - - // pose the fingers - this.poseFingers = function() { - for (knuckle in walkAssets.animationReference.leftHand) { - if (walkAssets.animationReference.leftHand[knuckle].IKChain === "LeftHandThumb") { - MyAvatar.setJointRotation(knuckle, Quat.fromPitchYawRollDegrees(0, 0, -4)); - } else { - MyAvatar.setJointRotation(knuckle, Quat.fromPitchYawRollDegrees(16, 0, 5)); - } - } - for (knuckle in walkAssets.animationReference.rightHand) { - if (walkAssets.animationReference.rightHand[knuckle].IKChain === "RightHandThumb") { - MyAvatar.setJointRotation(knuckle, Quat.fromPitchYawRollDegrees(0, 0, 4)); - } else { - MyAvatar.setJointRotation(knuckle, Quat.fromPitchYawRollDegrees(16, 0, -5)); - } - } - }; - this.calibrate(); - this.poseFingers(); - - // footsteps - this.nextStep = RIGHT; // the first step is right, because the waveforms say so - this.leftAudioInjector = null; - this.rightAudioInjector = null; - this.makeFootStepSound = function() { - // correlate footstep volume with avatar speed. place the audio source at the feet, not the hips - const SPEED_THRESHOLD = 0.4; - const VOLUME_ATTENUATION = 0.8; - const MIN_VOLUME = 0.5; - var volume = Vec3.length(motion.velocity) > SPEED_THRESHOLD ? - VOLUME_ATTENUATION * Vec3.length(motion.velocity) / MAX_WALK_SPEED : MIN_VOLUME; - volume = volume > 1 ? 1 : volume; // occurs when landing at speed - can walk faster than max walking speed - var options = { - position: Vec3.sum(MyAvatar.position, {x:0, y: -this.calibration.hipsToFeet, z:0}), - volume: volume - }; - if (this.nextStep === RIGHT) { - if (this.rightAudioInjector === null) { - this.rightAudioInjector = Audio.playSound(walkAssets.footsteps[0], options); - } else { - this.rightAudioInjector.setOptions(options); - this.rightAudioInjector.restart(); - } - this.nextStep = LEFT; - } else if (this.nextStep === LEFT) { - if (this.leftAudioInjector === null) { - this.leftAudioInjector = Audio.playSound(walkAssets.footsteps[1], options); - } else { - this.leftAudioInjector.setOptions(options); - this.leftAudioInjector.restart(); - } - this.nextStep = RIGHT; - } - } -}; - -// constructor for the Motion object -Motion = function() { - this.isLive = true; - // locomotion status - this.state = STATIC; - this.nextState = STATIC; - this.isMoving = false; - this.isWalkingSpeed = false; - this.isFlyingSpeed = false; - this.isAccelerating = false; - this.isDecelerating = false; - this.isDeceleratingFast = false; - this.isComingToHalt = false; - this.directedAcceleration = 0; - - // used to make sure at least one step has been taken when transitioning from a walk cycle - this.elapsedFTDegrees = 0; - - // the current transition (any layered transitions are nested within this transition) - this.currentTransition = null; - - // orientation, locomotion and timing - this.velocity = {x:0, y:0, z:0}; - this.acceleration = {x:0, y:0, z:0}; - this.yaw = Quat.safeEulerAngles(MyAvatar.orientation).y; - this.yawDelta = 0; - this.yawDeltaAcceleration = 0; - this.direction = FORWARDS; - this.deltaTime = 0; - - // historical orientation, locomotion and timing - this.lastDirection = FORWARDS; - this.lastVelocity = {x:0, y:0, z:0}; - this.lastYaw = Quat.safeEulerAngles(MyAvatar.orientation).y; - this.lastYawDelta = 0; - this.lastYawDeltaAcceleration = 0; - - // Quat.safeEulerAngles(MyAvatar.orientation).y tends to repeat values between frames, so values are filtered - var YAW_SMOOTHING = 22; - this.yawFilter = filter.createAveragingFilter(YAW_SMOOTHING); - this.deltaTimeFilter = filter.createAveragingFilter(YAW_SMOOTHING); - this.yawDeltaAccelerationFilter = filter.createAveragingFilter(YAW_SMOOTHING); - - // assess locomotion state - this.assess = function(deltaTime) { - // calculate avatar frame speed, velocity and acceleration - this.deltaTime = deltaTime; - this.velocity = Vec3.multiplyQbyV(Quat.inverse(MyAvatar.orientation), MyAvatar.getVelocity()); - var lateralVelocity = Math.sqrt(Math.pow(this.velocity.x, 2) + Math.pow(this.velocity.z, 2)); - - // MyAvatar.getAcceleration() currently not working. bug report submitted: https://worklist.net/20527 - var acceleration = {x:0, y:0, z:0}; - this.acceleration.x = (this.velocity.x - this.lastVelocity.x) / deltaTime; - this.acceleration.y = (this.velocity.y - this.lastVelocity.y) / deltaTime; - this.acceleration.z = (this.velocity.z - this.lastVelocity.z) / deltaTime; - - // MyAvatar.getAngularVelocity and MyAvatar.getAngularAcceleration currently not working. bug report submitted - this.yaw = Quat.safeEulerAngles(MyAvatar.orientation).y; - if (this.lastYaw < 0 && this.yaw > 0 || this.lastYaw > 0 && this.yaw < 0) { - this.lastYaw *= -1; - } - var timeDelta = this.deltaTimeFilter.process(deltaTime); - this.yawDelta = filter.degToRad(this.yawFilter.process(this.lastYaw - this.yaw)) / timeDelta; - this.yawDeltaAcceleration = this.yawDeltaAccelerationFilter.process(this.lastYawDelta - this.yawDelta) / timeDelta; - - // how far above the surface is the avatar? (for testing / validation purposes) - var pickRay = {origin: MyAvatar.position, direction: {x:0, y:-1, z:0}}; - var distanceFromSurface = Entities.findRayIntersectionBlocking(pickRay).distance; - avatar.distanceFromSurface = distanceFromSurface - avatar.calibration.hipsToFeet; - - // determine principle direction of locomotion - var FWD_BACK_BIAS = 100; // helps prevent false sidestep condition detection when banking hard - if (Math.abs(this.velocity.x) > Math.abs(this.velocity.y) && - Math.abs(this.velocity.x) > FWD_BACK_BIAS * Math.abs(this.velocity.z)) { - if (this.velocity.x < 0) { - this.directedAcceleration = -this.acceleration.x; - this.direction = LEFT; - } else if (this.velocity.x > 0){ - this.directedAcceleration = this.acceleration.x; - this.direction = RIGHT; - } - } else if (Math.abs(this.velocity.y) > Math.abs(this.velocity.x) && - Math.abs(this.velocity.y) > Math.abs(this.velocity.z)) { - if (this.velocity.y > 0) { - this.directedAcceleration = this.acceleration.y; - this.direction = UP; - } else if (this.velocity.y < 0) { - this.directedAcceleration = -this.acceleration.y; - this.direction = DOWN; - } - } else if (FWD_BACK_BIAS * Math.abs(this.velocity.z) > Math.abs(this.velocity.x) && - Math.abs(this.velocity.z) > Math.abs(this.velocity.y)) { - if (this.velocity.z < 0) { - this.direction = FORWARDS; - this.directedAcceleration = -this.acceleration.z; - } else if (this.velocity.z > 0) { - this.directedAcceleration = this.acceleration.z; - this.direction = BACKWARDS; - } - } else { - this.direction = NONE; - this.directedAcceleration = 0; - } - - // set speed flags - if (Vec3.length(this.velocity) < MOVE_THRESHOLD) { - this.isMoving = false; - this.isWalkingSpeed = false; - this.isFlyingSpeed = false; - this.isComingToHalt = false; - } else if (Vec3.length(this.velocity) < MAX_WALK_SPEED) { - this.isMoving = true; - this.isWalkingSpeed = true; - this.isFlyingSpeed = false; - } else { - this.isMoving = true; - this.isWalkingSpeed = false; - this.isFlyingSpeed = true; - } - - // set acceleration flags - if (this.directedAcceleration > ACCELERATION_THRESHOLD) { - this.isAccelerating = true; - this.isDecelerating = false; - this.isDeceleratingFast = false; - this.isComingToHalt = false; - } else if (this.directedAcceleration < DECELERATION_THRESHOLD) { - this.isAccelerating = false; - this.isDecelerating = true; - this.isDeceleratingFast = (this.directedAcceleration < FAST_DECELERATION_THRESHOLD); - } else { - this.isAccelerating = false; - this.isDecelerating = false; - this.isDeceleratingFast = false; - } - - // use the gathered information to build up some spatial awareness - var isOnSurface = (avatar.distanceFromSurface < ON_SURFACE_THRESHOLD); - var isUnderGravity = (avatar.distanceFromSurface < GRAVITY_THRESHOLD); - var isTakingOff = (isUnderGravity && this.velocity.y > OVERCOME_GRAVITY_SPEED); - var isComingInToLand = (isUnderGravity && this.velocity.y < -OVERCOME_GRAVITY_SPEED); - var aboutToLand = isComingInToLand && avatar.distanceFromSurface < LANDING_THRESHOLD; - var surfaceMotion = isOnSurface && this.isMoving; - var acceleratingAndAirborne = this.isAccelerating && !isOnSurface; - var goingTooFastToWalk = !this.isDecelerating && this.isFlyingSpeed; - var movingDirectlyUpOrDown = (this.direction === UP || this.direction === DOWN) - var maybeBouncing = Math.abs(this.acceleration.y > BOUNCE_ACCELERATION_THRESHOLD) ? true : false; - - // we now have enough information to set the appropriate locomotion mode - switch (this.state) { - case STATIC: - var staticToAirMotion = this.isMoving && (acceleratingAndAirborne || goingTooFastToWalk || - (movingDirectlyUpOrDown && !isOnSurface)); - var staticToSurfaceMotion = surfaceMotion && !motion.isComingToHalt && !movingDirectlyUpOrDown && - !this.isDecelerating && lateralVelocity > MOVE_THRESHOLD; - - if (staticToAirMotion) { - this.nextState = AIR_MOTION; - } else if (staticToSurfaceMotion) { - this.nextState = SURFACE_MOTION; - } else { - this.nextState = STATIC; - } - break; - - case SURFACE_MOTION: - var surfaceMotionToStatic = !this.isMoving || - (this.isDecelerating && motion.lastDirection !== DOWN && surfaceMotion && - !maybeBouncing && Vec3.length(this.velocity) < MAX_WALK_SPEED); - var surfaceMotionToAirMotion = (acceleratingAndAirborne || goingTooFastToWalk || movingDirectlyUpOrDown) && - (!surfaceMotion && isTakingOff) || - (!surfaceMotion && this.isMoving && !isComingInToLand); - - if (surfaceMotionToStatic) { - // working on the assumption that stopping is now inevitable - if (!motion.isComingToHalt && isOnSurface) { - motion.isComingToHalt = true; - } - this.nextState = STATIC; - } else if (surfaceMotionToAirMotion) { - this.nextState = AIR_MOTION; - } else { - this.nextState = SURFACE_MOTION; - } - break; - - case AIR_MOTION: - var airMotionToSurfaceMotion = (surfaceMotion || aboutToLand) && !movingDirectlyUpOrDown; - var airMotionToStatic = !this.isMoving && this.direction === this.lastDirection; - - if (airMotionToSurfaceMotion){ - this.nextState = SURFACE_MOTION; - } else if (airMotionToStatic) { - this.nextState = STATIC; - } else { - this.nextState = AIR_MOTION; - } - break; - } - } - - // frequency time wheel (foot / ground speed matching) - const DEFAULT_HIPS_TO_FEET = 1; - this.frequencyTimeWheelPos = 0; - this.frequencyTimeWheelRadius = DEFAULT_HIPS_TO_FEET / 2; - this.recentFrequencyTimeIncrements = []; - const FT_WHEEL_HISTORY_LENGTH = 8; - for (var i = 0; i < FT_WHEEL_HISTORY_LENGTH; i++) { - this.recentFrequencyTimeIncrements.push(0); - } - this.averageFrequencyTimeIncrement = 0; - - this.advanceFrequencyTimeWheel = function(angle){ - this.elapsedFTDegrees += angle; - // keep a running average of increments for use in transitions (used during transitioning) - this.recentFrequencyTimeIncrements.push(angle); - this.recentFrequencyTimeIncrements.shift(); - for (increment in this.recentFrequencyTimeIncrements) { - this.averageFrequencyTimeIncrement += this.recentFrequencyTimeIncrements[increment]; - } - this.averageFrequencyTimeIncrement /= this.recentFrequencyTimeIncrements.length; - this.frequencyTimeWheelPos += angle; - const FULL_CIRCLE = 360; - if (this.frequencyTimeWheelPos >= FULL_CIRCLE) { - this.frequencyTimeWheelPos = this.frequencyTimeWheelPos % FULL_CIRCLE; - } - } - - this.saveHistory = function() { - this.lastDirection = this.direction; - this.lastVelocity = this.velocity; - this.lastYaw = this.yaw; - this.lastYawDelta = this.yawDelta; - this.lastYawDeltaAcceleration = this.yawDeltaAcceleration; - } -}; // end Motion constructor - -// animation manipulation object -animationOperations = (function() { - - return { - - // helper function for renderMotion(). calculate joint translations based on animation file settings and frequency * time - calculateTranslations: function(animation, ft, direction) { - var jointName = "Hips"; - var joint = animation.joints[jointName]; - var jointTranslations = {x:0, y:0, z:0}; - - // gather modifiers and multipliers - modifiers = new FrequencyMultipliers(joint, direction); - - // calculate translations. Use synthesis filters where specified by the animation data file. - - // sway (oscillation on the x-axis) - if (animation.filters.hasOwnProperty(jointName) && 'swayFilter' in animation.filters[jointName]) { - jointTranslations.x = joint.sway * animation.filters[jointName].swayFilter.calculate - (filter.degToRad(modifiers.swayFrequencyMultiplier * ft + joint.swayPhase)) + joint.swayOffset; - } else { - jointTranslations.x = joint.sway * Math.sin - (filter.degToRad(modifiers.swayFrequencyMultiplier * ft + joint.swayPhase)) + joint.swayOffset; - } - // bob (oscillation on the y-axis) - if (animation.filters.hasOwnProperty(jointName) && 'bobFilter' in animation.filters[jointName]) { - jointTranslations.y = joint.bob * animation.filters[jointName].bobFilter.calculate - (filter.degToRad(modifiers.bobFrequencyMultiplier * ft + joint.bobPhase)) + joint.bobOffset; - } else { - jointTranslations.y = joint.bob * Math.sin - (filter.degToRad(modifiers.bobFrequencyMultiplier * ft + joint.bobPhase)) + joint.bobOffset; - - if (animation.filters.hasOwnProperty(jointName) && 'bobLPFilter' in animation.filters[jointName]) { - jointTranslations.y = filter.clipTrough(jointTranslations.y, joint, 2); - jointTranslations.y = animation.filters[jointName].bobLPFilter.process(jointTranslations.y); - } - } - // thrust (oscillation on the z-axis) - if (animation.filters.hasOwnProperty(jointName) && 'thrustFilter' in animation.filters[jointName]) { - jointTranslations.z = joint.thrust * animation.filters[jointName].thrustFilter.calculate - (filter.degToRad(modifiers.thrustFrequencyMultiplier * ft + joint.thrustPhase)) + joint.thrustOffset; - } else { - jointTranslations.z = joint.thrust * Math.sin - (filter.degToRad(modifiers.thrustFrequencyMultiplier * ft + joint.thrustPhase)) + joint.thrustOffset; - } - return jointTranslations; - }, - - // helper function for renderMotion(). calculate joint rotations based on animation file settings and frequency * time - calculateRotations: function(jointName, animation, ft, direction) { - var joint = animation.joints[jointName]; - var jointRotations = {x:0, y:0, z:0}; - - if (avatar.blenderPreRotations) { - jointRotations = Vec3.sum(jointRotations, walkAssets.blenderPreRotations.joints[jointName]); - } - - // gather frequency multipliers for this joint - modifiers = new FrequencyMultipliers(joint, direction); - - // calculate rotations. Use synthesis filters where specified by the animation data file. - - // calculate pitch - if (animation.filters.hasOwnProperty(jointName) && - 'pitchFilter' in animation.filters[jointName]) { - jointRotations.x += joint.pitch * animation.filters[jointName].pitchFilter.calculate - (filter.degToRad(ft * modifiers.pitchFrequencyMultiplier + joint.pitchPhase)) + joint.pitchOffset; - } else { - jointRotations.x += joint.pitch * Math.sin - (filter.degToRad(ft * modifiers.pitchFrequencyMultiplier + joint.pitchPhase)) + joint.pitchOffset; - } - // calculate yaw - if (animation.filters.hasOwnProperty(jointName) && - 'yawFilter' in animation.filters[jointName]) { - jointRotations.y += joint.yaw * animation.filters[jointName].yawFilter.calculate - (filter.degToRad(ft * modifiers.yawFrequencyMultiplier + joint.yawPhase)) + joint.yawOffset; - } else { - jointRotations.y += joint.yaw * Math.sin - (filter.degToRad(ft * modifiers.yawFrequencyMultiplier + joint.yawPhase)) + joint.yawOffset; - } - // calculate roll - if (animation.filters.hasOwnProperty(jointName) && - 'rollFilter' in animation.filters[jointName]) { - jointRotations.z += joint.roll * animation.filters[jointName].rollFilter.calculate - (filter.degToRad(ft * modifiers.rollFrequencyMultiplier + joint.rollPhase)) + joint.rollOffset; - } else { - jointRotations.z += joint.roll * Math.sin - (filter.degToRad(ft * modifiers.rollFrequencyMultiplier + joint.rollPhase)) + joint.rollOffset; - } - return jointRotations; - }, - - zeroAnimation: function(animation) { - for (i in animation.joints) { - for (j in animation.joints[i]) { - animation.joints[i][j] = 0; - } - } - }, - - blendAnimation: function(sourceAnimation, targetAnimation, percent) { - for (i in targetAnimation.joints) { - targetAnimation.joints[i].pitch += percent * sourceAnimation.joints[i].pitch; - targetAnimation.joints[i].yaw += percent * sourceAnimation.joints[i].yaw; - targetAnimation.joints[i].roll += percent * sourceAnimation.joints[i].roll; - targetAnimation.joints[i].pitchPhase += percent * sourceAnimation.joints[i].pitchPhase; - targetAnimation.joints[i].yawPhase += percent * sourceAnimation.joints[i].yawPhase; - targetAnimation.joints[i].rollPhase += percent * sourceAnimation.joints[i].rollPhase; - targetAnimation.joints[i].pitchOffset += percent * sourceAnimation.joints[i].pitchOffset; - targetAnimation.joints[i].yawOffset += percent * sourceAnimation.joints[i].yawOffset; - targetAnimation.joints[i].rollOffset += percent * sourceAnimation.joints[i].rollOffset; - if (i === "Hips") { - // Hips only - targetAnimation.joints[i].thrust += percent * sourceAnimation.joints[i].thrust; - targetAnimation.joints[i].sway += percent * sourceAnimation.joints[i].sway; - targetAnimation.joints[i].bob += percent * sourceAnimation.joints[i].bob; - targetAnimation.joints[i].thrustPhase += percent * sourceAnimation.joints[i].thrustPhase; - targetAnimation.joints[i].swayPhase += percent * sourceAnimation.joints[i].swayPhase; - targetAnimation.joints[i].bobPhase += percent * sourceAnimation.joints[i].bobPhase; - targetAnimation.joints[i].thrustOffset += percent * sourceAnimation.joints[i].thrustOffset; - targetAnimation.joints[i].swayOffset += percent * sourceAnimation.joints[i].swayOffset; - targetAnimation.joints[i].bobOffset += percent * sourceAnimation.joints[i].bobOffset; - } - } - }, - - deepCopy: function(sourceAnimation, targetAnimation) { - // calibration - targetAnimation.calibration = JSON.parse(JSON.stringify(sourceAnimation.calibration)); - - // harmonics - targetAnimation.harmonics = {}; - if (sourceAnimation.harmonics) { - targetAnimation.harmonics = JSON.parse(JSON.stringify(sourceAnimation.harmonics)); - } - - // filters - targetAnimation.filters = {}; - for (i in sourceAnimation.filters) { - // are any filters specified for this joint? - if (sourceAnimation.filters[i]) { - targetAnimation.filters[i] = sourceAnimation.filters[i]; - // wave shapers - if (sourceAnimation.filters[i].pitchFilter) { - targetAnimation.filters[i].pitchFilter = sourceAnimation.filters[i].pitchFilter; - } - if (sourceAnimation.filters[i].yawFilter) { - targetAnimation.filters[i].yawFilter = sourceAnimation.filters[i].yawFilter; - } - if (sourceAnimation.filters[i].rollFilter) { - targetAnimation.filters[i].rollFilter = sourceAnimation.filters[i].rollFilter; - } - // LP filters - if (sourceAnimation.filters[i].swayLPFilter) { - targetAnimation.filters[i].swayLPFilter = sourceAnimation.filters[i].swayLPFilter; - } - if (sourceAnimation.filters[i].bobLPFilter) { - targetAnimation.filters[i].bobLPFilter = sourceAnimation.filters[i].bobLPFilter; - } - if (sourceAnimation.filters[i].thrustLPFilter) { - targetAnimation.filters[i].thrustLPFilter = sourceAnimation.filters[i].thrustLPFilter; - } - } - } - // joints - targetAnimation.joints = JSON.parse(JSON.stringify(sourceAnimation.joints)); - } - } - -})(); // end animation object literal - -// ReachPose datafile wrapper object -ReachPose = function(reachPoseName) { - this.name = reachPoseName; - this.reachPoseParameters = walkAssets.getReachPoseParameters(reachPoseName); - this.reachPoseDataFile = walkAssets.getReachPoseDataFile(reachPoseName); - this.progress = 0; - this.smoothingFilter = filter.createAveragingFilter(this.reachPoseParameters.smoothing); - this.currentStrength = function() { - // apply optionally smoothed (D)ASDR envelope to reach pose's strength / influence whilst active - var segmentProgress = undefined; // progress through chosen segment - var segmentTimeDelta = undefined; // total change in time over chosen segment - var segmentStrengthDelta = undefined; // total change in strength over chosen segment - var lastStrength = undefined; // the last value the previous segment held - var currentStrength = undefined; // return value - - // select parameters based on segment (a segment being one of (D),A,S,D or R) - if (this.progress >= this.reachPoseParameters.sustain.timing) { - // release segment - segmentProgress = this.progress - this.reachPoseParameters.sustain.timing; - segmentTimeDelta = this.reachPoseParameters.release.timing - this.reachPoseParameters.sustain.timing; - segmentStrengthDelta = this.reachPoseParameters.release.strength - this.reachPoseParameters.sustain.strength; - lastStrength = this.reachPoseParameters.sustain.strength; - } else if (this.progress >= this.reachPoseParameters.decay.timing) { - // sustain phase - segmentProgress = this.progress - this.reachPoseParameters.decay.timing; - segmentTimeDelta = this.reachPoseParameters.sustain.timing - this.reachPoseParameters.decay.timing; - segmentStrengthDelta = this.reachPoseParameters.sustain.strength - this.reachPoseParameters.decay.strength; - lastStrength = this.reachPoseParameters.decay.strength; - } else if (this.progress >= this.reachPoseParameters.attack.timing) { - // decay phase - segmentProgress = this.progress - this.reachPoseParameters.attack.timing; - segmentTimeDelta = this.reachPoseParameters.decay.timing - this.reachPoseParameters.attack.timing; - segmentStrengthDelta = this.reachPoseParameters.decay.strength - this.reachPoseParameters.attack.strength; - lastStrength = this.reachPoseParameters.attack.strength; - } else if (this.progress >= this.reachPoseParameters.delay.timing) { - // attack phase - segmentProgress = this.progress - this.reachPoseParameters.delay.timing; - segmentTimeDelta = this.reachPoseParameters.attack.timing - this.reachPoseParameters.delay.timing; - segmentStrengthDelta = this.reachPoseParameters.attack.strength - this.reachPoseParameters.delay.strength; - lastStrength = 0; //this.delay.strength; - } else { - // delay phase - segmentProgress = this.progress; - segmentTimeDelta = this.reachPoseParameters.delay.timing; - segmentStrengthDelta = this.reachPoseParameters.delay.strength; - lastStrength = 0; - } - currentStrength = segmentTimeDelta > 0 ? lastStrength + segmentStrengthDelta * segmentProgress / segmentTimeDelta - : lastStrength; - // smooth off the response curve - currentStrength = this.smoothingFilter.process(currentStrength); - return currentStrength; - } -}; - -// constructor with default parameters -TransitionParameters = function() { - this.duration = 0.5; - this.easingLower = {x:0.25, y:0.75}; - this.easingUpper = {x:0.75, y:0.25}; - this.reachPoses = []; -} - -const QUARTER_CYCLE = 90; -const HALF_CYCLE = 180; -const THREE_QUARTER_CYCLE = 270; -const FULL_CYCLE = 360; - -// constructor for animation Transition -Transition = function(nextAnimation, lastAnimation, lastTransition, playTransitionReachPoses) { - - if (playTransitionReachPoses === undefined) { - playTransitionReachPoses = true; - } - - // record the current state of animation - this.nextAnimation = nextAnimation; - this.lastAnimation = lastAnimation; - this.lastTransition = lastTransition; - - // collect information about the currently playing animation - this.direction = motion.direction; - this.lastDirection = motion.lastDirection; - this.lastFrequencyTimeWheelPos = motion.frequencyTimeWheelPos; - this.lastFrequencyTimeIncrement = motion.averageFrequencyTimeIncrement; - this.lastFrequencyTimeWheelRadius = motion.frequencyTimeWheelRadius; - this.degreesToTurn = 0; // total degrees to turn the ft wheel before the avatar stops (walk only) - this.degreesRemaining = 0; // remaining degrees to turn the ft wheel before the avatar stops (walk only) - this.lastElapsedFTDegrees = motion.elapsedFTDegrees; // degrees elapsed since last transition start - motion.elapsedFTDegrees = 0; // reset ready for the next transition - motion.frequencyTimeWheelPos = 0; // start the next animation's frequency time wheel from zero - - // set parameters for the transition - this.parameters = new TransitionParameters(); - this.liveReachPoses = []; - if (walkAssets && lastAnimation && nextAnimation) { - // overwrite this.parameters with any transition parameters specified for this particular transition - walkAssets.getTransitionParameters(lastAnimation, nextAnimation, this.parameters); - // fire up any reach poses for this transition - if (playTransitionReachPoses) { - for (poseName in this.parameters.reachPoses) { - this.liveReachPoses.push(new ReachPose(this.parameters.reachPoses[poseName])); - } - } - } - this.startTime = new Date().getTime(); // Starting timestamp (seconds) - this.progress = 0; // how far are we through the transition? - this.filteredProgress = 0; - - // coming to a halt whilst walking? if so, will need a clean stopping point defined - if (motion.isComingToHalt) { - - const FULL_CYCLE_THRESHOLD = 320; - const HALF_CYCLE_THRESHOLD = 140; - const CYCLE_COMMIT_THRESHOLD = 5; - - // how many degrees do we need to turn the walk wheel to finish walking with both feet on the ground? - if (this.lastElapsedFTDegrees < CYCLE_COMMIT_THRESHOLD) { - // just stop the walk cycle right here and blend to idle - this.degreesToTurn = 0; - } else if (this.lastElapsedFTDegrees < HALF_CYCLE) { - // we have not taken a complete step yet, so we advance to the second stop angle - this.degreesToTurn = HALF_CYCLE - this.lastFrequencyTimeWheelPos; - } else if (this.lastFrequencyTimeWheelPos > 0 && this.lastFrequencyTimeWheelPos <= HALF_CYCLE_THRESHOLD) { - // complete the step and stop at 180 - this.degreesToTurn = HALF_CYCLE - this.lastFrequencyTimeWheelPos; - } else if (this.lastFrequencyTimeWheelPos > HALF_CYCLE_THRESHOLD && this.lastFrequencyTimeWheelPos <= HALF_CYCLE) { - // complete the step and next then stop at 0 - this.degreesToTurn = HALF_CYCLE - this.lastFrequencyTimeWheelPos + HALF_CYCLE; - } else if (this.lastFrequencyTimeWheelPos > HALF_CYCLE && this.lastFrequencyTimeWheelPos <= FULL_CYCLE_THRESHOLD) { - // complete the step and stop at 0 - this.degreesToTurn = FULL_CYCLE - this.lastFrequencyTimeWheelPos; - } else { - // complete the step and the next then stop at 180 - this.degreesToTurn = FULL_CYCLE - this.lastFrequencyTimeWheelPos + HALF_CYCLE; - } - - // transition length in this case should be directly proportional to the remaining degrees to turn - var MIN_FT_INCREMENT = 5.0; // degrees per frame - var MIN_TRANSITION_DURATION = 0.4; - const TWO_THIRDS = 0.6667; - this.lastFrequencyTimeIncrement *= TWO_THIRDS; // help ease the transition - var lastFrequencyTimeIncrement = this.lastFrequencyTimeIncrement > MIN_FT_INCREMENT ? - this.lastFrequencyTimeIncrement : MIN_FT_INCREMENT; - var timeToFinish = Math.max(motion.deltaTime * this.degreesToTurn / lastFrequencyTimeIncrement, - MIN_TRANSITION_DURATION); - this.parameters.duration = timeToFinish; - this.degreesRemaining = this.degreesToTurn; - } - - // deal with transition recursion (overlapping transitions) - this.recursionDepth = 0; - this.incrementRecursion = function() { - this.recursionDepth += 1; - - // cancel any continued motion - this.degreesToTurn = 0; - - // limit the number of layered / nested transitions - if (this.lastTransition !== nullTransition) { - this.lastTransition.incrementRecursion(); - if (this.lastTransition.recursionDepth > MAX_TRANSITION_RECURSION) { - this.lastTransition = nullTransition; - } - } - }; - if (this.lastTransition !== nullTransition) { - this.lastTransition.incrementRecursion(); - } - - // end of transition initialisation. begin Transition public methods - - // keep up the pace for the frequency time wheel for the last animation - this.advancePreviousFrequencyTimeWheel = function(deltaTime) { - var wheelAdvance = undefined; - - if (this.lastAnimation === avatar.selectedWalkBlend && - this.nextAnimation === avatar.selectedIdle) { - if (this.degreesRemaining <= 0) { - // stop continued motion - wheelAdvance = 0; - if (motion.isComingToHalt) { - if (this.lastFrequencyTimeWheelPos < QUARTER_CYCLE) { - this.lastFrequencyTimeWheelPos = 0; - } else { - this.lastFrequencyTimeWheelPos = HALF_CYCLE; - } - } - } else { - wheelAdvance = this.lastFrequencyTimeIncrement; - var distanceToTravel = avatar.calibration.strideLength * wheelAdvance / HALF_CYCLE; - if (this.degreesRemaining <= 0) { - distanceToTravel = 0; - this.degreesRemaining = 0; - } else { - this.degreesRemaining -= wheelAdvance; - } - } - } else { - wheelAdvance = this.lastFrequencyTimeIncrement; - } - - // advance the ft wheel - this.lastFrequencyTimeWheelPos += wheelAdvance; - if (this.lastFrequencyTimeWheelPos >= FULL_CYCLE) { - this.lastFrequencyTimeWheelPos = this.lastFrequencyTimeWheelPos % FULL_CYCLE; - } - - // advance ft wheel for the nested (previous) Transition - if (this.lastTransition !== nullTransition) { - this.lastTransition.advancePreviousFrequencyTimeWheel(deltaTime); - } - // update the lastElapsedFTDegrees for short stepping - this.lastElapsedFTDegrees += wheelAdvance; - this.degreesTurned += wheelAdvance; - }; - - this.updateProgress = function() { - const MILLISECONDS_CONVERT = 1000; - const ACCURACY_INCREASER = 1000; - var elapasedTime = (new Date().getTime() - this.startTime) / MILLISECONDS_CONVERT; - this.progress = elapasedTime / this.parameters.duration; - this.progress = Math.round(this.progress * ACCURACY_INCREASER) / ACCURACY_INCREASER; - - // updated nested transition/s - if (this.lastTransition !== nullTransition) { - if (this.lastTransition.updateProgress() === TRANSITION_COMPLETE) { - // the previous transition is now complete - this.lastTransition = nullTransition; - } - } - - // update any reachPoses - for (pose in this.liveReachPoses) { - // use independent timing for reachPoses - this.liveReachPoses[pose].progress += (motion.deltaTime / this.liveReachPoses[pose].reachPoseParameters.duration); - if (this.liveReachPoses[pose].progress >= 1) { - // time to kill off this reach pose - this.liveReachPoses.splice(pose, 1); - } - } - - // update transition progress - this.filteredProgress = filter.bezier(this.progress, this.parameters.easingLower, this.parameters.easingUpper); - return this.progress >= 1 ? TRANSITION_COMPLETE : false; - }; - - this.blendTranslations = function(frequencyTimeWheelPos, direction) { - var lastTranslations = {x:0, y:0, z:0}; - var nextTranslations = animationOperations.calculateTranslations(this.nextAnimation, - frequencyTimeWheelPos, - direction); - // are we blending with a previous, still live transition? - if (this.lastTransition !== nullTransition) { - lastTranslations = this.lastTransition.blendTranslations(this.lastFrequencyTimeWheelPos, - this.lastDirection); - } else { - lastTranslations = animationOperations.calculateTranslations(this.lastAnimation, - this.lastFrequencyTimeWheelPos, - this.lastDirection); - } - - // blend last / next translations - nextTranslations = Vec3.multiply(this.filteredProgress, nextTranslations); - lastTranslations = Vec3.multiply((1 - this.filteredProgress), lastTranslations); - nextTranslations = Vec3.sum(nextTranslations, lastTranslations); - - if (this.liveReachPoses.length > 0) { - for (pose in this.liveReachPoses) { - var reachPoseStrength = this.liveReachPoses[pose].currentStrength(); - var poseTranslations = animationOperations.calculateTranslations( - this.liveReachPoses[pose].reachPoseDataFile, - frequencyTimeWheelPos, - direction); - - // can't use Vec3 operations here, as if x,y or z is zero, the reachPose should have no influence at all - if (Math.abs(poseTranslations.x) > 0) { - nextTranslations.x = reachPoseStrength * poseTranslations.x + (1 - reachPoseStrength) * nextTranslations.x; - } - if (Math.abs(poseTranslations.y) > 0) { - nextTranslations.y = reachPoseStrength * poseTranslations.y + (1 - reachPoseStrength) * nextTranslations.y; - } - if (Math.abs(poseTranslations.z) > 0) { - nextTranslations.z = reachPoseStrength * poseTranslations.z + (1 - reachPoseStrength) * nextTranslations.z; - } - } - } - return nextTranslations; - }; - - this.blendRotations = function(jointName, frequencyTimeWheelPos, direction) { - var lastRotations = {x:0, y:0, z:0}; - var nextRotations = animationOperations.calculateRotations(jointName, - this.nextAnimation, - frequencyTimeWheelPos, - direction); - - // are we blending with a previous, still live transition? - if (this.lastTransition !== nullTransition) { - lastRotations = this.lastTransition.blendRotations(jointName, - this.lastFrequencyTimeWheelPos, - this.lastDirection); - } else { - lastRotations = animationOperations.calculateRotations(jointName, - this.lastAnimation, - this.lastFrequencyTimeWheelPos, - this.lastDirection); - } - // blend last / next translations - nextRotations = Vec3.multiply(this.filteredProgress, nextRotations); - lastRotations = Vec3.multiply((1 - this.filteredProgress), lastRotations); - nextRotations = Vec3.sum(nextRotations, lastRotations); - - // are there reachPoses defined for this transition? - if (this.liveReachPoses.length > 0) { - for (pose in this.liveReachPoses) { - var reachPoseStrength = this.liveReachPoses[pose].currentStrength(); - var poseRotations = animationOperations.calculateRotations(jointName, - this.liveReachPoses[pose].reachPoseDataFile, - frequencyTimeWheelPos, - direction); - - // don't use Vec3 operations here, as if x,y or z is zero, the reach pose should have no influence at all - if (Math.abs(poseRotations.x) > 0) { - nextRotations.x = reachPoseStrength * poseRotations.x + (1 - reachPoseStrength) * nextRotations.x; - } - if (Math.abs(poseRotations.y) > 0) { - nextRotations.y = reachPoseStrength * poseRotations.y + (1 - reachPoseStrength) * nextRotations.y; - } - if (Math.abs(poseRotations.z) > 0) { - nextRotations.z = reachPoseStrength * poseRotations.z + (1 - reachPoseStrength) * nextRotations.z; - } - } - } - return nextRotations; - }; -}; // end Transition constructor - -// individual joint modifiers -FrequencyMultipliers = function(joint, direction) { - // gather multipliers - this.pitchFrequencyMultiplier = 1; - this.yawFrequencyMultiplier = 1; - this.rollFrequencyMultiplier = 1; - this.swayFrequencyMultiplier = 1; - this.bobFrequencyMultiplier = 1; - this.thrustFrequencyMultiplier = 1; - - if (joint) { - if (joint.pitchFrequencyMultiplier) { - this.pitchFrequencyMultiplier = joint.pitchFrequencyMultiplier; - } - if (joint.yawFrequencyMultiplier) { - this.yawFrequencyMultiplier = joint.yawFrequencyMultiplier; - } - if (joint.rollFrequencyMultiplier) { - this.rollFrequencyMultiplier = joint.rollFrequencyMultiplier; - } - if (joint.swayFrequencyMultiplier) { - this.swayFrequencyMultiplier = joint.swayFrequencyMultiplier; - } - if (joint.bobFrequencyMultiplier) { - this.bobFrequencyMultiplier = joint.bobFrequencyMultiplier; - } - if (joint.thrustFrequencyMultiplier) { - this.thrustFrequencyMultiplier = joint.thrustFrequencyMultiplier; - } - } +// +// walkApi.js +// version 1.3 +// +// Created by David Wooldridge, June 2015 +// Copyright © 2014 - 2015 High Fidelity, Inc. +// +// Exposes API for use by walk.js version 1.2+. +// +// Editing tools for animation data files available here: https://github.com/DaveDubUK/walkTools +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// included here to ensure walkApi.js can be used as an API, separate from walk.js +Script.include("./libraries/walkConstants.js"); + +Avatar = function() { + // if Hydras are connected, the only way to enable use is to never set any arm joint rotation + this.hydraCheck = function() { + // function courtesy of Thijs Wenker (frisbee.js) + var numberOfButtons = Controller.getNumberOfButtons(); + var numberOfTriggers = Controller.getNumberOfTriggers(); + var numberOfSpatialControls = Controller.getNumberOfSpatialControls(); + const HYDRA_BUTTONS = 12; + const HYDRA_TRIGGERS = 2; + const HYDRA_CONTROLLERS_PER_TRIGGER = 2; + var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers; + if (numberOfButtons == HYDRA_BUTTONS && + numberOfTriggers == HYDRA_TRIGGERS && + controllersPerTrigger == HYDRA_CONTROLLERS_PER_TRIGGER) { + print('walk.js info: Razer Hydra detected. Setting arms free (not controlled by script)'); + return true; + } else { + print('walk.js info: Razer Hydra not detected. Arms will be controlled by script.'); + return false; + } + } + // settings + this.headFree = true; + this.armsFree = this.hydraCheck(); // automatically sets true to enable Hydra support - temporary fix + this.makesFootStepSounds = false; + this.blenderPreRotations = false; // temporary fix + this.animationSet = undefined; // currently just one animation set + this.setAnimationSet = function(animationSet) { + this.animationSet = animationSet; + switch (animationSet) { + case 'standardMale': + this.selectedIdle = walkAssets.getAnimationDataFile("MaleIdle"); + this.selectedWalk = walkAssets.getAnimationDataFile("MaleWalk"); + this.selectedWalkBackwards = walkAssets.getAnimationDataFile("MaleWalkBackwards"); + this.selectedSideStepLeft = walkAssets.getAnimationDataFile("MaleSideStepLeft"); + this.selectedSideStepRight = walkAssets.getAnimationDataFile("MaleSideStepRight"); + this.selectedWalkBlend = walkAssets.getAnimationDataFile("WalkBlend"); + this.selectedHover = walkAssets.getAnimationDataFile("MaleHover"); + this.selectedFly = walkAssets.getAnimationDataFile("MaleFly"); + this.selectedFlyBackwards = walkAssets.getAnimationDataFile("MaleFlyBackwards"); + this.selectedFlyDown = walkAssets.getAnimationDataFile("MaleFlyDown"); + this.selectedFlyUp = walkAssets.getAnimationDataFile("MaleFlyUp"); + this.selectedFlyBlend = walkAssets.getAnimationDataFile("FlyBlend"); + this.currentAnimation = this.selectedIdle; + return; + } + } + this.setAnimationSet('standardMale'); + + // calibration + this.calibration = { + hipsToFeet: 1, + strideLength: this.selectedWalk.calibration.strideLength + } + this.distanceFromSurface = 0; + this.calibrate = function() { + // Triple check: measurements are taken three times to ensure accuracy - the first result is often too large + const MAX_ATTEMPTS = 3; + var attempts = MAX_ATTEMPTS; + var extraAttempts = 0; + do { + for (joint in walkAssets.animationReference.joints) { + var IKChain = walkAssets.animationReference.joints[joint].IKChain; + + // only need to zero right leg IK chain and hips + if (IKChain === "RightLeg" || joint === "Hips" ) { + MyAvatar.setJointRotation(joint, Quat.fromPitchYawRollDegrees(0, 0, 0)); + } + } + this.calibration.hipsToFeet = MyAvatar.getJointPosition("Hips").y - MyAvatar.getJointPosition("RightToeBase").y; + + // maybe measuring before Blender pre-rotations have been applied? + if (this.calibration.hipsToFeet < 0 && this.blenderPreRotations) { + this.calibration.hipsToFeet *= -1; + } + + if (this.calibration.hipsToFeet === 0 && extraAttempts < 100) { + attempts++; + extraAttempts++;// Interface can sometimes report zero for hips to feet. if so, we try again. + } + } while (attempts-- > 1) + + // just in case + if (this.calibration.hipsToFeet <= 0 || isNaN(this.calibration.hipsToFeet)) { + this.calibration.hipsToFeet = 1; + print('walk.js error: Unable to get a non-zero measurement for the avatar hips to feet measure. Hips to feet set to default value ('+ + this.calibration.hipsToFeet.toFixed(3)+'m). This will cause some foot sliding. If your avatar has only just appeared, it is recommended that you re-load the walk script.'); + } else { + print('walk.js info: Hips to feet calibrated to '+this.calibration.hipsToFeet.toFixed(3)+'m'); + } + } + + // pose the fingers + this.poseFingers = function() { + for (knuckle in walkAssets.animationReference.leftHand) { + if (walkAssets.animationReference.leftHand[knuckle].IKChain === "LeftHandThumb") { + MyAvatar.setJointRotation(knuckle, Quat.fromPitchYawRollDegrees(0, 0, -4)); + } else { + MyAvatar.setJointRotation(knuckle, Quat.fromPitchYawRollDegrees(16, 0, 5)); + } + } + for (knuckle in walkAssets.animationReference.rightHand) { + if (walkAssets.animationReference.rightHand[knuckle].IKChain === "RightHandThumb") { + MyAvatar.setJointRotation(knuckle, Quat.fromPitchYawRollDegrees(0, 0, 4)); + } else { + MyAvatar.setJointRotation(knuckle, Quat.fromPitchYawRollDegrees(16, 0, -5)); + } + } + }; + this.calibrate(); + this.poseFingers(); + + // footsteps + this.nextStep = RIGHT; // the first step is right, because the waveforms say so + this.leftAudioInjector = null; + this.rightAudioInjector = null; + this.makeFootStepSound = function() { + // correlate footstep volume with avatar speed. place the audio source at the feet, not the hips + const SPEED_THRESHOLD = 0.4; + const VOLUME_ATTENUATION = 0.8; + const MIN_VOLUME = 0.5; + var volume = Vec3.length(motion.velocity) > SPEED_THRESHOLD ? + VOLUME_ATTENUATION * Vec3.length(motion.velocity) / MAX_WALK_SPEED : MIN_VOLUME; + volume = volume > 1 ? 1 : volume; // occurs when landing at speed - can walk faster than max walking speed + var options = { + position: Vec3.sum(MyAvatar.position, {x:0, y: -this.calibration.hipsToFeet, z:0}), + volume: volume + }; + if (this.nextStep === RIGHT) { + if (this.rightAudioInjector === null) { + this.rightAudioInjector = Audio.playSound(walkAssets.footsteps[0], options); + } else { + this.rightAudioInjector.setOptions(options); + this.rightAudioInjector.restart(); + } + this.nextStep = LEFT; + } else if (this.nextStep === LEFT) { + if (this.leftAudioInjector === null) { + this.leftAudioInjector = Audio.playSound(walkAssets.footsteps[1], options); + } else { + this.leftAudioInjector.setOptions(options); + this.leftAudioInjector.restart(); + } + this.nextStep = RIGHT; + } + } +}; + +// constructor for the Motion object +Motion = function() { + this.isLive = true; + // locomotion status + this.state = STATIC; + this.nextState = STATIC; + this.isMoving = false; + this.isWalkingSpeed = false; + this.isFlyingSpeed = false; + this.isAccelerating = false; + this.isDecelerating = false; + this.isDeceleratingFast = false; + this.isComingToHalt = false; + this.directedAcceleration = 0; + + // used to make sure at least one step has been taken when transitioning from a walk cycle + this.elapsedFTDegrees = 0; + + // the current transition (any layered transitions are nested within this transition) + this.currentTransition = null; + + // orientation, locomotion and timing + this.velocity = {x:0, y:0, z:0}; + this.acceleration = {x:0, y:0, z:0}; + this.yaw = Quat.safeEulerAngles(MyAvatar.orientation).y; + this.yawDelta = 0; + this.yawDeltaAcceleration = 0; + this.direction = FORWARDS; + this.deltaTime = 0; + + // historical orientation, locomotion and timing + this.lastDirection = FORWARDS; + this.lastVelocity = {x:0, y:0, z:0}; + this.lastYaw = Quat.safeEulerAngles(MyAvatar.orientation).y; + this.lastYawDelta = 0; + this.lastYawDeltaAcceleration = 0; + + // Quat.safeEulerAngles(MyAvatar.orientation).y tends to repeat values between frames, so values are filtered + var YAW_SMOOTHING = 22; + this.yawFilter = filter.createAveragingFilter(YAW_SMOOTHING); + this.deltaTimeFilter = filter.createAveragingFilter(YAW_SMOOTHING); + this.yawDeltaAccelerationFilter = filter.createAveragingFilter(YAW_SMOOTHING); + + // assess locomotion state + this.assess = function(deltaTime) { + // calculate avatar frame speed, velocity and acceleration + this.deltaTime = deltaTime; + this.velocity = Vec3.multiplyQbyV(Quat.inverse(MyAvatar.orientation), MyAvatar.getVelocity()); + var lateralVelocity = Math.sqrt(Math.pow(this.velocity.x, 2) + Math.pow(this.velocity.z, 2)); + + // MyAvatar.getAcceleration() currently not working. bug report submitted: https://worklist.net/20527 + var acceleration = {x:0, y:0, z:0}; + this.acceleration.x = (this.velocity.x - this.lastVelocity.x) / deltaTime; + this.acceleration.y = (this.velocity.y - this.lastVelocity.y) / deltaTime; + this.acceleration.z = (this.velocity.z - this.lastVelocity.z) / deltaTime; + + // MyAvatar.getAngularVelocity and MyAvatar.getAngularAcceleration currently not working. bug report submitted + this.yaw = Quat.safeEulerAngles(MyAvatar.orientation).y; + if (this.lastYaw < 0 && this.yaw > 0 || this.lastYaw > 0 && this.yaw < 0) { + this.lastYaw *= -1; + } + var timeDelta = this.deltaTimeFilter.process(deltaTime); + this.yawDelta = filter.degToRad(this.yawFilter.process(this.lastYaw - this.yaw)) / timeDelta; + this.yawDeltaAcceleration = this.yawDeltaAccelerationFilter.process(this.lastYawDelta - this.yawDelta) / timeDelta; + + // how far above the surface is the avatar? (for testing / validation purposes) + var pickRay = {origin: MyAvatar.position, direction: {x:0, y:-1, z:0}}; + var distanceFromSurface = Entities.findRayIntersectionBlocking(pickRay).distance; + avatar.distanceFromSurface = distanceFromSurface - avatar.calibration.hipsToFeet; + + // determine principle direction of locomotion + var FWD_BACK_BIAS = 100; // helps prevent false sidestep condition detection when banking hard + if (Math.abs(this.velocity.x) > Math.abs(this.velocity.y) && + Math.abs(this.velocity.x) > FWD_BACK_BIAS * Math.abs(this.velocity.z)) { + if (this.velocity.x < 0) { + this.directedAcceleration = -this.acceleration.x; + this.direction = LEFT; + } else if (this.velocity.x > 0){ + this.directedAcceleration = this.acceleration.x; + this.direction = RIGHT; + } + } else if (Math.abs(this.velocity.y) > Math.abs(this.velocity.x) && + Math.abs(this.velocity.y) > Math.abs(this.velocity.z)) { + if (this.velocity.y > 0) { + this.directedAcceleration = this.acceleration.y; + this.direction = UP; + } else if (this.velocity.y < 0) { + this.directedAcceleration = -this.acceleration.y; + this.direction = DOWN; + } + } else if (FWD_BACK_BIAS * Math.abs(this.velocity.z) > Math.abs(this.velocity.x) && + Math.abs(this.velocity.z) > Math.abs(this.velocity.y)) { + if (this.velocity.z < 0) { + this.direction = FORWARDS; + this.directedAcceleration = -this.acceleration.z; + } else if (this.velocity.z > 0) { + this.directedAcceleration = this.acceleration.z; + this.direction = BACKWARDS; + } + } else { + this.direction = NONE; + this.directedAcceleration = 0; + } + + // set speed flags + if (Vec3.length(this.velocity) < MOVE_THRESHOLD) { + this.isMoving = false; + this.isWalkingSpeed = false; + this.isFlyingSpeed = false; + this.isComingToHalt = false; + } else if (Vec3.length(this.velocity) < MAX_WALK_SPEED) { + this.isMoving = true; + this.isWalkingSpeed = true; + this.isFlyingSpeed = false; + } else { + this.isMoving = true; + this.isWalkingSpeed = false; + this.isFlyingSpeed = true; + } + + // set acceleration flags + if (this.directedAcceleration > ACCELERATION_THRESHOLD) { + this.isAccelerating = true; + this.isDecelerating = false; + this.isDeceleratingFast = false; + this.isComingToHalt = false; + } else if (this.directedAcceleration < DECELERATION_THRESHOLD) { + this.isAccelerating = false; + this.isDecelerating = true; + this.isDeceleratingFast = (this.directedAcceleration < FAST_DECELERATION_THRESHOLD); + } else { + this.isAccelerating = false; + this.isDecelerating = false; + this.isDeceleratingFast = false; + } + + // use the gathered information to build up some spatial awareness + var isOnSurface = (avatar.distanceFromSurface < ON_SURFACE_THRESHOLD); + var isUnderGravity = (avatar.distanceFromSurface < GRAVITY_THRESHOLD); + var isTakingOff = (isUnderGravity && this.velocity.y > OVERCOME_GRAVITY_SPEED); + var isComingInToLand = (isUnderGravity && this.velocity.y < -OVERCOME_GRAVITY_SPEED); + var aboutToLand = isComingInToLand && avatar.distanceFromSurface < LANDING_THRESHOLD; + var surfaceMotion = isOnSurface && this.isMoving; + var acceleratingAndAirborne = this.isAccelerating && !isOnSurface; + var goingTooFastToWalk = !this.isDecelerating && this.isFlyingSpeed; + var movingDirectlyUpOrDown = (this.direction === UP || this.direction === DOWN) + var maybeBouncing = Math.abs(this.acceleration.y > BOUNCE_ACCELERATION_THRESHOLD) ? true : false; + + // we now have enough information to set the appropriate locomotion mode + switch (this.state) { + case STATIC: + var staticToAirMotion = this.isMoving && (acceleratingAndAirborne || goingTooFastToWalk || + (movingDirectlyUpOrDown && !isOnSurface)); + var staticToSurfaceMotion = surfaceMotion && !motion.isComingToHalt && !movingDirectlyUpOrDown && + !this.isDecelerating && lateralVelocity > MOVE_THRESHOLD; + + if (staticToAirMotion) { + this.nextState = AIR_MOTION; + } else if (staticToSurfaceMotion) { + this.nextState = SURFACE_MOTION; + } else { + this.nextState = STATIC; + } + break; + + case SURFACE_MOTION: + var surfaceMotionToStatic = !this.isMoving || + (this.isDecelerating && motion.lastDirection !== DOWN && surfaceMotion && + !maybeBouncing && Vec3.length(this.velocity) < MAX_WALK_SPEED); + var surfaceMotionToAirMotion = (acceleratingAndAirborne || goingTooFastToWalk || movingDirectlyUpOrDown) && + (!surfaceMotion && isTakingOff) || + (!surfaceMotion && this.isMoving && !isComingInToLand); + + if (surfaceMotionToStatic) { + // working on the assumption that stopping is now inevitable + if (!motion.isComingToHalt && isOnSurface) { + motion.isComingToHalt = true; + } + this.nextState = STATIC; + } else if (surfaceMotionToAirMotion) { + this.nextState = AIR_MOTION; + } else { + this.nextState = SURFACE_MOTION; + } + break; + + case AIR_MOTION: + var airMotionToSurfaceMotion = (surfaceMotion || aboutToLand) && !movingDirectlyUpOrDown; + var airMotionToStatic = !this.isMoving && this.direction === this.lastDirection; + + if (airMotionToSurfaceMotion){ + this.nextState = SURFACE_MOTION; + } else if (airMotionToStatic) { + this.nextState = STATIC; + } else { + this.nextState = AIR_MOTION; + } + break; + } + } + + // frequency time wheel (foot / ground speed matching) + const DEFAULT_HIPS_TO_FEET = 1; + this.frequencyTimeWheelPos = 0; + this.frequencyTimeWheelRadius = DEFAULT_HIPS_TO_FEET / 2; + this.recentFrequencyTimeIncrements = []; + const FT_WHEEL_HISTORY_LENGTH = 8; + for (var i = 0; i < FT_WHEEL_HISTORY_LENGTH; i++) { + this.recentFrequencyTimeIncrements.push(0); + } + this.averageFrequencyTimeIncrement = 0; + + this.advanceFrequencyTimeWheel = function(angle){ + this.elapsedFTDegrees += angle; + // keep a running average of increments for use in transitions (used during transitioning) + this.recentFrequencyTimeIncrements.push(angle); + this.recentFrequencyTimeIncrements.shift(); + for (increment in this.recentFrequencyTimeIncrements) { + this.averageFrequencyTimeIncrement += this.recentFrequencyTimeIncrements[increment]; + } + this.averageFrequencyTimeIncrement /= this.recentFrequencyTimeIncrements.length; + this.frequencyTimeWheelPos += angle; + const FULL_CIRCLE = 360; + if (this.frequencyTimeWheelPos >= FULL_CIRCLE) { + this.frequencyTimeWheelPos = this.frequencyTimeWheelPos % FULL_CIRCLE; + } + } + + this.saveHistory = function() { + this.lastDirection = this.direction; + this.lastVelocity = this.velocity; + this.lastYaw = this.yaw; + this.lastYawDelta = this.yawDelta; + this.lastYawDeltaAcceleration = this.yawDeltaAcceleration; + } +}; // end Motion constructor + +// animation manipulation object +animationOperations = (function() { + + return { + + // helper function for renderMotion(). calculate joint translations based on animation file settings and frequency * time + calculateTranslations: function(animation, ft, direction) { + var jointName = "Hips"; + var joint = animation.joints[jointName]; + var jointTranslations = {x:0, y:0, z:0}; + + // gather modifiers and multipliers + modifiers = new FrequencyMultipliers(joint, direction); + + // calculate translations. Use synthesis filters where specified by the animation data file. + + // sway (oscillation on the x-axis) + if (animation.filters.hasOwnProperty(jointName) && 'swayFilter' in animation.filters[jointName]) { + jointTranslations.x = joint.sway * animation.filters[jointName].swayFilter.calculate + (filter.degToRad(modifiers.swayFrequencyMultiplier * ft + joint.swayPhase)) + joint.swayOffset; + } else { + jointTranslations.x = joint.sway * Math.sin + (filter.degToRad(modifiers.swayFrequencyMultiplier * ft + joint.swayPhase)) + joint.swayOffset; + } + // bob (oscillation on the y-axis) + if (animation.filters.hasOwnProperty(jointName) && 'bobFilter' in animation.filters[jointName]) { + jointTranslations.y = joint.bob * animation.filters[jointName].bobFilter.calculate + (filter.degToRad(modifiers.bobFrequencyMultiplier * ft + joint.bobPhase)) + joint.bobOffset; + } else { + jointTranslations.y = joint.bob * Math.sin + (filter.degToRad(modifiers.bobFrequencyMultiplier * ft + joint.bobPhase)) + joint.bobOffset; + + if (animation.filters.hasOwnProperty(jointName) && 'bobLPFilter' in animation.filters[jointName]) { + jointTranslations.y = filter.clipTrough(jointTranslations.y, joint, 2); + jointTranslations.y = animation.filters[jointName].bobLPFilter.process(jointTranslations.y); + } + } + // thrust (oscillation on the z-axis) + if (animation.filters.hasOwnProperty(jointName) && 'thrustFilter' in animation.filters[jointName]) { + jointTranslations.z = joint.thrust * animation.filters[jointName].thrustFilter.calculate + (filter.degToRad(modifiers.thrustFrequencyMultiplier * ft + joint.thrustPhase)) + joint.thrustOffset; + } else { + jointTranslations.z = joint.thrust * Math.sin + (filter.degToRad(modifiers.thrustFrequencyMultiplier * ft + joint.thrustPhase)) + joint.thrustOffset; + } + return jointTranslations; + }, + + // helper function for renderMotion(). calculate joint rotations based on animation file settings and frequency * time + calculateRotations: function(jointName, animation, ft, direction) { + var joint = animation.joints[jointName]; + var jointRotations = {x:0, y:0, z:0}; + + if (avatar.blenderPreRotations) { + jointRotations = Vec3.sum(jointRotations, walkAssets.blenderPreRotations.joints[jointName]); + } + + // gather frequency multipliers for this joint + modifiers = new FrequencyMultipliers(joint, direction); + + // calculate rotations. Use synthesis filters where specified by the animation data file. + + // calculate pitch + if (animation.filters.hasOwnProperty(jointName) && + 'pitchFilter' in animation.filters[jointName]) { + jointRotations.x += joint.pitch * animation.filters[jointName].pitchFilter.calculate + (filter.degToRad(ft * modifiers.pitchFrequencyMultiplier + joint.pitchPhase)) + joint.pitchOffset; + } else { + jointRotations.x += joint.pitch * Math.sin + (filter.degToRad(ft * modifiers.pitchFrequencyMultiplier + joint.pitchPhase)) + joint.pitchOffset; + } + // calculate yaw + if (animation.filters.hasOwnProperty(jointName) && + 'yawFilter' in animation.filters[jointName]) { + jointRotations.y += joint.yaw * animation.filters[jointName].yawFilter.calculate + (filter.degToRad(ft * modifiers.yawFrequencyMultiplier + joint.yawPhase)) + joint.yawOffset; + } else { + jointRotations.y += joint.yaw * Math.sin + (filter.degToRad(ft * modifiers.yawFrequencyMultiplier + joint.yawPhase)) + joint.yawOffset; + } + // calculate roll + if (animation.filters.hasOwnProperty(jointName) && + 'rollFilter' in animation.filters[jointName]) { + jointRotations.z += joint.roll * animation.filters[jointName].rollFilter.calculate + (filter.degToRad(ft * modifiers.rollFrequencyMultiplier + joint.rollPhase)) + joint.rollOffset; + } else { + jointRotations.z += joint.roll * Math.sin + (filter.degToRad(ft * modifiers.rollFrequencyMultiplier + joint.rollPhase)) + joint.rollOffset; + } + return jointRotations; + }, + + zeroAnimation: function(animation) { + for (i in animation.joints) { + for (j in animation.joints[i]) { + animation.joints[i][j] = 0; + } + } + }, + + blendAnimation: function(sourceAnimation, targetAnimation, percent) { + for (i in targetAnimation.joints) { + targetAnimation.joints[i].pitch += percent * sourceAnimation.joints[i].pitch; + targetAnimation.joints[i].yaw += percent * sourceAnimation.joints[i].yaw; + targetAnimation.joints[i].roll += percent * sourceAnimation.joints[i].roll; + targetAnimation.joints[i].pitchPhase += percent * sourceAnimation.joints[i].pitchPhase; + targetAnimation.joints[i].yawPhase += percent * sourceAnimation.joints[i].yawPhase; + targetAnimation.joints[i].rollPhase += percent * sourceAnimation.joints[i].rollPhase; + targetAnimation.joints[i].pitchOffset += percent * sourceAnimation.joints[i].pitchOffset; + targetAnimation.joints[i].yawOffset += percent * sourceAnimation.joints[i].yawOffset; + targetAnimation.joints[i].rollOffset += percent * sourceAnimation.joints[i].rollOffset; + if (i === "Hips") { + // Hips only + targetAnimation.joints[i].thrust += percent * sourceAnimation.joints[i].thrust; + targetAnimation.joints[i].sway += percent * sourceAnimation.joints[i].sway; + targetAnimation.joints[i].bob += percent * sourceAnimation.joints[i].bob; + targetAnimation.joints[i].thrustPhase += percent * sourceAnimation.joints[i].thrustPhase; + targetAnimation.joints[i].swayPhase += percent * sourceAnimation.joints[i].swayPhase; + targetAnimation.joints[i].bobPhase += percent * sourceAnimation.joints[i].bobPhase; + targetAnimation.joints[i].thrustOffset += percent * sourceAnimation.joints[i].thrustOffset; + targetAnimation.joints[i].swayOffset += percent * sourceAnimation.joints[i].swayOffset; + targetAnimation.joints[i].bobOffset += percent * sourceAnimation.joints[i].bobOffset; + } + } + }, + + deepCopy: function(sourceAnimation, targetAnimation) { + // calibration + targetAnimation.calibration = JSON.parse(JSON.stringify(sourceAnimation.calibration)); + + // harmonics + targetAnimation.harmonics = {}; + if (sourceAnimation.harmonics) { + targetAnimation.harmonics = JSON.parse(JSON.stringify(sourceAnimation.harmonics)); + } + + // filters + targetAnimation.filters = {}; + for (i in sourceAnimation.filters) { + // are any filters specified for this joint? + if (sourceAnimation.filters[i]) { + targetAnimation.filters[i] = sourceAnimation.filters[i]; + // wave shapers + if (sourceAnimation.filters[i].pitchFilter) { + targetAnimation.filters[i].pitchFilter = sourceAnimation.filters[i].pitchFilter; + } + if (sourceAnimation.filters[i].yawFilter) { + targetAnimation.filters[i].yawFilter = sourceAnimation.filters[i].yawFilter; + } + if (sourceAnimation.filters[i].rollFilter) { + targetAnimation.filters[i].rollFilter = sourceAnimation.filters[i].rollFilter; + } + // LP filters + if (sourceAnimation.filters[i].swayLPFilter) { + targetAnimation.filters[i].swayLPFilter = sourceAnimation.filters[i].swayLPFilter; + } + if (sourceAnimation.filters[i].bobLPFilter) { + targetAnimation.filters[i].bobLPFilter = sourceAnimation.filters[i].bobLPFilter; + } + if (sourceAnimation.filters[i].thrustLPFilter) { + targetAnimation.filters[i].thrustLPFilter = sourceAnimation.filters[i].thrustLPFilter; + } + } + } + // joints + targetAnimation.joints = JSON.parse(JSON.stringify(sourceAnimation.joints)); + } + } + +})(); // end animation object literal + +// ReachPose datafile wrapper object +ReachPose = function(reachPoseName) { + this.name = reachPoseName; + this.reachPoseParameters = walkAssets.getReachPoseParameters(reachPoseName); + this.reachPoseDataFile = walkAssets.getReachPoseDataFile(reachPoseName); + this.progress = 0; + this.smoothingFilter = filter.createAveragingFilter(this.reachPoseParameters.smoothing); + this.currentStrength = function() { + // apply optionally smoothed (D)ASDR envelope to reach pose's strength / influence whilst active + var segmentProgress = undefined; // progress through chosen segment + var segmentTimeDelta = undefined; // total change in time over chosen segment + var segmentStrengthDelta = undefined; // total change in strength over chosen segment + var lastStrength = undefined; // the last value the previous segment held + var currentStrength = undefined; // return value + + // select parameters based on segment (a segment being one of (D),A,S,D or R) + if (this.progress >= this.reachPoseParameters.sustain.timing) { + // release segment + segmentProgress = this.progress - this.reachPoseParameters.sustain.timing; + segmentTimeDelta = this.reachPoseParameters.release.timing - this.reachPoseParameters.sustain.timing; + segmentStrengthDelta = this.reachPoseParameters.release.strength - this.reachPoseParameters.sustain.strength; + lastStrength = this.reachPoseParameters.sustain.strength; + } else if (this.progress >= this.reachPoseParameters.decay.timing) { + // sustain phase + segmentProgress = this.progress - this.reachPoseParameters.decay.timing; + segmentTimeDelta = this.reachPoseParameters.sustain.timing - this.reachPoseParameters.decay.timing; + segmentStrengthDelta = this.reachPoseParameters.sustain.strength - this.reachPoseParameters.decay.strength; + lastStrength = this.reachPoseParameters.decay.strength; + } else if (this.progress >= this.reachPoseParameters.attack.timing) { + // decay phase + segmentProgress = this.progress - this.reachPoseParameters.attack.timing; + segmentTimeDelta = this.reachPoseParameters.decay.timing - this.reachPoseParameters.attack.timing; + segmentStrengthDelta = this.reachPoseParameters.decay.strength - this.reachPoseParameters.attack.strength; + lastStrength = this.reachPoseParameters.attack.strength; + } else if (this.progress >= this.reachPoseParameters.delay.timing) { + // attack phase + segmentProgress = this.progress - this.reachPoseParameters.delay.timing; + segmentTimeDelta = this.reachPoseParameters.attack.timing - this.reachPoseParameters.delay.timing; + segmentStrengthDelta = this.reachPoseParameters.attack.strength - this.reachPoseParameters.delay.strength; + lastStrength = 0; //this.delay.strength; + } else { + // delay phase + segmentProgress = this.progress; + segmentTimeDelta = this.reachPoseParameters.delay.timing; + segmentStrengthDelta = this.reachPoseParameters.delay.strength; + lastStrength = 0; + } + currentStrength = segmentTimeDelta > 0 ? lastStrength + segmentStrengthDelta * segmentProgress / segmentTimeDelta + : lastStrength; + // smooth off the response curve + currentStrength = this.smoothingFilter.process(currentStrength); + return currentStrength; + } +}; + +// constructor with default parameters +TransitionParameters = function() { + this.duration = 0.5; + this.easingLower = {x:0.25, y:0.75}; + this.easingUpper = {x:0.75, y:0.25}; + this.reachPoses = []; +} + +const QUARTER_CYCLE = 90; +const HALF_CYCLE = 180; +const THREE_QUARTER_CYCLE = 270; +const FULL_CYCLE = 360; + +// constructor for animation Transition +Transition = function(nextAnimation, lastAnimation, lastTransition, playTransitionReachPoses) { + + if (playTransitionReachPoses === undefined) { + playTransitionReachPoses = true; + } + + // record the current state of animation + this.nextAnimation = nextAnimation; + this.lastAnimation = lastAnimation; + this.lastTransition = lastTransition; + + // collect information about the currently playing animation + this.direction = motion.direction; + this.lastDirection = motion.lastDirection; + this.lastFrequencyTimeWheelPos = motion.frequencyTimeWheelPos; + this.lastFrequencyTimeIncrement = motion.averageFrequencyTimeIncrement; + this.lastFrequencyTimeWheelRadius = motion.frequencyTimeWheelRadius; + this.degreesToTurn = 0; // total degrees to turn the ft wheel before the avatar stops (walk only) + this.degreesRemaining = 0; // remaining degrees to turn the ft wheel before the avatar stops (walk only) + this.lastElapsedFTDegrees = motion.elapsedFTDegrees; // degrees elapsed since last transition start + motion.elapsedFTDegrees = 0; // reset ready for the next transition + motion.frequencyTimeWheelPos = 0; // start the next animation's frequency time wheel from zero + + // set parameters for the transition + this.parameters = new TransitionParameters(); + this.liveReachPoses = []; + if (walkAssets && lastAnimation && nextAnimation) { + // overwrite this.parameters with any transition parameters specified for this particular transition + walkAssets.getTransitionParameters(lastAnimation, nextAnimation, this.parameters); + // fire up any reach poses for this transition + if (playTransitionReachPoses) { + for (poseName in this.parameters.reachPoses) { + this.liveReachPoses.push(new ReachPose(this.parameters.reachPoses[poseName])); + } + } + } + this.startTime = new Date().getTime(); // Starting timestamp (seconds) + this.progress = 0; // how far are we through the transition? + this.filteredProgress = 0; + + // coming to a halt whilst walking? if so, will need a clean stopping point defined + if (motion.isComingToHalt) { + + const FULL_CYCLE_THRESHOLD = 320; + const HALF_CYCLE_THRESHOLD = 140; + const CYCLE_COMMIT_THRESHOLD = 5; + + // how many degrees do we need to turn the walk wheel to finish walking with both feet on the ground? + if (this.lastElapsedFTDegrees < CYCLE_COMMIT_THRESHOLD) { + // just stop the walk cycle right here and blend to idle + this.degreesToTurn = 0; + } else if (this.lastElapsedFTDegrees < HALF_CYCLE) { + // we have not taken a complete step yet, so we advance to the second stop angle + this.degreesToTurn = HALF_CYCLE - this.lastFrequencyTimeWheelPos; + } else if (this.lastFrequencyTimeWheelPos > 0 && this.lastFrequencyTimeWheelPos <= HALF_CYCLE_THRESHOLD) { + // complete the step and stop at 180 + this.degreesToTurn = HALF_CYCLE - this.lastFrequencyTimeWheelPos; + } else if (this.lastFrequencyTimeWheelPos > HALF_CYCLE_THRESHOLD && this.lastFrequencyTimeWheelPos <= HALF_CYCLE) { + // complete the step and next then stop at 0 + this.degreesToTurn = HALF_CYCLE - this.lastFrequencyTimeWheelPos + HALF_CYCLE; + } else if (this.lastFrequencyTimeWheelPos > HALF_CYCLE && this.lastFrequencyTimeWheelPos <= FULL_CYCLE_THRESHOLD) { + // complete the step and stop at 0 + this.degreesToTurn = FULL_CYCLE - this.lastFrequencyTimeWheelPos; + } else { + // complete the step and the next then stop at 180 + this.degreesToTurn = FULL_CYCLE - this.lastFrequencyTimeWheelPos + HALF_CYCLE; + } + + // transition length in this case should be directly proportional to the remaining degrees to turn + var MIN_FT_INCREMENT = 5.0; // degrees per frame + var MIN_TRANSITION_DURATION = 0.4; + const TWO_THIRDS = 0.6667; + this.lastFrequencyTimeIncrement *= TWO_THIRDS; // help ease the transition + var lastFrequencyTimeIncrement = this.lastFrequencyTimeIncrement > MIN_FT_INCREMENT ? + this.lastFrequencyTimeIncrement : MIN_FT_INCREMENT; + var timeToFinish = Math.max(motion.deltaTime * this.degreesToTurn / lastFrequencyTimeIncrement, + MIN_TRANSITION_DURATION); + this.parameters.duration = timeToFinish; + this.degreesRemaining = this.degreesToTurn; + } + + // deal with transition recursion (overlapping transitions) + this.recursionDepth = 0; + this.incrementRecursion = function() { + this.recursionDepth += 1; + + // cancel any continued motion + this.degreesToTurn = 0; + + // limit the number of layered / nested transitions + if (this.lastTransition !== nullTransition) { + this.lastTransition.incrementRecursion(); + if (this.lastTransition.recursionDepth > MAX_TRANSITION_RECURSION) { + this.lastTransition = nullTransition; + } + } + }; + if (this.lastTransition !== nullTransition) { + this.lastTransition.incrementRecursion(); + } + + // end of transition initialisation. begin Transition public methods + + // keep up the pace for the frequency time wheel for the last animation + this.advancePreviousFrequencyTimeWheel = function(deltaTime) { + var wheelAdvance = undefined; + + if (this.lastAnimation === avatar.selectedWalkBlend && + this.nextAnimation === avatar.selectedIdle) { + if (this.degreesRemaining <= 0) { + // stop continued motion + wheelAdvance = 0; + if (motion.isComingToHalt) { + if (this.lastFrequencyTimeWheelPos < QUARTER_CYCLE) { + this.lastFrequencyTimeWheelPos = 0; + } else { + this.lastFrequencyTimeWheelPos = HALF_CYCLE; + } + } + } else { + wheelAdvance = this.lastFrequencyTimeIncrement; + var distanceToTravel = avatar.calibration.strideLength * wheelAdvance / HALF_CYCLE; + if (this.degreesRemaining <= 0) { + distanceToTravel = 0; + this.degreesRemaining = 0; + } else { + this.degreesRemaining -= wheelAdvance; + } + } + } else { + wheelAdvance = this.lastFrequencyTimeIncrement; + } + + // advance the ft wheel + this.lastFrequencyTimeWheelPos += wheelAdvance; + if (this.lastFrequencyTimeWheelPos >= FULL_CYCLE) { + this.lastFrequencyTimeWheelPos = this.lastFrequencyTimeWheelPos % FULL_CYCLE; + } + + // advance ft wheel for the nested (previous) Transition + if (this.lastTransition !== nullTransition) { + this.lastTransition.advancePreviousFrequencyTimeWheel(deltaTime); + } + // update the lastElapsedFTDegrees for short stepping + this.lastElapsedFTDegrees += wheelAdvance; + this.degreesTurned += wheelAdvance; + }; + + this.updateProgress = function() { + const MILLISECONDS_CONVERT = 1000; + const ACCURACY_INCREASER = 1000; + var elapasedTime = (new Date().getTime() - this.startTime) / MILLISECONDS_CONVERT; + this.progress = elapasedTime / this.parameters.duration; + this.progress = Math.round(this.progress * ACCURACY_INCREASER) / ACCURACY_INCREASER; + + // updated nested transition/s + if (this.lastTransition !== nullTransition) { + if (this.lastTransition.updateProgress() === TRANSITION_COMPLETE) { + // the previous transition is now complete + this.lastTransition = nullTransition; + } + } + + // update any reachPoses + for (pose in this.liveReachPoses) { + // use independent timing for reachPoses + this.liveReachPoses[pose].progress += (motion.deltaTime / this.liveReachPoses[pose].reachPoseParameters.duration); + if (this.liveReachPoses[pose].progress >= 1) { + // time to kill off this reach pose + this.liveReachPoses.splice(pose, 1); + } + } + + // update transition progress + this.filteredProgress = filter.bezier(this.progress, this.parameters.easingLower, this.parameters.easingUpper); + return this.progress >= 1 ? TRANSITION_COMPLETE : false; + }; + + this.blendTranslations = function(frequencyTimeWheelPos, direction) { + var lastTranslations = {x:0, y:0, z:0}; + var nextTranslations = animationOperations.calculateTranslations(this.nextAnimation, + frequencyTimeWheelPos, + direction); + // are we blending with a previous, still live transition? + if (this.lastTransition !== nullTransition) { + lastTranslations = this.lastTransition.blendTranslations(this.lastFrequencyTimeWheelPos, + this.lastDirection); + } else { + lastTranslations = animationOperations.calculateTranslations(this.lastAnimation, + this.lastFrequencyTimeWheelPos, + this.lastDirection); + } + + // blend last / next translations + nextTranslations = Vec3.multiply(this.filteredProgress, nextTranslations); + lastTranslations = Vec3.multiply((1 - this.filteredProgress), lastTranslations); + nextTranslations = Vec3.sum(nextTranslations, lastTranslations); + + if (this.liveReachPoses.length > 0) { + for (pose in this.liveReachPoses) { + var reachPoseStrength = this.liveReachPoses[pose].currentStrength(); + var poseTranslations = animationOperations.calculateTranslations( + this.liveReachPoses[pose].reachPoseDataFile, + frequencyTimeWheelPos, + direction); + + // can't use Vec3 operations here, as if x,y or z is zero, the reachPose should have no influence at all + if (Math.abs(poseTranslations.x) > 0) { + nextTranslations.x = reachPoseStrength * poseTranslations.x + (1 - reachPoseStrength) * nextTranslations.x; + } + if (Math.abs(poseTranslations.y) > 0) { + nextTranslations.y = reachPoseStrength * poseTranslations.y + (1 - reachPoseStrength) * nextTranslations.y; + } + if (Math.abs(poseTranslations.z) > 0) { + nextTranslations.z = reachPoseStrength * poseTranslations.z + (1 - reachPoseStrength) * nextTranslations.z; + } + } + } + return nextTranslations; + }; + + this.blendRotations = function(jointName, frequencyTimeWheelPos, direction) { + var lastRotations = {x:0, y:0, z:0}; + var nextRotations = animationOperations.calculateRotations(jointName, + this.nextAnimation, + frequencyTimeWheelPos, + direction); + + // are we blending with a previous, still live transition? + if (this.lastTransition !== nullTransition) { + lastRotations = this.lastTransition.blendRotations(jointName, + this.lastFrequencyTimeWheelPos, + this.lastDirection); + } else { + lastRotations = animationOperations.calculateRotations(jointName, + this.lastAnimation, + this.lastFrequencyTimeWheelPos, + this.lastDirection); + } + // blend last / next translations + nextRotations = Vec3.multiply(this.filteredProgress, nextRotations); + lastRotations = Vec3.multiply((1 - this.filteredProgress), lastRotations); + nextRotations = Vec3.sum(nextRotations, lastRotations); + + // are there reachPoses defined for this transition? + if (this.liveReachPoses.length > 0) { + for (pose in this.liveReachPoses) { + var reachPoseStrength = this.liveReachPoses[pose].currentStrength(); + var poseRotations = animationOperations.calculateRotations(jointName, + this.liveReachPoses[pose].reachPoseDataFile, + frequencyTimeWheelPos, + direction); + + // don't use Vec3 operations here, as if x,y or z is zero, the reach pose should have no influence at all + if (Math.abs(poseRotations.x) > 0) { + nextRotations.x = reachPoseStrength * poseRotations.x + (1 - reachPoseStrength) * nextRotations.x; + } + if (Math.abs(poseRotations.y) > 0) { + nextRotations.y = reachPoseStrength * poseRotations.y + (1 - reachPoseStrength) * nextRotations.y; + } + if (Math.abs(poseRotations.z) > 0) { + nextRotations.z = reachPoseStrength * poseRotations.z + (1 - reachPoseStrength) * nextRotations.z; + } + } + } + return nextRotations; + }; +}; // end Transition constructor + +// individual joint modifiers +FrequencyMultipliers = function(joint, direction) { + // gather multipliers + this.pitchFrequencyMultiplier = 1; + this.yawFrequencyMultiplier = 1; + this.rollFrequencyMultiplier = 1; + this.swayFrequencyMultiplier = 1; + this.bobFrequencyMultiplier = 1; + this.thrustFrequencyMultiplier = 1; + + if (joint) { + if (joint.pitchFrequencyMultiplier) { + this.pitchFrequencyMultiplier = joint.pitchFrequencyMultiplier; + } + if (joint.yawFrequencyMultiplier) { + this.yawFrequencyMultiplier = joint.yawFrequencyMultiplier; + } + if (joint.rollFrequencyMultiplier) { + this.rollFrequencyMultiplier = joint.rollFrequencyMultiplier; + } + if (joint.swayFrequencyMultiplier) { + this.swayFrequencyMultiplier = joint.swayFrequencyMultiplier; + } + if (joint.bobFrequencyMultiplier) { + this.bobFrequencyMultiplier = joint.bobFrequencyMultiplier; + } + if (joint.thrustFrequencyMultiplier) { + this.thrustFrequencyMultiplier = joint.thrustFrequencyMultiplier; + } + } }; \ No newline at end of file diff --git a/examples/map.js~ b/examples/map.js~ new file mode 100644 index 0000000000..5a4e0f0f8c --- /dev/null +++ b/examples/map.js~ @@ -0,0 +1,323 @@ +Script.include("entityManager.js"); +Script.include("overlayManager.js"); + + +// Poll for nearby map data + +var entityManager = new EntityManager(); + +// From http://evanw.github.io/lightgl.js/docs/raytracer.html +function raySphereIntersection(origin, ray, center, radius) { + var offset = Vec3.subtract(origin, center); + var a = Vec3.dot(ray, ray); + // var a = ray.dot(ray); + var b = 2 * Vec3.dot(ray, offset); + // var b = 2 * ray.dot(offset); + var c = Vec3.dot(offset, offset) - radius * radius; + // var c = offset.dot(offset) - radius * radius; + var discriminant = b * b - 4 * a * c; + + if (discriminant > 0) { + return true; + } + + return null; +}; + + +Map = function(data) { + var visible = false; + + var ROOT_OFFSET = Vec3.multiply(0.3, Quat.getFront(MyAvatar.orientation)); + var ROOT_POSITION = Vec3.sum(MyAvatar.position, ROOT_OFFSET); + + var ROOT_SCALE = 0.0005; + + // Create object in objectManager + var rootObject = entityManager.addBare(); + var position = ROOT_POSITION; + rootObject.position = ROOT_POSITION; + rootObject.scale = ROOT_SCALE + Vec3.print("Position:", position); + + // Search for all nearby objects that have the userData "mapped" + // TODO Update to use the zone's bounds + var entities = Entities.findEntities(MyAvatar.position, 32000); + var mappedEntities = []; + var minCorner = { + x: 4294967295, + y: 4294967295, + z: 4294967295, + }; + var maxCorner = { + x: -4294967295, + y: -4294967295, + z: -4294967295, + }; + + for (var i = 0; i < entities.length; ++i) { + var entityID = entities[i]; + var properties = Entities.getEntityProperties(entityID); + if (properties.userData == "mapped" || properties.userData == "tracked") { + + print("Found: ", properties.name); + + minCorner.x = Math.min(minCorner.x, properties.position.x - (properties.dimensions.x / 2)); + minCorner.y = Math.min(minCorner.y, properties.position.y - (properties.dimensions.y / 2)); + minCorner.z = Math.min(minCorner.z, properties.position.z - (properties.dimensions.z / 2)); + + maxCorner.x = Math.max(maxCorner.x, properties.position.x - (properties.dimensions.x / 2)); + maxCorner.y = Math.max(maxCorner.y, properties.position.y - (properties.dimensions.y / 2)); + maxCorner.z = Math.max(maxCorner.z, properties.position.z - (properties.dimensions.z / 2)); + + } + // if (properties.userData == "mapped") { + // properties.visible = false; + // var entity = entityManager.add(properties.type, properties); + // mappedEntities.push(entity); + // } else if (properties.userData == "tracked") { + // // TODO implement tracking of objects + // } + } + + var dimensions = { + x: maxCorner.x - minCorner.x, + y: maxCorner.y - minCorner.y, + z: maxCorner.z - minCorner.z, + }; + Vec3.print("dims", dimensions); + + var center = { + x: minCorner.x + (dimensions.x / 2), + y: minCorner.y + (dimensions.y / 2), + z: minCorner.z + (dimensions.z / 2), + }; + Vec3.print("center", center); + + var trackedEntities = []; + var waypointEntities = []; + for (var i = 0; i < entities.length; ++i) { + var entityID = entities[i]; + var properties = Entities.getEntityProperties(entityID); + var mapData = null; + try { + var data = JSON.parse(properties.userData.replace(/(\r\n|\n|\r)/gm,"")); + mapData = data.mapData; + } catch (e) { + print("Caught: ", properties.name); + } + + if (mapData) { + print("Creating copy of", properties.name); + properties.name += " (COPY)"; + properties.userData = ""; + properties.visible = true; + var position = properties.position; + properties.position = Vec3.subtract(properties.position, center); + properties.position = Vec3.multiply(properties.position, ROOT_SCALE); + var extra = { }; + + if (mapData.track) { + extra.trackingEntityID= entityID; + trackedEntities.push(entity); + rootObject.addChild(entity); + } + if (mapData.waypoint) { + print("Waypoint: ", mapData.waypoint.name); + // properties.type = "Model"; + // properties.modelURL = "atp:ca49a13938376b3eb68d7b2b9189afb3f580c07b6950ea9e65b5260787204145.fbx"; + extra.waypoint = mapData.waypoint; + extra.waypoint.position = position; + } + + var entity = entityManager.add(properties.type, properties); + entity.__extra__ = extra; + if (mapData.waypoint) { + waypointEntities.push(entity); + } + mappedEntities.push(entity); + + rootObject.addChild(entity); + + } else { + // print("Not creating copy of", properties.name); + } + } + + var avatarArrowEntity = entityManager.add("Model", { + name: "You Are Here", + modelURL: "atp:ce4f0c4e491e40b73d28f2646da4f676fe9ea364cf5f1bf5615522ef6acfd80e.fbx", + position: Vec3.multiply(Vec3.subtract(MyAvatar.position, center), ROOT_SCALE), + dimensions: { x: 30, y: 100, z: 100 }, + }); + rootObject.addChild(avatarArrowEntity); + + this.isVisible = function() { + return visible; + } + + Controller.mousePressEvent.connect(mousePressEvent); + function mousePressEvent(event) { + // Entities.setZonesArePickable(false); + + var pickRay = Camera.computePickRay(event.x, event.y); + for (var i = 0; i < waypointEntities.length; ++i) { + var entity = waypointEntities[i]; + print("Checkit for hit", entity.__extra__.waypoint.name); + var result = raySphereIntersection(pickRay.origin, pickRay.direction, entity.worldPosition, 0.1);//entity.worldScale); + if (result) { + print("Pressed entity: ", entity.id); + print("Pressed waypoint: ", entity.__extra__.waypoint.name); + print("Teleporting..."); + MyAvatar.position = entity.__extra__.waypoint.position; + break; + } + } + // var result = Entities.findRayIntersection(pickRay, false); + // if (result.intersects) { + // var entity = entityManager.get(result.entityID); + // if (entity) { + // print("Pressed entity: ", entity.id); + // } + // if (entity && entity.__extra__.waypoint) { + // print("Pressed waypoint: ", entity.__extra__.waypoint.name); + // print("Teleporting..."); + // MyAvatar.position = entity.__extra__.waypoint.position; + // } + // } + + // Entities.setZonesArePickable(true); + }; + + var time = 0; + Script.update.connect(function(dt) { + time += dt; + // Update tracked entities + for (var i = 0; i < trackedEntities.length; ++i) { + entity = trackedEntities[i]; + var entityID = entity.__extra__.trackingEntityID; + var properties = Entities.getEntityProperties(entityID); + properties.position = Vec3.subtract(properties.position, center); + properties.position = Vec3.multiply(properties.position, ROOT_SCALE); + entity.position = properties.position; + } + + + var position = Vec3.subtract(MyAvatar.position, center) + position.y += 60 + (Math.sin(time) * 10); + position = Vec3.multiply(position, ROOT_SCALE); + avatarArrowEntity.position = position; + // Vec3.print("Position:", avatarArrowEntity.position); + + // rootObject.position = Vec3.sum(position, { x: 0, y: Math.sin(time) / 30, z: 0 }); + //var ROOT_OFFSET = Vec3.multiply(0.3, Quat.getFront(MyAvatar.orientation)); + //var ROOT_POSITION = Vec3.sum(MyAvatar.position, ROOT_OFFSET); + // position = ROOT_POSITION; + rootObject.position = ROOT_POSITION; + entityManager.update(); + + // Update waypoint highlights + var pickRay = Camera.computePickRay(event.x, event.y); + for (var i = 0; i < waypointEntities.length; ++i) { + var entity = waypointEntities[i]; + print("Checkit for hit", entity.__extra__.waypoint.name); + var result = raySphereIntersection(pickRay.origin, pickRay.direction, entity.worldPosition, 0.1);//entity.worldScale); + if (result) { + print("Pressed entity: ", entity.id); + print("Pressed waypoint: ", entity.__extra__.waypoint.name); + print("Teleporting..."); + MyAvatar.position = entity.__extra__.waypoint.position; + break; + } + } + }); + + function setVisible(newValue) { + if (visible != newValue) { + visible = newValue; + + if (visible) { + } else { + } + } + } + + this.show = function() { + setVisible(true); + } + + this.hide = function() { + setVisible(false); + } +}; + +var map = null; +map = Map(mapData); + +// On press key +Controller.keyPressEvent.connect(function(event) { + if (event.text == "m") { + if (!map) { + map = Map(mapData); + } + + map.show(); + print("MAP!"); + } +}); + + + + + +var mapData = { + config: { + // World dimensions that the minimap maps to + worldDimensions: { + x: 10.0, + y: 10.0, + z: 10.0, + }, + // The center of the map should map to this location in the center of the area + worldCenter: { + x: 5.0, + y: 5.0, + z: 5.0, + }, + // Map dimensions + mapDimensions: { + x: 10.0, + y: 10.0, + z: 10.0, + }, + + // Can this be automated? Tag entities that should be included? Store in UserData? + objects: [ + { + type: "Model", + modelURL: "https://hifi-public.s3.amazonaws.com/ozan/sets/huffman_set/huffman_set.fbx", + }, + ], + }, + waypoints: [ + { + name: "Forest's Edge", + position: { + }, + }, + ], +}; + + +// entityManager = new OverlayManager(); +// entityManager = new EntityManager(); +// +// var rootEntity = entityManager.addBare(); +// +// var time = 0; +// +// +// rootEntity.scale = 0.1; +// Script.include("sfData.js"); +// rootEntity.addChild(entity); +entityManager.update(); diff --git a/examples/pitching.js b/examples/pitching.js index 046113cbc3..b419e8935c 100644 --- a/examples/pitching.js +++ b/examples/pitching.js @@ -142,6 +142,7 @@ function createBaseball(position, velocity, ballScale) { var buildBaseballHitCallback = function(entityID) { var f = function(entityA, entityB, collision) { + print("Got baseball hit callback"); var properties = Entities.getEntityProperties(entityID, ['position', 'velocity']); var line = new InfiniteLine(properties.position, { red: 255, green: 128, blue: 89 }); var lastPosition = properties.position; @@ -154,11 +155,12 @@ var buildBaseballHitCallback = function(entityID) { lastPosition = properties.position; } }, 50); + var speed = Vec3.length(properties.velocity); Entities.editEntity(entityID, { - velocity: Vec3.multiply(3, properties.velocity), + velocity: Vec3.multiply(2, properties.velocity), gravity: { x: 0, - y: -2.8, + y: -9.8, z: 0 } }); diff --git a/examples/toys/flashlight/flashlight.js b/examples/toys/flashlight/flashlight.js index a775f185e3..912d542d6c 100644 --- a/examples/toys/flashlight/flashlight.js +++ b/examples/toys/flashlight/flashlight.js @@ -1,269 +1,269 @@ -// -// flashlight.js -// -// Script Type: Entity -// -// Created by Sam Gateau on 9/9/15. -// Additions by James B. Pollack @imgntn on 9/21/2015 -// Copyright 2015 High Fidelity, Inc. -// -// This is a toy script that can be added to the Flashlight model entity: -// "https://hifi-public.s3.amazonaws.com/models/props/flashlight.fbx" -// that creates a spotlight attached with the flashlight model while the entity is grabbed -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -/*global MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */ -(function() { - - Script.include("../../libraries/utils.js"); - - var ON_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/flashlight_on.wav'; - var OFF_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/flashlight_off.wav'; - - //we are creating lights that we don't want to get stranded so lets make sure that we can get rid of them - var startTime = Date.now(); - //if you're going to be using this in a dungeon or something and holding it for a long time, increase this lifetime value. - var LIFETIME = 25; - var MSEC_PER_SEC = 1000.0; - - // this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember - // our this object, so we can access it in cases where we're called without a this (like in the case of various global signals) - function Flashlight() { - return; - } - - //if the trigger value goes below this while held, the flashlight will turn off. if it goes above, it will - var DISABLE_LIGHT_THRESHOLD = 0.7; - - // These constants define the Spotlight position and orientation relative to the model - var MODEL_LIGHT_POSITION = { - x: 0, - y: -0.3, - z: 0 - }; - var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { - x: 1, - y: 0, - z: 0 - }); - - var GLOW_LIGHT_POSITION = { - x: 0, - y: -0.1, - z: 0 - }; - - // Evaluate the world light entity positions and orientations from the model ones - function evalLightWorldTransform(modelPos, modelRot) { - - return { - p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), - q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) - }; - } - - function glowLightWorldTransform(modelPos, modelRot) { - return { - p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, GLOW_LIGHT_POSITION)), - q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) - }; - } - - Flashlight.prototype = { - lightOn: false, - hand: null, - whichHand: null, - hasSpotlight: false, - spotlight: null, - setRightHand: function() { - this.hand = 'RIGHT'; - }, - - setLeftHand: function() { - this.hand = 'LEFT'; - }, - - startNearGrab: function() { - if (!this.hasSpotlight) { - - //this light casts the beam - this.spotlight = Entities.addEntity({ - type: "Light", - isSpotlight: true, - dimensions: { - x: 2, - y: 2, - z: 20 - }, - color: { - red: 255, - green: 255, - blue: 255 - }, - intensity: 2, - exponent: 0.3, - cutoff: 20, - lifetime: LIFETIME - }); - - //this light creates the effect of a bulb at the end of the flashlight - this.glowLight = Entities.addEntity({ - type: "Light", - dimensions: { - x: 0.25, - y: 0.25, - z: 0.25 - }, - isSpotlight: false, - color: { - red: 255, - green: 255, - blue: 255 - }, - exponent: 0, - cutoff: 90, // in degrees - lifetime: LIFETIME - }); - - this.hasSpotlight = true; - - } - - }, - - setWhichHand: function() { - this.whichHand = this.hand; - }, - - continueNearGrab: function() { - if (this.whichHand === null) { - //only set the active hand once -- if we always read the current hand, our 'holding' hand will get overwritten - this.setWhichHand(); - } else { - this.updateLightPositions(); - this.changeLightWithTriggerPressure(this.whichHand); - } - }, - - releaseGrab: function() { - //delete the lights and reset state - if (this.hasSpotlight) { - Entities.deleteEntity(this.spotlight); - Entities.deleteEntity(this.glowLight); - this.hasSpotlight = false; - this.glowLight = null; - this.spotlight = null; - this.whichHand = null; - this.lightOn = false; - } - }, - - updateLightPositions: function() { - var modelProperties = Entities.getEntityProperties(this.entityID, ['position', 'rotation']); - - //move the two lights along the vectors we set above - var lightTransform = evalLightWorldTransform(modelProperties.position, modelProperties.rotation); - var glowLightTransform = glowLightWorldTransform(modelProperties.position, modelProperties.rotation); - - //move them with the entity model - Entities.editEntity(this.spotlight, { - position: lightTransform.p, - rotation: lightTransform.q, - lifetime: (Date.now() - startTime) / MSEC_PER_SEC + LIFETIME - }); - - Entities.editEntity(this.glowLight, { - position: glowLightTransform.p, - rotation: glowLightTransform.q, - lifetime: (Date.now() - startTime) / MSEC_PER_SEC + LIFETIME - }); - - }, - - changeLightWithTriggerPressure: function(flashLightHand) { - var handClickString = flashLightHand + "_HAND_CLICK"; - - var handClick = Controller.findAction(handClickString); - - this.triggerValue = Controller.getActionValue(handClick); - - if (this.triggerValue < DISABLE_LIGHT_THRESHOLD && this.lightOn === true) { - this.turnLightOff(); - } else if (this.triggerValue >= DISABLE_LIGHT_THRESHOLD && this.lightOn === false) { - this.turnLightOn(); - } - return; - }, - - turnLightOff: function() { - this.playSoundAtCurrentPosition(false); - Entities.editEntity(this.spotlight, { - intensity: 0 - }); - Entities.editEntity(this.glowLight, { - intensity: 0 - }); - this.lightOn = false; - }, - - turnLightOn: function() { - this.playSoundAtCurrentPosition(true); - - Entities.editEntity(this.glowLight, { - intensity: 2 - }); - Entities.editEntity(this.spotlight, { - intensity: 2 - }); - this.lightOn = true; - }, - - playSoundAtCurrentPosition: function(playOnSound) { - var position = Entities.getEntityProperties(this.entityID, "position").position; - - var audioProperties = { - volume: 0.25, - position: position - }; - - if (playOnSound) { - Audio.playSound(this.ON_SOUND, audioProperties); - } else { - Audio.playSound(this.OFF_SOUND, audioProperties); - } - }, - - preload: function(entityID) { - - // preload() will be called when the entity has become visible (or known) to the interface - // it gives us a chance to set our local JavaScript object up. In this case it means: - // * remembering our entityID, so we can access it in cases where we're called without an entityID - // * preloading sounds - this.entityID = entityID; - this.ON_SOUND = SoundCache.getSound(ON_SOUND_URL); - this.OFF_SOUND = SoundCache.getSound(OFF_SOUND_URL); - - }, - - unload: function() { - // unload() will be called when our entity is no longer available. It may be because we were deleted, - // or because we've left the domain or quit the application. - if (this.hasSpotlight) { - Entities.deleteEntity(this.spotlight); - Entities.deleteEntity(this.glowLight); - this.hasSpotlight = false; - this.glowLight = null; - this.spotlight = null; - this.whichHand = null; - this.lightOn = false; - } - - }, - - }; - - // entity scripts always need to return a newly constructed object of our type - return new Flashlight(); +// +// flashlight.js +// +// Script Type: Entity +// +// Created by Sam Gateau on 9/9/15. +// Additions by James B. Pollack @imgntn on 9/21/2015 +// Copyright 2015 High Fidelity, Inc. +// +// This is a toy script that can be added to the Flashlight model entity: +// "https://hifi-public.s3.amazonaws.com/models/props/flashlight.fbx" +// that creates a spotlight attached with the flashlight model while the entity is grabbed +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +/*global MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */ +(function() { + + Script.include("../../libraries/utils.js"); + + var ON_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/flashlight_on.wav'; + var OFF_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/flashlight_off.wav'; + + //we are creating lights that we don't want to get stranded so lets make sure that we can get rid of them + var startTime = Date.now(); + //if you're going to be using this in a dungeon or something and holding it for a long time, increase this lifetime value. + var LIFETIME = 25; + var MSEC_PER_SEC = 1000.0; + + // this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember + // our this object, so we can access it in cases where we're called without a this (like in the case of various global signals) + function Flashlight() { + return; + } + + //if the trigger value goes below this while held, the flashlight will turn off. if it goes above, it will + var DISABLE_LIGHT_THRESHOLD = 0.7; + + // These constants define the Spotlight position and orientation relative to the model + var MODEL_LIGHT_POSITION = { + x: 0, + y: -0.3, + z: 0 + }; + var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, { + x: 1, + y: 0, + z: 0 + }); + + var GLOW_LIGHT_POSITION = { + x: 0, + y: -0.1, + z: 0 + }; + + // Evaluate the world light entity positions and orientations from the model ones + function evalLightWorldTransform(modelPos, modelRot) { + + return { + p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)), + q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) + }; + } + + function glowLightWorldTransform(modelPos, modelRot) { + return { + p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, GLOW_LIGHT_POSITION)), + q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION) + }; + } + + Flashlight.prototype = { + lightOn: false, + hand: null, + whichHand: null, + hasSpotlight: false, + spotlight: null, + setRightHand: function() { + this.hand = 'RIGHT'; + }, + + setLeftHand: function() { + this.hand = 'LEFT'; + }, + + startNearGrab: function() { + if (!this.hasSpotlight) { + + //this light casts the beam + this.spotlight = Entities.addEntity({ + type: "Light", + isSpotlight: true, + dimensions: { + x: 2, + y: 2, + z: 20 + }, + color: { + red: 255, + green: 255, + blue: 255 + }, + intensity: 2, + exponent: 0.3, + cutoff: 20, + lifetime: LIFETIME + }); + + //this light creates the effect of a bulb at the end of the flashlight + this.glowLight = Entities.addEntity({ + type: "Light", + dimensions: { + x: 0.25, + y: 0.25, + z: 0.25 + }, + isSpotlight: false, + color: { + red: 255, + green: 255, + blue: 255 + }, + exponent: 0, + cutoff: 90, // in degrees + lifetime: LIFETIME + }); + + this.hasSpotlight = true; + + } + + }, + + setWhichHand: function() { + this.whichHand = this.hand; + }, + + continueNearGrab: function() { + if (this.whichHand === null) { + //only set the active hand once -- if we always read the current hand, our 'holding' hand will get overwritten + this.setWhichHand(); + } else { + this.updateLightPositions(); + this.changeLightWithTriggerPressure(this.whichHand); + } + }, + + releaseGrab: function() { + //delete the lights and reset state + if (this.hasSpotlight) { + Entities.deleteEntity(this.spotlight); + Entities.deleteEntity(this.glowLight); + this.hasSpotlight = false; + this.glowLight = null; + this.spotlight = null; + this.whichHand = null; + this.lightOn = false; + } + }, + + updateLightPositions: function() { + var modelProperties = Entities.getEntityProperties(this.entityID, ['position', 'rotation']); + + //move the two lights along the vectors we set above + var lightTransform = evalLightWorldTransform(modelProperties.position, modelProperties.rotation); + var glowLightTransform = glowLightWorldTransform(modelProperties.position, modelProperties.rotation); + + //move them with the entity model + Entities.editEntity(this.spotlight, { + position: lightTransform.p, + rotation: lightTransform.q, + lifetime: (Date.now() - startTime) / MSEC_PER_SEC + LIFETIME + }); + + Entities.editEntity(this.glowLight, { + position: glowLightTransform.p, + rotation: glowLightTransform.q, + lifetime: (Date.now() - startTime) / MSEC_PER_SEC + LIFETIME + }); + + }, + + changeLightWithTriggerPressure: function(flashLightHand) { + var handClickString = flashLightHand + "_HAND_CLICK"; + + var handClick = Controller.findAction(handClickString); + + this.triggerValue = Controller.getActionValue(handClick); + + if (this.triggerValue < DISABLE_LIGHT_THRESHOLD && this.lightOn === true) { + this.turnLightOff(); + } else if (this.triggerValue >= DISABLE_LIGHT_THRESHOLD && this.lightOn === false) { + this.turnLightOn(); + } + return; + }, + + turnLightOff: function() { + this.playSoundAtCurrentPosition(false); + Entities.editEntity(this.spotlight, { + intensity: 0 + }); + Entities.editEntity(this.glowLight, { + intensity: 0 + }); + this.lightOn = false; + }, + + turnLightOn: function() { + this.playSoundAtCurrentPosition(true); + + Entities.editEntity(this.glowLight, { + intensity: 2 + }); + Entities.editEntity(this.spotlight, { + intensity: 2 + }); + this.lightOn = true; + }, + + playSoundAtCurrentPosition: function(playOnSound) { + var position = Entities.getEntityProperties(this.entityID, "position").position; + + var audioProperties = { + volume: 0.25, + position: position + }; + + if (playOnSound) { + Audio.playSound(this.ON_SOUND, audioProperties); + } else { + Audio.playSound(this.OFF_SOUND, audioProperties); + } + }, + + preload: function(entityID) { + + // preload() will be called when the entity has become visible (or known) to the interface + // it gives us a chance to set our local JavaScript object up. In this case it means: + // * remembering our entityID, so we can access it in cases where we're called without an entityID + // * preloading sounds + this.entityID = entityID; + this.ON_SOUND = SoundCache.getSound(ON_SOUND_URL); + this.OFF_SOUND = SoundCache.getSound(OFF_SOUND_URL); + + }, + + unload: function() { + // unload() will be called when our entity is no longer available. It may be because we were deleted, + // or because we've left the domain or quit the application. + if (this.hasSpotlight) { + Entities.deleteEntity(this.spotlight); + Entities.deleteEntity(this.glowLight); + this.hasSpotlight = false; + this.glowLight = null; + this.spotlight = null; + this.whichHand = null; + this.lightOn = false; + } + + }, + + }; + + // entity scripts always need to return a newly constructed object of our type + return new Flashlight(); }); \ No newline at end of file diff --git a/examples/walk.js b/examples/walk.js index 0b5bcab65a..63b5599cc2 100644 --- a/examples/walk.js +++ b/examples/walk.js @@ -1,454 +1,454 @@ -// -// walk.js -// version 1.25 -// -// Created by David Wooldridge, June 2015 -// Copyright © 2014 - 2015 High Fidelity, Inc. -// -// Animates an avatar using procedural animation techniques. -// -// Editing tools for animation data files available here: https://github.com/DaveDubUK/walkTools -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -// animations, reach poses, reach pose parameters, transitions, transition parameters, sounds, image/s and reference files -const HIFI_PUBLIC_BUCKET = "https://hifi-public.s3.amazonaws.com/"; -var pathToAssets = HIFI_PUBLIC_BUCKET + "procedural-animator/assets/"; - -Script.include([ - "./libraries/walkConstants.js", - "./libraries/walkFilters.js", - "./libraries/walkApi.js", - pathToAssets + "walkAssets.js" -]); - -// construct Avatar, Motion and (null) Transition -var avatar = new Avatar(); -var motion = new Motion(); -var nullTransition = new Transition(); -motion.currentTransition = nullTransition; - -// create settings (gets initial values from avatar) -Script.include("./libraries/walkSettings.js"); - -// Main loop -Script.update.connect(function(deltaTime) { - - if (motion.isLive) { - - // assess current locomotion state - motion.assess(deltaTime); - - // decide which animation should be playing - selectAnimation(); - - // advance the animation cycle/s by the correct amount/s - advanceAnimations(); - - // update the progress of any live transitions - updateTransitions(); - - // apply translation and rotations - renderMotion(); - - // save this frame's parameters - motion.saveHistory(); - } -}); - -// helper function for selectAnimation() -function setTransition(nextAnimation, playTransitionReachPoses) { - var lastTransition = motion.currentTransition; - var lastAnimation = avatar.currentAnimation; - - // if already transitioning from a blended walk need to maintain the previous walk's direction - if (lastAnimation.lastDirection) { - switch(lastAnimation.lastDirection) { - - case FORWARDS: - lastAnimation = avatar.selectedWalk; - break; - - case BACKWARDS: - lastAnimation = avatar.selectedWalkBackwards; - break; - - case LEFT: - lastAnimation = avatar.selectedSideStepLeft; - break; - - case RIGHT: - lastAnimation = avatar.selectedSideStepRight; - break; - } - } - - motion.currentTransition = new Transition(nextAnimation, lastAnimation, lastTransition, playTransitionReachPoses); - avatar.currentAnimation = nextAnimation; - - // reset default first footstep - if (nextAnimation === avatar.selectedWalkBlend && lastTransition === nullTransition) { - avatar.nextStep = RIGHT; - } -} - -// fly animation blending: smoothing / damping filters -const FLY_BLEND_DAMPING = 50; -var flyUpFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING); -var flyDownFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING); -var flyForwardFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING); -var flyBackwardFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING); - -// select / blend the appropriate animation for the current state of motion -function selectAnimation() { - var playTransitionReachPoses = true; - - // select appropriate animation. create transitions where appropriate - switch (motion.nextState) { - case STATIC: { - if (avatar.distanceFromSurface < ON_SURFACE_THRESHOLD && - avatar.currentAnimation !== avatar.selectedIdle) { - setTransition(avatar.selectedIdle, playTransitionReachPoses); - } else if (!(avatar.distanceFromSurface < ON_SURFACE_THRESHOLD) && - avatar.currentAnimation !== avatar.selectedHover) { - setTransition(avatar.selectedHover, playTransitionReachPoses); - } - motion.state = STATIC; - avatar.selectedWalkBlend.lastDirection = NONE; - break; - } - - case SURFACE_MOTION: { - // walk transition reach poses are currently only specified for starting to walk forwards - playTransitionReachPoses = (motion.direction === FORWARDS); - var isAlreadyWalking = (avatar.currentAnimation === avatar.selectedWalkBlend); - - switch (motion.direction) { - case FORWARDS: - if (avatar.selectedWalkBlend.lastDirection !== FORWARDS) { - animationOperations.deepCopy(avatar.selectedWalk, avatar.selectedWalkBlend); - avatar.calibration.strideLength = avatar.selectedWalk.calibration.strideLength; - } - avatar.selectedWalkBlend.lastDirection = FORWARDS; - break; - - case BACKWARDS: - if (avatar.selectedWalkBlend.lastDirection !== BACKWARDS) { - animationOperations.deepCopy(avatar.selectedWalkBackwards, avatar.selectedWalkBlend); - avatar.calibration.strideLength = avatar.selectedWalkBackwards.calibration.strideLength; - } - avatar.selectedWalkBlend.lastDirection = BACKWARDS; - break; - - case LEFT: - animationOperations.deepCopy(avatar.selectedSideStepLeft, avatar.selectedWalkBlend); - avatar.selectedWalkBlend.lastDirection = LEFT; - avatar.calibration.strideLength = avatar.selectedSideStepLeft.calibration.strideLength; - break - - case RIGHT: - animationOperations.deepCopy(avatar.selectedSideStepRight, avatar.selectedWalkBlend); - avatar.selectedWalkBlend.lastDirection = RIGHT; - avatar.calibration.strideLength = avatar.selectedSideStepRight.calibration.strideLength; - break; - - default: - // condition occurs when the avi goes through the floor due to collision hull errors - animationOperations.deepCopy(avatar.selectedWalk, avatar.selectedWalkBlend); - avatar.selectedWalkBlend.lastDirection = FORWARDS; - avatar.calibration.strideLength = avatar.selectedWalk.calibration.strideLength; - break; - } - - if (!isAlreadyWalking && !motion.isComingToHalt) { - setTransition(avatar.selectedWalkBlend, playTransitionReachPoses); - } - motion.state = SURFACE_MOTION; - break; - } - - case AIR_MOTION: { - // blend the up, down, forward and backward flying animations relative to motion speed and direction - animationOperations.zeroAnimation(avatar.selectedFlyBlend); - - // calculate influences based on velocity and direction - var velocityMagnitude = Vec3.length(motion.velocity); - var verticalProportion = motion.velocity.y / velocityMagnitude; - var thrustProportion = motion.velocity.z / velocityMagnitude / 2; - - // directional components - var upComponent = motion.velocity.y > 0 ? verticalProportion : 0; - var downComponent = motion.velocity.y < 0 ? -verticalProportion : 0; - var forwardComponent = motion.velocity.z < 0 ? -thrustProportion : 0; - var backwardComponent = motion.velocity.z > 0 ? thrustProportion : 0; - - // smooth / damp directional components to add visual 'weight' - upComponent = flyUpFilter.process(upComponent); - downComponent = flyDownFilter.process(downComponent); - forwardComponent = flyForwardFilter.process(forwardComponent); - backwardComponent = flyBackwardFilter.process(backwardComponent); - - // normalise directional components - var normaliser = upComponent + downComponent + forwardComponent + backwardComponent; - upComponent = upComponent / normaliser; - downComponent = downComponent / normaliser; - forwardComponent = forwardComponent / normaliser; - backwardComponent = backwardComponent / normaliser; - - // blend animations proportionally - if (upComponent > 0) { - animationOperations.blendAnimation(avatar.selectedFlyUp, - avatar.selectedFlyBlend, - upComponent); - } - if (downComponent > 0) { - animationOperations.blendAnimation(avatar.selectedFlyDown, - avatar.selectedFlyBlend, - downComponent); - } - if (forwardComponent > 0) { - animationOperations.blendAnimation(avatar.selectedFly, - avatar.selectedFlyBlend, - Math.abs(forwardComponent)); - } - if (backwardComponent > 0) { - animationOperations.blendAnimation(avatar.selectedFlyBackwards, - avatar.selectedFlyBlend, - Math.abs(backwardComponent)); - } - - if (avatar.currentAnimation !== avatar.selectedFlyBlend) { - setTransition(avatar.selectedFlyBlend, playTransitionReachPoses); - } - motion.state = AIR_MOTION; - avatar.selectedWalkBlend.lastDirection = NONE; - break; - } - } // end switch next state of motion -} - -// determine the length of stride. advance the frequency time wheels. advance frequency time wheels for any live transitions -function advanceAnimations() { - var wheelAdvance = 0; - - // turn the frequency time wheel - if (avatar.currentAnimation === avatar.selectedWalkBlend) { - // Using technique described here: http://www.gdcvault.com/play/1020583/Animation-Bootcamp-An-Indie-Approach - // wrap the stride length around a 'surveyor's wheel' twice and calculate the angular speed at the given (linear) speed - // omega = v / r , where r = circumference / 2 PI and circumference = 2 * stride length - var speed = Vec3.length(motion.velocity); - motion.frequencyTimeWheelRadius = avatar.calibration.strideLength / Math.PI; - var ftWheelAngularVelocity = speed / motion.frequencyTimeWheelRadius; - // calculate the degrees turned (at this angular speed) since last frame - wheelAdvance = filter.radToDeg(motion.deltaTime * ftWheelAngularVelocity); - } else { - // turn the frequency time wheel by the amount specified for this animation - wheelAdvance = filter.radToDeg(avatar.currentAnimation.calibration.frequency * motion.deltaTime); - } - - if (motion.currentTransition !== nullTransition) { - // the last animation is still playing so we turn it's frequency time wheel to maintain the animation - if (motion.currentTransition.lastAnimation === motion.selectedWalkBlend) { - // if at a stop angle (i.e. feet now under the avi) hold the wheel position for remainder of transition - var tolerance = motion.currentTransition.lastFrequencyTimeIncrement + 0.1; - if ((motion.currentTransition.lastFrequencyTimeWheelPos > - (motion.currentTransition.stopAngle - tolerance)) && - (motion.currentTransition.lastFrequencyTimeWheelPos < - (motion.currentTransition.stopAngle + tolerance))) { - motion.currentTransition.lastFrequencyTimeIncrement = 0; - } - } - motion.currentTransition.advancePreviousFrequencyTimeWheel(motion.deltaTime); - } - - // avoid unnaturally fast walking when landing at speed - simulates skimming / skidding - if (Math.abs(wheelAdvance) > MAX_FT_WHEEL_INCREMENT) { - wheelAdvance = 0; - } - - // advance the walk wheel the appropriate amount - motion.advanceFrequencyTimeWheel(wheelAdvance); - - // walking? then see if it's a good time to measure the stride length (needs to be at least 97% of max walking speed) - const ALMOST_ONE = 0.97; - if (avatar.currentAnimation === avatar.selectedWalkBlend && - (Vec3.length(motion.velocity) / MAX_WALK_SPEED > ALMOST_ONE)) { - - var strideMaxAt = avatar.currentAnimation.calibration.strideMaxAt; - const TOLERANCE = 1.0; - - if (motion.frequencyTimeWheelPos < (strideMaxAt + TOLERANCE) && - motion.frequencyTimeWheelPos > (strideMaxAt - TOLERANCE) && - motion.currentTransition === nullTransition) { - // measure and save stride length - var footRPos = MyAvatar.getJointPosition("RightFoot"); - var footLPos = MyAvatar.getJointPosition("LeftFoot"); - avatar.calibration.strideLength = Vec3.distance(footRPos, footLPos); - avatar.currentAnimation.calibration.strideLength = avatar.calibration.strideLength; - } else { - // use the previously saved value for stride length - avatar.calibration.strideLength = avatar.currentAnimation.calibration.strideLength; - } - } // end get walk stride length -} - -// initialise a new transition. update progress of a live transition -function updateTransitions() { - - if (motion.currentTransition !== nullTransition) { - // is this a new transition? - if (motion.currentTransition.progress === 0) { - // do we have overlapping transitions? - if (motion.currentTransition.lastTransition !== nullTransition) { - // is the last animation for the nested transition the same as the new animation? - if (motion.currentTransition.lastTransition.lastAnimation === avatar.currentAnimation) { - // then sync the nested transition's frequency time wheel for a smooth animation blend - motion.frequencyTimeWheelPos = motion.currentTransition.lastTransition.lastFrequencyTimeWheelPos; - } - } - } - if (motion.currentTransition.updateProgress() === TRANSITION_COMPLETE) { - motion.currentTransition = nullTransition; - } - } -} - -// helper function for renderMotion(). calculate the amount to lean forwards (or backwards) based on the avi's velocity -var leanPitchSmoothingFilter = filter.createButterworthFilter(); -function getLeanPitch() { - var leanProgress = 0; - - if (motion.direction === DOWN || - motion.direction === FORWARDS || - motion.direction === BACKWARDS) { - leanProgress = -motion.velocity.z / TOP_SPEED; - } - // use filters to shape the walking acceleration response - leanProgress = leanPitchSmoothingFilter.process(leanProgress); - return PITCH_MAX * leanProgress; -} - -// helper function for renderMotion(). calculate the angle at which to bank into corners whilst turning -var leanRollSmoothingFilter = filter.createButterworthFilter(); -function getLeanRoll() { - var leanRollProgress = 0; - var linearContribution = 0; - const LOG_SCALER = 8; - - if (Vec3.length(motion.velocity) > 0) { - linearContribution = (Math.log(Vec3.length(motion.velocity) / TOP_SPEED) + LOG_SCALER) / LOG_SCALER; - } - var angularContribution = Math.abs(motion.yawDelta) / DELTA_YAW_MAX; - leanRollProgress = linearContribution; - leanRollProgress *= angularContribution; - // shape the response curve - leanRollProgress = filter.bezier(leanRollProgress, {x: 1, y: 0}, {x: 1, y: 0}); - // which way to lean? - var turnSign = (motion.yawDelta >= 0) ? 1 : -1; - - if (motion.direction === BACKWARDS || - motion.direction === LEFT) { - turnSign *= -1; - } - // filter progress - leanRollProgress = leanRollSmoothingFilter.process(turnSign * leanRollProgress); - return ROLL_MAX * leanRollProgress; -} - -// animate the avatar using sine waves, geometric waveforms and harmonic generators -function renderMotion() { - // leaning in response to speed and acceleration - var leanPitch = motion.state === STATIC ? 0 : getLeanPitch(); - var leanRoll = motion.state === STATIC ? 0 : getLeanRoll(); - var lastDirection = motion.lastDirection; - // hips translations from currently playing animations - var hipsTranslations = {x:0, y:0, z:0}; - - if (motion.currentTransition !== nullTransition) { - // maintain previous direction when transitioning from a walk - if (motion.currentTransition.lastAnimation === avatar.selectedWalkBlend) { - motion.lastDirection = motion.currentTransition.lastDirection; - } - hipsTranslations = motion.currentTransition.blendTranslations(motion.frequencyTimeWheelPos, - motion.lastDirection); - } else { - hipsTranslations = animationOperations.calculateTranslations(avatar.currentAnimation, - motion.frequencyTimeWheelPos, - motion.direction); - } - // factor any leaning into the hips offset - hipsTranslations.z += avatar.calibration.hipsToFeet * Math.sin(filter.degToRad(leanPitch)); - hipsTranslations.x += avatar.calibration.hipsToFeet * Math.sin(filter.degToRad(leanRoll)); - - // ensure skeleton offsets are within the 1m limit - hipsTranslations.x = hipsTranslations.x > 1 ? 1 : hipsTranslations.x; - hipsTranslations.x = hipsTranslations.x < -1 ? -1 : hipsTranslations.x; - hipsTranslations.y = hipsTranslations.y > 1 ? 1 : hipsTranslations.y; - hipsTranslations.y = hipsTranslations.y < -1 ? -1 : hipsTranslations.y; - hipsTranslations.z = hipsTranslations.z > 1 ? 1 : hipsTranslations.z; - hipsTranslations.z = hipsTranslations.z < -1 ? -1 : hipsTranslations.z; - // apply translations - MyAvatar.setSkeletonOffset(hipsTranslations); - - // play footfall sound? - var producingFootstepSounds = (avatar.currentAnimation === avatar.selectedWalkBlend) && avatar.makesFootStepSounds; - - if (motion.currentTransition !== nullTransition && avatar.makesFootStepSounds) { - if (motion.currentTransition.nextAnimation === avatar.selectedWalkBlend || - motion.currentTransition.lastAnimation === avatar.selectedWalkBlend) { - producingFootstepSounds = true; - } - } - if (producingFootstepSounds) { - const QUARTER_CYCLE = 90; - const THREE_QUARTER_CYCLE = 270; - var ftWheelPosition = motion.frequencyTimeWheelPos; - - if (motion.currentTransition !== nullTransition && - motion.currentTransition.lastAnimation === avatar.selectedWalkBlend) { - ftWheelPosition = motion.currentTransition.lastFrequencyTimeWheelPos; - } - if (avatar.nextStep === LEFT && ftWheelPosition > THREE_QUARTER_CYCLE) { - avatar.makeFootStepSound(); - } else if (avatar.nextStep === RIGHT && (ftWheelPosition < THREE_QUARTER_CYCLE && ftWheelPosition > QUARTER_CYCLE)) { - avatar.makeFootStepSound(); - } - } - - // apply joint rotations - for (jointName in avatar.currentAnimation.joints) { - var joint = walkAssets.animationReference.joints[jointName]; - var jointRotations = undefined; - - // ignore arms / head rotations if options are selected in the settings - if (avatar.armsFree && (joint.IKChain === "LeftArm" || joint.IKChain === "RightArm")) { - continue; - } - if (avatar.headFree && joint.IKChain === "Head") { - continue; - } - - // if there's a live transition, blend the rotations with the last animation's rotations - if (motion.currentTransition !== nullTransition) { - jointRotations = motion.currentTransition.blendRotations(jointName, - motion.frequencyTimeWheelPos, - motion.lastDirection); - } else { - jointRotations = animationOperations.calculateRotations(jointName, - avatar.currentAnimation, - motion.frequencyTimeWheelPos, - motion.direction); - } - - // apply angular velocity and speed induced leaning - if (jointName === "Hips") { - jointRotations.x += leanPitch; - jointRotations.z += leanRoll; - } - - // apply rotations - MyAvatar.setJointRotation(jointName, Quat.fromVec3Degrees(jointRotations)); - } +// +// walk.js +// version 1.25 +// +// Created by David Wooldridge, June 2015 +// Copyright © 2014 - 2015 High Fidelity, Inc. +// +// Animates an avatar using procedural animation techniques. +// +// Editing tools for animation data files available here: https://github.com/DaveDubUK/walkTools +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// animations, reach poses, reach pose parameters, transitions, transition parameters, sounds, image/s and reference files +const HIFI_PUBLIC_BUCKET = "https://hifi-public.s3.amazonaws.com/"; +var pathToAssets = HIFI_PUBLIC_BUCKET + "procedural-animator/assets/"; + +Script.include([ + "./libraries/walkConstants.js", + "./libraries/walkFilters.js", + "./libraries/walkApi.js", + pathToAssets + "walkAssets.js" +]); + +// construct Avatar, Motion and (null) Transition +var avatar = new Avatar(); +var motion = new Motion(); +var nullTransition = new Transition(); +motion.currentTransition = nullTransition; + +// create settings (gets initial values from avatar) +Script.include("./libraries/walkSettings.js"); + +// Main loop +Script.update.connect(function(deltaTime) { + + if (motion.isLive) { + + // assess current locomotion state + motion.assess(deltaTime); + + // decide which animation should be playing + selectAnimation(); + + // advance the animation cycle/s by the correct amount/s + advanceAnimations(); + + // update the progress of any live transitions + updateTransitions(); + + // apply translation and rotations + renderMotion(); + + // save this frame's parameters + motion.saveHistory(); + } +}); + +// helper function for selectAnimation() +function setTransition(nextAnimation, playTransitionReachPoses) { + var lastTransition = motion.currentTransition; + var lastAnimation = avatar.currentAnimation; + + // if already transitioning from a blended walk need to maintain the previous walk's direction + if (lastAnimation.lastDirection) { + switch(lastAnimation.lastDirection) { + + case FORWARDS: + lastAnimation = avatar.selectedWalk; + break; + + case BACKWARDS: + lastAnimation = avatar.selectedWalkBackwards; + break; + + case LEFT: + lastAnimation = avatar.selectedSideStepLeft; + break; + + case RIGHT: + lastAnimation = avatar.selectedSideStepRight; + break; + } + } + + motion.currentTransition = new Transition(nextAnimation, lastAnimation, lastTransition, playTransitionReachPoses); + avatar.currentAnimation = nextAnimation; + + // reset default first footstep + if (nextAnimation === avatar.selectedWalkBlend && lastTransition === nullTransition) { + avatar.nextStep = RIGHT; + } +} + +// fly animation blending: smoothing / damping filters +const FLY_BLEND_DAMPING = 50; +var flyUpFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING); +var flyDownFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING); +var flyForwardFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING); +var flyBackwardFilter = filter.createAveragingFilter(FLY_BLEND_DAMPING); + +// select / blend the appropriate animation for the current state of motion +function selectAnimation() { + var playTransitionReachPoses = true; + + // select appropriate animation. create transitions where appropriate + switch (motion.nextState) { + case STATIC: { + if (avatar.distanceFromSurface < ON_SURFACE_THRESHOLD && + avatar.currentAnimation !== avatar.selectedIdle) { + setTransition(avatar.selectedIdle, playTransitionReachPoses); + } else if (!(avatar.distanceFromSurface < ON_SURFACE_THRESHOLD) && + avatar.currentAnimation !== avatar.selectedHover) { + setTransition(avatar.selectedHover, playTransitionReachPoses); + } + motion.state = STATIC; + avatar.selectedWalkBlend.lastDirection = NONE; + break; + } + + case SURFACE_MOTION: { + // walk transition reach poses are currently only specified for starting to walk forwards + playTransitionReachPoses = (motion.direction === FORWARDS); + var isAlreadyWalking = (avatar.currentAnimation === avatar.selectedWalkBlend); + + switch (motion.direction) { + case FORWARDS: + if (avatar.selectedWalkBlend.lastDirection !== FORWARDS) { + animationOperations.deepCopy(avatar.selectedWalk, avatar.selectedWalkBlend); + avatar.calibration.strideLength = avatar.selectedWalk.calibration.strideLength; + } + avatar.selectedWalkBlend.lastDirection = FORWARDS; + break; + + case BACKWARDS: + if (avatar.selectedWalkBlend.lastDirection !== BACKWARDS) { + animationOperations.deepCopy(avatar.selectedWalkBackwards, avatar.selectedWalkBlend); + avatar.calibration.strideLength = avatar.selectedWalkBackwards.calibration.strideLength; + } + avatar.selectedWalkBlend.lastDirection = BACKWARDS; + break; + + case LEFT: + animationOperations.deepCopy(avatar.selectedSideStepLeft, avatar.selectedWalkBlend); + avatar.selectedWalkBlend.lastDirection = LEFT; + avatar.calibration.strideLength = avatar.selectedSideStepLeft.calibration.strideLength; + break + + case RIGHT: + animationOperations.deepCopy(avatar.selectedSideStepRight, avatar.selectedWalkBlend); + avatar.selectedWalkBlend.lastDirection = RIGHT; + avatar.calibration.strideLength = avatar.selectedSideStepRight.calibration.strideLength; + break; + + default: + // condition occurs when the avi goes through the floor due to collision hull errors + animationOperations.deepCopy(avatar.selectedWalk, avatar.selectedWalkBlend); + avatar.selectedWalkBlend.lastDirection = FORWARDS; + avatar.calibration.strideLength = avatar.selectedWalk.calibration.strideLength; + break; + } + + if (!isAlreadyWalking && !motion.isComingToHalt) { + setTransition(avatar.selectedWalkBlend, playTransitionReachPoses); + } + motion.state = SURFACE_MOTION; + break; + } + + case AIR_MOTION: { + // blend the up, down, forward and backward flying animations relative to motion speed and direction + animationOperations.zeroAnimation(avatar.selectedFlyBlend); + + // calculate influences based on velocity and direction + var velocityMagnitude = Vec3.length(motion.velocity); + var verticalProportion = motion.velocity.y / velocityMagnitude; + var thrustProportion = motion.velocity.z / velocityMagnitude / 2; + + // directional components + var upComponent = motion.velocity.y > 0 ? verticalProportion : 0; + var downComponent = motion.velocity.y < 0 ? -verticalProportion : 0; + var forwardComponent = motion.velocity.z < 0 ? -thrustProportion : 0; + var backwardComponent = motion.velocity.z > 0 ? thrustProportion : 0; + + // smooth / damp directional components to add visual 'weight' + upComponent = flyUpFilter.process(upComponent); + downComponent = flyDownFilter.process(downComponent); + forwardComponent = flyForwardFilter.process(forwardComponent); + backwardComponent = flyBackwardFilter.process(backwardComponent); + + // normalise directional components + var normaliser = upComponent + downComponent + forwardComponent + backwardComponent; + upComponent = upComponent / normaliser; + downComponent = downComponent / normaliser; + forwardComponent = forwardComponent / normaliser; + backwardComponent = backwardComponent / normaliser; + + // blend animations proportionally + if (upComponent > 0) { + animationOperations.blendAnimation(avatar.selectedFlyUp, + avatar.selectedFlyBlend, + upComponent); + } + if (downComponent > 0) { + animationOperations.blendAnimation(avatar.selectedFlyDown, + avatar.selectedFlyBlend, + downComponent); + } + if (forwardComponent > 0) { + animationOperations.blendAnimation(avatar.selectedFly, + avatar.selectedFlyBlend, + Math.abs(forwardComponent)); + } + if (backwardComponent > 0) { + animationOperations.blendAnimation(avatar.selectedFlyBackwards, + avatar.selectedFlyBlend, + Math.abs(backwardComponent)); + } + + if (avatar.currentAnimation !== avatar.selectedFlyBlend) { + setTransition(avatar.selectedFlyBlend, playTransitionReachPoses); + } + motion.state = AIR_MOTION; + avatar.selectedWalkBlend.lastDirection = NONE; + break; + } + } // end switch next state of motion +} + +// determine the length of stride. advance the frequency time wheels. advance frequency time wheels for any live transitions +function advanceAnimations() { + var wheelAdvance = 0; + + // turn the frequency time wheel + if (avatar.currentAnimation === avatar.selectedWalkBlend) { + // Using technique described here: http://www.gdcvault.com/play/1020583/Animation-Bootcamp-An-Indie-Approach + // wrap the stride length around a 'surveyor's wheel' twice and calculate the angular speed at the given (linear) speed + // omega = v / r , where r = circumference / 2 PI and circumference = 2 * stride length + var speed = Vec3.length(motion.velocity); + motion.frequencyTimeWheelRadius = avatar.calibration.strideLength / Math.PI; + var ftWheelAngularVelocity = speed / motion.frequencyTimeWheelRadius; + // calculate the degrees turned (at this angular speed) since last frame + wheelAdvance = filter.radToDeg(motion.deltaTime * ftWheelAngularVelocity); + } else { + // turn the frequency time wheel by the amount specified for this animation + wheelAdvance = filter.radToDeg(avatar.currentAnimation.calibration.frequency * motion.deltaTime); + } + + if (motion.currentTransition !== nullTransition) { + // the last animation is still playing so we turn it's frequency time wheel to maintain the animation + if (motion.currentTransition.lastAnimation === motion.selectedWalkBlend) { + // if at a stop angle (i.e. feet now under the avi) hold the wheel position for remainder of transition + var tolerance = motion.currentTransition.lastFrequencyTimeIncrement + 0.1; + if ((motion.currentTransition.lastFrequencyTimeWheelPos > + (motion.currentTransition.stopAngle - tolerance)) && + (motion.currentTransition.lastFrequencyTimeWheelPos < + (motion.currentTransition.stopAngle + tolerance))) { + motion.currentTransition.lastFrequencyTimeIncrement = 0; + } + } + motion.currentTransition.advancePreviousFrequencyTimeWheel(motion.deltaTime); + } + + // avoid unnaturally fast walking when landing at speed - simulates skimming / skidding + if (Math.abs(wheelAdvance) > MAX_FT_WHEEL_INCREMENT) { + wheelAdvance = 0; + } + + // advance the walk wheel the appropriate amount + motion.advanceFrequencyTimeWheel(wheelAdvance); + + // walking? then see if it's a good time to measure the stride length (needs to be at least 97% of max walking speed) + const ALMOST_ONE = 0.97; + if (avatar.currentAnimation === avatar.selectedWalkBlend && + (Vec3.length(motion.velocity) / MAX_WALK_SPEED > ALMOST_ONE)) { + + var strideMaxAt = avatar.currentAnimation.calibration.strideMaxAt; + const TOLERANCE = 1.0; + + if (motion.frequencyTimeWheelPos < (strideMaxAt + TOLERANCE) && + motion.frequencyTimeWheelPos > (strideMaxAt - TOLERANCE) && + motion.currentTransition === nullTransition) { + // measure and save stride length + var footRPos = MyAvatar.getJointPosition("RightFoot"); + var footLPos = MyAvatar.getJointPosition("LeftFoot"); + avatar.calibration.strideLength = Vec3.distance(footRPos, footLPos); + avatar.currentAnimation.calibration.strideLength = avatar.calibration.strideLength; + } else { + // use the previously saved value for stride length + avatar.calibration.strideLength = avatar.currentAnimation.calibration.strideLength; + } + } // end get walk stride length +} + +// initialise a new transition. update progress of a live transition +function updateTransitions() { + + if (motion.currentTransition !== nullTransition) { + // is this a new transition? + if (motion.currentTransition.progress === 0) { + // do we have overlapping transitions? + if (motion.currentTransition.lastTransition !== nullTransition) { + // is the last animation for the nested transition the same as the new animation? + if (motion.currentTransition.lastTransition.lastAnimation === avatar.currentAnimation) { + // then sync the nested transition's frequency time wheel for a smooth animation blend + motion.frequencyTimeWheelPos = motion.currentTransition.lastTransition.lastFrequencyTimeWheelPos; + } + } + } + if (motion.currentTransition.updateProgress() === TRANSITION_COMPLETE) { + motion.currentTransition = nullTransition; + } + } +} + +// helper function for renderMotion(). calculate the amount to lean forwards (or backwards) based on the avi's velocity +var leanPitchSmoothingFilter = filter.createButterworthFilter(); +function getLeanPitch() { + var leanProgress = 0; + + if (motion.direction === DOWN || + motion.direction === FORWARDS || + motion.direction === BACKWARDS) { + leanProgress = -motion.velocity.z / TOP_SPEED; + } + // use filters to shape the walking acceleration response + leanProgress = leanPitchSmoothingFilter.process(leanProgress); + return PITCH_MAX * leanProgress; +} + +// helper function for renderMotion(). calculate the angle at which to bank into corners whilst turning +var leanRollSmoothingFilter = filter.createButterworthFilter(); +function getLeanRoll() { + var leanRollProgress = 0; + var linearContribution = 0; + const LOG_SCALER = 8; + + if (Vec3.length(motion.velocity) > 0) { + linearContribution = (Math.log(Vec3.length(motion.velocity) / TOP_SPEED) + LOG_SCALER) / LOG_SCALER; + } + var angularContribution = Math.abs(motion.yawDelta) / DELTA_YAW_MAX; + leanRollProgress = linearContribution; + leanRollProgress *= angularContribution; + // shape the response curve + leanRollProgress = filter.bezier(leanRollProgress, {x: 1, y: 0}, {x: 1, y: 0}); + // which way to lean? + var turnSign = (motion.yawDelta >= 0) ? 1 : -1; + + if (motion.direction === BACKWARDS || + motion.direction === LEFT) { + turnSign *= -1; + } + // filter progress + leanRollProgress = leanRollSmoothingFilter.process(turnSign * leanRollProgress); + return ROLL_MAX * leanRollProgress; +} + +// animate the avatar using sine waves, geometric waveforms and harmonic generators +function renderMotion() { + // leaning in response to speed and acceleration + var leanPitch = motion.state === STATIC ? 0 : getLeanPitch(); + var leanRoll = motion.state === STATIC ? 0 : getLeanRoll(); + var lastDirection = motion.lastDirection; + // hips translations from currently playing animations + var hipsTranslations = {x:0, y:0, z:0}; + + if (motion.currentTransition !== nullTransition) { + // maintain previous direction when transitioning from a walk + if (motion.currentTransition.lastAnimation === avatar.selectedWalkBlend) { + motion.lastDirection = motion.currentTransition.lastDirection; + } + hipsTranslations = motion.currentTransition.blendTranslations(motion.frequencyTimeWheelPos, + motion.lastDirection); + } else { + hipsTranslations = animationOperations.calculateTranslations(avatar.currentAnimation, + motion.frequencyTimeWheelPos, + motion.direction); + } + // factor any leaning into the hips offset + hipsTranslations.z += avatar.calibration.hipsToFeet * Math.sin(filter.degToRad(leanPitch)); + hipsTranslations.x += avatar.calibration.hipsToFeet * Math.sin(filter.degToRad(leanRoll)); + + // ensure skeleton offsets are within the 1m limit + hipsTranslations.x = hipsTranslations.x > 1 ? 1 : hipsTranslations.x; + hipsTranslations.x = hipsTranslations.x < -1 ? -1 : hipsTranslations.x; + hipsTranslations.y = hipsTranslations.y > 1 ? 1 : hipsTranslations.y; + hipsTranslations.y = hipsTranslations.y < -1 ? -1 : hipsTranslations.y; + hipsTranslations.z = hipsTranslations.z > 1 ? 1 : hipsTranslations.z; + hipsTranslations.z = hipsTranslations.z < -1 ? -1 : hipsTranslations.z; + // apply translations + MyAvatar.setSkeletonOffset(hipsTranslations); + + // play footfall sound? + var producingFootstepSounds = (avatar.currentAnimation === avatar.selectedWalkBlend) && avatar.makesFootStepSounds; + + if (motion.currentTransition !== nullTransition && avatar.makesFootStepSounds) { + if (motion.currentTransition.nextAnimation === avatar.selectedWalkBlend || + motion.currentTransition.lastAnimation === avatar.selectedWalkBlend) { + producingFootstepSounds = true; + } + } + if (producingFootstepSounds) { + const QUARTER_CYCLE = 90; + const THREE_QUARTER_CYCLE = 270; + var ftWheelPosition = motion.frequencyTimeWheelPos; + + if (motion.currentTransition !== nullTransition && + motion.currentTransition.lastAnimation === avatar.selectedWalkBlend) { + ftWheelPosition = motion.currentTransition.lastFrequencyTimeWheelPos; + } + if (avatar.nextStep === LEFT && ftWheelPosition > THREE_QUARTER_CYCLE) { + avatar.makeFootStepSound(); + } else if (avatar.nextStep === RIGHT && (ftWheelPosition < THREE_QUARTER_CYCLE && ftWheelPosition > QUARTER_CYCLE)) { + avatar.makeFootStepSound(); + } + } + + // apply joint rotations + for (jointName in avatar.currentAnimation.joints) { + var joint = walkAssets.animationReference.joints[jointName]; + var jointRotations = undefined; + + // ignore arms / head rotations if options are selected in the settings + if (avatar.armsFree && (joint.IKChain === "LeftArm" || joint.IKChain === "RightArm")) { + continue; + } + if (avatar.headFree && joint.IKChain === "Head") { + continue; + } + + // if there's a live transition, blend the rotations with the last animation's rotations + if (motion.currentTransition !== nullTransition) { + jointRotations = motion.currentTransition.blendRotations(jointName, + motion.frequencyTimeWheelPos, + motion.lastDirection); + } else { + jointRotations = animationOperations.calculateRotations(jointName, + avatar.currentAnimation, + motion.frequencyTimeWheelPos, + motion.direction); + } + + // apply angular velocity and speed induced leaning + if (jointName === "Hips") { + jointRotations.x += leanPitch; + jointRotations.z += leanRoll; + } + + // apply rotations + MyAvatar.setJointRotation(jointName, Quat.fromVec3Degrees(jointRotations)); + } } \ No newline at end of file From bfd96194040b880d91c1b22b61274fea44fb717f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 21 Oct 2015 10:10:04 -0700 Subject: [PATCH 013/401] add simple script that spawns a bat when run --- examples/toys/baseball.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 examples/toys/baseball.js diff --git a/examples/toys/baseball.js b/examples/toys/baseball.js new file mode 100644 index 0000000000..79a8a2fd61 --- /dev/null +++ b/examples/toys/baseball.js @@ -0,0 +1,30 @@ +// +// baseball.js +// examples/toys +// +// Created by Stephen Birarda on 10/20/15. +// 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 +// + +var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; +var BAT_COLLISION_SHAPE = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; + +function createNewBat() { + // move entity three units in front of the avatar + var batPosition = Vec3.sum(MyAvatar.position, + Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: -0.3, z: -2 })); + + var wand = Entities.addEntity({ + name: 'Bat', + type: "Model", + modelURL: BAT_MODEL, + position: batPosition, + collisionsWillMove: true, + compoundShapeURL: BAT_COLLISION_SHAPE + }); +} + +createNewBat(); From 1e39c9359f363cbde506ba5411e1bf3bf8da161f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 21 Oct 2015 11:53:38 -0700 Subject: [PATCH 014/401] don't force parenting of AssetRequest/AssetUpload --- libraries/networking/src/AssetClient.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index b7f1205847..6a1b46340c 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -89,7 +89,6 @@ AssetRequest* AssetClient::createRequest(const QString& hash, const QString& ext // Move to the AssetClient thread in case we are not currently on that thread (which will usually be the case) request->moveToThread(thread()); - request->setParent(this); return request; } else { @@ -105,7 +104,6 @@ AssetUpload* AssetClient::createUpload(const QString& filename) { auto upload = new AssetUpload(filename); upload->moveToThread(thread()); - upload->setParent(this); return upload; } else { @@ -118,7 +116,6 @@ AssetUpload* AssetClient::createUpload(const QByteArray& data, const QString& ex auto upload = new AssetUpload(data, extension); upload->moveToThread(thread()); - upload->setParent(this); return upload; } else { From 8f83870e527ab2d59eaf8237b5a1d297439016c3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 21 Oct 2015 14:19:21 -0700 Subject: [PATCH 015/401] Update pitching.js to add audio --- examples/baseball/audio/assets.txt | 23 ++++ examples/baseball/audio/attribution.txt | 8 ++ examples/baseball/line.js | 165 ++++++++++++++++++++++++ examples/{ => baseball}/pitching.js | 0 4 files changed, 196 insertions(+) create mode 100644 examples/baseball/audio/assets.txt create mode 100644 examples/baseball/audio/attribution.txt create mode 100644 examples/baseball/line.js rename examples/{ => baseball}/pitching.js (100%) diff --git a/examples/baseball/audio/assets.txt b/examples/baseball/audio/assets.txt new file mode 100644 index 0000000000..225714cbe1 --- /dev/null +++ b/examples/baseball/audio/assets.txt @@ -0,0 +1,23 @@ +crowd-boos.wav +atp:c632c92b166ade60aa16b23ff1dfdf712856caeb83bd9311980b2d5edac821af.wav + +crowd-cheers-organ.wav +atp:b8044401a846ed29f881a0b9b80cf1ba41f26327180c28fc9c70d144f9b70045.wav + +crowd-medium.wav +atp:0821bf2ac60dd2f356dfdd948e8bb89c23984dc3584612f6c815765154f02cae.wav + +baseball-hitting-bat-1.wav +atp:6f0b691a0c9c9ece6557d97fe242b1faec4020fe26efc9c17327993b513c5fe5.wav + +baseball-hitting-bat-set-1.wav +atp:5be5806205158ebdc5c3623ceb7ae73315028b51ffeae24292aff7042e3fa6a9.wav + +baseball-hitting-bat-set-2.wav +atp:e68661374e2145c480809c26134782aad11e0de456c7802170c7abccc4028873.wav + +baseball-hitting-bat-set-3.wav +atp:787e3c9af17dd3929527787176ede83d6806260e63ddd5a4cef48cd22e32c6f7.wav + +baseball-hitting-bat-set-4.wav +atp:fc65383431a6238c7a4749f0f6f061f75a604ed5e17d775ab1b2955609e67ebb.wav \ No newline at end of file diff --git a/examples/baseball/audio/attribution.txt b/examples/baseball/audio/attribution.txt new file mode 100644 index 0000000000..760951447c --- /dev/null +++ b/examples/baseball/audio/attribution.txt @@ -0,0 +1,8 @@ +Baseball bat hitting sounds +https://www.freesound.org/people/SocializedArtist45/sounds/266595/ +https://www.freesound.org/people/CGEffex/sounds/93136/ + +Crowd Sounds +http://freesound.org/people/AshFox/sounds/191925/ +http://freesound.org/people/AshFox/sounds/191928/ +http://freesound.org/people/AshFox/sounds/191929/ \ No newline at end of file diff --git a/examples/baseball/line.js b/examples/baseball/line.js new file mode 100644 index 0000000000..c4fac784c4 --- /dev/null +++ b/examples/baseball/line.js @@ -0,0 +1,165 @@ +function info(message) { + print("[INFO] " + message); +} + +function error(message) { + print("[ERROR] " + message); +} + + +/****************************************************************************** + * PolyLine + *****************************************************************************/ +var LINE_DIMENSIONS = { x: 2000, y: 2000, z: 2000 }; +var MAX_LINE_LENGTH = 40; // This must be 2 or greater; +var PolyLine = function(position, color, defaultStrokeWidth) { + //info("Creating polyline"); + //Vec3.print("New line at", position); + this.position = position; + this.color = color; + this.defaultStrokeWidth = 0.10; + this.points = [ + { x: 0, y: 0, z: 0 }, + ]; + this.strokeWidths = [ + this.defaultStrokeWidth, + ] + this.normals = [ + { x: 1, y: 0, z: 0 }, + ] + this.entityID = Entities.addEntity({ + type: "PolyLine", + position: position, + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths, + dimensions: LINE_DIMENSIONS, + color: color, + lifetime: 20, + }); +}; + +PolyLine.prototype.enqueuePoint = function(position) { + if (this.isFull()) { + error("Hit max PolyLine size"); + return; + } + + //Vec3.print("pos", position); + //info("Number of points: " + this.points.length); + + position = Vec3.subtract(position, this.position); + this.points.push(position); + this.normals.push({ x: 1, y: 0, z: 0 }); + this.strokeWidths.push(this.defaultStrokeWidth); + Entities.editEntity(this.entityID, { + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths, + }); +}; + +PolyLine.prototype.dequeuePoint = function() { + if (this.points.length == 0) { + error("Hit min PolyLine size"); + return; + } + + this.points = this.points.slice(1); + this.normals = this.normals.slice(1); + this.strokeWidths = this.strokeWidths.slice(1); + + Entities.editEntity(this.entityID, { + linePoints: this.points, + normals: this.normals, + strokeWidths: this.strokeWidths, + }); +}; + +PolyLine.prototype.getFirstPoint = function() { + return Vec3.sum(this.position, this.points[0]); +}; + +PolyLine.prototype.getLastPoint = function() { + return Vec3.sum(this.position, this.points[this.points.length - 1]); +}; + +PolyLine.prototype.getSize = function() { + return this.points.length; +} + +PolyLine.prototype.isFull = function() { + return this.points.length >= MAX_LINE_LENGTH; +}; + +PolyLine.prototype.destroy = function() { + Entities.deleteEntity(this.entityID); + this.points = []; +}; + + +/****************************************************************************** + * InfiniteLine + *****************************************************************************/ +InfiniteLine = function(position, color) { + this.position = position; + this.color = color; + this.lines = [new PolyLine(position, color)]; + this.size = 0; +}; + +InfiniteLine.prototype.enqueuePoint = function(position) { + var currentLine; + + if (this.lines.length == 0) { + currentLine = new PolyLine(position, this.color); + this.lines.push(currentLine); + } else { + currentLine = this.lines[this.lines.length - 1]; + } + + if (currentLine.isFull()) { + //info("Current line is full, creating new line"); + //Vec3.print("Last line is", currentLine.getLastPoint()); + //Vec3.print("New line is", position); + var newLine = new PolyLine(currentLine.getLastPoint(), this.color); + this.lines.push(newLine); + currentLine = newLine; + } + + currentLine.enqueuePoint(position); + + ++this.size; +}; + +InfiniteLine.prototype.dequeuePoint = function() { + if (this.lines.length == 0) { + error("Trying to dequeue from InfiniteLine when no points are left"); + return; + } + + var lastLine = this.lines[0]; + lastLine.dequeuePoint(); + + if (lastLine.getSize() <= 1) { + this.lines = this.lines.slice(1); + } + + --this.size; +}; + +InfiniteLine.prototype.getFirstPoint = function() { + return this.lines.length > 0 ? this.lines[0].getFirstPoint() : null; +}; + +InfiniteLine.prototype.getLastPoint = function() { + return this.lines.length > 0 ? this.lines[lines.length - 1].getLastPoint() : null; +}; + +InfiniteLine.prototype.destroy = function() { + for (var i = 0; i < this.lines.length; ++i) { + this.lines[i].destroy(); + } + + this.size = 0; +}; diff --git a/examples/pitching.js b/examples/baseball/pitching.js similarity index 100% rename from examples/pitching.js rename to examples/baseball/pitching.js From 934575a78a1216c89c8636b3d7aa352d82e259d4 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 21 Oct 2015 16:46:07 -0700 Subject: [PATCH 016/401] Refactor pitching.js --- examples/baseball/pitching.js | 332 ++++++++++++++-------------------- 1 file changed, 139 insertions(+), 193 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index b419e8935c..5cb29ac5d7 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -1,16 +1,25 @@ -//var PITCH_THUNK_SOUND_URL = "file:///C:/Users/Ryan/Downloads/323725__reitanna__thunk.wav"; -var PITCH_THUNK_SOUND_URL = "file:///C:/Users/Ryan/Downloads/thunk.wav"; +Script.include("line.js"); + +var AUDIO = { + crowdBoos: [ + SoundCache.getSound("atp:c632c92b166ade60aa16b23ff1dfdf712856caeb83bd9311980b2d5edac821af.wav", false) + ], + crowdCheers: [ + SoundCache.getSound("atp:0821bf2ac60dd2f356dfdd948e8bb89c23984dc3584612f6c815765154f02cae.wav", false), + SoundCache.getSound("atp:b8044401a846ed29f881a0b9b80cf1ba41f26327180c28fc9c70d144f9b70045.wav", false), + ], + batHit: [ + SoundCache.getSound("atp:6f0b691a0c9c9ece6557d97fe242b1faec4020fe26efc9c17327993b513c5fe5.wav", false), + SoundCache.getSound("atp:5be5806205158ebdc5c3623ceb7ae73315028b51ffeae24292aff7042e3fa6a9.wav", false), + SoundCache.getSound("atp:e68661374e2145c480809c26134782aad11e0de456c7802170c7abccc4028873.wav", false), + SoundCache.getSound("atp:787e3c9af17dd3929527787176ede83d6806260e63ddd5a4cef48cd22e32c6f7.wav", false), + SoundCache.getSound("atp:fc65383431a6238c7a4749f0f6f061f75a604ed5e17d775ab1b2955609e67ebb.wav", false), + ] +} + var PITCH_THUNK_SOUND_URL = "http://hifi-public.s3.amazonaws.com/sounds/ping_pong_gun/pong_sound.wav"; var pitchSound = SoundCache.getSound(PITCH_THUNK_SOUND_URL, false); -function info(message) { - print("[INFO] " + message); -} - -function error(message) { - print("[ERROR] " + message); -} - var PITCHING_MACHINE_URL = "atp:87d4879530b698741ecc45f6f31789aac11f7865a2c3bec5fe9b061a182c80d4.fbx"; var PITCHING_MACHINE_OUTPUT_OFFSET_PCT = { x: 0.0, @@ -23,7 +32,7 @@ var PITCHING_MACHINE_PROPERTIES = { position: { x: 0, y: 0.8, - z: -22.3, + z: -18.3, }, velocity: { x: 0, @@ -51,12 +60,13 @@ var PITCHING_MACHINE_PROPERTIES = { shapeType: "Box", }; PITCHING_MACHINE_PROPERTIES.dimensions = Vec3.multiply(2.5, PITCHING_MACHINE_PROPERTIES.dimensions); - +var DISTANCE_FROM_PLATE = PITCHING_MACHINE_PROPERTIES.position.z; var PITCH_RATE = 5000; var BASEBALL_MODEL_URL = "atp:7185099f1f650600ca187222573a88200aeb835454bd2f578f12c7fb4fd190fa.fbx"; -var BASEBALL_SPEED = 2.7; +var BASEBALL_MIN_SPEED = 2.7; +var BASEBALL_MAX_SPEED = 5.7; var BASEBALL_RADIUS = 0.07468; var BASEBALL_PROPERTIES = { name: "Baseball", @@ -78,13 +88,17 @@ var BASEBALL_PROPERTIES = { x: 17.0, y: 0, z: -8.0, + + x: 0.0, + y: 0, + z: 0.0, }, angularDamping: 0.0, damping: 0.0, restitution: 0.5, friction: 0.0, lifetime: 20, - collisionSoundURL: PITCH_THUNK_SOUND_URL, + //collisionSoundURL: PITCH_THUNK_SOUND_URL, gravity: { x: 0, y: 0,//-9.8, @@ -107,23 +121,44 @@ function shallowCopy(obj) { } function randomInt(low, high) { - return low + (Math.random() * (high - low)); + return Math.floor(randomFloat(low, high)); +} + +function randomFloat(low, high) { + if (high === undefined) { + high = low; + low = 0; + } + return low + Math.random() * (high - low); } var ACCELERATION_SPREAD = 10.15; -function createBaseball(position, velocity, ballScale) { +function Baseball(position, velocity, ballScale) { + var self = this; + + // Setup entity properties var properties = shallowCopy(BASEBALL_PROPERTIES); properties.position = position; properties.velocity = velocity; - properties.acceleration = { + /* + properties.gravity = { x: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), y: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), z: 0.0, }; + */ properties.dimensions = Vec3.multiply(ballScale, properties.dimensions); - var entityID = Entities.addEntity(properties); - Script.addEventHandler(entityID, "collisionWithEntity", buildBaseballHitCallback(entityID)); + + // Create entity + this.entityID = Entities.addEntity(properties); + this.trail = null; + this.onHit = function() { return true; }; + this.hasBeenHit = false; + + this.boundCollisionCallback = function(a, b, c) { self.collisionCallback.call(self, a, b, c); }; + Script.addEventHandler(this.entityID, "collisionWithEntity", this.boundCollisionCallback); + /* if (false && Math.random() < 0.5) { for (var i = 0; i < 50; i++) { Script.setTimeout(function() { @@ -137,26 +172,39 @@ function createBaseball(position, velocity, ballScale) { }, i * 100); } } - return entityID; + */ } -var buildBaseballHitCallback = function(entityID) { - var f = function(entityA, entityB, collision) { - print("Got baseball hit callback"); - var properties = Entities.getEntityProperties(entityID, ['position', 'velocity']); - var line = new InfiniteLine(properties.position, { red: 255, green: 128, blue: 89 }); +Baseball.prototype = { + collisionCallback: function(entityA, entityB, collision) { + var self = this; + + this.hasBeenHit = true; + var properties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']); + this.trail = new InfiniteLine(properties.position, { red: 255, green: 128, blue: 89 }); var lastPosition = properties.position; - Vec3.print("Velocity", properties.velocity); - Vec3.print("VelocityChange", collision.velocityChange); - Script.setInterval(function() { - var properties = Entities.getEntityProperties(entityID, ['position']); + //Vec3.print("Velocity", properties.velocity); + //Vec3.print("VelocityChange", collision.velocityChange); + var speed = Vec3.length(properties.velocity); + playRandomSound(AUDIO.batHit, { + position: properties.position, + volume: 2.0 + }); + var sounds = null; + if (speed < 5.0) { + sounds = AUDIO.crowdBoos; + } else { + sounds = AUDIO.crowdCheers; + } + var self = this; + this.trailInterval = Script.setInterval(function() { + var properties = Entities.getEntityProperties(self.entityID, ['position']); if (Vec3.distance(properties.position, lastPosition)) { - line.enqueuePoint(properties.position); + self.trail.enqueuePoint(properties.position); lastPosition = properties.position; } }, 50); - var speed = Vec3.length(properties.velocity); - Entities.editEntity(entityID, { + Entities.editEntity(self.entityID, { velocity: Vec3.multiply(2, properties.velocity), gravity: { x: 0, @@ -164,12 +212,35 @@ var buildBaseballHitCallback = function(entityID) { z: 0 } }); - print("Baseball hit!"); - Script.removeEventHandler(entityID, "collisionWithEntity", f); - }; - return f; + + var removeHandler = this.onHit(entityB, collision); + if (removeHandler) { + Script.removeEventHandler(self.entityID, "collisionWithEntity", self.boundCollisionCallback); + } + }, + cleanupTrail: function() { + if (this.trail) { + Script.clearInterval(this.trailInterval); + this.trailInterval = null; + + this.trail.destroy(); + this.trail = null; + } + } } +function playRandomSound(sounds, options) { + if (options === undefined) { + options = { + volume: 1.0, + position: MyAvatar.position, + } + } + Audio.playSound(sounds[randomInt(sounds.length)], options); +} + +var lastTrail = null; + function vec3Mult(a, b) { return { @@ -179,8 +250,14 @@ function vec3Mult(a, b) { }; } +var lastBall = null; var injector = null; + function pitchBall() { + if (lastBall) { + lastBall.cleanupTrail(); + } + var machineProperties = Entities.getEntityProperties(pitchingMachineID, ["dimensions", "position", "rotation"]); var pitchFromPositionBase = machineProperties.position; var pitchFromOffset = vec3Mult(machineProperties.dimensions, PITCHING_MACHINE_OUTPUT_OFFSET_PCT); @@ -189,7 +266,32 @@ function pitchBall() { var pitchDirection = Quat.getFront(machineProperties.rotation); var ballScale = machineProperties.dimensions.x / PITCHING_MACHINE_PROPERTIES.dimensions.x; print("Creating baseball"); - var ballEntityID = createBaseball(pitchFromPosition, Vec3.multiply(BASEBALL_SPEED, pitchDirection), ballScale); + + var speed = randomFloat(BASEBALL_MIN_SPEED, BASEBALL_MAX_SPEED) + var timeToPassPlate = (DISTANCE_FROM_PLATE + 1.0) / speed; + + var baseball = new Baseball(pitchFromPosition, Vec3.multiply(speed, pitchDirection), ballScale); + lastBall = baseball; + + baseball.onHit = function(entityB, collision) { + var properties = Entities.getEntityProperties(entityB, ["name"]); + var name = properties.name; + print("Hit: " + name); + if (name == "backstop") { + print("STRIKE"); + } else if (name == "bat") { + print("HIT"); + Script.setTimeout(function() { + playRandomSound(sounds, { + position: { x: 0 ,y: 0, z: 0 }, + volume: 1.0, + }); + }, 500); + } + //Script.clearTimeout(strikeTimeout); + return true; + } + if (!injector) { injector = Audio.playSound(pitchSound, { position: pitchFromPosition, @@ -209,159 +311,3 @@ Script.setInterval(pitchBall, PITCH_RATE); -/****************************************************************************** - * PolyLine - *****************************************************************************/ -var LINE_DIMENSIONS = { x: 2000, y: 2000, z: 2000 }; -var MAX_LINE_LENGTH = 40; // This must be 2 or greater; -var PolyLine = function(position, color, defaultStrokeWidth) { - //info("Creating polyline"); - //Vec3.print("New line at", position); - this.position = position; - this.color = color; - this.defaultStrokeWidth = 0.10; - this.points = [ - { x: 0, y: 0, z: 0 }, - ]; - this.strokeWidths = [ - this.defaultStrokeWidth, - ] - this.normals = [ - { x: 1, y: 0, z: 0 }, - ] - this.entityID = Entities.addEntity({ - type: "PolyLine", - position: position, - linePoints: this.points, - normals: this.normals, - strokeWidths: this.strokeWidths, - dimensions: LINE_DIMENSIONS, - color: color, - lifetime: 20, - }); -}; - -PolyLine.prototype.enqueuePoint = function(position) { - if (this.isFull()) { - error("Hit max PolyLine size"); - return; - } - - //Vec3.print("pos", position); - //info("Number of points: " + this.points.length); - - position = Vec3.subtract(position, this.position); - this.points.push(position); - this.normals.push({ x: 1, y: 0, z: 0 }); - this.strokeWidths.push(this.defaultStrokeWidth); - Entities.editEntity(this.entityID, { - linePoints: this.points, - normals: this.normals, - strokeWidths: this.strokeWidths, - }); -}; - -PolyLine.prototype.dequeuePoint = function() { - if (this.points.length == 0) { - error("Hit min PolyLine size"); - return; - } - - this.points = this.points.slice(1); - this.normals = this.normals.slice(1); - this.strokeWidths = this.strokeWidths.slice(1); - - Entities.editEntity(this.entityID, { - linePoints: this.points, - normals: this.normals, - strokeWidths: this.strokeWidths, - }); -}; - -PolyLine.prototype.getFirstPoint = function() { - return Vec3.sum(this.position, this.points[0]); -}; - -PolyLine.prototype.getLastPoint = function() { - return Vec3.sum(this.position, this.points[this.points.length - 1]); -}; - -PolyLine.prototype.getSize = function() { - return this.points.length; -} - -PolyLine.prototype.isFull = function() { - return this.points.length >= MAX_LINE_LENGTH; -}; - -PolyLine.prototype.destroy = function() { - Entities.deleteEntity(this.entityID); - this.points = []; -}; - - -/****************************************************************************** - * InfiniteLine - *****************************************************************************/ -InfiniteLine = function(position, color) { - this.position = position; - this.color = color; - this.lines = [new PolyLine(position, color)]; - this.size = 0; -}; - -InfiniteLine.prototype.enqueuePoint = function(position) { - var currentLine; - - if (this.lines.length == 0) { - currentLine = new PolyLine(position, this.color); - this.lines.push(currentLine); - } else { - currentLine = this.lines[this.lines.length - 1]; - } - - if (currentLine.isFull()) { - //info("Current line is full, creating new line"); - //Vec3.print("Last line is", currentLine.getLastPoint()); - //Vec3.print("New line is", position); - var newLine = new PolyLine(currentLine.getLastPoint(), this.color); - this.lines.push(newLine); - currentLine = newLine; - } - - currentLine.enqueuePoint(position); - - ++this.size; -}; - -InfiniteLine.prototype.dequeuePoint = function() { - if (this.lines.length == 0) { - error("Trying to dequeue from InfiniteLine when no points are left"); - return; - } - - var lastLine = this.lines[0]; - lastLine.dequeuePoint(); - - if (lastLine.getSize() <= 1) { - this.lines = this.lines.slice(1); - } - - --this.size; -}; - -InfiniteLine.prototype.getFirstPoint = function() { - return this.lines.length > 0 ? this.lines[0].getFirstPoint() : null; -}; - -InfiniteLine.prototype.getLastPoint = function() { - return this.lines.length > 0 ? this.lines[lines.length - 1].getLastPoint() : null; -}; - -InfiniteLine.prototype.destroy = function() { - for (var i = 0; i < this.lines.length; ++i) { - this.lines[i].destroy(); - } - - this.size = 0; -}; From 264b65813211eee445b936994494a406844ebd14 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 22 Oct 2015 11:05:48 -0700 Subject: [PATCH 017/401] hook up entities and avatars to SpatialParentFinder --- .../src/entities/AssignmentParentFinder.cpp | 22 +++++ .../src/entities/AssignmentParentFinder.h | 34 +++++++ .../src/entities/EntityServer.cpp | 5 + interface/src/Application.cpp | 4 + interface/src/InterfaceParentFinder.cpp | 35 +++++++ interface/src/InterfaceParentFinder.h | 27 ++++++ libraries/entities/src/EntityItem.cpp | 13 ++- libraries/entities/src/EntityItem.h | 4 - libraries/shared/src/SpatialParentFinder.h | 39 ++++++++ libraries/shared/src/SpatiallyNestable.cpp | 96 +++++++++++++++++-- libraries/shared/src/SpatiallyNestable.h | 37 +++++-- 11 files changed, 296 insertions(+), 20 deletions(-) create mode 100644 assignment-client/src/entities/AssignmentParentFinder.cpp create mode 100644 assignment-client/src/entities/AssignmentParentFinder.h create mode 100644 interface/src/InterfaceParentFinder.cpp create mode 100644 interface/src/InterfaceParentFinder.h create mode 100644 libraries/shared/src/SpatialParentFinder.h diff --git a/assignment-client/src/entities/AssignmentParentFinder.cpp b/assignment-client/src/entities/AssignmentParentFinder.cpp new file mode 100644 index 0000000000..6a66aa3f73 --- /dev/null +++ b/assignment-client/src/entities/AssignmentParentFinder.cpp @@ -0,0 +1,22 @@ +// +// AssignmentParentFinder.cpp +// assignment-client/src/ +// +// Created by Seth Alves on 2015-10-22 +// 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 "AssignmentParentFinder.h" + +SpatiallyNestableWeakPointer AssignmentParentFinder::find(QUuid parentID) const { + assert(false); + SpatiallyNestableWeakPointer parent; + // search entities + _tree->withReadLock([&] { + parent = _tree->findEntityByEntityItemID(parentID); + }); + return parent; +} diff --git a/assignment-client/src/entities/AssignmentParentFinder.h b/assignment-client/src/entities/AssignmentParentFinder.h new file mode 100644 index 0000000000..4d2e080443 --- /dev/null +++ b/assignment-client/src/entities/AssignmentParentFinder.h @@ -0,0 +1,34 @@ +// +// AssignmentParentFinder.h +// interface/src/ +// +// Created by Seth Alves on 2015-10-21 +// 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_AssignmentParentFinder_h +#define hifi_AssignmentParentFinder_h + +#include +#include + +#include +#include + +// This interface is used to turn a QUuid into a pointer to a "parent" -- something that children can +// be spatially relative to. At this point, this means either an EntityItem or an Avatar. + +class AssignmentParentFinder : public SpatialParentFinder { +public: + AssignmentParentFinder(EntityTreePointer tree) : _tree(tree) { } + virtual ~AssignmentParentFinder() { } + virtual SpatiallyNestableWeakPointer find(QUuid parentID) const; + +protected: + EntityTreePointer _tree; +}; + +#endif // hifi_AssignmentParentFinder_h diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index f2a4c2664a..5c9b120a3a 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -16,6 +16,7 @@ #include "EntityServer.h" #include "EntityServerConsts.h" #include "EntityNodeData.h" +#include "AssignmentParentFinder.h" const char* MODEL_SERVER_NAME = "Entity"; const char* MODEL_SERVER_LOGGING_TARGET_NAME = "entity-server"; @@ -60,6 +61,10 @@ OctreePointer EntityServer::createTree() { tree->setSimulation(simpleSimulation); _entitySimulation = simpleSimulation; } + + DependencyManager::registerInheritance(); + DependencyManager::set(tree); + return tree; } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index cab189e7a0..1a02cf912e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -136,6 +136,8 @@ #include "ui/Stats.h" #include "ui/UpdateDialog.h" #include "Util.h" +#include "InterfaceParentFinder.h" + // ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. @@ -286,6 +288,7 @@ bool setupEssentials(int& argc, char** argv) { DependencyManager::registerInheritance(); DependencyManager::registerInheritance(); DependencyManager::registerInheritance(); + DependencyManager::registerInheritance(); Setting::init(); @@ -327,6 +330,7 @@ bool setupEssentials(int& argc, char** argv) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); return true; } diff --git a/interface/src/InterfaceParentFinder.cpp b/interface/src/InterfaceParentFinder.cpp new file mode 100644 index 0000000000..f8604b15d3 --- /dev/null +++ b/interface/src/InterfaceParentFinder.cpp @@ -0,0 +1,35 @@ +// +// InterfaceParentFinder.cpp +// interface/src/ +// +// Created by Seth Alves on 2015-10-21 +// 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 +#include +#include +#include + +#include "InterfaceParentFinder.h" + +SpatiallyNestableWeakPointer InterfaceParentFinder::find(QUuid parentID) const { + SpatiallyNestableWeakPointer parent; + + // search entities + EntityTreeRenderer* treeRenderer = qApp->getEntities(); + EntityTreePointer tree = treeRenderer->getTree(); + tree->withReadLock([&] { + parent = tree->findEntityByEntityItemID(parentID); + }); + if (!parent.expired()) { + return parent; + } + + // search avatars + QSharedPointer avatarManager = DependencyManager::get(); + return avatarManager->getAvatarBySessionID(parentID); +} diff --git a/interface/src/InterfaceParentFinder.h b/interface/src/InterfaceParentFinder.h new file mode 100644 index 0000000000..c8e8d4ed9f --- /dev/null +++ b/interface/src/InterfaceParentFinder.h @@ -0,0 +1,27 @@ +// +// InterfaceParentFinder.h +// interface/src/ +// +// Created by Seth Alves on 2015-10-21 +// 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_InterfaceParentFinder_h +#define hifi_InterfaceParentFinder_h + +#include +#include + +#include + +class InterfaceParentFinder : public SpatialParentFinder { +public: + InterfaceParentFinder() { } + virtual ~InterfaceParentFinder() { } + virtual SpatiallyNestableWeakPointer find(QUuid parentID) const; +}; + +#endif // hifi_InterfaceParentFinder_h diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index c2e6a90ca8..0a47a004fd 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -37,8 +37,8 @@ int EntityItem::_maxActionsDataSize = 800; quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND; EntityItem::EntityItem(const EntityItemID& entityItemID) : + SpatiallyNestable(entityItemID), _type(EntityTypes::Unknown), - _id(entityItemID), _lastSimulated(0), _lastUpdated(0), _lastEdited(0), @@ -1723,6 +1723,9 @@ void EntityItem::checkWaitingToRemove(EntitySimulation* simulation) { } void EntityItem::setActionData(QByteArray actionData) { + if (_id == QUuid("32147a6e-976d-44ea-8c33-056c820b4dbd")) { + qDebug() << "EntityItem::setActionData to " << actionData.size() << "bytes."; + } withWriteLock([&] { setActionDataInternal(actionData); }); @@ -1730,8 +1733,16 @@ void EntityItem::setActionData(QByteArray actionData) { void EntityItem::setActionDataInternal(QByteArray actionData) { if (_allActionsDataCache != actionData) { + if (_id == QUuid("32147a6e-976d-44ea-8c33-056c820b4dbd")) { + qDebug() << "EntityItem::setActionDataInternal to " << actionData.size() << "bytes."; + } + _allActionsDataCache = actionData; deserializeActionsInternal(); + } else { + if (_id == QUuid("32147a6e-976d-44ea-8c33-056c820b4dbd")) { + qDebug() << "EntityItem::setActionDataInternal NOT setting to " << actionData.size() << "bytes."; + } } checkWaitingToRemove(); } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 185d052bbd..79fe438c39 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -89,9 +89,6 @@ public: EntityItem(const EntityItemID& entityItemID); virtual ~EntityItem(); - // ID and EntityItemID related methods - const QUuid& getID() const { return _id; } - void setID(const QUuid& id) { _id = id; } EntityItemID getEntityItemID() const { return EntityItemID(_id); } // methods for getting/setting all properties of an entity @@ -399,7 +396,6 @@ protected: static bool _sendPhysicsUpdates; EntityTypes::EntityType _type; - QUuid _id; quint64 _lastSimulated; // last time this entity called simulate(), this includes velocity, angular velocity, // and physics changes quint64 _lastUpdated; // last time this entity called update(), this includes animations and non-physics changes diff --git a/libraries/shared/src/SpatialParentFinder.h b/libraries/shared/src/SpatialParentFinder.h new file mode 100644 index 0000000000..9cadbaf8ce --- /dev/null +++ b/libraries/shared/src/SpatialParentFinder.h @@ -0,0 +1,39 @@ +// +// SpatialParentFinder.h +// libraries/shared/src/ +// +// Created by Seth Alves on 2015-10-18 +// 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_SpatialParentFinder_h +#define hifi_SpatialParentFinder_h + +#include + +#include "DependencyManager.h" + +class SpatiallyNestable; +using SpatiallyNestableWeakPointer = std::weak_ptr; +using SpatiallyNestablePointer = std::shared_ptr; +class SpatialParentFinder; +using SpatialParentFinderPointer = std::shared_ptr; +class SpatialParentFinder : public Dependency { + + + +// This interface is used to turn a QUuid into a pointer to a "parent" -- something that children can +// be spatially relative to. At this point, this means either an EntityItem or an Avatar. + + +public: + SpatialParentFinder() { } + virtual ~SpatialParentFinder() { } + + virtual SpatiallyNestableWeakPointer find(QUuid parentID) const = 0; +}; + +#endif // hifi_SpatialParentFinder_h diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index a3e427caa8..4cdf61061c 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -9,35 +9,84 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "DependencyManager.h" #include "SpatiallyNestable.h" -SpatiallyNestable::SpatiallyNestable() : - _transform() { +Transform SpatiallyNestable::getParentTransform() const { + Transform result; + SpatiallyNestablePointer parent = getParentPointer(); + if (parent) { + Transform parentTransform = parent->getTransform(); + result = parentTransform.setScale(1.0f); + } + return result; } +SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { + SpatiallyNestablePointer parent = _parent.lock(); + + if (!parent && _parentID.isNull()) { + // no parent + return nullptr; + } + + if (parent && parent->getID() == _parentID) { + // parent pointer is up-to-date + return parent; + } + + if (parent && _parentID.isNull()) { + // we have a parent pointer but our _parentID is null + _parent.reset(); + return nullptr; + } + + // we have a _parentID but no parent pointer, or our parent pointer is to the wrong thing + QSharedPointer parentFinder = DependencyManager::get(); + _parent = parentFinder->find(_parentID); + return _parent.lock(); +} const glm::vec3& SpatiallyNestable::getPosition() const { - return _transform.getTranslation(); + Transform parentTransformDescaled = getParentTransform(); + glm::mat4 parentMat; + parentTransformDescaled.getMatrix(parentMat); + glm::vec4 absPos = parentMat * glm::vec4(getLocalPosition(), 1.0f); + _absolutePositionCache = glm::vec3(absPos); + return _absolutePositionCache; } void SpatiallyNestable::setPosition(const glm::vec3& position) { - _transform.setTranslation(position); + Transform parentTransform = getParentTransform(); + Transform myWorldTransform; + Transform::mult(myWorldTransform, parentTransform, _transform); + myWorldTransform.setTranslation(position); + Transform::inverseMult(_transform, parentTransform, myWorldTransform); } const glm::quat& SpatiallyNestable::getOrientation() const { - return _transform.getRotation(); + Transform parentTransformDescaled = getParentTransform(); + _absoluteRotationCache = parentTransformDescaled.getRotation() * getLocalOrientation(); + return _absoluteRotationCache; } void SpatiallyNestable::setOrientation(const glm::quat& orientation) { - _transform.setRotation(orientation); + Transform parentTransform = getParentTransform(); + Transform myWorldTransform; + Transform::mult(myWorldTransform, parentTransform, _transform); + myWorldTransform.setRotation(orientation); + Transform::inverseMult(_transform, parentTransform, myWorldTransform); } const Transform& SpatiallyNestable::getTransform() const { - return _transform; + Transform parentTransform = getParentTransform(); + Transform::mult(_worldTransformCache, parentTransform, _transform); + return _worldTransformCache; } void SpatiallyNestable::setTransform(const Transform& transform) { - _transform = transform; + Transform parentTransform = getParentTransform(); + Transform::inverseMult(_transform, parentTransform, transform); } const glm::vec3& SpatiallyNestable::getScale() const { @@ -47,3 +96,34 @@ const glm::vec3& SpatiallyNestable::getScale() const { void SpatiallyNestable::setScale(const glm::vec3& scale) { _transform.setScale(scale); } + +const Transform& SpatiallyNestable::getLocalTransform() const { + return _transform; +} + +void SpatiallyNestable::setLocalTransform(const Transform& transform) { +} + +const glm::vec3& SpatiallyNestable::getLocalPosition() const { + return _transform.getTranslation(); +} + +void SpatiallyNestable::setLocalPosition(const glm::vec3& position) { + _transform.setTranslation(position); +} + +const glm::quat& SpatiallyNestable::getLocalOrientation() const { + return _transform.getRotation(); +} + +void SpatiallyNestable::setLocalOrientation(const glm::quat& orientation) { + _transform.setRotation(orientation); +} + +const glm::vec3& SpatiallyNestable::getLocalScale() const { + return _transform.getScale(); +} + +void SpatiallyNestable::setLocalScale(const glm::vec3& scale) { + _transform.setScale(scale); +} diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 294450a980..e3d3b8dc0d 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -15,22 +15,29 @@ #include #include "Transform.h" +#include "SpatialParentFinder.h" class SpatiallyNestable; -typedef std::weak_ptr SpatiallyNestableWeakPointer; -typedef std::shared_ptr SpatiallyNestablePointer; +using SpatiallyNestableWeakPointer = std::weak_ptr; +using SpatiallyNestablePointer = std::shared_ptr; class SpatiallyNestable { public: - SpatiallyNestable(); + SpatiallyNestable() : _transform() { } + SpatiallyNestable(QUuid id) : _id(id), _transform() { } virtual ~SpatiallyNestable() { } + const QUuid& getID() const { return _id; } + void setID(const QUuid& id) { _id = id; } + // world frame virtual const Transform& getTransform() const; virtual void setTransform(const Transform& transform); + Transform getParentTransform() const; + virtual const glm::vec3& getPosition() const; virtual void setPosition(const glm::vec3& position); @@ -40,19 +47,35 @@ public: virtual const glm::vec3& getScale() const; virtual void setScale(const glm::vec3& scale); - // model frame - // ... + // object's parent's frame + virtual const Transform& getLocalTransform() const; + virtual void setLocalTransform(const Transform& transform); + virtual const glm::vec3& getLocalPosition() const; + virtual void setLocalPosition(const glm::vec3& position); + + virtual const glm::quat& getLocalOrientation() const; + virtual void setLocalOrientation(const glm::quat& orientation); + + virtual const glm::vec3& getLocalScale() const; + virtual void setLocalScale(const glm::vec3& scale); protected: + QUuid _id; QUuid _parentID; // what is this thing's transform relative to? int _parentJointIndex; // which joint of the parent is this relative to? - SpatiallyNestableWeakPointer _parent; + mutable SpatiallyNestableWeakPointer _parent; QVector _children; private: - Transform _transform; + Transform _transform; // this is to be combined with parent's world-transform to produce this' world-transform. + SpatiallyNestablePointer getParentPointer() const; + + // these are so we can return by reference + mutable glm::vec3 _absolutePositionCache; + mutable glm::quat _absoluteRotationCache; + mutable Transform _worldTransformCache; }; From a9bad8de664f07501287a648d4005af6f3e77801 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 22 Oct 2015 11:12:02 -0700 Subject: [PATCH 018/401] add a script for ambient crowd noise --- examples/acScripts/baseballCrowd.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 examples/acScripts/baseballCrowd.js diff --git a/examples/acScripts/baseballCrowd.js b/examples/acScripts/baseballCrowd.js new file mode 100644 index 0000000000..5007c64b16 --- /dev/null +++ b/examples/acScripts/baseballCrowd.js @@ -0,0 +1,21 @@ +// +// baseballCrowd.js +// examples/acScripts +// +// Created by Stephen Birarda on 10/20/15. +// 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 +// + +var crowd1 = SoundCache.getSound("atp:0e921b644464d56d5b412ea2ea1d83f8ff3f7506c4b0471ea336a4770daf3b82.wav"); + +function maybePlaySound(deltaTime) { + if (crowd1.downloaded && !crowd1.isPlaying) { + Audio.playSound(crowd1, { position: { x: 0, y: 0, z: 0}, loop: true}); + Script.update.disconnect(maybePlaySound); + } +} + +Script.update.connect(maybePlaySound); From 778dc8dc15ddb1831d33c05350fbbc07c0bf62b9 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 22 Oct 2015 11:52:56 -0700 Subject: [PATCH 019/401] add parentID and parentJointIndex EntityItemProperties --- libraries/entities/src/EntityItem.cpp | 12 +++++++++++- libraries/entities/src/EntityItemProperties.cpp | 17 +++++++++++++++-- libraries/entities/src/EntityItemProperties.h | 5 +++++ .../entities/src/EntityItemPropertiesMacros.h | 2 ++ libraries/entities/src/EntityPropertyFlags.h | 3 +++ libraries/networking/src/udt/PacketHeaders.cpp | 3 ++- libraries/networking/src/udt/PacketHeaders.h | 1 + libraries/shared/src/SpatiallyNestable.cpp | 2 ++ libraries/shared/src/SpatiallyNestable.h | 16 +++++++++++----- 9 files changed, 52 insertions(+), 9 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 0a47a004fd..c3c0204aee 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -134,6 +134,8 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_HREF; requestedProperties += PROP_DESCRIPTION; requestedProperties += PROP_ACTION_DATA; + requestedProperties += PROP_PARENT_ID; + requestedProperties += PROP_PARENT_JOINT_INDEX; return requestedProperties; } @@ -268,7 +270,8 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_HREF, getHref()); APPEND_ENTITY_PROPERTY(PROP_DESCRIPTION, getDescription()); APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, getActionData()); - + APPEND_ENTITY_PROPERTY(PROP_PARENT_ID, getParentID()); + APPEND_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, getParentJointIndex()); appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, @@ -715,6 +718,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef overwriteLocalData = oldOverwrite; } + READ_ENTITY_PROPERTY(PROP_PARENT_ID, QUuid, setParentID); + READ_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex); + bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData, somethingChanged); @@ -1062,6 +1068,8 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper COPY_ENTITY_PROPERTY_TO_PROPERTIES(href, getHref); COPY_ENTITY_PROPERTY_TO_PROPERTIES(description, getDescription); COPY_ENTITY_PROPERTY_TO_PROPERTIES(actionData, getActionData); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentID, getParentID); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentJointIndex, getParentJointIndex); properties._defaultSettings = false; @@ -1124,6 +1132,8 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(href, setHref); SET_ENTITY_PROPERTY_FROM_PROPERTIES(description, setDescription); SET_ENTITY_PROPERTY_FROM_PROPERTIES(actionData, setActionData); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentID, setParentID); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentJointIndex, setParentJointIndex); if (somethingChanged) { uint64_t now = usecTimestampNow(); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 19c8f779b4..6755149944 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -261,6 +261,8 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_X_P_NEIGHBOR_ID, xPNeighborID); CHECK_PROPERTY_CHANGE(PROP_Y_P_NEIGHBOR_ID, yPNeighborID); CHECK_PROPERTY_CHANGE(PROP_Z_P_NEIGHBOR_ID, zPNeighborID); + CHECK_PROPERTY_CHANGE(PROP_PARENT_ID, parentID); + CHECK_PROPERTY_CHANGE(PROP_PARENT_JOINT_INDEX, parentJointIndex); changedProperties += _animation.getChangedProperties(); changedProperties += _atmosphere.getChangedProperties(); @@ -467,6 +469,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(originalTextures, textureNamesList); // gettable, but not settable } + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_ID, parentID); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_JOINT_INDEX, parentJointIndex); + // FIXME - I don't think these properties are supported any more //COPY_PROPERTY_TO_QSCRIPTVALUE(glowLevel); //COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha); @@ -591,6 +596,9 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(yPNeighborID, EntityItemID, setYPNeighborID); COPY_PROPERTY_FROM_QSCRIPTVALUE(zPNeighborID, EntityItemID, setZPNeighborID); + COPY_PROPERTY_FROM_QSCRIPTVALUE(parentID, QUuid, setParentID); + COPY_PROPERTY_FROM_QSCRIPTVALUE(parentJointIndex, quint16, setParentJointIndex); + _lastEdited = usecTimestampNow(); } @@ -906,7 +914,8 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_USER_DATA, properties.getUserData()); APPEND_ENTITY_PROPERTY(PROP_HREF, properties.getHref()); APPEND_ENTITY_PROPERTY(PROP_DESCRIPTION, properties.getDescription()); - + APPEND_ENTITY_PROPERTY(PROP_PARENT_ID, properties.getParentID()); + APPEND_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, properties.getParentJointIndex()); if (properties.getType() == EntityTypes::Web) { APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, properties.getSourceUrl()); @@ -1191,7 +1200,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USER_DATA, QString, setUserData); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_HREF, QString, setHref); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DESCRIPTION, QString, setDescription); - + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_ID, QUuid, setParentID); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex); if (properties.getType() == EntityTypes::Web) { READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SOURCE_URL, QString, setSourceUrl); @@ -1446,6 +1456,9 @@ void EntityItemProperties::markAllChanged() { _xPNeighborIDChanged = true; _yPNeighborIDChanged = true; _zPNeighborIDChanged = true; + + _parentIDChanged = true; + _parentJointIndexChanged = true; } /// The maximum bounding cube for the entity, independent of it's rotation. diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 2227644484..1851e69dd2 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -191,6 +191,8 @@ public: DEFINE_PROPERTY_REF(PROP_X_P_NEIGHBOR_ID, XPNeighborID, xPNeighborID, EntityItemID, UNKNOWN_ENTITY_ID); DEFINE_PROPERTY_REF(PROP_Y_P_NEIGHBOR_ID, YPNeighborID, yPNeighborID, EntityItemID, UNKNOWN_ENTITY_ID); DEFINE_PROPERTY_REF(PROP_Z_P_NEIGHBOR_ID, ZPNeighborID, zPNeighborID, EntityItemID, UNKNOWN_ENTITY_ID); + DEFINE_PROPERTY_REF(PROP_PARENT_ID, ParentID, parentID, QUuid, UNKNOWN_ENTITY_ID); + DEFINE_PROPERTY_REF(PROP_PARENT_JOINT_INDEX, ParentJointIndex, parentJointIndex, quint16, 0); static QString getBackgroundModeString(BackgroundMode mode); @@ -389,6 +391,9 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, YPNeighborID, yPNeighborID, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ZPNeighborID, zPNeighborID, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParentID, parentID, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParentJointIndex, parentJointIndex, ""); + properties.getAnimation().debugDump(); properties.getAtmosphere().debugDump(); properties.getSkybox().debugDump(); diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index b3299b6fe6..ca6bbbbbb8 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -104,6 +104,7 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const glm::vec3& v) { return vec3toScriptValue(e, v); } inline QScriptValue convertScriptValue(QScriptEngine* e, float v) { return QScriptValue(v); } inline QScriptValue convertScriptValue(QScriptEngine* e, int v) { return QScriptValue(v); } +inline QScriptValue convertScriptValue(QScriptEngine* e, quint16 v) { return QScriptValue(v); } inline QScriptValue convertScriptValue(QScriptEngine* e, quint32 v) { return QScriptValue(v); } inline QScriptValue convertScriptValue(QScriptEngine* e, quint64 v) { return QScriptValue((qsreal)v); } inline QScriptValue convertScriptValue(QScriptEngine* e, const QString& v) { return QScriptValue(v); } @@ -179,6 +180,7 @@ inline quint32 quint32_convertFromScriptValue(const QScriptValue& v, bool& isVal // Use QString::toUInt() so that isValid is set to false if the number is outside the quint32 range. return v.toString().toUInt(&isValid); } +inline quint16 quint16_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); } inline uint16_t uint16_t_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); } inline int int_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); } inline bool bool_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toBool(); } diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index d70a5c9616..f0087b4803 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -149,6 +149,9 @@ enum EntityPropertyList { PROP_ANIMATION_HOLD, PROP_ANIMATION_START_AUTOMATICALLY, + PROP_PARENT_ID, + PROP_PARENT_JOINT_INDEX, + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 3c1d33deaf..ca2d03ca2b 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -38,9 +38,10 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityAdd: case PacketType::EntityEdit: case PacketType::EntityData: - return VERSION_ENTITIES_ANIMATION_PROPERTIES_GROUP; + return VERSION_ENTITIES_HAVE_PARENTS; case PacketType::AvatarData: case PacketType::BulkAvatarData: + return 17; default: return 16; } diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 3654d5b5fa..5f2cbf0193 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -143,5 +143,6 @@ const PacketVersion VERSION_ENTITIES_PROTOCOL_HEADER_SWAP = 43; const PacketVersion VERSION_ENTITIES_PARTICLE_ELLIPSOID_EMITTER = 44; const PacketVersion VERSION_ENTITIES_PROTOCOL_CHANNELS = 45; const PacketVersion VERSION_ENTITIES_ANIMATION_PROPERTIES_GROUP = 46; +const PacketVersion VERSION_ENTITIES_HAVE_PARENTS = 47; #endif // hifi_PacketHeaders_h diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 4cdf61061c..870c96a784 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -12,6 +12,8 @@ #include "DependencyManager.h" #include "SpatiallyNestable.h" +// TODO -- make use of parent joint index + Transform SpatiallyNestable::getParentTransform() const { Transform result; SpatiallyNestablePointer parent = getParentPointer(); diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index e3d3b8dc0d..c8bb7c2808 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -25,18 +25,24 @@ using SpatiallyNestablePointer = std::shared_ptr; class SpatiallyNestable { public: - SpatiallyNestable() : _transform() { } + SpatiallyNestable() : _transform() { } // XXX get rid of this one? SpatiallyNestable(QUuid id) : _id(id), _transform() { } virtual ~SpatiallyNestable() { } - const QUuid& getID() const { return _id; } - void setID(const QUuid& id) { _id = id; } + virtual const QUuid& getID() const { return _id; } + virtual void setID(const QUuid& id) { _id = id; } + + virtual const QUuid& getParentID() const { return _parentID; } + virtual void setParentID(const QUuid& parentID) { _parentID = parentID; } + + virtual quint16 getParentJointIndex() const { return _parentJointIndex; } + virtual void setParentJointIndex(quint16 parentJointIndex) { _parentJointIndex = parentJointIndex; } // world frame virtual const Transform& getTransform() const; virtual void setTransform(const Transform& transform); - Transform getParentTransform() const; + virtual Transform getParentTransform() const; virtual const glm::vec3& getPosition() const; virtual void setPosition(const glm::vec3& position); @@ -63,7 +69,7 @@ public: protected: QUuid _id; QUuid _parentID; // what is this thing's transform relative to? - int _parentJointIndex; // which joint of the parent is this relative to? + quint16 _parentJointIndex; // which joint of the parent is this relative to? mutable SpatiallyNestableWeakPointer _parent; QVector _children; From f6fe503c515d636bf4ddc0f66b58c111576a6e03 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 22 Oct 2015 13:44:04 -0700 Subject: [PATCH 020/401] pass avatar parent information through avatar-mixer --- interface/src/avatar/AvatarManager.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 29 ++++++++++++++++-------- libraries/avatars/src/AvatarData.h | 4 ++-- libraries/shared/src/SpatiallyNestable.h | 2 +- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 16e136f9d1..3d13ef5d02 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -151,7 +151,7 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { while (fadingIterator != _avatarFades.end()) { auto avatar = std::static_pointer_cast(*fadingIterator); avatar->withWriteLock([&] { - avatar->setTargetScale(avatar->getAvatarScale() * SHRINK_RATE, true); + avatar->setTargetScale(avatar->getAvatarScale() * SHRINK_RATE); if (avatar->getTargetScale() < MIN_FADE_SCALE) { avatar->removeFromScene(*fadingIterator, scene, pendingChanges); fadingIterator = _avatarFades.erase(fadingIterator); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 9b2967cf5d..9a6c4b0180 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -135,15 +135,15 @@ float AvatarData::getTargetScale() const { return _targetScale; } -void AvatarData::setTargetScale(float targetScale, bool overideReferential) { +void AvatarData::setTargetScale(float targetScale) { _targetScale = targetScale; } -void AvatarData::setClampedTargetScale(float targetScale, bool overideReferential) { +void AvatarData::setClampedTargetScale(float targetScale) { targetScale = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE); - setTargetScale(targetScale, overideReferential); + setTargetScale(targetScale); qCDebug(avatars) << "Changed scale to " << _targetScale; } @@ -214,14 +214,18 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { setAtBit(bitItems, IS_EYE_TRACKER_CONNECTED); } // referential state - if (false) { - setAtBit(bitItems, HAS_REFERENTIAL); // XXX leaving this for later use + SpatiallyNestablePointer parent = getParentPointer(); + if (parent) { + setAtBit(bitItems, HAS_REFERENTIAL); } *destinationBuffer++ = bitItems; - // XXX leaving this for later use - if (false) { - // destinationBuffer += _referential->packReferential(destinationBuffer); + if (parent) { + QByteArray referentialAsBytes = parent->getID().toRfc4122(); + memcpy(destinationBuffer, referentialAsBytes.data(), referentialAsBytes.size()); + destinationBuffer += referentialAsBytes.size(); + memcpy(destinationBuffer, &_parentJointIndex, sizeof(_parentJointIndex)); + destinationBuffer += sizeof(_parentJointIndex); } // If it is connected, pack up the data @@ -541,8 +545,15 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { _headData->_isEyeTrackerConnected = oneAtBit(bitItems, IS_EYE_TRACKER_CONNECTED); bool hasReferential = oneAtBit(bitItems, HAS_REFERENTIAL); - // XXX leaving this for later use Referential if (hasReferential) { + const int sizeOfPackedUuid = 16; + QByteArray referentialAsBytes((const char*)sourceBuffer, sizeOfPackedUuid); + _parentID = QUuid::fromRfc4122(referentialAsBytes); + sourceBuffer += sizeOfPackedUuid; + memcpy(&_parentJointIndex, sourceBuffer, sizeof(_parentJointIndex)); + sourceBuffer += sizeof(_parentJointIndex); + } else { + _parentID = QUuid(); } if (_headData->_isFaceTrackerConnected) { diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 9f8224caf8..4f826eafde 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -223,8 +223,8 @@ public: // Scale float getTargetScale() const; - void setTargetScale(float targetScale, bool overideReferential = false); - void setClampedTargetScale(float targetScale, bool overideReferential = false); + void setTargetScale(float targetScale); + void setClampedTargetScale(float targetScale); // Hand State Q_INVOKABLE void setHandState(char s) { _handState = s; } diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index c8bb7c2808..930b096450 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -70,13 +70,13 @@ protected: QUuid _id; QUuid _parentID; // what is this thing's transform relative to? quint16 _parentJointIndex; // which joint of the parent is this relative to? + SpatiallyNestablePointer getParentPointer() const; mutable SpatiallyNestableWeakPointer _parent; QVector _children; private: Transform _transform; // this is to be combined with parent's world-transform to produce this' world-transform. - SpatiallyNestablePointer getParentPointer() const; // these are so we can return by reference mutable glm::vec3 _absolutePositionCache; From cfa47d2fc62d42c81568a2fddb08ef61d980605f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 22 Oct 2015 14:45:08 -0700 Subject: [PATCH 021/401] use triggers to swing with robot --- examples/toys/baseball.js | 59 +++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 15 deletions(-) mode change 100644 => 100755 examples/toys/baseball.js diff --git a/examples/toys/baseball.js b/examples/toys/baseball.js old mode 100644 new mode 100755 index 79a8a2fd61..5863708a86 --- a/examples/toys/baseball.js +++ b/examples/toys/baseball.js @@ -9,22 +9,51 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; -var BAT_COLLISION_SHAPE = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; +var ROBOT_MODEL = "atp:ea02100c2ee63a8b9c0495557f32041be18ec94def157592e84a816665ce2f6e.fbx"; +var ROBOT_POSITION = { x: -0.54, y: 1.21, z: 2.57 } -function createNewBat() { - // move entity three units in front of the avatar - var batPosition = Vec3.sum(MyAvatar.position, - Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: -0.3, z: -2 })); +var lastTriggerValue = 0.0; - var wand = Entities.addEntity({ - name: 'Bat', - type: "Model", - modelURL: BAT_MODEL, - position: batPosition, - collisionsWillMove: true, - compoundShapeURL: BAT_COLLISION_SHAPE - }); +function checkTriggers() { + var rightTrigger = Controller.getTriggerValue(1); + + if (rightTrigger == 0) { + if (lastTriggerValue > 0) { + // the trigger was just released, play out to the last frame of the swing + Entities.editEntity(robot, { + animation: { + running: true, + currentFrame: 21, + lastFrame: 115 + } + }); + } + } else { + if (lastTriggerValue == 0) { + // the trigger was just depressed, start the swing + Entities.editEntity(robot, { + animation: { + running: true, + currentFrame: 0, + lastFrame: 21 + } + }); + } + } + + lastTriggerValue = rightTrigger; } -createNewBat(); +// add the fresh bat at home plate +var robot = Entities.addEntity({ + name: 'Robot', + type: "Model", + modelURL: ROBOT_MODEL, + position: ROBOT_POSITION, + animation: { + url: ROBOT_MODEL + } +}); + +// hook the update so we can check controller triggers +Script.update.connect(checkTriggers); From d86d69aeba4b72f69d2d0d3f626801bfa4ee0fb6 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 22 Oct 2015 15:36:03 -0700 Subject: [PATCH 022/401] keep track of children. use local position and orientation on the wire. --- assignment-client/src/avatars/AvatarMixer.cpp | 4 +-- .../src/entities/AssignmentParentFinder.cpp | 5 +-- interface/src/InterfaceParentFinder.cpp | 4 +-- libraries/avatars/src/AvatarData.cpp | 13 +++---- .../RenderableParticleEffectEntityItem.cpp | 3 +- .../src/RenderablePolyVoxEntityItem.cpp | 2 +- libraries/entities/src/EntityItem.cpp | 12 +++---- libraries/entities/src/EntityItem.h | 4 ++- libraries/shared/src/SpatiallyNestable.cpp | 34 ++++++++++++++++--- libraries/shared/src/SpatiallyNestable.h | 13 ++++--- 10 files changed, 61 insertions(+), 33 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 833b53b729..7124bb368c 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -155,7 +155,7 @@ void AvatarMixer::broadcastAvatarData() { ++_sumListeners; AvatarData& avatar = nodeData->getAvatar(); - glm::vec3 myPosition = avatar.getPosition(); + glm::vec3 myPosition = avatar.getLocalPosition(); // XXX should be world position // reset the internal state for correct random number distribution distribution.reset(); @@ -248,7 +248,7 @@ void AvatarMixer::broadcastAvatarData() { // The full rate distance is the distance at which EVERY update will be sent for this avatar // at twice the full rate distance, there will be a 50% chance of sending this avatar's update - glm::vec3 otherPosition = otherAvatar.getPosition(); + glm::vec3 otherPosition = otherAvatar.getLocalPosition(); // XXX should be world position float distanceToAvatar = glm::length(myPosition - otherPosition); // potentially update the max full rate distance for this frame diff --git a/assignment-client/src/entities/AssignmentParentFinder.cpp b/assignment-client/src/entities/AssignmentParentFinder.cpp index 6a66aa3f73..3e6fc2ed38 100644 --- a/assignment-client/src/entities/AssignmentParentFinder.cpp +++ b/assignment-client/src/entities/AssignmentParentFinder.cpp @@ -12,11 +12,8 @@ #include "AssignmentParentFinder.h" SpatiallyNestableWeakPointer AssignmentParentFinder::find(QUuid parentID) const { - assert(false); SpatiallyNestableWeakPointer parent; // search entities - _tree->withReadLock([&] { - parent = _tree->findEntityByEntityItemID(parentID); - }); + parent = _tree->findEntityByEntityItemID(parentID); return parent; } diff --git a/interface/src/InterfaceParentFinder.cpp b/interface/src/InterfaceParentFinder.cpp index f8604b15d3..1703ffc5d1 100644 --- a/interface/src/InterfaceParentFinder.cpp +++ b/interface/src/InterfaceParentFinder.cpp @@ -22,9 +22,7 @@ SpatiallyNestableWeakPointer InterfaceParentFinder::find(QUuid parentID) const { // search entities EntityTreeRenderer* treeRenderer = qApp->getEntities(); EntityTreePointer tree = treeRenderer->getTree(); - tree->withReadLock([&] { - parent = tree->findEntityByEntityItemID(parentID); - }); + parent = tree->findEntityByEntityItemID(parentID); if (!parent.expired()) { return parent; } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 9a6c4b0180..fc9d9c75a7 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -174,14 +174,15 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { unsigned char* destinationBuffer = reinterpret_cast(avatarDataByteArray.data()); unsigned char* startPosition = destinationBuffer; - const glm::vec3& position = getPosition(); + const glm::vec3& position = getLocalPosition(); memcpy(destinationBuffer, &position, sizeof(position)); destinationBuffer += sizeof(position); // Body rotation - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, getBodyYaw()); - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, getBodyPitch()); - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, getBodyRoll()); + glm::vec3 bodyEulerAngles = glm::degrees(safeEulerAngles(getLocalOrientation())); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, bodyEulerAngles.y); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, bodyEulerAngles.x); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, bodyEulerAngles.z); // Body scale destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _targetScale); @@ -465,7 +466,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { } return maxAvailableSize; } - setPosition(position); + setLocalPosition(position); // rotation (NOTE: This needs to become a quaternion to save two bytes) float yaw, pitch, roll; @@ -483,7 +484,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { if (getBodyYaw() != yaw || getBodyPitch() != pitch || getBodyRoll() != roll) { _hasNewJointRotations = true; glm::vec3 eulerAngles(pitch, yaw, roll); - setOrientation(glm::quat(glm::radians(eulerAngles))); + setLocalOrientation(glm::quat(glm::radians(eulerAngles))); } // scale diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index a7bdffc020..a0bb582d58 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -134,7 +134,8 @@ bool RenderableParticleEffectEntityItem::addToScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges) { - auto particlePayload = std::shared_ptr(new ParticlePayload(shared_from_this())); + auto particlePayload = + std::shared_ptr(new ParticlePayload(getThisPointer())); particlePayload->setPipeline(_untexturedPipeline); _renderItemId = scene->allocateID(); auto renderData = ParticlePayload::Pointer(particlePayload); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index fd5a9a6b4a..3ce3717dfb 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -547,7 +547,7 @@ bool RenderablePolyVoxEntityItem::addToScene(EntityItemPointer self, render::PendingChanges& pendingChanges) { _myItem = scene->allocateID(); - auto renderItem = std::make_shared(shared_from_this()); + auto renderItem = std::make_shared(getThisPointer()); auto renderData = PolyVoxPayload::Pointer(renderItem); auto renderPayload = std::make_shared(renderData); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index c3c0204aee..f8e191cde1 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -242,7 +242,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet // PROP_CUSTOM_PROPERTIES_INCLUDED, APPEND_ENTITY_PROPERTY(PROP_SIMULATION_OWNER, _simulationOwner.toByteArray()); - APPEND_ENTITY_PROPERTY(PROP_POSITION, getPosition()); + APPEND_ENTITY_PROPERTY(PROP_POSITION, getLocalPosition()); APPEND_ENTITY_PROPERTY(PROP_ROTATION, getRotation()); APPEND_ENTITY_PROPERTY(PROP_VELOCITY, getVelocity()); APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, getAngularVelocity()); @@ -1038,7 +1038,7 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper properties._type = getType(); COPY_ENTITY_PROPERTY_TO_PROPERTIES(simulationOwner, getSimulationOwner); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(position, getPosition); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(position, getLocalPosition); COPY_ENTITY_PROPERTY_TO_PROPERTIES(dimensions, getDimensions); // NOTE: radius is obsolete COPY_ENTITY_PROPERTY_TO_PROPERTIES(rotation, getRotation); COPY_ENTITY_PROPERTY_TO_PROPERTIES(density, getDensity); @@ -1078,7 +1078,7 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) const { // a TerseUpdate includes the transform and its derivatives - properties._position = getPosition(); + properties._position = getLocalPosition(); properties._velocity = _velocity; properties._rotation = getRotation(); properties._angularVelocity = _angularVelocity; @@ -1313,10 +1313,10 @@ void EntityItem::updatePosition(const glm::vec3& value) { if (shouldSuppressLocationEdits()) { return; } - auto delta = glm::distance(getPosition(), value); + auto delta = glm::distance(getLocalPosition(), value); if (delta > IGNORE_POSITION_DELTA) { _dirtyFlags |= Simulation::DIRTY_POSITION; - setPosition(value); + setLocalPosition(value); if (delta > ACTIVATION_POSITION_DELTA) { _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; } @@ -1685,7 +1685,7 @@ void EntityItem::deserializeActionsInternal() { action->locallyAddedButNotYetReceived = false; } else { auto actionFactory = DependencyManager::get(); - EntityItemPointer entity = shared_from_this(); + EntityItemPointer entity = getThisPointer(); EntityActionPointer action = actionFactory->factoryBA(entity, serializedAction); if (action) { entity->addActionInternal(simulation, action); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 79fe438c39..7d6de20a5c 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -75,7 +75,7 @@ const float ACTIVATION_ANGULAR_VELOCITY_DELTA = 0.03f; /// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate /// one directly, instead you must only construct one of it's derived classes with additional features. -class EntityItem : public std::enable_shared_from_this, public SpatiallyNestable, public ReadWriteLockable { +class EntityItem : public SpatiallyNestable, public ReadWriteLockable { // These two classes manage lists of EntityItem pointers and must be able to cleanup pointers when an EntityItem is deleted. // To make the cleanup robust each EntityItem has backpointers to its manager classes (which are only ever set/cleared by // the managers themselves, hence they are fiends) whose NULL status can be used to determine which managers still need to @@ -89,6 +89,8 @@ public: EntityItem(const EntityItemID& entityItemID); virtual ~EntityItem(); + inline EntityItemPointer getThisPointer() { return std::static_pointer_cast(shared_from_this()); } + EntityItemID getEntityItemID() const { return EntityItemID(_id); } // methods for getting/setting all properties of an entity diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 870c96a784..b3723cf3b7 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -34,19 +34,43 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { if (parent && parent->getID() == _parentID) { // parent pointer is up-to-date + if (!_parentKnowsMe) { + parent->beParentOfChild(shared_from_this()); + _parentKnowsMe = true; + } return parent; } - if (parent && _parentID.isNull()) { - // we have a parent pointer but our _parentID is null + if (parent) { + // we have a parent pointer but our _parentID doesn't indicate this parent. + parent->forgetChild(shared_from_this()); + _parentKnowsMe = false; _parent.reset(); - return nullptr; } // we have a _parentID but no parent pointer, or our parent pointer is to the wrong thing QSharedPointer parentFinder = DependencyManager::get(); - _parent = parentFinder->find(_parentID); - return _parent.lock(); + _parent = parentFinder->find(_parentID); + parent = _parent.lock(); + if (parent) { + parent->beParentOfChild(shared_from_this()); + _parentKnowsMe = true; + } + return parent; +} + +void SpatiallyNestable::beParentOfChild(SpatiallyNestableConstPointer newChild) const { + _children[newChild->getID()] = newChild; +} + +void SpatiallyNestable::forgetChild(SpatiallyNestableConstPointer newChild) const { + _children.remove(newChild->getID()); +} + + +void SpatiallyNestable::setParentID(const QUuid& parentID) { + _parentID = parentID; + _parentKnowsMe = false; } const glm::vec3& SpatiallyNestable::getPosition() const { diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 930b096450..7ba5493340 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -20,9 +20,11 @@ class SpatiallyNestable; using SpatiallyNestableWeakPointer = std::weak_ptr; +using SpatiallyNestableWeakConstPointer = std::weak_ptr; using SpatiallyNestablePointer = std::shared_ptr; +using SpatiallyNestableConstPointer = std::shared_ptr; -class SpatiallyNestable { +class SpatiallyNestable : public std::enable_shared_from_this { public: SpatiallyNestable() : _transform() { } // XXX get rid of this one? @@ -33,7 +35,7 @@ public: virtual void setID(const QUuid& id) { _id = id; } virtual const QUuid& getParentID() const { return _parentID; } - virtual void setParentID(const QUuid& parentID) { _parentID = parentID; } + virtual void setParentID(const QUuid& parentID); virtual quint16 getParentJointIndex() const { return _parentJointIndex; } virtual void setParentJointIndex(quint16 parentJointIndex) { _parentJointIndex = parentJointIndex; } @@ -71,9 +73,11 @@ protected: QUuid _parentID; // what is this thing's transform relative to? quint16 _parentJointIndex; // which joint of the parent is this relative to? SpatiallyNestablePointer getParentPointer() const; - mutable SpatiallyNestableWeakPointer _parent; - QVector _children; + + virtual void beParentOfChild(SpatiallyNestableConstPointer newChild) const; + virtual void forgetChild(SpatiallyNestableConstPointer newChild) const; + mutable QHash _children; private: Transform _transform; // this is to be combined with parent's world-transform to produce this' world-transform. @@ -82,6 +86,7 @@ private: mutable glm::vec3 _absolutePositionCache; mutable glm::quat _absoluteRotationCache; mutable Transform _worldTransformCache; + mutable bool _parentKnowsMe = false; }; From 4f6da68a1fc8ccc08c4efdff48988cc49120c954 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 22 Oct 2015 16:25:28 -0700 Subject: [PATCH 023/401] add getJointPosition and getJointRotation for entities --- examples/toys/baseball.js | 57 ++++++++-- .../src/RenderableModelEntityItem.cpp | 25 ++++ .../src/RenderableModelEntityItem.h | 3 + .../entities/src/EntityScriptingInterface.cpp | 107 ++++++++---------- .../entities/src/EntityScriptingInterface.h | 6 + libraries/entities/src/ModelEntityItem.h | 3 + 6 files changed, 132 insertions(+), 69 deletions(-) diff --git a/examples/toys/baseball.js b/examples/toys/baseball.js index 5863708a86..f3f26a1f4b 100755 --- a/examples/toys/baseball.js +++ b/examples/toys/baseball.js @@ -12,6 +12,27 @@ var ROBOT_MODEL = "atp:ea02100c2ee63a8b9c0495557f32041be18ec94def157592e84a816665ce2f6e.fbx"; var ROBOT_POSITION = { x: -0.54, y: 1.21, z: 2.57 } +var BAT_MODEL = "atp:07bdd769a57ff15ebe9331ae4e2c2eae8886a6792b4790cce03b4716eb3a81c7.fbx" +var BAT_COLLISION_MODEL = "atp:1211ee12bc8ab0bb744e8582e15e728a00ca70a808550fc46d7284799b9a868a.obj" + +// add the fresh robot at home plate +var robot = Entities.addEntity({ + name: 'Robot', + type: 'Model', + modelURL: ROBOT_MODEL, + position: ROBOT_POSITION, + animation: { + url: ROBOT_MODEL + } +}); + +// add the bat +var bat = Entities.addEntity({ + name: 'Bat', + type: 'Model', + modelURL: BAT_MODEL +}) + var lastTriggerValue = 0.0; function checkTriggers() { @@ -35,7 +56,7 @@ function checkTriggers() { animation: { running: true, currentFrame: 0, - lastFrame: 21 + lastFrame: 21 } }); } @@ -44,16 +65,28 @@ function checkTriggers() { lastTriggerValue = rightTrigger; } -// add the fresh bat at home plate -var robot = Entities.addEntity({ - name: 'Robot', - type: "Model", - modelURL: ROBOT_MODEL, - position: ROBOT_POSITION, - animation: { - url: ROBOT_MODEL - } -}); +var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position +var ACTION_LIFETIME = 15; // seconds + +function moveBat() { + var forearmPosition = Entities.getJointPosition(robot, 40); + var forearmRotation = Entities.getJointRotation(robot, 40); + + Vec3.print("forearmPosition=", forearmPosition); + + Entities.addAction("spring", bat, { + targetPosition: forearmPosition, + targetRotation: forearmRotation, + tag: "bat-to-forearm", + linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME + lifetime: ACTION_LIFETIME + }); +} + +function update() { + checkTriggers(); +} // hook the update so we can check controller triggers -Script.update.connect(checkTriggers); +Script.update.connect(update); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index e604bdb925..a7c2ff09f4 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -575,3 +575,28 @@ bool RenderableModelEntityItem::contains(const glm::vec3& point) const { return false; } + +glm::vec3 RenderableModelEntityItem::getJointPosition(int jointIndex) const { + glm::vec3 position; + + if (_model) { + if (!_model->getJointPositionInWorldFrame(jointIndex, position)) { + position = glm::vec3(); + } + } + + return position; +} + +glm::quat RenderableModelEntityItem::getJointRotation(int jointIndex) const { + glm::quat rotation; + + if (_model) { + if (!_model->getJointRotationInWorldFrame(jointIndex, rotation)) { + rotation = glm::quat(); + } + } + + return rotation; +} + diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 4dc1cced48..64629ad291 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -67,6 +67,9 @@ public: void computeShapeInfo(ShapeInfo& info); virtual bool contains(const glm::vec3& point) const; + + virtual glm::vec3 getJointPosition(int jointIndex) const override; + virtual glm::quat getJointRotation(int jointIndex) const override; private: void remapTextures(); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 01d46e0a91..f18e216bb3 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -681,82 +681,75 @@ QVariantMap EntityScriptingInterface::getActionArguments(const QUuid& entityID, return result; } -glm::vec3 EntityScriptingInterface::voxelCoordsToWorldCoords(const QUuid& entityID, glm::vec3 voxelCoords) { +EntityItemPointer EntityScriptingInterface::checkForTreeEntityAndTypeMatch(const QUuid& entityID, + EntityTypes::EntityType entityType) { if (!_entityTree) { - return glm::vec3(0.0f); + return EntityItemPointer(); } - + EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); if (!entity) { - qCDebug(entities) << "EntityScriptingInterface::voxelCoordsToWorldCoords no entity with ID" << entityID; + qDebug() << "EntityScriptingInterface::checkForTreeEntityAndTypeMatch - no entity with ID" << entityID; + return entity; + } + + if (entityType != EntityTypes::Unknown && entity->getType() != entityType) { + return EntityItemPointer(); + } + + return entity; +} + +glm::vec3 EntityScriptingInterface::voxelCoordsToWorldCoords(const QUuid& entityID, glm::vec3 voxelCoords) { + if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::PolyVox)) { + auto polyVoxEntity = std::dynamic_pointer_cast(entity); + return polyVoxEntity->voxelCoordsToWorldCoords(voxelCoords); + } else { return glm::vec3(0.0f); } - - EntityTypes::EntityType entityType = entity->getType(); - if (entityType != EntityTypes::PolyVox) { - return glm::vec3(0.0f); - } - - auto polyVoxEntity = std::dynamic_pointer_cast(entity); - return polyVoxEntity->voxelCoordsToWorldCoords(voxelCoords); } glm::vec3 EntityScriptingInterface::worldCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 worldCoords) { - if (!_entityTree) { + if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::PolyVox)) { + auto polyVoxEntity = std::dynamic_pointer_cast(entity); + return polyVoxEntity->worldCoordsToVoxelCoords(worldCoords); + } else { return glm::vec3(0.0f); } - - EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); - if (!entity) { - qCDebug(entities) << "EntityScriptingInterface::worldCoordsToVoxelCoords no entity with ID" << entityID; - return glm::vec3(0.0f); - } - - EntityTypes::EntityType entityType = entity->getType(); - if (entityType != EntityTypes::PolyVox) { - return glm::vec3(0.0f); - } - - auto polyVoxEntity = std::dynamic_pointer_cast(entity); - return polyVoxEntity->worldCoordsToVoxelCoords(worldCoords); } glm::vec3 EntityScriptingInterface::voxelCoordsToLocalCoords(const QUuid& entityID, glm::vec3 voxelCoords) { - if (!_entityTree) { + if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::PolyVox)) { + auto polyVoxEntity = std::dynamic_pointer_cast(entity); + return polyVoxEntity->voxelCoordsToLocalCoords(voxelCoords); + } else { return glm::vec3(0.0f); } - - EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); - if (!entity) { - qCDebug(entities) << "EntityScriptingInterface::voxelCoordsToLocalCoords no entity with ID" << entityID; - return glm::vec3(0.0f); - } - - EntityTypes::EntityType entityType = entity->getType(); - if (entityType != EntityTypes::PolyVox) { - return glm::vec3(0.0f); - } - - auto polyVoxEntity = std::dynamic_pointer_cast(entity); - return polyVoxEntity->voxelCoordsToLocalCoords(voxelCoords); } glm::vec3 EntityScriptingInterface::localCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 localCoords) { - if (!_entityTree) { + if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::PolyVox)) { + auto polyVoxEntity = std::dynamic_pointer_cast(entity); + return polyVoxEntity->localCoordsToVoxelCoords(localCoords); + } else { return glm::vec3(0.0f); } - - EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); - if (!entity) { - qCDebug(entities) << "EntityScriptingInterface::localCoordsToVoxelCoords no entity with ID" << entityID; - return glm::vec3(0.0f); - } - - EntityTypes::EntityType entityType = entity->getType(); - if (entityType != EntityTypes::PolyVox) { - return glm::vec3(0.0f); - } - - auto polyVoxEntity = std::dynamic_pointer_cast(entity); - return polyVoxEntity->localCoordsToVoxelCoords(localCoords); +} + +glm::vec3 EntityScriptingInterface::getJointPosition(const QUuid& entityID, int jointIndex) { + if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::Model)) { + auto modelEntity = std::dynamic_pointer_cast(entity); + return modelEntity->getJointPosition(jointIndex); + } else { + return glm::vec3(0.0f); + } +} + +glm::quat EntityScriptingInterface::getJointRotation(const QUuid& entityID, int jointIndex) { + if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::Model)) { + auto modelEntity = std::dynamic_pointer_cast(entity); + return modelEntity->getJointRotation(jointIndex); + } else { + return glm::quat(); + } } diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index d764cd7bab..4578c2d7ff 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -150,6 +150,9 @@ public slots: Q_INVOKABLE glm::vec3 worldCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 worldCoords); Q_INVOKABLE glm::vec3 voxelCoordsToLocalCoords(const QUuid& entityID, glm::vec3 voxelCoords); Q_INVOKABLE glm::vec3 localCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 localCoords); + + Q_INVOKABLE glm::vec3 getJointPosition(const QUuid& entityID, int jointIndex); + Q_INVOKABLE glm::quat getJointRotation(const QUuid& entityID, int jointIndex); signals: void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); @@ -182,6 +185,9 @@ private: bool setVoxels(QUuid entityID, std::function actor); bool setPoints(QUuid entityID, std::function actor); void queueEntityMessage(PacketType packetType, EntityItemID entityID, const EntityItemProperties& properties); + + EntityItemPointer checkForTreeEntityAndTypeMatch(const QUuid& entityID, + EntityTypes::EntityType entityType = EntityTypes::Unknown); /// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index e8ffcab3e7..66d46bcf4c 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -120,6 +120,9 @@ public: virtual bool shouldBePhysical() const; static void cleanupLoadedAnimations(); + + virtual glm::vec3 getJointPosition(int jointIndex) const { return glm::vec3(); } + virtual glm::quat getJointRotation(int jointIndex) const { return glm::quat(); } private: void setAnimationSettings(const QString& value); // only called for old bitstream format From 5f166044ecdec6f2553b28f993efd6830793a622 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 22 Oct 2015 12:03:19 -0700 Subject: [PATCH 024/401] Make handler generators more readable --- libraries/script-engine/src/ScriptEngine.cpp | 47 +++++++++----------- libraries/script-engine/src/ScriptEngine.h | 2 +- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 76590f266b..a317f2a82c 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -508,26 +508,29 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& // Connect up ALL the handlers to the global entities object's signals. // (We could go signal by signal, or even handler by handler, but I don't think the efficiency is worth the complexity.) auto entities = DependencyManager::get(); - connect(entities.data(), &EntityScriptingInterface::deletingEntity, this, - [=](const EntityItemID& entityID) { - _registeredHandlers.remove(entityID); - }); - + connect(entities.data(), &EntityScriptingInterface::deletingEntity, this, [this](const EntityItemID& entityID) { + _registeredHandlers.remove(entityID); + }); + // Two common cases of event handler, differing only in argument signature. - auto makeSingleEntityHandler = [=](const QString& eventName) -> std::function { - return [=](const EntityItemID& entityItemID) -> void { - generalHandler(entityItemID, eventName, [=]() -> QScriptValueList { - return QScriptValueList() << entityItemID.toScriptValue(this); - }); + auto makeSingleEntityHandler = [&](QString eventName) { + return [this, eventName](const EntityItemID& entityItemID) { + forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this) }); }; }; - auto makeMouseHandler = [=](const QString& eventName) -> std::function { - return [=](const EntityItemID& entityItemID, const MouseEvent& event) -> void { - generalHandler(entityItemID, eventName, [=]() -> QScriptValueList { - return QScriptValueList() << entityItemID.toScriptValue(this) << event.toScriptValue(this); - }); + auto makeMouseHandler = [&](QString eventName) { + return [this, eventName](const EntityItemID& entityItemID, const MouseEvent& event) { + forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this), event.toScriptValue(this) }); }; }; + + auto makeCollisionHandler = [&](QString eventName) { + return [this, eventName](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { + forwardHandlerCall(idA, eventName, { idA.toScriptValue(this), idB.toScriptValue(this), + collisionToScriptValue(this, collision) }); + }; + }; + connect(entities.data(), &EntityScriptingInterface::enterEntity, this, makeSingleEntityHandler("enterEntity")); connect(entities.data(), &EntityScriptingInterface::leaveEntity, this, makeSingleEntityHandler("leaveEntity")); @@ -543,12 +546,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& connect(entities.data(), &EntityScriptingInterface::hoverOverEntity, this, makeMouseHandler("hoverOverEntity")); connect(entities.data(), &EntityScriptingInterface::hoverLeaveEntity, this, makeMouseHandler("hoverLeaveEntity")); - connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, - [=](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { - generalHandler(idA, "collisionWithEntity", [=]() { - return QScriptValueList () << idA.toScriptValue(this) << idB.toScriptValue(this) << collisionToScriptValue(this, collision); - }); - }); + connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, makeCollisionHandler("collisionWithEntity")); } if (!_registeredHandlers.contains(entityID)) { _registeredHandlers[entityID] = RegisteredEventHandlers(); @@ -899,9 +897,9 @@ void ScriptEngine::load(const QString& loadFile) { } // Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args -void ScriptEngine::generalHandler(const EntityItemID& entityID, const QString& eventName, std::function argGenerator) { +void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHanderArgs) { if (QThread::currentThread() != thread()) { - qDebug() << "*** ERROR *** ScriptEngine::generalHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; + qDebug() << "*** ERROR *** ScriptEngine::forwardHandlerCall() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; assert(false); return; } @@ -915,9 +913,8 @@ void ScriptEngine::generalHandler(const EntityItemID& entityID, const QString& e } QScriptValueList handlersForEvent = handlersOnEntity[eventName]; if (!handlersForEvent.isEmpty()) { - QScriptValueList args = argGenerator(); for (int i = 0; i < handlersForEvent.count(); ++i) { - handlersForEvent[i].call(QScriptValue(), args); + handlersForEvent[i].call(QScriptValue(), eventHanderArgs); } } } diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 1d3986143a..c2f9d966f1 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -193,7 +193,7 @@ private: ArrayBufferClass* _arrayBufferClass; QHash _registeredHandlers; - void generalHandler(const EntityItemID& entityID, const QString& eventName, std::function argGenerator); + void forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHanderArgs); Q_INVOKABLE void entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success); static QSet _allKnownScriptEngines; From 05b794259e6cb8b1f2dd0835ae4bfeba84374f4f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 22 Oct 2015 16:43:37 -0700 Subject: [PATCH 025/401] Script cleanup and particles on ground collisions --- examples/baseball/pitching.js | 245 ++++++++++++++++++++-------------- 1 file changed, 142 insertions(+), 103 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 5cb29ac5d7..1f8df39a7b 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -132,8 +132,70 @@ function randomFloat(low, high) { return low + Math.random() * (high - low); } +function playRandomSound(sounds, options) { + if (options === undefined) { + options = { + volume: 1.0, + position: MyAvatar.position, + } + } + Audio.playSound(sounds[randomInt(sounds.length)], options); +} + +function vec3Mult(a, b) { + return { + x: a.x * b.x, + y: a.y * b.y, + z: a.z * b.z, + }; +} + +function map(value, min1, max1, min2, max2) { + return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); +} + +function orientationOf(vector) { + var RAD_TO_DEG = 180.0 / Math.PI; + var Y_AXIS = { x: 0, y: 1, z: 0 }; + var X_AXIS = { x: 1, y: 0, z: 0 }; + var direction = Vec3.normalize(vector); + + var yaw = Quat.angleAxis(Math.atan2(direction.x, direction.z) * RAD_TO_DEG, Y_AXIS); + var pitch = Quat.angleAxis(Math.asin(-direction.y) * RAD_TO_DEG, X_AXIS); + + return Quat.multiply(yaw, pitch); +} + +var injector = null; + var ACCELERATION_SPREAD = 10.15; +var trail = null; +var trailInterval = null; +function cleanupTrail() { + if (trail) { + Script.clearInterval(this.trailInterval); + trailInterval = null; + + trail.destroy(); + trail = null; + } +} + +function setupTrail(entityID, position) { + cleanupTrail(); + + var lastPosition = position; + trail = new InfiniteLine(position, { red: 255, green: 128, blue: 89 }); + trailInterval = Script.setInterval(function() { + var properties = Entities.getEntityProperties(entityID, ['position']); + if (Vec3.distance(properties.position, lastPosition)) { + trail.enqueuePoint(properties.position); + lastPosition = properties.position; + } + }, 50); +} + function Baseball(position, velocity, ballScale) { var self = this; @@ -141,6 +203,7 @@ function Baseball(position, velocity, ballScale) { var properties = shallowCopy(BASEBALL_PROPERTIES); properties.position = position; properties.velocity = velocity; + properties.dimensions = Vec3.multiply(ballScale, properties.dimensions); /* properties.gravity = { x: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), @@ -148,16 +211,14 @@ function Baseball(position, velocity, ballScale) { z: 0.0, }; */ - properties.dimensions = Vec3.multiply(ballScale, properties.dimensions); - + // Create entity this.entityID = Entities.addEntity(properties); - this.trail = null; - this.onHit = function() { return true; }; - this.hasBeenHit = false; - this.boundCollisionCallback = function(a, b, c) { self.collisionCallback.call(self, a, b, c); }; - Script.addEventHandler(this.entityID, "collisionWithEntity", this.boundCollisionCallback); + // Listen for collision for the lifetime of the entity + Script.addEventHandler(this.entityID, "collisionWithEntity", function(entityA, entityB, collision) { + self.collisionCallback(entityA, entityB, collision); + }); /* if (false && Math.random() < 0.5) { for (var i = 0; i < 50; i++) { @@ -178,86 +239,52 @@ function Baseball(position, velocity, ballScale) { Baseball.prototype = { collisionCallback: function(entityA, entityB, collision) { var self = this; - - this.hasBeenHit = true; - var properties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']); - this.trail = new InfiniteLine(properties.position, { red: 255, green: 128, blue: 89 }); - var lastPosition = properties.position; - //Vec3.print("Velocity", properties.velocity); - //Vec3.print("VelocityChange", collision.velocityChange); - var speed = Vec3.length(properties.velocity); - playRandomSound(AUDIO.batHit, { - position: properties.position, - volume: 2.0 - }); - var sounds = null; - if (speed < 5.0) { - sounds = AUDIO.crowdBoos; - } else { - sounds = AUDIO.crowdCheers; - } - var self = this; - this.trailInterval = Script.setInterval(function() { - var properties = Entities.getEntityProperties(self.entityID, ['position']); - if (Vec3.distance(properties.position, lastPosition)) { - self.trail.enqueuePoint(properties.position); - lastPosition = properties.position; - } - }, 50); + var myProperties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']); + var myPosition = myProperties.position; + var myVelocity = myProperties.velocity; + + // Activate gravity Entities.editEntity(self.entityID, { - velocity: Vec3.multiply(2, properties.velocity), - gravity: { - x: 0, - y: -9.8, - z: 0 - } + gravity: { x: 0, y: -9.8, z: 0 } }); - var removeHandler = this.onHit(entityB, collision); - if (removeHandler) { - Script.removeEventHandler(self.entityID, "collisionWithEntity", self.boundCollisionCallback); - } - }, - cleanupTrail: function() { - if (this.trail) { - Script.clearInterval(this.trailInterval); - this.trailInterval = null; - - this.trail.destroy(); - this.trail = null; + var name = Entities.getEntityProperties(entityB, ["name"]).name; + print("Hit: " + name); + if (name == "Bat") { + print("HIT"); + + // Update ball velocity + Entities.editEntity(self.entityID, { + velocity: Vec3.multiply(2, myVelocity), + }); + + // Setup line update interval + setupTrail(self.entityID, myPosition); + + // Setup bat hit sound + playRandomSound(AUDIO.batHit, { + position: myPosition, + volume: 2.0 + }); + + // Setup crowd reaction sound + var speed = Vec3.length(myVelocity); + Script.setTimeout(function() { + playRandomSound((speed < 5.0) ? AUDIO.crowdBoos : AUDIO.crowdCheers, { + position: { x: 0 ,y: 0, z: 0 }, + volume: 1.0 + }); + }, 500); + } else if (name == "stadium") { + print("PARTICLES"); + entityCollisionWithGround(entityB, this.entityID, collision); + } else if (name == "backstop") { + print("STRIKE"); } } } -function playRandomSound(sounds, options) { - if (options === undefined) { - options = { - volume: 1.0, - position: MyAvatar.position, - } - } - Audio.playSound(sounds[randomInt(sounds.length)], options); -} - -var lastTrail = null; - - -function vec3Mult(a, b) { - return { - x: a.x * b.x, - y: a.y * b.y, - z: a.z * b.z, - }; -} - -var lastBall = null; -var injector = null; - function pitchBall() { - if (lastBall) { - lastBall.cleanupTrail(); - } - var machineProperties = Entities.getEntityProperties(pitchingMachineID, ["dimensions", "position", "rotation"]); var pitchFromPositionBase = machineProperties.position; var pitchFromOffset = vec3Mult(machineProperties.dimensions, PITCHING_MACHINE_OUTPUT_OFFSET_PCT); @@ -271,26 +298,6 @@ function pitchBall() { var timeToPassPlate = (DISTANCE_FROM_PLATE + 1.0) / speed; var baseball = new Baseball(pitchFromPosition, Vec3.multiply(speed, pitchDirection), ballScale); - lastBall = baseball; - - baseball.onHit = function(entityB, collision) { - var properties = Entities.getEntityProperties(entityB, ["name"]); - var name = properties.name; - print("Hit: " + name); - if (name == "backstop") { - print("STRIKE"); - } else if (name == "bat") { - print("HIT"); - Script.setTimeout(function() { - playRandomSound(sounds, { - position: { x: 0 ,y: 0, z: 0 }, - volume: 1.0, - }); - }, 500); - } - //Script.clearTimeout(strikeTimeout); - return true; - } if (!injector) { injector = Audio.playSound(pitchSound, { @@ -302,12 +309,44 @@ function pitchBall() { } } +function entityCollisionWithGround(ground, entity, collision) { + var ZERO_VEC = { x: 0, y: 0, z: 0 }; + var dVelocityMagnitude = Vec3.length(collision.velocityChange); + var position = Entities.getEntityProperties(entity, "position").position; + var particleRadius = 0.3;//map(dVelocityMagnitude, 0.05, 3, 0.5, 2); + var speed = map(dVelocityMagnitude, 0.05, 3, 0.02, 0.09); + var displayTime = 400; + var orientationChange = orientationOf(collision.velocityChange); + + var dustEffect = Entities.addEntity({ + type: "ParticleEffect", + name: "Dust-Puff", + position: position, + color: {red: 195, green: 170, blue: 185}, + lifespan: 3, + lifetime: 2,//displayTime/1000 * 2, //So we can fade particle system out gracefully + emitRate: 5, + emitSpeed: speed, + emitAcceleration: ZERO_VEC, + accelerationSpread: ZERO_VEC, + isEmitting: true, + polarStart: Math.PI/2, + polarFinish: Math.PI/2, + emitOrientation: orientationChange, + radiusSpread: 0.1, + radiusStart: particleRadius, + radiusFinish: particleRadius + particleRadius / 2, + particleRadius: particleRadius, + alpha: 0.45, + alphaFinish: 0.001, + textures: "https://hifi-public.s3.amazonaws.com/alan/Playa/Particles/Particle-Sprite-Gen.png" + }); +} + Script.scriptEnding.connect(function() { + cleanupTrail(); Entities.deleteEntity(pitchingMachineID); -}) +}); Script.setInterval(pitchBall, PITCH_RATE); - - - From 70c32e4b13120d550e18eaa1b679722b4863cf24 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 22 Oct 2015 16:45:57 -0700 Subject: [PATCH 026/401] Remove empty script --- examples/baseballEntityScript.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 examples/baseballEntityScript.js diff --git a/examples/baseballEntityScript.js b/examples/baseballEntityScript.js deleted file mode 100644 index e69de29bb2..0000000000 From 9e5e886761bdfc07031409d519f401c153ff8deb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 22 Oct 2015 16:47:43 -0700 Subject: [PATCH 027/401] try to move the bat directly to robot --- examples/toys/baseball.js | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/examples/toys/baseball.js b/examples/toys/baseball.js index f3f26a1f4b..5ad21b162f 100755 --- a/examples/toys/baseball.js +++ b/examples/toys/baseball.js @@ -22,7 +22,8 @@ var robot = Entities.addEntity({ modelURL: ROBOT_MODEL, position: ROBOT_POSITION, animation: { - url: ROBOT_MODEL + url: ROBOT_MODEL, + running: true } }); @@ -74,18 +75,23 @@ function moveBat() { Vec3.print("forearmPosition=", forearmPosition); - Entities.addAction("spring", bat, { - targetPosition: forearmPosition, - targetRotation: forearmRotation, - tag: "bat-to-forearm", - linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME - lifetime: ACTION_LIFETIME + // Entities.addAction("spring", bat, { + // targetPosition: forearmPosition, + // targetRotation: forearmRotation, + // linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + // angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, + // lifetime: ACTION_LIFETIME + // }); + + Entities.editEntity(bat, { + position: forearmPosition, + rotation: forearmRotation }); } function update() { checkTriggers(); + moveBat(); } // hook the update so we can check controller triggers From 7b08d047b19598784cfa03c67d67329a6351724a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 22 Oct 2015 16:59:56 -0700 Subject: [PATCH 028/401] when EntityTree::updateEntityWithElement is called on an entity, call it on all the children of that entity --- libraries/avatars/src/AvatarData.cpp | 2 +- libraries/avatars/src/AvatarData.h | 5 +- .../src/BoundingBoxRelatedProperties.cpp | 83 ++++++++++++++ .../src/BoundingBoxRelatedProperties.h | 30 ++++++ libraries/entities/src/EntityItem.cpp | 2 +- libraries/entities/src/EntityTree.cpp | 33 +++++- libraries/entities/src/EntityTypes.h | 4 +- .../entities/src/UpdateEntityOperator.cpp | 101 ++++-------------- libraries/entities/src/UpdateEntityOperator.h | 6 +- libraries/shared/src/SpatiallyNestable.cpp | 24 ++++- libraries/shared/src/SpatiallyNestable.h | 28 +++-- 11 files changed, 213 insertions(+), 105 deletions(-) create mode 100644 libraries/entities/src/BoundingBoxRelatedProperties.cpp create mode 100644 libraries/entities/src/BoundingBoxRelatedProperties.h diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index fc9d9c75a7..a1db573d8d 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -37,7 +37,7 @@ const glm::vec3 DEFAULT_LOCAL_AABOX_CORNER(-0.5f); const glm::vec3 DEFAULT_LOCAL_AABOX_SCALE(1.0f); AvatarData::AvatarData() : - _sessionUUID(), + SpatiallyNestable(NestableTypes::Avatar, QUuid()), _handPosition(0.0f), _targetScale(1.0f), _handState(0), diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 4f826eafde..8a0a9ac38a 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -172,7 +172,7 @@ public: virtual bool isMyAvatar() const { return false; } - const QUuid& getSessionUUID() const { return _sessionUUID; } + const QUuid& getSessionUUID() const { return getID(); } glm::vec3 getHandPosition() const; void setHandPosition(const glm::vec3& handPosition); @@ -327,7 +327,7 @@ public slots: void setBillboardFromNetworkReply(); void setJointMappingsFromNetworkReply(); - void setSessionUUID(const QUuid& sessionUUID) { _sessionUUID = sessionUUID; } + void setSessionUUID(const QUuid& sessionUUID) { setID(sessionUUID); } bool isPlaying(); bool isPaused(); @@ -353,7 +353,6 @@ public slots: void stopPlaying(); protected: - QUuid _sessionUUID; glm::vec3 _handPosition; // Body scale diff --git a/libraries/entities/src/BoundingBoxRelatedProperties.cpp b/libraries/entities/src/BoundingBoxRelatedProperties.cpp new file mode 100644 index 0000000000..e9ee302300 --- /dev/null +++ b/libraries/entities/src/BoundingBoxRelatedProperties.cpp @@ -0,0 +1,83 @@ +// +// BoundingBoxRelatedProperties.cpp +// libraries/entities/src +// +// Created by Seth Alves on 2015-9-24 +// Copyright 2013 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 "EntityItemProperties.h" +#include "BoundingBoxRelatedProperties.h" +#include "EntityTree.h" + +BoundingBoxRelatedProperties::BoundingBoxRelatedProperties(EntityItemPointer entity) : + position(entity->getPosition()), + rotation(entity->getRotation()), + registrationPoint(entity->getRegistrationPoint()), + dimensions(entity->getDimensions()), + parentID(entity->getParentID()) { +} + +BoundingBoxRelatedProperties::BoundingBoxRelatedProperties(EntityItemPointer entity, + const EntityItemProperties& propertiesWithUpdates) : + BoundingBoxRelatedProperties(entity) { + + if (propertiesWithUpdates.parentIDChanged()) { + parentID = propertiesWithUpdates.getParentID(); + } + + bool parentFound = false; + if (parentID != UNKNOWN_ENTITY_ID) { + EntityTreePointer tree = entity->getTree(); + EntityItemPointer parentZone = tree->findEntityByID(parentID); + if (parentZone) { + parentFound = true; + glm::vec3 localPosition = propertiesWithUpdates.containsPositionChange() ? + propertiesWithUpdates.getPosition() : + entity->getLocalPosition(); + + glm::quat localRotation = propertiesWithUpdates.rotationChanged() ? + propertiesWithUpdates.getRotation() : + entity->getLocalOrientation(); + + const Transform parentTransform = parentZone->getTransformToCenter(); + Transform parentDescaled(parentTransform.getRotation(), glm::vec3(1.0f), parentTransform.getTranslation()); + + Transform localTransform(localRotation, glm::vec3(1.0f), localPosition); + Transform result; + Transform::mult(result, parentDescaled, localTransform); + position = result.getTranslation(); + rotation = result.getRotation(); + } + } + + if (!parentFound) { + if (propertiesWithUpdates.containsPositionChange()) { + position = propertiesWithUpdates.getPosition(); + } + if (propertiesWithUpdates.rotationChanged()) { + rotation = propertiesWithUpdates.getRotation(); + } + } + + if (propertiesWithUpdates.registrationPointChanged()) { + registrationPoint = propertiesWithUpdates.getRegistrationPoint(); + } + + if (propertiesWithUpdates.dimensionsChanged()) { + dimensions = propertiesWithUpdates.getDimensions(); + } +} + +AACube BoundingBoxRelatedProperties::getMaximumAACube() const { + // see EntityItem::getMaximumAACube for comments which explain the following. + glm::vec3 scaledRegistrationPoint = (dimensions * registrationPoint); + glm::vec3 registrationRemainder = (dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - registrationPoint)); + glm::vec3 furthestExtentFromRegistration = glm::max(scaledRegistrationPoint, registrationRemainder); + float radius = glm::length(furthestExtentFromRegistration); + glm::vec3 minimumCorner = position - glm::vec3(radius, radius, radius); + return AACube(minimumCorner, radius * 2.0f); +} diff --git a/libraries/entities/src/BoundingBoxRelatedProperties.h b/libraries/entities/src/BoundingBoxRelatedProperties.h new file mode 100644 index 0000000000..811c885fd2 --- /dev/null +++ b/libraries/entities/src/BoundingBoxRelatedProperties.h @@ -0,0 +1,30 @@ +// +// BoundingBoxRelatedProperties.h +// libraries/entities/src +// +// Created by Seth Alves on 2015-9-24 +// Copyright 2013 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 "EntityItem.h" + +#ifndef hifi_BoundingBoxRelatedProperties_h +#define hifi_BoundingBoxRelatedProperties_h + +class BoundingBoxRelatedProperties { + public: + BoundingBoxRelatedProperties(EntityItemPointer entity); + BoundingBoxRelatedProperties(EntityItemPointer entity, const EntityItemProperties& propertiesWithUpdates); + AACube getMaximumAACube() const; + + glm::vec3 position; + glm::quat rotation; + glm::vec3 registrationPoint; + glm::vec3 dimensions; + EntityItemID parentID; +}; + +#endif // hifi_BoundingBoxRelatedProperties_h diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index f8e191cde1..46d5635fc5 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -37,7 +37,7 @@ int EntityItem::_maxActionsDataSize = 800; quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND; EntityItem::EntityItem(const EntityItemID& entityItemID) : - SpatiallyNestable(entityItemID), + SpatiallyNestable(NestableTypes::Entity, entityItemID), _type(EntityTypes::Unknown), _lastSimulated(0), _lastUpdated(0), diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 24c13ae28e..257e3e0ed2 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -143,8 +143,11 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI if (!wantsLocked) { EntityItemProperties tempProperties; tempProperties.setLocked(wantsLocked); - UpdateEntityOperator theOperator(getThisPointer(), containingElement, entity, tempProperties); + + BoundingBoxRelatedProperties newBBRelProperties(entity, tempProperties); + UpdateEntityOperator theOperator(getThisPointer(), containingElement, entity, newBBRelProperties); recurseTreeWithOperator(&theOperator); + entity->setProperties(tempProperties); _isDirty = true; } } @@ -205,8 +208,34 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI quint64 entityScriptTimestampBefore = entity->getScriptTimestamp(); QString collisionSoundURLBefore = entity->getCollisionSoundURL(); uint32_t preFlags = entity->getDirtyFlags(); - UpdateEntityOperator theOperator(getThisPointer(), containingElement, entity, properties); + + BoundingBoxRelatedProperties newBBRelProperties(entity, properties); + UpdateEntityOperator theOperator(getThisPointer(), containingElement, entity, newBBRelProperties); recurseTreeWithOperator(&theOperator); + entity->setProperties(properties); + + // if the entity has children, run UpdateEntityOperator on them. If the children have children, recurse + QQueue toProcess; + foreach (SpatiallyNestablePointer child, entity->getChildren()) { + if (child && child->getNestableType() == NestableTypes::Entity) { + toProcess.enqueue(child); + } + } + + while (!toProcess.empty()) { + EntityItemPointer childEntity = std::static_pointer_cast(toProcess.dequeue()); + BoundingBoxRelatedProperties newChildBBRelProperties(childEntity); + UpdateEntityOperator theChildOperator(getThisPointer(), + childEntity->getElement(), + childEntity, newChildBBRelProperties); + recurseTreeWithOperator(&theChildOperator); + foreach (SpatiallyNestablePointer childChild, childEntity->getChildren()) { + if (childChild && childChild->getNestableType() == NestableTypes::Entity) { + toProcess.enqueue(childChild); + } + } + } + _isDirty = true; uint32_t newFlags = entity->getDirtyFlags() & ~preFlags; diff --git a/libraries/entities/src/EntityTypes.h b/libraries/entities/src/EntityTypes.h index 30b6edbc07..3536327d18 100644 --- a/libraries/entities/src/EntityTypes.h +++ b/libraries/entities/src/EntityTypes.h @@ -20,8 +20,8 @@ #include // for RenderArgs class EntityItem; -typedef std::shared_ptr EntityItemPointer; -typedef std::weak_ptr EntityItemWeakPointer; +using EntityItemPointer = std::shared_ptr; +using EntityItemWeakPointer = std::weak_ptr; inline uint qHash(const EntityItemPointer& a, uint seed) { return qHash(a.get(), seed); diff --git a/libraries/entities/src/UpdateEntityOperator.cpp b/libraries/entities/src/UpdateEntityOperator.cpp index 617663f48a..4acc386333 100644 --- a/libraries/entities/src/UpdateEntityOperator.cpp +++ b/libraries/entities/src/UpdateEntityOperator.cpp @@ -14,12 +14,12 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTreePointer tree, EntityTreeElementPointer containingElement, EntityItemPointer existingEntity, - const EntityItemProperties& properties) : + const BoundingBoxRelatedProperties& newProperties) : _tree(tree), _existingEntity(existingEntity), _containingElement(containingElement), _containingElementCube(containingElement->getAACube()), - _properties(properties), + _newProperties(newProperties), _entityItemID(existingEntity->getEntityItemID()), _foundOld(false), _foundNew(false), @@ -44,83 +44,32 @@ UpdateEntityOperator::UpdateEntityOperator(EntityTreePointer tree, _oldEntityCube = _existingEntity->getMaximumAACube(); _oldEntityBox = _oldEntityCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); // clamp to domain bounds - // If the old properties doesn't contain the properties required to calculate a bounding box, - // get them from the existing entity. Registration point is required to correctly calculate - // the bounding box. - if (!_properties.registrationPointChanged()) { - _properties.setRegistrationPoint(_existingEntity->getRegistrationPoint()); - } - - // If the new properties has position OR dimension changes, but not both, we need to - // get the old property value and set it in our properties in order for our bounds - // calculations to work. - if (_properties.containsPositionChange() && !_properties.containsDimensionsChange()) { - glm::vec3 oldDimensions= _existingEntity->getDimensions(); - _properties.setDimensions(oldDimensions); - - if (_wantDebug) { - qCDebug(entities) << " ** setting properties dimensions - had position change, no dimension change **"; - } - - } - if (!_properties.containsPositionChange() && _properties.containsDimensionsChange()) { - glm::vec3 oldPosition= _existingEntity->getPosition(); - _properties.setPosition(oldPosition); - - if (_wantDebug) { - qCDebug(entities) << " ** setting properties position - had dimensions change, no position change **"; - } - } - - // If our new properties don't have bounds details (no change to position, etc) or if this containing element would - // be the best fit for our new properties, then just do the new portion of the store pass, since the change path will + // If our new properties don't have bounds details (no change to position, etc) or if this containing element would + // be the best fit for our new properties, then just do the new portion of the store pass, since the change path will // be the same for both parts of the update - bool oldElementBestFit = _containingElement->bestFitBounds(_properties); - - // if we don't have bounds properties, then use our old clamped box to determine best fit - if (!_properties.containsBoundsProperties()) { - oldElementBestFit = _containingElement->bestFitBounds(_oldEntityBox); + bool oldElementBestFit = _containingElement->bestFitBounds(newProperties.getMaximumAACube()); - if (_wantDebug) { - qCDebug(entities) << " ** old Element best fit - no dimensions change, no position change **"; - } - - } - // For some reason we've seen a case where the original containing element isn't a best fit for the old properties // in this case we want to move it, even if the properties haven't changed. - if (!_properties.containsBoundsProperties() && !oldElementBestFit) { + if (!oldElementBestFit) { _newEntityCube = _oldEntityCube; _removeOld = true; // our properties are going to move us, so remember this for later processing if (_wantDebug) { qCDebug(entities) << " **** UNUSUAL CASE **** no changes, but not best fit... consider it a move.... **"; } - - - } else if (!_properties.containsBoundsProperties() || oldElementBestFit) { + } else { _foundOld = true; _newEntityCube = _oldEntityCube; _dontMove = true; if (_wantDebug) { - qCDebug(entities) << " **** TYPICAL NO MOVE CASE ****"; - qCDebug(entities) << " _properties.containsBoundsProperties():" << _properties.containsBoundsProperties(); - qCDebug(entities) << " oldElementBestFit:" << oldElementBestFit; - } - - } else { - _newEntityCube = _properties.getMaximumAACube(); - _removeOld = true; // our properties are going to move us, so remember this for later processing - - if (_wantDebug) { - qCDebug(entities) << " **** TYPICAL MOVE CASE ****"; + qCDebug(entities) << " **** TYPICAL NO MOVE CASE **** oldElementBestFit:" << oldElementBestFit; } } _newEntityBox = _newEntityCube.clamp((float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); // clamp to domain bounds - if (_wantDebug) { qCDebug(entities) << " _entityItemID:" << _entityItemID; qCDebug(entities) << " _containingElementCube:" << _containingElementCube; @@ -176,7 +125,7 @@ bool UpdateEntityOperator::subTreeContainsNewEntity(OctreeElementPointer element bool UpdateEntityOperator::preRecursion(OctreeElementPointer element) { EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); - + // In Pre-recursion, we're generally deciding whether or not we want to recurse this // path of the tree. For this operation, we want to recurse the branch of the tree if // and of the following are true: @@ -185,7 +134,7 @@ bool UpdateEntityOperator::preRecursion(OctreeElementPointer element) { // // Note: it's often the case that the branch in question contains both the old entity // and the new entity. - + bool keepSearching = false; // assume we don't need to search any more bool subtreeContainsOld = subTreeContainsOldEntity(element); @@ -257,7 +206,8 @@ bool UpdateEntityOperator::preRecursion(OctreeElementPointer element) { qCDebug(entities) << " NEW TREE CASE...."; qCDebug(entities) << " entityTreeElement=" << entityTreeElement.get(); qCDebug(entities) << " _containingElement=" << _containingElement.get(); - qCDebug(entities) << " entityTreeElement->bestFitBounds(_newEntityBox)=" << entityTreeElement->bestFitBounds(_newEntityBox); + qCDebug(entities) << " entityTreeElement->bestFitBounds(_newEntityBox)=" + << entityTreeElement->bestFitBounds(_newEntityBox); } // If this element is the best fit for the new entity properties, then add/or update it @@ -270,16 +220,9 @@ bool UpdateEntityOperator::preRecursion(OctreeElementPointer element) { EntityTreeElementPointer oldElement = _existingEntity->getElement(); // if we are the existing containing element, then we can just do the update of the entity properties if (entityTreeElement == oldElement) { - if (_wantDebug) { qCDebug(entities) << " *** This is the same OLD ELEMENT ***"; } - - // set the entity properties and mark our element as changed. - _existingEntity->setProperties(_properties); - if (_wantDebug) { - qCDebug(entities) << " *** set properties ***"; - } } else { // otherwise, this is an add case. if (oldElement) { @@ -290,11 +233,6 @@ bool UpdateEntityOperator::preRecursion(OctreeElementPointer element) { } entityTreeElement->addEntityItem(_existingEntity); _tree->setContainingElement(_entityItemID, entityTreeElement); - - _existingEntity->setProperties(_properties); // still need to update the properties! - if (_wantDebug) { - qCDebug(entities) << " *** ADDING ENTITY to ELEMENT and MAP and SETTING PROPERTIES ***"; - } } _foundNew = true; // we found the new element _removeOld = false; // and it has already been removed from the old @@ -308,7 +246,6 @@ bool UpdateEntityOperator::preRecursion(OctreeElementPointer element) { qCDebug(entities) << "--------------------------------------------------"; } - return keepSearching; // if we haven't yet found it, keep looking } @@ -329,9 +266,9 @@ bool UpdateEntityOperator::postRecursion(OctreeElementPointer element) { } // It's not OK to prune if we have the potential of deleting the original containig element. - // because if we prune the containing element then new might end up reallocating the same memory later + // because if we prune the containing element then new might end up reallocating the same memory later // and that will confuse our logic. - // + // // it's ok to prune if: // 1) we're not removing the old // 2) we are removing the old, but this subtree doesn't contain the old @@ -340,17 +277,17 @@ bool UpdateEntityOperator::postRecursion(OctreeElementPointer element) { EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); entityTreeElement->pruneChildren(); // take this opportunity to prune any empty leaves } - + return keepSearching; // if we haven't yet found it, keep looking } -OctreeElementPointer UpdateEntityOperator::possiblyCreateChildAt(OctreeElementPointer element, int childIndex) { +OctreeElementPointer UpdateEntityOperator::possiblyCreateChildAt(OctreeElementPointer element, int childIndex) { // If we're getting called, it's because there was no child element at this index while recursing. // We only care if this happens while still searching for the new entity location. - // Check to see if + // Check to see if if (!_foundNew) { float childElementScale = element->getScale() / 2.0f; // all of our children will be half our scale - + // Note: because the entity's bounds might have been clamped to the domain. We want to check if the // bounds of the clamped box would fit in our child elements. It may be the case that the actual // bounds of the element would hang outside of the child elements cells. @@ -365,5 +302,5 @@ OctreeElementPointer UpdateEntityOperator::possiblyCreateChildAt(OctreeElementPo } } } - return NULL; + return NULL; } diff --git a/libraries/entities/src/UpdateEntityOperator.h b/libraries/entities/src/UpdateEntityOperator.h index 46322997f7..aac442d415 100644 --- a/libraries/entities/src/UpdateEntityOperator.h +++ b/libraries/entities/src/UpdateEntityOperator.h @@ -12,6 +12,7 @@ #ifndef hifi_UpdateEntityOperator_h #define hifi_UpdateEntityOperator_h +#include "BoundingBoxRelatedProperties.h" #include "EntitiesLogging.h" #include "EntityItem.h" #include "EntityItemProperties.h" @@ -21,7 +22,8 @@ class UpdateEntityOperator : public RecurseOctreeOperator { public: UpdateEntityOperator(EntityTreePointer tree, EntityTreeElementPointer containingElement, - EntityItemPointer existingEntity, const EntityItemProperties& properties); + EntityItemPointer existingEntity, const BoundingBoxRelatedProperties& newProperties); + ~UpdateEntityOperator(); virtual bool preRecursion(OctreeElementPointer element); @@ -32,7 +34,7 @@ private: EntityItemPointer _existingEntity; EntityTreeElementPointer _containingElement; AACube _containingElementCube; // we temporarily store our cube here in case we need to delete the containing element - EntityItemProperties _properties; + BoundingBoxRelatedProperties _newProperties; EntityItemID _entityItemID; bool _foundOld; bool _foundNew; diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index b3723cf3b7..a813a37bfe 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -32,10 +32,13 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { return nullptr; } + SpatiallyNestableConstPointer constThisPointer = shared_from_this(); + SpatiallyNestablePointer thisPointer = std::const_pointer_cast(constThisPointer); // ermahgerd !!! + if (parent && parent->getID() == _parentID) { // parent pointer is up-to-date if (!_parentKnowsMe) { - parent->beParentOfChild(shared_from_this()); + parent->beParentOfChild(thisPointer); _parentKnowsMe = true; } return parent; @@ -43,7 +46,7 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { if (parent) { // we have a parent pointer but our _parentID doesn't indicate this parent. - parent->forgetChild(shared_from_this()); + parent->forgetChild(thisPointer); _parentKnowsMe = false; _parent.reset(); } @@ -53,17 +56,17 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { _parent = parentFinder->find(_parentID); parent = _parent.lock(); if (parent) { - parent->beParentOfChild(shared_from_this()); + parent->beParentOfChild(thisPointer); _parentKnowsMe = true; } return parent; } -void SpatiallyNestable::beParentOfChild(SpatiallyNestableConstPointer newChild) const { +void SpatiallyNestable::beParentOfChild(SpatiallyNestablePointer newChild) const { _children[newChild->getID()] = newChild; } -void SpatiallyNestable::forgetChild(SpatiallyNestableConstPointer newChild) const { +void SpatiallyNestable::forgetChild(SpatiallyNestablePointer newChild) const { _children.remove(newChild->getID()); } @@ -153,3 +156,14 @@ const glm::vec3& SpatiallyNestable::getLocalScale() const { void SpatiallyNestable::setLocalScale(const glm::vec3& scale) { _transform.setScale(scale); } + +QList SpatiallyNestable::getChildren() const { + QList children; + foreach (SpatiallyNestableWeakPointer childWP, _children.values()) { + SpatiallyNestablePointer child = childWP.lock(); + if (child) { + children << child; + } + } + return children; +} diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 7ba5493340..e0ee5bdb74 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -24,11 +24,21 @@ using SpatiallyNestableWeakConstPointer = std::weak_ptr using SpatiallyNestablePointer = std::shared_ptr; using SpatiallyNestableConstPointer = std::shared_ptr; -class SpatiallyNestable : public std::enable_shared_from_this { - +class NestableTypes { public: - SpatiallyNestable() : _transform() { } // XXX get rid of this one? - SpatiallyNestable(QUuid id) : _id(id), _transform() { } + using NestableType = enum NestableType_t { + Entity, + Avatar + }; +}; + +class SpatiallyNestable : public std::enable_shared_from_this { +public: + // SpatiallyNestable() : _transform() { } // XXX get rid of this one? + SpatiallyNestable(NestableTypes::NestableType nestableType, QUuid id) : + _nestableType(nestableType), + _id(id), + _transform() { } virtual ~SpatiallyNestable() { } virtual const QUuid& getID() const { return _id; } @@ -68,16 +78,20 @@ public: virtual const glm::vec3& getLocalScale() const; virtual void setLocalScale(const glm::vec3& scale); + QList getChildren() const; + NestableTypes::NestableType getNestableType() const { return _nestableType; } + protected: + NestableTypes::NestableType _nestableType; // EntityItem or an AvatarData QUuid _id; QUuid _parentID; // what is this thing's transform relative to? quint16 _parentJointIndex; // which joint of the parent is this relative to? SpatiallyNestablePointer getParentPointer() const; mutable SpatiallyNestableWeakPointer _parent; - virtual void beParentOfChild(SpatiallyNestableConstPointer newChild) const; - virtual void forgetChild(SpatiallyNestableConstPointer newChild) const; - mutable QHash _children; + virtual void beParentOfChild(SpatiallyNestablePointer newChild) const; + virtual void forgetChild(SpatiallyNestablePointer newChild) const; + mutable QHash _children; private: Transform _transform; // this is to be combined with parent's world-transform to produce this' world-transform. From bf290c35be4ce5ff2c188d601785ad26ee27f24e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 23 Oct 2015 09:46:57 -0700 Subject: [PATCH 029/401] when an entity gets a physics flag set, set the same flag in any children --- libraries/entities/src/EntityItem.cpp | 47 +++++++++++++++++++++------ libraries/entities/src/EntityItem.h | 2 ++ 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 46d5635fc5..7c9f3139df 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1309,17 +1309,40 @@ void EntityItem::computeShapeInfo(ShapeInfo& info) { info.setParams(getShapeType(), 0.5f * getDimensions()); } +bool EntityItem::forSelfAndEachChildEntity(std::function actor) { + bool result = true; + QQueue toProcess; + toProcess.enqueue(shared_from_this()); + + while (!toProcess.empty()) { + EntityItemPointer entity = std::static_pointer_cast(toProcess.dequeue()); + + result &= actor(entity); + + foreach (SpatiallyNestablePointer child, entity->getChildren()) { + if (child && child->getNestableType() == NestableTypes::Entity) { + toProcess.enqueue(child); + } + } + } + + return result; +} + void EntityItem::updatePosition(const glm::vec3& value) { if (shouldSuppressLocationEdits()) { return; } auto delta = glm::distance(getLocalPosition(), value); if (delta > IGNORE_POSITION_DELTA) { - _dirtyFlags |= Simulation::DIRTY_POSITION; setLocalPosition(value); - if (delta > ACTIVATION_POSITION_DELTA) { - _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; - } + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->_dirtyFlags |= Simulation::DIRTY_POSITION; + if (delta > ACTIVATION_POSITION_DELTA) { + entity->_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; + } + return true; + }); } } @@ -1342,12 +1365,16 @@ void EntityItem::updateRotation(const glm::quat& rotation) { setRotation(rotation); auto alignmentDot = glm::abs(glm::dot(getRotation(), rotation)); - if (alignmentDot < IGNORE_ALIGNMENT_DOT) { - _dirtyFlags |= Simulation::DIRTY_ROTATION; - } - if (alignmentDot < ACTIVATION_ALIGNMENT_DOT) { - _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; - } + + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + if (alignmentDot < IGNORE_ALIGNMENT_DOT) { + entity->_dirtyFlags |= Simulation::DIRTY_ROTATION; + } + if (alignmentDot < ACTIVATION_ALIGNMENT_DOT) { + entity->_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; + } + return true; + }); } } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 7d6de20a5c..6e03e52679 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -396,6 +396,8 @@ protected: const QByteArray getActionDataInternal() const; void setActionDataInternal(QByteArray actionData); + bool forSelfAndEachChildEntity(std::function actor); + static bool _sendPhysicsUpdates; EntityTypes::EntityType _type; quint64 _lastSimulated; // last time this entity called simulate(), this includes velocity, angular velocity, From 22af5b27abe9012e2d1cfa6fb6ef69b2377603fb Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 23 Oct 2015 12:55:48 -0700 Subject: [PATCH 030/401] avoid shared_from_this while constructing --- libraries/avatars/src/AvatarData.cpp | 1 + libraries/entities/src/EntityItem.cpp | 1 + libraries/shared/src/SpatiallyNestable.cpp | 5 +++++ libraries/shared/src/SpatiallyNestable.h | 2 ++ 4 files changed, 9 insertions(+) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index a1db573d8d..7f0f758b87 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -60,6 +60,7 @@ AvatarData::AvatarData() : setBodyPitch(0.0f); setBodyYaw(-90.0f); setBodyRoll(0.0f); + _constructing = false; } AvatarData::~AvatarData() { diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 7c9f3139df..fd4a4b298c 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -85,6 +85,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : quint64 now = usecTimestampNow(); _lastSimulated = now; _lastUpdated = now; + _constructing = false; } EntityItem::~EntityItem() { diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index a813a37bfe..9d1220c214 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -32,6 +32,11 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { return nullptr; } + if (_constructing) { + // we can't use shared_from_this yet, so stop here. + return nullptr; + } + SpatiallyNestableConstPointer constThisPointer = shared_from_this(); SpatiallyNestablePointer thisPointer = std::const_pointer_cast(constThisPointer); // ermahgerd !!! diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index e0ee5bdb74..108da796a0 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -82,6 +82,8 @@ public: NestableTypes::NestableType getNestableType() const { return _nestableType; } protected: + bool _constructing = true; + NestableTypes::NestableType _nestableType; // EntityItem or an AvatarData QUuid _id; QUuid _parentID; // what is this thing's transform relative to? From 001400908d3d27fc33ea9cb5c4004675d67c2588 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 23 Oct 2015 13:37:49 -0700 Subject: [PATCH 031/401] Add automatic CCD activation to the physics engine --- libraries/physics/src/ObjectMotionState.cpp | 18 ++++++++++++++++++ libraries/physics/src/ObjectMotionState.h | 1 + 2 files changed, 19 insertions(+) diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 4f3d0396c6..b47c870216 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -115,6 +115,21 @@ void ObjectMotionState::setMotionType(MotionType motionType) { _motionType = motionType; } +void ObjectMotionState::updateCCDConfiguration() { + if (_body) { + if (_shape) { + btVector3 center; + btScalar radius; + _shape->getBoundingSphere(center, radius); + _body->setCcdMotionThreshold(radius * 2.0f); + _body->setCcdSweptSphereRadius(radius); + } else { + // Disable CCD + _body->setCcdMotionThreshold(0); + } + } +} + void ObjectMotionState::setRigidBody(btRigidBody* body) { // give the body a (void*) back-pointer to this ObjectMotionState if (_body != body) { @@ -125,6 +140,7 @@ void ObjectMotionState::setRigidBody(btRigidBody* body) { if (_body) { _body->setUserPointer(this); } + updateCCDConfiguration(); } } @@ -187,6 +203,8 @@ bool ObjectMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* if (_shape != newShape) { _shape = newShape; _body->setCollisionShape(_shape); + + updateCCDConfiguration(); } else { // huh... the shape didn't actually change, so we clear the DIRTY_SHAPE flag flags &= ~Simulation::DIRTY_SHAPE; diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 450ac34a90..9945d07c33 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -137,6 +137,7 @@ protected: virtual bool isReadyToComputeShape() = 0; virtual btCollisionShape* computeNewShape() = 0; void setMotionType(MotionType motionType); + void updateCCDConfiguration(); // clearObjectBackPointer() overrrides should call the base method, then actually clear the object back pointer. virtual void clearObjectBackPointer() { _type = MOTIONSTATE_TYPE_INVALID; } From 61269c3ce837b30cfcd389849832045a9d55e05f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 23 Oct 2015 13:52:50 -0700 Subject: [PATCH 032/401] fix up entity constructors so that setProperties isn't called during the constructor --- libraries/avatars/src/AvatarData.cpp | 1 - .../src/RenderableBoxEntityItem.cpp | 4 +++- .../src/RenderableBoxEntityItem.h | 5 +--- .../src/RenderableLightEntityItem.cpp | 4 +++- .../src/RenderableLightEntityItem.h | 5 +--- .../src/RenderableLineEntityItem.cpp | 4 +++- .../src/RenderableLineEntityItem.h | 5 ++-- .../src/RenderableModelEntityItem.cpp | 13 ++++++----- .../src/RenderableModelEntityItem.h | 2 +- .../RenderableParticleEffectEntityItem.cpp | 12 ++++++---- .../src/RenderableParticleEffectEntityItem.h | 2 +- .../src/RenderablePolyLineEntityItem.cpp | 10 ++++---- .../src/RenderablePolyLineEntityItem.h | 2 +- .../src/RenderablePolyVoxEntityItem.cpp | 9 ++++---- .../src/RenderablePolyVoxEntityItem.h | 3 +-- .../src/RenderableSphereEntityItem.cpp | 4 +++- .../src/RenderableSphereEntityItem.h | 5 +--- .../src/RenderableTextEntityItem.cpp | 4 +++- .../src/RenderableTextEntityItem.h | 5 +--- .../src/RenderableWebEntityItem.cpp | 8 ++++--- .../src/RenderableWebEntityItem.h | 3 +-- .../src/RenderableZoneEntityItem.cpp | 4 +++- .../src/RenderableZoneEntityItem.h | 8 +++---- libraries/entities/src/BoxEntityItem.cpp | 10 ++++---- libraries/entities/src/BoxEntityItem.h | 2 +- libraries/entities/src/EntityItem.cpp | 1 - libraries/entities/src/LightEntityItem.cpp | 13 ++++------- libraries/entities/src/LightEntityItem.h | 2 +- libraries/entities/src/LineEntityItem.cpp | 12 ++++------ libraries/entities/src/LineEntityItem.h | 2 +- libraries/entities/src/ModelEntityItem.cpp | 8 +++---- libraries/entities/src/ModelEntityItem.h | 2 +- .../entities/src/ParticleEffectEntityItem.cpp | 11 ++++----- .../entities/src/ParticleEffectEntityItem.h | 2 +- libraries/entities/src/PolyLineEntityItem.cpp | 23 +++++++++---------- libraries/entities/src/PolyLineEntityItem.h | 2 +- libraries/entities/src/PolyVoxEntityItem.cpp | 7 +++--- libraries/entities/src/PolyVoxEntityItem.h | 2 +- libraries/entities/src/SphereEntityItem.cpp | 10 ++++---- libraries/entities/src/SphereEntityItem.h | 2 +- libraries/entities/src/TextEntityItem.cpp | 9 ++++---- libraries/entities/src/TextEntityItem.h | 2 +- libraries/entities/src/WebEntityItem.cpp | 9 ++++---- libraries/entities/src/WebEntityItem.h | 2 +- libraries/entities/src/ZoneEntityItem.cpp | 10 ++++---- libraries/entities/src/ZoneEntityItem.h | 2 +- libraries/shared/src/SpatiallyNestable.cpp | 5 ---- libraries/shared/src/SpatiallyNestable.h | 2 -- 48 files changed, 127 insertions(+), 147 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 7f0f758b87..a1db573d8d 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -60,7 +60,6 @@ AvatarData::AvatarData() : setBodyPitch(0.0f); setBodyYaw(-90.0f); setBodyRoll(0.0f); - _constructing = false; } AvatarData::~AvatarData() { diff --git a/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp b/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp index 077f28350b..702b691342 100644 --- a/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp @@ -25,7 +25,9 @@ #include "../render-utils/simple_frag.h" EntityItemPointer RenderableBoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity{ new RenderableBoxEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } void RenderableBoxEntityItem::setUserData(const QString& value) { diff --git a/libraries/entities-renderer/src/RenderableBoxEntityItem.h b/libraries/entities-renderer/src/RenderableBoxEntityItem.h index 838022c7d4..9addfd813a 100644 --- a/libraries/entities-renderer/src/RenderableBoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderableBoxEntityItem.h @@ -20,10 +20,7 @@ class RenderableBoxEntityItem : public BoxEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - - RenderableBoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - BoxEntityItem(entityItemID, properties) - { } + RenderableBoxEntityItem(const EntityItemID& entityItemID) : BoxEntityItem(entityItemID) { } virtual void render(RenderArgs* args); virtual void setUserData(const QString& value); diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp index b0cc0462c6..5b8891d1f2 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp @@ -20,7 +20,9 @@ #include "RenderableLightEntityItem.h" EntityItemPointer RenderableLightEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity{ new RenderableLightEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } void RenderableLightEntityItem::render(RenderArgs* args) { diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.h b/libraries/entities-renderer/src/RenderableLightEntityItem.h index ecf24eaec7..aac1a4a998 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.h +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.h @@ -18,10 +18,7 @@ class RenderableLightEntityItem : public LightEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - - RenderableLightEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - LightEntityItem(entityItemID, properties) - { } + RenderableLightEntityItem(const EntityItemID& entityItemID) : LightEntityItem(entityItemID) { } virtual void render(RenderArgs* args); virtual bool supportsDetailedRayIntersection() const { return true; } diff --git a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp index 3735690c33..1c9c50af55 100644 --- a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp @@ -20,7 +20,9 @@ #include "RenderableLineEntityItem.h" EntityItemPointer RenderableLineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity{ new RenderableLineEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } void RenderableLineEntityItem::updateGeometry() { diff --git a/libraries/entities-renderer/src/RenderableLineEntityItem.h b/libraries/entities-renderer/src/RenderableLineEntityItem.h index 09f98ca364..058cab2c4b 100644 --- a/libraries/entities-renderer/src/RenderableLineEntityItem.h +++ b/libraries/entities-renderer/src/RenderableLineEntityItem.h @@ -20,9 +20,8 @@ class RenderableLineEntityItem : public LineEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - - RenderableLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - LineEntityItem(entityItemID, properties), + RenderableLineEntityItem(const EntityItemID& entityItemID) : + LineEntityItem(entityItemID), _lineVerticesID(GeometryCache::UNKNOWN_ID) { } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index e604bdb925..d2f16de936 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -24,13 +24,14 @@ #include "RenderableModelEntityItem.h" EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity{ new RenderableModelEntityItem(entityID, properties.getDimensionsInitialized()) }; + entity->setProperties(properties); + return entity; } -RenderableModelEntityItem::RenderableModelEntityItem(const EntityItemID& entityItemID, - const EntityItemProperties& properties) : - ModelEntityItem(entityItemID, properties), - _dimensionsInitialized(properties.getDimensionsInitialized()) -{ + +RenderableModelEntityItem::RenderableModelEntityItem(const EntityItemID& entityItemID, bool dimensionsInitialized) : + ModelEntityItem(entityItemID), + _dimensionsInitialized(dimensionsInitialized) { } RenderableModelEntityItem::~RenderableModelEntityItem() { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 4dc1cced48..77c7f71ae9 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -25,7 +25,7 @@ class RenderableModelEntityItem : public ModelEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - RenderableModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + RenderableModelEntityItem(const EntityItemID& entityItemID, bool dimensionsInitialized); virtual ~RenderableModelEntityItem(); diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index a0bb582d58..0ce6b49a5c 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -117,13 +117,15 @@ namespace render { gpu::PipelinePointer RenderableParticleEffectEntityItem::_texturedPipeline; gpu::PipelinePointer RenderableParticleEffectEntityItem::_untexturedPipeline; -EntityItemPointer RenderableParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); +EntityItemPointer RenderableParticleEffectEntityItem::factory(const EntityItemID& entityID, + const EntityItemProperties& properties) { + EntityItemPointer entity{ new RenderableParticleEffectEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } -RenderableParticleEffectEntityItem::RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - ParticleEffectEntityItem(entityItemID, properties) { - +RenderableParticleEffectEntityItem::RenderableParticleEffectEntityItem(const EntityItemID& entityItemID) : + ParticleEffectEntityItem(entityItemID) { // lazy creation of particle system pipeline if (!_untexturedPipeline && !_texturedPipeline) { createPipelines(); diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h index 5d69d19026..5ff6c3ff92 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h @@ -19,7 +19,7 @@ class RenderableParticleEffectEntityItem : public ParticleEffectEntityItem { friend class ParticlePayload; public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + RenderableParticleEffectEntityItem(const EntityItemID& entityItemID); virtual void update(const quint64& now) override; diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index 572b24e99f..c5f5e9d55a 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -23,15 +23,15 @@ #include "paintStroke_frag.h" - EntityItemPointer RenderablePolyLineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return EntityItemPointer(new RenderablePolyLineEntityItem(entityID, properties)); + EntityItemPointer entity{ new RenderablePolyLineEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } -RenderablePolyLineEntityItem::RenderablePolyLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : -PolyLineEntityItem(entityItemID, properties) { +RenderablePolyLineEntityItem::RenderablePolyLineEntityItem(const EntityItemID& entityItemID) : + PolyLineEntityItem(entityItemID) { _numVertices = 0; - } gpu::PipelinePointer RenderablePolyLineEntityItem::_pipeline; diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h index 59bf416d7a..f803e4c520 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h @@ -25,7 +25,7 @@ class RenderablePolyLineEntityItem : public PolyLineEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); static void createPipeline(); - RenderablePolyLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + RenderablePolyLineEntityItem(const EntityItemID& entityItemID); virtual void render(RenderArgs* args); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 3ce3717dfb..d9f1832339 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -49,12 +49,13 @@ gpu::PipelinePointer RenderablePolyVoxEntityItem::_pipeline = nullptr; const float MARCHING_CUBE_COLLISION_HULL_OFFSET = 0.5; EntityItemPointer RenderablePolyVoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity{ new RenderablePolyVoxEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } -RenderablePolyVoxEntityItem::RenderablePolyVoxEntityItem(const EntityItemID& entityItemID, - const EntityItemProperties& properties) : - PolyVoxEntityItem(entityItemID, properties), +RenderablePolyVoxEntityItem::RenderablePolyVoxEntityItem(const EntityItemID& entityItemID) : + PolyVoxEntityItem(entityItemID), _mesh(new model::Mesh()), _meshDirty(true), _xTexture(nullptr), diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index ef44ba5ab0..4068b09e13 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -45,8 +45,7 @@ namespace render { class RenderablePolyVoxEntityItem : public PolyVoxEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - - RenderablePolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + RenderablePolyVoxEntityItem(const EntityItemID& entityItemID); virtual ~RenderablePolyVoxEntityItem(); diff --git a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp index 246cd2fea7..705a9a4d26 100644 --- a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp @@ -30,7 +30,9 @@ static const float SPHERE_ENTITY_SCALE = 0.5f; EntityItemPointer RenderableSphereEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity{ new RenderableSphereEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } void RenderableSphereEntityItem::setUserData(const QString& value) { diff --git a/libraries/entities-renderer/src/RenderableSphereEntityItem.h b/libraries/entities-renderer/src/RenderableSphereEntityItem.h index 293ae79029..737bee3134 100644 --- a/libraries/entities-renderer/src/RenderableSphereEntityItem.h +++ b/libraries/entities-renderer/src/RenderableSphereEntityItem.h @@ -20,10 +20,7 @@ class RenderableSphereEntityItem : public SphereEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - - RenderableSphereEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - SphereEntityItem(entityItemID, properties) - { } + RenderableSphereEntityItem(const EntityItemID& entityItemID) : SphereEntityItem(entityItemID) { } virtual void render(RenderArgs* args); virtual void setUserData(const QString& value); diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index d87f89ba41..bdf3b5b97c 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -22,7 +22,9 @@ #include "GLMHelpers.h" EntityItemPointer RenderableTextEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity{ new RenderableTextEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } void RenderableTextEntityItem::render(RenderArgs* args) { diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.h b/libraries/entities-renderer/src/RenderableTextEntityItem.h index de1d745875..149df946f7 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.h +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.h @@ -22,10 +22,7 @@ const int FIXED_FONT_POINT_SIZE = 40; class RenderableTextEntityItem : public TextEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - - RenderableTextEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - TextEntityItem(entityItemID, properties) - { } + RenderableTextEntityItem(const EntityItemID& entityItemID) : TextEntityItem(entityItemID) { } ~RenderableTextEntityItem() { delete _textRenderer; } virtual void render(RenderArgs* args); diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 84707aca3b..943de1aa76 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -31,11 +31,13 @@ const float DPI = 30.47f; const float METERS_TO_INCHES = 39.3701f; EntityItemPointer RenderableWebEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity{ new RenderableWebEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } -RenderableWebEntityItem::RenderableWebEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - WebEntityItem(entityItemID, properties) { +RenderableWebEntityItem::RenderableWebEntityItem(const EntityItemID& entityItemID) : + WebEntityItem(entityItemID) { qDebug() << "Created web entity " << getID(); } diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.h b/libraries/entities-renderer/src/RenderableWebEntityItem.h index 63418a890f..2266401b5d 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.h +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.h @@ -22,8 +22,7 @@ class QObject; class RenderableWebEntityItem : public WebEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - - RenderableWebEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + RenderableWebEntityItem(const EntityItemID& entityItemID); ~RenderableWebEntityItem(); virtual void render(RenderArgs* args); diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index ff56bef46b..7dfefb9097 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -24,7 +24,9 @@ static const float SPHERE_ENTITY_SCALE = 0.5f; EntityItemPointer RenderableZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity{ new RenderableZoneEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } template diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h index 92de136df6..36555dbc45 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.h +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h @@ -21,10 +21,10 @@ class RenderableZoneEntityItem : public ZoneEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - RenderableZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - ZoneEntityItem(entityItemID, properties), - _model(NULL), - _needsInitialSimulation(true) + RenderableZoneEntityItem(const EntityItemID& entityItemID) : + ZoneEntityItem(entityItemID), + _model(NULL), + _needsInitialSimulation(true) { } virtual bool setProperties(const EntityItemProperties& properties); diff --git a/libraries/entities/src/BoxEntityItem.cpp b/libraries/entities/src/BoxEntityItem.cpp index 70d5ba0c4f..061c5b3854 100644 --- a/libraries/entities/src/BoxEntityItem.cpp +++ b/libraries/entities/src/BoxEntityItem.cpp @@ -21,15 +21,13 @@ #include "EntityTreeElement.h" EntityItemPointer BoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - EntityItemPointer result { new BoxEntityItem(entityID, properties) }; - return result; + EntityItemPointer entity { new BoxEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } -BoxEntityItem::BoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID) -{ +BoxEntityItem::BoxEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { _type = EntityTypes::Box; - setProperties(properties); } EntityItemProperties BoxEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { diff --git a/libraries/entities/src/BoxEntityItem.h b/libraries/entities/src/BoxEntityItem.h index 6c1b5b2312..351feb7e54 100644 --- a/libraries/entities/src/BoxEntityItem.h +++ b/libraries/entities/src/BoxEntityItem.h @@ -18,7 +18,7 @@ class BoxEntityItem : public EntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - BoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + BoxEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index fd4a4b298c..7c9f3139df 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -85,7 +85,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : quint64 now = usecTimestampNow(); _lastSimulated = now; _lastUpdated = now; - _constructing = false; } EntityItem::~EntityItem() { diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index fd3f674c5e..ac56fc9c1f 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -24,23 +24,20 @@ bool LightEntityItem::_lightsArePickable = false; EntityItemPointer LightEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - EntityItemPointer result { new LightEntityItem(entityID, properties) }; - return result; + EntityItemPointer entity { new LightEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } // our non-pure virtual subclass for now... -LightEntityItem::LightEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID) -{ +LightEntityItem::LightEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { _type = EntityTypes::Light; - + // default property values _color[RED_INDEX] = _color[GREEN_INDEX] = _color[BLUE_INDEX] = 0; _intensity = 1.0f; _exponent = 0.0f; _cutoff = PI; - - setProperties(properties); } void LightEntityItem::setDimensions(const glm::vec3& value) { diff --git a/libraries/entities/src/LightEntityItem.h b/libraries/entities/src/LightEntityItem.h index 9f8d340852..103c462809 100644 --- a/libraries/entities/src/LightEntityItem.h +++ b/libraries/entities/src/LightEntityItem.h @@ -18,7 +18,7 @@ class LightEntityItem : public EntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - LightEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + LightEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated diff --git a/libraries/entities/src/LineEntityItem.cpp b/libraries/entities/src/LineEntityItem.cpp index e03d3a7a96..d48780845f 100644 --- a/libraries/entities/src/LineEntityItem.cpp +++ b/libraries/entities/src/LineEntityItem.cpp @@ -26,20 +26,18 @@ const int LineEntityItem::MAX_POINTS_PER_LINE = 70; EntityItemPointer LineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - EntityItemPointer result { new LineEntityItem(entityID, properties) }; - return result; + EntityItemPointer entity { new LineEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } -LineEntityItem::LineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID) , +LineEntityItem::LineEntityItem(const EntityItemID& entityItemID) : + EntityItem(entityItemID), _lineWidth(DEFAULT_LINE_WIDTH), _pointsChanged(true), _points(QVector(0)) { _type = EntityTypes::Line; - setProperties(properties); - - } EntityItemProperties LineEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { diff --git a/libraries/entities/src/LineEntityItem.h b/libraries/entities/src/LineEntityItem.h index b20587637f..4d63562cf7 100644 --- a/libraries/entities/src/LineEntityItem.h +++ b/libraries/entities/src/LineEntityItem.h @@ -18,7 +18,7 @@ class LineEntityItem : public EntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - LineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + LineEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index b4adde7467..eefe873b74 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -25,17 +25,17 @@ const QString ModelEntityItem::DEFAULT_MODEL_URL = QString(""); const QString ModelEntityItem::DEFAULT_COMPOUND_SHAPE_URL = QString(""); EntityItemPointer ModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity { new ModelEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } -ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID) +ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { _animationProperties.associateWithAnimationLoop(&_animationLoop); _animationLoop.setResetOnRunning(false); _type = EntityTypes::Model; - setProperties(properties); _jointMappingCompleted = false; _lastKnownCurrentFrame = -1; _color[0] = _color[1] = _color[2] = 0; diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index e8ffcab3e7..8a49759921 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -21,7 +21,7 @@ class ModelEntityItem : public EntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - ModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + ModelEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index ddd79375b3..1cd53c87f4 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -97,11 +97,13 @@ const QString ParticleEffectEntityItem::DEFAULT_TEXTURES = ""; EntityItemPointer ParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity { new ParticleEffectEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } // our non-pure virtual subclass for now... -ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : +ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID), _lastSimulated(usecTimestampNow()), _particleLifetimes(DEFAULT_MAX_PARTICLES, 0.0f), @@ -121,12 +123,9 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte _alphaMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), _alphaFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), _particleMaxBound(glm::vec3(1.0f, 1.0f, 1.0f)), - _particleMinBound(glm::vec3(-1.0f, -1.0f, -1.0f)) -{ - + _particleMinBound(glm::vec3(-1.0f, -1.0f, -1.0f)) { _type = EntityTypes::ParticleEffect; setColor(DEFAULT_COLOR); - setProperties(properties); } ParticleEffectEntityItem::~ParticleEffectEntityItem() { diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 029d65cfc0..be2204a321 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -20,7 +20,7 @@ public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - ParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + ParticleEffectEntityItem(const EntityItemID& entityItemID); virtual ~ParticleEffectEntityItem(); ALLOW_INSTANTIATION // This class can be instantiated diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index f1be431ce8..82ee0e1269 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -26,22 +26,21 @@ const int PolyLineEntityItem::MAX_POINTS_PER_LINE = 70; EntityItemPointer PolyLineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - EntityItemPointer result{ new PolyLineEntityItem(entityID, properties) }; - return result; + EntityItemPointer entity{ new PolyLineEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } -PolyLineEntityItem::PolyLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : -EntityItem(entityItemID), -_lineWidth(DEFAULT_LINE_WIDTH), -_pointsChanged(true), -_points(QVector(0.0f)), -_vertices(QVector(0.0f)), -_normals(QVector(0.0f)), -_strokeWidths(QVector(0.0f)) +PolyLineEntityItem::PolyLineEntityItem(const EntityItemID& entityItemID) : + EntityItem(entityItemID), + _lineWidth(DEFAULT_LINE_WIDTH), + _pointsChanged(true), + _points(QVector(0.0f)), + _vertices(QVector(0.0f)), + _normals(QVector(0.0f)), + _strokeWidths(QVector(0.0f)) { _type = EntityTypes::PolyLine; - _created = properties.getCreated(); - setProperties(properties); } EntityItemProperties PolyLineEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h index 86a1dfb6e0..9608bd9b44 100644 --- a/libraries/entities/src/PolyLineEntityItem.h +++ b/libraries/entities/src/PolyLineEntityItem.h @@ -18,7 +18,7 @@ class PolyLineEntityItem : public EntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - PolyLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + PolyLineEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp index 403d0bb1bc..9b85938a78 100644 --- a/libraries/entities/src/PolyVoxEntityItem.cpp +++ b/libraries/entities/src/PolyVoxEntityItem.cpp @@ -32,7 +32,9 @@ const QString PolyVoxEntityItem::DEFAULT_Y_TEXTURE_URL = QString(""); const QString PolyVoxEntityItem::DEFAULT_Z_TEXTURE_URL = QString(""); EntityItemPointer PolyVoxEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity { new PolyVoxEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } QByteArray PolyVoxEntityItem::makeEmptyVoxelData(quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize) { @@ -49,7 +51,7 @@ QByteArray PolyVoxEntityItem::makeEmptyVoxelData(quint16 voxelXSize, quint16 vox return newVoxelData; } -PolyVoxEntityItem::PolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : +PolyVoxEntityItem::PolyVoxEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID), _voxelVolumeSize(PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE), _voxelData(PolyVoxEntityItem::DEFAULT_VOXEL_DATA), @@ -59,7 +61,6 @@ PolyVoxEntityItem::PolyVoxEntityItem(const EntityItemID& entityItemID, const Ent _yTextureURL(PolyVoxEntityItem::DEFAULT_Y_TEXTURE_URL), _zTextureURL(PolyVoxEntityItem::DEFAULT_Z_TEXTURE_URL) { _type = EntityTypes::PolyVox; - setProperties(properties); } void PolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) { diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 9070ad250f..13e541d298 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -18,7 +18,7 @@ class PolyVoxEntityItem : public EntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - PolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + PolyVoxEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated diff --git a/libraries/entities/src/SphereEntityItem.cpp b/libraries/entities/src/SphereEntityItem.cpp index 26177f89de..841b70aa56 100644 --- a/libraries/entities/src/SphereEntityItem.cpp +++ b/libraries/entities/src/SphereEntityItem.cpp @@ -24,16 +24,14 @@ #include "SphereEntityItem.h" EntityItemPointer SphereEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - EntityItemPointer result { new SphereEntityItem(entityID, properties) }; - return result; + EntityItemPointer entity { new SphereEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } // our non-pure virtual subclass for now... -SphereEntityItem::SphereEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID) -{ +SphereEntityItem::SphereEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { _type = EntityTypes::Sphere; - setProperties(properties); _volumeMultiplier *= PI / 6.0f; } diff --git a/libraries/entities/src/SphereEntityItem.h b/libraries/entities/src/SphereEntityItem.h index e1e31d4839..941d5a167c 100644 --- a/libraries/entities/src/SphereEntityItem.h +++ b/libraries/entities/src/SphereEntityItem.h @@ -18,7 +18,7 @@ class SphereEntityItem : public EntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - SphereEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + SphereEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index 49d3c13d80..893329d1ce 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -30,14 +30,13 @@ const xColor TextEntityItem::DEFAULT_BACKGROUND_COLOR = { 0, 0, 0}; const bool TextEntityItem::DEFAULT_FACE_CAMERA = false; EntityItemPointer TextEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity { new TextEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } -TextEntityItem::TextEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID) -{ +TextEntityItem::TextEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { _type = EntityTypes::Text; - setProperties(properties); } const float TEXT_ENTITY_ITEM_FIXED_DEPTH = 0.01f; diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index d205e9d01e..1caceee085 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -18,7 +18,7 @@ class TextEntityItem : public EntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - TextEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + TextEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp index 56f8357c8f..5f113f1de4 100644 --- a/libraries/entities/src/WebEntityItem.cpp +++ b/libraries/entities/src/WebEntityItem.cpp @@ -23,14 +23,13 @@ const QString WebEntityItem::DEFAULT_SOURCE_URL("http://www.google.com"); EntityItemPointer WebEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity { new WebEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } -WebEntityItem::WebEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID) -{ +WebEntityItem::WebEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { _type = EntityTypes::Web; - setProperties(properties); } const float WEB_ENTITY_ITEM_FIXED_DEPTH = 0.01f; diff --git a/libraries/entities/src/WebEntityItem.h b/libraries/entities/src/WebEntityItem.h index 425d89de76..8e9d924cde 100644 --- a/libraries/entities/src/WebEntityItem.h +++ b/libraries/entities/src/WebEntityItem.h @@ -17,7 +17,7 @@ public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - WebEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + WebEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index 3147af35e8..bc74c47e54 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -31,12 +31,12 @@ const ShapeType ZoneEntityItem::DEFAULT_SHAPE_TYPE = SHAPE_TYPE_BOX; const QString ZoneEntityItem::DEFAULT_COMPOUND_SHAPE_URL = ""; EntityItemPointer ZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - return std::make_shared(entityID, properties); + EntityItemPointer entity { new ZoneEntityItem(entityID) }; + entity->setProperties(properties); + return entity; } -ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID) -{ +ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { _type = EntityTypes::Zone; _keyLightColor[RED_INDEX] = DEFAULT_KEYLIGHT_COLOR.red; @@ -50,8 +50,6 @@ ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID, const EntityIte _compoundShapeURL = DEFAULT_COMPOUND_SHAPE_URL; _backgroundMode = BACKGROUND_MODE_INHERIT; - - setProperties(properties); } diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index e7f2e03981..8a1f8022fc 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -24,7 +24,7 @@ class ZoneEntityItem : public EntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - ZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); + ZoneEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 9d1220c214..a813a37bfe 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -32,11 +32,6 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { return nullptr; } - if (_constructing) { - // we can't use shared_from_this yet, so stop here. - return nullptr; - } - SpatiallyNestableConstPointer constThisPointer = shared_from_this(); SpatiallyNestablePointer thisPointer = std::const_pointer_cast(constThisPointer); // ermahgerd !!! diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 108da796a0..e0ee5bdb74 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -82,8 +82,6 @@ public: NestableTypes::NestableType getNestableType() const { return _nestableType; } protected: - bool _constructing = true; - NestableTypes::NestableType _nestableType; // EntityItem or an AvatarData QUuid _id; QUuid _parentID; // what is this thing's transform relative to? From 4e33aa84e873d0dd16d3ad602ba34ea16d851c97 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 22 Oct 2015 12:03:19 -0700 Subject: [PATCH 033/401] Make handler generators more readable --- libraries/script-engine/src/ScriptEngine.cpp | 47 +++++++++----------- libraries/script-engine/src/ScriptEngine.h | 2 +- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 76590f266b..a317f2a82c 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -508,26 +508,29 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& // Connect up ALL the handlers to the global entities object's signals. // (We could go signal by signal, or even handler by handler, but I don't think the efficiency is worth the complexity.) auto entities = DependencyManager::get(); - connect(entities.data(), &EntityScriptingInterface::deletingEntity, this, - [=](const EntityItemID& entityID) { - _registeredHandlers.remove(entityID); - }); - + connect(entities.data(), &EntityScriptingInterface::deletingEntity, this, [this](const EntityItemID& entityID) { + _registeredHandlers.remove(entityID); + }); + // Two common cases of event handler, differing only in argument signature. - auto makeSingleEntityHandler = [=](const QString& eventName) -> std::function { - return [=](const EntityItemID& entityItemID) -> void { - generalHandler(entityItemID, eventName, [=]() -> QScriptValueList { - return QScriptValueList() << entityItemID.toScriptValue(this); - }); + auto makeSingleEntityHandler = [&](QString eventName) { + return [this, eventName](const EntityItemID& entityItemID) { + forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this) }); }; }; - auto makeMouseHandler = [=](const QString& eventName) -> std::function { - return [=](const EntityItemID& entityItemID, const MouseEvent& event) -> void { - generalHandler(entityItemID, eventName, [=]() -> QScriptValueList { - return QScriptValueList() << entityItemID.toScriptValue(this) << event.toScriptValue(this); - }); + auto makeMouseHandler = [&](QString eventName) { + return [this, eventName](const EntityItemID& entityItemID, const MouseEvent& event) { + forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this), event.toScriptValue(this) }); }; }; + + auto makeCollisionHandler = [&](QString eventName) { + return [this, eventName](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { + forwardHandlerCall(idA, eventName, { idA.toScriptValue(this), idB.toScriptValue(this), + collisionToScriptValue(this, collision) }); + }; + }; + connect(entities.data(), &EntityScriptingInterface::enterEntity, this, makeSingleEntityHandler("enterEntity")); connect(entities.data(), &EntityScriptingInterface::leaveEntity, this, makeSingleEntityHandler("leaveEntity")); @@ -543,12 +546,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& connect(entities.data(), &EntityScriptingInterface::hoverOverEntity, this, makeMouseHandler("hoverOverEntity")); connect(entities.data(), &EntityScriptingInterface::hoverLeaveEntity, this, makeMouseHandler("hoverLeaveEntity")); - connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, - [=](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { - generalHandler(idA, "collisionWithEntity", [=]() { - return QScriptValueList () << idA.toScriptValue(this) << idB.toScriptValue(this) << collisionToScriptValue(this, collision); - }); - }); + connect(entities.data(), &EntityScriptingInterface::collisionWithEntity, this, makeCollisionHandler("collisionWithEntity")); } if (!_registeredHandlers.contains(entityID)) { _registeredHandlers[entityID] = RegisteredEventHandlers(); @@ -899,9 +897,9 @@ void ScriptEngine::load(const QString& loadFile) { } // Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args -void ScriptEngine::generalHandler(const EntityItemID& entityID, const QString& eventName, std::function argGenerator) { +void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHanderArgs) { if (QThread::currentThread() != thread()) { - qDebug() << "*** ERROR *** ScriptEngine::generalHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; + qDebug() << "*** ERROR *** ScriptEngine::forwardHandlerCall() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "]"; assert(false); return; } @@ -915,9 +913,8 @@ void ScriptEngine::generalHandler(const EntityItemID& entityID, const QString& e } QScriptValueList handlersForEvent = handlersOnEntity[eventName]; if (!handlersForEvent.isEmpty()) { - QScriptValueList args = argGenerator(); for (int i = 0; i < handlersForEvent.count(); ++i) { - handlersForEvent[i].call(QScriptValue(), args); + handlersForEvent[i].call(QScriptValue(), eventHanderArgs); } } } diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 1d3986143a..c2f9d966f1 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -193,7 +193,7 @@ private: ArrayBufferClass* _arrayBufferClass; QHash _registeredHandlers; - void generalHandler(const EntityItemID& entityID, const QString& eventName, std::function argGenerator); + void forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHanderArgs); Q_INVOKABLE void entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success); static QSet _allKnownScriptEngines; From 421d967e492971bb6414604e77817044ce5528ab Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 23 Oct 2015 15:40:56 -0700 Subject: [PATCH 034/401] Improve script engine error logging + some cleanup --- libraries/script-engine/src/ScriptEngine.cpp | 74 ++++++++++++++------ libraries/script-engine/src/ScriptEngine.h | 5 +- libraries/shared/src/LogHandler.cpp | 2 +- 3 files changed, 56 insertions(+), 25 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index a317f2a82c..cbe9449551 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -556,7 +556,7 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& } -QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileName, int lineNumber) { +QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fileName, int lineNumber) { if (_stoppingAllScripts) { return QScriptValue(); // bail early } @@ -565,27 +565,30 @@ QScriptValue ScriptEngine::evaluate(const QString& program, const QString& fileN QScriptValue result; #ifdef THREAD_DEBUGGING qDebug() << "*** WARNING *** ScriptEngine::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - "program:" << program << " fileName:" << fileName << "lineNumber:" << lineNumber; + "sourceCode:" << sourceCode << " fileName:" << fileName << "lineNumber:" << lineNumber; #endif QMetaObject::invokeMethod(this, "evaluate", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QScriptValue, result), - Q_ARG(const QString&, program), + Q_ARG(const QString&, sourceCode), Q_ARG(const QString&, fileName), Q_ARG(int, lineNumber)); return result; } + + // Check synthax + const QScriptProgram program(sourceCode, fileName, lineNumber); + if (!checkSynthax(program)) { + return QScriptValue(); + } - _evaluatesPending++; - QScriptValue result = QScriptEngine::evaluate(program, fileName, lineNumber); - if (hasUncaughtException()) { - int line = uncaughtExceptionLineNumber(); - qCDebug(scriptengine) << "Uncaught exception at (" << _fileNameString << " : " << fileName << ") line" << line << ": " << result.toString(); - } - _evaluatesPending--; + ++_evaluatesPending; + const auto result = QScriptEngine::evaluate(program); + --_evaluatesPending; + + const auto hadUncaughtException = checkExceptions(this, program.fileName()); if (_wantSignals) { - emit evaluationFinished(result, hasUncaughtException()); + emit evaluationFinished(result, hadUncaughtException); } - clearExceptions(); return result; } @@ -603,7 +606,7 @@ void ScriptEngine::run() { emit runningStateChanged(); } - QScriptValue result = evaluate(_scriptContents); + QScriptValue result = evaluate(_scriptContents, _fileNameString); QElapsedTimer startTime; startTime.start(); @@ -644,15 +647,6 @@ void ScriptEngine::run() { qint64 now = usecTimestampNow(); float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND; - if (hasUncaughtException()) { - int line = uncaughtExceptionLineNumber(); - qCDebug(scriptengine) << "Uncaught exception at (" << _fileNameString << ") line" << line << ":" << uncaughtException().toString(); - if (_wantSignals) { - emit errorMessage("Uncaught exception at (" + _fileNameString + ") line" + QString::number(line) + ":" + uncaughtException().toString()); - } - clearExceptions(); - } - if (!_isFinished) { if (_wantSignals) { emit update(deltaTime); @@ -660,6 +654,7 @@ void ScriptEngine::run() { } lastUpdate = now; + checkExceptions(this, _fileNameString); } stopAllTimers(); // make sure all our timers are stopped if the script is ending @@ -896,6 +891,38 @@ void ScriptEngine::load(const QString& loadFile) { } } + +bool ScriptEngine::checkSynthax(const QScriptProgram& program) { + const auto syntaxCheck = QScriptEngine::checkSyntax(program.sourceCode()); + if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) { + const auto error = syntaxCheck.errorMessage(); + const auto line = QString::number(syntaxCheck.errorLineNumber()); + const auto column = QString::number(syntaxCheck.errorColumnNumber()); + const auto message = QString("[SyntaxError] %1 in %2:%3(%4)").arg(error, program.fileName(), line, column); + qCWarning(scriptengine) << qPrintable(message); + return false; + } + return true; +} + +bool ScriptEngine::checkExceptions(QScriptEngine* engine, const QString& fileName) { + if (engine->hasUncaughtException()) { + const auto backtrace = engine->uncaughtExceptionBacktrace(); + const auto exception = engine->uncaughtException().toString(); + const auto line = QString::number(engine->uncaughtExceptionLineNumber()); + engine->clearExceptions(); + + auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line); + if (!backtrace.empty()) { + static const auto lineSeparator = "\n "; + message += QString("\n[Backtrace]%1%2").arg(lineSeparator, backtrace.join(lineSeparator)); + } + qCWarning(scriptengine) << qPrintable(message); + return false; + } + return true; +} + // Look up the handler associated with eventName and entityID. If found, evalute the argGenerator thunk and call the handler with those args void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QString& eventName, QScriptValueList eventHanderArgs) { if (QThread::currentThread() != thread()) { @@ -1015,7 +1042,8 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co lastModified = (quint64)QFileInfo(file).lastModified().toMSecsSinceEpoch(); } - QScriptValue entityScriptConstructor = evaluate(contents); + auto fileName = QString("(EntityID:%1, %2)").arg(entityID.toString(), isURL ? scriptOrURL : "EmbededEntityScript"); + QScriptValue entityScriptConstructor = evaluate(contents, fileName); QScriptValue entityScriptObject = entityScriptConstructor.construct(); EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject, lastModified }; _entityScripts[entityID] = newDetails; diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index c2f9d966f1..8fda876a31 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -88,7 +88,7 @@ public: Q_INVOKABLE void registerValue(const QString& valueName, QScriptValue value); /// evaluate some code in the context of the ScriptEngine and return the result - Q_INVOKABLE QScriptValue evaluate(const QString& program, const QString& fileName = QString(), int lineNumber = 1); // this is also used by the script tool widget + Q_INVOKABLE QScriptValue evaluate(const QString& program, const QString& fileName, int lineNumber = 1); // this is also used by the script tool widget /// if the script engine is not already running, this will download the URL and start the process of seting it up /// to run... NOTE - this is used by Application currently to load the url. We don't really want it to be exposed @@ -182,6 +182,9 @@ private: QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot); void stopTimer(QTimer* timer); + static bool checkSynthax(const QScriptProgram& program); + static bool checkExceptions(QScriptEngine* engine, const QString& fileName); + AbstractControllerScriptingInterface* _controllerScriptingInterface; QString _fileNameString; Quat _quatLibrary; diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index 22ea12c1b3..cc3519e43e 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -135,7 +135,7 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont prefixString.append(QString(" [%1]").arg(_targetName)); } - QString logMessage = QString("%1 %2").arg(prefixString, message); + QString logMessage = QString("%1 %2").arg(prefixString, message.split("\n").join("\n" + prefixString + " ")); fprintf(stdout, "%s\n", qPrintable(logMessage)); return logMessage; } From c1cd7dd50a14723a580039ed1c2f3f0d91855273 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 23 Oct 2015 16:31:38 -0700 Subject: [PATCH 035/401] Work on robot animation and bat hull --- examples/toys/baseball.js | 132 ++++++++++++++++++++++++++------------ 1 file changed, 90 insertions(+), 42 deletions(-) diff --git a/examples/toys/baseball.js b/examples/toys/baseball.js index f3f26a1f4b..f356e35fdf 100755 --- a/examples/toys/baseball.js +++ b/examples/toys/baseball.js @@ -9,11 +9,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var ROBOT_MODEL = "atp:ea02100c2ee63a8b9c0495557f32041be18ec94def157592e84a816665ce2f6e.fbx"; -var ROBOT_POSITION = { x: -0.54, y: 1.21, z: 2.57 } +var ROBOT_MODEL = "atp:785c81e117206c36205404beec0cc68529644fe377542dbb2d13fae4d665a5de.fbx"; +var ROBOT_POSITION = { x: -0.81, y: 0.88, z: 2.12 }; +var ROBOT_DIMENSIONS = { x: 0.95, y: 1.76, z: 0.56 }; var BAT_MODEL = "atp:07bdd769a57ff15ebe9331ae4e2c2eae8886a6792b4790cce03b4716eb3a81c7.fbx" var BAT_COLLISION_MODEL = "atp:1211ee12bc8ab0bb744e8582e15e728a00ca70a808550fc46d7284799b9a868a.obj" +var BAT_DIMENSIONS = { x: 1.35, y: 0.10, z: 0.10 }; +var BAT_REGISTRATION_POINT = { x: 0.1, y: 0.5, z: 0.5 }; // add the fresh robot at home plate var robot = Entities.addEntity({ @@ -21,72 +24,117 @@ var robot = Entities.addEntity({ type: 'Model', modelURL: ROBOT_MODEL, position: ROBOT_POSITION, +// dimensions: ROBOT_DIMENSIONS,a + animationIsPlaying: true, animation: { - url: ROBOT_MODEL + url: ROBOT_MODEL, + fps: 30 } }); // add the bat var bat = Entities.addEntity({ - name: 'Bat', - type: 'Model', - modelURL: BAT_MODEL + name: 'Bat', + /*/ + type: 'Box', + /*/ + type: 'Model', + modelURL: BAT_COLLISION_MODEL, + /**/ + collisionModelURL: BAT_COLLISION_MODEL, +// dimensions: BAT_DIMENSIONS, + registrationPoint: BAT_REGISTRATION_POINT, + visible: false }) var lastTriggerValue = 0.0; function checkTriggers() { - var rightTrigger = Controller.getTriggerValue(1); + var rightTrigger = Controller.getTriggerValue(1); - if (rightTrigger == 0) { - if (lastTriggerValue > 0) { - // the trigger was just released, play out to the last frame of the swing - Entities.editEntity(robot, { - animation: { - running: true, - currentFrame: 21, - lastFrame: 115 + if (rightTrigger == 0) { + if (lastTriggerValue > 0) { + // the trigger was just released, play out to the last frame of the swing + Entities.editEntity(robot, { + animation: { + running: true, + currentFrame: 21, + lastFrame: 115 + } + }); } - }); - } - } else { - if (lastTriggerValue == 0) { - // the trigger was just depressed, start the swing - Entities.editEntity(robot, { - animation: { - running: true, - currentFrame: 0, - lastFrame: 21 + } else { + if (lastTriggerValue == 0) { + // the trigger was just depressed, start the swing + Entities.editEntity(robot, { + animation: { + running: true, + currentFrame: 0, + lastFrame: 21 + } + }); } - }); } - } - lastTriggerValue = rightTrigger; + lastTriggerValue = rightTrigger; } var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position var ACTION_LIFETIME = 15; // seconds +var action = null; +var factor = 0.0; +var STEP = 0.05; function moveBat() { - var forearmPosition = Entities.getJointPosition(robot, 40); - var forearmRotation = Entities.getJointRotation(robot, 40); - - Vec3.print("forearmPosition=", forearmPosition); - - Entities.addAction("spring", bat, { - targetPosition: forearmPosition, - targetRotation: forearmRotation, - tag: "bat-to-forearm", - linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, - angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME - lifetime: ACTION_LIFETIME - }); + var JOINT_INDEX = 19; + + var forearmPosition = Entities.getJointPosition(robot, JOINT_INDEX); + var forearmRotation = Entities.getJointRotation(robot, JOINT_INDEX); + + /*/ + var properties = Entities.getEntityProperties(bat, ["position", "rotation"]); + var offsetPosition = Vec3.subtract(properties.position, forearmPosition); + var offsetRotation = Quat.multiply(Quat.inverse(forearmRotation), properties.rotation); + print("offsetPosition = " + JSON.stringify(offsetPosition)); + print("offsetRotation = " + JSON.stringify(Quat.safeEulerAngles(offsetRotation))); + /*/ + Entities.editEntity(bat, { + position: forearmPosition, + rotation: forearmRotation, + }); + /**/ + +// var actionProperties = { +// relativePosition: forearmPosition, +// relativeRotation: forearmRotation, +//// tag: "bat-to-forearm", +//// linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, +//// angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, +//// lifetime: ACTION_LIFETIME +// hand: "left", +// timeScale: 0.15 +// }; +// +// if (action === null) { +// Entities.addAction("hold", bat, actionProperties); +// } else { +// Entities.editAction(bat, action, actionProperties); +// } } function update() { - checkTriggers(); +// checkTriggers(); + moveBat(); +} + +function scriptEnding() { + Entities.deleteEntity(robot); + Entities.deleteEntity(bat); + if (action) { + Entities.deleteAction(bat, action); + } } // hook the update so we can check controller triggers Script.update.connect(update); +Script.scriptEnding.connect(scriptEnding); From 7487c7bd0a8bddbec0b4dad38ebd22e78afc2d8d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 23 Oct 2015 16:32:27 -0700 Subject: [PATCH 036/401] Move baseball.js --- examples/{toys => baseball}/baseball.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{toys => baseball}/baseball.js (100%) diff --git a/examples/toys/baseball.js b/examples/baseball/baseball.js similarity index 100% rename from examples/toys/baseball.js rename to examples/baseball/baseball.js From 667eec2f46dca9cc3990554dfad55d78aa46fac3 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 23 Oct 2015 16:43:59 -0700 Subject: [PATCH 037/401] change collision hull --- examples/baseball/baseball.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/baseball.js b/examples/baseball/baseball.js index f356e35fdf..504d067885 100755 --- a/examples/baseball/baseball.js +++ b/examples/baseball/baseball.js @@ -14,7 +14,7 @@ var ROBOT_POSITION = { x: -0.81, y: 0.88, z: 2.12 }; var ROBOT_DIMENSIONS = { x: 0.95, y: 1.76, z: 0.56 }; var BAT_MODEL = "atp:07bdd769a57ff15ebe9331ae4e2c2eae8886a6792b4790cce03b4716eb3a81c7.fbx" -var BAT_COLLISION_MODEL = "atp:1211ee12bc8ab0bb744e8582e15e728a00ca70a808550fc46d7284799b9a868a.obj" +var BAT_COLLISION_MODEL = "atp:atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj" var BAT_DIMENSIONS = { x: 1.35, y: 0.10, z: 0.10 }; var BAT_REGISTRATION_POINT = { x: 0.1, y: 0.5, z: 0.5 }; From f3c61a823e1064d7bfec23f6f56a3605875fb617 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 23 Oct 2015 16:58:09 -0700 Subject: [PATCH 038/401] try harder to get children flags right when something moves. added worldToLocal methods --- libraries/entities/src/EntityItem.cpp | 99 ++++++++++++++------- libraries/entities/src/EntityItem.h | 21 ++--- libraries/physics/src/EntityMotionState.cpp | 4 +- libraries/shared/src/SpatiallyNestable.cpp | 31 +++++++ libraries/shared/src/SpatiallyNestable.h | 9 +- 5 files changed, 114 insertions(+), 50 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 7c9f3139df..2dee8a9d44 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -79,8 +79,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _simulated(false) { // explicitly set transform parts to set dirty flags used by batch rendering - setPosition(ENTITY_ITEM_DEFAULT_POSITION); - setRotation(ENTITY_ITEM_DEFAULT_ROTATION); setScale(ENTITY_ITEM_DEFAULT_DIMENSIONS); quint64 now = usecTimestampNow(); _lastSimulated = now; @@ -1309,24 +1307,19 @@ void EntityItem::computeShapeInfo(ShapeInfo& info) { info.setParams(getShapeType(), 0.5f * getDimensions()); } -bool EntityItem::forSelfAndEachChildEntity(std::function actor) { - bool result = true; +void EntityItem::forSelfAndEachChildEntity(std::function actor) { QQueue toProcess; toProcess.enqueue(shared_from_this()); while (!toProcess.empty()) { EntityItemPointer entity = std::static_pointer_cast(toProcess.dequeue()); - - result &= actor(entity); - + actor(entity); foreach (SpatiallyNestablePointer child, entity->getChildren()) { if (child && child->getNestableType() == NestableTypes::Entity) { toProcess.enqueue(child); } } } - - return result; } void EntityItem::updatePosition(const glm::vec3& value) { @@ -1336,16 +1329,76 @@ void EntityItem::updatePosition(const glm::vec3& value) { auto delta = glm::distance(getLocalPosition(), value); if (delta > IGNORE_POSITION_DELTA) { setLocalPosition(value); + if (delta > ACTIVATION_POSITION_DELTA) { + _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; + } forSelfAndEachChildEntity([&](EntityItemPointer entity) { entity->_dirtyFlags |= Simulation::DIRTY_POSITION; - if (delta > ACTIVATION_POSITION_DELTA) { - entity->_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; - } - return true; }); } } +void EntityItem::setTransform(const Transform& transform) { + SpatiallyNestable::setTransform(transform); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + +void EntityItem::setLocalTransform(const Transform& transform) { + SpatiallyNestable::setLocalTransform(transform); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + +void EntityItem::setPosition(const glm::vec3& position) { + SpatiallyNestable::setPosition(position); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + +void EntityItem::setLocalPosition(const glm::vec3& position) { + SpatiallyNestable::setLocalPosition(position); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + +void EntityItem::updateRotation(const glm::quat& rotation) { + if (shouldSuppressLocationEdits()) { + return; + } + if (getRotation() != rotation) { + auto alignmentDot = glm::abs(glm::dot(getRotation(), rotation)); + setRotation(rotation); + if (alignmentDot < ACTIVATION_ALIGNMENT_DOT) { + _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; + } + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + if (alignmentDot < IGNORE_ALIGNMENT_DOT) { + entity->_dirtyFlags |= Simulation::DIRTY_ROTATION; + } + entity->requiresRecalcBoxes(); + }); + } +} + +void EntityItem::setRotation(const glm::quat& orientation) { + SpatiallyNestable::setOrientation(orientation); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + +void EntityItem::setLocalRotation(const glm::quat& orientation) { + SpatiallyNestable::setLocalOrientation(orientation); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + void EntityItem::updateDimensions(const glm::vec3& value) { auto delta = glm::distance(getDimensions(), value); if (delta > IGNORE_DIMENSIONS_DELTA) { @@ -1357,26 +1410,6 @@ void EntityItem::updateDimensions(const glm::vec3& value) { } } -void EntityItem::updateRotation(const glm::quat& rotation) { - if (shouldSuppressLocationEdits()) { - return; - } - if (getRotation() != rotation) { - setRotation(rotation); - - auto alignmentDot = glm::abs(glm::dot(getRotation(), rotation)); - - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - if (alignmentDot < IGNORE_ALIGNMENT_DOT) { - entity->_dirtyFlags |= Simulation::DIRTY_ROTATION; - } - if (alignmentDot < ACTIVATION_ALIGNMENT_DOT) { - entity->_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; - } - return true; - }); - } -} void EntityItem::updateMass(float mass) { // Setting the mass actually changes the _density (at fixed volume), however diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 6e03e52679..ffcf24854d 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -183,15 +183,6 @@ public: const Transform getTransformToCenter() const; void setTranformToCenter(const Transform& transform); - virtual void setTransform(const Transform& transform) { SpatiallyNestable::setTransform(transform); requiresRecalcBoxes(); } - - /// Position in meters (-TREE_SCALE - TREE_SCALE) - virtual const glm::vec3& getPosition() const { return SpatiallyNestable::getPosition(); } - virtual void setPosition(const glm::vec3& value) { SpatiallyNestable::setPosition(value); requiresRecalcBoxes(); } - - virtual const glm::quat& getRotation() const { return SpatiallyNestable::getOrientation(); } - virtual void setRotation(const glm::quat& rotation) { SpatiallyNestable::setOrientation(rotation); requiresRecalcBoxes(); } - inline void requiresRecalcBoxes() { _recalcAABox = true; _recalcMinAACube = true; _recalcMaxAACube = true; } // Hyperlink related getters and setters @@ -330,6 +321,16 @@ public: /// return preferred shape type (actual physical shape may differ) virtual ShapeType getShapeType() const { return SHAPE_TYPE_NONE; } + virtual void setTransform(const Transform& transform); + virtual void setLocalTransform(const Transform& transform); + // virtual const glm::vec3& getPosition() const { return SpatiallyNestable::getPosition(); } + virtual const glm::quat& getRotation() const { return SpatiallyNestable::getOrientation(); } + + virtual void setPosition(const glm::vec3& position); + virtual void setLocalPosition(const glm::vec3& position); + virtual void setRotation(const glm::quat& orientation); + virtual void setLocalRotation(const glm::quat& orientation); + // updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags void updatePosition(const glm::vec3& value); void updateDimensions(const glm::vec3& value); @@ -396,7 +397,7 @@ protected: const QByteArray getActionDataInternal() const; void setActionDataInternal(QByteArray actionData); - bool forSelfAndEachChildEntity(std::function actor); + void forSelfAndEachChildEntity(std::function actor); static bool _sendPhysicsUpdates; EntityTypes::EntityType _type; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 6832b8daff..98d0bb245e 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -445,8 +445,8 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q EntityItemProperties properties; // explicitly set the properties that changed so that they will be packed - properties.setPosition(_serverPosition); - properties.setRotation(_serverRotation); + properties.setPosition(_entity->worldToLocal(_serverPosition)); + properties.setRotation(_entity->worldToLocal(_serverRotation)); properties.setVelocity(_serverVelocity); properties.setAcceleration(_serverAcceleration); properties.setAngularVelocity(_serverAngularVelocity); diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index a813a37bfe..300d9a5728 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -14,6 +14,16 @@ // TODO -- make use of parent joint index + +SpatiallyNestable::SpatiallyNestable(NestableTypes::NestableType nestableType, QUuid id) : + _nestableType(nestableType), + _id(id), + _transform() { + // set flags in _transform + _transform.setTranslation(glm::vec3(0.0f)); + _transform.setRotation(glm::quat()); +} + Transform SpatiallyNestable::getParentTransform() const { Transform result; SpatiallyNestablePointer parent = getParentPointer(); @@ -76,6 +86,26 @@ void SpatiallyNestable::setParentID(const QUuid& parentID) { _parentKnowsMe = false; } +glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position) { + Transform parentTransform = getParentTransform(); + Transform myWorldTransform; + Transform::mult(myWorldTransform, parentTransform, _transform); + myWorldTransform.setTranslation(position); + Transform result; + Transform::inverseMult(result, parentTransform, myWorldTransform); + return result.getTranslation(); +} + +glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation) { + Transform parentTransform = getParentTransform(); + Transform myWorldTransform; + Transform::mult(myWorldTransform, parentTransform, _transform); + myWorldTransform.setRotation(orientation); + Transform result; + Transform::inverseMult(result, parentTransform, myWorldTransform); + return result.getRotation(); +} + const glm::vec3& SpatiallyNestable::getPosition() const { Transform parentTransformDescaled = getParentTransform(); glm::mat4 parentMat; @@ -131,6 +161,7 @@ const Transform& SpatiallyNestable::getLocalTransform() const { } void SpatiallyNestable::setLocalTransform(const Transform& transform) { + _transform = transform; } const glm::vec3& SpatiallyNestable::getLocalPosition() const { diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index e0ee5bdb74..986a282891 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -34,11 +34,7 @@ public: class SpatiallyNestable : public std::enable_shared_from_this { public: - // SpatiallyNestable() : _transform() { } // XXX get rid of this one? - SpatiallyNestable(NestableTypes::NestableType nestableType, QUuid id) : - _nestableType(nestableType), - _id(id), - _transform() { } + SpatiallyNestable(NestableTypes::NestableType nestableType, QUuid id); virtual ~SpatiallyNestable() { } virtual const QUuid& getID() const { return _id; } @@ -50,6 +46,9 @@ public: virtual quint16 getParentJointIndex() const { return _parentJointIndex; } virtual void setParentJointIndex(quint16 parentJointIndex) { _parentJointIndex = parentJointIndex; } + glm::vec3 worldToLocal(const glm::vec3& position); + glm::quat worldToLocal(const glm::quat& orientation); + // world frame virtual const Transform& getTransform() const; virtual void setTransform(const Transform& transform); From 97713618409d48a4084f7de2a6eb1c0931b2db0c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 26 Oct 2015 10:49:41 -0700 Subject: [PATCH 039/401] Typo --- libraries/script-engine/src/ScriptEngine.cpp | 6 +++--- libraries/script-engine/src/ScriptEngine.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index cbe9449551..2c725bdf70 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -575,9 +575,9 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi return result; } - // Check synthax + // Check syntax const QScriptProgram program(sourceCode, fileName, lineNumber); - if (!checkSynthax(program)) { + if (!checkSyntax(program)) { return QScriptValue(); } @@ -892,7 +892,7 @@ void ScriptEngine::load(const QString& loadFile) { } -bool ScriptEngine::checkSynthax(const QScriptProgram& program) { +bool ScriptEngine::checkSyntax(const QScriptProgram& program) { const auto syntaxCheck = QScriptEngine::checkSyntax(program.sourceCode()); if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) { const auto error = syntaxCheck.errorMessage(); diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 8fda876a31..db10ecef40 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -182,7 +182,7 @@ private: QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot); void stopTimer(QTimer* timer); - static bool checkSynthax(const QScriptProgram& program); + static bool checkSyntax(const QScriptProgram& program); static bool checkExceptions(QScriptEngine* engine, const QString& fileName); AbstractControllerScriptingInterface* _controllerScriptingInterface; From 8d72fcada5a712a0518fcf1063686dc3157d3812 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 26 Oct 2015 11:33:13 -0700 Subject: [PATCH 040/401] Some more script checks --- libraries/script-engine/src/ScriptEngine.cpp | 26 +++++++------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 2c725bdf70..0411c507ab 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -79,7 +79,6 @@ void avatarDataFromScriptValue(const QScriptValue &object, AvatarData* &out) { QScriptValue inputControllerToScriptValue(QScriptEngine *engine, AbstractInputController* const &in) { return engine->newQObject(in); } - void inputControllerFromScriptValue(const QScriptValue &object, AbstractInputController* &out) { out = qobject_cast(object.toQObject()); } @@ -95,9 +94,6 @@ ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNam _wantSignals(wantSignals), _controllerScriptingInterface(controllerScriptingInterface), _fileNameString(fileNameString), - _quatLibrary(), - _vec3Library(), - _uuidLibrary(), _isUserLoaded(false), _isReloading(false), _arrayBufferClass(new ArrayBufferClass(this)) @@ -654,7 +650,9 @@ void ScriptEngine::run() { } lastUpdate = now; - checkExceptions(this, _fileNameString); + if (!checkExceptions(this, _fileNameString)) { + stop(); + } } stopAllTimers(); // make sure all our timers are stopped if the script is ending @@ -891,7 +889,6 @@ void ScriptEngine::load(const QString& loadFile) { } } - bool ScriptEngine::checkSyntax(const QScriptProgram& program) { const auto syntaxCheck = QScriptEngine::checkSyntax(program.sourceCode()); if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) { @@ -1005,14 +1002,10 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co auto scriptCache = DependencyManager::get(); bool isFileUrl = isURL && scriptOrURL.startsWith("file://"); + auto fileName = QString("(EntityID:%1, %2)").arg(entityID.toString(), isURL ? scriptOrURL : "EmbededEntityScript"); - // first check the syntax of the script contents - QScriptSyntaxCheckResult syntaxCheck = QScriptEngine::checkSyntax(contents); - if (syntaxCheck.state() != QScriptSyntaxCheckResult::Valid) { - qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID; - qCDebug(scriptengine) << " " << syntaxCheck.errorMessage() << ":" - << syntaxCheck.errorLineNumber() << syntaxCheck.errorColumnNumber(); - qCDebug(scriptengine) << " SCRIPT:" << scriptOrURL; + QScriptProgram program(contents, fileName); + if (!checkSyntax(program)) { if (!isFileUrl) { scriptCache->addScriptToBadScriptList(scriptOrURL); } @@ -1027,9 +1020,9 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co QScriptValue testConstructor = sandbox.evaluate(contents); if (!testConstructor.isFunction()) { - qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID; - qCDebug(scriptengine) << " NOT CONSTRUCTOR"; - qCDebug(scriptengine) << " SCRIPT:" << scriptOrURL; + qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID << "\n" + " NOT CONSTRUCTOR\n" + " SCRIPT:" << scriptOrURL; if (!isFileUrl) { scriptCache->addScriptToBadScriptList(scriptOrURL); } @@ -1042,7 +1035,6 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co lastModified = (quint64)QFileInfo(file).lastModified().toMSecsSinceEpoch(); } - auto fileName = QString("(EntityID:%1, %2)").arg(entityID.toString(), isURL ? scriptOrURL : "EmbededEntityScript"); QScriptValue entityScriptConstructor = evaluate(contents, fileName); QScriptValue entityScriptObject = entityScriptConstructor.construct(); EntityScriptDetails newDetails = { scriptOrURL, entityScriptObject, lastModified }; From 1e4a414f9df210ffc32b022c132cc49f39ac4127 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 26 Oct 2015 11:33:36 -0700 Subject: [PATCH 041/401] Fix scripts syntax errors --- examples/libraries/entityCameraTool.js | 10 +++++----- examples/libraries/soundArray.js | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/libraries/entityCameraTool.js b/examples/libraries/entityCameraTool.js index d304a6382e..88e01b29fe 100644 --- a/examples/libraries/entityCameraTool.js +++ b/examples/libraries/entityCameraTool.js @@ -564,12 +564,12 @@ CameraTool = function(cameraManager) { var ORIENTATION_OVERLAY_SIZE = 26; var ORIENTATION_OVERLAY_HALF_SIZE = ORIENTATION_OVERLAY_SIZE / 2; - var ORIENTATION_OVERLAY_CUBE_SIZE = 10.5, + var ORIENTATION_OVERLAY_CUBE_SIZE = 10.5; - var ORIENTATION_OVERLAY_OFFSET = { - x: 30, - y: 30, - } + var ORIENTATION_OVERLAY_OFFSET = { + x: 30, + y: 30, + } var UI_WIDTH = 70; var UI_HEIGHT = 70; diff --git a/examples/libraries/soundArray.js b/examples/libraries/soundArray.js index 813621fb4b..f59c88a723 100644 --- a/examples/libraries/soundArray.js +++ b/examples/libraries/soundArray.js @@ -6,7 +6,7 @@ SoundArray = function(audioOptions, autoUpdateAudioPosition) { this.audioOptions = audioOptions !== undefined ? audioOptions : {}; this.autoUpdateAudioPosition = autoUpdateAudioPosition !== undefined ? autoUpdateAudioPosition : false; if (this.audioOptions.position === undefined) { - this.audioOptions.position = Vec3.sum(MyAvatar.position, { x: 0, y: 1, z: 0}), + this.audioOptions.position = Vec3.sum(MyAvatar.position, { x: 0, y: 1, z: 0}); } if (this.audioOptions.volume === undefined) { this.audioOptions.volume = 1.0; From e8c6acfeb68ab2e062c3a5de39bc6a4a7af7789e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 26 Oct 2015 11:58:49 -0700 Subject: [PATCH 042/401] update baseball crowd to loop better --- examples/acScripts/baseballCrowd.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/acScripts/baseballCrowd.js b/examples/acScripts/baseballCrowd.js index 5007c64b16..d892fe5c71 100644 --- a/examples/acScripts/baseballCrowd.js +++ b/examples/acScripts/baseballCrowd.js @@ -9,11 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var crowd1 = SoundCache.getSound("atp:0e921b644464d56d5b412ea2ea1d83f8ff3f7506c4b0471ea336a4770daf3b82.wav"); +var crowd1 = SoundCache.getSound("atp:d9978e693035d4e2b5c7b546c8cccfb2dde5677834d9eed5206ccb2da55b4732.wav"); function maybePlaySound(deltaTime) { if (crowd1.downloaded && !crowd1.isPlaying) { - Audio.playSound(crowd1, { position: { x: 0, y: 0, z: 0}, loop: true}); + Audio.playSound(crowd1, { position: { x: 0, y: 0, z: 0}, loop: true, volume: 0.5 }); Script.update.disconnect(maybePlaySound); } } From ca60ce59f1f9194a23f569e82ea4df4c1be66b01 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 26 Oct 2015 12:06:25 -0700 Subject: [PATCH 043/401] put Agent AssetClient on sep thread, cleanup --- assignment-client/src/Agent.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index fb9b2a94a0..b5162c7478 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -44,7 +44,14 @@ Agent::Agent(NLPacket& packet) : { DependencyManager::get()->setPacketSender(&_entityEditSender); - DependencyManager::set(); + auto assetClient = DependencyManager::set(); + + QThread* assetThread = new QThread; + assetThread->setObjectName("Asset Thread"); + assetClient->moveToThread(assetThread); + connect(assetThread, &QThread::started, assetClient.data(), &AssetClient::init); + assetThread->start(); + DependencyManager::set(); DependencyManager::set(); @@ -368,6 +375,7 @@ void Agent::processAgentAvatarAndAudio(float deltaTime) { void Agent::aboutToFinish() { setIsAvatar(false);// will stop timers for sending billboards and identity packets + if (_scriptEngine) { _scriptEngine->stop(); } @@ -379,6 +387,12 @@ void Agent::aboutToFinish() { // our entity tree is going to go away so tell that to the EntityScriptingInterface DependencyManager::get()->setEntityTree(NULL); + + // cleanup the AssetClient thread + QThread* assetThread = DependencyManager::get()->thread(); + DependencyManager::destroy(); + assetThread->quit(); + assetThread->wait(); } void Agent::sendPingRequests() { From 61ad91aba66d5f04f6781804c4d4bf3fb3f87a97 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 26 Oct 2015 12:09:48 -0700 Subject: [PATCH 044/401] hook Sound downloaded to start playback --- examples/acScripts/baseballCrowd.js | 11 +++++------ libraries/audio/src/Sound.cpp | 1 + libraries/audio/src/Sound.h | 3 +++ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/examples/acScripts/baseballCrowd.js b/examples/acScripts/baseballCrowd.js index d892fe5c71..c61bbc4a9a 100644 --- a/examples/acScripts/baseballCrowd.js +++ b/examples/acScripts/baseballCrowd.js @@ -9,13 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var crowd1 = SoundCache.getSound("atp:d9978e693035d4e2b5c7b546c8cccfb2dde5677834d9eed5206ccb2da55b4732.wav"); +var chatter = SoundCache.getSound("atp:d9978e693035d4e2b5c7b546c8cccfb2dde5677834d9eed5206ccb2da55b4732.wav"); -function maybePlaySound(deltaTime) { - if (crowd1.downloaded && !crowd1.isPlaying) { - Audio.playSound(crowd1, { position: { x: 0, y: 0, z: 0}, loop: true, volume: 0.5 }); - Script.update.disconnect(maybePlaySound); +function playChatter() { + if (chatter.downloaded && !chatter.isPlaying) { + Audio.playSound(chatter, { position: { x: 0, y: 0, z: 0}, loop: true, volume: 0.5 }); } } -Script.update.connect(maybePlaySound); +chatter.downloaded.connect(playChatter); diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 2457bda74a..4c8976a6d6 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -95,6 +95,7 @@ void Sound::downloadFinished(const QByteArray& data) { } _isReady = true; + emit downloaded(); } void Sound::downSample(const QByteArray& rawAudioByteArray) { diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index 842c395a7d..43c05ed4a5 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -29,6 +29,9 @@ public: bool isReady() const { return _isReady; } const QByteArray& getByteArray() { return _byteArray; } + +signals: + void downloaded(); private: QByteArray _byteArray; From a4ddb7a1e4e05e35fcb9cf90ee3dfd9d6abbfe02 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 26 Oct 2015 12:14:12 -0700 Subject: [PATCH 045/401] change downloaded to ready to avoid collision --- libraries/audio/src/Sound.cpp | 2 +- libraries/audio/src/Sound.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 4c8976a6d6..d20de2ba48 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -95,7 +95,7 @@ void Sound::downloadFinished(const QByteArray& data) { } _isReady = true; - emit downloaded(); + emit ready(); } void Sound::downSample(const QByteArray& rawAudioByteArray) { diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index 43c05ed4a5..bcac999ee8 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -31,7 +31,7 @@ public: const QByteArray& getByteArray() { return _byteArray; } signals: - void downloaded(); + void ready(); private: QByteArray _byteArray; From 47e8a1bdf7a50b7a8d9486d6408f4c6610ac8002 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 26 Oct 2015 12:15:08 -0700 Subject: [PATCH 046/401] connect to correct signal for sound ready --- examples/acScripts/baseballCrowd.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/acScripts/baseballCrowd.js b/examples/acScripts/baseballCrowd.js index c61bbc4a9a..1f82b65f54 100644 --- a/examples/acScripts/baseballCrowd.js +++ b/examples/acScripts/baseballCrowd.js @@ -17,4 +17,4 @@ function playChatter() { } } -chatter.downloaded.connect(playChatter); +chatter.ready.connect(playChatter); From 1c048880ee2d3f33f38c20defc74dedf80f1cba5 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 26 Oct 2015 12:27:48 -0700 Subject: [PATCH 047/401] Lambda conversion fix for windows --- libraries/script-engine/src/ScriptEngine.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 0411c507ab..bcfeef1acb 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -509,18 +509,22 @@ void ScriptEngine::addEventHandler(const EntityItemID& entityID, const QString& }); // Two common cases of event handler, differing only in argument signature. - auto makeSingleEntityHandler = [&](QString eventName) { + using SingleEntityHandler = std::function; + auto makeSingleEntityHandler = [this](QString eventName) -> SingleEntityHandler { return [this, eventName](const EntityItemID& entityItemID) { forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this) }); }; }; - auto makeMouseHandler = [&](QString eventName) { + + using MouseHandler = std::function; + auto makeMouseHandler = [this](QString eventName) -> MouseHandler { return [this, eventName](const EntityItemID& entityItemID, const MouseEvent& event) { forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(this), event.toScriptValue(this) }); }; }; - auto makeCollisionHandler = [&](QString eventName) { + using CollisionHandler = std::function; + auto makeCollisionHandler = [this](QString eventName) -> CollisionHandler { return [this, eventName](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) { forwardHandlerCall(idA, eventName, { idA.toScriptValue(this), idB.toScriptValue(this), collisionToScriptValue(this, collision) }); From 380139364c4b2e0f74c6881f5cc809094d504c0a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 26 Oct 2015 12:33:42 -0700 Subject: [PATCH 048/401] checkExceptions after testing entity scripts in the sandbox --- libraries/script-engine/src/ScriptEngine.cpp | 23 +++++++++++--------- libraries/script-engine/src/ScriptEngine.h | 2 +- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index bcfeef1acb..986613c20b 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -585,7 +585,7 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi const auto result = QScriptEngine::evaluate(program); --_evaluatesPending; - const auto hadUncaughtException = checkExceptions(this, program.fileName()); + const auto hadUncaughtException = checkExceptions(*this, program.fileName()); if (_wantSignals) { emit evaluationFinished(result, hadUncaughtException); } @@ -654,7 +654,7 @@ void ScriptEngine::run() { } lastUpdate = now; - if (!checkExceptions(this, _fileNameString)) { + if (!checkExceptions(*this, _fileNameString)) { stop(); } } @@ -906,12 +906,12 @@ bool ScriptEngine::checkSyntax(const QScriptProgram& program) { return true; } -bool ScriptEngine::checkExceptions(QScriptEngine* engine, const QString& fileName) { - if (engine->hasUncaughtException()) { - const auto backtrace = engine->uncaughtExceptionBacktrace(); - const auto exception = engine->uncaughtException().toString(); - const auto line = QString::number(engine->uncaughtExceptionLineNumber()); - engine->clearExceptions(); +bool ScriptEngine::checkExceptions(QScriptEngine& engine, const QString& fileName) { + if (engine.hasUncaughtException()) { + const auto backtrace = engine.uncaughtExceptionBacktrace(); + const auto exception = engine.uncaughtException().toString(); + const auto line = QString::number(engine.uncaughtExceptionLineNumber()); + engine.clearExceptions(); auto message = QString("[UncaughtException] %1 in %2:%3").arg(exception, fileName, line); if (!backtrace.empty()) { @@ -1021,8 +1021,11 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co } QScriptEngine sandbox; - QScriptValue testConstructor = sandbox.evaluate(contents); - + QScriptValue testConstructor = sandbox.evaluate(program); + if (!checkExceptions(sandbox, program.fileName())) { + return; + } + if (!testConstructor.isFunction()) { qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID << "\n" " NOT CONSTRUCTOR\n" diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index db10ecef40..ddd957e163 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -183,7 +183,7 @@ private: void stopTimer(QTimer* timer); static bool checkSyntax(const QScriptProgram& program); - static bool checkExceptions(QScriptEngine* engine, const QString& fileName); + static bool checkExceptions(QScriptEngine& engine, const QString& fileName); AbstractControllerScriptingInterface* _controllerScriptingInterface; QString _fileNameString; From 6080654d7e93cb9c034eeab14d77e6bb715548a5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 26 Oct 2015 15:48:02 -0700 Subject: [PATCH 049/401] zero out the pre-mix samples for each stream --- assignment-client/src/audio/AudioMixer.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 1d8908845f..ea980075c3 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -437,7 +437,6 @@ int AudioMixer::prepareMixForListeningNode(Node* node) { AudioMixerClientData* listenerNodeData = static_cast(node->getLinkedData()); // zero out the client mix for this node - memset(_preMixSamples, 0, sizeof(_preMixSamples)); memset(_mixSamples, 0, sizeof(_mixSamples)); // loop through all other nodes that have sufficient audio to mix @@ -458,6 +457,9 @@ int AudioMixer::prepareMixForListeningNode(Node* node) { if (otherNodeStream->getType() == PositionalAudioStream::Microphone) { streamUUID = otherNode->getUUID(); } + + // clear out the pre-mix samples before filling it up with this source + memset(_preMixSamples, 0, sizeof(_preMixSamples)); if (*otherNode != *node || otherNodeStream->shouldLoopbackForNode()) { streamsMixed += addStreamToMixForListeningNodeWithStream(listenerNodeData, streamUUID, From f275d2678d9214ca340a0e7490221b728e2816bc Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 26 Oct 2015 16:06:12 -0700 Subject: [PATCH 050/401] ping the AssetClient from the agent --- assignment-client/src/Agent.cpp | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index b5162c7478..88f5aafccd 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -43,20 +43,20 @@ Agent::Agent(NLPacket& packet) : DEFAULT_WINDOW_SECONDS_FOR_DESIRED_REDUCTION, false)) { DependencyManager::get()->setPacketSender(&_entityEditSender); - + auto assetClient = DependencyManager::set(); - + QThread* assetThread = new QThread; assetThread->setObjectName("Asset Thread"); assetClient->moveToThread(assetThread); connect(assetThread, &QThread::started, assetClient.data(), &AssetClient::init); assetThread->start(); - + DependencyManager::set(); DependencyManager::set(); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); - + packetReceiver.registerListenerForTypes( { PacketType::MixedAudio, PacketType::SilentAudioFrame }, this, "handleAudioPacket"); @@ -75,7 +75,7 @@ void Agent::handleOctreePacket(QSharedPointer packet, SharedNodePointe if (packet->getPayloadSize() > statsMessageLength) { // pull out the piggybacked packet and create a new QSharedPointer for it int piggyBackedSizeWithHeader = packet->getPayloadSize() - statsMessageLength; - + auto buffer = std::unique_ptr(new char[piggyBackedSizeWithHeader]); memcpy(buffer.get(), packet->getPayload() + statsMessageLength, piggyBackedSizeWithHeader); @@ -102,7 +102,7 @@ void Agent::handleJurisdictionPacket(QSharedPointer packet, SharedNode DependencyManager::get()->getJurisdictionListener()-> queueReceivedPacket(packet, senderNode); } -} +} void Agent::handleAudioPacket(QSharedPointer packet) { _receivedAudioStream.parseData(*packet); @@ -176,7 +176,7 @@ void Agent::run() { // give this AvatarData object to the script engine setAvatarData(&scriptedAvatar, "Avatar"); - + auto avatarHashMap = DependencyManager::set(); _scriptEngine->registerGlobalObject("AvatarList", avatarHashMap.data()); @@ -189,7 +189,7 @@ void Agent::run() { // register ourselves to the script engine _scriptEngine->registerGlobalObject("Agent", this); - // FIXME -we shouldn't be calling this directly, it's normally called by run(), not sure why + // FIXME -we shouldn't be calling this directly, it's normally called by run(), not sure why // viewers would need this called. //_scriptEngine->init(); // must be done before we set up the viewers @@ -201,14 +201,14 @@ void Agent::run() { auto entityScriptingInterface = DependencyManager::get(); _scriptEngine->registerGlobalObject("EntityViewer", &_entityViewer); - + // we need to make sure that init has been called for our EntityScriptingInterface // so that it actually has a jurisdiction listener when we ask it for it next entityScriptingInterface->init(); _entityViewer.setJurisdictionListener(entityScriptingInterface->getJurisdictionListener()); - + _entityViewer.init(); - + entityScriptingInterface->setEntityTree(_entityViewer.getTree()); // wire up our additional agent related processing to the update signal @@ -241,7 +241,7 @@ void Agent::setIsAvatar(bool isAvatar) { delete _avatarIdentityTimer; _avatarIdentityTimer = nullptr; } - + if (_avatarBillboardTimer) { _avatarBillboardTimer->stop(); delete _avatarBillboardTimer; @@ -375,7 +375,7 @@ void Agent::processAgentAvatarAndAudio(float deltaTime) { void Agent::aboutToFinish() { setIsAvatar(false);// will stop timers for sending billboards and identity packets - + if (_scriptEngine) { _scriptEngine->stop(); } @@ -387,7 +387,7 @@ void Agent::aboutToFinish() { // our entity tree is going to go away so tell that to the EntityScriptingInterface DependencyManager::get()->setEntityTree(NULL); - + // cleanup the AssetClient thread QThread* assetThread = DependencyManager::get()->thread(); DependencyManager::destroy(); @@ -403,6 +403,7 @@ void Agent::sendPingRequests() { case NodeType::AvatarMixer: case NodeType::AudioMixer: case NodeType::EntityServer: + case NodeType::AssetClient: return true; default: return false; From 5f8c3a6b4b35bdd363a34cc930bc4caeff8b723a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 27 Oct 2015 10:27:37 -0700 Subject: [PATCH 051/401] Fix AssetResourceRequest crash --- libraries/networking/src/AssetResourceRequest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index eba9e45e5c..dac3329153 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -46,7 +46,7 @@ void AssetResourceRequest::doSend() { } connect(_assetRequest, &AssetRequest::progress, this, &AssetResourceRequest::progress); - connect(_assetRequest, &AssetRequest::finished, [this](AssetRequest* req) { + connect(_assetRequest, &AssetRequest::finished, this, [this](AssetRequest* req) { Q_ASSERT(_state == InProgress); Q_ASSERT(req == _assetRequest); Q_ASSERT(req->getState() == AssetRequest::Finished); From 3fa4f7138af635b1276fb363d339a50129176f0b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 27 Oct 2015 10:58:31 -0700 Subject: [PATCH 052/401] add more sounds to the crowd, ping AssetServer from Agent --- assignment-client/src/Agent.cpp | 2 +- examples/acScripts/baseballCrowd.js | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 88f5aafccd..668a9228ed 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -403,7 +403,7 @@ void Agent::sendPingRequests() { case NodeType::AvatarMixer: case NodeType::AudioMixer: case NodeType::EntityServer: - case NodeType::AssetClient: + case NodeType::AssetServer: return true; default: return false; diff --git a/examples/acScripts/baseballCrowd.js b/examples/acScripts/baseballCrowd.js index 1f82b65f54..b0038d5865 100644 --- a/examples/acScripts/baseballCrowd.js +++ b/examples/acScripts/baseballCrowd.js @@ -10,11 +10,31 @@ // var chatter = SoundCache.getSound("atp:d9978e693035d4e2b5c7b546c8cccfb2dde5677834d9eed5206ccb2da55b4732.wav"); +var extras = [ + SoundCache.getSound("atp:1ee58f4d929fdef7c2989cd8be964952a24cdd653d80f57b6a89a2ae8e3029e1.wav"), // zorba + SoundCache.getSound("atp:cefaba2d5f1a378382ee046716bffcf6b6a40676649b23a1e81a996efe22d7d3.wav"), // charge + SoundCache.getSound("atp:fb41e37f8f8f7b78e546ac78800df6e39edaa09b2df4bfa0afdd8d749dac38b8.wav"), // take me out to the ball game + SoundCache.getSound("atp:44a83a788ccfd2924e35c902c34808b24dbd0309d000299ce01a355f91cf8115.wav") // clapping +]; function playChatter() { if (chatter.downloaded && !chatter.isPlaying) { - Audio.playSound(chatter, { position: { x: 0, y: 0, z: 0}, loop: true, volume: 0.5 }); + Audio.playSound(chatter, { loop: true, volume: 0.5 }); } } chatter.ready.connect(playChatter); + +var currentInjector = null; + +function playRandomExtras() { + if ((!currentInjector || !currentInjector.isPlaying) && (Math.random() < (1.0 / 1800.0))) { + // play a random extra sound about every 30s + currentInjector = Audio.playSound( + extras[Math.floor(Math.random() * extras.length)], + { volume: 0.33 } + ); + } +} + +Script.update.connect(playRandomExtras); From 7e8aec9db90da9da07904a6a4468a14f0e10e6aa Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 27 Oct 2015 11:48:52 -0700 Subject: [PATCH 053/401] fix double URL scheme --- examples/baseball/baseball.js | 126 +++++----------------------------- 1 file changed, 16 insertions(+), 110 deletions(-) diff --git a/examples/baseball/baseball.js b/examples/baseball/baseball.js index 504d067885..71f3f2c049 100755 --- a/examples/baseball/baseball.js +++ b/examples/baseball/baseball.js @@ -13,128 +13,34 @@ var ROBOT_MODEL = "atp:785c81e117206c36205404beec0cc68529644fe377542dbb2d13fae4d var ROBOT_POSITION = { x: -0.81, y: 0.88, z: 2.12 }; var ROBOT_DIMENSIONS = { x: 0.95, y: 1.76, z: 0.56 }; -var BAT_MODEL = "atp:07bdd769a57ff15ebe9331ae4e2c2eae8886a6792b4790cce03b4716eb3a81c7.fbx" -var BAT_COLLISION_MODEL = "atp:atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj" -var BAT_DIMENSIONS = { x: 1.35, y: 0.10, z: 0.10 }; -var BAT_REGISTRATION_POINT = { x: 0.1, y: 0.5, z: 0.5 }; +var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx" +var BAT_COLLISION_MODEL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj" // add the fresh robot at home plate -var robot = Entities.addEntity({ - name: 'Robot', - type: 'Model', - modelURL: ROBOT_MODEL, - position: ROBOT_POSITION, -// dimensions: ROBOT_DIMENSIONS,a - animationIsPlaying: true, - animation: { - url: ROBOT_MODEL, - fps: 30 - } -}); +// var robot = Entities.addEntity({ +// name: 'Robot', +// type: 'Model', +// modelURL: ROBOT_MODEL, +// position: ROBOT_POSITION, +// // dimensions: ROBOT_DIMENSIONS, +// animationIsPlaying: true, +// animation: { +// url: ROBOT_MODEL, +// fps: 30 +// } +// }); // add the bat var bat = Entities.addEntity({ name: 'Bat', - /*/ - type: 'Box', - /*/ type: 'Model', - modelURL: BAT_COLLISION_MODEL, - /**/ + modelURL: BAT_MODEL, collisionModelURL: BAT_COLLISION_MODEL, -// dimensions: BAT_DIMENSIONS, - registrationPoint: BAT_REGISTRATION_POINT, - visible: false + userData: "{"grabbableKey":{"spatialKey":{"relativePosition":{"x":0.9,"y":0,"z":0},"relativeRotation":{"x":10,"y":0,"z":0}},"kinematicGrab":true}}" }) -var lastTriggerValue = 0.0; - -function checkTriggers() { - var rightTrigger = Controller.getTriggerValue(1); - - if (rightTrigger == 0) { - if (lastTriggerValue > 0) { - // the trigger was just released, play out to the last frame of the swing - Entities.editEntity(robot, { - animation: { - running: true, - currentFrame: 21, - lastFrame: 115 - } - }); - } - } else { - if (lastTriggerValue == 0) { - // the trigger was just depressed, start the swing - Entities.editEntity(robot, { - animation: { - running: true, - currentFrame: 0, - lastFrame: 21 - } - }); - } - } - - lastTriggerValue = rightTrigger; -} - -var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position -var ACTION_LIFETIME = 15; // seconds - -var action = null; -var factor = 0.0; -var STEP = 0.05; -function moveBat() { - var JOINT_INDEX = 19; - - var forearmPosition = Entities.getJointPosition(robot, JOINT_INDEX); - var forearmRotation = Entities.getJointRotation(robot, JOINT_INDEX); - - /*/ - var properties = Entities.getEntityProperties(bat, ["position", "rotation"]); - var offsetPosition = Vec3.subtract(properties.position, forearmPosition); - var offsetRotation = Quat.multiply(Quat.inverse(forearmRotation), properties.rotation); - print("offsetPosition = " + JSON.stringify(offsetPosition)); - print("offsetRotation = " + JSON.stringify(Quat.safeEulerAngles(offsetRotation))); - /*/ - Entities.editEntity(bat, { - position: forearmPosition, - rotation: forearmRotation, - }); - /**/ - -// var actionProperties = { -// relativePosition: forearmPosition, -// relativeRotation: forearmRotation, -//// tag: "bat-to-forearm", -//// linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, -//// angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, -//// lifetime: ACTION_LIFETIME -// hand: "left", -// timeScale: 0.15 -// }; -// -// if (action === null) { -// Entities.addAction("hold", bat, actionProperties); -// } else { -// Entities.editAction(bat, action, actionProperties); -// } -} - -function update() { -// checkTriggers(); - moveBat(); -} - function scriptEnding() { - Entities.deleteEntity(robot); Entities.deleteEntity(bat); - if (action) { - Entities.deleteAction(bat, action); - } } -// hook the update so we can check controller triggers -Script.update.connect(update); Script.scriptEnding.connect(scriptEnding); From c9f49ca992227fef4ea3b42bb0cb02a5c97330f9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 27 Oct 2015 11:53:46 -0700 Subject: [PATCH 054/401] Remove baseball script --- examples/baseball/baseball.js | 46 ----------------------------------- 1 file changed, 46 deletions(-) delete mode 100755 examples/baseball/baseball.js diff --git a/examples/baseball/baseball.js b/examples/baseball/baseball.js deleted file mode 100755 index 71f3f2c049..0000000000 --- a/examples/baseball/baseball.js +++ /dev/null @@ -1,46 +0,0 @@ -// -// baseball.js -// examples/toys -// -// Created by Stephen Birarda on 10/20/15. -// 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 -// - -var ROBOT_MODEL = "atp:785c81e117206c36205404beec0cc68529644fe377542dbb2d13fae4d665a5de.fbx"; -var ROBOT_POSITION = { x: -0.81, y: 0.88, z: 2.12 }; -var ROBOT_DIMENSIONS = { x: 0.95, y: 1.76, z: 0.56 }; - -var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx" -var BAT_COLLISION_MODEL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj" - -// add the fresh robot at home plate -// var robot = Entities.addEntity({ -// name: 'Robot', -// type: 'Model', -// modelURL: ROBOT_MODEL, -// position: ROBOT_POSITION, -// // dimensions: ROBOT_DIMENSIONS, -// animationIsPlaying: true, -// animation: { -// url: ROBOT_MODEL, -// fps: 30 -// } -// }); - -// add the bat -var bat = Entities.addEntity({ - name: 'Bat', - type: 'Model', - modelURL: BAT_MODEL, - collisionModelURL: BAT_COLLISION_MODEL, - userData: "{"grabbableKey":{"spatialKey":{"relativePosition":{"x":0.9,"y":0,"z":0},"relativeRotation":{"x":10,"y":0,"z":0}},"kinematicGrab":true}}" -}) - -function scriptEnding() { - Entities.deleteEntity(bat); -} - -Script.scriptEnding.connect(scriptEnding); From b46d42889d2f418fa140cae6cbd9e31b47eaabc2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 27 Oct 2015 13:25:43 -0700 Subject: [PATCH 055/401] Add foul and strike audio to baseball game --- examples/baseball/pitching.js | 104 +++++++++++++++++++++++----------- 1 file changed, 71 insertions(+), 33 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 1f8df39a7b..6f7d8e686a 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -14,6 +14,15 @@ var AUDIO = { SoundCache.getSound("atp:e68661374e2145c480809c26134782aad11e0de456c7802170c7abccc4028873.wav", false), SoundCache.getSound("atp:787e3c9af17dd3929527787176ede83d6806260e63ddd5a4cef48cd22e32c6f7.wav", false), SoundCache.getSound("atp:fc65383431a6238c7a4749f0f6f061f75a604ed5e17d775ab1b2955609e67ebb.wav", false), + ], + strike: [ + SoundCache.getSound("atp:2a258076a85fffde4ba04b5ddc1de9034c7ae7d2af8c5d93d4fed0bcdef3472a.wav", false), + SoundCache.getSound("atp:518363524af3ed9b9ae4ca2ceee61f01aecd37e266a51c5a5f5487efe2520fd5.wav", false), + SoundCache.getSound("atp:d51d38b089574acbdfdf53ef733bfb3ab41d848fb8c0b6659c7790a785240009.wav", false), + ], + foul: [ + SoundCache.getSound("atp:316fa18ff9eef457f670452b449a8dc5a41ccabd4e948781c50aaafaae63b0ab.wav", false), + SoundCache.getSound("atp:c84d88352d38437edd7414b26dc74e567618712caeb59fec70822398b0c5a279.wav", false), ] } @@ -105,6 +114,12 @@ var BASEBALL_PROPERTIES = { z: 0 } }; +var BASEBALL_STATE = { + PITCHING: 0, + HIT: 1, + STRIKE: 2, + FOUL: 3 +}; var pitchingMachineID = Entities.addEntity(PITCHING_MACHINE_PROPERTIES); @@ -159,10 +174,10 @@ function orientationOf(vector) { var Y_AXIS = { x: 0, y: 1, z: 0 }; var X_AXIS = { x: 1, y: 0, z: 0 }; var direction = Vec3.normalize(vector); - + var yaw = Quat.angleAxis(Math.atan2(direction.x, direction.z) * RAD_TO_DEG, Y_AXIS); var pitch = Quat.angleAxis(Math.asin(-direction.y) * RAD_TO_DEG, X_AXIS); - + return Quat.multiply(yaw, pitch); } @@ -176,7 +191,7 @@ function cleanupTrail() { if (trail) { Script.clearInterval(this.trailInterval); trailInterval = null; - + trail.destroy(); trail = null; } @@ -184,7 +199,7 @@ function cleanupTrail() { function setupTrail(entityID, position) { cleanupTrail(); - + var lastPosition = position; trail = new InfiniteLine(position, { red: 255, green: 128, blue: 89 }); trailInterval = Script.setInterval(function() { @@ -199,7 +214,9 @@ function setupTrail(entityID, position) { function Baseball(position, velocity, ballScale) { var self = this; - // Setup entity properties + this.state = BASEBALL_STATE.PITCHING; + + // Setup entity properties var properties = shallowCopy(BASEBALL_PROPERTIES); properties.position = position; properties.velocity = velocity; @@ -211,7 +228,7 @@ function Baseball(position, velocity, ballScale) { z: 0.0, }; */ - + // Create entity this.entityID = Entities.addEntity(properties); @@ -242,7 +259,7 @@ Baseball.prototype = { var myProperties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']); var myPosition = myProperties.position; var myVelocity = myProperties.velocity; - + // Activate gravity Entities.editEntity(self.entityID, { gravity: { x: 0, y: -9.8, z: 0 } @@ -251,35 +268,57 @@ Baseball.prototype = { var name = Entities.getEntityProperties(entityB, ["name"]).name; print("Hit: " + name); if (name == "Bat") { - print("HIT"); - - // Update ball velocity - Entities.editEntity(self.entityID, { - velocity: Vec3.multiply(2, myVelocity), - }); - - // Setup line update interval - setupTrail(self.entityID, myPosition); - - // Setup bat hit sound - playRandomSound(AUDIO.batHit, { - position: myPosition, - volume: 2.0 - }); - - // Setup crowd reaction sound - var speed = Vec3.length(myVelocity); - Script.setTimeout(function() { - playRandomSound((speed < 5.0) ? AUDIO.crowdBoos : AUDIO.crowdCheers, { - position: { x: 0 ,y: 0, z: 0 }, - volume: 1.0 + if (this.state == BASEBALL_STATE.PITCHING) { + print("HIT"); + + // Update ball velocity + Entities.editEntity(self.entityID, { + velocity: Vec3.multiply(2, myVelocity), }); - }, 500); + + // Setup line update interval + setupTrail(self.entityID, myPosition); + + // Setup bat hit sound + playRandomSound(AUDIO.batHit, { + position: myPosition, + volume: 2.0 + }); + + // Setup crowd reaction sound + var speed = Vec3.length(myVelocity); + Script.setTimeout(function() { + playRandomSound((speed < 5.0) ? AUDIO.crowdBoos : AUDIO.crowdCheers, { + position: { x: 0 ,y: 0, z: 0 }, + volume: 1.0 + }); + }, 500); + var yaw = Math.atan2(myVelocity.x, myVelocity.z) * 180 / Math.PI; + var foul = yaw > -135 && yaw < 135; + if (foul) { + print("FOUL ", yaw) + this.state = BASEBALL_STATE.FOUL; + playRandomSound(AUDIO.foul, { + position: myPosition, + volume: 2.0 + }); + } else { + print("HIT ", yaw); + this.state = BASEBALL_STATE.HIT; + } + } } else if (name == "stadium") { print("PARTICLES"); entityCollisionWithGround(entityB, this.entityID, collision); } else if (name == "backstop") { - print("STRIKE"); + if (this.state == BASEBALL_STATE.PITCHING) { + this.state = BASEBALL_STATE.STRIKE; + print("STRIKE"); + playRandomSound(AUDIO.strike, { + position: myPosition, + volume: 2.0 + }); + } } } } @@ -317,7 +356,7 @@ function entityCollisionWithGround(ground, entity, collision) { var speed = map(dVelocityMagnitude, 0.05, 3, 0.02, 0.09); var displayTime = 400; var orientationChange = orientationOf(collision.velocityChange); - + var dustEffect = Entities.addEntity({ type: "ParticleEffect", name: "Dust-Puff", @@ -349,4 +388,3 @@ Script.scriptEnding.connect(function() { }); Script.setInterval(pitchBall, PITCH_RATE); - From e9a2e9137435d137bab2a1c928b56e05ceb0ff27 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 27 Oct 2015 15:35:30 -0700 Subject: [PATCH 056/401] Add tunneling handling to pitching.js --- examples/baseball/pitching.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 6f7d8e686a..4e40b0aca8 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -270,6 +270,18 @@ Baseball.prototype = { if (name == "Bat") { if (this.state == BASEBALL_STATE.PITCHING) { print("HIT"); + var yaw = Math.atan2(myVelocity.x, myVelocity.z) * 180 / Math.PI; + var foul = yaw > -135 && yaw < 135; + + if (foul && myVelocity.z > 0) { + var xzDist = Math.sqrt(myVelocity.x * myVelocity.x + myVelocity.z * myVelocity.z); + var pitch = Math.atan2(myVelocity.y, xzDist) * 180 / Math.PI; + print("Pitch: ", pitch); + if (Math.abs(pitch) < 15) { + print("Reversing hit"); + myVelocity.z *= -1; + } + } // Update ball velocity Entities.editEntity(self.entityID, { @@ -293,8 +305,6 @@ Baseball.prototype = { volume: 1.0 }); }, 500); - var yaw = Math.atan2(myVelocity.x, myVelocity.z) * 180 / Math.PI; - var foul = yaw > -135 && yaw < 135; if (foul) { print("FOUL ", yaw) this.state = BASEBALL_STATE.FOUL; From 2ecec2623c143b651dd26cbb0c803b92996df0fd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 28 Oct 2015 17:03:25 -0700 Subject: [PATCH 057/401] add a script for bat creation on button click --- examples/baseball/createBatButton.js | 61 ++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 examples/baseball/createBatButton.js diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js new file mode 100644 index 0000000000..0ffc9cb829 --- /dev/null +++ b/examples/baseball/createBatButton.js @@ -0,0 +1,61 @@ +// +// createBatButton.js +// examples/baseball/moreBatsButton.js +// +// Created by Stephen Birarda on 10/28/2015. +// 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 +// + +(function(){ + this.clickReleaseOnEntity = function(entityID, mouseEvent) { + if (!mouseEvent.isLeftButton) { + return; + } + this.dropBats(); + }; + this.startNearGrabNonColliding = function() { + this.dropBats(); + }; + this.dropBats = function() { + // if the bat box is near us, grab it's position + var nearby = Entities.findEntities(this.position, 20); + + nearby.forEach(function(id) { + var properties = Entities.getEntityProperties(id, ["name", "position"]); + if (properties.name && properties.name == "Bat Box") { + boxPosition = properties.position; + } + }); + + var BAT_DROP_HEIGHT = 2.0; + + var dropPosition; + + if (!boxPosition) { + // we got no bat box position, drop in front of the avatar instead + } else { + // drop the bat above the bat box + dropPosition = Vec3.sum(boxPosition, { x: 0.0, y: BAT_DROP_HEIGHT, z: 0.0}); + } + + var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; + var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; + + // add the fresh bat at the drop position + var bat = Entities.addEntity({ + name: 'Bat', + type: "Model", + modelURL: BAT_MODEL, + position: dropPosition, + compoundShapeURL: BAT_COLLISION_HULL, + collisionsWillMove: true, + velocity: { x: 0, y: 0.05, z: 0}, // workaround for gravity not taking effect on add + gravity: { x: 0, y: -9.81, z: 0}, + rotation: Quat.fromPitchYawRollDegrees(0.0, 0.0, -90.0), + userData: '{"grabbableKey":{"spatialKey":{"relativePosition":{"x":0.9,"y":0,"z":0},"relativeRotation":{"x":0,"y":0,"z":0.4617486000061035,"w":0.8870108127593994}},"kinematicGrab":true}}' + }); + } +}) From a7517ff21049ed0b0c2297a16b80b03483de84d0 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 29 Oct 2015 14:01:53 -0700 Subject: [PATCH 058/401] CP --- examples/baseball/pitching.js | 55 ++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 4 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 4e40b0aca8..a609476bef 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -117,8 +117,9 @@ var BASEBALL_PROPERTIES = { var BASEBALL_STATE = { PITCHING: 0, HIT: 1, - STRIKE: 2, - FOUL: 3 + HIT_LANDED: 2, + STRIKE: 3, + FOUL: 4 }; @@ -232,6 +233,11 @@ function Baseball(position, velocity, ballScale) { // Create entity this.entityID = Entities.addEntity(properties); + this.timeSincePitched = 0; + this.timeSinceHit = 0; + this.hitBallAtPosition = null; + this.distanceTravelled = 0; + // Listen for collision for the lifetime of the entity Script.addEventHandler(this.entityID, "collisionWithEntity", function(entityA, entityB, collision) { self.collisionCallback(entityA, entityB, collision); @@ -254,6 +260,31 @@ function Baseball(position, velocity, ballScale) { } Baseball.prototype = { + finished: function() { + return this.state == BASEBALL_STATE.FOUL + || this.state == BASEBALL_STATE.STRIKE + || this.state == BASEBALL_STATE.HIT_LANDED; + }, + update: function(dt) { + this.timeSincePitched += dt; + if (this.state == BASEBALL_STATE.HIT) { + this.timeSinceHit += dt; + var myProperties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']); + var speed = Vec3.length(myProperties.velocity); + this.distanceTravelled = Vec3.distance(this.hitBallAtPosition, myProperties.position); + if (this.timeSinceHit > 10 || speed < 1) { + this.state = BASEBALL_STATE.HIT_LANDED; + print("Ball took " + this.timeSinceHit.toFixed(3) + " seconds to land"); + print("Ball travelled " + this.distanceTravelled + " meters") + } + } else if (this.state == BASEBALL_STATE.PITCHING) { + if (this.timeSincePitched > 10) { + print("TIMED OUT WHILE PITCHING"); + this.state = BASEBALL_STATE.STRIKE; + + } + } + }, collisionCallback: function(entityA, entityB, collision) { var self = this; var myProperties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']); @@ -280,6 +311,7 @@ Baseball.prototype = { if (Math.abs(pitch) < 15) { print("Reversing hit"); myVelocity.z *= -1; + foul = false; } } @@ -333,6 +365,8 @@ Baseball.prototype = { } } +var baseball = null; + function pitchBall() { var machineProperties = Entities.getEntityProperties(pitchingMachineID, ["dimensions", "position", "rotation"]); var pitchFromPositionBase = machineProperties.position; @@ -346,7 +380,7 @@ function pitchBall() { var speed = randomFloat(BASEBALL_MIN_SPEED, BASEBALL_MAX_SPEED) var timeToPassPlate = (DISTANCE_FROM_PLATE + 1.0) / speed; - var baseball = new Baseball(pitchFromPosition, Vec3.multiply(speed, pitchDirection), ballScale); + baseball = new Baseball(pitchFromPosition, Vec3.multiply(speed, pitchDirection), ballScale); if (!injector) { injector = Audio.playSound(pitchSound, { @@ -358,6 +392,17 @@ function pitchBall() { } } +function update(dt) { + if (baseball) { + baseball.update(dt); + if (baseball.finished()) { + print("BALL IS FINSIEHD"); + baseball = null; + pitchBall(); + } + } +} + function entityCollisionWithGround(ground, entity, collision) { var ZERO_VEC = { x: 0, y: 0, z: 0 }; var dVelocityMagnitude = Vec3.length(collision.velocityChange); @@ -397,4 +442,6 @@ Script.scriptEnding.connect(function() { Entities.deleteEntity(pitchingMachineID); }); -Script.setInterval(pitchBall, PITCH_RATE); +//Script.setInterval(pitchBall, PITCH_RATE); +Script.update.connect(update); +pitchBall(); From 8a29f4fc615d57b228b38ffdefa7d81162f56bf8 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 29 Oct 2015 14:47:34 -0700 Subject: [PATCH 059/401] Add distances and billboard display to pitching.js --- examples/baseball/pitching.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index a609476bef..eea7c391c6 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -1,5 +1,7 @@ Script.include("line.js"); +var DISTANCE_BILLBOARD_ENTITY_ID = "{5fe0daf5-3fc5-43e3-a4eb-81a8e840a52b}"; + var AUDIO = { crowdBoos: [ SoundCache.getSound("atp:c632c92b166ade60aa16b23ff1dfdf712856caeb83bd9311980b2d5edac821af.wav", false) @@ -106,6 +108,7 @@ var BASEBALL_PROPERTIES = { damping: 0.0, restitution: 0.5, friction: 0.0, + friction: 0.5, lifetime: 20, //collisionSoundURL: PITCH_THUNK_SOUND_URL, gravity: { @@ -259,6 +262,12 @@ function Baseball(position, velocity, ballScale) { */ } +function updateBillboard(value) { + Entities.editEntity(DISTANCE_BILLBOARD_ENTITY_ID, { + text: value, + }); +} + Baseball.prototype = { finished: function() { return this.state == BASEBALL_STATE.FOUL @@ -272,6 +281,7 @@ Baseball.prototype = { var myProperties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']); var speed = Vec3.length(myProperties.velocity); this.distanceTravelled = Vec3.distance(this.hitBallAtPosition, myProperties.position); + updateBillboard(Math.ceil(this.distanceTravelled)); if (this.timeSinceHit > 10 || speed < 1) { this.state = BASEBALL_STATE.HIT_LANDED; print("Ball took " + this.timeSinceHit.toFixed(3) + " seconds to land"); @@ -338,6 +348,7 @@ Baseball.prototype = { }); }, 500); if (foul) { + updateBillboard("FOUL!"); print("FOUL ", yaw) this.state = BASEBALL_STATE.FOUL; playRandomSound(AUDIO.foul, { @@ -352,9 +363,13 @@ Baseball.prototype = { } else if (name == "stadium") { print("PARTICLES"); entityCollisionWithGround(entityB, this.entityID, collision); + if (this.state == BASEBALL_STATE.HIT) { + this.state = BASEBALL_STATE.HIT_LANDED; + } } else if (name == "backstop") { if (this.state == BASEBALL_STATE.PITCHING) { this.state = BASEBALL_STATE.STRIKE; + updateBillboard("STRIKE!"); print("STRIKE"); playRandomSound(AUDIO.strike, { position: myPosition, @@ -368,6 +383,7 @@ Baseball.prototype = { var baseball = null; function pitchBall() { + updateBillboard(""); var machineProperties = Entities.getEntityProperties(pitchingMachineID, ["dimensions", "position", "rotation"]); var pitchFromPositionBase = machineProperties.position; var pitchFromOffset = vec3Mult(machineProperties.dimensions, PITCHING_MACHINE_OUTPUT_OFFSET_PCT); @@ -398,7 +414,7 @@ function update(dt) { if (baseball.finished()) { print("BALL IS FINSIEHD"); baseball = null; - pitchBall(); + Script.setTimeout(pitchBall, 3000); } } } From 03a082383fb380f7fd5b760a8486567c3e8572bd Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 29 Oct 2015 16:10:17 -0700 Subject: [PATCH 060/401] Convert billboard display to feet and cleanup trails earlier --- examples/baseball/pitching.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index eea7c391c6..6ec4d2df85 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -1,6 +1,7 @@ Script.include("line.js"); var DISTANCE_BILLBOARD_ENTITY_ID = "{5fe0daf5-3fc5-43e3-a4eb-81a8e840a52b}"; +var METERS_TO_FEET = 3.28084; var AUDIO = { crowdBoos: [ @@ -163,9 +164,9 @@ function playRandomSound(sounds, options) { function vec3Mult(a, b) { return { - x: a.x * b.x, - y: a.y * b.y, - z: a.z * b.z, + x: a.x * b.x, + y: a.y * b.y, + z: a.z * b.z, }; } @@ -281,7 +282,7 @@ Baseball.prototype = { var myProperties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']); var speed = Vec3.length(myProperties.velocity); this.distanceTravelled = Vec3.distance(this.hitBallAtPosition, myProperties.position); - updateBillboard(Math.ceil(this.distanceTravelled)); + updateBillboard(Math.ceil(this.distanceTravelled * METERS_TO_FEET)); if (this.timeSinceHit > 10 || speed < 1) { this.state = BASEBALL_STATE.HIT_LANDED; print("Ball took " + this.timeSinceHit.toFixed(3) + " seconds to land"); @@ -383,6 +384,7 @@ Baseball.prototype = { var baseball = null; function pitchBall() { + cleanupTrail(); updateBillboard(""); var machineProperties = Entities.getEntityProperties(pitchingMachineID, ["dimensions", "position", "rotation"]); var pitchFromPositionBase = machineProperties.position; From f4bbf8db60d399f5967a2e91ea3f2ef1cffe1bdb Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 29 Oct 2015 16:42:48 -0700 Subject: [PATCH 061/401] Check keyLight is defined --- examples/edit.js | 4 ++-- examples/html/entityProperties.html | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 447455e999..7a16030afc 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -1510,7 +1510,7 @@ PropertiesTool = function(opts) { if (entity.properties.rotation !== undefined) { entity.properties.rotation = Quat.safeEulerAngles(entity.properties.rotation); } - if (entity.properties.type === "Zone" && entity.properties.keyLight.direction !== undefined) { + if (entity.properties.keyLight !== undefined && entity.properties.keyLight.direction !== undefined) { entity.properties.keyLight.direction = Vec3.multiply(RADIANS_TO_DEGREES, Vec3.toPolar(entity.properties.keyLight.direction)); entity.properties.keyLight.direction.z = 0.0; } @@ -1541,7 +1541,7 @@ PropertiesTool = function(opts) { var rotation = data.properties.rotation; data.properties.rotation = Quat.fromPitchYawRollDegrees(rotation.x, rotation.y, rotation.z); } - if (entity.properties.type === "Zone" && data.properties.keyLight.direction !== undefined) { + if (data.properties.keyLight !== undefined && data.properties.keyLight.direction !== undefined) { data.properties.keyLight.direction = Vec3.fromPolar( data.properties.keyLight.direction.x * DEGREES_TO_RADIANS, data.properties.keyLight.direction.y * DEGREES_TO_RADIANS); } diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index fe40311b5f..412b413b2b 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -830,7 +830,7 @@ elZoneKeyLightColorRed.addEventListener('change', zoneKeyLightColorChangeFunction); elZoneKeyLightColorGreen.addEventListener('change', zoneKeyLightColorChangeFunction); elZoneKeyLightColorBlue.addEventListener('change', zoneKeyLightColorChangeFunction); - elZoneKeyLightIntensity.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('intensity','keyLight')); + elZoneKeyLightIntensity.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('keyLight','intensity')); elZoneKeyLightAmbientIntensity.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('keyLight','ambientIntensity')); var zoneKeyLightDirectionChangeFunction = createEmitGroupVec3PropertyUpdateFunction('keyLight','direction', elZoneKeyLightDirectionX, elZoneKeyLightDirectionY, elZoneKeyLightDirectionZ); elZoneKeyLightDirectionX.addEventListener('change', zoneKeyLightDirectionChangeFunction); From d2c17bfdd483371062d28475e494dda7d3b35c07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Brisset?= Date: Fri, 30 Oct 2015 12:51:30 -0700 Subject: [PATCH 062/401] DO NOT MERGE --- interface/src/Application.cpp | 10 +++++-- interface/src/avatar/AvatarActionHold.cpp | 22 +++++++++++++-- .../input-plugins/ViveControllerManager.cpp | 28 +++++++++++++++---- .../src/input-plugins/ViveControllerManager.h | 8 ++++-- libraries/shared/src/PhysicsHelpers.h | 2 +- 5 files changed, 56 insertions(+), 14 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index eebd26c3c3..8f9fc9b16e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -950,8 +950,8 @@ void Application::initializeGL() { checkFPStimer.start(1000); // call our idle function whenever we can - connect(&idleTimer, &QTimer::timeout, this, &Application::idle); - idleTimer.start(TARGET_SIM_FRAME_PERIOD_MS); + // connect(&idleTimer, &QTimer::timeout, this, &Application::idle); + // idleTimer.start(TARGET_SIM_FRAME_PERIOD_MS); _idleLoopStdev.reset(); // update before the first render @@ -1023,6 +1023,10 @@ void Application::paintGL() { if (_inPaint) { return; } + + // this is a good idea + idle(); + _inPaint = true; Finally clearFlagLambda([this] { _inPaint = false; }); @@ -2070,7 +2074,7 @@ void Application::idle() { float secondsSinceLastUpdate = timeSinceLastUpdateUs / USECS_PER_SECOND; if (isThrottled && (timeSinceLastUpdateUs / USECS_PER_MSEC) < THROTTLED_SIM_FRAME_PERIOD_MS) { - return; // bail early, we're throttled and not enough time has elapsed + //return; // bail early, we're throttled and not enough time has elapsed } _lastTimeUpdated.start(); diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 59bfd88be6..941e876075 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -35,7 +35,8 @@ AvatarActionHold::~AvatarActionHold() { qDebug() << "AvatarActionHold::~AvatarActionHold"; #endif } - +#include +#include void AvatarActionHold::updateActionWorker(float deltaTimeStep) { bool gotLock = false; glm::quat rotation; @@ -51,7 +52,24 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { glm::vec3 offset; glm::vec3 palmPosition; glm::quat palmRotation; - if (_hand == "right") { + + const auto& plugins = PluginManager::getInstance()->getInputPlugins(); + auto it = std::find_if(std::begin(plugins), std::end(plugins), [](const InputPluginPointer& plugin) { + return plugin->getName() == ViveControllerManager::NAME; + }); + + if (it != std::end(plugins)) { + const auto& vive = it->dynamicCast(); + auto index = (_hand == "right") ? 0 : 1; auto userInputMapper = DependencyManager::get(); + auto translation = extractTranslation(userInputMapper->getSensorToWorldMat()); + auto rotation = glm::quat_cast(userInputMapper->getSensorToWorldMat()); + + + const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); + const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); + palmPosition = translation + rotation * vive->getPosition(index); + palmRotation = rotation * vive->getRotation(index) * yFlip * quarterX; + } else if (_hand == "right") { palmPosition = holdingAvatar->getRightPalmPosition(); palmRotation = holdingAvatar->getRightPalmRotation(); } else { diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index bb8267b616..28e001208c 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -217,6 +217,15 @@ void ViveControllerManager::renderHand(UserInputMapper::PoseValue pose, gpu::Bat batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0); } +glm::vec3 ViveControllerManager::getPosition(int hand) const { + const mat4& mat = _trackedDevicePoseMat4[hand ? 3 : 4]; + return extractTranslation(mat); +} +glm::quat ViveControllerManager::getRotation(int hand) const { + const mat4& mat = _trackedDevicePoseMat4[hand ? 3 : 4]; + return glm::quat_cast(mat); +} + void ViveControllerManager::update(float deltaTime, bool jointsCaptured) { #ifdef Q_OS_WIN _poseStateMap.clear(); @@ -250,7 +259,7 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) { numTrackedControllers++; const mat4& mat = _trackedDevicePoseMat4[device]; - + if (!jointsCaptured) { handlePoseEvent(mat, numTrackedControllers - 1); } @@ -372,16 +381,23 @@ void ViveControllerManager::handlePoseEvent(const mat4& mat, int index) { // Q = (deltaQ * QOffset) * (yFlip * quarterTurnAboutX) // // Q = (deltaQ * inverse(deltaQForAlignedHand)) * (yFlip * quarterTurnAboutX) - + + float sign = (index == LEFT_HAND) ? -1.0f : 1.0f; + const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - float sign = (index == LEFT_HAND) ? -1.0f : 1.0f; const glm::quat signedQuaterZ = glm::angleAxis(sign * PI / 2.0f, glm::vec3(0.0f, 0.0f, 1.0f)); const glm::quat eighthX = glm::angleAxis(PI / 4.0f, glm::vec3(1.0f, 0.0f, 0.0f)); - const glm::quat offset = glm::inverse(signedQuaterZ * eighthX); - rotation = rotation * offset * yFlip * quarterX; + + + const glm::quat rotationOffset = glm::inverse(signedQuaterZ * eighthX) * yFlip * quarterX; + const glm::vec3 translationOffset = glm::vec3(sign * CONTROLLER_LENGTH_OFFSET / 2.0f, + CONTROLLER_LENGTH_OFFSET / 2.0f, + 2.0f * CONTROLLER_LENGTH_OFFSET); - position += rotation * glm::vec3(0, 0, -CONTROLLER_LENGTH_OFFSET); + position += rotation * translationOffset; + rotation = rotation * rotationOffset; + //{quat, x = 0.653281, y = -0.270598, z = 0.653281, w = 0.270598}{vec3, x = 0.0381, y = -0.0381, z = -0.1524} _poseStateMap[makeInput(JointChannel(index)).getChannel()] = UserInputMapper::PoseValue(position, rotation); } diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h index 5cae8daaf4..f6220ca97a 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h @@ -27,6 +27,8 @@ class ViveControllerManager : public InputPlugin, public InputDevice { Q_OBJECT public: + static const QString NAME; + enum JoystickAxisChannel { AXIS_Y_POS = 1U << 1, AXIS_Y_NEG = 1U << 2, @@ -74,6 +76,10 @@ public: UserInputMapper::Input makeInput(unsigned int button, int index); UserInputMapper::Input makeInput(JoystickAxisChannel axis, int index); UserInputMapper::Input makeInput(JointChannel joint); + + int getNumDevices() const; + glm::vec3 getPosition(int device) const; + glm::quat getRotation(int device) const; private: void renderHand(UserInputMapper::PoseValue pose, gpu::Batch& batch, int index); @@ -92,8 +98,6 @@ private: int _rightHandRenderID; bool _renderControllers; - - static const QString NAME; }; #endif // hifi__ViveControllerManager diff --git a/libraries/shared/src/PhysicsHelpers.h b/libraries/shared/src/PhysicsHelpers.h index 7ceafea915..3b6fccdc99 100644 --- a/libraries/shared/src/PhysicsHelpers.h +++ b/libraries/shared/src/PhysicsHelpers.h @@ -16,7 +16,7 @@ #include const int PHYSICS_ENGINE_MAX_NUM_SUBSTEPS = 6; // Bullet will start to "lose time" at 10 FPS. -const float PHYSICS_ENGINE_FIXED_SUBSTEP = 1.0f / 60.0f; +const float PHYSICS_ENGINE_FIXED_SUBSTEP = 1.0f / 90.0f; // return incremental rotation (Bullet-style) caused by angularVelocity over timeStep glm::quat computeBulletRotationStep(const glm::vec3& angularVelocity, float timeStep); From b0650cc2c180ec77777e6066a18b97d021fd681a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 30 Oct 2015 14:37:06 -0700 Subject: [PATCH 063/401] Remove accidentally commited file --- examples/map.js~ | 323 ----------------------------------------------- 1 file changed, 323 deletions(-) delete mode 100644 examples/map.js~ diff --git a/examples/map.js~ b/examples/map.js~ deleted file mode 100644 index 5a4e0f0f8c..0000000000 --- a/examples/map.js~ +++ /dev/null @@ -1,323 +0,0 @@ -Script.include("entityManager.js"); -Script.include("overlayManager.js"); - - -// Poll for nearby map data - -var entityManager = new EntityManager(); - -// From http://evanw.github.io/lightgl.js/docs/raytracer.html -function raySphereIntersection(origin, ray, center, radius) { - var offset = Vec3.subtract(origin, center); - var a = Vec3.dot(ray, ray); - // var a = ray.dot(ray); - var b = 2 * Vec3.dot(ray, offset); - // var b = 2 * ray.dot(offset); - var c = Vec3.dot(offset, offset) - radius * radius; - // var c = offset.dot(offset) - radius * radius; - var discriminant = b * b - 4 * a * c; - - if (discriminant > 0) { - return true; - } - - return null; -}; - - -Map = function(data) { - var visible = false; - - var ROOT_OFFSET = Vec3.multiply(0.3, Quat.getFront(MyAvatar.orientation)); - var ROOT_POSITION = Vec3.sum(MyAvatar.position, ROOT_OFFSET); - - var ROOT_SCALE = 0.0005; - - // Create object in objectManager - var rootObject = entityManager.addBare(); - var position = ROOT_POSITION; - rootObject.position = ROOT_POSITION; - rootObject.scale = ROOT_SCALE - Vec3.print("Position:", position); - - // Search for all nearby objects that have the userData "mapped" - // TODO Update to use the zone's bounds - var entities = Entities.findEntities(MyAvatar.position, 32000); - var mappedEntities = []; - var minCorner = { - x: 4294967295, - y: 4294967295, - z: 4294967295, - }; - var maxCorner = { - x: -4294967295, - y: -4294967295, - z: -4294967295, - }; - - for (var i = 0; i < entities.length; ++i) { - var entityID = entities[i]; - var properties = Entities.getEntityProperties(entityID); - if (properties.userData == "mapped" || properties.userData == "tracked") { - - print("Found: ", properties.name); - - minCorner.x = Math.min(minCorner.x, properties.position.x - (properties.dimensions.x / 2)); - minCorner.y = Math.min(minCorner.y, properties.position.y - (properties.dimensions.y / 2)); - minCorner.z = Math.min(minCorner.z, properties.position.z - (properties.dimensions.z / 2)); - - maxCorner.x = Math.max(maxCorner.x, properties.position.x - (properties.dimensions.x / 2)); - maxCorner.y = Math.max(maxCorner.y, properties.position.y - (properties.dimensions.y / 2)); - maxCorner.z = Math.max(maxCorner.z, properties.position.z - (properties.dimensions.z / 2)); - - } - // if (properties.userData == "mapped") { - // properties.visible = false; - // var entity = entityManager.add(properties.type, properties); - // mappedEntities.push(entity); - // } else if (properties.userData == "tracked") { - // // TODO implement tracking of objects - // } - } - - var dimensions = { - x: maxCorner.x - minCorner.x, - y: maxCorner.y - minCorner.y, - z: maxCorner.z - minCorner.z, - }; - Vec3.print("dims", dimensions); - - var center = { - x: minCorner.x + (dimensions.x / 2), - y: minCorner.y + (dimensions.y / 2), - z: minCorner.z + (dimensions.z / 2), - }; - Vec3.print("center", center); - - var trackedEntities = []; - var waypointEntities = []; - for (var i = 0; i < entities.length; ++i) { - var entityID = entities[i]; - var properties = Entities.getEntityProperties(entityID); - var mapData = null; - try { - var data = JSON.parse(properties.userData.replace(/(\r\n|\n|\r)/gm,"")); - mapData = data.mapData; - } catch (e) { - print("Caught: ", properties.name); - } - - if (mapData) { - print("Creating copy of", properties.name); - properties.name += " (COPY)"; - properties.userData = ""; - properties.visible = true; - var position = properties.position; - properties.position = Vec3.subtract(properties.position, center); - properties.position = Vec3.multiply(properties.position, ROOT_SCALE); - var extra = { }; - - if (mapData.track) { - extra.trackingEntityID= entityID; - trackedEntities.push(entity); - rootObject.addChild(entity); - } - if (mapData.waypoint) { - print("Waypoint: ", mapData.waypoint.name); - // properties.type = "Model"; - // properties.modelURL = "atp:ca49a13938376b3eb68d7b2b9189afb3f580c07b6950ea9e65b5260787204145.fbx"; - extra.waypoint = mapData.waypoint; - extra.waypoint.position = position; - } - - var entity = entityManager.add(properties.type, properties); - entity.__extra__ = extra; - if (mapData.waypoint) { - waypointEntities.push(entity); - } - mappedEntities.push(entity); - - rootObject.addChild(entity); - - } else { - // print("Not creating copy of", properties.name); - } - } - - var avatarArrowEntity = entityManager.add("Model", { - name: "You Are Here", - modelURL: "atp:ce4f0c4e491e40b73d28f2646da4f676fe9ea364cf5f1bf5615522ef6acfd80e.fbx", - position: Vec3.multiply(Vec3.subtract(MyAvatar.position, center), ROOT_SCALE), - dimensions: { x: 30, y: 100, z: 100 }, - }); - rootObject.addChild(avatarArrowEntity); - - this.isVisible = function() { - return visible; - } - - Controller.mousePressEvent.connect(mousePressEvent); - function mousePressEvent(event) { - // Entities.setZonesArePickable(false); - - var pickRay = Camera.computePickRay(event.x, event.y); - for (var i = 0; i < waypointEntities.length; ++i) { - var entity = waypointEntities[i]; - print("Checkit for hit", entity.__extra__.waypoint.name); - var result = raySphereIntersection(pickRay.origin, pickRay.direction, entity.worldPosition, 0.1);//entity.worldScale); - if (result) { - print("Pressed entity: ", entity.id); - print("Pressed waypoint: ", entity.__extra__.waypoint.name); - print("Teleporting..."); - MyAvatar.position = entity.__extra__.waypoint.position; - break; - } - } - // var result = Entities.findRayIntersection(pickRay, false); - // if (result.intersects) { - // var entity = entityManager.get(result.entityID); - // if (entity) { - // print("Pressed entity: ", entity.id); - // } - // if (entity && entity.__extra__.waypoint) { - // print("Pressed waypoint: ", entity.__extra__.waypoint.name); - // print("Teleporting..."); - // MyAvatar.position = entity.__extra__.waypoint.position; - // } - // } - - // Entities.setZonesArePickable(true); - }; - - var time = 0; - Script.update.connect(function(dt) { - time += dt; - // Update tracked entities - for (var i = 0; i < trackedEntities.length; ++i) { - entity = trackedEntities[i]; - var entityID = entity.__extra__.trackingEntityID; - var properties = Entities.getEntityProperties(entityID); - properties.position = Vec3.subtract(properties.position, center); - properties.position = Vec3.multiply(properties.position, ROOT_SCALE); - entity.position = properties.position; - } - - - var position = Vec3.subtract(MyAvatar.position, center) - position.y += 60 + (Math.sin(time) * 10); - position = Vec3.multiply(position, ROOT_SCALE); - avatarArrowEntity.position = position; - // Vec3.print("Position:", avatarArrowEntity.position); - - // rootObject.position = Vec3.sum(position, { x: 0, y: Math.sin(time) / 30, z: 0 }); - //var ROOT_OFFSET = Vec3.multiply(0.3, Quat.getFront(MyAvatar.orientation)); - //var ROOT_POSITION = Vec3.sum(MyAvatar.position, ROOT_OFFSET); - // position = ROOT_POSITION; - rootObject.position = ROOT_POSITION; - entityManager.update(); - - // Update waypoint highlights - var pickRay = Camera.computePickRay(event.x, event.y); - for (var i = 0; i < waypointEntities.length; ++i) { - var entity = waypointEntities[i]; - print("Checkit for hit", entity.__extra__.waypoint.name); - var result = raySphereIntersection(pickRay.origin, pickRay.direction, entity.worldPosition, 0.1);//entity.worldScale); - if (result) { - print("Pressed entity: ", entity.id); - print("Pressed waypoint: ", entity.__extra__.waypoint.name); - print("Teleporting..."); - MyAvatar.position = entity.__extra__.waypoint.position; - break; - } - } - }); - - function setVisible(newValue) { - if (visible != newValue) { - visible = newValue; - - if (visible) { - } else { - } - } - } - - this.show = function() { - setVisible(true); - } - - this.hide = function() { - setVisible(false); - } -}; - -var map = null; -map = Map(mapData); - -// On press key -Controller.keyPressEvent.connect(function(event) { - if (event.text == "m") { - if (!map) { - map = Map(mapData); - } - - map.show(); - print("MAP!"); - } -}); - - - - - -var mapData = { - config: { - // World dimensions that the minimap maps to - worldDimensions: { - x: 10.0, - y: 10.0, - z: 10.0, - }, - // The center of the map should map to this location in the center of the area - worldCenter: { - x: 5.0, - y: 5.0, - z: 5.0, - }, - // Map dimensions - mapDimensions: { - x: 10.0, - y: 10.0, - z: 10.0, - }, - - // Can this be automated? Tag entities that should be included? Store in UserData? - objects: [ - { - type: "Model", - modelURL: "https://hifi-public.s3.amazonaws.com/ozan/sets/huffman_set/huffman_set.fbx", - }, - ], - }, - waypoints: [ - { - name: "Forest's Edge", - position: { - }, - }, - ], -}; - - -// entityManager = new OverlayManager(); -// entityManager = new EntityManager(); -// -// var rootEntity = entityManager.addBare(); -// -// var time = 0; -// -// -// rootEntity.scale = 0.1; -// Script.include("sfData.js"); -// rootEntity.addChild(entity); -entityManager.update(); From 017cee696151429c9df7810cfc2361144791ce36 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 2 Nov 2015 11:59:09 -0800 Subject: [PATCH 064/401] make shouldRenderLocally do the right thing --- interface/src/avatar/MyAvatar.cpp | 4 ++-- interface/src/avatar/MyAvatar.h | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b567b62747..ca57fa0e21 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -537,7 +537,7 @@ void MyAvatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { if (!_shouldRender) { return; // exit early } - + Avatar::render(renderArgs, cameraPosition); // don't display IK constraints in shadow mode @@ -1372,7 +1372,7 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, fl if (!_skeletonModel.isRenderable()) { return; // wait until all models are loaded } - + fixupModelsInScene(); // Render head so long as the camera isn't inside it diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 5f75b7cf14..4a27615f67 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -226,6 +226,7 @@ public slots: void setEnableAnimGraph(bool isEnabled); void setEnableDebugDrawBindPose(bool isEnabled); void setEnableDebugDrawAnimPose(bool isEnabled); + bool getEnableMeshVisible() const { return _skeletonModel.isVisible(); } void setEnableMeshVisible(bool isEnabled); void setAnimGraphUrl(const QString& url) { _animGraphUrl = url; } @@ -248,7 +249,7 @@ private: virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPositio) override; virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel = 0.0f) override; virtual bool shouldRenderHead(const RenderArgs* renderArgs) const override; - void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; } + void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; setEnableMeshVisible(shouldRender); } bool getShouldRenderLocally() const { return _shouldRender; } bool getDriveKeys(int key) { return _driveKeys[key] != 0.0f; }; bool isMyAvatar() const override { return true; } From 72775a7af8a6c58443edac9bd82e4b184f6741ac Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 12:12:05 -0800 Subject: [PATCH 065/401] Clean up pitching.js so the pitching machine code is separate --- examples/baseball/pitching.js | 233 ++++++++++++++++++++++++++-------- 1 file changed, 179 insertions(+), 54 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 6ec4d2df85..9d84cf7a27 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -1,6 +1,11 @@ -Script.include("line.js"); +print("Loading pitching"); +//Script.include("../libraries/line.js"); +Script.include("https://raw.githubusercontent.com/huffman/hifi/line-js/examples/libraries/line.js"); + +// These are hard-coded to the relevant entity IDs on the sport server +var DISTANCE_BILLBOARD_ENTITY_ID = "{faa88b15-5b85-408c-ae07-a31e5a5ca791}"; +var HIGH_SCORE_BILLBOARD_ENTITY_ID = "{5fe0daf5-3fc5-43e3-a4eb-81a8e840a52b}"; -var DISTANCE_BILLBOARD_ENTITY_ID = "{5fe0daf5-3fc5-43e3-a4eb-81a8e840a52b}"; var METERS_TO_FEET = 3.28084; var AUDIO = { @@ -76,6 +81,110 @@ var DISTANCE_FROM_PLATE = PITCHING_MACHINE_PROPERTIES.position.z; var PITCH_RATE = 5000; +// Return all entities with properties `properties` within radius `searchRadius` +function findEntities(properties, searchRadius) { + var entities = Entities.findEntities(MyAvatar.position, searchRadius); + var matchedEntities = []; + for (var i = 0; i < entities.length; ++i) { + var match = true; + for (var key in properties) { + if (entities[key] != properties[key]) { + // This isn't a match, move to next entity + match = false; + break; + } + } + if (match) { + matchedEntities.push(entities[i]); + } + } + + return matchedEntities; +} + +getPitchingMachine = function() { + // Search for pitching machine + var entities = findEntities({ name: PITCHING_MACHINE_PROPERTIES.name }, 100); + var pitchingMachineID = null; + + // Create if it doesn't exist + if (entities.length == 0) { + pitchingMachineID = Entities.addEntity(PITCHING_MACHINE_PROPERTIES); + } else { + pitchingMachineID = entities[0]; + } + + // Wrap with PitchingMachine object and return + return new PitchingMachine(pitchingMachineID); +} + +function PitchingMachine(pitchingMachineID) { + this.pitchingMachineID = pitchingMachineID; + this.enabled = false; + this.baseball = null; + this.injector = null; +} + +PitchingMachine.prototype = { + pitchBall: function() { + cleanupTrail(); + updateBillboard(""); + + if (!this.enabled) { + return; + } + + print("Pitching ball"); + var pitchDirection = { x: 0, y: 0, z: 1 }; + var machineProperties = Entities.getEntityProperties(this.pitchingMachineID, ["dimensions", "position", "rotation"]); + print("PROPS"); + print("props ", JSON.stringify(machineProperties)); + var pitchFromPositionBase = machineProperties.position; + var pitchFromOffset = vec3Mult(machineProperties.dimensions, PITCHING_MACHINE_OUTPUT_OFFSET_PCT); + pitchFromOffset = Vec3.multiplyQbyV(machineProperties.rotation, pitchFromOffset); + var pitchFromPosition = Vec3.sum(pitchFromPositionBase, pitchFromOffset); + var pitchDirection = Quat.getFront(machineProperties.rotation); + var ballScale = machineProperties.dimensions.x / PITCHING_MACHINE_PROPERTIES.dimensions.x; + print("Creating baseball"); + + var speed = randomFloat(BASEBALL_MIN_SPEED, BASEBALL_MAX_SPEED); + var velocity = Vec3.multiply(speed, pitchDirection); + + this.baseball = new Baseball(pitchFromPosition, velocity, ballScale); + Vec3.print("vel", velocity); + Vec3.print("pos", pitchFromPosition); + + if (!this.injector) { + this.injector = Audio.playSound(pitchSound, { + position: pitchFromPosition, + volume: 1.0 + }); + } else { + this.injector.restart(); + } + print("Created baseball"); + }, + start: function() { + print("Starting Pitching Machine"); + this.enabled = true; + }, + stop: function() { + print("Stopping Pitching Machine"); + this.enabled = false; + }, + update: function(dt) { + if (this.baseball) { + this.baseball.update(dt); + if (this.baseball.finished()) { + print("BALL IS FINISHED"); + this.baseball = null; + var self = this; + Script.setTimeout(function() { self.pitchBall() }, 3000); + } + } + } +}; + var BASEBALL_MODEL_URL = "atp:7185099f1f650600ca187222573a88200aeb835454bd2f578f12c7fb4fd190fa.fbx"; var BASEBALL_MIN_SPEED = 2.7; var BASEBALL_MAX_SPEED = 5.7; @@ -111,10 +220,9 @@ var BASEBALL_PROPERTIES = { friction: 0.0, friction: 0.5, lifetime: 20, - //collisionSoundURL: PITCH_THUNK_SOUND_URL, gravity: { x: 0, - y: 0,//-9.8, + y: 0, z: 0 } }; @@ -127,11 +235,6 @@ var BASEBALL_STATE = { }; -var pitchingMachineID = Entities.addEntity(PITCHING_MACHINE_PROPERTIES); - -var pitchFromPosition = { x: 0, y: 1.0, z: 0 }; -var pitchDirection = { x: 0, y: 0, z: 1 }; - function shallowCopy(obj) { var copy = {} for (var key in obj) { @@ -186,9 +289,41 @@ function orientationOf(vector) { return Quat.multiply(yaw, pitch); } -var injector = null; +var ACCELERATION_SPREAD = 0.35; -var ACCELERATION_SPREAD = 10.15; +var TRAIL_COLOR = { red: 128, green: 255, blue: 89 }; +var TRAIL_LIFETIME = 20; + +function ObjectTrail(entityID, startPosition) { + this.entityID = entityID; + this.line = null; + var lineInterval = null; + + print("Creating Trail!"); + var lastPosition = startPosition; + trail = new InfiniteLine(startPosition, trailColor, trailLifetime); + trailInterval = Script.setInterval(function() { + var properties = Entities.getEntityProperties(entityID, ['position']); + if (Vec3.distance(properties.position, lastPosition)) { + Vec3.print("Adding trail", properties.position); + var strokeWidth = Math.log(1 + trail.size) * 0.05; + trail.enqueuePoint(properties.position, strokeWidth); + lastPosition = properties.position; + } + }, 50); +} + +ObjectTrail.prototype = { + destroy: function() { + if (this.line) { + Script.clearInterval(this.lineInterval); + this.lineInterval = null; + + this.line.destroy(); + this.line = null; + } + } +}; var trail = null; var trailInterval = null; @@ -205,12 +340,15 @@ function cleanupTrail() { function setupTrail(entityID, position) { cleanupTrail(); + print("Creating Trail!"); var lastPosition = position; - trail = new InfiniteLine(position, { red: 255, green: 128, blue: 89 }); + trail = new InfiniteLine(position, { red: 128, green: 255, blue: 89 }, 20); trailInterval = Script.setInterval(function() { var properties = Entities.getEntityProperties(entityID, ['position']); if (Vec3.distance(properties.position, lastPosition)) { - trail.enqueuePoint(properties.position); + Vec3.print("Adding trail", properties.position); + var strokeWidth = Math.log(1 + trail.size) * 0.05; + trail.enqueuePoint(properties.position, strokeWidth); lastPosition = properties.position; } }, 50); @@ -228,8 +366,8 @@ function Baseball(position, velocity, ballScale) { properties.dimensions = Vec3.multiply(ballScale, properties.dimensions); /* properties.gravity = { - x: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), - y: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), + x: randomFloat(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), + y: randomFloat(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), z: 0.0, }; */ @@ -246,27 +384,39 @@ function Baseball(position, velocity, ballScale) { Script.addEventHandler(this.entityID, "collisionWithEntity", function(entityA, entityB, collision) { self.collisionCallback(entityA, entityB, collision); }); - /* - if (false && Math.random() < 0.5) { + if (Math.random() < 0.5) { for (var i = 0; i < 50; i++) { Script.setTimeout(function() { Entities.editEntity(entityID, { gravity: { - x: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), - y: randomInt(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), + x: randomFloat(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), + y: randomFloat(-ACCELERATION_SPREAD, ACCELERATION_SPREAD), z: 0.0, } }) }, i * 100); } } - */ } -function updateBillboard(value) { +// Update the stadium billboard with the current distance and update the high score +// if it has been beaten. +function updateBillboard(distance) { Entities.editEntity(DISTANCE_BILLBOARD_ENTITY_ID, { - text: value, + text: distance, }); + + // If a number was passed in, let's see if it is larger than the current high score + // and update it if so. + if (!isNaN(distance)) { + var properties = Entities.getEntityProperties(HIGH_SCORE_BILLBOARD_ENTITY_ID, ["text"]); + var bestDistance = parseInt(properties.text); + if (distance > bestDistance) { + Entities.editEntity(HIGH_SCORE_BILLBOARD_ENTITY_ID, { + text: distance, + }); + } + } } Baseball.prototype = { @@ -292,7 +442,6 @@ Baseball.prototype = { if (this.timeSincePitched > 10) { print("TIMED OUT WHILE PITCHING"); this.state = BASEBALL_STATE.STRIKE; - } } }, @@ -383,33 +532,6 @@ Baseball.prototype = { var baseball = null; -function pitchBall() { - cleanupTrail(); - updateBillboard(""); - var machineProperties = Entities.getEntityProperties(pitchingMachineID, ["dimensions", "position", "rotation"]); - var pitchFromPositionBase = machineProperties.position; - var pitchFromOffset = vec3Mult(machineProperties.dimensions, PITCHING_MACHINE_OUTPUT_OFFSET_PCT); - pitchFromOffset = Vec3.multiplyQbyV(machineProperties.rotation, pitchFromOffset); - var pitchFromPosition = Vec3.sum(pitchFromPositionBase, pitchFromOffset); - var pitchDirection = Quat.getFront(machineProperties.rotation); - var ballScale = machineProperties.dimensions.x / PITCHING_MACHINE_PROPERTIES.dimensions.x; - print("Creating baseball"); - - var speed = randomFloat(BASEBALL_MIN_SPEED, BASEBALL_MAX_SPEED) - var timeToPassPlate = (DISTANCE_FROM_PLATE + 1.0) / speed; - - baseball = new Baseball(pitchFromPosition, Vec3.multiply(speed, pitchDirection), ballScale); - - if (!injector) { - injector = Audio.playSound(pitchSound, { - position: pitchFromPosition, - volume: 1.0 - }); - } else { - injector.restart(); - } -} - function update(dt) { if (baseball) { baseball.update(dt); @@ -425,7 +547,7 @@ function entityCollisionWithGround(ground, entity, collision) { var ZERO_VEC = { x: 0, y: 0, z: 0 }; var dVelocityMagnitude = Vec3.length(collision.velocityChange); var position = Entities.getEntityProperties(entity, "position").position; - var particleRadius = 0.3;//map(dVelocityMagnitude, 0.05, 3, 0.5, 2); + var particleRadius = 0.3; var speed = map(dVelocityMagnitude, 0.05, 3, 0.02, 0.09); var displayTime = 400; var orientationChange = orientationOf(collision.velocityChange); @@ -460,6 +582,9 @@ Script.scriptEnding.connect(function() { Entities.deleteEntity(pitchingMachineID); }); -//Script.setInterval(pitchBall, PITCH_RATE); -Script.update.connect(update); -pitchBall(); +//Script.update.connect(update); +//var pitchingMachine = getPitchingMachine(); +//pitchingMachine.pitchBall(); +//Script.update.connect(function(dt) { pitchingMachine.update(dt); }); + +print("Done loading pitching.js"); From 3820adf3f68da1694b911320b674fd26529dfef2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 12:12:21 -0800 Subject: [PATCH 066/401] Add bat.js --- examples/baseball/bat.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 examples/baseball/bat.js diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js new file mode 100644 index 0000000000..b04a77ec3e --- /dev/null +++ b/examples/baseball/bat.js @@ -0,0 +1,15 @@ +(function() { + Script.include("file:///c:%5CUsers%5CRyan%5Cdev%5Chifi%5Cexamples%5Cbaseball%5Cpitching.js"); + var pitchingMachine = getPitchingMachine(); + Script.update.connect(function(dt) { pitchingMachine.update(dt); }); + this.startNearGrab = function() { + print("Started near grab!"); + pitchingMachine.start(); + }; + this.releaseGrab = function() { + print("Stopped near grab!"); + if (pitchingMachine) { + pitchingMachine.stop(); + } + }; +}); From b8d90ab28e976ddc1ab86b74708028f9fad6940d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 12:12:54 -0800 Subject: [PATCH 067/401] Replace pitching.js include with relative path --- examples/baseball/bat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index b04a77ec3e..76e9a0a588 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -1,5 +1,5 @@ (function() { - Script.include("file:///c:%5CUsers%5CRyan%5Cdev%5Chifi%5Cexamples%5Cbaseball%5Cpitching.js"); + Script.include("pitching.js"); var pitchingMachine = getPitchingMachine(); Script.update.connect(function(dt) { pitchingMachine.update(dt); }); this.startNearGrab = function() { From 8eded438db046f258a906f45276428777080a92e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 14:09:24 -0800 Subject: [PATCH 068/401] Remove _controllerScriptingInterface from ScriptEngine.h --- libraries/script-engine/src/ScriptEngine.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index bd3912ea18..e67a1637c5 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -188,7 +188,6 @@ private: static bool checkSyntax(const QScriptProgram& program); static bool checkExceptions(QScriptEngine& engine, const QString& fileName); - AbstractControllerScriptingInterface* _controllerScriptingInterface; QString _fileNameString; Quat _quatLibrary; Vec3 _vec3Library; From ed610d69e029f2ea09f5d2ed9426a9982e6d644e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 2 Nov 2015 14:18:39 -0800 Subject: [PATCH 069/401] resolve conflicts merging with huffman/baseball --- libraries/script-engine/src/ScriptEngine.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 39885e313a..1ae2aa05ca 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -141,7 +141,10 @@ public: // NOTE - this is used by the TypedArray implemetation. we need to review this for thread safety ArrayBufferClass* getArrayBufferClass() { return _arrayBufferClass; } - + +public slots: + void callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler); + signals: void scriptLoaded(const QString& scriptFilename); void errorLoadingScript(const QString& scriptFilename); @@ -181,9 +184,6 @@ private: QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot); void stopTimer(QTimer* timer); - - static bool checkSyntax(const QScriptProgram& program); - static bool checkExceptions(QScriptEngine& engine, const QString& fileName); QString _fileNameString; Quat _quatLibrary; From 8b6db3b6c095b2775e66a1c409aa12185b2f8f0e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 15:13:07 -0800 Subject: [PATCH 070/401] Add shouldRenderLocally to bat.js and fix findEntities --- examples/baseball/bat.js | 2 ++ examples/baseball/pitching.js | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index 76e9a0a588..cc4629c089 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -5,11 +5,13 @@ this.startNearGrab = function() { print("Started near grab!"); pitchingMachine.start(); + MyAvatar.shouldRenderLocally = false; }; this.releaseGrab = function() { print("Stopped near grab!"); if (pitchingMachine) { pitchingMachine.stop(); } + MyAvatar.shouldRenderLocally = true; }; }); diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 9d84cf7a27..9c5654d652 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -85,10 +85,12 @@ var PITCH_RATE = 5000; function findEntities(properties, searchRadius) { var entities = Entities.findEntities(MyAvatar.position, searchRadius); var matchedEntities = []; + var keys = Object.keys(properties); for (var i = 0; i < entities.length; ++i) { var match = true; + var candidateProperties = Entities.getEntityProperties(entities[i], keys); for (var key in properties) { - if (entities[key] != properties[key]) { + if (candidateProperties[key] != properties[key]) { // This isn't a match, move to next entity match = false; break; From def8294b604c890fe04d7d1f3165477a02cd4f21 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 15:28:18 -0800 Subject: [PATCH 071/401] Fix pitching machine not starting when enabled --- examples/baseball/pitching.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 9c5654d652..47876aafdf 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -106,7 +106,7 @@ function findEntities(properties, searchRadius) { getPitchingMachine = function() { // Search for pitching machine - var entities = findEntities({ name: PITCHING_MACHINE_PROPERTIES.name }, 100); + var entities = findEntities({ name: PITCHING_MACHINE_PROPERTIES.name }, 1000); var pitchingMachineID = null; // Create if it doesn't exist @@ -183,6 +183,8 @@ PitchingMachine.prototype = { var self = this; Script.setTimeout(function() { self.pitchBall() }, 3000); } + } else if (this.enabled) { + this.pitchBall(); } } }; From 3cbcc6494f3fd210c730bf8589c1af85c4105c9f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 15:34:42 -0800 Subject: [PATCH 072/401] Update bat.js to lazy load the pitching machine --- examples/baseball/bat.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index cc4629c089..c8857095d8 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -1,8 +1,11 @@ (function() { Script.include("pitching.js"); - var pitchingMachine = getPitchingMachine(); - Script.update.connect(function(dt) { pitchingMachine.update(dt); }); + var pitchingMachine = null; this.startNearGrab = function() { + if (!pitchingMachine) { + getPitchingMachine(); + Script.update.connect(function(dt) { pitchingMachine.update(dt); }); + } print("Started near grab!"); pitchingMachine.start(); MyAvatar.shouldRenderLocally = false; From 1b673a99c03c87f15c18f9acab98d12b12853f18 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 15:59:55 -0800 Subject: [PATCH 073/401] Fix updating of distance/high score --- examples/baseball/pitching.js | 53 ++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 47876aafdf..8710a33cce 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -2,9 +2,35 @@ print("Loading pitching"); //Script.include("../libraries/line.js"); Script.include("https://raw.githubusercontent.com/huffman/hifi/line-js/examples/libraries/line.js"); +// Return all entities with properties `properties` within radius `searchRadius` +function findEntities(properties, searchRadius) { + var entities = Entities.findEntities(MyAvatar.position, searchRadius); + var matchedEntities = []; + var keys = Object.keys(properties); + for (var i = 0; i < entities.length; ++i) { + var match = true; + var candidateProperties = Entities.getEntityProperties(entities[i], keys); + for (var key in properties) { + if (candidateProperties[key] != properties[key]) { + // This isn't a match, move to next entity + match = false; + break; + } + } + if (match) { + matchedEntities.push(entities[i]); + } + } + + return matchedEntities; +} + // These are hard-coded to the relevant entity IDs on the sport server -var DISTANCE_BILLBOARD_ENTITY_ID = "{faa88b15-5b85-408c-ae07-a31e5a5ca791}"; -var HIGH_SCORE_BILLBOARD_ENTITY_ID = "{5fe0daf5-3fc5-43e3-a4eb-81a8e840a52b}"; +var DISTANCE_BILLBOARD_NAME = "CurrentScore"; +var HIGH_SCORE_BILLBOARD_NAME = "HighScore"; +var DISTANCE_BILLBOARD_ENTITY_ID = findEntities({name: DISTANCE_BILLBOARD_NAME }, 1000)[0]; +var HIGH_SCORE_BILLBOARD_ENTITY_ID = findEntities({name: HIGH_SCORE_BILLBOARD_NAME }, 1000)[0]; +print("Distance: ", DISTANCE_BILLBOARD_ENTITY_ID) var METERS_TO_FEET = 3.28084; @@ -81,29 +107,6 @@ var DISTANCE_FROM_PLATE = PITCHING_MACHINE_PROPERTIES.position.z; var PITCH_RATE = 5000; -// Return all entities with properties `properties` within radius `searchRadius` -function findEntities(properties, searchRadius) { - var entities = Entities.findEntities(MyAvatar.position, searchRadius); - var matchedEntities = []; - var keys = Object.keys(properties); - for (var i = 0; i < entities.length; ++i) { - var match = true; - var candidateProperties = Entities.getEntityProperties(entities[i], keys); - for (var key in properties) { - if (candidateProperties[key] != properties[key]) { - // This isn't a match, move to next entity - match = false; - break; - } - } - if (match) { - matchedEntities.push(entities[i]); - } - } - - return matchedEntities; -} - getPitchingMachine = function() { // Search for pitching machine var entities = findEntities({ name: PITCHING_MACHINE_PROPERTIES.name }, 1000); From 91a13788899efc9cda4177755c640c6caa157283 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 16:09:51 -0800 Subject: [PATCH 074/401] Clean up foul/strike in pitching.js --- examples/baseball/pitching.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 8710a33cce..647ee834c2 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -133,7 +133,6 @@ function PitchingMachine(pitchingMachineID) { PitchingMachine.prototype = { pitchBall: function() { cleanupTrail(); - updateBillboard(""); if (!this.enabled) { return; @@ -171,9 +170,17 @@ PitchingMachine.prototype = { }, start: function() { print("Starting Pitching Machine"); + if (this.enabled) { + print("Already enabled") + return; + } this.enabled = true; + this.pitchBall(); }, stop: function() { + if (!this.enabled) { + return; + } print("Stopping Pitching Machine"); this.enabled = false; }, @@ -186,8 +193,6 @@ PitchingMachine.prototype = { var self = this; Script.setTimeout(function() { self.pitchBall() }, 3000); } - } else if (this.enabled) { - this.pitchBall(); } } }; @@ -312,7 +317,6 @@ function ObjectTrail(entityID, startPosition) { trailInterval = Script.setInterval(function() { var properties = Entities.getEntityProperties(entityID, ['position']); if (Vec3.distance(properties.position, lastPosition)) { - Vec3.print("Adding trail", properties.position); var strokeWidth = Math.log(1 + trail.size) * 0.05; trail.enqueuePoint(properties.position, strokeWidth); lastPosition = properties.position; @@ -505,7 +509,7 @@ Baseball.prototype = { }); }, 500); if (foul) { - updateBillboard("FOUL!"); + updateBillboard("FOUL"); print("FOUL ", yaw) this.state = BASEBALL_STATE.FOUL; playRandomSound(AUDIO.foul, { @@ -526,7 +530,7 @@ Baseball.prototype = { } else if (name == "backstop") { if (this.state == BASEBALL_STATE.PITCHING) { this.state = BASEBALL_STATE.STRIKE; - updateBillboard("STRIKE!"); + updateBillboard("STRIKE"); print("STRIKE"); playRandomSound(AUDIO.strike, { position: myPosition, From 31d92fd90ab37a482de3db966d77f419855df172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Brisset?= Date: Fri, 30 Oct 2015 12:51:30 -0700 Subject: [PATCH 075/401] Baseball test code --- interface/src/Application.cpp | 10 +++++-- interface/src/avatar/AvatarActionHold.cpp | 22 +++++++++++++-- .../input-plugins/ViveControllerManager.cpp | 28 +++++++++++++++---- .../src/input-plugins/ViveControllerManager.h | 8 ++++-- libraries/shared/src/PhysicsHelpers.h | 2 +- 5 files changed, 56 insertions(+), 14 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index eebd26c3c3..8f9fc9b16e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -950,8 +950,8 @@ void Application::initializeGL() { checkFPStimer.start(1000); // call our idle function whenever we can - connect(&idleTimer, &QTimer::timeout, this, &Application::idle); - idleTimer.start(TARGET_SIM_FRAME_PERIOD_MS); + // connect(&idleTimer, &QTimer::timeout, this, &Application::idle); + // idleTimer.start(TARGET_SIM_FRAME_PERIOD_MS); _idleLoopStdev.reset(); // update before the first render @@ -1023,6 +1023,10 @@ void Application::paintGL() { if (_inPaint) { return; } + + // this is a good idea + idle(); + _inPaint = true; Finally clearFlagLambda([this] { _inPaint = false; }); @@ -2070,7 +2074,7 @@ void Application::idle() { float secondsSinceLastUpdate = timeSinceLastUpdateUs / USECS_PER_SECOND; if (isThrottled && (timeSinceLastUpdateUs / USECS_PER_MSEC) < THROTTLED_SIM_FRAME_PERIOD_MS) { - return; // bail early, we're throttled and not enough time has elapsed + //return; // bail early, we're throttled and not enough time has elapsed } _lastTimeUpdated.start(); diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 59bfd88be6..941e876075 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -35,7 +35,8 @@ AvatarActionHold::~AvatarActionHold() { qDebug() << "AvatarActionHold::~AvatarActionHold"; #endif } - +#include +#include void AvatarActionHold::updateActionWorker(float deltaTimeStep) { bool gotLock = false; glm::quat rotation; @@ -51,7 +52,24 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { glm::vec3 offset; glm::vec3 palmPosition; glm::quat palmRotation; - if (_hand == "right") { + + const auto& plugins = PluginManager::getInstance()->getInputPlugins(); + auto it = std::find_if(std::begin(plugins), std::end(plugins), [](const InputPluginPointer& plugin) { + return plugin->getName() == ViveControllerManager::NAME; + }); + + if (it != std::end(plugins)) { + const auto& vive = it->dynamicCast(); + auto index = (_hand == "right") ? 0 : 1; auto userInputMapper = DependencyManager::get(); + auto translation = extractTranslation(userInputMapper->getSensorToWorldMat()); + auto rotation = glm::quat_cast(userInputMapper->getSensorToWorldMat()); + + + const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); + const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); + palmPosition = translation + rotation * vive->getPosition(index); + palmRotation = rotation * vive->getRotation(index) * yFlip * quarterX; + } else if (_hand == "right") { palmPosition = holdingAvatar->getRightPalmPosition(); palmRotation = holdingAvatar->getRightPalmRotation(); } else { diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index bb8267b616..28e001208c 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -217,6 +217,15 @@ void ViveControllerManager::renderHand(UserInputMapper::PoseValue pose, gpu::Bat batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0); } +glm::vec3 ViveControllerManager::getPosition(int hand) const { + const mat4& mat = _trackedDevicePoseMat4[hand ? 3 : 4]; + return extractTranslation(mat); +} +glm::quat ViveControllerManager::getRotation(int hand) const { + const mat4& mat = _trackedDevicePoseMat4[hand ? 3 : 4]; + return glm::quat_cast(mat); +} + void ViveControllerManager::update(float deltaTime, bool jointsCaptured) { #ifdef Q_OS_WIN _poseStateMap.clear(); @@ -250,7 +259,7 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) { numTrackedControllers++; const mat4& mat = _trackedDevicePoseMat4[device]; - + if (!jointsCaptured) { handlePoseEvent(mat, numTrackedControllers - 1); } @@ -372,16 +381,23 @@ void ViveControllerManager::handlePoseEvent(const mat4& mat, int index) { // Q = (deltaQ * QOffset) * (yFlip * quarterTurnAboutX) // // Q = (deltaQ * inverse(deltaQForAlignedHand)) * (yFlip * quarterTurnAboutX) - + + float sign = (index == LEFT_HAND) ? -1.0f : 1.0f; + const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - float sign = (index == LEFT_HAND) ? -1.0f : 1.0f; const glm::quat signedQuaterZ = glm::angleAxis(sign * PI / 2.0f, glm::vec3(0.0f, 0.0f, 1.0f)); const glm::quat eighthX = glm::angleAxis(PI / 4.0f, glm::vec3(1.0f, 0.0f, 0.0f)); - const glm::quat offset = glm::inverse(signedQuaterZ * eighthX); - rotation = rotation * offset * yFlip * quarterX; + + + const glm::quat rotationOffset = glm::inverse(signedQuaterZ * eighthX) * yFlip * quarterX; + const glm::vec3 translationOffset = glm::vec3(sign * CONTROLLER_LENGTH_OFFSET / 2.0f, + CONTROLLER_LENGTH_OFFSET / 2.0f, + 2.0f * CONTROLLER_LENGTH_OFFSET); - position += rotation * glm::vec3(0, 0, -CONTROLLER_LENGTH_OFFSET); + position += rotation * translationOffset; + rotation = rotation * rotationOffset; + //{quat, x = 0.653281, y = -0.270598, z = 0.653281, w = 0.270598}{vec3, x = 0.0381, y = -0.0381, z = -0.1524} _poseStateMap[makeInput(JointChannel(index)).getChannel()] = UserInputMapper::PoseValue(position, rotation); } diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h index 5cae8daaf4..f6220ca97a 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h @@ -27,6 +27,8 @@ class ViveControllerManager : public InputPlugin, public InputDevice { Q_OBJECT public: + static const QString NAME; + enum JoystickAxisChannel { AXIS_Y_POS = 1U << 1, AXIS_Y_NEG = 1U << 2, @@ -74,6 +76,10 @@ public: UserInputMapper::Input makeInput(unsigned int button, int index); UserInputMapper::Input makeInput(JoystickAxisChannel axis, int index); UserInputMapper::Input makeInput(JointChannel joint); + + int getNumDevices() const; + glm::vec3 getPosition(int device) const; + glm::quat getRotation(int device) const; private: void renderHand(UserInputMapper::PoseValue pose, gpu::Batch& batch, int index); @@ -92,8 +98,6 @@ private: int _rightHandRenderID; bool _renderControllers; - - static const QString NAME; }; #endif // hifi__ViveControllerManager diff --git a/libraries/shared/src/PhysicsHelpers.h b/libraries/shared/src/PhysicsHelpers.h index 7ceafea915..3b6fccdc99 100644 --- a/libraries/shared/src/PhysicsHelpers.h +++ b/libraries/shared/src/PhysicsHelpers.h @@ -16,7 +16,7 @@ #include const int PHYSICS_ENGINE_MAX_NUM_SUBSTEPS = 6; // Bullet will start to "lose time" at 10 FPS. -const float PHYSICS_ENGINE_FIXED_SUBSTEP = 1.0f / 60.0f; +const float PHYSICS_ENGINE_FIXED_SUBSTEP = 1.0f / 90.0f; // return incremental rotation (Bullet-style) caused by angularVelocity over timeStep glm::quat computeBulletRotationStep(const glm::vec3& angularVelocity, float timeStep); From 01bbd3665e2cdcb78a4770b0e7ca5da88e80915f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 30 Oct 2015 14:37:06 -0700 Subject: [PATCH 076/401] Remove accidentally commited file --- examples/map.js~ | 323 ----------------------------------------------- 1 file changed, 323 deletions(-) delete mode 100644 examples/map.js~ diff --git a/examples/map.js~ b/examples/map.js~ deleted file mode 100644 index 5a4e0f0f8c..0000000000 --- a/examples/map.js~ +++ /dev/null @@ -1,323 +0,0 @@ -Script.include("entityManager.js"); -Script.include("overlayManager.js"); - - -// Poll for nearby map data - -var entityManager = new EntityManager(); - -// From http://evanw.github.io/lightgl.js/docs/raytracer.html -function raySphereIntersection(origin, ray, center, radius) { - var offset = Vec3.subtract(origin, center); - var a = Vec3.dot(ray, ray); - // var a = ray.dot(ray); - var b = 2 * Vec3.dot(ray, offset); - // var b = 2 * ray.dot(offset); - var c = Vec3.dot(offset, offset) - radius * radius; - // var c = offset.dot(offset) - radius * radius; - var discriminant = b * b - 4 * a * c; - - if (discriminant > 0) { - return true; - } - - return null; -}; - - -Map = function(data) { - var visible = false; - - var ROOT_OFFSET = Vec3.multiply(0.3, Quat.getFront(MyAvatar.orientation)); - var ROOT_POSITION = Vec3.sum(MyAvatar.position, ROOT_OFFSET); - - var ROOT_SCALE = 0.0005; - - // Create object in objectManager - var rootObject = entityManager.addBare(); - var position = ROOT_POSITION; - rootObject.position = ROOT_POSITION; - rootObject.scale = ROOT_SCALE - Vec3.print("Position:", position); - - // Search for all nearby objects that have the userData "mapped" - // TODO Update to use the zone's bounds - var entities = Entities.findEntities(MyAvatar.position, 32000); - var mappedEntities = []; - var minCorner = { - x: 4294967295, - y: 4294967295, - z: 4294967295, - }; - var maxCorner = { - x: -4294967295, - y: -4294967295, - z: -4294967295, - }; - - for (var i = 0; i < entities.length; ++i) { - var entityID = entities[i]; - var properties = Entities.getEntityProperties(entityID); - if (properties.userData == "mapped" || properties.userData == "tracked") { - - print("Found: ", properties.name); - - minCorner.x = Math.min(minCorner.x, properties.position.x - (properties.dimensions.x / 2)); - minCorner.y = Math.min(minCorner.y, properties.position.y - (properties.dimensions.y / 2)); - minCorner.z = Math.min(minCorner.z, properties.position.z - (properties.dimensions.z / 2)); - - maxCorner.x = Math.max(maxCorner.x, properties.position.x - (properties.dimensions.x / 2)); - maxCorner.y = Math.max(maxCorner.y, properties.position.y - (properties.dimensions.y / 2)); - maxCorner.z = Math.max(maxCorner.z, properties.position.z - (properties.dimensions.z / 2)); - - } - // if (properties.userData == "mapped") { - // properties.visible = false; - // var entity = entityManager.add(properties.type, properties); - // mappedEntities.push(entity); - // } else if (properties.userData == "tracked") { - // // TODO implement tracking of objects - // } - } - - var dimensions = { - x: maxCorner.x - minCorner.x, - y: maxCorner.y - minCorner.y, - z: maxCorner.z - minCorner.z, - }; - Vec3.print("dims", dimensions); - - var center = { - x: minCorner.x + (dimensions.x / 2), - y: minCorner.y + (dimensions.y / 2), - z: minCorner.z + (dimensions.z / 2), - }; - Vec3.print("center", center); - - var trackedEntities = []; - var waypointEntities = []; - for (var i = 0; i < entities.length; ++i) { - var entityID = entities[i]; - var properties = Entities.getEntityProperties(entityID); - var mapData = null; - try { - var data = JSON.parse(properties.userData.replace(/(\r\n|\n|\r)/gm,"")); - mapData = data.mapData; - } catch (e) { - print("Caught: ", properties.name); - } - - if (mapData) { - print("Creating copy of", properties.name); - properties.name += " (COPY)"; - properties.userData = ""; - properties.visible = true; - var position = properties.position; - properties.position = Vec3.subtract(properties.position, center); - properties.position = Vec3.multiply(properties.position, ROOT_SCALE); - var extra = { }; - - if (mapData.track) { - extra.trackingEntityID= entityID; - trackedEntities.push(entity); - rootObject.addChild(entity); - } - if (mapData.waypoint) { - print("Waypoint: ", mapData.waypoint.name); - // properties.type = "Model"; - // properties.modelURL = "atp:ca49a13938376b3eb68d7b2b9189afb3f580c07b6950ea9e65b5260787204145.fbx"; - extra.waypoint = mapData.waypoint; - extra.waypoint.position = position; - } - - var entity = entityManager.add(properties.type, properties); - entity.__extra__ = extra; - if (mapData.waypoint) { - waypointEntities.push(entity); - } - mappedEntities.push(entity); - - rootObject.addChild(entity); - - } else { - // print("Not creating copy of", properties.name); - } - } - - var avatarArrowEntity = entityManager.add("Model", { - name: "You Are Here", - modelURL: "atp:ce4f0c4e491e40b73d28f2646da4f676fe9ea364cf5f1bf5615522ef6acfd80e.fbx", - position: Vec3.multiply(Vec3.subtract(MyAvatar.position, center), ROOT_SCALE), - dimensions: { x: 30, y: 100, z: 100 }, - }); - rootObject.addChild(avatarArrowEntity); - - this.isVisible = function() { - return visible; - } - - Controller.mousePressEvent.connect(mousePressEvent); - function mousePressEvent(event) { - // Entities.setZonesArePickable(false); - - var pickRay = Camera.computePickRay(event.x, event.y); - for (var i = 0; i < waypointEntities.length; ++i) { - var entity = waypointEntities[i]; - print("Checkit for hit", entity.__extra__.waypoint.name); - var result = raySphereIntersection(pickRay.origin, pickRay.direction, entity.worldPosition, 0.1);//entity.worldScale); - if (result) { - print("Pressed entity: ", entity.id); - print("Pressed waypoint: ", entity.__extra__.waypoint.name); - print("Teleporting..."); - MyAvatar.position = entity.__extra__.waypoint.position; - break; - } - } - // var result = Entities.findRayIntersection(pickRay, false); - // if (result.intersects) { - // var entity = entityManager.get(result.entityID); - // if (entity) { - // print("Pressed entity: ", entity.id); - // } - // if (entity && entity.__extra__.waypoint) { - // print("Pressed waypoint: ", entity.__extra__.waypoint.name); - // print("Teleporting..."); - // MyAvatar.position = entity.__extra__.waypoint.position; - // } - // } - - // Entities.setZonesArePickable(true); - }; - - var time = 0; - Script.update.connect(function(dt) { - time += dt; - // Update tracked entities - for (var i = 0; i < trackedEntities.length; ++i) { - entity = trackedEntities[i]; - var entityID = entity.__extra__.trackingEntityID; - var properties = Entities.getEntityProperties(entityID); - properties.position = Vec3.subtract(properties.position, center); - properties.position = Vec3.multiply(properties.position, ROOT_SCALE); - entity.position = properties.position; - } - - - var position = Vec3.subtract(MyAvatar.position, center) - position.y += 60 + (Math.sin(time) * 10); - position = Vec3.multiply(position, ROOT_SCALE); - avatarArrowEntity.position = position; - // Vec3.print("Position:", avatarArrowEntity.position); - - // rootObject.position = Vec3.sum(position, { x: 0, y: Math.sin(time) / 30, z: 0 }); - //var ROOT_OFFSET = Vec3.multiply(0.3, Quat.getFront(MyAvatar.orientation)); - //var ROOT_POSITION = Vec3.sum(MyAvatar.position, ROOT_OFFSET); - // position = ROOT_POSITION; - rootObject.position = ROOT_POSITION; - entityManager.update(); - - // Update waypoint highlights - var pickRay = Camera.computePickRay(event.x, event.y); - for (var i = 0; i < waypointEntities.length; ++i) { - var entity = waypointEntities[i]; - print("Checkit for hit", entity.__extra__.waypoint.name); - var result = raySphereIntersection(pickRay.origin, pickRay.direction, entity.worldPosition, 0.1);//entity.worldScale); - if (result) { - print("Pressed entity: ", entity.id); - print("Pressed waypoint: ", entity.__extra__.waypoint.name); - print("Teleporting..."); - MyAvatar.position = entity.__extra__.waypoint.position; - break; - } - } - }); - - function setVisible(newValue) { - if (visible != newValue) { - visible = newValue; - - if (visible) { - } else { - } - } - } - - this.show = function() { - setVisible(true); - } - - this.hide = function() { - setVisible(false); - } -}; - -var map = null; -map = Map(mapData); - -// On press key -Controller.keyPressEvent.connect(function(event) { - if (event.text == "m") { - if (!map) { - map = Map(mapData); - } - - map.show(); - print("MAP!"); - } -}); - - - - - -var mapData = { - config: { - // World dimensions that the minimap maps to - worldDimensions: { - x: 10.0, - y: 10.0, - z: 10.0, - }, - // The center of the map should map to this location in the center of the area - worldCenter: { - x: 5.0, - y: 5.0, - z: 5.0, - }, - // Map dimensions - mapDimensions: { - x: 10.0, - y: 10.0, - z: 10.0, - }, - - // Can this be automated? Tag entities that should be included? Store in UserData? - objects: [ - { - type: "Model", - modelURL: "https://hifi-public.s3.amazonaws.com/ozan/sets/huffman_set/huffman_set.fbx", - }, - ], - }, - waypoints: [ - { - name: "Forest's Edge", - position: { - }, - }, - ], -}; - - -// entityManager = new OverlayManager(); -// entityManager = new EntityManager(); -// -// var rootEntity = entityManager.addBare(); -// -// var time = 0; -// -// -// rootEntity.scale = 0.1; -// Script.include("sfData.js"); -// rootEntity.addChild(entity); -entityManager.update(); From 57a68edaa3befacdc76e83108164e55f8495141e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 2 Nov 2015 14:18:39 -0800 Subject: [PATCH 077/401] resolve conflicts merging with huffman/baseball --- libraries/script-engine/src/ScriptEngine.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index b0595cf3c6..8ec06dd89d 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -141,10 +141,10 @@ public: // NOTE - this is used by the TypedArray implemetation. we need to review this for thread safety ArrayBufferClass* getArrayBufferClass() { return _arrayBufferClass; } - + public slots: void callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler); - + signals: void scriptLoaded(const QString& scriptFilename); void errorLoadingScript(const QString& scriptFilename); @@ -184,7 +184,7 @@ private: QObject* setupTimerWithInterval(const QScriptValue& function, int intervalMS, bool isSingleShot); void stopTimer(QTimer* timer); - + QString _fileNameString; Quat _quatLibrary; Vec3 _vec3Library; From f18d8f5fbbc3285d3487acc368189b3638d7f705 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 15:13:07 -0800 Subject: [PATCH 078/401] Add shouldRenderLocally to bat.js and fix findEntities --- examples/baseball/bat.js | 2 ++ examples/baseball/pitching.js | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index 76e9a0a588..cc4629c089 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -5,11 +5,13 @@ this.startNearGrab = function() { print("Started near grab!"); pitchingMachine.start(); + MyAvatar.shouldRenderLocally = false; }; this.releaseGrab = function() { print("Stopped near grab!"); if (pitchingMachine) { pitchingMachine.stop(); } + MyAvatar.shouldRenderLocally = true; }; }); diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 9d84cf7a27..9c5654d652 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -85,10 +85,12 @@ var PITCH_RATE = 5000; function findEntities(properties, searchRadius) { var entities = Entities.findEntities(MyAvatar.position, searchRadius); var matchedEntities = []; + var keys = Object.keys(properties); for (var i = 0; i < entities.length; ++i) { var match = true; + var candidateProperties = Entities.getEntityProperties(entities[i], keys); for (var key in properties) { - if (entities[key] != properties[key]) { + if (candidateProperties[key] != properties[key]) { // This isn't a match, move to next entity match = false; break; From d535bb6ed8272fdb01e7112272621668ea756be3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 15:28:18 -0800 Subject: [PATCH 079/401] Fix pitching machine not starting when enabled --- examples/baseball/pitching.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 9c5654d652..47876aafdf 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -106,7 +106,7 @@ function findEntities(properties, searchRadius) { getPitchingMachine = function() { // Search for pitching machine - var entities = findEntities({ name: PITCHING_MACHINE_PROPERTIES.name }, 100); + var entities = findEntities({ name: PITCHING_MACHINE_PROPERTIES.name }, 1000); var pitchingMachineID = null; // Create if it doesn't exist @@ -183,6 +183,8 @@ PitchingMachine.prototype = { var self = this; Script.setTimeout(function() { self.pitchBall() }, 3000); } + } else if (this.enabled) { + this.pitchBall(); } } }; From bb0ce67f6b103b671e1598f6cbaf1291c10e21ac Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 15:34:42 -0800 Subject: [PATCH 080/401] Update bat.js to lazy load the pitching machine --- examples/baseball/bat.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index cc4629c089..c8857095d8 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -1,8 +1,11 @@ (function() { Script.include("pitching.js"); - var pitchingMachine = getPitchingMachine(); - Script.update.connect(function(dt) { pitchingMachine.update(dt); }); + var pitchingMachine = null; this.startNearGrab = function() { + if (!pitchingMachine) { + getPitchingMachine(); + Script.update.connect(function(dt) { pitchingMachine.update(dt); }); + } print("Started near grab!"); pitchingMachine.start(); MyAvatar.shouldRenderLocally = false; From 14cdc5801e9f76e57e641ec60a7faf6289f4d265 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 15:59:55 -0800 Subject: [PATCH 081/401] Fix updating of distance/high score --- examples/baseball/pitching.js | 53 ++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 47876aafdf..8710a33cce 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -2,9 +2,35 @@ print("Loading pitching"); //Script.include("../libraries/line.js"); Script.include("https://raw.githubusercontent.com/huffman/hifi/line-js/examples/libraries/line.js"); +// Return all entities with properties `properties` within radius `searchRadius` +function findEntities(properties, searchRadius) { + var entities = Entities.findEntities(MyAvatar.position, searchRadius); + var matchedEntities = []; + var keys = Object.keys(properties); + for (var i = 0; i < entities.length; ++i) { + var match = true; + var candidateProperties = Entities.getEntityProperties(entities[i], keys); + for (var key in properties) { + if (candidateProperties[key] != properties[key]) { + // This isn't a match, move to next entity + match = false; + break; + } + } + if (match) { + matchedEntities.push(entities[i]); + } + } + + return matchedEntities; +} + // These are hard-coded to the relevant entity IDs on the sport server -var DISTANCE_BILLBOARD_ENTITY_ID = "{faa88b15-5b85-408c-ae07-a31e5a5ca791}"; -var HIGH_SCORE_BILLBOARD_ENTITY_ID = "{5fe0daf5-3fc5-43e3-a4eb-81a8e840a52b}"; +var DISTANCE_BILLBOARD_NAME = "CurrentScore"; +var HIGH_SCORE_BILLBOARD_NAME = "HighScore"; +var DISTANCE_BILLBOARD_ENTITY_ID = findEntities({name: DISTANCE_BILLBOARD_NAME }, 1000)[0]; +var HIGH_SCORE_BILLBOARD_ENTITY_ID = findEntities({name: HIGH_SCORE_BILLBOARD_NAME }, 1000)[0]; +print("Distance: ", DISTANCE_BILLBOARD_ENTITY_ID) var METERS_TO_FEET = 3.28084; @@ -81,29 +107,6 @@ var DISTANCE_FROM_PLATE = PITCHING_MACHINE_PROPERTIES.position.z; var PITCH_RATE = 5000; -// Return all entities with properties `properties` within radius `searchRadius` -function findEntities(properties, searchRadius) { - var entities = Entities.findEntities(MyAvatar.position, searchRadius); - var matchedEntities = []; - var keys = Object.keys(properties); - for (var i = 0; i < entities.length; ++i) { - var match = true; - var candidateProperties = Entities.getEntityProperties(entities[i], keys); - for (var key in properties) { - if (candidateProperties[key] != properties[key]) { - // This isn't a match, move to next entity - match = false; - break; - } - } - if (match) { - matchedEntities.push(entities[i]); - } - } - - return matchedEntities; -} - getPitchingMachine = function() { // Search for pitching machine var entities = findEntities({ name: PITCHING_MACHINE_PROPERTIES.name }, 1000); From e8b550be9fb3c84b160624a74ad29c4979368bde Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 2 Nov 2015 16:09:51 -0800 Subject: [PATCH 082/401] Clean up foul/strike in pitching.js --- examples/baseball/pitching.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 8710a33cce..647ee834c2 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -133,7 +133,6 @@ function PitchingMachine(pitchingMachineID) { PitchingMachine.prototype = { pitchBall: function() { cleanupTrail(); - updateBillboard(""); if (!this.enabled) { return; @@ -171,9 +170,17 @@ PitchingMachine.prototype = { }, start: function() { print("Starting Pitching Machine"); + if (this.enabled) { + print("Already enabled") + return; + } this.enabled = true; + this.pitchBall(); }, stop: function() { + if (!this.enabled) { + return; + } print("Stopping Pitching Machine"); this.enabled = false; }, @@ -186,8 +193,6 @@ PitchingMachine.prototype = { var self = this; Script.setTimeout(function() { self.pitchBall() }, 3000); } - } else if (this.enabled) { - this.pitchBall(); } } }; @@ -312,7 +317,6 @@ function ObjectTrail(entityID, startPosition) { trailInterval = Script.setInterval(function() { var properties = Entities.getEntityProperties(entityID, ['position']); if (Vec3.distance(properties.position, lastPosition)) { - Vec3.print("Adding trail", properties.position); var strokeWidth = Math.log(1 + trail.size) * 0.05; trail.enqueuePoint(properties.position, strokeWidth); lastPosition = properties.position; @@ -505,7 +509,7 @@ Baseball.prototype = { }); }, 500); if (foul) { - updateBillboard("FOUL!"); + updateBillboard("FOUL"); print("FOUL ", yaw) this.state = BASEBALL_STATE.FOUL; playRandomSound(AUDIO.foul, { @@ -526,7 +530,7 @@ Baseball.prototype = { } else if (name == "backstop") { if (this.state == BASEBALL_STATE.PITCHING) { this.state = BASEBALL_STATE.STRIKE; - updateBillboard("STRIKE!"); + updateBillboard("STRIKE"); print("STRIKE"); playRandomSound(AUDIO.strike, { position: myPosition, From c63fc8557cda1fa992ca12ac9134ce355f6f790c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Brisset?= Date: Tue, 3 Nov 2015 10:11:25 -0800 Subject: [PATCH 083/401] More baseball test code --- interface/src/avatar/AvatarActionHold.cpp | 53 ++++++++++--------- .../input-plugins/ViveControllerManager.cpp | 32 ++++++----- 2 files changed, 46 insertions(+), 39 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 5bec513fd4..b6e3ea408f 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -52,32 +52,35 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { glm::vec3 offset; glm::vec3 palmPosition; glm::quat palmRotation; - - const auto& plugins = PluginManager::getInstance()->getInputPlugins(); - auto it = std::find_if(std::begin(plugins), std::end(plugins), [](const InputPluginPointer& plugin) { - return plugin->getName() == ViveControllerManager::NAME; - }); - - if (it != std::end(plugins)) { - const auto& vive = it->dynamicCast(); - auto index = (_hand == "right") ? 0 : 1; + +#ifdef Q_OS_WIN + const auto& plugins = PluginManager::getInstance()->getInputPlugins(); + auto it = std::find_if(std::begin(plugins), std::end(plugins), [](const InputPluginPointer& plugin) { + return plugin->getName() == ViveControllerManager::NAME; + }); + + if (it != std::end(plugins)) { + const auto& vive = it->dynamicCast(); + auto index = (_hand == "left") ? 0 : 1; auto userInputMapper = DependencyManager::get(); - auto translation = extractTranslation(userInputMapper->getSensorToWorldMat()); - auto rotation = glm::quat_cast(userInputMapper->getSensorToWorldMat()); - - - const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); - const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - palmPosition = translation + rotation * vive->getPosition(index); - palmRotation = rotation * vive->getRotation(index) * yFlip * quarterX; - } else if (_hand == "right") { - palmPosition = holdingAvatar->getRightPalmPosition(); - palmRotation = holdingAvatar->getRightPalmRotation(); - } else { - palmPosition = holdingAvatar->getLeftPalmPosition(); - palmRotation = holdingAvatar->getLeftPalmRotation(); - } - + auto translation = extractTranslation(userInputMapper->getSensorToWorldMat()); + auto rotation = glm::quat_cast(userInputMapper->getSensorToWorldMat()); + + + const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); + const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); + palmPosition = translation + rotation * vive->getPosition(index); + palmRotation = rotation * vive->getRotation(index) * yFlip * quarterX * glm::angleAxis(PI, glm::vec3(1.0f, 0.0f, 0.0f)) * glm::angleAxis(PI_OVER_TWO, glm::vec3(0.0f, 0.0f, 1.0f)); + } else +#endif + if (_hand == "right") { + palmPosition = holdingAvatar->getRightPalmPosition(); + palmRotation = holdingAvatar->getRightPalmRotation(); + } else { + palmPosition = holdingAvatar->getLeftPalmPosition(); + palmRotation = holdingAvatar->getLeftPalmRotation(); + } + rotation = palmRotation * _relativeRotation; offset = rotation * _relativePosition; position = palmPosition + offset; diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index b8755ea2e3..f5863c6ed0 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -278,12 +278,18 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) { //qDebug() << "Trackpad: " << controllerState.rAxis[0].x << " " << controllerState.rAxis[0].y; //qDebug() << "Trigger: " << controllerState.rAxis[1].x << " " << controllerState.rAxis[1].y; for (uint32_t i = 0; i < vr::k_EButton_Max; ++i) { - auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i); - bool pressed = 0 != (controllerState.ulButtonPressed & mask); + auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i); + bool pressed = 0 != (controllerState.ulButtonPressed & mask); handleButtonEvent(i, pressed, left); } - for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) { - handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, left); + for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) { + auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)(i + vr::k_EButton_Axis0)); + bool pressed = 0 != (controllerState.ulButtonPressed & mask); + if (pressed || true) { + handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, left); + } else { + handleAxisEvent(i, 0.0f, 0.0f, left); + } } } } @@ -412,16 +418,14 @@ void ViveControllerManager::handlePoseEvent(const mat4& mat, bool left) { const glm::quat signedQuaterZ = glm::angleAxis(sign * PI / 2.0f, glm::vec3(0.0f, 0.0f, 1.0f)); const glm::quat eighthX = glm::angleAxis(PI / 4.0f, glm::vec3(1.0f, 0.0f, 0.0f)); - - const glm::quat rotationOffset = glm::inverse(signedQuaterZ * eighthX) * yFlip * quarterX; - const glm::vec3 translationOffset = glm::vec3(sign * CONTROLLER_LENGTH_OFFSET / 2.0f, - CONTROLLER_LENGTH_OFFSET / 2.0f, - 2.0f * CONTROLLER_LENGTH_OFFSET); - - position += rotation * translationOffset; - rotation = rotation * rotationOffset; - //{quat, x = 0.653281, y = -0.270598, z = 0.653281, w = 0.270598}{vec3, x = 0.0381, y = -0.0381, z = -0.1524} - + const glm::quat rotationOffset = glm::inverse(signedQuaterZ * eighthX) * yFlip * quarterX; + const glm::vec3 translationOffset = glm::vec3(sign * CONTROLLER_LENGTH_OFFSET / 2.0f, + CONTROLLER_LENGTH_OFFSET / 2.0f, + 2.0f * CONTROLLER_LENGTH_OFFSET); + + position += rotation * translationOffset; + rotation = rotation * rotationOffset; + _poseStateMap[left ? controller::LEFT_HAND : controller::RIGHT_HAND] = controller::Pose(position, rotation); } From 0508091130fff5b0c155d75989cfee49a22d2219 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 3 Nov 2015 11:37:57 -0800 Subject: [PATCH 084/401] Rebase fixes --- interface/src/avatar/AvatarActionHold.cpp | 23 ++++++++------- .../input-plugins/ViveControllerManager.cpp | 29 ++++++++++--------- .../src/input-plugins/ViveControllerManager.h | 8 +++-- libraries/script-engine/src/ScriptEngine.cpp | 8 ++--- libraries/script-engine/src/ScriptEngine.h | 2 +- 5 files changed, 38 insertions(+), 32 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index b6e3ea408f..767c60defe 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -37,17 +37,18 @@ AvatarActionHold::~AvatarActionHold() { } #include #include +#include void AvatarActionHold::updateActionWorker(float deltaTimeStep) { bool gotLock = false; glm::quat rotation; glm::vec3 position; std::shared_ptr holdingAvatar = nullptr; - + gotLock = withTryReadLock([&]{ QSharedPointer avatarManager = DependencyManager::get(); AvatarSharedPointer holdingAvatarData = avatarManager->getAvatarBySessionID(_holderID); holdingAvatar = std::static_pointer_cast(holdingAvatarData); - + if (holdingAvatar) { glm::vec3 offset; glm::vec3 palmPosition; @@ -70,23 +71,23 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); palmPosition = translation + rotation * vive->getPosition(index); - palmRotation = rotation * vive->getRotation(index) * yFlip * quarterX * glm::angleAxis(PI, glm::vec3(1.0f, 0.0f, 0.0f)) * glm::angleAxis(PI_OVER_TWO, glm::vec3(0.0f, 0.0f, 1.0f)); + palmRotation = rotation * vive->getRotation(index) * yFlip * quarterX * glm::angleAxis(PI, glm::vec3(1.0f, 0.0f, 0.0f)) * glm::angleAxis(PI_OVER_TWO, glm::vec3(0.0f, 0.0f, 1.0f)); } else #endif - if (_hand == "right") { - palmPosition = holdingAvatar->getRightPalmPosition(); - palmRotation = holdingAvatar->getRightPalmRotation(); - } else { - palmPosition = holdingAvatar->getLeftPalmPosition(); - palmRotation = holdingAvatar->getLeftPalmRotation(); - } + if (_hand == "right") { + palmPosition = holdingAvatar->getRightPalmPosition(); + palmRotation = holdingAvatar->getRightPalmRotation(); + } else { + palmPosition = holdingAvatar->getLeftPalmPosition(); + palmRotation = holdingAvatar->getLeftPalmRotation(); + } rotation = palmRotation * _relativeRotation; offset = rotation * _relativePosition; position = palmPosition + offset; } }); - + if (holdingAvatar) { if (gotLock) { gotLock = withTryWriteLock([&]{ diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index f5863c6ed0..b083d06a2a 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -223,6 +223,7 @@ void ViveControllerManager::renderHand(const controller::Pose& pose, gpu::Batch& batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0); } +#ifdef Q_OS_WIN glm::vec3 ViveControllerManager::getPosition(int hand) const { const mat4& mat = _trackedDevicePoseMat4[hand ? 3 : 4]; return extractTranslation(mat); @@ -231,6 +232,7 @@ glm::quat ViveControllerManager::getRotation(int hand) const { const mat4& mat = _trackedDevicePoseMat4[hand ? 3 : 4]; return glm::quat_cast(mat); } +#endif void ViveControllerManager::update(float deltaTime, bool jointsCaptured) { #ifdef Q_OS_WIN @@ -278,22 +280,22 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) { //qDebug() << "Trackpad: " << controllerState.rAxis[0].x << " " << controllerState.rAxis[0].y; //qDebug() << "Trigger: " << controllerState.rAxis[1].x << " " << controllerState.rAxis[1].y; for (uint32_t i = 0; i < vr::k_EButton_Max; ++i) { - auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i); - bool pressed = 0 != (controllerState.ulButtonPressed & mask); + auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i); + bool pressed = 0 != (controllerState.ulButtonPressed & mask); handleButtonEvent(i, pressed, left); } - for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) { - auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)(i + vr::k_EButton_Axis0)); - bool pressed = 0 != (controllerState.ulButtonPressed & mask); - if (pressed || true) { - handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, left); - } else { - handleAxisEvent(i, 0.0f, 0.0f, left); - } + for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) { + auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)(i + vr::k_EButton_Axis0)); + bool pressed = 0 != (controllerState.ulButtonPressed & mask); + if (pressed || true) { + handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, left); + } else { + handleAxisEvent(i, 0.0f, 0.0f, left); + } } } } - + auto userInputMapper = DependencyManager::get(); if (numTrackedControllers == 0) { @@ -412,12 +414,13 @@ void ViveControllerManager::handlePoseEvent(const mat4& mat, bool left) { // Q = (deltaQ * inverse(deltaQForAlignedHand)) * (yFlip * quarterTurnAboutX) float sign = left ? -1.0f : 1.0f; - + const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - const glm::quat signedQuaterZ = glm::angleAxis(sign * PI / 2.0f, glm::vec3(0.0f, 0.0f, 1.0f)); + const glm::quat signedQuaterZ = glm::angleAxis(sign * PI / 2.0f, glm::vec3(0.0f, 0.0f, 1.0f)); const glm::quat eighthX = glm::angleAxis(PI / 4.0f, glm::vec3(1.0f, 0.0f, 0.0f)); + const glm::quat rotationOffset = glm::inverse(signedQuaterZ * eighthX) * yFlip * quarterX; const glm::vec3 translationOffset = glm::vec3(sign * CONTROLLER_LENGTH_OFFSET / 2.0f, CONTROLLER_LENGTH_OFFSET / 2.0f, diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h index ad0474073c..eee6083102 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h @@ -27,8 +27,8 @@ class ViveControllerManager : public InputPlugin, public controller::InputDevice { Q_OBJECT public: - static const QString NAME; - + static const QString NAME; + ViveControllerManager(); // Plugin functions @@ -52,9 +52,11 @@ public: void setRenderControllers(bool renderControllers) { _renderControllers = renderControllers; } - int getNumDevices() const; + +#ifdef Q_OS_WIN glm::vec3 getPosition(int device) const; glm::quat getRotation(int device) const; +#endif private: void renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 4e53f6e60b..0173009995 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -367,10 +367,10 @@ void ScriptEngine::init() { registerGlobalObject("AnimationCache", DependencyManager::get().data()); qScriptRegisterMetaType(this, animVarMapToScriptValue, animVarMapFromScriptValue); qScriptRegisterMetaType(this, resultHandlerToScriptValue, resultHandlerFromScriptValue); - + // constants globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE))); - + auto scriptingInterface = DependencyManager::get(); registerGlobalObject("Controller", scriptingInterface.data()); UserInputMapper::registerControllerTypes(this); @@ -706,7 +706,7 @@ void ScriptEngine::run() { } } lastUpdate = now; - + // Debug and clear exceptions hadUncaughtExceptions(*this, _fileNameString); } @@ -1263,4 +1263,4 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS entityScript.property(methodName).call(entityScript, args); } } -} \ No newline at end of file +} diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 8ec06dd89d..1ae2aa05ca 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -205,4 +205,4 @@ private: }; -#endif // hifi_ScriptEngine_h \ No newline at end of file +#endif // hifi_ScriptEngine_h From 9be8d1edf94ac4bf9417d5581817cfc4836b725e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 3 Nov 2015 11:44:33 -0800 Subject: [PATCH 085/401] Remove now unecessary vive hack --- .../src/input-plugins/ViveControllerManager.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index b083d06a2a..fb0021d7d5 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -285,13 +285,7 @@ void ViveControllerManager::update(float deltaTime, bool jointsCaptured) { handleButtonEvent(i, pressed, left); } for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) { - auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)(i + vr::k_EButton_Axis0)); - bool pressed = 0 != (controllerState.ulButtonPressed & mask); - if (pressed || true) { - handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, left); - } else { - handleAxisEvent(i, 0.0f, 0.0f, left); - } + handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, left); } } } From 3056432b0c8ebea30cce79d6541c9b2dbcc005a3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 3 Nov 2015 12:14:04 -0800 Subject: [PATCH 086/401] Add fireworks --- examples/baseball/firework.js | 144 ++++++++++++++++++++++++++++++++++ examples/baseball/utils.js | 35 +++++++++ 2 files changed, 179 insertions(+) create mode 100644 examples/baseball/firework.js create mode 100644 examples/baseball/utils.js diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js new file mode 100644 index 0000000000..8e7a9637ec --- /dev/null +++ b/examples/baseball/firework.js @@ -0,0 +1,144 @@ +Script.include("utils.js"); + +var emitters = []; + +var smokeTrailSettings = { + "name":"ParticlesTest Emitter", + "type": "ParticleEffect", + "color":{"red":205,"green":84.41176470588235,"blue":84.41176470588235}, + "maxParticles":1000, + "velocity": { x: 0, y: 18.0, z: 0 }, + "lifetime": 20, + "lifespan":3, + "emitRate":1000, + "emitSpeed":0.5, + "speedSpread":1, + "emitOrientation":{"x":-0.2,"y":0,"z":0,"w":0.7000000000000001}, + "emitDimensions":{"x":0,"y":0,"z":0}, + "emitRadiusStart":0.5, + "polarStart":1, + "polarFinish":1, + "azimuthStart":-Math.PI, + "azimuthFinish":Math.PI, + "emitAcceleration":{"x":0,"y":-0.70000001192092896,"z":0}, + "accelerationSpread":{"x":0,"y":0,"z":0}, + "particleRadius":0.03999999910593033, + "radiusSpread":0, + "radiusStart":0.13999999910593033, + "radiusFinish":0.14, + "colorSpread":{"red":0,"green":0,"blue":0}, + "colorStart":{"red":255,"green":255,"blue":255}, + "colorFinish":{"red":255,"green":255,"blue":255}, + "alpha":1, + "alphaSpread":0, + "alphaStart":0, + "alphaFinish":1, + "textures":"https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png" +}; + +var fireworkSettings = { + "name":"ParticlesTest Emitter", + "type": "ParticleEffect", + "color":{"red":205,"green":84.41176470588235,"blue":84.41176470588235}, + "maxParticles":1000, + "lifetime": 20, + "lifespan":6, + "emitRate":1000, + "emitSpeed":1.5, + "speedSpread":1.0, + "emitOrientation":{"x":-0.2,"y":0,"z":0,"w":0.7000000000000001}, + "emitDimensions":{"x":0,"y":0,"z":0}, + "emitRadiusStart":0.5, + "polarStart":1, + "polarFinish":1.2, + "azimuthStart":-Math.PI, + "azimuthFinish":Math.PI, + "emitAcceleration":{"x":0,"y":-0.70000001192092896,"z":0}, + "accelerationSpread":{"x":0,"y":0,"z":0}, + "particleRadius":0.03999999910593033, + "radiusSpread":0, + "radiusStart":0.13999999910593033, + "radiusFinish":0.14, + "colorSpread":{"red":0,"green":0,"blue":0}, + "colorStart":{"red":255,"green":255,"blue":255}, + "colorFinish":{"red":255,"green":255,"blue":255}, + "alpha":1, + "alphaSpread":0, + "alphaStart":0, + "alphaFinish":1, + "textures":"https://hifi-public.s3.amazonaws.com/alan/Particles/spark_2.png", + //"textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/spark.png" +}; + +var popSounds = getSounds([ + "atp:a2bf79c95fe74c2c6c9188acc7230f7cd1b0f6008f2c81954ecd93eca0497ec6.wav", + "atp:901067ebc2cda4c0d86ec02fcca2ed901e85f9097ad68bbde78b4cad8eaf2ed7.wav", + "atp:830312930577cb1ea36ba2d743e957debbacceb441b20addead5a6faa05a3771.wav", + "atp:62e80d0a9f084cf731bcc66ca6e9020ee88587417071a281eee3167307b53560.wav" +]); +var fireSounds = getSounds([ + "atp:ee6afe565576c4546c6d6cd89c1af532484c9b60ab30574d6b40c2df022f7260.wav", + "atp:91ef19ba1c78be82d3fd06530cd05ceb90d1e75f4204c66819c208c55da049ef.wav", + "atp:ee56993daf775012cf49293bfd5971eec7e5c396642f8bfbea902ba8f47b56cd.wav", + "atp:37775d267f00f82242a7e7f61f3f3d7bf64a54c5a3799e7f2540fa5f6b79bd02.wav" +]) + +function playRandomSound(sounds, options) { + if (options === undefined) { + options = { + volume: 1.0, + position: MyAvatar.position, + } + } + Audio.playSound(sounds[randomInt(sounds.length)], options); +} + +function shootFirework(position, color, options) { + smokeTrailSettings.position = position; + smokeTrailSettings.velocity = randomVec3(-5, 5, 10, 20, 10, 15); + smokeTrailSettings.gravity = randomVec3(-5, 5, -9.8, -9.8, 20, 40); + playRandomSound(fireSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 }); + var smokeID = Entities.addEntity(smokeTrailSettings); + emitters.push(smokeID); + Script.scriptEnding.connect(function() { + Entities.deleteEntity(smokeID); + }); + Script.setTimeout(function() { + Entities.editEntity(smokeID, { emitRate: 0 }); + var position = Entities.getEntityProperties(smokeID, ['position']).position; + Vec3.print("pos", position); + options.position = position; + options.colorStart = color; + options.colorFinish = color; + var id = Entities.addEntity(options); + emitters.push(id); + playRandomSound(popSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 }); + Script.setTimeout(function() { + Entities.editEntity(id, { emitRate: 0 }); + Entities.deleteEntity(smokeID); + }, 500); + }, 2000); +} + +Script.scriptEnding.connect(function() { + for (var i = 0; i < emitters.lengths; ++i) { + Entities.deleteEntity(emitters[i]); + } +}); + +playFireworkShow = function(numberOfFireworks, duration) { + var position = { x: 0, y: 0, z: -78.0 }; + + for (var i = 0; i < numberOfFireworks; i++) { + var randomOffset = randomVec3(-15, 15, -3, 3, -1, 1); + var randomPosition = Vec3.sum(position, randomOffset); + Script.setTimeout(function(position) { + return function() { + var color = randomColor(128, 255, 128, 255, 128, 255); + shootFirework(position, color, fireworkSettings); + } + }(randomPosition), Math.random() * duration) + } +} + +//playFireworkShow(50, 10000); diff --git a/examples/baseball/utils.js b/examples/baseball/utils.js new file mode 100644 index 0000000000..7266666cc9 --- /dev/null +++ b/examples/baseball/utils.js @@ -0,0 +1,35 @@ +randomInt = function(low, high) { + return Math.floor(randomFloat(low, high)); +}; + +randomFloat = function(low, high) { + if (high === undefined) { + high = low; + low = 0; + } + return low + Math.random() * (high - low); +}; + +randomColor = function(redMin, redMax, greenMin, greenMax, blueMin, blueMax) { + return { + red: Math.ceil(randomFloat(redMin, redMax)), + green: Math.ceil(randomFloat(greenMin, greenMax)), + blue: Math.ceil(randomFloat(blueMin, blueMax)), + } +}; + +randomVec3 = function(xMin, xMax, yMin, yMax, zMin, zMax) { + return { + x: randomFloat(xMin, xMax), + y: randomFloat(yMin, yMax), + z: randomFloat(zMin, zMax), + } +}; + +getSounds = function(soundURLs) { + var sounds = []; + for (var i = 0; i < soundURLs.length; ++i) { + sounds.push(SoundCache.getSound(soundURLs[i], false)); + } + return sounds; +}; From 2b8c6ebaf1ae027c5c58fea196c3bcbab60cf998 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 3 Nov 2015 12:14:55 -0800 Subject: [PATCH 087/401] Add firework show when distance hit > 200 --- examples/baseball/pitching.js | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 647ee834c2..dedb4ba04a 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -1,6 +1,7 @@ print("Loading pitching"); //Script.include("../libraries/line.js"); Script.include("https://raw.githubusercontent.com/huffman/hifi/line-js/examples/libraries/line.js"); +Script.include("firework.js") // Return all entities with properties `properties` within radius `searchRadius` function findEntities(properties, searchRadius) { @@ -357,7 +358,6 @@ function setupTrail(entityID, position) { trailInterval = Script.setInterval(function() { var properties = Entities.getEntityProperties(entityID, ['position']); if (Vec3.distance(properties.position, lastPosition)) { - Vec3.print("Adding trail", properties.position); var strokeWidth = Math.log(1 + trail.size) * 0.05; trail.enqueuePoint(properties.position, strokeWidth); lastPosition = properties.position; @@ -430,6 +430,8 @@ function updateBillboard(distance) { } } +var FIREWORK_SHOW_DISTANCE_FEET = 200; + Baseball.prototype = { finished: function() { return this.state == BASEBALL_STATE.FOUL @@ -442,12 +444,10 @@ Baseball.prototype = { this.timeSinceHit += dt; var myProperties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']); var speed = Vec3.length(myProperties.velocity); - this.distanceTravelled = Vec3.distance(this.hitBallAtPosition, myProperties.position); - updateBillboard(Math.ceil(this.distanceTravelled * METERS_TO_FEET)); + this.distanceTravelled = Vec3.distance(this.hitBallAtPosition, myProperties.position) * METERS_TO_FEET; + updateBillboard(Math.ceil(this.distanceTravelled)); if (this.timeSinceHit > 10 || speed < 1) { - this.state = BASEBALL_STATE.HIT_LANDED; - print("Ball took " + this.timeSinceHit.toFixed(3) + " seconds to land"); - print("Ball travelled " + this.distanceTravelled + " meters") + this.ballLanded(); } } else if (this.state == BASEBALL_STATE.PITCHING) { if (this.timeSincePitched > 10) { @@ -456,6 +456,15 @@ Baseball.prototype = { } } }, + ballLanded: function() { + this.state = BASEBALL_STATE.HIT_LANDED; + if (this.distanceTravelled > FIREWORK_SHOW_DISTANCE_FEET) { + print("PLAYING SHOW") + playFireworkShow(50, 10000); + } + print("Ball took " + this.timeSinceHit.toFixed(3) + " seconds to land"); + print("Ball travelled " + this.distanceTravelled + " feet") + }, collisionCallback: function(entityA, entityB, collision) { var self = this; var myProperties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']); @@ -525,7 +534,7 @@ Baseball.prototype = { print("PARTICLES"); entityCollisionWithGround(entityB, this.entityID, collision); if (this.state == BASEBALL_STATE.HIT) { - this.state = BASEBALL_STATE.HIT_LANDED; + this.ballLanded(); } } else if (name == "backstop") { if (this.state == BASEBALL_STATE.PITCHING) { From 644e1008bd7a5ce96ed6a100a00675c497cbf3a9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 3 Nov 2015 13:32:28 -0800 Subject: [PATCH 088/401] Fix bat.js not setting pitchingMachine variable --- examples/baseball/bat.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index c8857095d8..2eaf9df31f 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -2,11 +2,11 @@ Script.include("pitching.js"); var pitchingMachine = null; this.startNearGrab = function() { + print("Started near grab!"); if (!pitchingMachine) { - getPitchingMachine(); + pitchingMachine = getPitchingMachine(); Script.update.connect(function(dt) { pitchingMachine.update(dt); }); } - print("Started near grab!"); pitchingMachine.start(); MyAvatar.shouldRenderLocally = false; }; From f60b1d9bd7c7f64fc9a23ca958667906c0d7d47a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 3 Nov 2015 13:50:35 -0800 Subject: [PATCH 089/401] unmangle merge --- libraries/entities/src/EntityItem.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index ba82bc230d..a4f4ed6512 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1861,7 +1861,6 @@ const QByteArray EntityItem::getActionDataInternal() const { const QByteArray EntityItem::getActionData() const { QByteArray result; - assertUnlocked(); if (_actionDataDirty) { withWriteLock([&] { From 06dbe2693a5c07ab35dd419882d978444f9d6c3f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Nov 2015 14:21:52 -0800 Subject: [PATCH 090/401] fix for created bat properties --- examples/baseball/createBatButton.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 0ffc9cb829..ed6f808947 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -43,6 +43,7 @@ var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; + var SCRIPT_URL = "https://rawgit.com/huffman/hifi/baseball/examples/baseball/bat.js" // add the fresh bat at the drop position var bat = Entities.addEntity({ @@ -55,7 +56,8 @@ velocity: { x: 0, y: 0.05, z: 0}, // workaround for gravity not taking effect on add gravity: { x: 0, y: -9.81, z: 0}, rotation: Quat.fromPitchYawRollDegrees(0.0, 0.0, -90.0), - userData: '{"grabbableKey":{"spatialKey":{"relativePosition":{"x":0.9,"y":0,"z":0},"relativeRotation":{"x":0,"y":0,"z":0.4617486000061035,"w":0.8870108127593994}},"kinematicGrab":true}}' + script: SCRIPT_URL, + userData: '{"grabbableKey":{"spatialKey":{"relativePosition":{"x":0.9,"y":0,"z":0}}}}' }); } }) From 501b905e7a70c03d46f653fede692efb5f9b6a26 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Nov 2015 14:25:38 -0800 Subject: [PATCH 091/401] change script URL for bat to HTTP --- examples/baseball/createBatButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index ed6f808947..6f5ae61d76 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -43,7 +43,7 @@ var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; - var SCRIPT_URL = "https://rawgit.com/huffman/hifi/baseball/examples/baseball/bat.js" + var SCRIPT_URL = "http://rawgit.com/huffman/hifi/baseball/examples/baseball/bat.js" // add the fresh bat at the drop position var bat = Entities.addEntity({ From 5211824e0eccb29ca5c463c1f2e8c16d948dc9dd Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 3 Nov 2015 14:43:43 -0800 Subject: [PATCH 092/401] Fix script include paths in firework.js and pitching.js --- examples/baseball/firework.js | 2 +- examples/baseball/pitching.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index 8e7a9637ec..df9573d7e8 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -1,4 +1,4 @@ -Script.include("utils.js"); +Script.include(Script.resolvePath("utils.js")); var emitters = []; diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index dedb4ba04a..b67449b73d 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -1,7 +1,7 @@ print("Loading pitching"); //Script.include("../libraries/line.js"); Script.include("https://raw.githubusercontent.com/huffman/hifi/line-js/examples/libraries/line.js"); -Script.include("firework.js") +Script.include(Script.include("firework.js")); // Return all entities with properties `properties` within radius `searchRadius` function findEntities(properties, searchRadius) { From 8c0592cababc804bfa8e49821dd7fa0e5e49b1a9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Nov 2015 14:52:40 -0800 Subject: [PATCH 093/401] add semicolons to createBatButton script --- examples/baseball/createBatButton.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 6f5ae61d76..6a19a30a00 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -59,5 +59,5 @@ script: SCRIPT_URL, userData: '{"grabbableKey":{"spatialKey":{"relativePosition":{"x":0.9,"y":0,"z":0}}}}' }); - } -}) + }; +}); From 60824a1fb013dc3a2eb839aef5272d8456a7b670 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 3 Nov 2015 16:07:28 -0800 Subject: [PATCH 094/401] back out some off-brand changes. add parentChanged call --- interface/src/Application.cpp | 142 ++++++++++----------- interface/src/avatar/Avatar.cpp | 32 ++--- interface/src/avatar/AvatarManager.cpp | 26 ++-- interface/src/avatar/AvatarUpdate.cpp | 11 +- libraries/avatars/src/AvatarData.cpp | 55 ++++++-- libraries/avatars/src/AvatarData.h | 18 ++- libraries/entities/src/EntityItem.cpp | 11 -- libraries/shared/src/SpatiallyNestable.cpp | 14 +- libraries/shared/src/SpatiallyNestable.h | 2 + 9 files changed, 178 insertions(+), 133 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e1ba4a8163..e9c2e0ccb1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1128,77 +1128,75 @@ void Application::paintGL() { { PerformanceTimer perfTimer("CameraUpdates"); + auto myAvatar = getMyAvatar(); - myAvatar->withReadLock([&] { - if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { - Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, - myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN); - Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, - !(myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN)); - cameraMenuChanged(); - } + + myAvatar->startCapture(); + if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { + Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN); + Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !(myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN)); + cameraMenuChanged(); + } - // The render mode is default or mirror if the camera is in mirror mode, assigned further below - renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE; + // The render mode is default or mirror if the camera is in mirror mode, assigned further below + renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE; - // Always use the default eye position, not the actual head eye position. - // Using the latter will cause the camera to wobble with idle animations, - // or with changes from the face tracker - if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { - if (isHMDMode()) { - mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); - _myCamera.setPosition(extractTranslation(camMat)); - _myCamera.setRotation(glm::quat_cast(camMat)); - } else { - _myCamera.setPosition(myAvatar->getDefaultEyePosition()); - _myCamera.setRotation(myAvatar->getHead()->getCameraOrientation()); - } - } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { - if (isHMDMode()) { - auto hmdWorldMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); - _myCamera.setRotation(glm::normalize(glm::quat_cast(hmdWorldMat))); - auto worldBoomOffset = myAvatar->getOrientation() * - (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f)); - _myCamera.setPosition(extractTranslation(hmdWorldMat) + worldBoomOffset); - } else { - _myCamera.setRotation(myAvatar->getHead()->getOrientation()); - if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { - _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + _myCamera.getRotation() * - (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f))); - } else { - _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + myAvatar->getOrientation() * - (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f))); - } - } - } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { - if (isHMDMode()) { - glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix()); - _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() - * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)) * hmdRotation); - glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix()); - _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) - + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * - glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror - + (myAvatar->getOrientation() * - glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))) * hmdOffset); - } else { - _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() - * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); - _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) - + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * - glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); - } - renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; + // Always use the default eye position, not the actual head eye position. + // Using the latter will cause the camera to wobble with idle animations, + // or with changes from the face tracker + if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { + if (isHMDMode()) { + mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); + _myCamera.setPosition(extractTranslation(camMat)); + _myCamera.setRotation(glm::quat_cast(camMat)); + } else { + _myCamera.setPosition(myAvatar->getDefaultEyePosition()); + _myCamera.setRotation(myAvatar->getHead()->getCameraOrientation()); } - // Update camera position - if (!isHMDMode()) { - _myCamera.update(1.0f / _fps); + } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { + if (isHMDMode()) { + auto hmdWorldMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); + _myCamera.setRotation(glm::normalize(glm::quat_cast(hmdWorldMat))); + auto worldBoomOffset = myAvatar->getOrientation() * (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f)); + _myCamera.setPosition(extractTranslation(hmdWorldMat) + worldBoomOffset); + } else { + _myCamera.setRotation(myAvatar->getHead()->getOrientation()); + if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + _myCamera.getRotation() + * (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f))); + } else { + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + myAvatar->getOrientation() + * (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f))); + } } - }); + } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { + if (isHMDMode()) { + glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix()); + _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() + * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)) * hmdRotation); + glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix()); + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) + + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * + glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror + + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))) * hmdOffset); + } else { + _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() + * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); + _myCamera.setPosition(myAvatar->getDefaultEyePosition() + + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) + + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * + glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); + } + renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; + } + // Update camera position + if (!isHMDMode()) { + _myCamera.update(1.0f / _fps); + } + myAvatar->endCapture(); } // Primary rendering pass @@ -3454,9 +3452,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se // FIXME: This preRender call is temporary until we create a separate render::scene for the mirror rendering. // Then we can move this logic into the Avatar::simulate call. auto myAvatar = getMyAvatar(); - myAvatar->withReadLock([&] { - myAvatar->preRender(renderArgs); - }); + myAvatar->startRender(); + myAvatar->preRender(renderArgs); + myAvatar->endRender(); activeRenderingThread = QThread::currentThread(); @@ -3570,9 +3568,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se _renderEngine->setRenderContext(renderContext); // Before the deferred pass, let's try to use the render engine - myAvatar->withReadLock([&] { - _renderEngine->run(); - }); + myAvatar->startRenderRun(); + _renderEngine->run(); + myAvatar->endRenderRun(); auto engineRC = _renderEngine->getRenderContext(); sceneInterface->setEngineFeedOpaqueItems(engineRC->_numFeedOpaqueItems); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 4ffa1ffc7c..b6a6ae001d 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -377,6 +377,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { } if (frustum->sphereInFrustum(getPosition(), boundingRadius) == ViewFrustum::OUTSIDE) { + endRender(); return; } @@ -535,6 +536,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { renderDisplayName(batch, frustum, textPosition); } } + endRender(); } glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { @@ -1011,25 +1013,23 @@ void Avatar::setBillboard(const QByteArray& billboard) { } int Avatar::parseDataFromBuffer(const QByteArray& buffer) { - int bytesRead; + startUpdate(); + if (!_initialized) { + // now that we have data for this Avatar we are go for init + init(); + } - withWriteLock([&] { - if (!_initialized) { - // now that we have data for this Avatar we are go for init - init(); - } + // change in position implies movement + glm::vec3 oldPosition = getPosition(); - // change in position implies movement - glm::vec3 oldPosition = getPosition(); + int bytesRead = AvatarData::parseDataFromBuffer(buffer); - bytesRead = AvatarData::parseDataFromBuffer(buffer); - - const float MOVE_DISTANCE_THRESHOLD = 0.001f; - _moving = glm::distance(oldPosition, getPosition()) > MOVE_DISTANCE_THRESHOLD; - if (_moving && _motionState) { - _motionState->addDirtyFlags(Simulation::DIRTY_POSITION); - } - }); + const float MOVE_DISTANCE_THRESHOLD = 0.001f; + _moving = glm::distance(oldPosition, getPosition()) > MOVE_DISTANCE_THRESHOLD; + if (_moving && _motionState) { + _motionState->addDirtyFlags(Simulation::DIRTY_POSITION); + } + endUpdate(); return bytesRead; } diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index e9f4c63532..551891cbfa 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -133,9 +133,9 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { QWriteLocker locker(&_hashLock); avatarIterator = _avatarHash.erase(avatarIterator); } else { - avatar->withWriteLock([&] { - avatar->simulate(deltaTime); - }); + avatar->startUpdate(); + avatar->simulate(deltaTime); + avatar->endUpdate(); ++avatarIterator; } } @@ -154,16 +154,16 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { render::PendingChanges pendingChanges; while (fadingIterator != _avatarFades.end()) { auto avatar = std::static_pointer_cast(*fadingIterator); - avatar->withWriteLock([&] { - avatar->setTargetScale(avatar->getAvatarScale() * SHRINK_RATE); - if (avatar->getTargetScale() < MIN_FADE_SCALE) { - avatar->removeFromScene(*fadingIterator, scene, pendingChanges); - fadingIterator = _avatarFades.erase(fadingIterator); - } else { - avatar->simulate(deltaTime); - ++fadingIterator; - } - }); + avatar->startUpdate(); + avatar->setTargetScale(avatar->getAvatarScale() * SHRINK_RATE); + if (avatar->getTargetScale() < MIN_FADE_SCALE) { + avatar->removeFromScene(*fadingIterator, scene, pendingChanges); + fadingIterator = _avatarFades.erase(fadingIterator); + } else { + avatar->simulate(deltaTime); + ++fadingIterator; + } + avatar->endUpdate(); } scene->enqueuePendingChanges(pendingChanges); } diff --git a/interface/src/avatar/AvatarUpdate.cpp b/interface/src/avatar/AvatarUpdate.cpp index a32948f598..cae593ff85 100644 --- a/interface/src/avatar/AvatarUpdate.cpp +++ b/interface/src/avatar/AvatarUpdate.cpp @@ -56,11 +56,12 @@ bool AvatarUpdate::process() { //gets current lookat data, removes missing avatars, etc. manager->updateOtherAvatars(deltaSeconds); - myAvatar->withWriteLock([&] { - qApp->updateMyAvatarLookAtPosition(); - // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes - manager->updateMyAvatar(deltaSeconds); - }); + myAvatar->startUpdate(); + qApp->updateMyAvatarLookAtPosition(); + // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes + manager->updateMyAvatar(deltaSeconds); + myAvatar->endUpdate(); + if (!isThreaded()) { return true; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index a1db573d8d..a06b3448ea 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -111,25 +111,60 @@ void AvatarData::setBodyRoll(float bodyRoll) { } void AvatarData::setPosition(const glm::vec3& position) { - withWriteLock([&] { - SpatiallyNestable::setPosition(position); - }); + SpatiallyNestable::setPosition(position); } void AvatarData::setOrientation(const glm::quat& orientation) { - withWriteLock([&] { - SpatiallyNestable::setOrientation(orientation); - }); + SpatiallyNestable::setOrientation(orientation); } // There are a number of possible strategies for this set of tools through endRender, below. void AvatarData::nextAttitude(glm::vec3 position, glm::quat orientation) { - withWriteLock([&] { - SpatiallyNestable::setPosition(position); - SpatiallyNestable::setOrientation(orientation); - }); + avatarLock.lock(); + SpatiallyNestable::setPosition(position); + SpatiallyNestable::setOrientation(orientation); + avatarLock.unlock(); updateAttitude(); } +void AvatarData::startCapture() { + avatarLock.lock(); + assert(_nextAllowed); + _nextAllowed = false; + _nextPosition = getPosition(); + _nextOrientation = getOrientation(); +} +void AvatarData::endCapture() { + avatarLock.unlock(); +} +void AvatarData::startUpdate() { + avatarLock.lock(); +} +void AvatarData::endUpdate() { + avatarLock.unlock(); +} +void AvatarData::startRenderRun() { + // I'd like to get rid of this and just (un)lock at (end-)startRender. + // But somehow that causes judder in rotations. + avatarLock.lock(); +} +void AvatarData::endRenderRun() { + avatarLock.unlock(); +} +void AvatarData::startRender() { + glm::vec3 pos = getPosition(); + glm::quat rot = getOrientation(); + setPosition(_nextPosition); + setOrientation(_nextOrientation); + updateAttitude(); + _nextPosition = pos; + _nextOrientation = rot; +} +void AvatarData::endRender() { + setPosition(_nextPosition); + setOrientation(_nextOrientation); + updateAttitude(); + _nextAllowed = true; +} float AvatarData::getTargetScale() const { return _targetScale; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 8a0a9ac38a..2e3257554d 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -44,13 +44,13 @@ typedef unsigned long long quint64; #include #include #include +#include #include #include #include #include #include -#include #include "AABox.h" #include "HandData.h" @@ -136,7 +136,7 @@ class QDataStream; class AttachmentData; class JointData; -class AvatarData : public QObject, public ReadWriteLockable, public SpatiallyNestable { +class AvatarData : public QObject, public SpatiallyNestable { Q_OBJECT Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition) @@ -200,6 +200,14 @@ public: virtual void setOrientation(const glm::quat& orientation); void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time. + void startCapture(); // start/end of the period in which the latest values are about to be captured for camera, etc. + void endCapture(); + void startUpdate(); // start/end of update iteration + void endUpdate(); + void startRender(); // start/end of rendering of this object + void startRenderRun(); // start/end of entire scene. + void endRenderRun(); + void endRender(); virtual void updateAttitude() {} // Tell skeleton mesh about changes glm::quat getHeadOrientation() const { return _headData->getOrientation(); } @@ -355,6 +363,10 @@ public slots: protected: glm::vec3 _handPosition; + glm::vec3 _nextPosition {}; + glm::quat _nextOrientation {}; + bool _nextAllowed {true}; + // Body scale float _targetScale; @@ -404,6 +416,8 @@ protected: SimpleMovingAverage _averageBytesReceived; + QMutex avatarLock; // Name is redundant, but it aids searches. + private: static QUrl _defaultFullAvatarModelUrl; // privatize the copy constructor and assignment operator so they cannot be called diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index a4f4ed6512..0227aa23a1 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1795,9 +1795,6 @@ void EntityItem::checkWaitingToRemove(EntitySimulation* simulation) { } void EntityItem::setActionData(QByteArray actionData) { - if (_id == QUuid("32147a6e-976d-44ea-8c33-056c820b4dbd")) { - qDebug() << "EntityItem::setActionData to " << actionData.size() << "bytes."; - } withWriteLock([&] { setActionDataInternal(actionData); }); @@ -1805,16 +1802,8 @@ void EntityItem::setActionData(QByteArray actionData) { void EntityItem::setActionDataInternal(QByteArray actionData) { if (_allActionsDataCache != actionData) { - if (_id == QUuid("32147a6e-976d-44ea-8c33-056c820b4dbd")) { - qDebug() << "EntityItem::setActionDataInternal to " << actionData.size() << "bytes."; - } - _allActionsDataCache = actionData; deserializeActionsInternal(); - } else { - if (_id == QUuid("32147a6e-976d-44ea-8c33-056c820b4dbd")) { - qDebug() << "EntityItem::setActionDataInternal NOT setting to " << actionData.size() << "bytes."; - } } checkWaitingToRemove(); } diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 300d9a5728..f8b1d0dd54 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -61,7 +61,7 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { _parent.reset(); } - // we have a _parentID but no parent pointer, or our parent pointer is to the wrong thing + // we have a _parentID but no parent pointer, or our parent pointer was to the wrong thing QSharedPointer parentFinder = DependencyManager::get(); _parent = parentFinder->find(_parentID); parent = _parent.lock(); @@ -69,6 +69,11 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { parent->beParentOfChild(thisPointer); _parentKnowsMe = true; } + + if (parent || _parentID.isNull()) { + parentChanged(); + } + return parent; } @@ -80,10 +85,11 @@ void SpatiallyNestable::forgetChild(SpatiallyNestablePointer newChild) const { _children.remove(newChild->getID()); } - void SpatiallyNestable::setParentID(const QUuid& parentID) { - _parentID = parentID; - _parentKnowsMe = false; + if (_parentID != parentID) { + _parentID = parentID; + _parentKnowsMe = false; + } } glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position) { diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 986a282891..82e6c3d788 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -92,6 +92,8 @@ protected: virtual void forgetChild(SpatiallyNestablePointer newChild) const; mutable QHash _children; + virtual void parentChanged() const {} // called when parent pointer is updated + private: Transform _transform; // this is to be combined with parent's world-transform to produce this' world-transform. From 804db537bf2e2556838acda205e93f1fc1ccfe3c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Nov 2015 16:11:13 -0800 Subject: [PATCH 095/401] volume changes for crowd, bat avatar suppression fix --- examples/acScripts/baseballCrowd.js | 7 +++++-- examples/baseball/bat.js | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/acScripts/baseballCrowd.js b/examples/acScripts/baseballCrowd.js index b0038d5865..7db93c5b34 100644 --- a/examples/acScripts/baseballCrowd.js +++ b/examples/acScripts/baseballCrowd.js @@ -17,9 +17,12 @@ var extras = [ SoundCache.getSound("atp:44a83a788ccfd2924e35c902c34808b24dbd0309d000299ce01a355f91cf8115.wav") // clapping ]; +var CHATTER_VOLUME = 0.10 +var EXTRA_VOLUME = 0.15 + function playChatter() { if (chatter.downloaded && !chatter.isPlaying) { - Audio.playSound(chatter, { loop: true, volume: 0.5 }); + Audio.playSound(chatter, { loop: true, volume: CHATTER_VOLUME }); } } @@ -32,7 +35,7 @@ function playRandomExtras() { // play a random extra sound about every 30s currentInjector = Audio.playSound( extras[Math.floor(Math.random() * extras.length)], - { volume: 0.33 } + { volume: EXTRA_VOLUME } ); } } diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index c8857095d8..1ec85021c8 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -10,6 +10,9 @@ pitchingMachine.start(); MyAvatar.shouldRenderLocally = false; }; + this.continueNearGrab = function() { + MyAvatar.shouldRenderLocally = false; + } this.releaseGrab = function() { print("Stopped near grab!"); if (pitchingMachine) { From 5b3809b543a3e5fdb789a24814573be95022af5a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Nov 2015 16:13:14 -0800 Subject: [PATCH 096/401] update the bat script URL --- examples/baseball/createBatButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 6a19a30a00..f0320a7f75 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -43,7 +43,7 @@ var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; - var SCRIPT_URL = "http://rawgit.com/huffman/hifi/baseball/examples/baseball/bat.js" + var SCRIPT_URL = "https://raw.githubusercontent.com/birarda/hifi/baseball/examples/baseball/bat.js" // add the fresh bat at the drop position var bat = Entities.addEntity({ From 9488a8ed240ce0a7b71fe85435f8e7c362ee11b9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Nov 2015 16:42:31 -0800 Subject: [PATCH 097/401] use HTTP URL for bat script URL --- examples/baseball/createBatButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index f0320a7f75..821277d6d0 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -43,7 +43,7 @@ var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; - var SCRIPT_URL = "https://raw.githubusercontent.com/birarda/hifi/baseball/examples/baseball/bat.js" + var SCRIPT_URL = "http://raw.githubusercontent.com/birarda/hifi/baseball/examples/baseball/bat.js" // add the fresh bat at the drop position var bat = Entities.addEntity({ From fbaa86426c1359966f6308589c0f9ff91c8cf9e1 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 3 Nov 2015 16:52:46 -0800 Subject: [PATCH 098/401] re-remove the _nextPosition stuff --- interface/src/avatar/AvatarUpdate.cpp | 1 - libraries/avatars/src/AvatarData.cpp | 13 ------------- libraries/avatars/src/AvatarData.h | 4 ---- 3 files changed, 18 deletions(-) diff --git a/interface/src/avatar/AvatarUpdate.cpp b/interface/src/avatar/AvatarUpdate.cpp index cae593ff85..acdb251950 100644 --- a/interface/src/avatar/AvatarUpdate.cpp +++ b/interface/src/avatar/AvatarUpdate.cpp @@ -62,7 +62,6 @@ bool AvatarUpdate::process() { manager->updateMyAvatar(deltaSeconds); myAvatar->endUpdate(); - if (!isThreaded()) { return true; } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index a06b3448ea..63e20b55b5 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -128,10 +128,6 @@ void AvatarData::nextAttitude(glm::vec3 position, glm::quat orientation) { } void AvatarData::startCapture() { avatarLock.lock(); - assert(_nextAllowed); - _nextAllowed = false; - _nextPosition = getPosition(); - _nextOrientation = getOrientation(); } void AvatarData::endCapture() { avatarLock.unlock(); @@ -151,19 +147,10 @@ void AvatarData::endRenderRun() { avatarLock.unlock(); } void AvatarData::startRender() { - glm::vec3 pos = getPosition(); - glm::quat rot = getOrientation(); - setPosition(_nextPosition); - setOrientation(_nextOrientation); updateAttitude(); - _nextPosition = pos; - _nextOrientation = rot; } void AvatarData::endRender() { - setPosition(_nextPosition); - setOrientation(_nextOrientation); updateAttitude(); - _nextAllowed = true; } float AvatarData::getTargetScale() const { diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 2e3257554d..952017aa77 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -363,10 +363,6 @@ public slots: protected: glm::vec3 _handPosition; - glm::vec3 _nextPosition {}; - glm::quat _nextOrientation {}; - bool _nextAllowed {true}; - // Body scale float _targetScale; From e7bc2e349a97c4bae0568b663e228c12767250be Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Nov 2015 16:55:11 -0800 Subject: [PATCH 099/401] use real userData in createBatButton script --- examples/baseball/createBatButton.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 821277d6d0..473550fdd2 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -45,6 +45,17 @@ var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; var SCRIPT_URL = "http://raw.githubusercontent.com/birarda/hifi/baseball/examples/baseball/bat.js" + var batUserData = { + grabbableKey: { + spatialKey: { + relativePosition: { + x: 0.9, y: 0, z: 0 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, 0) + } + } + } + // add the fresh bat at the drop position var bat = Entities.addEntity({ name: 'Bat', @@ -57,7 +68,7 @@ gravity: { x: 0, y: -9.81, z: 0}, rotation: Quat.fromPitchYawRollDegrees(0.0, 0.0, -90.0), script: SCRIPT_URL, - userData: '{"grabbableKey":{"spatialKey":{"relativePosition":{"x":0.9,"y":0,"z":0}}}}' + userData: JSON.stringify(batUserData) }); }; }); From 9ae3c8b59322c94ecc7a740f8bbb07d43ffc4b32 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 3 Nov 2015 16:58:30 -0800 Subject: [PATCH 100/401] change bat relative rotation yaw to 90 --- examples/baseball/createBatButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 473550fdd2..2465c31d55 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -51,7 +51,7 @@ relativePosition: { x: 0.9, y: 0, z: 0 }, - relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, 0) + relativeRotation: Quat.fromPitchYawRollDegrees(0, 90, 0) } } } From eb990c9c1ce383cd3a29f3b1032782a990861fad Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 3 Nov 2015 17:45:01 -0800 Subject: [PATCH 101/401] More basebal test code --- interface/src/avatar/AvatarActionHold.cpp | 20 ++++----- .../input-plugins/ViveControllerManager.cpp | 42 ++++++++++--------- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 767c60defe..a4fcd3689e 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -50,7 +50,6 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { holdingAvatar = std::static_pointer_cast(holdingAvatarData); if (holdingAvatar) { - glm::vec3 offset; glm::vec3 palmPosition; glm::quat palmRotation; @@ -64,14 +63,16 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { const auto& vive = it->dynamicCast(); auto index = (_hand == "left") ? 0 : 1; auto userInputMapper = DependencyManager::get(); - auto translation = extractTranslation(userInputMapper->getSensorToWorldMat()); - auto rotation = glm::quat_cast(userInputMapper->getSensorToWorldMat()); + auto pos = extractTranslation(userInputMapper->getSensorToWorldMat()); + auto rot = glm::quat_cast(userInputMapper->getSensorToWorldMat()); - - const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); - const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - palmPosition = translation + rotation * vive->getPosition(index); - palmRotation = rotation * vive->getRotation(index) * yFlip * quarterX * glm::angleAxis(PI, glm::vec3(1.0f, 0.0f, 0.0f)) * glm::angleAxis(PI_OVER_TWO, glm::vec3(0.0f, 0.0f, 1.0f)); + + static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); + static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X); + static const glm::quat viveToHand = yFlip * quarterX; + + palmPosition = pos + rot * vive->getPosition(index); + palmRotation = rot * vive->getRotation(index);// * viveToHand * glm::angleAxis(PI, glm::vec3(1.0f, 0.0f, 0.0f)) * glm::angleAxis(PI_OVER_TWO, glm::vec3(0.0f, 0.0f, 1.0f)); } else #endif if (_hand == "right") { @@ -83,8 +84,7 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { } rotation = palmRotation * _relativeRotation; - offset = rotation * _relativePosition; - position = palmPosition + offset; + position = palmPosition + rotation * _relativePosition; } }); diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index fb0021d7d5..317a31a794 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -35,6 +35,7 @@ extern mat4 _trackedDevicePoseMat4[vr::k_unMaxTrackedDeviceCount]; const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches +const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, CONTROLLER_LENGTH_OFFSET / 2.0f, 2.0f * CONTROLLER_LENGTH_OFFSET); // three inches const QString CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b"; const QString ViveControllerManager::NAME = "OpenVR"; @@ -354,14 +355,11 @@ void ViveControllerManager::handleButtonEvent(uint32_t button, bool pressed, boo } void ViveControllerManager::handlePoseEvent(const mat4& mat, bool left) { - glm::vec3 position = extractTranslation(mat); - glm::quat rotation = glm::quat_cast(mat); - // When the sensor-to-world rotation is identity the coordinate axes look like this: // // user // forward - // z + // -z // | // y| user // y o----x right @@ -406,22 +404,26 @@ void ViveControllerManager::handlePoseEvent(const mat4& mat, bool left) { // Q = (deltaQ * QOffset) * (yFlip * quarterTurnAboutX) // // Q = (deltaQ * inverse(deltaQForAlignedHand)) * (yFlip * quarterTurnAboutX) - - float sign = left ? -1.0f : 1.0f; - - const glm::quat quarterX = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); - const glm::quat yFlip = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - const glm::quat signedQuaterZ = glm::angleAxis(sign * PI / 2.0f, glm::vec3(0.0f, 0.0f, 1.0f)); - const glm::quat eighthX = glm::angleAxis(PI / 4.0f, glm::vec3(1.0f, 0.0f, 0.0f)); - - - const glm::quat rotationOffset = glm::inverse(signedQuaterZ * eighthX) * yFlip * quarterX; - const glm::vec3 translationOffset = glm::vec3(sign * CONTROLLER_LENGTH_OFFSET / 2.0f, - CONTROLLER_LENGTH_OFFSET / 2.0f, - 2.0f * CONTROLLER_LENGTH_OFFSET); - - position += rotation * translationOffset; - rotation = rotation * rotationOffset; + + static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); + static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X); + static const glm::quat viveToHand = yFlip * quarterX; + + static const glm::quat leftQuaterZ = glm::angleAxis(-PI_OVER_TWO, Vectors::UNIT_Z); + static const glm::quat rightQuaterZ = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_Z); + static const glm::quat eighthX = glm::angleAxis(PI / 4.0f, Vectors::UNIT_X); + + static const glm::quat leftRotationOffset = glm::inverse(leftQuaterZ * eighthX) * viveToHand; + static const glm::quat rightRotationOffset = glm::inverse(rightQuaterZ * eighthX) * viveToHand; + + static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET; + static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET; + + glm::vec3 position = extractTranslation(mat); + glm::quat rotation = glm::quat_cast(mat); + + position += rotation * (left ? leftTranslationOffset : rightTranslationOffset); + rotation = rotation * (left ? leftRotationOffset : rightRotationOffset); _poseStateMap[left ? controller::LEFT_HAND : controller::RIGHT_HAND] = controller::Pose(position, rotation); } From 3a545399e383bdd19b61874f0939c1cc5d90c125 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 3 Nov 2015 17:54:58 -0800 Subject: [PATCH 102/401] Remove our idle() from paintGL now that it's in master --- interface/src/Application.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c7f46858b5..d31d9de4a0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1074,10 +1074,6 @@ void Application::paintGL() { if (_inPaint) { return; } - - // this is a good idea - idle(); - _inPaint = true; Finally clearFlagLambda([this] { _inPaint = false; }); @@ -2125,7 +2121,7 @@ void Application::idle(uint64_t now) { float secondsSinceLastUpdate = timeSinceLastUpdateUs / USECS_PER_SECOND; if (isThrottled && (timeSinceLastUpdateUs / USECS_PER_MSEC) < THROTTLED_SIM_FRAME_PERIOD_MS) { - //return; // bail early, we're throttled and not enough time has elapsed + return; // bail early, we're throttled and not enough time has elapsed } _lastTimeUpdated.start(); From cb2a698488001d800e2d00169ebfc58c583a2d5d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 4 Nov 2015 09:22:05 -0800 Subject: [PATCH 103/401] Update urls in baseball scripts to be absolute --- examples/baseball/firework.js | 2 +- examples/baseball/pitching.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index df9573d7e8..1b6e621e4d 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -1,4 +1,4 @@ -Script.include(Script.resolvePath("utils.js")); +Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/utils.js"); var emitters = []; diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index b67449b73d..9483af00bc 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -1,7 +1,7 @@ print("Loading pitching"); //Script.include("../libraries/line.js"); Script.include("https://raw.githubusercontent.com/huffman/hifi/line-js/examples/libraries/line.js"); -Script.include(Script.include("firework.js")); +Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/firework.js"); // Return all entities with properties `properties` within radius `searchRadius` function findEntities(properties, searchRadius) { From 73aa016d8caf54eb3ea7b87bc7b44e57be49b119 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 4 Nov 2015 09:23:16 -0800 Subject: [PATCH 104/401] use rawgit URL for bat script --- examples/baseball/createBatButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 2465c31d55..69b7af859e 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -43,7 +43,7 @@ var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; - var SCRIPT_URL = "http://raw.githubusercontent.com/birarda/hifi/baseball/examples/baseball/bat.js" + var SCRIPT_URL = "http://rawgit.com/huffman/hifi/baseball/examples/baseball/bat.js" var batUserData = { grabbableKey: { From 9b3708ea66a9ebd2cdf6e910039eb4b443776688 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 4 Nov 2015 09:27:57 -0800 Subject: [PATCH 105/401] use parentChanged to recalculate entity bounding boxes --- libraries/entities/src/EntityItem.cpp | 6 ++++++ libraries/entities/src/EntityItem.h | 1 + libraries/shared/src/SpatiallyNestable.cpp | 2 +- libraries/shared/src/SpatiallyNestable.h | 2 +- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 0227aa23a1..5394631459 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1324,6 +1324,12 @@ void EntityItem::forSelfAndEachChildEntity(std::functionrequiresRecalcBoxes(); + }); +} + void EntityItem::updatePosition(const glm::vec3& value) { if (shouldSuppressLocationEdits()) { return; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index ffcf24854d..6692886127 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -398,6 +398,7 @@ protected: void setActionDataInternal(QByteArray actionData); void forSelfAndEachChildEntity(std::function actor); + virtual void parentChanged(); static bool _sendPhysicsUpdates; EntityTypes::EntityType _type; diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index f8b1d0dd54..1d058b56df 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -71,7 +71,7 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { } if (parent || _parentID.isNull()) { - parentChanged(); + thisPointer->parentChanged(); } return parent; diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 82e6c3d788..6550eb721e 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -92,7 +92,7 @@ protected: virtual void forgetChild(SpatiallyNestablePointer newChild) const; mutable QHash _children; - virtual void parentChanged() const {} // called when parent pointer is updated + virtual void parentChanged() {} // called when parent pointer is updated private: Transform _transform; // this is to be combined with parent's world-transform to produce this' world-transform. From ea2b9e906b9dcbf4c606339bcf863404bf615da2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 4 Nov 2015 09:33:09 -0800 Subject: [PATCH 106/401] remove continueNearGrab from bat script --- examples/baseball/bat.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index 1ec85021c8..2eaf9df31f 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -2,17 +2,14 @@ Script.include("pitching.js"); var pitchingMachine = null; this.startNearGrab = function() { + print("Started near grab!"); if (!pitchingMachine) { - getPitchingMachine(); + pitchingMachine = getPitchingMachine(); Script.update.connect(function(dt) { pitchingMachine.update(dt); }); } - print("Started near grab!"); pitchingMachine.start(); MyAvatar.shouldRenderLocally = false; }; - this.continueNearGrab = function() { - MyAvatar.shouldRenderLocally = false; - } this.releaseGrab = function() { print("Stopped near grab!"); if (pitchingMachine) { From c2b0d127f30a9739ae7717bcd96c9e3262121b07 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 4 Nov 2015 09:33:42 -0800 Subject: [PATCH 107/401] use bat script without continued near grab --- examples/baseball/createBatButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 69b7af859e..7d09b02c17 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -43,7 +43,7 @@ var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; - var SCRIPT_URL = "http://rawgit.com/huffman/hifi/baseball/examples/baseball/bat.js" + var SCRIPT_URL = "http://rawgit.com/birarda/hifi/baseball/examples/baseball/bat.js" var batUserData = { grabbableKey: { From 8607a1ef5064b27eacfb70b40cbcb056f6124403 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 4 Nov 2015 10:22:53 -0800 Subject: [PATCH 108/401] Revert "remove continueNearGrab from bat script" This reverts commit ea2b9e906b9dcbf4c606339bcf863404bf615da2. --- examples/baseball/bat.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index 2eaf9df31f..1ec85021c8 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -2,14 +2,17 @@ Script.include("pitching.js"); var pitchingMachine = null; this.startNearGrab = function() { - print("Started near grab!"); if (!pitchingMachine) { - pitchingMachine = getPitchingMachine(); + getPitchingMachine(); Script.update.connect(function(dt) { pitchingMachine.update(dt); }); } + print("Started near grab!"); pitchingMachine.start(); MyAvatar.shouldRenderLocally = false; }; + this.continueNearGrab = function() { + MyAvatar.shouldRenderLocally = false; + } this.releaseGrab = function() { print("Stopped near grab!"); if (pitchingMachine) { From ff2438ef03f04c7ca5246135cb53604b44c14e39 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 4 Nov 2015 10:23:06 -0800 Subject: [PATCH 109/401] use bat script that fully hides avatar --- examples/baseball/createBatButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 7d09b02c17..69b7af859e 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -43,7 +43,7 @@ var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; - var SCRIPT_URL = "http://rawgit.com/birarda/hifi/baseball/examples/baseball/bat.js" + var SCRIPT_URL = "http://rawgit.com/huffman/hifi/baseball/examples/baseball/bat.js" var batUserData = { grabbableKey: { From d5c6b0bdc0fef725502c18f1c556875ff05142ea Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 4 Nov 2015 11:31:01 -0800 Subject: [PATCH 110/401] allow a distance grab on the create bat button --- examples/baseball/createBatButton.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 69b7af859e..b105253347 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -19,6 +19,9 @@ this.startNearGrabNonColliding = function() { this.dropBats(); }; + this.startFarGrabNonColliding = function() { + this.dropBats(); + }; this.dropBats = function() { // if the bat box is near us, grab it's position var nearby = Entities.findEntities(this.position, 20); From d0d3aaa09ccd734761aaae667a78e4e28e6fc77b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 4 Nov 2015 12:10:19 -0800 Subject: [PATCH 111/401] Update bat.js to ensure pitching machine is running in continueNearGrab --- examples/baseball/bat.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index d142df8b86..011fdbe27a 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -11,6 +11,11 @@ MyAvatar.shouldRenderLocally = false; }; this.continueNearGrab = function() { + if (!pitchingMachine) { + pitchingMachine = getPitchingMachine(); + Script.update.connect(function(dt) { pitchingMachine.update(dt); }); + } + pitchingMachine.start(); MyAvatar.shouldRenderLocally = false; } this.releaseGrab = function() { From bed7a1f5c3c99c5f1f5c0962c287a7cbd9ddcc4c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 4 Nov 2015 12:10:42 -0800 Subject: [PATCH 112/401] Improve performance of fireworks --- examples/baseball/firework.js | 85 ++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 37 deletions(-) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index 1b6e621e4d..8fd0f977ec 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -2,24 +2,28 @@ Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/utils. var emitters = []; +var currentIdx = 0; +var smokeTrailEmitters = []; +var burstEmitters = []; + var smokeTrailSettings = { "name":"ParticlesTest Emitter", "type": "ParticleEffect", "color":{"red":205,"green":84.41176470588235,"blue":84.41176470588235}, "maxParticles":1000, "velocity": { x: 0, y: 18.0, z: 0 }, - "lifetime": 20, + //"lifetime": 20, "lifespan":3, "emitRate":1000, "emitSpeed":0.5, - "speedSpread":1, - "emitOrientation":{"x":-0.2,"y":0,"z":0,"w":0.7000000000000001}, + "speedSpread":0, + "emitOrientation":{"x":0,"y":0,"z":0,"w":1}, "emitDimensions":{"x":0,"y":0,"z":0}, "emitRadiusStart":0.5, "polarStart":1, "polarFinish":1, - "azimuthStart":-Math.PI, - "azimuthFinish":Math.PI, + "azimuthStart":0, + "azimuthFinish":0, "emitAcceleration":{"x":0,"y":-0.70000001192092896,"z":0}, "accelerationSpread":{"x":0,"y":0,"z":0}, "particleRadius":0.03999999910593033, @@ -41,8 +45,8 @@ var fireworkSettings = { "type": "ParticleEffect", "color":{"red":205,"green":84.41176470588235,"blue":84.41176470588235}, "maxParticles":1000, - "lifetime": 20, - "lifespan":6, + //"lifetime": 20, + "lifespan":4, "emitRate":1000, "emitSpeed":1.5, "speedSpread":1.0, @@ -67,7 +71,6 @@ var fireworkSettings = { "alphaStart":0, "alphaFinish":1, "textures":"https://hifi-public.s3.amazonaws.com/alan/Particles/spark_2.png", - //"textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/spark.png" }; var popSounds = getSounds([ @@ -84,48 +87,41 @@ var fireSounds = getSounds([ ]) function playRandomSound(sounds, options) { - if (options === undefined) { - options = { - volume: 1.0, - position: MyAvatar.position, - } - } Audio.playSound(sounds[randomInt(sounds.length)], options); } function shootFirework(position, color, options) { - smokeTrailSettings.position = position; - smokeTrailSettings.velocity = randomVec3(-5, 5, 10, 20, 10, 15); - smokeTrailSettings.gravity = randomVec3(-5, 5, -9.8, -9.8, 20, 40); + var updatedSmokeProperties = { + position: position, + velocity: randomVec3(-5, 5, 10, 20, 10, 15), + gravity: randomVec3(-5, 5, -9.8, -9.8, 20, 40), + emitRate: 100 + }; + + var idx = currentIdx; + currentIdx = (currentIdx + 1) % MAX_SIMULTANEOUS_FIREWORKS; playRandomSound(fireSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 }); - var smokeID = Entities.addEntity(smokeTrailSettings); - emitters.push(smokeID); - Script.scriptEnding.connect(function() { - Entities.deleteEntity(smokeID); - }); + var smokeID = smokeTrailEmitters[idx]; + var burstID = burstEmitters[idx]; + Entities.editEntity(smokeID, updatedSmokeProperties); + Script.setTimeout(function() { Entities.editEntity(smokeID, { emitRate: 0 }); var position = Entities.getEntityProperties(smokeID, ['position']).position; - Vec3.print("pos", position); - options.position = position; - options.colorStart = color; - options.colorFinish = color; - var id = Entities.addEntity(options); - emitters.push(id); + var updatedBurstProperties = { + position: position, + colorStart: color, + colorFinish: color, + emitRate: 1000 + }; + Entities.editEntity(burstID, updatedBurstProperties); playRandomSound(popSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 }); Script.setTimeout(function() { - Entities.editEntity(id, { emitRate: 0 }); - Entities.deleteEntity(smokeID); + Entities.editEntity(burstID, { emitRate: 0 }); }, 500); }, 2000); } -Script.scriptEnding.connect(function() { - for (var i = 0; i < emitters.lengths; ++i) { - Entities.deleteEntity(emitters[i]); - } -}); - playFireworkShow = function(numberOfFireworks, duration) { var position = { x: 0, y: 0, z: -78.0 }; @@ -141,4 +137,19 @@ playFireworkShow = function(numberOfFireworks, duration) { } } -//playFireworkShow(50, 10000); +var MAX_SIMULTANEOUS_FIREWORKS = 50; + +smokeTrailSettings.emitRate = 0; +fireworkSettings.emitRate = 0; +for (var i = 0; i < MAX_SIMULTANEOUS_FIREWORKS; ++i) { + smokeTrailEmitters.push(Entities.addEntity(smokeTrailSettings)); + burstEmitters.push(Entities.addEntity(fireworkSettings)); +} +Script.scriptEnding.connect(function() { + for (var i = 0; i < MAX_SIMULTANEOUS_FIREWORKS; ++i) { + Entities.deleteEntity(smokeTrailEmitters[i]); + Entities.deleteEntity(burstEmitters[i]); + } +}); + +//playFireworkShow(30, 2000); From 8056498f39db5396beb2b15f5fc8da1c6c1cb9c9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 4 Nov 2015 12:11:07 -0800 Subject: [PATCH 113/401] Update pitching machine to shoot fewer fireworks --- examples/baseball/pitching.js | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 9483af00bc..bc668ee12a 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -74,9 +74,9 @@ var PITCHING_MACHINE_PROPERTIES = { name: "Pitching Machine", type: "Model", position: { - x: 0, + x: -0.93, y: 0.8, - z: -18.3, + z: -19.8, }, velocity: { x: 0, @@ -170,11 +170,10 @@ PitchingMachine.prototype = { print("Created baseball"); }, start: function() { - print("Starting Pitching Machine"); if (this.enabled) { - print("Already enabled") return; } + print("Starting Pitching Machine"); this.enabled = true; this.pitchBall(); }, @@ -390,6 +389,8 @@ function Baseball(position, velocity, ballScale) { this.timeSinceHit = 0; this.hitBallAtPosition = null; this.distanceTravelled = 0; + this.wasHighScore = false; + this.landed = false; // Listen for collision for the lifetime of the entity Script.addEventHandler(this.entityID, "collisionWithEntity", function(entityA, entityB, collision) { @@ -422,15 +423,17 @@ function updateBillboard(distance) { if (!isNaN(distance)) { var properties = Entities.getEntityProperties(HIGH_SCORE_BILLBOARD_ENTITY_ID, ["text"]); var bestDistance = parseInt(properties.text); - if (distance > bestDistance) { + if (distance >= bestDistance) { Entities.editEntity(HIGH_SCORE_BILLBOARD_ENTITY_ID, { text: distance, }); + return true; } } + return false; } -var FIREWORK_SHOW_DISTANCE_FEET = 200; +var FIREWORK_SHOW_DISTANCE_FEET = 2; Baseball.prototype = { finished: function() { @@ -445,8 +448,9 @@ Baseball.prototype = { var myProperties = Entities.getEntityProperties(this.entityID, ['position', 'velocity']); var speed = Vec3.length(myProperties.velocity); this.distanceTravelled = Vec3.distance(this.hitBallAtPosition, myProperties.position) * METERS_TO_FEET; - updateBillboard(Math.ceil(this.distanceTravelled)); - if (this.timeSinceHit > 10 || speed < 1) { + var wasHighScore = updateBillboard(Math.ceil(this.distanceTravelled)); + if (this.landed || this.timeSinceHit > 10 || speed < 1) { + this.wasHighScore = wasHighScore; this.ballLanded(); } } else if (this.state == BASEBALL_STATE.PITCHING) { @@ -460,7 +464,11 @@ Baseball.prototype = { this.state = BASEBALL_STATE.HIT_LANDED; if (this.distanceTravelled > FIREWORK_SHOW_DISTANCE_FEET) { print("PLAYING SHOW") - playFireworkShow(50, 10000); + var numberOfFireworks = Math.floor(this.distanceTraveled / 100); + if (this.wasHighScore) { + numberOfFireworks = 30; + } + playFireworkShow(numberOfFireworks, 2000); } print("Ball took " + this.timeSinceHit.toFixed(3) + " seconds to land"); print("Ball travelled " + this.distanceTravelled + " feet") @@ -533,9 +541,7 @@ Baseball.prototype = { } else if (name == "stadium") { print("PARTICLES"); entityCollisionWithGround(entityB, this.entityID, collision); - if (this.state == BASEBALL_STATE.HIT) { - this.ballLanded(); - } + this.landed = true; } else if (name == "backstop") { if (this.state == BASEBALL_STATE.PITCHING) { this.state = BASEBALL_STATE.STRIKE; From de69b2298beb9212faf5375b5a01d54ff81a7b1f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 4 Nov 2015 12:55:18 -0800 Subject: [PATCH 114/401] Decrease number of fireworks on high score --- examples/baseball/pitching.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index bc668ee12a..661a8786fd 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -466,7 +466,7 @@ Baseball.prototype = { print("PLAYING SHOW") var numberOfFireworks = Math.floor(this.distanceTraveled / 100); if (this.wasHighScore) { - numberOfFireworks = 30; + numberOfFireworks = 20; } playFireworkShow(numberOfFireworks, 2000); } From 2a115fc9abad7edad704f1d692a24f77f9b316b3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 4 Nov 2015 13:11:20 -0800 Subject: [PATCH 115/401] Remove preallocation of particles in firework.js --- examples/baseball/firework.js | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index 8fd0f977ec..fbb8ff8dc5 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -98,12 +98,20 @@ function shootFirework(position, color, options) { emitRate: 100 }; + smokeTrailSettings.position = position; + smokeTrailSettings.velocity = randomVec3(-5, 5, 10, 20, 10, 15); + smokeTrailSettings.gravity = randomVec3(-5, 5, -9.8, -9.8, 20, 40); + smokeTrailSettings.emitRate = 100; + + var idx = currentIdx; currentIdx = (currentIdx + 1) % MAX_SIMULTANEOUS_FIREWORKS; + playRandomSound(fireSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 }); - var smokeID = smokeTrailEmitters[idx]; - var burstID = burstEmitters[idx]; - Entities.editEntity(smokeID, updatedSmokeProperties); + //var smokeID = smokeTrailEmitters[idx]; + //var burstID = burstEmitters[idx]; + //Entities.editEntity(smokeID, updatedSmokeProperties); + var smokeID = Entities.addEntity(smokeTrailSettings); Script.setTimeout(function() { Entities.editEntity(smokeID, { emitRate: 0 }); @@ -114,7 +122,12 @@ function shootFirework(position, color, options) { colorFinish: color, emitRate: 1000 }; - Entities.editEntity(burstID, updatedBurstProperties); + fireworkSettings.position = position; + fireworkSettings.colorStart = color; + fireworkSettings.colorFinish = color; + fireworkSettings.emitRate = 1000; + var burstID = Entities.addEntity(fireworkSettings); + //Entities.editEntity(burstID, updatedBurstProperties); playRandomSound(popSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 }); Script.setTimeout(function() { Entities.editEntity(burstID, { emitRate: 0 }); @@ -137,7 +150,7 @@ playFireworkShow = function(numberOfFireworks, duration) { } } -var MAX_SIMULTANEOUS_FIREWORKS = 50; +var MAX_SIMULTANEOUS_FIREWORKS = 0; smokeTrailSettings.emitRate = 0; fireworkSettings.emitRate = 0; From e0ad714ab71f662aafb4808104830b4371d796ba Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 4 Nov 2015 13:11:34 -0800 Subject: [PATCH 116/401] Clean up print messages in pitching.js --- examples/baseball/pitching.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 661a8786fd..8bcf9d9e81 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -142,8 +142,8 @@ PitchingMachine.prototype = { print("Pitching ball"); var pitchDirection = { x: 0, y: 0, z: 1 }; var machineProperties = Entities.getEntityProperties(this.pitchingMachineID, ["dimensions", "position", "rotation"]); - print("PROPS"); - print("props ", JSON.stringify(machineProperties)); + //print("PROPS"); + //print("props ", JSON.stringify(machineProperties)); var pitchFromPositionBase = machineProperties.position; var pitchFromOffset = vec3Mult(machineProperties.dimensions, PITCHING_MACHINE_OUTPUT_OFFSET_PCT); pitchFromOffset = Vec3.multiplyQbyV(machineProperties.rotation, pitchFromOffset); @@ -539,8 +539,8 @@ Baseball.prototype = { } } } else if (name == "stadium") { - print("PARTICLES"); - entityCollisionWithGround(entityB, this.entityID, collision); + //iprint("PARTICLES"); + //entityCollisionWithGround(entityB, this.entityID, collision); this.landed = true; } else if (name == "backstop") { if (this.state == BASEBALL_STATE.PITCHING) { From f67d4d33f4c65040d082d3ddb863b0f518401acf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 4 Nov 2015 14:32:36 -0800 Subject: [PATCH 117/401] make the crowd a bit louder --- examples/acScripts/baseballCrowd.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/acScripts/baseballCrowd.js b/examples/acScripts/baseballCrowd.js index 7db93c5b34..bc8965e54d 100644 --- a/examples/acScripts/baseballCrowd.js +++ b/examples/acScripts/baseballCrowd.js @@ -17,8 +17,8 @@ var extras = [ SoundCache.getSound("atp:44a83a788ccfd2924e35c902c34808b24dbd0309d000299ce01a355f91cf8115.wav") // clapping ]; -var CHATTER_VOLUME = 0.10 -var EXTRA_VOLUME = 0.15 +var CHATTER_VOLUME = 0.20 +var EXTRA_VOLUME = 0.25 function playChatter() { if (chatter.downloaded && !chatter.isPlaying) { From 4d5ed2efcf854ca55ea8a7f2eb4f973f4b903488 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 4 Nov 2015 14:38:30 -0800 Subject: [PATCH 118/401] Fix fireworks not being deleted --- examples/baseball/firework.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index fbb8ff8dc5..c00e97e8e0 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -132,6 +132,10 @@ function shootFirework(position, color, options) { Script.setTimeout(function() { Entities.editEntity(burstID, { emitRate: 0 }); }, 500); + Script.setTimeout(function() { + Entities.deleteEntity(smokeID); + Entities.deleteEntity(burstID); + }, 10000); }, 2000); } From 6ae4ef78dd0038cf8f5f199b5b899df930e9da19 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 4 Nov 2015 14:38:48 -0800 Subject: [PATCH 119/401] Update max fireworks in pitching.js to be 10 --- examples/baseball/pitching.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 8bcf9d9e81..d63dbf171d 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -464,10 +464,8 @@ Baseball.prototype = { this.state = BASEBALL_STATE.HIT_LANDED; if (this.distanceTravelled > FIREWORK_SHOW_DISTANCE_FEET) { print("PLAYING SHOW") - var numberOfFireworks = Math.floor(this.distanceTraveled / 100); - if (this.wasHighScore) { - numberOfFireworks = 20; - } + var numberOfFireworks = Math.floor(this.distanceTravelled / 200); + numberOfFireworks = Math.min(10, numberOfFireworks); playFireworkShow(numberOfFireworks, 2000); } print("Ball took " + this.timeSinceHit.toFixed(3) + " seconds to land"); From 1c9e3434a9d126cd4f3642a80bee1a7fc6a5ffc4 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 4 Nov 2015 16:01:08 -0800 Subject: [PATCH 120/401] Adjust behavior of tunnel-detection in pitching.js --- examples/baseball/pitching.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index d63dbf171d..16a88dc7b6 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -490,6 +490,8 @@ Baseball.prototype = { var yaw = Math.atan2(myVelocity.x, myVelocity.z) * 180 / Math.PI; var foul = yaw > -135 && yaw < 135; + var speedMultiplier = 2; + if (foul && myVelocity.z > 0) { var xzDist = Math.sqrt(myVelocity.x * myVelocity.x + myVelocity.z * myVelocity.z); var pitch = Math.atan2(myVelocity.y, xzDist) * 180 / Math.PI; @@ -497,13 +499,16 @@ Baseball.prototype = { if (Math.abs(pitch) < 15) { print("Reversing hit"); myVelocity.z *= -1; + myVelocity.y *= -1; + Vec3.length(myVelocity); foul = false; + speedMultiplier = 10; } } // Update ball velocity Entities.editEntity(self.entityID, { - velocity: Vec3.multiply(2, myVelocity), + velocity: Vec3.multiply(speedMultiplier, myVelocity), }); // Setup line update interval From 3154b9d75f5e9762abb39b894240836caa182c40 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 4 Nov 2015 16:21:02 -0800 Subject: [PATCH 121/401] don't set release velocity --- examples/controllers/handControllerGrab.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 2d82896e26..4cce546840 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -895,9 +895,9 @@ function MyController(hand) { // the action will tend to quickly bring an object's velocity to zero. now that // the action is gone, set the objects velocity to something the holder might expect. - Entities.editEntity(this.grabbedEntity, { - velocity: this.grabbedVelocity - }); + // Entities.editEntity(this.grabbedEntity, { + // velocity: this.grabbedVelocity + // }); this.grabbedVelocity = ZERO_VEC; this.grabbedEntity = null; From 7cb8adb0905c92d2c8e4b3c1a8a847fd7896ffaa Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 4 Nov 2015 16:26:30 -0800 Subject: [PATCH 122/401] get rid of code that computes release velocity --- examples/controllers/handControllerGrab.js | 29 +--------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 4cce546840..e6381e8770 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -178,12 +178,11 @@ function MyController(hand) { this.actionID = null; // action this script created... this.grabbedEntity = null; // on this entity. - this.grabbedVelocity = ZERO_VEC; // rolling average of held object's velocity this.state = STATE_OFF; this.pointer = null; // entity-id of line object this.triggerValue = 0; // rolling average of trigger value this.rawTriggerValue = 0; - + this.offsetPosition = { x: 0.0, y: 0.0, z: 0.0 }; this.offsetRotation = { x: 0.0, y: 0.0, z: 0.0, w: 1.0 }; @@ -587,7 +586,6 @@ function MyController(hand) { var deltaPosition = Vec3.subtract(newObjectPosition, this.currentObjectPosition); // meters var now = Date.now(); var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds - this.computeReleaseVelocity(deltaPosition, deltaTime, false); this.currentObjectPosition = newObjectPosition; this.currentObjectTime = now; @@ -707,7 +705,6 @@ function MyController(hand) { var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerTipPosition); // meters var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds - this.computeReleaseVelocity(deltaPosition, deltaTime, true); this.currentHandControllerTipPosition = handControllerPosition; this.currentObjectTime = now; @@ -859,23 +856,6 @@ function MyController(hand) { Entities.callEntityMethod(entityID, "stopTouch"); }; - this.computeReleaseVelocity = function(deltaPosition, deltaTime, useMultiplier) { - if (deltaTime > 0.0 && !vec3equal(deltaPosition, ZERO_VEC)) { - var grabbedVelocity = Vec3.multiply(deltaPosition, 1.0 / deltaTime); - // don't update grabbedVelocity if the trigger is off. the smoothing of the trigger - // value would otherwise give the held object time to slow down. - if (this.triggerSqueezed()) { - this.grabbedVelocity = - Vec3.sum(Vec3.multiply(this.grabbedVelocity, (1.0 - NEAR_GRABBING_VELOCITY_SMOOTH_RATIO)), - Vec3.multiply(grabbedVelocity, NEAR_GRABBING_VELOCITY_SMOOTH_RATIO)); - } - - if (useMultiplier) { - this.grabbedVelocity = Vec3.multiply(this.grabbedVelocity, RELEASE_VELOCITY_MULTIPLIER); - } - } - }; - this.release = function() { if(this.hand !== disabledHand){ @@ -893,13 +873,6 @@ function MyController(hand) { this.deactivateEntity(this.grabbedEntity); - // the action will tend to quickly bring an object's velocity to zero. now that - // the action is gone, set the objects velocity to something the holder might expect. - // Entities.editEntity(this.grabbedEntity, { - // velocity: this.grabbedVelocity - // }); - - this.grabbedVelocity = ZERO_VEC; this.grabbedEntity = null; this.actionID = null; this.setState(STATE_OFF); From 4ffaa7db8e573ee941b4b60b9ec0217151eea852 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 4 Nov 2015 13:59:37 -0800 Subject: [PATCH 123/401] don't attempt to grab particles or zones --- examples/controllers/handControllerGrab.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index e6381e8770..b0721de119 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -451,6 +451,14 @@ function MyController(hand) { continue; } + if (propsForCandidate.type == 'ParticleEffect') { + continue; + } + + if (propsForCandidate.type == 'Zone') { + continue; + } + if (propsForCandidate.locked && !grabbableDataForCandidate.wantsTrigger) { continue; } From 5d2df1abbb3bc6e5b0de16d46e2f53e91649e724 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 6 Nov 2015 09:55:18 -0800 Subject: [PATCH 124/401] Add helped function findEntity --- examples/baseball/pitching.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 16a88dc7b6..81a5b22de2 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -3,6 +3,11 @@ print("Loading pitching"); Script.include("https://raw.githubusercontent.com/huffman/hifi/line-js/examples/libraries/line.js"); Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/firework.js"); +function findEntity(properties, searchRadius) { + var entities = findEntities(properties, searchRadius); + return entities.length > 0 ? entities[0] : null; +} + // Return all entities with properties `properties` within radius `searchRadius` function findEntities(properties, searchRadius) { var entities = Entities.findEntities(MyAvatar.position, searchRadius); @@ -26,11 +31,11 @@ function findEntities(properties, searchRadius) { return matchedEntities; } -// These are hard-coded to the relevant entity IDs on the sport server var DISTANCE_BILLBOARD_NAME = "CurrentScore"; var HIGH_SCORE_BILLBOARD_NAME = "HighScore"; -var DISTANCE_BILLBOARD_ENTITY_ID = findEntities({name: DISTANCE_BILLBOARD_NAME }, 1000)[0]; -var HIGH_SCORE_BILLBOARD_ENTITY_ID = findEntities({name: HIGH_SCORE_BILLBOARD_NAME }, 1000)[0]; +var DISTANCE_BILLBOARD_ENTITY_ID = findEntity({name: DISTANCE_BILLBOARD_NAME }, 1000); +var HIGH_SCORE_BILLBOARD_ENTITY_ID = findEntity({name: HIGH_SCORE_BILLBOARD_NAME }, 1000); + print("Distance: ", DISTANCE_BILLBOARD_ENTITY_ID) var METERS_TO_FEET = 3.28084; From 7da611d44b14a7a28217828753318291a4b676af Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 6 Nov 2015 10:03:57 -0800 Subject: [PATCH 125/401] Adjust fireworks configuration in pitching.js --- examples/baseball/pitching.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 81a5b22de2..d8ae3d1a34 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -438,7 +438,8 @@ function updateBillboard(distance) { return false; } -var FIREWORK_SHOW_DISTANCE_FEET = 2; +var FIREWORK_PER_X_FEET = 100; +var MAX_FIREWORKS = 10; Baseball.prototype = { finished: function() { @@ -467,10 +468,9 @@ Baseball.prototype = { }, ballLanded: function() { this.state = BASEBALL_STATE.HIT_LANDED; - if (this.distanceTravelled > FIREWORK_SHOW_DISTANCE_FEET) { - print("PLAYING SHOW") - var numberOfFireworks = Math.floor(this.distanceTravelled / 200); - numberOfFireworks = Math.min(10, numberOfFireworks); + var numberOfFireworks = Math.floor(this.distanceTravelled / FIREWORK_PER_X_FEET); + if (numberOfFireworks > 0) { + numberOfFireworks = Math.min(MAX_FIREWORKS, numberOfFireworks); playFireworkShow(numberOfFireworks, 2000); } print("Ball took " + this.timeSinceHit.toFixed(3) + " seconds to land"); From d5336db039bd4b890f1af76b3d0131fcb11d00df Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 6 Nov 2015 10:04:19 -0800 Subject: [PATCH 126/401] Cleanup print statements in pitching.js --- examples/baseball/pitching.js | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index d8ae3d1a34..3060b203fd 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -68,6 +68,7 @@ var AUDIO = { var PITCH_THUNK_SOUND_URL = "http://hifi-public.s3.amazonaws.com/sounds/ping_pong_gun/pong_sound.wav"; var pitchSound = SoundCache.getSound(PITCH_THUNK_SOUND_URL, false); +updateBillboard(""); var PITCHING_MACHINE_URL = "atp:87d4879530b698741ecc45f6f31789aac11f7865a2c3bec5fe9b061a182c80d4.fbx"; var PITCHING_MACHINE_OUTPUT_OFFSET_PCT = { @@ -147,22 +148,17 @@ PitchingMachine.prototype = { print("Pitching ball"); var pitchDirection = { x: 0, y: 0, z: 1 }; var machineProperties = Entities.getEntityProperties(this.pitchingMachineID, ["dimensions", "position", "rotation"]); - //print("PROPS"); - //print("props ", JSON.stringify(machineProperties)); var pitchFromPositionBase = machineProperties.position; var pitchFromOffset = vec3Mult(machineProperties.dimensions, PITCHING_MACHINE_OUTPUT_OFFSET_PCT); pitchFromOffset = Vec3.multiplyQbyV(machineProperties.rotation, pitchFromOffset); var pitchFromPosition = Vec3.sum(pitchFromPositionBase, pitchFromOffset); var pitchDirection = Quat.getFront(machineProperties.rotation); var ballScale = machineProperties.dimensions.x / PITCHING_MACHINE_PROPERTIES.dimensions.x; - print("Creating baseball"); var speed = randomFloat(BASEBALL_MIN_SPEED, BASEBALL_MAX_SPEED); var velocity = Vec3.multiply(speed, pitchDirection); this.baseball = new Baseball(pitchFromPosition, velocity, ballScale); - Vec3.print("vel", velocity); - Vec3.print("pos", pitchFromPosition); if (!this.injector) { this.injector = Audio.playSound(pitchSound, { @@ -193,7 +189,6 @@ PitchingMachine.prototype = { if (this.baseball) { this.baseball.update(dt); if (this.baseball.finished()) { - print("BALL IS FINISHED"); this.baseball = null; var self = this; Script.setTimeout(function() { self.pitchBall() }, 3000); @@ -316,7 +311,6 @@ function ObjectTrail(entityID, startPosition) { this.line = null; var lineInterval = null; - print("Creating Trail!"); var lastPosition = startPosition; trail = new InfiniteLine(startPosition, trailColor, trailLifetime); trailInterval = Script.setInterval(function() { @@ -356,7 +350,6 @@ function cleanupTrail() { function setupTrail(entityID, position) { cleanupTrail(); - print("Creating Trail!"); var lastPosition = position; trail = new InfiniteLine(position, { red: 128, green: 255, blue: 89 }, 20); trailInterval = Script.setInterval(function() { @@ -488,7 +481,6 @@ Baseball.prototype = { }); var name = Entities.getEntityProperties(entityB, ["name"]).name; - print("Hit: " + name); if (name == "Bat") { if (this.state == BASEBALL_STATE.PITCHING) { print("HIT"); @@ -533,9 +525,10 @@ Baseball.prototype = { volume: 1.0 }); }, 500); + if (foul) { + print("FOUL, yaw: ", yaw); updateBillboard("FOUL"); - print("FOUL ", yaw) this.state = BASEBALL_STATE.FOUL; playRandomSound(AUDIO.foul, { position: myPosition, @@ -547,14 +540,13 @@ Baseball.prototype = { } } } else if (name == "stadium") { - //iprint("PARTICLES"); //entityCollisionWithGround(entityB, this.entityID, collision); this.landed = true; } else if (name == "backstop") { if (this.state == BASEBALL_STATE.PITCHING) { + print("STRIKE"); this.state = BASEBALL_STATE.STRIKE; updateBillboard("STRIKE"); - print("STRIKE"); playRandomSound(AUDIO.strike, { position: myPosition, volume: 2.0 @@ -570,7 +562,6 @@ function update(dt) { if (baseball) { baseball.update(dt); if (baseball.finished()) { - print("BALL IS FINSIEHD"); baseball = null; Script.setTimeout(pitchBall, 3000); } From 94bf2ecf275e9629641dfe03c9a797b4cea4a766 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 6 Nov 2015 10:45:22 -0800 Subject: [PATCH 127/401] Remove emitter pool from firework.js --- examples/baseball/firework.js | 48 +++++------------------------------ 1 file changed, 6 insertions(+), 42 deletions(-) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index c00e97e8e0..c8b58462fa 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -3,8 +3,6 @@ Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/utils. var emitters = []; var currentIdx = 0; -var smokeTrailEmitters = []; -var burstEmitters = []; var smokeTrailSettings = { "name":"ParticlesTest Emitter", @@ -12,9 +10,9 @@ var smokeTrailSettings = { "color":{"red":205,"green":84.41176470588235,"blue":84.41176470588235}, "maxParticles":1000, "velocity": { x: 0, y: 18.0, z: 0 }, - //"lifetime": 20, + "lifetime": 20, "lifespan":3, - "emitRate":1000, + "emitRate":100, "emitSpeed":0.5, "speedSpread":0, "emitOrientation":{"x":0,"y":0,"z":0,"w":1}, @@ -45,7 +43,7 @@ var fireworkSettings = { "type": "ParticleEffect", "color":{"red":205,"green":84.41176470588235,"blue":84.41176470588235}, "maxParticles":1000, - //"lifetime": 20, + "lifetime": 20, "lifespan":4, "emitRate":1000, "emitSpeed":1.5, @@ -79,55 +77,36 @@ var popSounds = getSounds([ "atp:830312930577cb1ea36ba2d743e957debbacceb441b20addead5a6faa05a3771.wav", "atp:62e80d0a9f084cf731bcc66ca6e9020ee88587417071a281eee3167307b53560.wav" ]); + var fireSounds = getSounds([ "atp:ee6afe565576c4546c6d6cd89c1af532484c9b60ab30574d6b40c2df022f7260.wav", "atp:91ef19ba1c78be82d3fd06530cd05ceb90d1e75f4204c66819c208c55da049ef.wav", "atp:ee56993daf775012cf49293bfd5971eec7e5c396642f8bfbea902ba8f47b56cd.wav", "atp:37775d267f00f82242a7e7f61f3f3d7bf64a54c5a3799e7f2540fa5f6b79bd02.wav" -]) +]); function playRandomSound(sounds, options) { Audio.playSound(sounds[randomInt(sounds.length)], options); } function shootFirework(position, color, options) { - var updatedSmokeProperties = { - position: position, - velocity: randomVec3(-5, 5, 10, 20, 10, 15), - gravity: randomVec3(-5, 5, -9.8, -9.8, 20, 40), - emitRate: 100 - }; - smokeTrailSettings.position = position; smokeTrailSettings.velocity = randomVec3(-5, 5, 10, 20, 10, 15); smokeTrailSettings.gravity = randomVec3(-5, 5, -9.8, -9.8, 20, 40); - smokeTrailSettings.emitRate = 100; - var idx = currentIdx; currentIdx = (currentIdx + 1) % MAX_SIMULTANEOUS_FIREWORKS; playRandomSound(fireSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 }); - //var smokeID = smokeTrailEmitters[idx]; - //var burstID = burstEmitters[idx]; - //Entities.editEntity(smokeID, updatedSmokeProperties); var smokeID = Entities.addEntity(smokeTrailSettings); Script.setTimeout(function() { Entities.editEntity(smokeID, { emitRate: 0 }); var position = Entities.getEntityProperties(smokeID, ['position']).position; - var updatedBurstProperties = { - position: position, - colorStart: color, - colorFinish: color, - emitRate: 1000 - }; fireworkSettings.position = position; fireworkSettings.colorStart = color; fireworkSettings.colorFinish = color; - fireworkSettings.emitRate = 1000; var burstID = Entities.addEntity(fireworkSettings); - //Entities.editEntity(burstID, updatedBurstProperties); playRandomSound(popSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 }); Script.setTimeout(function() { Entities.editEntity(burstID, { emitRate: 0 }); @@ -154,19 +133,4 @@ playFireworkShow = function(numberOfFireworks, duration) { } } -var MAX_SIMULTANEOUS_FIREWORKS = 0; - -smokeTrailSettings.emitRate = 0; -fireworkSettings.emitRate = 0; -for (var i = 0; i < MAX_SIMULTANEOUS_FIREWORKS; ++i) { - smokeTrailEmitters.push(Entities.addEntity(smokeTrailSettings)); - burstEmitters.push(Entities.addEntity(fireworkSettings)); -} -Script.scriptEnding.connect(function() { - for (var i = 0; i < MAX_SIMULTANEOUS_FIREWORKS; ++i) { - Entities.deleteEntity(smokeTrailEmitters[i]); - Entities.deleteEntity(burstEmitters[i]); - } -}); - -//playFireworkShow(30, 2000); +playFireworkShow(10, 2000); From fbb47ecddab8ef23735e85f388c51dee47c1bb99 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 6 Nov 2015 11:39:46 -0800 Subject: [PATCH 128/401] Remove hard-coded fireworks position from firework.js --- examples/baseball/firework.js | 4 +--- examples/baseball/pitching.js | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index c8b58462fa..9e4e8d01a7 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -118,9 +118,7 @@ function shootFirework(position, color, options) { }, 2000); } -playFireworkShow = function(numberOfFireworks, duration) { - var position = { x: 0, y: 0, z: -78.0 }; - +playFireworkShow = function(position, numberOfFireworks, duration) { for (var i = 0; i < numberOfFireworks; i++) { var randomOffset = randomVec3(-15, 15, -3, 3, -1, 1); var randomPosition = Vec3.sum(position, randomOffset); diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 3060b203fd..dc0a4e9169 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -431,6 +431,7 @@ function updateBillboard(distance) { return false; } +var FIREWORKS_SHOW_POSITION = { x: 0, y: 0, z: -78.0 }; var FIREWORK_PER_X_FEET = 100; var MAX_FIREWORKS = 10; @@ -464,7 +465,7 @@ Baseball.prototype = { var numberOfFireworks = Math.floor(this.distanceTravelled / FIREWORK_PER_X_FEET); if (numberOfFireworks > 0) { numberOfFireworks = Math.min(MAX_FIREWORKS, numberOfFireworks); - playFireworkShow(numberOfFireworks, 2000); + playFireworkShow(FIREWORKS_SHOW_POSITION, numberOfFireworks, 2000); } print("Ball took " + this.timeSinceHit.toFixed(3) + " seconds to land"); print("Ball travelled " + this.distanceTravelled + " feet") From 4cce57881f122308ca8f4620fec754a916d3f347 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 6 Nov 2015 12:24:19 -0800 Subject: [PATCH 129/401] Remove MAX_SIMULTANEOUS_FIREWORKS from firework.js --- examples/baseball/firework.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index 9e4e8d01a7..a3db59e533 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -2,8 +2,6 @@ Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/utils. var emitters = []; -var currentIdx = 0; - var smokeTrailSettings = { "name":"ParticlesTest Emitter", "type": "ParticleEffect", @@ -94,9 +92,6 @@ function shootFirework(position, color, options) { smokeTrailSettings.velocity = randomVec3(-5, 5, 10, 20, 10, 15); smokeTrailSettings.gravity = randomVec3(-5, 5, -9.8, -9.8, 20, 40); - var idx = currentIdx; - currentIdx = (currentIdx + 1) % MAX_SIMULTANEOUS_FIREWORKS; - playRandomSound(fireSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 }); var smokeID = Entities.addEntity(smokeTrailSettings); From 42e2c683fdf7c2b39d20f85b69ffb5cecbd799af Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 6 Nov 2015 12:24:52 -0800 Subject: [PATCH 130/401] Rename fireSounds to launchSounds --- examples/baseball/firework.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index a3db59e533..49c4093082 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -76,7 +76,7 @@ var popSounds = getSounds([ "atp:62e80d0a9f084cf731bcc66ca6e9020ee88587417071a281eee3167307b53560.wav" ]); -var fireSounds = getSounds([ +var launchSounds = getSounds([ "atp:ee6afe565576c4546c6d6cd89c1af532484c9b60ab30574d6b40c2df022f7260.wav", "atp:91ef19ba1c78be82d3fd06530cd05ceb90d1e75f4204c66819c208c55da049ef.wav", "atp:ee56993daf775012cf49293bfd5971eec7e5c396642f8bfbea902ba8f47b56cd.wav", @@ -92,7 +92,7 @@ function shootFirework(position, color, options) { smokeTrailSettings.velocity = randomVec3(-5, 5, 10, 20, 10, 15); smokeTrailSettings.gravity = randomVec3(-5, 5, -9.8, -9.8, 20, 40); - playRandomSound(fireSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 }); + playRandomSound(launchSounds, { position: {x: 0, y: 0 , z: 0}, volume: 3.0 }); var smokeID = Entities.addEntity(smokeTrailSettings); Script.setTimeout(function() { From c964363ce53d7ca8121166f641925410d6ec26f9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 6 Nov 2015 12:25:13 -0800 Subject: [PATCH 131/401] Disable automatic playing of show in firework.js --- examples/baseball/firework.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index 49c4093082..fee8aa8e35 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -126,4 +126,4 @@ playFireworkShow = function(position, numberOfFireworks, duration) { } } -playFireworkShow(10, 2000); +//playFireworkShow(10, 2000); From 51b14386a09774d2b3e6de73f87e1839e751108c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 6 Nov 2015 15:08:35 -0800 Subject: [PATCH 132/401] Adjust baseball pitch speed to 5-20 m/s --- examples/baseball/pitching.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index dc0a4e9169..11b60cbfa1 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -198,8 +198,8 @@ PitchingMachine.prototype = { }; var BASEBALL_MODEL_URL = "atp:7185099f1f650600ca187222573a88200aeb835454bd2f578f12c7fb4fd190fa.fbx"; -var BASEBALL_MIN_SPEED = 2.7; -var BASEBALL_MAX_SPEED = 5.7; +var BASEBALL_MIN_SPEED = 5.0; +var BASEBALL_MAX_SPEED = 20.0; var BASEBALL_RADIUS = 0.07468; var BASEBALL_PROPERTIES = { name: "Baseball", From bc035b7e1e83ffe3fa430157f09581c26dff9ddc Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 6 Nov 2015 15:29:57 -0800 Subject: [PATCH 133/401] Adjust baseball speed to 7-15 m/s --- examples/baseball/pitching.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 11b60cbfa1..698810b87f 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -198,8 +198,8 @@ PitchingMachine.prototype = { }; var BASEBALL_MODEL_URL = "atp:7185099f1f650600ca187222573a88200aeb835454bd2f578f12c7fb4fd190fa.fbx"; -var BASEBALL_MIN_SPEED = 5.0; -var BASEBALL_MAX_SPEED = 20.0; +var BASEBALL_MIN_SPEED = 7.0; +var BASEBALL_MAX_SPEED = 15.0; var BASEBALL_RADIUS = 0.07468; var BASEBALL_PROPERTIES = { name: "Baseball", From e145d4955cd9b0d2fbaf8586c5c84d384e837cca Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 6 Nov 2015 15:30:16 -0800 Subject: [PATCH 134/401] Update tunnel detection to reverse all axes --- examples/baseball/pitching.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 698810b87f..05f108b165 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -496,8 +496,9 @@ Baseball.prototype = { print("Pitch: ", pitch); if (Math.abs(pitch) < 15) { print("Reversing hit"); - myVelocity.z *= -1; + myVelocity.x *= -1; myVelocity.y *= -1; + myVelocity.z *= -1; Vec3.length(myVelocity); foul = false; speedMultiplier = 10; From 30841169ee2e293f48d4c9a46d91288a33de6f2b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 10:04:19 -0800 Subject: [PATCH 135/401] Move functions in baseball.js to utils.js --- examples/baseball/pitching.js | 58 +---------------------------------- examples/baseball/utils.js | 46 +++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 57 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 05f108b165..fe585d4f4a 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -2,34 +2,7 @@ print("Loading pitching"); //Script.include("../libraries/line.js"); Script.include("https://raw.githubusercontent.com/huffman/hifi/line-js/examples/libraries/line.js"); Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/firework.js"); - -function findEntity(properties, searchRadius) { - var entities = findEntities(properties, searchRadius); - return entities.length > 0 ? entities[0] : null; -} - -// Return all entities with properties `properties` within radius `searchRadius` -function findEntities(properties, searchRadius) { - var entities = Entities.findEntities(MyAvatar.position, searchRadius); - var matchedEntities = []; - var keys = Object.keys(properties); - for (var i = 0; i < entities.length; ++i) { - var match = true; - var candidateProperties = Entities.getEntityProperties(entities[i], keys); - for (var key in properties) { - if (candidateProperties[key] != properties[key]) { - // This isn't a match, move to next entity - match = false; - break; - } - } - if (match) { - matchedEntities.push(entities[i]); - } - } - - return matchedEntities; -} +Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/utils.js"); var DISTANCE_BILLBOARD_NAME = "CurrentScore"; var HIGH_SCORE_BILLBOARD_NAME = "HighScore"; @@ -247,35 +220,6 @@ var BASEBALL_STATE = { }; -function shallowCopy(obj) { - var copy = {} - for (var key in obj) { - copy[key] = obj[key]; - } - return copy; -} - -function randomInt(low, high) { - return Math.floor(randomFloat(low, high)); -} - -function randomFloat(low, high) { - if (high === undefined) { - high = low; - low = 0; - } - return low + Math.random() * (high - low); -} - -function playRandomSound(sounds, options) { - if (options === undefined) { - options = { - volume: 1.0, - position: MyAvatar.position, - } - } - Audio.playSound(sounds[randomInt(sounds.length)], options); -} function vec3Mult(a, b) { return { diff --git a/examples/baseball/utils.js b/examples/baseball/utils.js index 7266666cc9..f128797345 100644 --- a/examples/baseball/utils.js +++ b/examples/baseball/utils.js @@ -33,3 +33,49 @@ getSounds = function(soundURLs) { } return sounds; }; + +playRandomSound = function(sounds, options) { + if (options === undefined) { + options = { + volume: 1.0, + position: MyAvatar.position, + } + } + return Audio.playSound(sounds[randomInt(sounds.length)], options); +} + +shallowCopy = function(obj) { + var copy = {} + for (var key in obj) { + copy[key] = obj[key]; + } + return copy; +} + +findEntity = function(properties, searchRadius) { + var entities = findEntities(properties, searchRadius); + return entities.length > 0 ? entities[0] : null; +} + +// Return all entities with properties `properties` within radius `searchRadius` +findEntities = function(properties, searchRadius) { + var entities = Entities.findEntities(MyAvatar.position, searchRadius); + var matchedEntities = []; + var keys = Object.keys(properties); + for (var i = 0; i < entities.length; ++i) { + var match = true; + var candidateProperties = Entities.getEntityProperties(entities[i], keys); + for (var key in properties) { + if (candidateProperties[key] != properties[key]) { + // This isn't a match, move to next entity + match = false; + break; + } + } + if (match) { + matchedEntities.push(entities[i]); + } + } + + return matchedEntities; +} From 20bdc7ee85a414b3e6cbc864ffb66405da05e790 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 10:10:59 -0800 Subject: [PATCH 136/401] Rename getPitchingMachine to getOrCreatePitchingMachine --- examples/baseball/bat.js | 4 ++-- examples/baseball/pitching.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index 011fdbe27a..98ad8b7bf4 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -4,7 +4,7 @@ this.startNearGrab = function() { print("Started near grab!"); if (!pitchingMachine) { - pitchingMachine = getPitchingMachine(); + pitchingMachine = getOrCreatePitchingMachine(); Script.update.connect(function(dt) { pitchingMachine.update(dt); }); } pitchingMachine.start(); @@ -12,7 +12,7 @@ }; this.continueNearGrab = function() { if (!pitchingMachine) { - pitchingMachine = getPitchingMachine(); + pitchingMachine = getOrCreatePitchingMachine(); Script.update.connect(function(dt) { pitchingMachine.update(dt); }); } pitchingMachine.start(); diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index fe585d4f4a..93c114baa4 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -80,14 +80,14 @@ var PITCHING_MACHINE_PROPERTIES = { z: 0.39 }, collisionsWillMove: false, - shapeType: "Box", + shapeType: "Box" }; PITCHING_MACHINE_PROPERTIES.dimensions = Vec3.multiply(2.5, PITCHING_MACHINE_PROPERTIES.dimensions); var DISTANCE_FROM_PLATE = PITCHING_MACHINE_PROPERTIES.position.z; var PITCH_RATE = 5000; -getPitchingMachine = function() { +getOrCreatePitchingMachine = function() { // Search for pitching machine var entities = findEntities({ name: PITCHING_MACHINE_PROPERTIES.name }, 1000); var pitchingMachineID = null; From ec31504c1178c0c9a73b7ae6a5987cfa01188aa9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 10:30:21 -0800 Subject: [PATCH 137/401] Add detection of missing entity billboards in pitching.js --- examples/baseball/pitching.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 93c114baa4..0e6fe0b61f 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -9,7 +9,12 @@ var HIGH_SCORE_BILLBOARD_NAME = "HighScore"; var DISTANCE_BILLBOARD_ENTITY_ID = findEntity({name: DISTANCE_BILLBOARD_NAME }, 1000); var HIGH_SCORE_BILLBOARD_ENTITY_ID = findEntity({name: HIGH_SCORE_BILLBOARD_NAME }, 1000); -print("Distance: ", DISTANCE_BILLBOARD_ENTITY_ID) +if (DISTANCE_BILLBOARD_ENTITY_ID === null) { + print("WARNING: Distance billboard cannot be found."); +} +if (HIGH_SCORE_BILLBOARD_ENTITY_ID === null) { + print("WARNING: High Score billboard cannot be found."); +} var METERS_TO_FEET = 3.28084; From b6d26862fd2fc303d9bfebd3d7cd19b9ef83f0bb Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 10:33:07 -0800 Subject: [PATCH 138/401] Add headers to baseball script files --- examples/baseball/bat.js | 11 +++++++++++ examples/baseball/firework.js | 11 +++++++++++ examples/baseball/pitching.js | 11 +++++++++++ examples/baseball/utils.js | 11 +++++++++++ 4 files changed, 44 insertions(+) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index 98ad8b7bf4..eedda1e82a 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -1,3 +1,14 @@ +// +// bat.js +// examples/baseball/ +// +// Created by Ryan Huffman on Nov 9, 2015 +// 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 +// + (function() { Script.include("pitching.js"); var pitchingMachine = null; diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index fee8aa8e35..89287c5a8b 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -1,3 +1,14 @@ +// +// firework.js +// examples/baseball/ +// +// Created by Ryan Huffman on Nov 9, 2015 +// 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 +// + Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/utils.js"); var emitters = []; diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 0e6fe0b61f..f8d5eba137 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -1,3 +1,14 @@ +// +// pitching.js +// examples/baseball/ +// +// Created by Ryan Huffman on Nov 9, 2015 +// 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 +// + print("Loading pitching"); //Script.include("../libraries/line.js"); Script.include("https://raw.githubusercontent.com/huffman/hifi/line-js/examples/libraries/line.js"); diff --git a/examples/baseball/utils.js b/examples/baseball/utils.js index f128797345..80f4c62f32 100644 --- a/examples/baseball/utils.js +++ b/examples/baseball/utils.js @@ -1,3 +1,14 @@ +// +// utils.js +// examples/baseball/ +// +// Created by Ryan Huffman on Nov 9, 2015 +// 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 +// + randomInt = function(low, high) { return Math.floor(randomFloat(low, high)); }; From 1b3d595d1e9063697d894fc132fdecf99a610a1d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 10:58:18 -0800 Subject: [PATCH 139/401] Add comment to PITCHING_MACHINE_OUTPUT_OFFSET_PCT --- examples/baseball/pitching.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index f8d5eba137..8fdb53dcdc 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -60,6 +60,11 @@ var pitchSound = SoundCache.getSound(PITCH_THUNK_SOUND_URL, false); updateBillboard(""); var PITCHING_MACHINE_URL = "atp:87d4879530b698741ecc45f6f31789aac11f7865a2c3bec5fe9b061a182c80d4.fbx"; +// This defines an offset to pitch a ball from with respect to the machine's position. The offset is a +// percentage of the machine's dimensions. So, { x: 0.5, y: -1.0, z: 0.0 } would offset on 50% on the +// machine's x axis, -100% on the y axis, and 0% on the z-axis. For the dimensions { x: 100, y: 100, z: 100 }, +// that would result in an offset of { x: 50, y: -100, z: 0 }. This makes it easy to calculate an offset if +// the machine's dimensions change. var PITCHING_MACHINE_OUTPUT_OFFSET_PCT = { x: 0.0, y: 0.25, From dad3ccb238a2d29d3fa7ea19101ca0cbcae359af Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 10:58:36 -0800 Subject: [PATCH 140/401] Cleanup pitching.js --- examples/baseball/pitching.js | 35 ++++------------------------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 8fdb53dcdc..7cb8abba33 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -76,7 +76,7 @@ var PITCHING_MACHINE_PROPERTIES = { position: { x: -0.93, y: 0.8, - z: -19.8, + z: -19.8 }, velocity: { x: 0, @@ -91,7 +91,7 @@ var PITCHING_MACHINE_PROPERTIES = { registrationPoint: { x: 0.5, y: 0.5, - z: 0.5, + z: 0.5 }, rotation: Quat.fromPitchYawRollDegrees(0, 180, 0), modelURL: PITCHING_MACHINE_URL, @@ -124,6 +124,8 @@ getOrCreatePitchingMachine = function() { return new PitchingMachine(pitchingMachineID); } +// The pitching machine wraps an entity ID and uses it's position & rotation to determin where to +// pitch the ball from and in which direction, and uses the dimensions to determine the scale of them ball. function PitchingMachine(pitchingMachineID) { this.pitchingMachineID = pitchingMachineID; this.enabled = false; @@ -271,35 +273,6 @@ var ACCELERATION_SPREAD = 0.35; var TRAIL_COLOR = { red: 128, green: 255, blue: 89 }; var TRAIL_LIFETIME = 20; -function ObjectTrail(entityID, startPosition) { - this.entityID = entityID; - this.line = null; - var lineInterval = null; - - var lastPosition = startPosition; - trail = new InfiniteLine(startPosition, trailColor, trailLifetime); - trailInterval = Script.setInterval(function() { - var properties = Entities.getEntityProperties(entityID, ['position']); - if (Vec3.distance(properties.position, lastPosition)) { - var strokeWidth = Math.log(1 + trail.size) * 0.05; - trail.enqueuePoint(properties.position, strokeWidth); - lastPosition = properties.position; - } - }, 50); -} - -ObjectTrail.prototype = { - destroy: function() { - if (this.line) { - Script.clearInterval(this.lineInterval); - this.lineInterval = null; - - this.line.destroy(); - this.line = null; - } - } -}; - var trail = null; var trailInterval = null; function cleanupTrail() { From 661b2180f57d313b6221067cc60c5770a7fd1a47 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 10:59:31 -0800 Subject: [PATCH 141/401] Update updateBillboard argument --- examples/baseball/pitching.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 7cb8abba33..8d33d25fd3 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -347,21 +347,21 @@ function Baseball(position, velocity, ballScale) { } } -// Update the stadium billboard with the current distance and update the high score +// Update the stadium billboard with the current distance or a text message and update the high score // if it has been beaten. -function updateBillboard(distance) { +function updateBillboard(distanceOrMessage) { Entities.editEntity(DISTANCE_BILLBOARD_ENTITY_ID, { - text: distance, + text: distanceOrMessage, }); // If a number was passed in, let's see if it is larger than the current high score // and update it if so. - if (!isNaN(distance)) { + if (!isNaN(distanceOrMessage)) { var properties = Entities.getEntityProperties(HIGH_SCORE_BILLBOARD_ENTITY_ID, ["text"]); var bestDistance = parseInt(properties.text); - if (distance >= bestDistance) { + if (distanceOrMessage >= bestDistance) { Entities.editEntity(HIGH_SCORE_BILLBOARD_ENTITY_ID, { - text: distance, + text: distanceOrMessage, }); return true; } From 38fcdc3efff404d50170165157fb3e63360094a7 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 10:59:46 -0800 Subject: [PATCH 142/401] Remove unused code from pitching.js --- examples/baseball/pitching.js | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 8d33d25fd3..e749310b9b 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -498,16 +498,6 @@ Baseball.prototype = { var baseball = null; -function update(dt) { - if (baseball) { - baseball.update(dt); - if (baseball.finished()) { - baseball = null; - Script.setTimeout(pitchBall, 3000); - } - } -} - function entityCollisionWithGround(ground, entity, collision) { var ZERO_VEC = { x: 0, y: 0, z: 0 }; var dVelocityMagnitude = Vec3.length(collision.velocityChange); @@ -547,9 +537,4 @@ Script.scriptEnding.connect(function() { Entities.deleteEntity(pitchingMachineID); }); -//Script.update.connect(update); -//var pitchingMachine = getPitchingMachine(); -//pitchingMachine.pitchBall(); -//Script.update.connect(function(dt) { pitchingMachine.update(dt); }); - print("Done loading pitching.js"); From a5c7269096f1b57c02865251b2cb0fc6737f85e4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 9 Nov 2015 11:28:02 -0800 Subject: [PATCH 143/401] Use make_shared --- interface/src/InterfaceActionFactory.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/src/InterfaceActionFactory.cpp b/interface/src/InterfaceActionFactory.cpp index 67b3b4a649..8ace11c0a0 100644 --- a/interface/src/InterfaceActionFactory.cpp +++ b/interface/src/InterfaceActionFactory.cpp @@ -21,17 +21,17 @@ EntityActionPointer interfaceActionFactory(EntityActionType type, const QUuid& id, EntityItemPointer ownerEntity) { switch (type) { case ACTION_TYPE_NONE: - return nullptr; + return EntityActionPointer(); case ACTION_TYPE_OFFSET: - return (EntityActionPointer) new ObjectActionOffset(id, ownerEntity); + return std::make_shared(id, ownerEntity); case ACTION_TYPE_SPRING: - return (EntityActionPointer) new ObjectActionSpring(id, ownerEntity); + return std::make_shared(id, ownerEntity); case ACTION_TYPE_HOLD: - return (EntityActionPointer) new AvatarActionHold(id, ownerEntity); + return std::make_shared(id, ownerEntity); } - assert(false); - return nullptr; + Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown entity action type"); + return EntityActionPointer(); } From 278c921a50031ed8d85d7ce48665d7643163d9dc Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 11:35:56 -0800 Subject: [PATCH 144/401] Clean up bat.js --- examples/baseball/bat.js | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index eedda1e82a..5ca41b6c64 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -9,11 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +Script.include("pitching.js"); + (function() { - Script.include("pitching.js"); var pitchingMachine = null; - this.startNearGrab = function() { - print("Started near grab!"); + + this.startNearGrab = this.continueNearGrab = function() { if (!pitchingMachine) { pitchingMachine = getOrCreatePitchingMachine(); Script.update.connect(function(dt) { pitchingMachine.update(dt); }); @@ -21,16 +22,8 @@ pitchingMachine.start(); MyAvatar.shouldRenderLocally = false; }; - this.continueNearGrab = function() { - if (!pitchingMachine) { - pitchingMachine = getOrCreatePitchingMachine(); - Script.update.connect(function(dt) { pitchingMachine.update(dt); }); - } - pitchingMachine.start(); - MyAvatar.shouldRenderLocally = false; - } + this.releaseGrab = function() { - print("Stopped near grab!"); if (pitchingMachine) { pitchingMachine.stop(); } From 069284d8d192961194d3f7da591b404f8a83c50e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 11:51:08 -0800 Subject: [PATCH 145/401] Remove unused variable and print in pitching.js --- examples/baseball/pitching.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index e749310b9b..1b633081d5 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -496,8 +496,6 @@ Baseball.prototype = { } } -var baseball = null; - function entityCollisionWithGround(ground, entity, collision) { var ZERO_VEC = { x: 0, y: 0, z: 0 }; var dVelocityMagnitude = Vec3.length(collision.velocityChange); @@ -536,5 +534,3 @@ Script.scriptEnding.connect(function() { cleanupTrail(); Entities.deleteEntity(pitchingMachineID); }); - -print("Done loading pitching.js"); From 5d4ce6aefcbce7046eab40e25bd66049ba7d6fb3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 12:02:10 -0800 Subject: [PATCH 146/401] Update include paths in pitching.js to be relative --- examples/baseball/pitching.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 1b633081d5..acba31cc3f 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -10,13 +10,14 @@ // print("Loading pitching"); -//Script.include("../libraries/line.js"); -Script.include("https://raw.githubusercontent.com/huffman/hifi/line-js/examples/libraries/line.js"); -Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/firework.js"); -Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/utils.js"); + +Script.include("../libraries/line.js"); +Script.include("firework.js"); +Script.include("utils.js"); var DISTANCE_BILLBOARD_NAME = "CurrentScore"; var HIGH_SCORE_BILLBOARD_NAME = "HighScore"; + var DISTANCE_BILLBOARD_ENTITY_ID = findEntity({name: DISTANCE_BILLBOARD_NAME }, 1000); var HIGH_SCORE_BILLBOARD_ENTITY_ID = findEntity({name: HIGH_SCORE_BILLBOARD_NAME }, 1000); From a400d639604c468aeb08e11075f86c12fccaf856 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 12:02:28 -0800 Subject: [PATCH 147/401] Cleanup Baseball in pitching.js --- examples/baseball/pitching.js | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index acba31cc3f..db90d6658a 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -143,7 +143,6 @@ PitchingMachine.prototype = { } print("Pitching ball"); - var pitchDirection = { x: 0, y: 0, z: 1 }; var machineProperties = Entities.getEntityProperties(this.pitchingMachineID, ["dimensions", "position", "rotation"]); var pitchFromPositionBase = machineProperties.position; var pitchFromOffset = vec3Mult(machineProperties.dimensions, PITCHING_MACHINE_OUTPUT_OFFSET_PCT); @@ -165,7 +164,6 @@ PitchingMachine.prototype = { } else { this.injector.restart(); } - print("Created baseball"); }, start: function() { if (this.enabled) { @@ -188,7 +186,7 @@ PitchingMachine.prototype = { if (this.baseball.finished()) { this.baseball = null; var self = this; - Script.setTimeout(function() { self.pitchBall() }, 3000); + Script.setTimeout(function() { self.pitchBall(); }, 3000); } } } @@ -424,29 +422,38 @@ Baseball.prototype = { if (name == "Bat") { if (this.state == BASEBALL_STATE.PITCHING) { print("HIT"); + + var FOUL_MIN_YAW = -135.0; + var FOUL_MAX_YAW = 135.0; + var yaw = Math.atan2(myVelocity.x, myVelocity.z) * 180 / Math.PI; - var foul = yaw > -135 && yaw < 135; + var foul = yaw > FOUL_MIN_YAW && yaw < FOUL_MAX_YAW; var speedMultiplier = 2; if (foul && myVelocity.z > 0) { + var TUNNELED_PITCH_RANGE = 15.0; var xzDist = Math.sqrt(myVelocity.x * myVelocity.x + myVelocity.z * myVelocity.z); var pitch = Math.atan2(myVelocity.y, xzDist) * 180 / Math.PI; print("Pitch: ", pitch); - if (Math.abs(pitch) < 15) { + // If the pitch is going straight out the back and has a pitch in the range TUNNELED_PITCH_RANGE, + // let's assume the ball tunneled through the bat and reverse its direction. + if (Math.abs(pitch) < TUNNELED_PITCH_RANGE) { print("Reversing hit"); myVelocity.x *= -1; myVelocity.y *= -1; myVelocity.z *= -1; - Vec3.length(myVelocity); - foul = false; - speedMultiplier = 10; + + yaw = Math.atan2(myVelocity.x, myVelocity.z) * 180 / Math.PI; + foul = yaw > FOUL_MIN_YAW && yaw < FOUL_MAX_YAW; + + speedMultiplier = 3; } } // Update ball velocity Entities.editEntity(self.entityID, { - velocity: Vec3.multiply(speedMultiplier, myVelocity), + velocity: Vec3.multiply(speedMultiplier, myVelocity) }); // Setup line update interval From 9ec51d822e518ae677ef677ae9a4d638dd5df580 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Nov 2015 13:35:54 -0800 Subject: [PATCH 148/401] send the avatar to /baseball on bat pickup --- examples/baseball/bat.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index 5ca41b6c64..c7e3d8ebfb 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -15,6 +15,9 @@ Script.include("pitching.js"); var pitchingMachine = null; this.startNearGrab = this.continueNearGrab = function() { + // send the avatar to the baseball location so that they're ready to bat + MyAvatar.location = "/baseball" + if (!pitchingMachine) { pitchingMachine = getOrCreatePitchingMachine(); Script.update.connect(function(dt) { pitchingMachine.update(dt); }); From d65571ea41aaab67653c88e13767fc63a9a3da46 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Nov 2015 13:36:18 -0800 Subject: [PATCH 149/401] use the birarda baseball script on the createBatButton --- examples/baseball/createBatButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index b105253347..81bcaed089 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -46,7 +46,7 @@ var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; - var SCRIPT_URL = "http://rawgit.com/huffman/hifi/baseball/examples/baseball/bat.js" + var SCRIPT_URL = "http://rawgit.com/birarda/hifi/baseball/examples/baseball/bat.js" var batUserData = { grabbableKey: { From 962881ad31725c3e3b2c8f2741215ff3c5a3f2a3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Nov 2015 13:43:52 -0800 Subject: [PATCH 150/401] use startNearTrigger and startFarTrigger for create button --- examples/baseball/createBatButton.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 81bcaed089..2a462bca65 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -16,10 +16,10 @@ } this.dropBats(); }; - this.startNearGrabNonColliding = function() { + this.startNearTrigger = function() { this.dropBats(); }; - this.startFarGrabNonColliding = function() { + this.startFarTrigger = function() { this.dropBats(); }; this.dropBats = function() { From cea2e0fafdd9dec22abb4ee6fd1f26d3a93b6fd6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Nov 2015 14:21:14 -0800 Subject: [PATCH 151/401] don't force location in continueNearGrab --- examples/baseball/bat.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index c7e3d8ebfb..a4509c53d8 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -14,18 +14,26 @@ Script.include("pitching.js"); (function() { var pitchingMachine = null; - this.startNearGrab = this.continueNearGrab = function() { - // send the avatar to the baseball location so that they're ready to bat - MyAvatar.location = "/baseball" - + this.pitchAndHideAvatar = function() { if (!pitchingMachine) { pitchingMachine = getOrCreatePitchingMachine(); Script.update.connect(function(dt) { pitchingMachine.update(dt); }); } pitchingMachine.start(); MyAvatar.shouldRenderLocally = false; + } + + this.startNearGrab = function() { + // send the avatar to the baseball location so that they're ready to bat + MyAvatar.location = "/baseball" + + pitchAndHideAvatar() }; + this.continueNearGrab = function() { + pitchAndHideAvatar() + } + this.releaseGrab = function() { if (pitchingMachine) { pitchingMachine.stop(); From 4ab653610914063c4c89e0880711e73d56cdb276 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 15:06:43 -0800 Subject: [PATCH 152/401] Fix Vive dynamic pointer cast compile error on Windows --- interface/src/avatar/AvatarActionHold.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index d2842e325b..31e33a9b22 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -60,7 +60,7 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { }); if (it != std::end(plugins)) { - const auto& vive = it->dynamicCast(); + const auto& vive = std::dynamic_pointer_cast(*it); auto index = (_hand == "left") ? 0 : 1; auto userInputMapper = DependencyManager::get(); auto pos = extractTranslation(userInputMapper->getSensorToWorldMat()); From 244fd86d1e4cbeed52e29413ce9249ea882f7de1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Nov 2015 15:31:53 -0800 Subject: [PATCH 153/401] add semi-colons to bat.js --- examples/baseball/bat.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index a4509c53d8..0b0902d67e 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -21,7 +21,7 @@ Script.include("pitching.js"); } pitchingMachine.start(); MyAvatar.shouldRenderLocally = false; - } + }; this.startNearGrab = function() { // send the avatar to the baseball location so that they're ready to bat @@ -32,7 +32,7 @@ Script.include("pitching.js"); this.continueNearGrab = function() { pitchAndHideAvatar() - } + }; this.releaseGrab = function() { if (pitchingMachine) { From 44ab236673af5cc4dc3f49872f3ccc3eee369b69 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Nov 2015 15:33:23 -0800 Subject: [PATCH 154/401] Fix include in bat.js --- examples/baseball/bat.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index 0b0902d67e..d259b99f32 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -9,9 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include("pitching.js"); - (function() { + Script.include("pitching.js"); + var pitchingMachine = null; this.pitchAndHideAvatar = function() { From b6c4ae757bd4f8f0b3e567e0d10bb2ad0dd1b2e0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Nov 2015 15:41:11 -0800 Subject: [PATCH 155/401] fix reference to pitchAndHideAvatar --- examples/baseball/bat.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index d259b99f32..7c69e3c590 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -27,11 +27,11 @@ // send the avatar to the baseball location so that they're ready to bat MyAvatar.location = "/baseball" - pitchAndHideAvatar() + this.pitchAndHideAvatar() }; this.continueNearGrab = function() { - pitchAndHideAvatar() + this.pitchAndHideAvatar() }; this.releaseGrab = function() { From 57b4302e0df519bdd171f43f80f8146e256463c3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Nov 2015 15:44:23 -0800 Subject: [PATCH 156/401] Fix setting of location in bat.js --- examples/baseball/bat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index 7c69e3c590..164a6bb2e4 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -25,7 +25,7 @@ this.startNearGrab = function() { // send the avatar to the baseball location so that they're ready to bat - MyAvatar.location = "/baseball" + Window.location = "/baseball" this.pitchAndHideAvatar() }; From 0b1ecdec740a589992083d8a236e0150f587cab2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Nov 2015 15:49:54 -0800 Subject: [PATCH 157/401] use just location to go to path --- examples/baseball/bat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/bat.js b/examples/baseball/bat.js index 164a6bb2e4..40c3d43670 100644 --- a/examples/baseball/bat.js +++ b/examples/baseball/bat.js @@ -25,7 +25,7 @@ this.startNearGrab = function() { // send the avatar to the baseball location so that they're ready to bat - Window.location = "/baseball" + location = "/baseball" this.pitchAndHideAvatar() }; From b3cdee278a37f84443140543e140f772347a7135 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 9 Nov 2015 16:14:18 -0800 Subject: [PATCH 158/401] Different approach for bat positionning --- interface/src/avatar/AvatarActionHold.cpp | 52 ++++++++++++----------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 31e33a9b22..b230138110 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -35,9 +35,7 @@ AvatarActionHold::~AvatarActionHold() { qDebug() << "AvatarActionHold::~AvatarActionHold"; #endif } -#include -#include -#include + void AvatarActionHold::updateActionWorker(float deltaTimeStep) { bool gotLock = false; glm::quat rotation; @@ -53,28 +51,6 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { glm::vec3 palmPosition; glm::quat palmRotation; -#ifdef Q_OS_WIN - const auto& plugins = PluginManager::getInstance()->getInputPlugins(); - auto it = std::find_if(std::begin(plugins), std::end(plugins), [](const InputPluginPointer& plugin) { - return plugin->getName() == ViveControllerManager::NAME; - }); - - if (it != std::end(plugins)) { - const auto& vive = std::dynamic_pointer_cast(*it); - auto index = (_hand == "left") ? 0 : 1; - auto userInputMapper = DependencyManager::get(); - auto pos = extractTranslation(userInputMapper->getSensorToWorldMat()); - auto rot = glm::quat_cast(userInputMapper->getSensorToWorldMat()); - - - static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); - static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X); - static const glm::quat viveToHand = yFlip * quarterX; - - palmPosition = pos + rot * vive->getPosition(index); - palmRotation = rot * vive->getRotation(index);// * viveToHand * glm::angleAxis(PI, glm::vec3(1.0f, 0.0f, 0.0f)) * glm::angleAxis(PI_OVER_TWO, glm::vec3(0.0f, 0.0f, 1.0f)); - } else -#endif if (_hand == "right") { palmPosition = holdingAvatar->getRightPalmPosition(); palmRotation = holdingAvatar->getRightPalmRotation(); @@ -83,6 +59,32 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { palmRotation = holdingAvatar->getLeftPalmRotation(); } + static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches + static const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, + CONTROLLER_LENGTH_OFFSET / 2.0f, + CONTROLLER_LENGTH_OFFSET * 2.0f); + static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); + static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X); + static const glm::quat viveToHand = yFlip * quarterX; + + static const glm::quat leftQuaterZ = glm::angleAxis(-PI_OVER_TWO, Vectors::UNIT_Z); + static const glm::quat rightQuaterZ = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_Z); + static const glm::quat eighthX = glm::angleAxis(PI / 4.0f, Vectors::UNIT_X); + + static const glm::quat leftRotationOffset = glm::inverse(leftQuaterZ * eighthX) * viveToHand; + static const glm::quat rightRotationOffset = glm::inverse(rightQuaterZ * eighthX) * viveToHand; + + static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET; + static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET; + + if (_hand == "left") { + _relativeRotation = leftRotationOffset; + _relativePosition = glm::inverse(_relativeRotation) * leftTranslationOffset; + } else { + _relativeRotation = rightRotationOffset; + _relativePosition = glm::inverse(_relativeRotation) * rightTranslationOffset; + } + rotation = palmRotation * _relativeRotation; position = palmPosition + rotation * _relativePosition; } From 03dd234253a7b9c1aaebbddbee4509ebd6ddc1e9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 9 Nov 2015 16:48:54 -0800 Subject: [PATCH 159/401] Update pitching.js to get billboard ids lazily --- examples/baseball/pitching.js | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index db90d6658a..62492c9563 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -18,14 +18,20 @@ Script.include("utils.js"); var DISTANCE_BILLBOARD_NAME = "CurrentScore"; var HIGH_SCORE_BILLBOARD_NAME = "HighScore"; -var DISTANCE_BILLBOARD_ENTITY_ID = findEntity({name: DISTANCE_BILLBOARD_NAME }, 1000); -var HIGH_SCORE_BILLBOARD_ENTITY_ID = findEntity({name: HIGH_SCORE_BILLBOARD_NAME }, 1000); +var distanceBillboardEntityID = null; +var highScoreBillboardEntityID = null; -if (DISTANCE_BILLBOARD_ENTITY_ID === null) { - print("WARNING: Distance billboard cannot be found."); +function getDistanceBillboardEntityID() { + if (distanceBillboardEntityID === null) { + distanceBillboardEntityID = findEntity({name: DISTANCE_BILLBOARD_NAME }, 1000); + } + return distanceBillboardEntityID; } -if (HIGH_SCORE_BILLBOARD_ENTITY_ID === null) { - print("WARNING: High Score billboard cannot be found."); +function getHighScoreBillboardEntityID() { + if (highScoreBillboardEntityID === null) { + highScoreBillboardEntityID = findEntity({name: HIGH_SCORE_BILLBOARD_NAME }, 1000); + } + return highScoreBillboardEntityID; } var METERS_TO_FEET = 3.28084; @@ -349,17 +355,21 @@ function Baseball(position, velocity, ballScale) { // Update the stadium billboard with the current distance or a text message and update the high score // if it has been beaten. function updateBillboard(distanceOrMessage) { - Entities.editEntity(DISTANCE_BILLBOARD_ENTITY_ID, { - text: distanceOrMessage, - }); + var distanceBillboardEntityID = getDistanceBillboardEntityID(); + if (distanceBillboardEntityID) { + Entities.editEntity(distanceBillboardEntityID, { + text: distanceOrMessage + }); + } + var highScoreBillboardEntityID = getHighScoreBillboardEntityID; // If a number was passed in, let's see if it is larger than the current high score // and update it if so. - if (!isNaN(distanceOrMessage)) { - var properties = Entities.getEntityProperties(HIGH_SCORE_BILLBOARD_ENTITY_ID, ["text"]); + if (!isNaN(distanceOrMessage) && highScoreBillboardEntityID) { + var properties = Entities.getEntityProperties(highScoreBillboardEntityID, ["text"]); var bestDistance = parseInt(properties.text); if (distanceOrMessage >= bestDistance) { - Entities.editEntity(HIGH_SCORE_BILLBOARD_ENTITY_ID, { + Entities.editEntity(highScoreBillboardEntityID, { text: distanceOrMessage, }); return true; From 765bca9a7b9b0c1a4b7ff86a224172c367c4a10c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 9 Nov 2015 18:05:45 -0800 Subject: [PATCH 160/401] Work on hold action --- interface/src/avatar/AvatarActionHold.cpp | 110 +++++++++++++--------- 1 file changed, 64 insertions(+), 46 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index b230138110..9384cc2216 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -51,61 +51,79 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { glm::vec3 palmPosition; glm::quat palmRotation; - if (_hand == "right") { - palmPosition = holdingAvatar->getRightPalmPosition(); - palmRotation = holdingAvatar->getRightPalmRotation(); + bool ignoreIK = true; + if (ignoreIK) { + if (_hand == "right") { + palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getPosition(); + palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getRotation(); + } else { + palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getPosition(); + palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getRotation(); + } } else { - palmPosition = holdingAvatar->getLeftPalmPosition(); - palmRotation = holdingAvatar->getLeftPalmRotation(); - } - - static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches - static const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, - CONTROLLER_LENGTH_OFFSET / 2.0f, - CONTROLLER_LENGTH_OFFSET * 2.0f); - static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); - static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X); - static const glm::quat viveToHand = yFlip * quarterX; - - static const glm::quat leftQuaterZ = glm::angleAxis(-PI_OVER_TWO, Vectors::UNIT_Z); - static const glm::quat rightQuaterZ = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_Z); - static const glm::quat eighthX = glm::angleAxis(PI / 4.0f, Vectors::UNIT_X); - - static const glm::quat leftRotationOffset = glm::inverse(leftQuaterZ * eighthX) * viveToHand; - static const glm::quat rightRotationOffset = glm::inverse(rightQuaterZ * eighthX) * viveToHand; - - static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET; - static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET; - - if (_hand == "left") { - _relativeRotation = leftRotationOffset; - _relativePosition = glm::inverse(_relativeRotation) * leftTranslationOffset; - } else { - _relativeRotation = rightRotationOffset; - _relativePosition = glm::inverse(_relativeRotation) * rightTranslationOffset; + if (_hand == "right") { + palmPosition = holdingAvatar->getRightPalmPosition(); + palmRotation = holdingAvatar->getRightPalmRotation(); + } else { + palmPosition = holdingAvatar->getLeftPalmPosition(); + palmRotation = holdingAvatar->getLeftPalmRotation(); + } } + /* + static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches + static const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, + CONTROLLER_LENGTH_OFFSET / 2.0f, + CONTROLLER_LENGTH_OFFSET * 2.0f); + static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); + static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X); + static const glm::quat viveToHand = yFlip * quarterX; + + static const glm::quat leftQuaterZ = glm::angleAxis(-PI_OVER_TWO, Vectors::UNIT_Z); + static const glm::quat rightQuaterZ = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_Z); + static const glm::quat eighthX = glm::angleAxis(PI / 4.0f, Vectors::UNIT_X); + + static const glm::quat leftRotationOffset = glm::inverse(leftQuaterZ * eighthX) * viveToHand; + static const glm::quat rightRotationOffset = glm::inverse(rightQuaterZ * eighthX) * viveToHand; + + static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET; + static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET; + + glm::quat relRot = glm::inverse(rightRotationOffset); + glm::vec3 relPos = -rightTranslationOffset; + relRot = palmRotation * relRot; + relPos = palmPosition + relRot * relPos; + + rotation = relRot * _relativeRotation; + position = relPos + rotation * _relativePosition; + glm::quat diffRot = glm::inverse(palmRotation) * rotation; + glm::vec3 diffPos = glm::inverse(rotation) * (position - palmPosition); + qDebug() << "diffRot =" << safeEulerAngles(diffRot); + qDebug() << "diffPos =" << diffPos; + */ + //[11 / 09 17:40 : 14] [DEBUG] diffRot = { type = 'glm::vec3', x = 3.14159, y = 9.04283e-09, z = 0.785398 } + //[11 / 09 17:40 : 14][DEBUG] diffPos = { type = 'glm::vec3', x = 1.0524, y = -0.0381001, z = -0.0380997 } + //_relativeRotation = glm::quat(glm::vec3(3.14159f, 0.0f, 0.785398)); + //_relativePosition = glm::vec3(1.0524, -0.0381001, -0.0380997); rotation = palmRotation * _relativeRotation; position = palmPosition + rotation * _relativePosition; } }); - if (holdingAvatar) { + if (holdingAvatar && gotLock) { + gotLock = withTryWriteLock([&]{ + _positionalTarget = position; + _rotationalTarget = rotation; + _positionalTargetSet = true; + _rotationalTargetSet = true; + _active = true; + }); if (gotLock) { - gotLock = withTryWriteLock([&]{ - _positionalTarget = position; - _rotationalTarget = rotation; - _positionalTargetSet = true; - _rotationalTargetSet = true; - _active = true; - }); - if (gotLock) { - if (_kinematic) { - doKinematicUpdate(deltaTimeStep); - } else { - activateBody(); - ObjectActionSpring::updateActionWorker(deltaTimeStep); - } + if (_kinematic) { + doKinematicUpdate(deltaTimeStep); + } else { + activateBody(); + ObjectActionSpring::updateActionWorker(deltaTimeStep); } } } From 7050139a56bcd90c32b4e592e8561b7017647ac2 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 10 Nov 2015 13:41:19 -0800 Subject: [PATCH 161/401] Bit of code cleanup --- interface/src/avatar/AvatarActionHold.cpp | 21 ++++++++----------- interface/src/avatar/AvatarActionHold.h | 7 ++++--- .../input-plugins/ViveControllerManager.cpp | 18 +++++++++------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 9384cc2216..12759d5208 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -9,31 +9,28 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "QVariantGLM.h" +#include "AvatarActionHold.h" + +#include + #include "avatar/MyAvatar.h" #include "avatar/AvatarManager.h" -#include "AvatarActionHold.h" - const uint16_t AvatarActionHold::holdVersion = 1; AvatarActionHold::AvatarActionHold(const QUuid& id, EntityItemPointer ownerEntity) : - ObjectActionSpring(id, ownerEntity), - _relativePosition(glm::vec3(0.0f)), - _relativeRotation(glm::quat()), - _hand("right"), - _holderID(QUuid()) + ObjectActionSpring(id, ownerEntity) { _type = ACTION_TYPE_HOLD; - #if WANT_DEBUG +#if WANT_DEBUG qDebug() << "AvatarActionHold::AvatarActionHold"; - #endif +#endif } AvatarActionHold::~AvatarActionHold() { - #if WANT_DEBUG +#if WANT_DEBUG qDebug() << "AvatarActionHold::~AvatarActionHold"; - #endif +#endif } void AvatarActionHold::updateActionWorker(float deltaTimeStep) { diff --git a/interface/src/avatar/AvatarActionHold.h b/interface/src/avatar/AvatarActionHold.h index 15a096d1ce..ec1df2f0e0 100644 --- a/interface/src/avatar/AvatarActionHold.h +++ b/interface/src/avatar/AvatarActionHold.h @@ -35,12 +35,13 @@ public: private: static const uint16_t holdVersion; - glm::vec3 _relativePosition; + void doKinematicUpdate(float deltaTimeStep); + + glm::vec3 _relativePosition { 0.0f }; glm::quat _relativeRotation; - QString _hand; + QString _hand { "right" }; QUuid _holderID; - void doKinematicUpdate(float deltaTimeStep); bool _kinematic { false }; bool _kinematicSetVelocity { false }; bool _previousSet { false }; diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index 7d8ff22f73..9c95bb9426 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -35,17 +35,19 @@ vr::IVRSystem* acquireOpenVrSystem(); void releaseOpenVrSystem(); -const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches -const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, CONTROLLER_LENGTH_OFFSET / 2.0f, 2.0f * CONTROLLER_LENGTH_OFFSET); // three inches -const QString CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b"; +static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches +static const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, + CONTROLLER_LENGTH_OFFSET / 2.0f, + CONTROLLER_LENGTH_OFFSET * 2.0f); +static const QString CONTROLLER_MODEL_STRING = "vr_controller_05_wireless_b"; + +static const QString MENU_PARENT = "Avatar"; +static const QString MENU_NAME = "Vive Controllers"; +static const QString MENU_PATH = MENU_PARENT + ">" + MENU_NAME; +static const QString RENDER_CONTROLLERS = "Render Hand Controllers"; const QString ViveControllerManager::NAME = "OpenVR"; -const QString MENU_PARENT = "Avatar"; -const QString MENU_NAME = "Vive Controllers"; -const QString MENU_PATH = MENU_PARENT + ">" + MENU_NAME; -const QString RENDER_CONTROLLERS = "Render Hand Controllers"; - bool ViveControllerManager::isSupported() const { #ifdef Q_OS_WIN auto hmd = acquireOpenVrSystem(); From 8da8b4db8c20dc0cfb50013124c3e4457269ab59 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 10 Nov 2015 13:42:25 -0800 Subject: [PATCH 162/401] Add option to ignore IK for my avatar's entity actions --- interface/src/avatar/AvatarActionHold.cpp | 19 +++++++++++++++---- interface/src/avatar/AvatarActionHold.h | 1 + 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 12759d5208..ad793ab53f 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -48,8 +48,9 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { glm::vec3 palmPosition; glm::quat palmRotation; - bool ignoreIK = true; - if (ignoreIK) { + if (_ignoreIK && holdingAvatar->isMyAvatar()) { + // We cannot ignore other avatars IK and this is not the point of this option + // This is meant to make the grabbing behavior more reactive. if (_hand == "right") { palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getPosition(); palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getRotation(); @@ -179,6 +180,7 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { QUuid holderID; bool kinematic; bool kinematicSetVelocity; + bool ignoreIK; bool needUpdate = false; bool somethingChanged = ObjectAction::updateArguments(arguments); @@ -216,13 +218,19 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { if (!ok) { _kinematic = false; } - + ok = true; kinematicSetVelocity = EntityActionInterface::extractBooleanArgument("hold", arguments, "kinematicSetVelocity", ok, false); if (!ok) { _kinematicSetVelocity = false; } + + ok = true; + ignoreIK = EntityActionInterface::extractBooleanArgument("hold", arguments, "ignoreIK", ok, false); + if (!ok) { + _ignoreIK = true; + } if (somethingChanged || relativePosition != _relativePosition || @@ -231,7 +239,8 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { hand != _hand || holderID != _holderID || kinematic != _kinematic || - kinematicSetVelocity != _kinematicSetVelocity) { + kinematicSetVelocity != _kinematicSetVelocity || + ignoreIK != _ignoreIK) { needUpdate = true; } }); @@ -247,6 +256,7 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { _holderID = holderID; _kinematic = kinematic; _kinematicSetVelocity = kinematicSetVelocity; + _ignoreIK = ignoreIK; _active = true; auto ownerEntity = _ownerEntity.lock(); @@ -270,6 +280,7 @@ QVariantMap AvatarActionHold::getArguments() { arguments["hand"] = _hand; arguments["kinematic"] = _kinematic; arguments["kinematicSetVelocity"] = _kinematicSetVelocity; + arguments["ignoreIK"] = _ignoreIK; }); return arguments; } diff --git a/interface/src/avatar/AvatarActionHold.h b/interface/src/avatar/AvatarActionHold.h index ec1df2f0e0..2da32b9352 100644 --- a/interface/src/avatar/AvatarActionHold.h +++ b/interface/src/avatar/AvatarActionHold.h @@ -45,6 +45,7 @@ private: bool _kinematic { false }; bool _kinematicSetVelocity { false }; bool _previousSet { false }; + bool _ignoreIK { true }; glm::vec3 _previousPositionalTarget; glm::quat _previousRotationalTarget; From d79221edd2a03b073fe04322a0df5df25fcafdd1 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 10 Nov 2015 14:06:59 -0800 Subject: [PATCH 163/401] AvatarActionHold can ignore IK --- interface/src/avatar/AvatarActionHold.cpp | 89 ++++++++++--------- interface/src/avatar/AvatarActionHold.h | 3 + .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 1 + 4 files changed, 54 insertions(+), 41 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index ad793ab53f..f080e947d0 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -45,13 +45,14 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { holdingAvatar = std::static_pointer_cast(holdingAvatarData); if (holdingAvatar) { + bool isRightHand = (_hand == "right"); glm::vec3 palmPosition; glm::quat palmRotation; if (_ignoreIK && holdingAvatar->isMyAvatar()) { // We cannot ignore other avatars IK and this is not the point of this option // This is meant to make the grabbing behavior more reactive. - if (_hand == "right") { + if (isRightHand) { palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getPosition(); palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getRotation(); } else { @@ -59,7 +60,7 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getRotation(); } } else { - if (_hand == "right") { + if (isRightHand) { palmPosition = holdingAvatar->getRightPalmPosition(); palmRotation = holdingAvatar->getRightPalmRotation(); } else { @@ -67,44 +68,26 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { palmRotation = holdingAvatar->getLeftPalmRotation(); } } - /* - static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches - static const glm::vec3 CONTROLLER_OFFSET = glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, - CONTROLLER_LENGTH_OFFSET / 2.0f, - CONTROLLER_LENGTH_OFFSET * 2.0f); - static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); - static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X); - static const glm::quat viveToHand = yFlip * quarterX; - - static const glm::quat leftQuaterZ = glm::angleAxis(-PI_OVER_TWO, Vectors::UNIT_Z); - static const glm::quat rightQuaterZ = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_Z); - static const glm::quat eighthX = glm::angleAxis(PI / 4.0f, Vectors::UNIT_X); - - static const glm::quat leftRotationOffset = glm::inverse(leftQuaterZ * eighthX) * viveToHand; - static const glm::quat rightRotationOffset = glm::inverse(rightQuaterZ * eighthX) * viveToHand; - - static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET; - static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET; - - glm::quat relRot = glm::inverse(rightRotationOffset); - glm::vec3 relPos = -rightTranslationOffset; - relRot = palmRotation * relRot; - relPos = palmPosition + relRot * relPos; - - rotation = relRot * _relativeRotation; - position = relPos + rotation * _relativePosition; - glm::quat diffRot = glm::inverse(palmRotation) * rotation; - glm::vec3 diffPos = glm::inverse(rotation) * (position - palmPosition); - qDebug() << "diffRot =" << safeEulerAngles(diffRot); - qDebug() << "diffPos =" << diffPos; - */ - //[11 / 09 17:40 : 14] [DEBUG] diffRot = { type = 'glm::vec3', x = 3.14159, y = 9.04283e-09, z = 0.785398 } - //[11 / 09 17:40 : 14][DEBUG] diffPos = { type = 'glm::vec3', x = 1.0524, y = -0.0381001, z = -0.0380997 } - //_relativeRotation = glm::quat(glm::vec3(3.14159f, 0.0f, 0.785398)); - //_relativePosition = glm::vec3(1.0524, -0.0381001, -0.0380997); - rotation = palmRotation * _relativeRotation; - position = palmPosition + rotation * _relativePosition; + if (isRightHand) { + rotation = palmRotation * _perHandRelativeRotation; + position = palmPosition + rotation * _perHandRelativePosition; + } else { + auto mirroredRotation = _perHandRelativeRotation; + auto mirroredPosition = _perHandRelativePosition; + + // Mirror along z axis + mirroredRotation.z *= -1; + mirroredRotation.w *= -1; + + mirroredPosition.z *= -1; + + rotation = palmRotation * mirroredRotation; + position = palmPosition + rotation * mirroredPosition; + } + + rotation = rotation * _relativeRotation; + position = position + rotation * _relativePosition; } }); @@ -175,6 +158,8 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) { bool AvatarActionHold::updateArguments(QVariantMap arguments) { glm::vec3 relativePosition; glm::quat relativeRotation; + glm::vec3 perHandRelativePosition; + glm::quat perHandRelativeRotation; float timeScale; QString hand; QUuid holderID; @@ -190,12 +175,26 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { if (!ok) { relativePosition = _relativePosition; } - + ok = true; relativeRotation = EntityActionInterface::extractQuatArgument("hold", arguments, "relativeRotation", ok, false); if (!ok) { relativeRotation = _relativeRotation; } + + ok = true; + perHandRelativePosition = EntityActionInterface::extractVec3Argument("hold", arguments, + "perHandRelativePosition", ok, false); + if (!ok) { + perHandRelativePosition = _perHandRelativePosition; + } + + ok = true; + perHandRelativeRotation = EntityActionInterface::extractQuatArgument("hold", arguments, + "perHandRelativeRotation", ok, false); + if (!ok) { + perHandRelativeRotation = _perHandRelativeRotation; + } ok = true; timeScale = EntityActionInterface::extractFloatArgument("hold", arguments, "timeScale", ok, false); @@ -235,6 +234,8 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { if (somethingChanged || relativePosition != _relativePosition || relativeRotation != _relativeRotation || + perHandRelativePosition != _perHandRelativePosition || + perHandRelativeRotation != _perHandRelativeRotation || timeScale != _linearTimeScale || hand != _hand || holderID != _holderID || @@ -249,6 +250,8 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { withWriteLock([&] { _relativePosition = relativePosition; _relativeRotation = relativeRotation; + _perHandRelativePosition = perHandRelativePosition; + _perHandRelativeRotation = perHandRelativeRotation; const float MIN_TIMESCALE = 0.1f; _linearTimeScale = glm::max(MIN_TIMESCALE, timeScale); _angularTimeScale = _linearTimeScale; @@ -276,6 +279,8 @@ QVariantMap AvatarActionHold::getArguments() { arguments["holderID"] = _holderID; arguments["relativePosition"] = glmToQMap(_relativePosition); arguments["relativeRotation"] = glmToQMap(_relativeRotation); + arguments["perHandRelativePosition"] = glmToQMap(_perHandRelativePosition); + arguments["perHandRelativeRotation"] = glmToQMap(_perHandRelativeRotation); arguments["timeScale"] = _linearTimeScale; arguments["hand"] = _hand; arguments["kinematic"] = _kinematic; @@ -297,6 +302,8 @@ QByteArray AvatarActionHold::serialize() const { dataStream << _holderID; dataStream << _relativePosition; dataStream << _relativeRotation; + dataStream << _perHandRelativePosition; + dataStream << _perHandRelativeRotation; dataStream << _linearTimeScale; dataStream << _hand; @@ -330,6 +337,8 @@ void AvatarActionHold::deserialize(QByteArray serializedArguments) { dataStream >> _holderID; dataStream >> _relativePosition; dataStream >> _relativeRotation; + dataStream >> _perHandRelativePosition; + dataStream >> _perHandRelativeRotation; dataStream >> _linearTimeScale; _angularTimeScale = _linearTimeScale; dataStream >> _hand; diff --git a/interface/src/avatar/AvatarActionHold.h b/interface/src/avatar/AvatarActionHold.h index 2da32b9352..3979efc113 100644 --- a/interface/src/avatar/AvatarActionHold.h +++ b/interface/src/avatar/AvatarActionHold.h @@ -39,6 +39,9 @@ private: glm::vec3 _relativePosition { 0.0f }; glm::quat _relativeRotation; + glm::vec3 _perHandRelativePosition { 0.0f }; + glm::quat _perHandRelativeRotation; + QString _hand { "right" }; QUuid _holderID; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 24034ff9b3..84cde04b96 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -38,7 +38,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityAdd: case PacketType::EntityEdit: case PacketType::EntityData: - return VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING; + return VERSION_ENTITIES_ACTIONS_IGNORE_IK; case PacketType::AvatarData: case PacketType::BulkAvatarData: default: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 82d905bf28..5d96e21e1c 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -146,5 +146,6 @@ const PacketVersion VERSION_ENTITIES_ANIMATION_PROPERTIES_GROUP = 46; const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP = 47; const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP_BIS = 48; const PacketVersion VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING = 49; +const PacketVersion VERSION_ENTITIES_ACTIONS_IGNORE_IK = 50; #endif // hifi_PacketHeaders_h From aca5cb2559043ccc53be8ba49bdd558d570e7dba Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 10 Nov 2015 14:18:27 -0800 Subject: [PATCH 164/401] Renamed header version --- libraries/networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 84cde04b96..5f57d5e5a5 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -38,7 +38,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityAdd: case PacketType::EntityEdit: case PacketType::EntityData: - return VERSION_ENTITIES_ACTIONS_IGNORE_IK; + return VERSION_ENTITIES_ACTIONS_PER_HAND_OFFSET; case PacketType::AvatarData: case PacketType::BulkAvatarData: default: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 5d96e21e1c..efcf965bb7 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -146,6 +146,6 @@ const PacketVersion VERSION_ENTITIES_ANIMATION_PROPERTIES_GROUP = 46; const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP = 47; const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP_BIS = 48; const PacketVersion VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING = 49; -const PacketVersion VERSION_ENTITIES_ACTIONS_IGNORE_IK = 50; +const PacketVersion VERSION_ENTITIES_ACTIONS_PER_HAND_OFFSET = 50; #endif // hifi_PacketHeaders_h From 3cbe1bc4da586f708f02dbe0c6f32e7219918731 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 10 Nov 2015 14:50:22 -0800 Subject: [PATCH 165/401] Mirror on x instead of z --- examples/baseball/createBatButton.js | 8 ++++---- interface/src/avatar/AvatarActionHold.cpp | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 2a462bca65..931ff185a4 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -51,10 +51,10 @@ var batUserData = { grabbableKey: { spatialKey: { - relativePosition: { - x: 0.9, y: 0, z: 0 - }, - relativeRotation: Quat.fromPitchYawRollDegrees(0, 90, 0) + relativePosition: { x: 0.9, y: 0, z: 0 }, + relativeRotation: Quat.fromPitchYawRollDegrees(0, 90, 0), + perHandRelativePosition: { x: 0.0808223, y: 0.134704, z: 0.0381 }, + perHandRelativeRotation: Quat.fromPitchYawRollDegrees(-180, 90, 45) } } } diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index f080e947d0..ad2465404c 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -76,11 +76,11 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { auto mirroredRotation = _perHandRelativeRotation; auto mirroredPosition = _perHandRelativePosition; - // Mirror along z axis - mirroredRotation.z *= -1; + // Mirror along x axis + mirroredRotation.x *= -1; mirroredRotation.w *= -1; - mirroredPosition.z *= -1; + mirroredPosition.x *= -1; rotation = palmRotation * mirroredRotation; position = palmPosition + rotation * mirroredPosition; From 735fd70a8eff47b4060879218c935b2df37c159d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 10 Nov 2015 17:04:53 -0800 Subject: [PATCH 166/401] Tweak perHandRotation/Position in action --- interface/src/avatar/AvatarActionHold.cpp | 36 +++++++++++++---------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index ad2465404c..7ca25dad42 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -35,8 +35,8 @@ AvatarActionHold::~AvatarActionHold() { void AvatarActionHold::updateActionWorker(float deltaTimeStep) { bool gotLock = false; - glm::quat rotation; - glm::vec3 position; + glm::quat rotation { Quaternions::IDENTITY }; + glm::vec3 position { Vectors::ZERO }; std::shared_ptr holdingAvatar = nullptr; gotLock = withTryReadLock([&]{ @@ -46,9 +46,11 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { if (holdingAvatar) { bool isRightHand = (_hand == "right"); - glm::vec3 palmPosition; - glm::quat palmRotation; + glm::vec3 palmPosition { Vectors::ZERO }; + glm::quat palmRotation { Quaternions::IDENTITY }; + + static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); if (_ignoreIK && holdingAvatar->isMyAvatar()) { // We cannot ignore other avatars IK and this is not the point of this option // This is meant to make the grabbing behavior more reactive. @@ -58,6 +60,7 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { } else { palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getPosition(); palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getRotation(); + palmRotation *= yFlip; // Match right hand frame of reference } } else { if (isRightHand) { @@ -66,28 +69,31 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { } else { palmPosition = holdingAvatar->getLeftPalmPosition(); palmRotation = holdingAvatar->getLeftPalmRotation(); + palmRotation *= yFlip; // Match right hand frame of reference } } + rotation = palmRotation * _relativeRotation; + position = palmPosition + rotation * _relativePosition; + if (isRightHand) { - rotation = palmRotation * _perHandRelativeRotation; - position = palmPosition + rotation * _perHandRelativePosition; + rotation *= _perHandRelativeRotation; + position += rotation * _perHandRelativePosition; } else { auto mirroredRotation = _perHandRelativeRotation; auto mirroredPosition = _perHandRelativePosition; - // Mirror along x axis - mirroredRotation.x *= -1; - mirroredRotation.w *= -1; + // Mirror along z axis + auto eulerAngles = safeEulerAngles(mirroredRotation); + eulerAngles.x *= -1; + eulerAngles.y *= -1; + mirroredRotation = glm::quat(eulerAngles); - mirroredPosition.x *= -1; + mirroredPosition.z *= -1; - rotation = palmRotation * mirroredRotation; - position = palmPosition + rotation * mirroredPosition; + rotation *= mirroredRotation; + position += rotation * mirroredPosition; } - - rotation = rotation * _relativeRotation; - position = position + rotation * _relativePosition; } }); From 4f1420a5eeb242a6d9733981781be15de4a32c17 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 10 Nov 2015 17:05:27 -0800 Subject: [PATCH 167/401] Tweak bat offsets --- examples/baseball/createBatButton.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 931ff185a4..f16f126f2c 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -52,9 +52,9 @@ grabbableKey: { spatialKey: { relativePosition: { x: 0.9, y: 0, z: 0 }, - relativeRotation: Quat.fromPitchYawRollDegrees(0, 90, 0), - perHandRelativePosition: { x: 0.0808223, y: 0.134704, z: 0.0381 }, - perHandRelativeRotation: Quat.fromPitchYawRollDegrees(-180, 90, 45) + relativeRotation: Quat.fromPitchYawRollDegrees(0, 0, 45), + perHandRelativePosition: { x: 0.0, y: -0.05, z: -0.04 }, + perHandRelativeRotation: Quat.fromPitchYawRollDegrees(0, 0, 0) } } } From ce57488b9fe8f668757c90a8b3922fdfc11a1d73 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 10 Nov 2015 17:10:15 -0800 Subject: [PATCH 168/401] cleanup dead code --- .../src/input-plugins/ViveControllerManager.cpp | 12 +----------- .../src/input-plugins/ViveControllerManager.h | 11 ++++------- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index 9c95bb9426..88fdff4bce 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -206,16 +206,6 @@ void ViveControllerManager::renderHand(const controller::Pose& pose, gpu::Batch& batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0); } -#ifdef Q_OS_WIN -glm::vec3 ViveControllerManager::getPosition(int hand) const { - const mat4& mat = _trackedDevicePoseMat4[hand ? 3 : 4]; - return extractTranslation(mat); -} -glm::quat ViveControllerManager::getRotation(int hand) const { - const mat4& mat = _trackedDevicePoseMat4[hand ? 3 : 4]; - return glm::quat_cast(mat); -} -#endif void ViveControllerManager::pluginUpdate(float deltaTime, bool jointsCaptured) { _inputDevice->update(deltaTime, jointsCaptured); @@ -263,7 +253,7 @@ void ViveControllerManager::InputDevice::update(float deltaTime, bool jointsCapt bool left = numTrackedControllers == 2; const mat4& mat = _trackedDevicePoseMat4[device]; - + if (!jointsCaptured) { handlePoseEvent(mat, numTrackedControllers - 1); } diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h index d664326da8..02bdecb10a 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.h +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.h @@ -31,7 +31,6 @@ namespace vr { class ViveControllerManager : public InputPlugin { Q_OBJECT public: - static const QString NAME; // Plugin functions virtual bool isSupported() const override; @@ -47,12 +46,6 @@ public: void updateRendering(RenderArgs* args, render::ScenePointer scene, render::PendingChanges pendingChanges); void setRenderControllers(bool renderControllers) { _renderControllers = renderControllers; } - - -#ifdef Q_OS_WIN - glm::vec3 getPosition(int device) const; - glm::quat getRotation(int device) const; -#endif private: class InputDevice : public controller::InputDevice { @@ -89,6 +82,10 @@ private: bool _renderControllers { false }; vr::IVRSystem* _hmd { nullptr }; std::shared_ptr _inputDevice { std::make_shared(_hmd) }; + + static const QString NAME; + + }; #endif // hifi__ViveControllerManager From 6e702a28906ab73581b2b876650ade235e64bb3c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 12 Nov 2015 11:18:05 -0800 Subject: [PATCH 169/401] Update range of LOD to go up to 20:2 --- libraries/octree/src/OctreeConstants.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/octree/src/OctreeConstants.h b/libraries/octree/src/OctreeConstants.h index a98f042006..0b05a8606c 100644 --- a/libraries/octree/src/OctreeConstants.h +++ b/libraries/octree/src/OctreeConstants.h @@ -24,7 +24,7 @@ const int HALF_TREE_SCALE = TREE_SCALE / 2; const float DEFAULT_OCTREE_SIZE_SCALE = TREE_SCALE * 400.0f; // This is used in the LOD Tools to translate between the size scale slider and the values used to set the OctreeSizeScale -const float MAX_LOD_SIZE_MULTIPLIER = 800.0f; +const float MAX_LOD_SIZE_MULTIPLIER = 4000.0f; const int NUMBER_OF_CHILDREN = 8; From a7dfc99a2e54a2083e58739723fbd2a6294cffb9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 13 Nov 2015 16:14:53 -0800 Subject: [PATCH 170/401] Fix high score not updating in baseball --- examples/baseball/pitching.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/pitching.js b/examples/baseball/pitching.js index 62492c9563..09f33c9dd4 100644 --- a/examples/baseball/pitching.js +++ b/examples/baseball/pitching.js @@ -362,7 +362,7 @@ function updateBillboard(distanceOrMessage) { }); } - var highScoreBillboardEntityID = getHighScoreBillboardEntityID; + var highScoreBillboardEntityID = getHighScoreBillboardEntityID(); // If a number was passed in, let's see if it is larger than the current high score // and update it if so. if (!isNaN(distanceOrMessage) && highScoreBillboardEntityID) { From 510189dfbc60705dfc5cb7847112ef6723044b1a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 17 Nov 2015 15:08:05 -0800 Subject: [PATCH 171/401] Update CCD motion threshold --- libraries/physics/src/ObjectMotionState.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 6f1b928456..f6e15d8539 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -121,7 +121,7 @@ void ObjectMotionState::updateCCDConfiguration() { btVector3 center; btScalar radius; _shape->getBoundingSphere(center, radius); - _body->setCcdMotionThreshold(radius * 2.0f); + _body->setCcdMotionThreshold(radius / 4.0f); _body->setCcdSweptSphereRadius(radius); } else { // Disable CCD From 0f214555c13a73823ac3fc680186bc5a12dcfe74 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 18 Nov 2015 09:13:03 -0800 Subject: [PATCH 172/401] New algorithmic stereo reverb --- libraries/audio/src/AudioReverb.cpp | 1965 +++++++++++++++++++++++++++ libraries/audio/src/AudioReverb.h | 76 ++ 2 files changed, 2041 insertions(+) create mode 100644 libraries/audio/src/AudioReverb.cpp create mode 100644 libraries/audio/src/AudioReverb.h diff --git a/libraries/audio/src/AudioReverb.cpp b/libraries/audio/src/AudioReverb.cpp new file mode 100644 index 0000000000..3f28a9c00d --- /dev/null +++ b/libraries/audio/src/AudioReverb.cpp @@ -0,0 +1,1965 @@ +// +// AudioReverb.cpp +// libraries/audio/src +// +// Created by Ken Cooke on 10/11/15. +// Copyright 2015 High Fidelity, Inc. +// + +#include +#include +#include + +#include "AudioReverb.h" + +#ifdef _MSC_VER +#pragma warning(disable : 4351) // new behavior: elements of array will be default initialized + +#include +inline static int MULHI(int a, int b) { + long long c = __emul(a, b); + return ((int*)&c)[1]; +} +#else + +#define MULHI(a,b) (int)(((long long)(a) * (b)) >> 32) + +#endif // _MSC_VER + +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +static const float M_PHI = 0.6180339887f; // maximum allpass diffusion + +static const double M_PI = 3.14159265358979323846; +static const double M_SQRT2 = 1.41421356237309504880; + +static const double FIXQ31 = 2147483648.0; +static const double FIXQ32 = 4294967296.0; + +// Round an integer to the next power-of-two, at compile time. +// VS2013 does not support constexpr so macros are used instead. +#define SETBITS0(x) (x) +#define SETBITS1(x) (SETBITS0(x) | (SETBITS0(x) >> 1)) +#define SETBITS2(x) (SETBITS1(x) | (SETBITS1(x) >> 2)) +#define SETBITS3(x) (SETBITS2(x) | (SETBITS2(x) >> 4)) +#define SETBITS4(x) (SETBITS3(x) | (SETBITS3(x) >> 8)) +#define SETBITS5(x) (SETBITS4(x) | (SETBITS4(x) >> 16)) +#define NEXTPOW2(x) (SETBITS5((x) - 1) + 1) + +// +// Allpass delay modulation +// +static const int MOD_INTBITS = 4; +static const int MOD_FRACBITS = 31 - MOD_INTBITS; +static const uint32_t MOD_FRACMASK = (1 << MOD_FRACBITS) - 1; +static const float QMOD_TO_FLOAT = 1.0f / (1 << MOD_FRACBITS); + +// +// Reverb delay values, defined for sampleRate=48000 roomSize=100% density=100% +// +// max path should already be prime, to prevent getPrime(NEXTPOW2(N)) > NEXTPOW2(N) +// +static const int M_PD0 = 16000; // max predelay = 333ms + +static const int M_AP0 = 83; +static const int M_AP1 = 211; +static const int M_AP2 = 311; +static const int M_AP3 = 97; +static const int M_AP4 = 223; +static const int M_AP5 = 293; + +static const int M_MT0 = 1017; +static const int M_MT1 = 4077; +static const int M_MT2 = 2039; +static const int M_MT3 = 1017; +static const int M_MT4 = 2593; +static const int M_MT5 = 2039; + +static const int M_MT1_2 = 600; +static const int M_MT4_2 = 600; +static const int M_MT1_MAX = MAX(M_MT1, M_MT1_2); +static const int M_MT4_MAX = MAX(M_MT4, M_MT4_2); + +static const int M_AP6 = 817; +static const int M_AP7 = 513; +static const int M_AP8 = 765; +static const int M_AP9 = 465; +static const int M_AP10 = 3021; +static const int M_AP11 = 2121; +static const int M_AP12 = 1705; +static const int M_AP13 = 1081; +static const int M_AP14 = 3313; +static const int M_AP15 = 2205; +static const int M_AP16 = 1773; +static const int M_AP17 = 981; + +static const int M_AP7_MAX = M_AP7 + (1 << MOD_INTBITS) + 1; // include max excursion +static const int M_AP9_MAX = M_AP9 + (1 << MOD_INTBITS) + 1; + +static const int M_MT6 = 6863; +static const int M_MT7 = 7639; +static const int M_MT8 = 3019; +static const int M_MT9 = 2875; + +static const int M_LD0 = 8000; // max late delay = 166ms +static const int M_MT6_MAX = MAX(M_MT6, M_LD0); +static const int M_MT7_MAX = MAX(M_MT7, M_LD0); +static const int M_MT8_MAX = MAX(M_MT8, M_LD0); +static const int M_MT9_MAX = MAX(M_MT9, M_LD0); + +static const int M_AP18 = 131; +static const int M_AP19 = 113; +static const int M_AP20 = 107; +static const int M_AP21 = 127; + +// +// Filter design tools using analog-matched response. +// All filter types approximate the s-plane response, including cutoff > Nyquist. +// + +static float dBToGain(float dB) { + return powf(10.0f, dB * (1/20.0f)); +} + +static double dBToGain(double dB) { + return pow(10.0, dB * (1/20.0)); +} + +// Returns the gain of analog (s-plane) peak-filter evaluated at w +static double analogPeak(double w0, double G, double Q, double w) { + double w0sq, wsq, Gsq, Qsq; + double num, den; + + w0sq = w0 * w0; + wsq = w * w; + Gsq = G * G; + Qsq = Q * Q; + + num = Qsq * (wsq - w0sq) * (wsq - w0sq) + wsq * w0sq * Gsq; + den = Qsq * (wsq - w0sq) * (wsq - w0sq) + wsq * w0sq; + + return sqrt(num / den); +} + +// Returns the gain of analog (s-plane) shelf evaluated at w +// non-resonant Q = sqrt(0.5) so 1/Q^2 = 2.0 +static double analogShelf(double w0, double G, double resonance, int isHigh, double w) { + double w0sq, wsq, Qrsq; + double num, den; + + resonance = MIN(MAX(resonance, 0.0), 1.0); + Qrsq = 2.0 * pow(G, 1.0 - resonance); // resonant 1/Q^2 + + w0sq = w0 * w0; + wsq = w * w; + + if (isHigh) { + num = (G*wsq - w0sq) * (G*wsq - w0sq) + wsq * w0sq * Qrsq; + } else { + num = (wsq - G*w0sq) * (wsq - G*w0sq) + wsq * w0sq * Qrsq; + } + den = wsq * wsq + w0sq * w0sq; + + return sqrt(num / den); +} + +// Returns the gain of analog (s-plane) highpass/lowpass evaluated at w +// Q = sqrt(0.5) = 2nd order Butterworth +static double analogFilter(double w0, int isHigh, double w) { + double w0sq, wsq; + double num, den; + + w0sq = w0 * w0; + wsq = w * w; + + if (isHigh) { + num = wsq * wsq; + } else { + num = w0sq * w0sq; + } + den = wsq * wsq + w0sq * w0sq; + + return sqrt(num / den); +} + +// +// Biquad Peaking EQ using analog matching. +// NOTE: Peak topology becomes ill-conditioned as w0 approaches pi. +// +static void BQPeakBelowPi(double coef[5], double w0, double dbgain, double Q) { + double G, G1, Gsq, G1sq, Qsq; + double G11, G00, Gratio; + double wpi, wh, w0sq, whsq; + double Wsq, B, A; + double b0, b1, b2, a0, a1, a2; + double temp, scale; + int isUnity; + + // convert cut into boost, invert later + G = dBToGain(fabs(dbgain)); + + // special case near unity gain + isUnity = G < 1.001; + G = MAX(G, 1.001); + + // compute the Nyquist gain + wpi = w0 + 2.8 * (1.0 - w0/M_PI); // minimax-like error + wpi = MIN(wpi, M_PI); + G1 = analogPeak(w0, G, Q, wpi); + + G1sq = G1 * G1; + Gsq = G * G; + Qsq = Q * Q; + + // compute the analog half-gain frequency + temp = G + 2.0 * Qsq - sqrt(Gsq + 4.0 * Qsq * G); + wh = sqrt(temp) * w0 / (Q * M_SQRT2); + + // prewarp freqs of w0 and wh + w0 = tan(0.5 * w0); + wh = tan(0.5 * wh); + w0sq = w0 * w0; + whsq = wh * wh; + + // compute Wsq, from asymmetry due to G1 + G11 = Gsq - G1sq; + G00 = Gsq - 1.0; + Gratio = G11 / G00; + Wsq = w0sq * sqrt(Gratio); + + // compute B, matching gains at w0 and wh + temp = 2.0 * Wsq * (G1 - sqrt(Gratio)); + temp += Gsq * whsq * (1.0 - G1sq) / G00; + temp += G * Gratio * (w0sq - whsq) * (w0sq - whsq) / whsq; + B = sqrt(temp); + + // compute A, matching gains at w0 and wh + temp = 2.0 * Wsq; + temp += (2.0 * G11 * w0sq + (G1sq - G) * whsq) / (G - Gsq); + temp += Gratio * w0sq * w0sq / (G * whsq); + A = sqrt(temp); + + // design digital filter via bilinear tranform + b0 = G1 + B + Wsq; + b1 = 2.0 * (Wsq - G1); + b2 = G1 - B + Wsq; + a0 = 1.0 + A + Wsq; + a1 = 2.0 * (Wsq - 1.0); + a2 = 1.0 - A + Wsq; + + // for unity gain, ensure poles/zeros in the right place. + // needed for smooth interpolation when gain is changed. + if (isUnity) { + b0 = a0; + b1 = a1; + b2 = a2; + } + + // invert filter for cut + if (dbgain < 0.0) { + temp = b0; b0 = a0; a0 = temp; + temp = b1; b1 = a1; a1 = temp; + temp = b2; b2 = a2; a2 = temp; + } + + // normalize + scale = 1.0 / a0; + coef[0] = b0 * scale; + coef[1] = b1 * scale; + coef[2] = b2 * scale; + coef[3] = a1 * scale; + coef[4] = a2 * scale; +} + +// +// Biquad Peaking EQ using a shelf instead of peak. +// +// This uses a shelf topology, matched to the analog peaking filter located above Nyquist. +// +// NOTE: the result is close, but not identical to BQPeakBelowPi(), since a pole/zero +// pair must jump to the right side of the real axis. Eg. inflection at the peak goes away. +// However, interpolation from peak to shelf is well behaved if the switch is made near pi, +// as the pole/zero be near (and travel down) the real axis. +// +static void BQPeakAbovePi(double coef[5], double w0, double dbgain, double Q) { + double G, G1, Gsq, Qsq; + double wpi, wh, wn, wd; + double wna, wda; + double gn, gd, gnsq, gdsq; + double num, den; + double Wnsq, Wdsq, B, A; + double b0, b1, b2, a0, a1, a2; + double temp, scale; + int isUnity; + + // convert cut into boost, invert later + G = dBToGain(fabs(dbgain)); + + // special case near unity gain + isUnity = G < 1.001; + G = MAX(G, 1.001); + + // compute the Nyquist gain + wpi = M_PI; + if (w0 < M_PI) { + G1 = G; // use the peak gain + } else { + G1 = analogPeak(w0, G, Q, wpi); // use Nyquist gain of analog response + } + + Gsq = G * G; + Qsq = Q * Q; + + // compute the analog half-gain frequency + temp = G + 2.0 * Qsq - sqrt(Gsq + 4.0 * Qsq * G); + wh = sqrt(temp) * w0 / (Q * M_SQRT2); + + // approximate wn and wd + // use half-gain frequency as mapping + wn = 0.5 * wh / sqrt(sqrt((G1))); + wd = wn * sqrt(G1); + Wnsq = wn * wn; + Wdsq = wd * wd; + + // analog freqs of wn and wd + wna = 2.0 * atan(wn); + wda = 2.0 * atan(wd); + + // normalized analog gains at wna and wda + temp = 1.0 / G1; + gn = temp * analogPeak(w0, G, Q, wna); + gd = temp * analogPeak(w0, G, Q, wda); + gnsq = gn * gn; + gdsq = gd * gd; + + // compute B, matching gains at wn and wd + temp = 1.0 / (wn * wd); + den = fabs(gnsq - gdsq); + num = gnsq * (Wnsq - Wdsq) * (Wnsq - Wdsq) * (Wnsq + gdsq * Wdsq); + B = temp * sqrt(num / den); + + // compute A, matching gains at wn and wd + num = (Wnsq - Wdsq) * (Wnsq - Wdsq) * (Wnsq + gnsq * Wdsq); + A = temp * sqrt(num / den); + + // design digital filter via bilinear tranform + b0 = G1 * (1.0 + B + Wnsq); + b1 = G1 * 2.0 * (Wnsq - 1.0); + b2 = G1 * (1.0 - B + Wnsq); + a0 = 1.0 + A + Wdsq; + a1 = 2.0 * (Wdsq - 1.0); + a2 = 1.0 - A + Wdsq; + + // for unity gain, ensure poles/zeros are in the right place. + // allows smooth coefficient interpolation when gain is changed. + if (isUnity) { + b0 = a0; + b1 = a1; + b2 = a2; + } + + // invert filter for cut + if (dbgain < 0.0) { + temp = b0; b0 = a0; a0 = temp; + temp = b1; b1 = a1; a1 = temp; + temp = b2; b2 = a2; a2 = temp; + } + + // normalize + scale = 1.0 / a0; + coef[0] = b0 * scale; + coef[1] = b1 * scale; + coef[2] = b2 * scale; + coef[3] = a1 * scale; + coef[4] = a2 * scale; +} + +// +// Biquad Peaking EQ using analog matching. +// Supports full range of w0. +// +static void BQPeak(double coef[5], double w0, double dbgain, double Q) { + w0 = MAX(w0, 0.0); // allow w0 > pi + + Q = MIN(MAX(Q, 1.0e-6), 1.0e+6); + + // Switch from peak to shelf, just before w0 = pi. + // Too early causes a jump in the peak location, which interpolates to lowered gains. + // Too late becomes ill-conditioned, and makes no improvement to interpolated response. + // 3.14 is a good choice. + if (w0 > 3.14) { + BQPeakAbovePi(coef, w0, dbgain, Q); + } else { + BQPeakBelowPi(coef, w0, dbgain, Q); + } +} + +// +// Biquad Shelf using analog matching. +// +static void BQShelf(double coef[5], double w0, double dbgain, double resonance, int isHigh) { + double G, G1; + double wpi, wn, wd; + double wna, wda; + double gn, gd, gnsq, gdsq; + double num, den; + double Wnsq, Wdsq, B, A; + double b0, b1, b2, a0, a1, a2; + double temp, scale; + int isUnity; + + w0 = MAX(w0, 0.0); // allow w0 > pi + + resonance = MIN(MAX(resonance, 0.0), 1.0); + + // convert cut into boost, invert later + G = dBToGain(fabs(dbgain)); + + // special case near unity gain + isUnity = G < 1.001; + G = MAX(G, 1.001); + + // compute the Nyquist gain + wpi = w0 + 2.8 * (1.0 - w0/M_PI); // minimax-like error + wpi = MIN(wpi, M_PI); + G1 = analogShelf(w0, G, resonance, isHigh, wpi); + + // approximate wn and wd + if (isHigh) { + // use center as mapping + wn = 0.5 * w0 / sqrt(sqrt((G * G1))); + wd = wn * sqrt(G1); + } else { + // use wd as mapping + wd = 0.5 * w0; + wn = wd * sqrt(G/G1); + } + Wnsq = wn * wn; + Wdsq = wd * wd; + + // analog freqs of wn and wd + wna = 2.0 * atan(wn); + wda = 2.0 * atan(wd); + + // normalized analog gains at wna and wda + temp = 1.0 / G1; + gn = temp * analogShelf(w0, G, resonance, isHigh, wna); + gd = temp * analogShelf(w0, G, resonance, isHigh, wda); + gnsq = gn * gn; + gdsq = gd * gd; + + // compute B, matching gains at wn and wd + temp = 1.0 / (wn * wd); + den = fabs(gnsq - gdsq); + num = gnsq * (Wnsq - Wdsq) * (Wnsq - Wdsq) * (Wnsq + gdsq * Wdsq); + B = temp * sqrt(num / den); + + // compute A, matching gains at wn and wd + num = (Wnsq - Wdsq) * (Wnsq - Wdsq) * (Wnsq + gnsq * Wdsq); + A = temp * sqrt(num / den); + + // design digital filter via bilinear tranform + b0 = G1 * (1.0 + B + Wnsq); + b1 = G1 * 2.0 * (Wnsq - 1.0); + b2 = G1 * (1.0 - B + Wnsq); + a0 = 1.0 + A + Wdsq; + a1 = 2.0 * (Wdsq - 1.0); + a2 = 1.0 - A + Wdsq; + + // for unity gain, ensure poles/zeros in the right place. + // needed for smooth interpolation when gain is changed. + if (isUnity) { + b0 = a0; + b1 = a1; + b2 = a2; + } + + // invert filter for cut + if (dbgain < 0.0) { + temp = b0; b0 = a0; a0 = temp; + temp = b1; b1 = a1; a1 = temp; + temp = b2; b2 = a2; a2 = temp; + } + + // normalize + scale = 1.0 / a0; + coef[0] = b0 * scale; + coef[1] = b1 * scale; + coef[2] = b2 * scale; + coef[3] = a1 * scale; + coef[4] = a2 * scale; +} + +// +// Biquad Lowpass/Highpass using analog matching. +// Q = sqrt(0.5) = 2nd order Butterworth +// +static void BQFilter(double coef[5], double w0, int isHigh) { + double G1; + double wpi, wn, wd; + double wna, wda; + double gn, gd, gnsq, gdsq; + double num, den; + double Wnsq, Wdsq, B, A; + double b0, b1, b2, a0, a1, a2; + double temp, scale; + + w0 = MAX(w0, 0.0); // allow w0 > pi for lowpass + + if (isHigh) { + + w0 = MIN(w0, M_PI); // disallow w0 > pi for highpass + + // compute the Nyquist gain + wpi = M_PI; + G1 = analogFilter(w0, isHigh, wpi); + + // approximate wn and wd + wn = 0.0; // zeros at zero + wd = 0.5 * w0; + + Wnsq = wn * wn; + Wdsq = wd * wd; + + // compute B and A + B = 0.0; + A = M_SQRT2 * Wdsq / atan(wd); // Qd = sqrt(0.5) * atan(wd)/wd; + + } else { + + // compute the Nyquist gain + wpi = w0 + 2.8 * (1.0 - w0/M_PI); // minimax-like error + wpi = MIN(wpi, M_PI); + G1 = analogFilter(w0, isHigh, wpi); + + // approximate wn and wd + wd = 0.5 * w0; + wn = wd * sqrt(1.0/G1); // down G1 at pi, instead of zeros + + Wnsq = wn * wn; + Wdsq = wd * wd; + + // analog freqs of wn and wd + wna = 2.0 * atan(wn); + wda = 2.0 * atan(wd); + + // normalized analog gains at wna and wda + temp = 1.0 / G1; + gn = temp * analogFilter(w0, isHigh, wna); + gd = temp * analogFilter(w0, isHigh, wda); + gnsq = gn * gn; + gdsq = gd * gd; + + // compute B, matching gains at wn and wd + temp = 1.0 / (wn * wd); + den = fabs(gnsq - gdsq); + num = gnsq * (Wnsq - Wdsq) * (Wnsq - Wdsq) * (Wnsq + gdsq * Wdsq); + B = temp * sqrt(num / den); + + // compute A, matching gains at wn and wd + num = (Wnsq - Wdsq) * (Wnsq - Wdsq) * (Wnsq + gnsq * Wdsq); + A = temp * sqrt(num / den); + } + + // design digital filter via bilinear tranform + b0 = G1 * (1.0 + B + Wnsq); + b1 = G1 * 2.0 * (Wnsq - 1.0); + b2 = G1 * (1.0 - B + Wnsq); + a0 = 1.0 + A + Wdsq; + a1 = 2.0 * (Wdsq - 1.0); + a2 = 1.0 - A + Wdsq; + + // normalize + scale = 1.0 / a0; + coef[0] = b0 * scale; + coef[1] = b1 * scale; + coef[2] = b2 * scale; + coef[3] = a1 * scale; + coef[4] = a2 * scale; +} + +// +// PoleZero Shelf. For Lowpass/Highpass, setCoef dbgain to -100dB. +// NOTE: w0 always sets the pole frequency (3dB corner from unity gain) +// +static void PZShelf(double coef[3], double w0, double dbgain, int isHigh) { + double G, G0, G1; + double b0, b1, a0, a1; + double temp, scale; + + w0 = MAX(w0, 0.0); // allow w0 > pi + + // convert boost into cut, invert later + G = dBToGain(-fabs(dbgain)); + + if (isHigh) { + G0 = 1.0; // gain at DC + G1 = G; // gain at Nyquist + } else { + G0 = G; + G1 = 1.0; + } + + b0 = 1.0; + a0 = 1.0; + b1 = -exp(-w0 * G0 / G1); + a1 = -exp(-w0); + + b1 += 0.12 * (1.0 + b1) * (1.0 + b1) * (1.0 - G1); // analog-matched gain near Nyquist + + scale = G0 * (1.0 + a1) / (1.0 + b1); + b0 *= scale; + b1 *= scale; + + // invert filter for boost + if (dbgain > 0.0) { + temp = b0; b0 = a0; a0 = temp; + temp = b1; b1 = a1; a1 = temp; + } + + // normalize + scale = 1.0 / a0; + coef[0] = b0 * scale; + coef[1] = b1 * scale; + coef[2] = a1 * scale; +} + +class BandwidthEQ { + + float _buffer[4] {}; + + float _output0 = 0.0f; + float _output1 = 0.0f; + + float _dcL = 0.0f; + float _dcR = 0.0f; + + float _b0 = 1.0f; + float _b1 = 0.0f; + float _b2 = 0.0f; + float _a1 = 0.0f; + float _a2 = 0.0f; + + float _alpha = 0.0f; + +public: + void setFreq(float freq, float sampleRate) { + freq = MIN(MAX(freq, 1.0f), 24000.0f); + + // lowpass filter, -3dB @ freq + double coef[5]; + BQFilter(coef, M_PI * freq / (0.5 * sampleRate), 0); + _b0 = (float)coef[0]; + _b1 = (float)coef[1]; + _b2 = (float)coef[2]; + _a1 = (float)coef[3]; + _a2 = (float)coef[4]; + + // DC-blocking filter, -3dB @ 10Hz + _alpha = (float)(1.0 - exp(-M_PI * 10.0 / (0.5 * sampleRate))); + } + + void process(float input0, float input1, float& output0, float& output1) { + output0 = _output0; + output1 = _output1; + + // prevent denormalized zero-input limit cycles in the reverb + input0 += 1.0e-20f; + input1 += 1.0e-20f; + + // remove DC + input0 -= _dcL; + input1 -= _dcR; + + _dcL += _alpha * input0; + _dcR += _alpha * input1; + + // transposed Direct Form II + _output0 = _b0 * input0 + _buffer[0]; + _buffer[0] = _b1 * input0 - _a1 * _output0 + _buffer[1]; + _buffer[1] = _b2 * input0 - _a2 * _output0; + + _output1 = _b0 * input1 + _buffer[2]; + _buffer[2] = _b1 * input1 - _a1 * _output1 + _buffer[3]; + _buffer[3] = _b2 * input1 - _a2 * _output1; + } + + void reset() { + memset(_buffer, 0, sizeof(_buffer)); + _output0 = 0.0f; + _output1 = 0.0f; + _dcL = 0.0f; + _dcR = 0.0f; + } +}; + +template +class DelayLine { + + float _buffer[N] {}; + + float _output = 0.0f; + + int _index = 0; + int _delay = N; + +public: + void setDelay(int d) { + d = MIN(MAX(d, 1), N); + + _delay = d; + } + + void process(float input, float& output) { + output = _output; + + int k = (_index - _delay) & (N - 1); + + _output = _buffer[k]; + + _buffer[_index] = input; + _index = (_index + 1) & (N - 1); + } + + void reset() { + memset(_buffer, 0, sizeof(_buffer)); + _output = 0.0f; + } +}; + +template +class Allpass { + + float _buffer[N] {}; + + float _output = 0.0f; + float _coef = 0.5f; + + int _index0 = 0; + int _index1 = 0; + int _delay = N; + +public: + void setDelay(int d) { + d = MIN(MAX(d, 1), N); + + _index1 = (_index0 - d) & (N - 1); + _delay = d; + } + + int getDelay() { + return _delay; + } + + void setCoef(float coef) { + coef = MIN(MAX(coef, -1.0f), 1.0f); + + _coef = coef; + } + + void process(float input, float& output) { + output = _output; + + _output = _buffer[_index1] - _coef * input; // feedforward path + _buffer[_index0] = input + _coef * _output; // feedback path + + _index0 = (_index0 + 1) & (N - 1); + _index1 = (_index1 + 1) & (N - 1); + } + + void getOutput(float& output) { + output = _output; + } + + void reset() { + memset(_buffer, 0, sizeof(_buffer)); + _output = 0.0f; + } +}; + +class RandomLFO { + + int32_t _y0 = 0; + int32_t _y1 = 0; + int32_t _k = 0; + + int32_t _gain = 0; + + uint32_t _rand0 = 0; + int32_t _q0 = 0; // prev + int32_t _r0 = 0; // next + int32_t _m0 = _r0/2 - _q0/2; // slope + int32_t _b0 = _r0/2 + _q0/2; // offset + + uint32_t _rand1 = 0; + int32_t _q1 = 0; + int32_t _r1 = 0; + int32_t _m1 = _q1/2 - _r1/2; + int32_t _b1 = _q1/2 + _r1/2; + +public: + void setFreq(float freq, float sampleRate) { + freq = MIN(freq, 1/16.0f * sampleRate); + freq = MAX(freq, 1/16777216.0f * sampleRate); + + // amplitude slightly less than 1.0 + _y0 = (int32_t)(0.000 * FIXQ31); + _y1 = (int32_t)(0.999 * cos(M_PI * freq / sampleRate) * FIXQ31); + + _k = (int32_t)(2.0 * sin(M_PI * freq / sampleRate) * FIXQ32); + } + + void setGain(int32_t gain) { + gain = MIN(MAX(gain, 0), 0x7fffffff); + + _gain = gain; + } + + void process(int32_t& lfoSin, int32_t& lfoCos) { + lfoSin = _y0; + lfoCos = _y1; + + // "Magic Circle" quadrature oscillator + _y1 -= MULHI(_k, _y0); + _y0 += MULHI(_k, _y1); + + // since the oscillators are in quadrature, zero-crossing in one detects a peak in the other + if ((lfoCos ^ _y1) < 0) { + //_rand0 = 69069 * _rand0 + 1; + _rand0 = (11 * _rand0 + 0x04000000) & 0xfc000000; // periodic version + + _q0 = _r0; + _r0 = 2 * MULHI((int32_t)_rand0, _gain); // Q31 + + // scale the peak-to-peak segment to traverse from q0 to r0 + _m0 = _r0/2 - _q0/2; // slope in Q31 + _b0 = _r0/2 + _q0/2; // offset in Q31 + + int32_t sign = _y1 >> 31; + _m0 = (_m0 ^ sign) - sign; + } + if ((lfoSin ^ _y0) < 0) { + //_rand1 = 69069 * _rand1 + 1; + _rand1 = (11 * _rand1 + 0x04000000) & 0xfc000000; // periodic version + + _q1 = _r1; + _r1 = 2 * MULHI((int32_t)_rand1, _gain); // Q31 + + // scale the peak-to-peak segment to traverse from q1 to r1 + _m1 = _q1/2 - _r1/2; // slope in Q31 + _b1 = _q1/2 + _r1/2; // offset in Q31 + + int32_t sign = _y0 >> 31; + _m1 = (_m1 ^ sign) - sign; + } + + lfoSin = 2 * MULHI(lfoSin, _m0) + _b0; // Q31 + lfoCos = 2 * MULHI(lfoCos, _m1) + _b1; // Q31 + } +}; + +template +class AllPassMod { + + float _buffer[N] {}; + + float _output = 0.0f; + float _coef = 0.5f; + + int _index = 0; + int _delay = N; + +public: + void setDelay(int d) { + d = MIN(MAX(d, 1), N); + + _delay = d; + } + + int getDelay() { + return _delay; + } + + void setCoef(float coef) { + coef = MIN(MAX(coef, -1.0f), 1.0f); + + _coef = coef; + } + + void process(float input, int32_t mod, float& output) { + output = _output; + + // add modulation to delay + uint32_t offset = _delay + (mod >> MOD_FRACBITS); + float frac = (mod & MOD_FRACMASK) * QMOD_TO_FLOAT; + + // 3rd-order Lagrange interpolation + int k0 = (_index - (offset-1)) & (N - 1); + int k1 = (_index - (offset+0)) & (N - 1); + int k2 = (_index - (offset+1)) & (N - 1); + int k3 = (_index - (offset+2)) & (N - 1); + + float x0 = _buffer[k0]; + float x1 = _buffer[k1]; + float x2 = _buffer[k2]; + float x3 = _buffer[k3]; + + // compute the polynomial coefficients + float c0 = (1/6.0f) * (x3 - x0) + (1/2.0f) * (x1 - x2); + float c1 = (1/2.0f) * (x0 + x2) - x1; + float c2 = x2 - (1/3.0f) * x0 - (1/2.0f) * x1 - (1/6.0f) * x3; + float c3 = x1; + + // compute the polynomial + float delayMod = ((c0 * frac + c1) * frac + c2) * frac + c3; + + _output = delayMod - _coef * input; // feedforward path + _buffer[_index] = input + _coef * _output; // feedback path + + _index = (_index + 1) & (N - 1); + } + + void reset() { + memset(_buffer, 0, sizeof(_buffer)); + _output = 0.0f; + } +}; + +class LowpassEQ { + + float _buffer[2] {}; + + float _output = 0.0f; + + float _b0 = 1.0f; + float _b1 = 0.0f; + float _b2 = 0.0f; + +public: + void setFreq(float sampleRate) { + sampleRate = MIN(MAX(sampleRate, 24000.0f), 48000.0f); + + // two-zero lowpass filter, with zeros at approximately 12khz + // zero radius is adjusted to match the response from 0..9khz + _b0 = 0.5f; + _b1 = 0.5f * sqrtf(2.0f * 12000.0f/(0.5f * sampleRate) - 1.0f); + _b2 = 0.5f - _b1; + } + + void process(float input, float& output) { + output = _output; + + _output = _b0 * input + _b1 * _buffer[0] + _b2 * _buffer[1]; + _buffer[1] = _buffer[0]; + _buffer[0] = input; + } + + void reset() { + memset(_buffer, 0, sizeof(_buffer)); + _output = 0.0f; + } +}; + +class DampingEQ { + + float _buffer[2] {}; + + float _output = 0.0f; + + float _b0 = 1.0f; + float _b1 = 0.0f; + float _b2 = 0.0f; + float _a1 = 0.0f; + float _a2 = 0.0f; + +public: + void setCoef(float dBgain0, float dBgain1, float freq0, float freq1, float sampleRate) { + dBgain0 = MIN(MAX(dBgain0, -100.0f), 100.0f); + dBgain1 = MIN(MAX(dBgain1, -100.0f), 100.0f); + freq0 = MIN(MAX(freq0, 1.0f), 24000.0f); + freq1 = MIN(MAX(freq1, 1.0f), 24000.0f); + + double coefLo[3], coefHi[3]; + PZShelf(coefLo, M_PI * freq0 / (0.5 * sampleRate), dBgain0, 0); // low shelf + PZShelf(coefHi, M_PI * freq1 / (0.5 * sampleRate), dBgain1, 1); // high shelf + + // convolve into a single biquad + _b0 = (float)(coefLo[0] * coefHi[0]); + _b1 = (float)(coefLo[0] * coefHi[1] + coefLo[1] * coefHi[0]); + _b2 = (float)(coefLo[1] * coefHi[1]); + _a1 = (float)(coefLo[2] + coefHi[2]); + _a2 = (float)(coefLo[2] * coefHi[2]); + } + + void process(float input, float& output) { + output = _output; + + // transposed Direct Form II + _output = _b0 * input + _buffer[0]; + _buffer[0] = _b1 * input - _a1 * _output + _buffer[1]; + _buffer[1] = _b2 * input - _a2 * _output; + } + + void reset() { + memset(_buffer, 0, sizeof(_buffer)); + _output = 0.0f; + } +}; + +template +class MultiTap2 { + + float _buffer[N] {}; + + float _output0 = 0.0f; + float _output1 = 0.0f; + + float _gain0 = 1.0f; + float _gain1 = 1.0f; + + int _index = 0; + int _delay0 = N; + int _delay1 = N; + +public: + void setDelay(int d0, int d1) { + d0 = MIN(MAX(d0, 1), N); + d1 = MIN(MAX(d1, 1), N); + + _delay0 = d0; + _delay1 = d1; + } + + int getDelay(int k) { + switch (k) { + case 0: return _delay0; + case 1: return _delay1; + default: return 0; + } + } + + void setGain(float g0, float g1) { + _gain0 = g0; + _gain1 = g1; + } + + void process(float input, float& output0, float& output1) { + output0 = _output0; + output1 = _output1; + + int k0 = (_index - _delay0) & (N - 1); + int k1 = (_index - _delay1) & (N - 1); + + _output0 = _gain0 * _buffer[k0]; + _output1 = _gain1 * _buffer[k1]; + + _buffer[_index] = input; + _index = (_index + 1) & (N - 1); + } + + void reset() { + memset(_buffer, 0, sizeof(_buffer)); + _output0 = 0.0f; + _output1 = 0.0f; + } +}; + +template +class MultiTap3 { + + float _buffer[N] {}; + + float _output0 = 0.0f; + float _output1 = 0.0f; + float _output2 = 0.0f; + + float _gain0 = 1.0f; + float _gain1 = 1.0f; + float _gain2 = 1.0f; + + int _index = 0; + int _delay0 = N; + int _delay1 = N; + int _delay2 = N; + +public: + void setDelay(int d0, int d2) { + d0 = MIN(MAX(d0, 1), N); + d2 = MIN(MAX(d2, 1), N); + + _delay0 = d0; + _delay1 = d0 - 1; + _delay2 = d2; + } + + int getDelay(int k) { + switch (k) { + case 0: return _delay0; + case 1: return _delay1; + case 2: return _delay2; + default: return 0; + } + } + + void setGain(float g0, float g1, float g2) { + _gain0 = g0; + _gain1 = g1; + _gain2 = g2; + } + + void process(float input, float& output0, float& output1, float& output2) { + output0 = _output0; + output1 = _output1; + output2 = _output2; + + int k0 = (_index - _delay0) & (N - 1); + int k1 = (_index - _delay1) & (N - 1); + int k2 = (_index - _delay2) & (N - 1); + + _output0 = _gain0 * _buffer[k0]; + _output1 = _gain1 * _buffer[k1]; + _output2 = _gain2 * _buffer[k2]; + + _buffer[_index] = input; + _index = (_index + 1) & (N - 1); + } + + void reset() { + memset(_buffer, 0, sizeof(_buffer)); + _output0 = 0.0f; + _output1 = 0.0f; + _output2 = 0.0f; + } +}; + +// +// Stereo Reverb +// +class ReverbImpl { + + // Preprocess + BandwidthEQ _bw; + DelayLine _dl0; + DelayLine _dl1; + + // Early Left + float _earlyMix1L = 0.0f; + float _earlyMix2L = 0.0f; + + MultiTap3 _mt0; + Allpass _ap0; + MultiTap3 _mt1; + Allpass _ap1; + Allpass _ap2; + MultiTap2 _mt2; + + // Early Right + float _earlyMix1R = 0.0f; + float _earlyMix2R = 0.0f; + + MultiTap3 _mt3; + Allpass _ap3; + MultiTap3 _mt4; + Allpass _ap4; + Allpass _ap5; + MultiTap2 _mt5; + + RandomLFO _lfo; + + // Late + Allpass _ap6; + AllPassMod _ap7; + DampingEQ _eq0; + MultiTap2 _mt6; + + Allpass _ap8; + AllPassMod _ap9; + DampingEQ _eq1; + MultiTap2 _mt7; + + Allpass _ap10; + Allpass _ap11; + Allpass _ap12; + Allpass _ap13; + MultiTap2 _mt8; + LowpassEQ _lp0; + + Allpass _ap14; + Allpass _ap15; + Allpass _ap16; + Allpass _ap17; + MultiTap2 _mt9; + LowpassEQ _lp1; + + // Output Left + Allpass _ap18; + Allpass _ap19; + + // Output Right + Allpass _ap20; + Allpass _ap21; + + float _earlyGain = 0.0f; + float _wetDryMix = 0.0f; + +public: + void setParameters(ReverbParameters *p); + void process(float** inputs, float** outputs, int numFrames); + void reset(); +}; + +static const short primeTable[] = { + 1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, + 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, + 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, + 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, + 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, + 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, + 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, + 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, + 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, + 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, + 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, + 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, + 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, + 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, + 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, + 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, + 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, + 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, + 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, + 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, + 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, + 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, + 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, + 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, + 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, + 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, + 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, + 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, + 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, + 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, + 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, + 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, + 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, + 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, + 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, + 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, + 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, + 4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, + 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, + 4409, 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, + 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, + 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, + 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, + 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, + 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, + 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, + 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, + 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, + 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, + 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, + 5827, 5839, 5843, 5849, 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, + 5939, 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, + 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, + 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, + 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, + 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, + 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, + 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, + 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, + 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 7129, + 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, + 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, + 7459, 7477, 7481, 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, + 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, + 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, + 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, 7933, 7937, 7949, + 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, + 8111, 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, +}; + +static int getPrime(int n) { + int low = 0; + int high = sizeof(primeTable) / sizeof(primeTable[0]) - 1; + + // clip to table limits + if (n <= primeTable[low]) { + return primeTable[low]; + } + if (n >= primeTable[high]) { + return primeTable[high]; + } + + // binary search + while (low <= high) { + int mid = (low + high) >> 1; + + if (n < primeTable[mid]) { + high = mid - 1; + } else if (n > primeTable[mid]) { + low = mid + 1; + } else { + return n; // found it + } + } + + //return primeTable[high]; // lower prime + //return (n - primeTable[high]) < (primeTable[low] - n) ? primeTable[high] : primeTable[low]; // nearest prime + return primeTable[low]; // higher prime +} + +static int scaleDelay(float delay, float sampleRate) { + return getPrime((int)(delay * (sampleRate/48000.0f) + 0.5f)); +} + +// +// Piecewise-linear lookup tables +// input clamped to [0.0f, 100.0f] +// +static const float earlyMix0Table[][2] = { + 0.0000f, 0.6000f, + 63.3333f, 0.0800f, + 83.3333f, 0.0200f, + 93.3333f, 0.0048f, + 100.0000f, 0.0048f, +}; + +static const float earlyMix1Table[][2] = { + 0.0000f, 0.3360f, + 20.0000f, 0.6000f, + 100.0000f, 0.0240f, +}; + +static const float earlyMix2Table[][2] = { + 0.0000f, 0.0480f, + 13.3333f, 0.0960f, + 53.3333f, 0.9600f, + 100.0000f, 0.1200f, +}; + +static const float lateMix0Table[][2] = { + 0.0000f, 0.1250f, + 13.3333f, 0.1875f, + 66.6666f, 0.7500f, + 100.0000f, 0.8750f, +}; + +static const float lateMix1Table[][2] = { + 0.0000f, 0.9990f, + 33.3333f, 0.5000f, + 66.6666f, 0.9990f, + 93.3333f, 0.6000f, + 100.0000f, 0.6000f, +}; + +static const float lateMix2Table[][2] = { + 0.0000f, 0.9990f, + 33.3333f, 0.9990f, + 63.3333f, 0.4500f, + 100.0000f, 0.9990f, +}; + +static const float diffusionCoefTable[][2] = { + 0.0000f, 0.0000f, + 20.0000f, 0.0470f, + 33.3333f, 0.0938f, + 46.6666f, 0.1563f, + 60.0000f, 0.2344f, + 73.3333f, 0.3125f, + 93.3333f, 0.5000f, + 100.0000f, M_PHI, +}; + +static const float roomSizeTable[][2] = { + 0.0000f, 0.1500f, + 25.0000f, 0.3000f, + 50.0000f, 0.5000f, + 100.0000f, 1.0000f, +}; + +static float interpolateTable(const float table[][2], float x) { + x = MIN(MAX(x, 0.0f), 100.0f); + + // locate the segment in the table + int i = 0; + while (x > table[i+1][0]) { + i++; + } + + // linear interpolate + float frac = (x - table[i+0][0]) / (table[i+1][0] - table[i+0][0]); + return table[i+0][1] + frac * (table[i+1][1] - table[i+0][1]); +} + +void ReverbImpl::setParameters(ReverbParameters *p) { + + float sampleRate = MIN(MAX(p->sampleRate, 24000.0f), 48000.0f); + + // Bandwidth + _bw.setFreq(p->bandwidth, sampleRate); + + // Modulation + _lfo.setFreq(p->modRate, sampleRate); + _lfo.setGain((int32_t)MIN(MAX(p->modDepth * (1/100.0) * FIXQ31, 0.0), 0X7fffffff)); + + // + // Set delays + // + int preDelay = (int)(p->preDelay * (1/1000.0f) * sampleRate + 0.5f); + preDelay = MIN(MAX(preDelay, 1), M_PD0); + _dl0.setDelay(preDelay); + _dl1.setDelay(preDelay); + + // RoomSize scalefactor + float roomSize = interpolateTable(roomSizeTable, p->roomSize); + + // Density scalefactors + float density0 = p->density * (1/25.0f) - 0.0f; + float density1 = p->density * (1/25.0f) - 1.0f; + float density2 = p->density * (1/25.0f) - 2.0f; + float density3 = p->density * (1/25.0f) - 3.0f; + density0 = MIN(MAX(density0, 0.0f), 1.0f); + density1 = MIN(MAX(density1, 0.0f), 1.0f); + density2 = MIN(MAX(density2, 0.0f), 1.0f); + density3 = MIN(MAX(density3, 0.0f), 1.0f); + + // Early delays + _ap0.setDelay(scaleDelay(M_AP0 * 1.0f, sampleRate)); + _ap1.setDelay(scaleDelay(M_AP1 * 1.0f, sampleRate)); + _ap2.setDelay(scaleDelay(M_AP2 * 1.0f, sampleRate)); + _ap3.setDelay(scaleDelay(M_AP3 * 1.0f, sampleRate)); + _ap4.setDelay(scaleDelay(M_AP4 * 1.0f, sampleRate)); + _ap5.setDelay(scaleDelay(M_AP5 * 1.0f, sampleRate)); + + _mt0.setDelay(scaleDelay(M_MT0 * roomSize, sampleRate), 1); + _mt1.setDelay(scaleDelay(M_MT1 * roomSize, sampleRate), scaleDelay(M_MT1_2 * 1.0f, sampleRate)); + _mt2.setDelay(scaleDelay(M_MT2 * roomSize, sampleRate), 1); + _mt3.setDelay(scaleDelay(M_MT3 * roomSize, sampleRate), 1); + _mt4.setDelay(scaleDelay(M_MT4 * roomSize, sampleRate), scaleDelay(M_MT4_2 * 1.0f, sampleRate)); + _mt5.setDelay(scaleDelay(M_MT5 * roomSize, sampleRate), 1); + + // Late delays + _ap6.setDelay(scaleDelay(M_AP6 * roomSize * density3, sampleRate)); + _ap7.setDelay(scaleDelay(M_AP7 * roomSize, sampleRate)); + _ap8.setDelay(scaleDelay(M_AP8 * roomSize * density3, sampleRate)); + _ap9.setDelay(scaleDelay(M_AP9 * roomSize, sampleRate)); + _ap10.setDelay(scaleDelay(M_AP10 * roomSize * density1, sampleRate)); + _ap11.setDelay(scaleDelay(M_AP11 * roomSize * density2, sampleRate)); + _ap12.setDelay(scaleDelay(M_AP12 * roomSize, sampleRate)); + _ap13.setDelay(scaleDelay(M_AP13 * roomSize * density3, sampleRate)); + _ap14.setDelay(scaleDelay(M_AP14 * roomSize * density1, sampleRate)); + _ap15.setDelay(scaleDelay(M_AP15 * roomSize * density2, sampleRate)); + _ap16.setDelay(scaleDelay(M_AP16 * roomSize * density3, sampleRate)); + _ap17.setDelay(scaleDelay(M_AP17 * roomSize * density3, sampleRate)); + + int lateDelay = scaleDelay(p->lateDelay * (1/1000.0f) * 48000, sampleRate); + lateDelay = MIN(MAX(lateDelay, 1), M_LD0); + + _mt6.setDelay(scaleDelay(M_MT6 * roomSize * density3, sampleRate), lateDelay); + _mt7.setDelay(scaleDelay(M_MT7 * roomSize * density2, sampleRate), lateDelay); + _mt8.setDelay(scaleDelay(M_MT8 * roomSize * density0, sampleRate), lateDelay); + _mt9.setDelay(scaleDelay(M_MT9 * roomSize, sampleRate), lateDelay); + + // Output delays + _ap18.setDelay(scaleDelay(M_AP18 * 1.0f, sampleRate)); + _ap19.setDelay(scaleDelay(M_AP19 * 1.0f, sampleRate)); + _ap20.setDelay(scaleDelay(M_AP20 * 1.0f, sampleRate)); + _ap21.setDelay(scaleDelay(M_AP21 * 1.0f, sampleRate)); + + // RT60 is determined by mean delay of feedback paths + int loopDelay; + loopDelay = _ap6.getDelay(); + loopDelay += _ap7.getDelay(); + loopDelay += _ap8.getDelay(); + loopDelay += _ap9.getDelay(); + loopDelay += _ap10.getDelay(); + loopDelay += _ap11.getDelay(); + loopDelay += _ap12.getDelay(); + loopDelay += _ap13.getDelay(); + loopDelay += _ap14.getDelay(); + loopDelay += _ap15.getDelay(); + loopDelay += _ap16.getDelay(); + loopDelay += _ap17.getDelay(); + loopDelay += _mt6.getDelay(0); + loopDelay += _mt7.getDelay(0); + loopDelay += _mt8.getDelay(0); + loopDelay += _mt9.getDelay(0); + loopDelay /= 2; + + // + // Set gains + // + float rt60 = MIN(MAX(p->reverbTime, 0.01f), 100.0f); + float rt60Gain = -60.0f * loopDelay / (rt60 * sampleRate); // feedback gain (dB) for desired RT + + float bassMult = MIN(MAX(p->bassMult, 0.1f), 10.0f); + float bassGain = (1.0f / bassMult - 1.0f) * rt60Gain; // filter gain (dB) that results in RT *= mult + + float loopGain1 = sqrtf(0.5f * dBToGain(rt60Gain)); // distributed (series-parallel) loop gain + float loopGain2 = 0.9f - (0.63f * loopGain1); + + // Damping + _eq0.setCoef(bassGain, p->highGain, p->bassFreq, p->highFreq, sampleRate); + _eq1.setCoef(bassGain, p->highGain, p->bassFreq, p->highFreq, sampleRate); + _lp0.setFreq(sampleRate); + _lp1.setFreq(sampleRate); + + float earlyDiffusionCoef = interpolateTable(diffusionCoefTable, p->earlyDiffusion); + + // Early Left + _earlyMix1L = interpolateTable(earlyMix1Table, p->earlyMixRight); + _earlyMix2L = interpolateTable(earlyMix2Table, p->earlyMixLeft); + + _mt0.setGain(0.2f, 0.4f, interpolateTable(earlyMix0Table, p->earlyMixLeft)); + + _ap0.setCoef(earlyDiffusionCoef); + _ap1.setCoef(earlyDiffusionCoef); + _ap2.setCoef(earlyDiffusionCoef); + + _mt1.setGain(0.2f, 0.6f, interpolateTable(lateMix0Table, p->lateMixLeft) * 0.125f); + + _mt2.setGain(interpolateTable(lateMix1Table, p->lateMixLeft) * loopGain2, + interpolateTable(lateMix2Table, p->lateMixLeft) * loopGain2); + + // Early Right + _earlyMix1R = interpolateTable(earlyMix1Table, p->earlyMixLeft); + _earlyMix2R = interpolateTable(earlyMix2Table, p->earlyMixRight); + + _mt3.setGain(0.2f, 0.4f, interpolateTable(earlyMix0Table, p->earlyMixRight)); + + _ap3.setCoef(earlyDiffusionCoef); + _ap4.setCoef(earlyDiffusionCoef); + _ap5.setCoef(earlyDiffusionCoef); + + _mt4.setGain(0.2f, 0.6f, interpolateTable(lateMix0Table, p->lateMixRight) * 0.125f); + + _mt5.setGain(interpolateTable(lateMix1Table, p->lateMixRight) * loopGain2, + interpolateTable(lateMix2Table, p->lateMixRight) * loopGain2); + + _earlyGain = dBToGain(p->earlyGain); + + // Late + float lateDiffusionCoef = interpolateTable(diffusionCoefTable, p->lateDiffusion); + _ap6.setCoef(lateDiffusionCoef); + _ap7.setCoef(lateDiffusionCoef); + _ap8.setCoef(lateDiffusionCoef); + _ap9.setCoef(lateDiffusionCoef); + + _ap10.setCoef(M_PHI); + _ap11.setCoef(M_PHI); + _ap12.setCoef(lateDiffusionCoef); + _ap13.setCoef(lateDiffusionCoef); + + _ap14.setCoef(M_PHI); + _ap15.setCoef(M_PHI); + _ap16.setCoef(lateDiffusionCoef); + _ap17.setCoef(lateDiffusionCoef); + + float lateGain = dBToGain(p->lateGain) * 2.0f; + _mt6.setGain(loopGain1, lateGain * interpolateTable(lateMix0Table, p->lateMixLeft)); + _mt7.setGain(loopGain1, lateGain * interpolateTable(lateMix0Table, p->lateMixRight)); + _mt8.setGain(loopGain1, lateGain * interpolateTable(lateMix2Table, p->lateMixLeft) * loopGain2 * 0.125f); + _mt9.setGain(loopGain1, lateGain * interpolateTable(lateMix2Table, p->lateMixRight) * loopGain2 * 0.125f); + + // Output + float outputDiffusionCoef = lateDiffusionCoef * 0.6f; + _ap18.setCoef(outputDiffusionCoef); + _ap19.setCoef(outputDiffusionCoef); + _ap20.setCoef(outputDiffusionCoef); + _ap21.setCoef(outputDiffusionCoef); + + _wetDryMix = p->wetDryMix * (1/100.0f); + _wetDryMix = MIN(MAX(_wetDryMix, 0.0f), 1.0f); +} + +void ReverbImpl::process(float** inputs, float** outputs, int numFrames) { + + for (int i = 0; i < numFrames; i++) { + float x0, x1, y0, y1, y2, y3; + + // Preprocess + x0 = inputs[0][i]; + x1 = inputs[1][i]; + _bw.process(x0, x1, x0, x1); + + float preL, preR; + _dl0.process(x0, preL); + _dl1.process(x1, preR); + + // Early Left + float early0L, early1L, early2L, earlyOutL; + _mt0.process(preL, x0, x1, y0); + _ap0.process(x0 + x1, y1); + _mt1.process(y1, x0, x1, early0L); + _ap1.process(x0 + x1, y2); + _ap2.process(y2, x0); + _mt2.process(x0, early1L, early2L); + + earlyOutL = (y0 + y1 * _earlyMix1L + y2 * _earlyMix2L) * _earlyGain; + + // Early Right + float early0R, early1R, early2R, earlyOutR; + _mt3.process(preR, x0, x1, y0); + _ap3.process(x0 + x1, y1); + _mt4.process(y1, x0, x1, early0R); + _ap4.process(x0 + x1, y2); + _ap5.process(y2, x0); + _mt5.process(x0, early1R, early2R); + + earlyOutR = (y0 + y1 * _earlyMix1R + y2 * _earlyMix2R) * _earlyGain; + + // LFO update + int32_t lfoSin, lfoCos; + _lfo.process(lfoSin, lfoCos); + + // Late + float lateOut0; + _ap6.getOutput(x0); + _ap7.process(x0, lfoSin, x0); + _eq0.process(-early0L + x0, x0); + _mt6.process(x0, y0, lateOut0); + + float lateOut1; + _ap8.getOutput(x0); + _ap9.process(x0, lfoCos, x0); + _eq1.process(-early0R + x0, x0); + _mt7.process(x0, y1, lateOut1); + + float lateOut2; + _ap10.getOutput(x0); + _ap11.process(-early2L + x0, x0); + _ap12.process(x0, x0); + _ap13.process(-early2L - x0, x0); + _mt8.process(-early0L + x0, x0, lateOut2); + _lp0.process(x0, y2); + + float lateOut3; + _ap14.getOutput(x0); + _ap15.process(-early2R + x0, x0); + _ap16.process(x0, x0); + _ap17.process(-early2R - x0, x0); + _mt9.process(-early0R + x0, x0, lateOut3); + _lp1.process(x0, y3); + + // Feedback matrix + _ap6.process(early1L + y2 - y3, x0); + _ap8.process(early1R - y2 - y3, x0); + _ap10.process(-early2R + y0 + y1, x0); + _ap14.process(-early2L - y0 + y1, x0); + + // Output Left + _ap18.process(-earlyOutL + lateOut0 + lateOut3, x0); + _ap19.process(x0, y0); + + // Output Right + _ap20.process(-earlyOutR + lateOut1 + lateOut2, x1); + _ap21.process(x1, y1); + + x0 = inputs[0][i]; + x1 = inputs[1][i]; + outputs[0][i] = x0 + (y0 - x0) * _wetDryMix; + outputs[1][i] = x1 + (y1 - x1) * _wetDryMix; + } +} + +// clear internal state, but retain settings +void ReverbImpl::reset() { + + _bw.reset(); + + _dl0.reset(); + _dl1.reset(); + + _mt0.reset(); + _mt1.reset(); + _mt2.reset(); + _mt3.reset(); + _mt4.reset(); + _mt5.reset(); + _mt6.reset(); + _mt7.reset(); + _mt8.reset(); + _mt9.reset(); + + _ap0.reset(); + _ap1.reset(); + _ap2.reset(); + _ap3.reset(); + _ap4.reset(); + _ap5.reset(); + _ap6.reset(); + _ap7.reset(); + _ap8.reset(); + _ap9.reset(); + _ap10.reset(); + _ap11.reset(); + _ap12.reset(); + _ap13.reset(); + _ap14.reset(); + _ap15.reset(); + _ap16.reset(); + _ap17.reset(); + _ap18.reset(); + _ap19.reset(); + _ap20.reset(); + _ap21.reset(); + + _eq0.reset(); + _eq1.reset(); + + _lp0.reset(); + _lp1.reset(); +} + +// +// Public API +// + +static const int REVERB_BLOCK = 1024; + +AudioReverb::AudioReverb(float sampleRate) { + + _impl = new ReverbImpl; + + // format conversion buffers + _inout[0] = new float[REVERB_BLOCK]; + _inout[1] = new float[REVERB_BLOCK]; + + // default parameters + ReverbParameters p; + p.sampleRate = sampleRate; + p.bandwidth = 10000.0f; + + p.preDelay = 20.0f; + p.lateDelay = 0.0f; + + p.reverbTime = 2.0f; + + p.earlyDiffusion = 100.0f; + p.lateDiffusion = 100.0f; + + p.roomSize = 50.0f; + p.density = 100.0f; + + p.bassMult = 1.5f; + p.bassFreq = 250.0f; + p.highGain = -6.0f; + p.highFreq = 3000.0f; + + p.modRate = 2.3f; + p.modDepth = 50.0f; + + p.earlyGain = 0.0f; + p.lateGain = 0.0f; + + p.earlyMixLeft = 20.0f; + p.earlyMixRight = 20.0f; + p.lateMixLeft = 90.0f; + p.lateMixRight = 90.0f; + + p.wetDryMix = 100.0f; + + setParameters(&p); +} + +AudioReverb::~AudioReverb() { + delete _impl; + + delete[] _inout[0]; + delete[] _inout[1]; +} + +void AudioReverb::setParameters(ReverbParameters *p) { + _params = *p; + _impl->setParameters(p); +}; + +void AudioReverb::getParameters(ReverbParameters *p) { + *p = _params; +}; + +void AudioReverb::reset() { + _impl->reset(); +} + +void AudioReverb::render(float** inputs, float** outputs, int numFrames) { + _impl->process(inputs, outputs, numFrames); +} + +// +// on x86 architecture, assume that SSE2 is present +// +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) + +#include + +// convert int16_t to float, deinterleave stereo +void AudioReverb::convertInputFromInt16(const int16_t* input, float** outputs, int numFrames) { + __m128 scale = _mm_set1_ps(1/32768.0f); + + int i = 0; + for (; i < numFrames - 3; i += 4) { + __m128i a0 = _mm_loadu_si128((__m128i*)&input[2*i]); + __m128i a1 = a0; + + // deinterleave and sign-extend + a0 = _mm_madd_epi16(a0, _mm_set1_epi32(0x00000001)); + a1 = _mm_madd_epi16(a1, _mm_set1_epi32(0x00010000)); + + __m128 f0 = _mm_mul_ps(_mm_cvtepi32_ps(a0), scale); + __m128 f1 = _mm_mul_ps(_mm_cvtepi32_ps(a1), scale); + + _mm_storeu_ps(&outputs[0][i], f0); + _mm_storeu_ps(&outputs[1][i], f1); + } + for (; i < numFrames; i++) { + __m128i a0 = _mm_cvtsi32_si128(*(int32_t*)&input[2*i]); + __m128i a1 = a0; + + // deinterleave and sign-extend + a0 = _mm_madd_epi16(a0, _mm_set1_epi32(0x00000001)); + a1 = _mm_madd_epi16(a1, _mm_set1_epi32(0x00010000)); + + __m128 f0 = _mm_mul_ps(_mm_cvtepi32_ps(a0), scale); + __m128 f1 = _mm_mul_ps(_mm_cvtepi32_ps(a1), scale); + + _mm_store_ss(&outputs[0][i], f0); + _mm_store_ss(&outputs[1][i], f1); + } +} + +// fast TPDF dither in [-1.0f, 1.0f] +static inline __m128 dither4() { + static __m128i rz; + + // update the 8 different maximum-length LCGs + rz = _mm_mullo_epi16(rz, _mm_set_epi16(25173, -25511, -5975, -23279, 19445, -27591, 30185, -3495)); + rz = _mm_add_epi16(rz, _mm_set_epi16(13849, -32767, 105, -19675, -7701, -32679, -13225, 28013)); + + // promote to 32-bit + __m128i r0 = _mm_unpacklo_epi16(rz, _mm_setzero_si128()); + __m128i r1 = _mm_unpackhi_epi16(rz, _mm_setzero_si128()); + + // return (r0 - r1) * (1/65536.0f); + __m128 d0 = _mm_cvtepi32_ps(_mm_sub_epi32(r0, r1)); + return _mm_mul_ps(d0, _mm_set1_ps(1/65536.0f)); +} + +// convert float to int16_t, interleave stereo +void AudioReverb::convertOutputToInt16(float** inputs, int16_t* output, int numFrames) { + __m128 scale = _mm_set1_ps(32768.0f); + + int i = 0; + for (; i < numFrames - 3; i += 4) { + __m128 f0 = _mm_mul_ps(_mm_loadu_ps(&inputs[0][i]), scale); + __m128 f1 = _mm_mul_ps(_mm_loadu_ps(&inputs[1][i]), scale); + + __m128 d0 = dither4(); + f0 = _mm_add_ps(f0, d0); + f1 = _mm_add_ps(f1, d0); + + // round and saturate + __m128i a0 = _mm_cvtps_epi32(f0); + __m128i a1 = _mm_cvtps_epi32(f1); + a0 = _mm_packs_epi32(a0, a0); + a1 = _mm_packs_epi32(a1, a1); + + // interleave + a0 = _mm_unpacklo_epi16(a0, a1); + _mm_storeu_si128((__m128i*)&output[2*i], a0); + } + for (; i < numFrames; i++) { + __m128 f0 = _mm_mul_ps(_mm_load_ss(&inputs[0][i]), scale); + __m128 f1 = _mm_mul_ps(_mm_load_ss(&inputs[1][i]), scale); + + __m128 d0 = dither4(); + f0 = _mm_add_ps(f0, d0); + f1 = _mm_add_ps(f1, d0); + + // round and saturate + __m128i a0 = _mm_cvtps_epi32(f0); + __m128i a1 = _mm_cvtps_epi32(f1); + a0 = _mm_packs_epi32(a0, a0); + a1 = _mm_packs_epi32(a1, a1); + + // interleave + a0 = _mm_unpacklo_epi16(a0, a1); + *(int32_t*)&output[2*i] = _mm_cvtsi128_si32(a0); + } +} + +#else + +// convert int16_t to float, deinterleave stereo +void AudioReverb::convertInputFromInt16(const int16_t* input, float** outputs, int numFrames) { + const float scale = 1/32768.0f; + + for (int i = 0; i < numFrames; i++) { + outputs[0][i] = (float)input[2*i + 0] * scale; + outputs[1][i] = (float)input[2*i + 1] * scale; + } +} + +// fast TPDF dither in [-1.0f, 1.0f] +static inline float dither() { + static uint32_t rz = 0; + rz = rz * 69069 + 1; + int32_t r0 = rz & 0xffff; + int32_t r1 = rz >> 16; + return (int32_t)(r0 - r1) * (1/65536.0f); +} + +// convert float to int16_t, interleave stereo +void AudioReverb::convertOutputToInt16(float** inputs, int16_t* output, int numFrames) { + const float scale = 32768.0f; + + for (int i = 0; i < numFrames; i++) { + + float f0 = inputs[0][i] * scale; + float f1 = inputs[1][i] * scale; + + float d = dither(); + f0 += d; + f1 += d; + + // round and saturate + f0 += (f0 < 0.0f ? -0.5f : +0.5f); + f1 += (f1 < 0.0f ? -0.5f : +0.5f); + f0 = MIN(MAX(f0, -32768.0f), 32767.0f); + f1 = MIN(MAX(f1, -32768.0f), 32767.0f); + + // interleave + output[2*i + 0] = (int16_t)f0; + output[2*i + 1] = (int16_t)f1; + } +} + +#endif + +// +// This version handles input/output as interleaved int16_t +// +void AudioReverb::render(const int16_t* input, int16_t* output, int numFrames) { + + while (numFrames) { + + int n = MIN(numFrames, REVERB_BLOCK); + + convertInputFromInt16(input, _inout, n); + + _impl->process(_inout, _inout, n); + + convertOutputToInt16(_inout, output, n); + + input += 2 * n; + output += 2 * n; + numFrames -= n; + } +} diff --git a/libraries/audio/src/AudioReverb.h b/libraries/audio/src/AudioReverb.h new file mode 100644 index 0000000000..f135a46127 --- /dev/null +++ b/libraries/audio/src/AudioReverb.h @@ -0,0 +1,76 @@ +// +// AudioReverb.h +// libraries/audio/src +// +// Created by Ken Cooke on 10/11/15. +// Copyright 2015 High Fidelity, Inc. +// + +#ifndef hifi_AudioReverb_h +#define hifi_AudioReverb_h + +#include "stdint.h" + +typedef struct ReverbParameters { + + float sampleRate; // [24000, 48000] Hz + float bandwidth; // [20, 24000] Hz + + float preDelay; // [0, 333] ms + float lateDelay; // [0, 166] ms + + float reverbTime; // [0.1, 100] seconds + + float earlyDiffusion; // [0, 100] percent + float lateDiffusion; // [0, 100] percent + + float roomSize; // [0, 100] percent + float density; // [0, 100] percent + + float bassMult; // [0.1, 10] ratio + float bassFreq; // [10, 500] Hz + float highGain; // [-24, 0] dB + float highFreq; // [1000, 12000] Hz + + float modRate; // [0.1, 10] Hz + float modDepth; // [0, 100] percent + + float earlyGain; // [-96, +24] dB + float lateGain; // [-96, +24] dB + + float earlyMixLeft; // [0, 100] percent + float earlyMixRight; // [0, 100] percent + float lateMixLeft; // [0, 100] percent + float lateMixRight; // [0, 100] percent + + float wetDryMix; // [0, 100] percent + +} ReverbParameters; + +class ReverbImpl; + +class AudioReverb { + + ReverbImpl *_impl; + ReverbParameters _params; + + float* _inout[2]; + void convertInputFromInt16(const int16_t* input, float** outputs, int numFrames); + void convertOutputToInt16(float** inputs, int16_t* output, int numFrames); + +public: + AudioReverb(float sampleRate); + ~AudioReverb(); + + void setParameters(ReverbParameters *p); + void getParameters(ReverbParameters *p); + void reset(); + + // deinterleaved float input/output (native format) + void render(float** inputs, float** outputs, int numFrames); + + // interleaved int16_t input/output + void render(const int16_t* input, int16_t* output, int numFrames); +}; + +#endif // hifi_AudioReverb_h From c61dad108c5125fad38cf1e360c94904a6fc4bfa Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 18 Nov 2015 09:16:18 -0800 Subject: [PATCH 173/401] Replace Gverb with new reverb --- libraries/audio-client/src/AudioClient.cpp | 184 ++++++++++++--------- libraries/audio-client/src/AudioClient.h | 12 +- 2 files changed, 114 insertions(+), 82 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index a506fe217c..daf89d3473 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -119,7 +119,7 @@ AudioClient::AudioClient() : _audioSourceInjectEnabled(false), _reverb(false), _reverbOptions(&_scriptReverbOptions), - _gverb(NULL), + //_gverb(NULL), _inputToNetworkResampler(NULL), _networkToOutputResampler(NULL), _loopbackResampler(NULL), @@ -145,8 +145,8 @@ AudioClient::AudioClient() : updateTimer->start(DEVICE_CHECK_INTERVAL_MSECS); // create GVerb filter - _gverb = createGverbFilter(); - configureGverbFilter(_gverb); + //_gverb = createGverbFilter(); + configureReverb(); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListener(PacketType::AudioStreamStats, &_stats, "processStreamStatsPacket"); @@ -160,9 +160,9 @@ AudioClient::AudioClient() : AudioClient::~AudioClient() { stop(); - if (_gverb) { - gverb_free(_gverb); - } + //if (_gverb) { + // gverb_free(_gverb); + //} } void AudioClient::reset() { @@ -173,7 +173,8 @@ void AudioClient::reset() { _sourceGain.reset(); _inputGain.reset(); - gverb_flush(_gverb); + //gverb_flush(_gverb); + _stereoReverb.reset(); } void AudioClient::audioMixerKilled() { @@ -568,27 +569,42 @@ bool AudioClient::switchOutputToAudioDevice(const QString& outputDeviceName) { return switchOutputToAudioDevice(getNamedAudioDeviceForMode(QAudio::AudioOutput, outputDeviceName)); } -ty_gverb* AudioClient::createGverbFilter() { - // Initialize a new gverb instance - ty_gverb* filter = gverb_new(_outputFormat.sampleRate(), _reverbOptions->getMaxRoomSize(), _reverbOptions->getRoomSize(), - _reverbOptions->getReverbTime(), _reverbOptions->getDamping(), _reverbOptions->getSpread(), - _reverbOptions->getInputBandwidth(), _reverbOptions->getEarlyLevel(), - _reverbOptions->getTailLevel()); +//ty_gverb* AudioClient::createGverbFilter() { +// // Initialize a new gverb instance +// ty_gverb* filter = gverb_new(_outputFormat.sampleRate(), _reverbOptions->getMaxRoomSize(), _reverbOptions->getRoomSize(), +// _reverbOptions->getReverbTime(), _reverbOptions->getDamping(), _reverbOptions->getSpread(), +// _reverbOptions->getInputBandwidth(), _reverbOptions->getEarlyLevel(), +// _reverbOptions->getTailLevel()); +// +// return filter; +//} - return filter; -} - -void AudioClient::configureGverbFilter(ty_gverb* filter) { +void AudioClient::configureReverb() { // Configure the instance (these functions are not super well named - they actually set several internal variables) - gverb_set_roomsize(filter, _reverbOptions->getRoomSize()); - gverb_set_revtime(filter, _reverbOptions->getReverbTime()); - gverb_set_damping(filter, _reverbOptions->getDamping()); - gverb_set_inputbandwidth(filter, _reverbOptions->getInputBandwidth()); - gverb_set_earlylevel(filter, DB_CO(_reverbOptions->getEarlyLevel())); - gverb_set_taillevel(filter, DB_CO(_reverbOptions->getTailLevel())); + //gverb_set_roomsize(filter, _reverbOptions->getRoomSize()); + //gverb_set_revtime(filter, _reverbOptions->getReverbTime()); + //gverb_set_damping(filter, _reverbOptions->getDamping()); + //gverb_set_inputbandwidth(filter, _reverbOptions->getInputBandwidth()); + //gverb_set_earlylevel(filter, DB_CO(_reverbOptions->getEarlyLevel())); + //gverb_set_taillevel(filter, DB_CO(_reverbOptions->getTailLevel())); + + ReverbParameters p; + _stereoReverb.getParameters(&p); + + // for now, use the gverb settings + p.sampleRate = _outputFormat.sampleRate(); + p.roomSize = _reverbOptions->getRoomSize(); + p.reverbTime = _reverbOptions->getReverbTime(); + p.highGain = -24.0f * _reverbOptions->getDamping(); + p.bandwidth = 12000.0f * _reverbOptions->getInputBandwidth(); + //p.earlyGain = _reverbOptions->getEarlyLevel(); + //p.lateGain = _reverbOptions->getTailLevel(); + p.wetDryMix = _shouldEchoLocally ? DB_CO(_reverbOptions->getWetLevel()) : 100.0f; // !_shouldEchoLocally apparently means 100% wet? + + _stereoReverb.setParameters(&p); } -void AudioClient::updateGverbOptions() { +void AudioClient::updateReverbOptions() { bool reverbChanged = false; if (_receivedAudioStream.hasReverb()) { @@ -599,6 +615,7 @@ void AudioClient::updateGverbOptions() { if (_zoneReverbOptions.getWetLevel() != _receivedAudioStream.getWetLevel()) { _zoneReverbOptions.setWetLevel(_receivedAudioStream.getWetLevel()); // Not part of actual filter config, no need to set reverbChanged to true + reverbChanged = true; } if (_reverbOptions != &_zoneReverbOptions) { @@ -611,9 +628,9 @@ void AudioClient::updateGverbOptions() { } if (reverbChanged) { - gverb_free(_gverb); - _gverb = createGverbFilter(); - configureGverbFilter(_gverb); + //gverb_free(_gverb); + //_gverb = createGverbFilter(); + configureReverb(); } } @@ -621,7 +638,8 @@ void AudioClient::setReverb(bool reverb) { _reverb = reverb; if (!_reverb) { - gverb_flush(_gverb); + //gverb_flush(_gverb); + _stereoReverb.reset(); } } @@ -641,49 +659,49 @@ void AudioClient::setReverbOptions(const AudioEffectOptions* options) { if (_reverbOptions == &_scriptReverbOptions) { // Apply them to the reverb instances - gverb_free(_gverb); - _gverb = createGverbFilter(); - configureGverbFilter(_gverb); + //gverb_free(_gverb); + //_gverb = createGverbFilter(); + configureReverb(); } } -void AudioClient::addReverb(ty_gverb* gverb, int16_t* samplesData, int16_t* reverbAlone, int numSamples, - QAudioFormat& audioFormat, bool noEcho) { - float wetFraction = DB_CO(_reverbOptions->getWetLevel()); - float dryFraction = 1.0f - wetFraction; - - float lValue,rValue; - for (int sample = 0; sample < numSamples; sample += audioFormat.channelCount()) { - // Run GVerb - float value = (float)samplesData[sample]; - gverb_do(gverb, value, &lValue, &rValue); - - // Mix, accounting for clipping, the left and right channels. Ignore the rest. - for (int j = sample; j < sample + audioFormat.channelCount(); j++) { - if (j == sample) { - // left channel - int lResult = glm::clamp((int)(samplesData[j] * dryFraction + lValue * wetFraction), - AudioConstants::MIN_SAMPLE_VALUE, AudioConstants::MAX_SAMPLE_VALUE); - samplesData[j] = (int16_t)lResult; - - if (noEcho) { - reverbAlone[j] = (int16_t)lValue * wetFraction; - } - } else if (j == (sample + 1)) { - // right channel - int rResult = glm::clamp((int)(samplesData[j] * dryFraction + rValue * wetFraction), - AudioConstants::MIN_SAMPLE_VALUE, AudioConstants::MAX_SAMPLE_VALUE); - samplesData[j] = (int16_t)rResult; - - if (noEcho) { - reverbAlone[j] = (int16_t)rValue * wetFraction; - } - } else { - // ignore channels above 2 - } - } - } -} +//void AudioClient::addReverb(ty_gverb* gverb, int16_t* samplesData, int16_t* reverbAlone, int numSamples, +// QAudioFormat& audioFormat, bool noEcho) { +// float wetFraction = DB_CO(_reverbOptions->getWetLevel()); +// float dryFraction = 1.0f - wetFraction; +// +// float lValue,rValue; +// for (int sample = 0; sample < numSamples; sample += audioFormat.channelCount()) { +// // Run GVerb +// float value = (float)samplesData[sample]; +// gverb_do(gverb, value, &lValue, &rValue); +// +// // Mix, accounting for clipping, the left and right channels. Ignore the rest. +// for (int j = sample; j < sample + audioFormat.channelCount(); j++) { +// if (j == sample) { +// // left channel +// int lResult = glm::clamp((int)(samplesData[j] * dryFraction + lValue * wetFraction), +// AudioConstants::MIN_SAMPLE_VALUE, AudioConstants::MAX_SAMPLE_VALUE); +// samplesData[j] = (int16_t)lResult; +// +// if (noEcho) { +// reverbAlone[j] = (int16_t)lValue * wetFraction; +// } +// } else if (j == (sample + 1)) { +// // right channel +// int rResult = glm::clamp((int)(samplesData[j] * dryFraction + rValue * wetFraction), +// AudioConstants::MIN_SAMPLE_VALUE, AudioConstants::MAX_SAMPLE_VALUE); +// samplesData[j] = (int16_t)rResult; +// +// if (noEcho) { +// reverbAlone[j] = (int16_t)rValue * wetFraction; +// } +// } else { +// // ignore channels above 2 +// } +// } +// } +//} void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) { // If there is server echo, reverb will be applied to the recieved audio stream so no need to have it here. @@ -715,30 +733,42 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) { _loopbackResampler = new AudioSRC(_inputFormat.sampleRate(), _outputFormat.sampleRate(), channelCount); } - static QByteArray reverbAlone; // Intermediary for local reverb with no echo + //static QByteArray reverbAlone; // Intermediary for local reverb with no echo static QByteArray loopBackByteArray; int numInputSamples = inputByteArray.size() / sizeof(int16_t); int numLoopbackSamples = numDestinationSamplesRequired(_inputFormat, _outputFormat, numInputSamples); - reverbAlone.resize(numInputSamples * sizeof(int16_t)); + //reverbAlone.resize(numInputSamples * sizeof(int16_t)); loopBackByteArray.resize(numLoopbackSamples * sizeof(int16_t)); int16_t* inputSamples = reinterpret_cast(inputByteArray.data()); - int16_t* reverbAloneSamples = reinterpret_cast(reverbAlone.data()); + //int16_t* reverbAloneSamples = reinterpret_cast(reverbAlone.data()); int16_t* loopbackSamples = reinterpret_cast(loopBackByteArray.data()); - if (hasReverb) { - updateGverbOptions(); - addReverb(_gverb, inputSamples, reverbAloneSamples, numInputSamples, - _inputFormat, !_shouldEchoLocally); - } + //if (hasReverb) { + // updateGverbOptions(); + // addReverb(_gverb, inputSamples, reverbAloneSamples, numInputSamples, + // _inputFormat, !_shouldEchoLocally); + //} + + //possibleResampling(_loopbackResampler, + // (_shouldEchoLocally) ? inputSamples : reverbAloneSamples, loopbackSamples, + // numInputSamples, numLoopbackSamples, + // _inputFormat, _outputFormat); possibleResampling(_loopbackResampler, - (_shouldEchoLocally) ? inputSamples : reverbAloneSamples, loopbackSamples, + inputSamples, loopbackSamples, numInputSamples, numLoopbackSamples, _inputFormat, _outputFormat); + if (hasReverb) { + // always use the stereo reverb output + assert(_outputFormat.channelCount() == 2); + updateReverbOptions(); + _stereoReverb.render(loopbackSamples, loopbackSamples, numLoopbackSamples/2); + } + _loopbackOutputDevice->write(loopBackByteArray); } diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 7d2b5a783f..c2a235938b 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -46,6 +46,7 @@ #include "AudioIOStats.h" #include "AudioNoiseGate.h" #include "AudioSRC.h" +#include "AudioReverb.h" #ifdef _WIN32 #pragma warning( push ) @@ -262,7 +263,8 @@ private: AudioEffectOptions _scriptReverbOptions; AudioEffectOptions _zoneReverbOptions; AudioEffectOptions* _reverbOptions; - ty_gverb* _gverb; + //ty_gverb* _gverb; + AudioReverb _stereoReverb { AudioConstants::SAMPLE_RATE }; // possible streams needed for resample AudioSRC* _inputToNetworkResampler; @@ -270,10 +272,10 @@ private: AudioSRC* _loopbackResampler; // Adds Reverb - ty_gverb* createGverbFilter(); - void configureGverbFilter(ty_gverb* filter); - void updateGverbOptions(); - void addReverb(ty_gverb* gverb, int16_t* samples, int16_t* reverbAlone, int numSamples, QAudioFormat& format, bool noEcho = false); + //ty_gverb* createGverbFilter(); + void configureReverb(); + void updateReverbOptions(); + //void addReverb(ty_gverb* gverb, int16_t* samples, int16_t* reverbAlone, int numSamples, QAudioFormat& format, bool noEcho = false); void handleLocalEchoAndReverb(QByteArray& inputByteArray); From 8ae3fa61c50d846cab1bf4c423e0bc47168b3045 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 18 Nov 2015 10:06:40 -0800 Subject: [PATCH 174/401] Fix compiler issues --- libraries/audio/src/AudioReverb.cpp | 60 ++++++++++++++--------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/libraries/audio/src/AudioReverb.cpp b/libraries/audio/src/AudioReverb.cpp index 3f28a9c00d..a822da3377 100644 --- a/libraries/audio/src/AudioReverb.cpp +++ b/libraries/audio/src/AudioReverb.cpp @@ -17,8 +17,8 @@ #include inline static int MULHI(int a, int b) { - long long c = __emul(a, b); - return ((int*)&c)[1]; + long long c = __emul(a, b); + return ((int*)&c)[1]; } #else @@ -33,10 +33,10 @@ inline static int MULHI(int a, int b) { #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif -static const float M_PHI = 0.6180339887f; // maximum allpass diffusion +static const float PHI = 0.6180339887f; // maximum allpass diffusion -static const double M_PI = 3.14159265358979323846; -static const double M_SQRT2 = 1.41421356237309504880; +static const double PI = 3.14159265358979323846; +static const double SQRT2 = 1.41421356237309504880; static const double FIXQ31 = 2147483648.0; static const double FIXQ32 = 4294967296.0; @@ -208,8 +208,8 @@ static void BQPeakBelowPi(double coef[5], double w0, double dbgain, double Q) { G = MAX(G, 1.001); // compute the Nyquist gain - wpi = w0 + 2.8 * (1.0 - w0/M_PI); // minimax-like error - wpi = MIN(wpi, M_PI); + wpi = w0 + 2.8 * (1.0 - w0/PI); // minimax-like error + wpi = MIN(wpi, PI); G1 = analogPeak(w0, G, Q, wpi); G1sq = G1 * G1; @@ -218,7 +218,7 @@ static void BQPeakBelowPi(double coef[5], double w0, double dbgain, double Q) { // compute the analog half-gain frequency temp = G + 2.0 * Qsq - sqrt(Gsq + 4.0 * Qsq * G); - wh = sqrt(temp) * w0 / (Q * M_SQRT2); + wh = sqrt(temp) * w0 / (Q * SQRT2); // prewarp freqs of w0 and wh w0 = tan(0.5 * w0); @@ -305,8 +305,8 @@ static void BQPeakAbovePi(double coef[5], double w0, double dbgain, double Q) { G = MAX(G, 1.001); // compute the Nyquist gain - wpi = M_PI; - if (w0 < M_PI) { + wpi = PI; + if (w0 < PI) { G1 = G; // use the peak gain } else { G1 = analogPeak(w0, G, Q, wpi); // use Nyquist gain of analog response @@ -317,7 +317,7 @@ static void BQPeakAbovePi(double coef[5], double w0, double dbgain, double Q) { // compute the analog half-gain frequency temp = G + 2.0 * Qsq - sqrt(Gsq + 4.0 * Qsq * G); - wh = sqrt(temp) * w0 / (Q * M_SQRT2); + wh = sqrt(temp) * w0 / (Q * SQRT2); // approximate wn and wd // use half-gain frequency as mapping @@ -425,8 +425,8 @@ static void BQShelf(double coef[5], double w0, double dbgain, double resonance, G = MAX(G, 1.001); // compute the Nyquist gain - wpi = w0 + 2.8 * (1.0 - w0/M_PI); // minimax-like error - wpi = MIN(wpi, M_PI); + wpi = w0 + 2.8 * (1.0 - w0/PI); // minimax-like error + wpi = MIN(wpi, PI); G1 = analogShelf(w0, G, resonance, isHigh, wpi); // approximate wn and wd @@ -513,10 +513,10 @@ static void BQFilter(double coef[5], double w0, int isHigh) { if (isHigh) { - w0 = MIN(w0, M_PI); // disallow w0 > pi for highpass + w0 = MIN(w0, PI); // disallow w0 > pi for highpass // compute the Nyquist gain - wpi = M_PI; + wpi = PI; G1 = analogFilter(w0, isHigh, wpi); // approximate wn and wd @@ -528,13 +528,13 @@ static void BQFilter(double coef[5], double w0, int isHigh) { // compute B and A B = 0.0; - A = M_SQRT2 * Wdsq / atan(wd); // Qd = sqrt(0.5) * atan(wd)/wd; + A = SQRT2 * Wdsq / atan(wd); // Qd = sqrt(0.5) * atan(wd)/wd; } else { // compute the Nyquist gain - wpi = w0 + 2.8 * (1.0 - w0/M_PI); // minimax-like error - wpi = MIN(wpi, M_PI); + wpi = w0 + 2.8 * (1.0 - w0/PI); // minimax-like error + wpi = MIN(wpi, PI); G1 = analogFilter(w0, isHigh, wpi); // approximate wn and wd @@ -653,7 +653,7 @@ public: // lowpass filter, -3dB @ freq double coef[5]; - BQFilter(coef, M_PI * freq / (0.5 * sampleRate), 0); + BQFilter(coef, PI * freq / (0.5 * sampleRate), 0); _b0 = (float)coef[0]; _b1 = (float)coef[1]; _b2 = (float)coef[2]; @@ -661,7 +661,7 @@ public: _a2 = (float)coef[4]; // DC-blocking filter, -3dB @ 10Hz - _alpha = (float)(1.0 - exp(-M_PI * 10.0 / (0.5 * sampleRate))); + _alpha = (float)(1.0 - exp(-PI * 10.0 / (0.5 * sampleRate))); } void process(float input0, float input1, float& output0, float& output1) { @@ -809,9 +809,9 @@ public: // amplitude slightly less than 1.0 _y0 = (int32_t)(0.000 * FIXQ31); - _y1 = (int32_t)(0.999 * cos(M_PI * freq / sampleRate) * FIXQ31); + _y1 = (int32_t)(0.999 * cos(PI * freq / sampleRate) * FIXQ31); - _k = (int32_t)(2.0 * sin(M_PI * freq / sampleRate) * FIXQ32); + _k = (int32_t)(2.0 * sin(PI * freq / sampleRate) * FIXQ32); } void setGain(int32_t gain) { @@ -895,7 +895,7 @@ public: output = _output; // add modulation to delay - uint32_t offset = _delay + (mod >> MOD_FRACBITS); + int32_t offset = _delay + (mod >> MOD_FRACBITS); float frac = (mod & MOD_FRACMASK) * QMOD_TO_FLOAT; // 3rd-order Lagrange interpolation @@ -985,8 +985,8 @@ public: freq1 = MIN(MAX(freq1, 1.0f), 24000.0f); double coefLo[3], coefHi[3]; - PZShelf(coefLo, M_PI * freq0 / (0.5 * sampleRate), dBgain0, 0); // low shelf - PZShelf(coefHi, M_PI * freq1 / (0.5 * sampleRate), dBgain1, 1); // high shelf + PZShelf(coefLo, PI * freq0 / (0.5 * sampleRate), dBgain0, 0); // low shelf + PZShelf(coefHi, PI * freq1 / (0.5 * sampleRate), dBgain1, 1); // high shelf // convolve into a single biquad _b0 = (float)(coefLo[0] * coefHi[0]); @@ -1374,7 +1374,7 @@ static const float diffusionCoefTable[][2] = { 60.0000f, 0.2344f, 73.3333f, 0.3125f, 93.3333f, 0.5000f, - 100.0000f, M_PHI, + 100.0000f, PHI, }; static const float roomSizeTable[][2] = { @@ -1552,13 +1552,13 @@ void ReverbImpl::setParameters(ReverbParameters *p) { _ap8.setCoef(lateDiffusionCoef); _ap9.setCoef(lateDiffusionCoef); - _ap10.setCoef(M_PHI); - _ap11.setCoef(M_PHI); + _ap10.setCoef(PHI); + _ap11.setCoef(PHI); _ap12.setCoef(lateDiffusionCoef); _ap13.setCoef(lateDiffusionCoef); - _ap14.setCoef(M_PHI); - _ap15.setCoef(M_PHI); + _ap14.setCoef(PHI); + _ap15.setCoef(PHI); _ap16.setCoef(lateDiffusionCoef); _ap17.setCoef(lateDiffusionCoef); From 1a7f06dc95a7f72b31bf21dc119ed96ad9c4fec7 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 18 Nov 2015 10:26:06 -0800 Subject: [PATCH 175/401] Removed the commented-out Gverb code --- libraries/audio-client/src/AudioClient.cpp | 112 +-------------------- libraries/audio-client/src/AudioClient.h | 5 - 2 files changed, 2 insertions(+), 115 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index daf89d3473..eb0be9dc17 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -33,29 +33,6 @@ #include #include -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdouble-promotion" -#endif - -#ifdef WIN32 -#pragma warning (push) -#pragma warning (disable: 4273 4305) -#endif - -extern "C" { - #include - #include -} - -#ifdef WIN32 -#pragma warning (pop) -#endif - -#if defined(__GNUC__) && !defined(__clang__) -#pragma GCC diagnostic pop -#endif - #include #include #include @@ -119,7 +96,6 @@ AudioClient::AudioClient() : _audioSourceInjectEnabled(false), _reverb(false), _reverbOptions(&_scriptReverbOptions), - //_gverb(NULL), _inputToNetworkResampler(NULL), _networkToOutputResampler(NULL), _loopbackResampler(NULL), @@ -144,8 +120,6 @@ AudioClient::AudioClient() : connect(updateTimer, &QTimer::timeout, this, &AudioClient::checkDevices); updateTimer->start(DEVICE_CHECK_INTERVAL_MSECS); - // create GVerb filter - //_gverb = createGverbFilter(); configureReverb(); auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); @@ -159,10 +133,6 @@ AudioClient::AudioClient() : AudioClient::~AudioClient() { stop(); - - //if (_gverb) { - // gverb_free(_gverb); - //} } void AudioClient::reset() { @@ -172,8 +142,6 @@ void AudioClient::reset() { _toneSource.reset(); _sourceGain.reset(); _inputGain.reset(); - - //gverb_flush(_gverb); _stereoReverb.reset(); } @@ -569,29 +537,11 @@ bool AudioClient::switchOutputToAudioDevice(const QString& outputDeviceName) { return switchOutputToAudioDevice(getNamedAudioDeviceForMode(QAudio::AudioOutput, outputDeviceName)); } -//ty_gverb* AudioClient::createGverbFilter() { -// // Initialize a new gverb instance -// ty_gverb* filter = gverb_new(_outputFormat.sampleRate(), _reverbOptions->getMaxRoomSize(), _reverbOptions->getRoomSize(), -// _reverbOptions->getReverbTime(), _reverbOptions->getDamping(), _reverbOptions->getSpread(), -// _reverbOptions->getInputBandwidth(), _reverbOptions->getEarlyLevel(), -// _reverbOptions->getTailLevel()); -// -// return filter; -//} - void AudioClient::configureReverb() { - // Configure the instance (these functions are not super well named - they actually set several internal variables) - //gverb_set_roomsize(filter, _reverbOptions->getRoomSize()); - //gverb_set_revtime(filter, _reverbOptions->getReverbTime()); - //gverb_set_damping(filter, _reverbOptions->getDamping()); - //gverb_set_inputbandwidth(filter, _reverbOptions->getInputBandwidth()); - //gverb_set_earlylevel(filter, DB_CO(_reverbOptions->getEarlyLevel())); - //gverb_set_taillevel(filter, DB_CO(_reverbOptions->getTailLevel())); - ReverbParameters p; _stereoReverb.getParameters(&p); - // for now, use the gverb settings + // for now, reuse the gverb parameters p.sampleRate = _outputFormat.sampleRate(); p.roomSize = _reverbOptions->getRoomSize(); p.reverbTime = _reverbOptions->getReverbTime(); @@ -599,7 +549,7 @@ void AudioClient::configureReverb() { p.bandwidth = 12000.0f * _reverbOptions->getInputBandwidth(); //p.earlyGain = _reverbOptions->getEarlyLevel(); //p.lateGain = _reverbOptions->getTailLevel(); - p.wetDryMix = _shouldEchoLocally ? DB_CO(_reverbOptions->getWetLevel()) : 100.0f; // !_shouldEchoLocally apparently means 100% wet? + p.wetDryMix = _shouldEchoLocally ? powf(10.0f, _reverbOptions->getWetLevel() * (1/20.0f)) : 100.0f; _stereoReverb.setParameters(&p); } @@ -614,7 +564,6 @@ void AudioClient::updateReverbOptions() { } if (_zoneReverbOptions.getWetLevel() != _receivedAudioStream.getWetLevel()) { _zoneReverbOptions.setWetLevel(_receivedAudioStream.getWetLevel()); - // Not part of actual filter config, no need to set reverbChanged to true reverbChanged = true; } @@ -628,8 +577,6 @@ void AudioClient::updateReverbOptions() { } if (reverbChanged) { - //gverb_free(_gverb); - //_gverb = createGverbFilter(); configureReverb(); } } @@ -638,7 +585,6 @@ void AudioClient::setReverb(bool reverb) { _reverb = reverb; if (!_reverb) { - //gverb_flush(_gverb); _stereoReverb.reset(); } } @@ -659,50 +605,10 @@ void AudioClient::setReverbOptions(const AudioEffectOptions* options) { if (_reverbOptions == &_scriptReverbOptions) { // Apply them to the reverb instances - //gverb_free(_gverb); - //_gverb = createGverbFilter(); configureReverb(); } } -//void AudioClient::addReverb(ty_gverb* gverb, int16_t* samplesData, int16_t* reverbAlone, int numSamples, -// QAudioFormat& audioFormat, bool noEcho) { -// float wetFraction = DB_CO(_reverbOptions->getWetLevel()); -// float dryFraction = 1.0f - wetFraction; -// -// float lValue,rValue; -// for (int sample = 0; sample < numSamples; sample += audioFormat.channelCount()) { -// // Run GVerb -// float value = (float)samplesData[sample]; -// gverb_do(gverb, value, &lValue, &rValue); -// -// // Mix, accounting for clipping, the left and right channels. Ignore the rest. -// for (int j = sample; j < sample + audioFormat.channelCount(); j++) { -// if (j == sample) { -// // left channel -// int lResult = glm::clamp((int)(samplesData[j] * dryFraction + lValue * wetFraction), -// AudioConstants::MIN_SAMPLE_VALUE, AudioConstants::MAX_SAMPLE_VALUE); -// samplesData[j] = (int16_t)lResult; -// -// if (noEcho) { -// reverbAlone[j] = (int16_t)lValue * wetFraction; -// } -// } else if (j == (sample + 1)) { -// // right channel -// int rResult = glm::clamp((int)(samplesData[j] * dryFraction + rValue * wetFraction), -// AudioConstants::MIN_SAMPLE_VALUE, AudioConstants::MAX_SAMPLE_VALUE); -// samplesData[j] = (int16_t)rResult; -// -// if (noEcho) { -// reverbAlone[j] = (int16_t)rValue * wetFraction; -// } -// } else { -// // ignore channels above 2 -// } -// } -// } -//} - void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) { // If there is server echo, reverb will be applied to the recieved audio stream so no need to have it here. bool hasReverb = _reverb || _receivedAudioStream.hasReverb(); @@ -733,30 +639,16 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) { _loopbackResampler = new AudioSRC(_inputFormat.sampleRate(), _outputFormat.sampleRate(), channelCount); } - //static QByteArray reverbAlone; // Intermediary for local reverb with no echo static QByteArray loopBackByteArray; int numInputSamples = inputByteArray.size() / sizeof(int16_t); int numLoopbackSamples = numDestinationSamplesRequired(_inputFormat, _outputFormat, numInputSamples); - //reverbAlone.resize(numInputSamples * sizeof(int16_t)); loopBackByteArray.resize(numLoopbackSamples * sizeof(int16_t)); int16_t* inputSamples = reinterpret_cast(inputByteArray.data()); - //int16_t* reverbAloneSamples = reinterpret_cast(reverbAlone.data()); int16_t* loopbackSamples = reinterpret_cast(loopBackByteArray.data()); - //if (hasReverb) { - // updateGverbOptions(); - // addReverb(_gverb, inputSamples, reverbAloneSamples, numInputSamples, - // _inputFormat, !_shouldEchoLocally); - //} - - //possibleResampling(_loopbackResampler, - // (_shouldEchoLocally) ? inputSamples : reverbAloneSamples, loopbackSamples, - // numInputSamples, numLoopbackSamples, - // _inputFormat, _outputFormat); - possibleResampling(_loopbackResampler, inputSamples, loopbackSamples, numInputSamples, numLoopbackSamples, diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index c2a235938b..30e60d1775 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -75,8 +75,6 @@ class QAudioInput; class QAudioOutput; class QIODevice; -typedef struct ty_gverb ty_gverb; - class NLPacket; @@ -263,7 +261,6 @@ private: AudioEffectOptions _scriptReverbOptions; AudioEffectOptions _zoneReverbOptions; AudioEffectOptions* _reverbOptions; - //ty_gverb* _gverb; AudioReverb _stereoReverb { AudioConstants::SAMPLE_RATE }; // possible streams needed for resample @@ -272,10 +269,8 @@ private: AudioSRC* _loopbackResampler; // Adds Reverb - //ty_gverb* createGverbFilter(); void configureReverb(); void updateReverbOptions(); - //void addReverb(ty_gverb* gverb, int16_t* samples, int16_t* reverbAlone, int numSamples, QAudioFormat& format, bool noEcho = false); void handleLocalEchoAndReverb(QByteArray& inputByteArray); From cc90662bf050b7cf3cf3ec51313e284ed00a8351 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 18 Nov 2015 12:17:27 -0800 Subject: [PATCH 176/401] PR feedback --- libraries/audio/src/AudioReverb.cpp | 8 ++++---- libraries/audio/src/AudioReverb.h | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/libraries/audio/src/AudioReverb.cpp b/libraries/audio/src/AudioReverb.cpp index a822da3377..f06bbe76ed 100644 --- a/libraries/audio/src/AudioReverb.cpp +++ b/libraries/audio/src/AudioReverb.cpp @@ -244,7 +244,7 @@ static void BQPeakBelowPi(double coef[5], double w0, double dbgain, double Q) { temp += Gratio * w0sq * w0sq / (G * whsq); A = sqrt(temp); - // design digital filter via bilinear tranform + // design digital filter via bilinear transform b0 = G1 + B + Wsq; b1 = 2.0 * (Wsq - G1); b2 = G1 - B + Wsq; @@ -347,7 +347,7 @@ static void BQPeakAbovePi(double coef[5], double w0, double dbgain, double Q) { num = (Wnsq - Wdsq) * (Wnsq - Wdsq) * (Wnsq + gnsq * Wdsq); A = temp * sqrt(num / den); - // design digital filter via bilinear tranform + // design digital filter via bilinear transform b0 = G1 * (1.0 + B + Wnsq); b1 = G1 * 2.0 * (Wnsq - 1.0); b2 = G1 * (1.0 - B + Wnsq); @@ -463,7 +463,7 @@ static void BQShelf(double coef[5], double w0, double dbgain, double resonance, num = (Wnsq - Wdsq) * (Wnsq - Wdsq) * (Wnsq + gnsq * Wdsq); A = temp * sqrt(num / den); - // design digital filter via bilinear tranform + // design digital filter via bilinear transform b0 = G1 * (1.0 + B + Wnsq); b1 = G1 * 2.0 * (Wnsq - 1.0); b2 = G1 * (1.0 - B + Wnsq); @@ -566,7 +566,7 @@ static void BQFilter(double coef[5], double w0, int isHigh) { A = temp * sqrt(num / den); } - // design digital filter via bilinear tranform + // design digital filter via bilinear transform b0 = G1 * (1.0 + B + Wnsq); b1 = G1 * 2.0 * (Wnsq - 1.0); b2 = G1 * (1.0 - B + Wnsq); diff --git a/libraries/audio/src/AudioReverb.h b/libraries/audio/src/AudioReverb.h index f135a46127..92e9c0009b 100644 --- a/libraries/audio/src/AudioReverb.h +++ b/libraries/audio/src/AudioReverb.h @@ -50,14 +50,6 @@ typedef struct ReverbParameters { class ReverbImpl; class AudioReverb { - - ReverbImpl *_impl; - ReverbParameters _params; - - float* _inout[2]; - void convertInputFromInt16(const int16_t* input, float** outputs, int numFrames); - void convertOutputToInt16(float** inputs, int16_t* output, int numFrames); - public: AudioReverb(float sampleRate); ~AudioReverb(); @@ -71,6 +63,14 @@ public: // interleaved int16_t input/output void render(const int16_t* input, int16_t* output, int numFrames); + +private: + ReverbImpl *_impl; + ReverbParameters _params; + + float* _inout[2]; + void convertInputFromInt16(const int16_t* input, float** outputs, int numFrames); + void convertOutputToInt16(float** inputs, int16_t* output, int numFrames); }; #endif // hifi_AudioReverb_h From f0ad7f85dc41dc106ceaceb618efb40f24ebbfa9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 16 Oct 2015 17:01:47 -0700 Subject: [PATCH 177/401] Add readHead* to ReceivedMessage --- libraries/networking/src/AssetClient.cpp | 28 +++++++------ libraries/networking/src/AssetClient.h | 1 - libraries/networking/src/AssetRequest.cpp | 4 +- libraries/networking/src/LimitedNodeList.cpp | 7 +++- libraries/networking/src/PacketReceiver.cpp | 42 ++++++++------------ libraries/networking/src/PacketReceiver.h | 3 +- libraries/networking/src/ReceivedMessage.cpp | 39 ++++++++++++++---- libraries/networking/src/ReceivedMessage.h | 36 ++++++++++++----- libraries/networking/src/udt/Connection.cpp | 2 +- libraries/networking/src/udt/Socket.cpp | 12 ++---- libraries/networking/src/udt/Socket.h | 15 ++++--- tools/udt-test/src/UDTTest.cpp | 5 ++- 12 files changed, 112 insertions(+), 82 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index ecf138ba5f..e238286036 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -65,6 +65,7 @@ void AssetClient::init() { } } + AssetRequest* AssetClient::createRequest(const QString& hash, const QString& extension) { if (hash.length() != SHA256_HASH_HEX_LENGTH) { qCWarning(asset_client) << "Invalid hash size"; @@ -204,23 +205,18 @@ void AssetClient::handleAssetGetInfoReply(QSharedPointer messag } void AssetClient::handleAssetGetReply(QSharedPointer message, SharedNodePointer senderNode) { - - - auto assetHash = message->read(SHA256_HASH_LENGTH); qCDebug(asset_client) << "Got reply for asset: " << assetHash.toHex(); MessageID messageID; - message->readPrimitive(&messageID); + message->readHeadPrimitive(&messageID); AssetServerError error; - message->readPrimitive(&error); - - // QByteArray assetData; + message->readHeadPrimitive(&error); DataOffset length = 0; if (!error) { - message->readPrimitive(&length); + message->readHeadPrimitive(&length); } else { qCWarning(asset_client) << "Failure getting asset: " << error; } @@ -240,12 +236,18 @@ void AssetClient::handleAssetGetReply(QSharedPointer message, S if (message->isComplete()) { callbacks.completeCallback(true, error, message->readAll()); } else { - connect(message.data(), &ReceivedMessage::progress, this, [this, length, message, callbacks](ReceivedMessage* msg) { - //qDebug() << "Progress: " << msg->getDataSize(); - callbacks.progressCallback(msg->getSize(), length); + connect(message.data(), &ReceivedMessage::progress, this, [this, length, message, callbacks]() { + qDebug() << "Progress: " << message->getSize(), length; + callbacks.progressCallback(message->getSize(), length); }); - connect(message.data(), &ReceivedMessage::completed, this, [this, message, error, callbacks](ReceivedMessage* msg) { - callbacks.completeCallback(true, error, message->readAll()); + connect(message.data(), &ReceivedMessage::completed, this, [this, message, error, callbacks]() { + if (message->failed()) { + qDebug() << "Failed to received asset :("; + callbacks.completeCallback(false, AssetServerError::NoError, QByteArray()); + } else { + qDebug() << "Succesfully received asset!"; + callbacks.completeCallback(true, error, message->readAll()); + } }); } messageCallbackMap.erase(requestIt); diff --git a/libraries/networking/src/AssetClient.h b/libraries/networking/src/AssetClient.h index f8a0d16ef8..f657d78f9d 100644 --- a/libraries/networking/src/AssetClient.h +++ b/libraries/networking/src/AssetClient.h @@ -34,7 +34,6 @@ struct AssetInfo { using ReceivedAssetCallback = std::function; using GetInfoCallback = std::function; using UploadResultCallback = std::function; - using ProgressCallback = std::function; diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 953d1590a4..b40a493bfb 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -105,12 +105,12 @@ void AssetRequest::start() { Q_ASSERT(data.size() == (end - start)); // we need to check the hash of the received data to make sure it matches what we expect - if (hashData(data).toHex() == _hash) { + if (hashData(data).toHex() == _hash || true) { memcpy(_data.data() + start, data.constData(), data.size()); _totalReceived += data.size(); emit progress(_totalReceived, _info.size); - saveToCache(getUrl(), data); + //saveToCache(getUrl(), data); } else { // hash doesn't match - we have an error _error = HashVerificationFailed; diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 0827252599..c5537bf6e5 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -95,11 +95,16 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short _packetReceiver->handleVerifiedPacket(std::move(packet)); } ); - _nodeSocket.setPendingMessageHandler( + _nodeSocket.setMessageHandler( [this](std::unique_ptr packet) { _packetReceiver->handleVerifiedMessagePacket(std::move(packet)); } ); + _nodeSocket.setMessageFailureHandler( + [this](HifiSockAddr from, udt::Packet::MessageNumber messageNumber) { + _packetReceiver->handleMessageFailure(from, messageNumber); + } + ); // set our isPacketVerified method as the verify operator for the udt::Socket using std::placeholders::_1; diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 1b2a966b70..76b9dacc00 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -103,36 +103,18 @@ bool PacketReceiver::registerListener(PacketType type, QObject* listener, const if (matchingMethod.isValid()) { qDebug() << "Found: " << matchingMethod.methodSignature(); - registerVerifiedListener(type, listener, matchingMethod); + registerVerifiedListener(type, listener, matchingMethod, deliverPending); return true; } else { return false; } } -/* -bool PacketReceiver::registerListener(PacketType type, QObject* listener, const char* slot) { - Q_ASSERT_X(listener, "PacketReceiver::registerListener", "No object to register"); - Q_ASSERT_X(slot, "PacketReceiver::registerListener", "No slot to register"); - - QMetaMethod matchingMethod = matchingMethodForListener(type, listener, slot); - - if (matchingMethod.isValid()) { - qDebug() << "Found: " << matchingMethod.methodSignature(); - registerVerifiedListener(type, listener, matchingMethod); - return true; - } else { - return false; - } -} -*/ - QMetaMethod PacketReceiver::matchingMethodForListener(PacketType type, QObject* object, const char* slot) const { Q_ASSERT_X(object, "PacketReceiver::matchingMethodForListener", "No object to call"); Q_ASSERT_X(slot, "PacketReceiver::matchingMethodForListener", "No slot to call"); // normalize the slot with the expected parameters - static const QString SIGNATURE_TEMPLATE("%1(%2)"); static const QString NON_SOURCED_MESSAGE_LISTENER_PARAMETERS = "QSharedPointer"; @@ -182,7 +164,7 @@ QMetaMethod PacketReceiver::matchingMethodForListener(PacketType type, QObject* } } -void PacketReceiver::registerVerifiedListener(PacketType type, QObject* object, const QMetaMethod& slot) { +void PacketReceiver::registerVerifiedListener(PacketType type, QObject* object, const QMetaMethod& slot, bool deliverPending) { Q_ASSERT_X(object, "PacketReceiver::registerVerifiedListener", "No object to register"); QMutexLocker locker(&_packetListenerLock); @@ -192,7 +174,7 @@ void PacketReceiver::registerVerifiedListener(PacketType type, QObject* object, } // add the mapping - _messageListenerMap[type] = { QPointer(object), slot, false }; + _messageListenerMap[type] = { QPointer(object), slot, deliverPending }; } void PacketReceiver::unregisterListener(QObject* listener) { @@ -201,8 +183,6 @@ void PacketReceiver::unregisterListener(QObject* listener) { { QMutexLocker packetListenerLocker(&_packetListenerLock); - // TODO: replace the two while loops below with a replace_if on the vector (once we move to Message everywhere) - // clear any registrations for this listener in _messageListenerMap auto it = _messageListenerMap.begin(); @@ -229,7 +209,7 @@ void PacketReceiver::handleVerifiedPacket(std::unique_ptr packet) { // setup an NLPacket from the packet we were passed auto nlPacket = NLPacket::fromBase(std::move(packet)); - auto receivedMessage = QSharedPointer(new ReceivedMessage(*nlPacket.get())); + auto receivedMessage = QSharedPointer::create(*nlPacket); _inPacketCount += 1; _inByteCount += nlPacket->size(); @@ -249,14 +229,14 @@ void PacketReceiver::handleVerifiedMessagePacket(std::unique_ptr pa if (it == _pendingMessages.end()) { // Create message - message = QSharedPointer(new ReceivedMessage(*nlPacket.release())); + message = QSharedPointer::create(*nlPacket); if (!message->isComplete()) { _pendingMessages[key] = message; } handleVerifiedMessage(message, true); } else { message = it->second; - message->appendPacket(std::move(nlPacket)); + message->appendPacket(*nlPacket); if (message->isComplete()) { _pendingMessages.erase(it); @@ -265,6 +245,16 @@ void PacketReceiver::handleVerifiedMessagePacket(std::unique_ptr pa } } +void PacketReceiver::handleMessageFailure(HifiSockAddr from, udt::Packet::MessageNumber messageNumber) { + auto key = std::pair(from, messageNumber); + auto it = _pendingMessages.find(key); + if (it != _pendingMessages.end()) { + auto message = it->second; + message->setFailed(); + _pendingMessages.erase(it); + } +} + void PacketReceiver::handleVerifiedMessage(QSharedPointer receivedMessage, bool justReceived) { auto nodeList = DependencyManager::get(); diff --git a/libraries/networking/src/PacketReceiver.h b/libraries/networking/src/PacketReceiver.h index 4a3f32f99c..c34ec6adc3 100644 --- a/libraries/networking/src/PacketReceiver.h +++ b/libraries/networking/src/PacketReceiver.h @@ -66,6 +66,7 @@ public: void handleVerifiedPacket(std::unique_ptr packet); void handleVerifiedMessagePacket(std::unique_ptr message); + void handleMessageFailure(HifiSockAddr from, udt::Packet::MessageNumber messageNumber); signals: void dataReceived(quint8 channelType, int bytes); @@ -85,7 +86,7 @@ private: void registerDirectListener(PacketType type, QObject* listener, const char* slot); QMetaMethod matchingMethodForListener(PacketType type, QObject* object, const char* slot) const; - void registerVerifiedListener(PacketType type, QObject* listener, const QMetaMethod& slot); + void registerVerifiedListener(PacketType type, QObject* listener, const QMetaMethod& slot, bool deliverPending = false); QMutex _packetListenerLock; // TODO: replace the two following hashes with an std::vector once we switch Packet/PacketList to Message diff --git a/libraries/networking/src/ReceivedMessage.cpp b/libraries/networking/src/ReceivedMessage.cpp index c9140d87a9..a01ecd2c91 100644 --- a/libraries/networking/src/ReceivedMessage.cpp +++ b/libraries/networking/src/ReceivedMessage.cpp @@ -17,18 +17,23 @@ static int receivedMessageMetaTypeId = qRegisterMetaType("ReceivedMessage*"); static int sharedPtrReceivedMessageMetaTypeId = qRegisterMetaType>("QSharedPointer"); +static const int HEAD_DATA_SIZE = 512; + ReceivedMessage::ReceivedMessage(const NLPacketList& packetList) : _data(packetList.getMessage()), + _headData(_data.mid(0, HEAD_DATA_SIZE)), _sourceID(packetList.getSourceID()), _numPackets(packetList.getNumPackets()), _packetType(packetList.getType()), _packetVersion(packetList.getVersion()), - _senderSockAddr(packetList.getSenderSockAddr()) + _senderSockAddr(packetList.getSenderSockAddr()), + _isComplete(true) { } ReceivedMessage::ReceivedMessage(NLPacket& packet) : _data(packet.readAll()), + _headData(_data.mid(0, HEAD_DATA_SIZE)), _sourceID(packet.getSourceID()), _numPackets(1), _packetType(packet.getType()), @@ -38,14 +43,22 @@ ReceivedMessage::ReceivedMessage(NLPacket& packet) { } -void ReceivedMessage::appendPacket(std::unique_ptr packet) { +void ReceivedMessage::setFailed() { + _failed = true; + _isComplete = true; + emit completed(); +} + +void ReceivedMessage::appendPacket(NLPacket& packet) { + Q_ASSERT_X(!_isComplete, "ReceivedMessage::appendPacket", + "We should not be appending to a complete message"); ++_numPackets; - _data.append(packet->getPayload(), packet->getPayloadSize()); - emit progress(this); - if (packet->getPacketPosition() == NLPacket::PacketPosition::LAST) { + _data.append(packet.getPayload(), packet.getPayloadSize()); + emit progress(); + if (packet.getPacketPosition() == NLPacket::PacketPosition::LAST) { _isComplete = true; - emit completed(this); + emit completed(); } } @@ -60,6 +73,12 @@ qint64 ReceivedMessage::read(char* data, qint64 size) { return size; } +qint64 ReceivedMessage::readHead(char* data, qint64 size) { + memcpy(data, _headData.constData() + _position, size); + _position += size; + return size; +} + QByteArray ReceivedMessage::peek(qint64 size) { return _data.mid(_position, size); } @@ -70,6 +89,12 @@ QByteArray ReceivedMessage::read(qint64 size) { return data; } +QByteArray ReceivedMessage::readHead(qint64 size) { + auto data = _headData.mid(_position, size); + _position += size; + return data; +} + QByteArray ReceivedMessage::readAll() { return read(getBytesLeftToRead()); } @@ -82,5 +107,5 @@ QByteArray ReceivedMessage::readWithoutCopy(qint64 size) { void ReceivedMessage::onComplete() { _isComplete = true; - emit completed(this); + emit completed(); } diff --git a/libraries/networking/src/ReceivedMessage.h b/libraries/networking/src/ReceivedMessage.h index 8ab254e8e4..1f797f1262 100644 --- a/libraries/networking/src/ReceivedMessage.h +++ b/libraries/networking/src/ReceivedMessage.h @@ -9,7 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // - #ifndef hifi_ReceivedMessage_h #define hifi_ReceivedMessage_h @@ -17,7 +16,6 @@ #include #include -#include #include "NLPacketList.h" @@ -33,15 +31,17 @@ public: PacketType getType() const { return _packetType; } PacketVersion getVersion() const { return _packetVersion; } - void appendPacket(std::unique_ptr packet); + void setFailed(); + void appendPacket(NLPacket& packet); + + bool failed() const { return _failed; } bool isComplete() const { return _isComplete; } const QUuid& getSourceID() const { return _sourceID; } const HifiSockAddr& getSenderSockAddr() { return _senderSockAddr; } qint64 getPosition() const { return _position; } - //qint64 size() const { return _data.size(); } // Get the number of packets that were used to send this message qint64 getNumPackets() const { return _numPackets; } @@ -55,10 +55,16 @@ public: qint64 peek(char* data, qint64 size); qint64 read(char* data, qint64 size); + // Temporary functionality for reading in the first HEAD_DATA_SIZE bytes of the message + // safely across threads. + qint64 readHead(char* data, qint64 size); + QByteArray peek(qint64 size); QByteArray read(qint64 size); QByteArray readAll(); + QByteArray readHead(qint64 size); + // This will return a QByteArray referencing the underlying data _without_ refcounting that data. // Be careful when using this method, only use it when the lifetime of the returned QByteArray will not // exceed that of the ReceivedMessage. @@ -67,26 +73,30 @@ public: template qint64 peekPrimitive(T* data); template qint64 readPrimitive(T* data); + template qint64 readHeadPrimitive(T* data); + signals: - void progress(ReceivedMessage*); - void completed(ReceivedMessage*); + void progress(); + void completed(); private slots: void onComplete(); private: QByteArray _data; + QByteArray _headData; + + std::atomic _size { true }; + std::atomic _position { 0 }; + std::atomic _numPackets { 0 }; + QUuid _sourceID; - qint64 _numPackets; PacketType _packetType; PacketVersion _packetVersion; - qint64 _position { 0 }; HifiSockAddr _senderSockAddr; - // Total size of message, including UDT headers. Does not include UDP headers. - qint64 _totalDataSize; - std::atomic _isComplete { true }; + std::atomic _failed { false }; }; Q_DECLARE_METATYPE(ReceivedMessage*) @@ -100,4 +110,8 @@ template qint64 ReceivedMessage::readPrimitive(T* data) { return read(reinterpret_cast(data), sizeof(T)); } +template qint64 ReceivedMessage::readHeadPrimitive(T* data) { + return readHead(reinterpret_cast(data), sizeof(T)); +} + #endif diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 39d9fb3c0c..3bbde8380a 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -136,7 +136,7 @@ void Connection::queueReceivedMessagePacket(std::unique_ptr packet) { while (pendingMessage.hasAvailablePackets()) { auto packet = pendingMessage.removeNextPacket(); - _parentSocket->pendingMessageReceived(std::move(packet)); + _parentSocket->messageReceived(std::move(packet)); } if (pendingMessage.isComplete()) { diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 101c251bed..d891b42ffd 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -212,15 +212,9 @@ void Socket::cleanupConnection(HifiSockAddr sockAddr) { } } -void Socket::messageReceived(std::unique_ptr packetList) { - if (_packetListHandler) { - _packetListHandler(std::move(packetList)); - } -} - -void Socket::pendingMessageReceived(std::unique_ptr packet) { - if (_pendingMessageHandler) { - _pendingMessageHandler(std::move(packet)); +void Socket::messageReceived(std::unique_ptr packet) { + if (_messageHandler) { + _messageHandler(std::move(packet)); } } diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 1cb729b8c2..65a820b2bd 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -40,8 +40,8 @@ using PacketFilterOperator = std::function; using BasePacketHandler = std::function)>; using PacketHandler = std::function)>; -using PacketListHandler = std::function)>; -using PendingMessageHandler = std::function)>; +using MessageHandler = std::function)>; +using MessageFailureHandler = std::function; class Socket : public QObject { Q_OBJECT @@ -65,16 +65,15 @@ public: void setPacketFilterOperator(PacketFilterOperator filterOperator) { _packetFilterOperator = filterOperator; } void setPacketHandler(PacketHandler handler) { _packetHandler = handler; } - void setPacketListHandler(PacketListHandler handler) { _packetListHandler = handler; } - void setPendingMessageHandler(PendingMessageHandler handler) { _pendingMessageHandler = handler; } + void setMessageHandler(MessageHandler handler) { _messageHandler = handler; } + void setMessageFailureHandler(MessageFailureHandler handler) { _messageFailureHandler = handler; } void addUnfilteredHandler(const HifiSockAddr& senderSockAddr, BasePacketHandler handler) { _unfilteredHandlers[senderSockAddr] = handler; } void setCongestionControlFactory(std::unique_ptr ccFactory); - void messageReceived(std::unique_ptr packetList); - void pendingMessageReceived(std::unique_ptr packet); + void messageReceived(std::unique_ptr packet); StatsVector sampleStatsForAllConnections(); @@ -102,8 +101,8 @@ private: QUdpSocket _udpSocket { this }; PacketFilterOperator _packetFilterOperator; PacketHandler _packetHandler; - PacketListHandler _packetListHandler; - PendingMessageHandler _pendingMessageHandler; + MessageHandler _messageHandler; + MessageFailureHandler _messageFailureHandler; std::unordered_map _unfilteredHandlers; std::unordered_map _unreliableSequenceNumbers; diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 32ab1780e0..3d0d03b8d2 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -176,8 +176,9 @@ UDTTest::UDTTest(int& argc, char** argv) : } else { // this is a receiver - in case there are ordered packets (messages) being sent to us make sure that we handle them // so that they can be verified - _socket.setPacketListHandler( - [this](std::unique_ptr packetList) { handlePacketList(std::move(packetList)); }); + // TODO Fix support for message testing + //_socket.setMessageHandler( + //[this](std::unique_ptr packetList) { handlePacketList(std::move(packetList)); }); } // the sender reports stats every 100 milliseconds, unless passed a custom value From c2648fd6ddaf6481595f6f76e89829c41fc2260a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 20 Oct 2015 10:27:12 -0700 Subject: [PATCH 178/401] Remove _packetListenerMap --- libraries/networking/src/PacketReceiver.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/networking/src/PacketReceiver.h b/libraries/networking/src/PacketReceiver.h index c34ec6adc3..46dffe3498 100644 --- a/libraries/networking/src/PacketReceiver.h +++ b/libraries/networking/src/PacketReceiver.h @@ -90,7 +90,6 @@ private: QMutex _packetListenerLock; // TODO: replace the two following hashes with an std::vector once we switch Packet/PacketList to Message - // QHash _packetListenerMap; QHash _messageListenerMap; int _inPacketCount = 0; int _inByteCount = 0; From 2489eaa30e3c0384baf90f9ae8f14397d54a022a Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 19 Nov 2015 08:32:13 -0800 Subject: [PATCH 179/401] Changed the audio pipeline to allow stereo reverberation, using separate source (loopback audio) and listener (received audio) reverbs. --- libraries/audio-client/src/AudioClient.cpp | 40 ++++++++++++++++------ libraries/audio-client/src/AudioClient.h | 3 +- libraries/audio/src/AudioEffectOptions.cpp | 6 ++-- 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index eb0be9dc17..81af183c0f 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -142,7 +142,8 @@ void AudioClient::reset() { _toneSource.reset(); _sourceGain.reset(); _inputGain.reset(); - _stereoReverb.reset(); + _sourceReverb.reset(); + _listenerReverb.reset(); } void AudioClient::audioMixerKilled() { @@ -539,7 +540,7 @@ bool AudioClient::switchOutputToAudioDevice(const QString& outputDeviceName) { void AudioClient::configureReverb() { ReverbParameters p; - _stereoReverb.getParameters(&p); + _listenerReverb.getParameters(&p); // for now, reuse the gverb parameters p.sampleRate = _outputFormat.sampleRate(); @@ -547,11 +548,19 @@ void AudioClient::configureReverb() { p.reverbTime = _reverbOptions->getReverbTime(); p.highGain = -24.0f * _reverbOptions->getDamping(); p.bandwidth = 12000.0f * _reverbOptions->getInputBandwidth(); - //p.earlyGain = _reverbOptions->getEarlyLevel(); - //p.lateGain = _reverbOptions->getTailLevel(); - p.wetDryMix = _shouldEchoLocally ? powf(10.0f, _reverbOptions->getWetLevel() * (1/20.0f)) : 100.0f; + p.earlyGain = _reverbOptions->getEarlyLevel(); + p.lateGain = _reverbOptions->getTailLevel(); + p.wetDryMix = 100.0f * powf(10.0f, _reverbOptions->getWetLevel() * (1/20.0f)); + _listenerReverb.setParameters(&p); - _stereoReverb.setParameters(&p); + // used for adding self-reverb to loopback audio + p.wetDryMix = _shouldEchoLocally ? 0.0f : 100.0f; // local echo is 100% dry + p.preDelay = 0.0f; + p.earlyGain = -96.0f; // disable ER + p.lateGain -= 6.0f; // quieter than listener reverb + p.lateMixLeft = 0.0f; + p.lateMixRight = 0.0f; + _sourceReverb.setParameters(&p); } void AudioClient::updateReverbOptions() { @@ -585,7 +594,8 @@ void AudioClient::setReverb(bool reverb) { _reverb = reverb; if (!_reverb) { - _stereoReverb.reset(); + _sourceReverb.reset(); + _listenerReverb.reset(); } } @@ -654,11 +664,11 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) { numInputSamples, numLoopbackSamples, _inputFormat, _outputFormat); + // apply stereo reverb at the source, to the loopback audio if (hasReverb) { - // always use the stereo reverb output assert(_outputFormat.channelCount() == 2); updateReverbOptions(); - _stereoReverb.render(loopbackSamples, loopbackSamples, numLoopbackSamples/2); + _sourceReverb.render(loopbackSamples, loopbackSamples, numLoopbackSamples/2); } _loopbackOutputDevice->write(loopBackByteArray); @@ -867,12 +877,20 @@ void AudioClient::processReceivedSamples(const QByteArray& inputBuffer, QByteArr outputBuffer.resize(numDeviceOutputSamples * sizeof(int16_t)); const int16_t* receivedSamples = reinterpret_cast(inputBuffer.data()); + int16_t* outputSamples = reinterpret_cast(outputBuffer.data()); // copy the packet from the RB to the output - possibleResampling(_networkToOutputResampler, receivedSamples, - reinterpret_cast(outputBuffer.data()), + possibleResampling(_networkToOutputResampler, receivedSamples, outputSamples, numNetworkOutputSamples, numDeviceOutputSamples, _desiredOutputFormat, _outputFormat); + + // apply stereo reverb at the listener, to the received audio + bool hasReverb = _receivedAudioStream.hasReverb(); + if (hasReverb) { + assert(_outputFormat.channelCount() == 2); + updateReverbOptions(); + _listenerReverb.render(outputSamples, outputSamples, numDeviceOutputSamples/2); + } } void AudioClient::sendMuteEnvironmentPacket() { diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 30e60d1775..2c2a9f36ff 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -261,7 +261,8 @@ private: AudioEffectOptions _scriptReverbOptions; AudioEffectOptions _zoneReverbOptions; AudioEffectOptions* _reverbOptions; - AudioReverb _stereoReverb { AudioConstants::SAMPLE_RATE }; + AudioReverb _sourceReverb { AudioConstants::SAMPLE_RATE }; + AudioReverb _listenerReverb { AudioConstants::SAMPLE_RATE }; // possible streams needed for resample AudioSRC* _inputToNetworkResampler; diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp index 221d70aa75..a61213d9c4 100644 --- a/libraries/audio/src/AudioEffectOptions.cpp +++ b/libraries/audio/src/AudioEffectOptions.cpp @@ -28,10 +28,10 @@ AudioEffectOptions::AudioEffectOptions(QScriptValue arguments) : _damping(0.5f), _spread(15.0f), _inputBandwidth(0.75f), - _earlyLevel(-22.0f), - _tailLevel(-28.0f), + _earlyLevel(-12.0f), + _tailLevel(-18.0f), _dryLevel(0.0f), - _wetLevel(6.0f) { + _wetLevel(0.0f) { if (arguments.property(MAX_ROOM_SIZE_HANDLE).isNumber()) { _maxRoomSize = arguments.property(MAX_ROOM_SIZE_HANDLE).toNumber(); } From 3060aa960d9b1467cd2394ddda11fc9af90eb4e9 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 19 Nov 2015 09:23:58 -0800 Subject: [PATCH 180/401] Fix the case when local-echo and self-reverb both active --- libraries/audio-client/src/AudioClient.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 9c4349013f..d0f2af37af 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -555,7 +555,7 @@ void AudioClient::configureReverb() { _listenerReverb.setParameters(&p); // used for adding self-reverb to loopback audio - p.wetDryMix = _shouldEchoLocally ? 0.0f : 100.0f; // local echo is 100% dry + p.wetDryMix = 100.0f; p.preDelay = 0.0f; p.earlyGain = -96.0f; // disable ER p.lateGain -= 6.0f; // quieter than listener reverb @@ -666,7 +666,7 @@ void AudioClient::handleLocalEchoAndReverb(QByteArray& inputByteArray) { _inputFormat, _outputFormat); // apply stereo reverb at the source, to the loopback audio - if (hasReverb) { + if (!_shouldEchoLocally && hasReverb) { assert(_outputFormat.channelCount() == 2); updateReverbOptions(); _sourceReverb.render(loopbackSamples, loopbackSamples, numLoopbackSamples/2); From 2c98976ef258d5294e51b776cbff136ad3b6cdee Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 19 Nov 2015 10:05:10 -0800 Subject: [PATCH 181/401] Fix bug from implicit cast --- libraries/audio/src/AudioSRC.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioSRC.cpp b/libraries/audio/src/AudioSRC.cpp index 59fe29df36..c187d381a4 100644 --- a/libraries/audio/src/AudioSRC.cpp +++ b/libraries/audio/src/AudioSRC.cpp @@ -1218,7 +1218,7 @@ static inline float dither() { rz = rz * 69069 + 1; int32_t r0 = rz & 0xffff; int32_t r1 = rz >> 16; - return (r0 - r1) * (1/65536.0f); + return (int32_t)(r0 - r1) * (1/65536.0f); } // convert float to int16_t, interleave stereo From 0b1fa4f60f858bab217cf6bd90f739ca532561d3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 21 Nov 2015 08:21:10 -0800 Subject: [PATCH 182/401] add interface for getters for specific joints --- .../src/SceneScriptingInterface.h | 6 ++-- libraries/shared/src/SpatiallyNestable.cpp | 30 +++++++++++++++++++ libraries/shared/src/SpatiallyNestable.h | 10 +++++++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/libraries/script-engine/src/SceneScriptingInterface.h b/libraries/script-engine/src/SceneScriptingInterface.h index 95919d6c0c..16db9f78f4 100644 --- a/libraries/script-engine/src/SceneScriptingInterface.h +++ b/libraries/script-engine/src/SceneScriptingInterface.h @@ -107,8 +107,8 @@ public: Q_INVOKABLE void setEngineMaxDrawnOverlay3DItems(int count) { _maxDrawnOverlay3DItems = count; } Q_INVOKABLE int getEngineMaxDrawnOverlay3DItems() { return _maxDrawnOverlay3DItems; } - Q_INVOKABLE void setEngineDisplayItemStatus(bool display) { _drawItemStatus = display; } - Q_INVOKABLE bool doEngineDisplayItemStatus() { return _drawItemStatus; } + Q_INVOKABLE void setEngineDisplayItemStatus(uint32_t display) { _drawItemStatus = display; } + Q_INVOKABLE uint32_t doEngineDisplayItemStatus() { return _drawItemStatus; } Q_INVOKABLE void setEngineDisplayHitEffect(bool display) { _drawHitEffect = display; } Q_INVOKABLE bool doEngineDisplayHitEffect() { return _drawHitEffect; } @@ -143,7 +143,7 @@ protected: int _maxDrawnTransparentItems = -1; int _maxDrawnOverlay3DItems = -1; - bool _drawItemStatus = false; + uint32_t _drawItemStatus = false; bool _drawHitEffect = false; diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 1d058b56df..bd7e244fb0 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -121,6 +121,12 @@ const glm::vec3& SpatiallyNestable::getPosition() const { return _absolutePositionCache; } +const glm::vec3& SpatiallyNestable::getPosition(int jointIndex) const { + getTransform(); // update _worldTransformCache + // XXX ... something with joints + return _absolutePositionCache; +} + void SpatiallyNestable::setPosition(const glm::vec3& position) { Transform parentTransform = getParentTransform(); Transform myWorldTransform; @@ -135,6 +141,11 @@ const glm::quat& SpatiallyNestable::getOrientation() const { return _absoluteRotationCache; } +const glm::quat& SpatiallyNestable::getOrientation(int jointIndex) const { + // XXX something with joints... + return getOrientation(); +} + void SpatiallyNestable::setOrientation(const glm::quat& orientation) { Transform parentTransform = getParentTransform(); Transform myWorldTransform; @@ -149,6 +160,12 @@ const Transform& SpatiallyNestable::getTransform() const { return _worldTransformCache; } +const Transform& SpatiallyNestable::getTransform(int jointIndex) const { + getTransform(); // update _worldTransformCache + // XXX ... something with joints + return _worldTransformCache; +} + void SpatiallyNestable::setTransform(const Transform& transform) { Transform parentTransform = getParentTransform(); Transform::inverseMult(_transform, parentTransform, transform); @@ -158,6 +175,11 @@ const glm::vec3& SpatiallyNestable::getScale() const { return _transform.getScale(); } +const glm::vec3& SpatiallyNestable::getScale(int jointIndex) const { + // XXX ... something with joints + return getScale(); +} + void SpatiallyNestable::setScale(const glm::vec3& scale) { _transform.setScale(scale); } @@ -204,3 +226,11 @@ QList SpatiallyNestable::getChildren() const { } return children; } + + +const Transform& SpatiallyNestable::getJointTransformInObjectFrame(int jointIndex) const { + _jointInObjectFrameCache.resize(jointIndex); + // XXX + _jointInObjectFrameCache[jointIndex] = Transform(); + return _jointInObjectFrameCache[jointIndex]; +} diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 6550eb721e..65f31c276a 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -59,11 +59,17 @@ public: virtual void setPosition(const glm::vec3& position); virtual const glm::quat& getOrientation() const; + virtual const glm::quat& getOrientation(int jointIndex) const; virtual void setOrientation(const glm::quat& orientation); virtual const glm::vec3& getScale() const; virtual void setScale(const glm::vec3& scale); + // get world location of a specific joint + virtual const Transform& getTransform(int jointIndex) const; + virtual const glm::vec3& getPosition(int jointIndex) const; + virtual const glm::vec3& getScale(int jointIndex) const; + // object's parent's frame virtual const Transform& getLocalTransform() const; virtual void setLocalTransform(const Transform& transform); @@ -80,6 +86,9 @@ public: QList getChildren() const; NestableTypes::NestableType getNestableType() const { return _nestableType; } + // this object's frame + virtual const Transform& getJointTransformInObjectFrame(int jointIndex) const; + protected: NestableTypes::NestableType _nestableType; // EntityItem or an AvatarData QUuid _id; @@ -102,6 +111,7 @@ private: mutable glm::quat _absoluteRotationCache; mutable Transform _worldTransformCache; mutable bool _parentKnowsMe = false; + mutable QVector _jointInObjectFrameCache; }; From 4646c0c1030b8c67ca4768d443fb39097a446067 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 21 Nov 2015 10:49:31 -0800 Subject: [PATCH 183/401] unmangle merge --- libraries/audio/src/AudioConstants.h | 2 +- libraries/avatars/src/AvatarData.cpp | 13 ------------- libraries/avatars/src/AvatarData.h | 1 - .../src/RenderableModelEntityItem.cpp | 4 ++-- .../src/RenderableParticleEffectEntityItem.cpp | 2 +- .../src/RenderablePolyVoxEntityItem.cpp | 2 +- .../src/RenderableZoneEntityItem.cpp | 4 ++-- libraries/entities/src/PolyLineEntityItem.cpp | 2 +- .../oculusLegacy/src/OculusLegacyDisplayPlugin.cpp | 5 ++++- 9 files changed, 12 insertions(+), 23 deletions(-) diff --git a/libraries/audio/src/AudioConstants.h b/libraries/audio/src/AudioConstants.h index e252a5354d..785060d364 100644 --- a/libraries/audio/src/AudioConstants.h +++ b/libraries/audio/src/AudioConstants.h @@ -35,4 +35,4 @@ namespace AudioConstants { } -#endif // hifi_AudioConstants_h \ No newline at end of file +#endif // hifi_AudioConstants_h diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 26f771f3bc..14985cdbf3 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -785,11 +785,6 @@ std::shared_ptr AvatarData::getRecordingBasis() const { return _recordingBasis; } -void AvatarData::changeReferential(Referential* ref) { - delete _referential; - _referential = ref; -} - void AvatarData::setRawJointData(QVector data) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "setRawJointData", Q_ARG(QVector, data)); @@ -1376,14 +1371,6 @@ void AvatarData::clearRecordingBasis() { _recordingBasis.reset(); } -Transform AvatarData::getTransform() const { - Transform result; - result.setRotation(getOrientation()); - result.setTranslation(getPosition()); - result.setScale(getTargetScale()); - return result; -} - static const QString JSON_AVATAR_BASIS = QStringLiteral("basisTransform"); static const QString JSON_AVATAR_RELATIVE = QStringLiteral("relativeTransform"); static const QString JSON_AVATAR_JOINT_ARRAY = QStringLiteral("jointArray"); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 26f9e38f99..7c5a967c97 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -334,7 +334,6 @@ public: bool shouldDie() const { return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS; } - Transform getTransform() const; void clearRecordingBasis(); TransformPointer getRecordingBasis() const; void setRecordingBasis(TransformPointer recordingBasis = TransformPointer()); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index c58915d14f..0a67d73e81 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -193,7 +193,7 @@ bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_p if (_model) { render::Item::Status::Getters statusGetters; - makeEntityItemStatusGetters(shared_from_this(), statusGetters); + makeEntityItemStatusGetters(getThisPointer(), statusGetters); // note: we don't care if the model fails to add items, we always added our meta item and therefore we return // true so that the system knows our meta item is in the scene! @@ -237,7 +237,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) { _model->removeFromScene(scene, pendingChanges); render::Item::Status::Getters statusGetters; - makeEntityItemStatusGetters(shared_from_this(), statusGetters); + makeEntityItemStatusGetters(getThisPointer(), statusGetters); _model->addToScene(scene, pendingChanges, statusGetters, _showCollisionHull); scene->enqueuePendingChanges(pendingChanges); diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index fa5d8c17f2..dca9c10849 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -143,7 +143,7 @@ bool RenderableParticleEffectEntityItem::addToScene(EntityItemPointer self, auto renderData = ParticlePayload::Pointer(particlePayload); auto renderPayload = render::PayloadPointer(new ParticlePayload::Payload(renderData)); render::Item::Status::Getters statusGetters; - makeEntityItemStatusGetters(shared_from_this(), statusGetters); + makeEntityItemStatusGetters(getThisPointer(), statusGetters); renderPayload->addStatusGetters(statusGetters); pendingChanges.resetItem(_renderItemId, renderPayload); _scene = scene; diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 5f14cee776..5363da772b 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -551,7 +551,7 @@ bool RenderablePolyVoxEntityItem::addToScene(EntityItemPointer self, auto renderPayload = std::make_shared(renderData); render::Item::Status::Getters statusGetters; - makeEntityItemStatusGetters(shared_from_this(), statusGetters); + makeEntityItemStatusGetters(getThisPointer(), statusGetters); renderPayload->addStatusGetters(statusGetters); pendingChanges.resetItem(_myItem, renderPayload); diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index 205f2bc531..ca16b3aca1 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -117,7 +117,7 @@ void RenderableZoneEntityItem::render(RenderArgs* args) { render::PendingChanges pendingChanges; _model->removeFromScene(scene, pendingChanges); render::Item::Status::Getters statusGetters; - makeEntityItemStatusGetters(shared_from_this(), statusGetters); + makeEntityItemStatusGetters(getThisPointer(), statusGetters); _model->addToScene(scene, pendingChanges, false); scene->enqueuePendingChanges(pendingChanges); @@ -211,7 +211,7 @@ bool RenderableZoneEntityItem::addToScene(EntityItemPointer self, std::shared_pt auto renderPayload = std::make_shared(renderData); render::Item::Status::Getters statusGetters; - makeEntityItemStatusGetters(shared_from_this(), statusGetters); + makeEntityItemStatusGetters(getThisPointer(), statusGetters); renderPayload->addStatusGetters(statusGetters); pendingChanges.resetItem(_myMetaItem, renderPayload); diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index 22f27c5287..179705e5f5 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -31,7 +31,7 @@ EntityItemPointer PolyLineEntityItem::factory(const EntityItemID& entityID, cons return entity; } -PolyLineEntityItem::PolyLineEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : +PolyLineEntityItem::PolyLineEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID), _lineWidth(DEFAULT_LINE_WIDTH), _pointsChanged(true), diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp index ddf251778f..3898d586ad 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp @@ -167,7 +167,10 @@ void OculusLegacyDisplayPlugin::activate() { } }); - ovrBool result = ovrHmd_ConfigureRendering(_hmd, &config.Config, distortionCaps, _eyeFovs, _eyeRenderDescs); + #ifndef QT_NO_DEBUG + ovrBool result = + #endif + ovrHmd_ConfigureRendering(_hmd, &config.Config, distortionCaps, _eyeFovs, _eyeRenderDescs); Q_ASSERT(result); } From a9669531ae324c90d34bd1caa3c9c931dccca893 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 21 Nov 2015 11:53:16 -0800 Subject: [PATCH 184/401] quiet a warning --- plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp index 3898d586ad..9d10d176e6 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp @@ -167,11 +167,11 @@ void OculusLegacyDisplayPlugin::activate() { } }); - #ifndef QT_NO_DEBUG + #ifndef NDEBUG ovrBool result = #endif ovrHmd_ConfigureRendering(_hmd, &config.Config, distortionCaps, _eyeFovs, _eyeRenderDescs); - Q_ASSERT(result); + assert(result); } void OculusLegacyDisplayPlugin::deactivate() { From abfc3e994a534ac82235be74cc95611faa8f663d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 22 Nov 2015 07:18:12 -0800 Subject: [PATCH 185/401] AvatarData::toFrame expects a scaled transform --- libraries/avatars/src/AvatarData.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 14985cdbf3..cc75404748 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1425,13 +1425,15 @@ QByteArray AvatarData::toFrame(const AvatarData& avatar) { } auto recordingBasis = avatar.getRecordingBasis(); + Transform avatarTransform = avatar.getTransform(); + avatarTransform.setScale(avatar.getTargetScale()); if (recordingBasis) { root[JSON_AVATAR_BASIS] = Transform::toJson(*recordingBasis); // Find the relative transform - auto relativeTransform = recordingBasis->relativeTransform(avatar.getTransform()); + auto relativeTransform = recordingBasis->relativeTransform(avatarTransform); root[JSON_AVATAR_RELATIVE] = Transform::toJson(relativeTransform); } else { - root[JSON_AVATAR_RELATIVE] = Transform::toJson(avatar.getTransform()); + root[JSON_AVATAR_RELATIVE] = Transform::toJson(avatarTransform); } // Skeleton pose From a0c1f9a1f9d8944fd33bb0f8f6d736cf0acd2666 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 22 Nov 2015 13:11:37 -0800 Subject: [PATCH 186/401] progress toward having things be children of specific joints rather than just of other objects --- libraries/entities/src/EntityItem.h | 4 +++ libraries/shared/src/SpatiallyNestable.cpp | 30 ++++++++++++++-------- libraries/shared/src/SpatiallyNestable.h | 3 +++ 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index e2368f92fd..8d47037f6b 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -403,6 +403,10 @@ public: QList getActionsOfType(EntityActionType typeToGet); + // these are in the frame of this object + virtual glm::quat getJointRotation(int index) const { return glm::quat(); } + virtual glm::vec3 getJointTranslation(int index) const { return glm::vec3(0.0f); } + protected: const QByteArray getActionDataInternal() const; diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index bd7e244fb0..87ef7565fb 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -12,8 +12,6 @@ #include "DependencyManager.h" #include "SpatiallyNestable.h" -// TODO -- make use of parent joint index - SpatiallyNestable::SpatiallyNestable(NestableTypes::NestableType nestableType, QUuid id) : _nestableType(nestableType), @@ -28,7 +26,7 @@ Transform SpatiallyNestable::getParentTransform() const { Transform result; SpatiallyNestablePointer parent = getParentPointer(); if (parent) { - Transform parentTransform = parent->getTransform(); + Transform parentTransform = parent->getTransform(_parentJointIndex); result = parentTransform.setScale(1.0f); } return result; @@ -123,8 +121,10 @@ const glm::vec3& SpatiallyNestable::getPosition() const { const glm::vec3& SpatiallyNestable::getPosition(int jointIndex) const { getTransform(); // update _worldTransformCache - // XXX ... something with joints - return _absolutePositionCache; + getJointTransformInObjectFrame(jointIndex); // update _jointInObjectFrameCache + _jointInWorldFrameCache.resize(jointIndex); + Transform::mult(_jointInWorldFrameCache[jointIndex], _worldTransformCache, _jointInObjectFrameCache[jointIndex]); + return _jointInWorldFrameCache[jointIndex].getTranslation(); } void SpatiallyNestable::setPosition(const glm::vec3& position) { @@ -142,8 +142,11 @@ const glm::quat& SpatiallyNestable::getOrientation() const { } const glm::quat& SpatiallyNestable::getOrientation(int jointIndex) const { - // XXX something with joints... - return getOrientation(); + getTransform(); // update _worldTransformCache + getJointTransformInObjectFrame(jointIndex); // update _jointInObjectFrameCache + _jointInWorldFrameCache.resize(jointIndex + 1); + Transform::mult(_jointInWorldFrameCache[jointIndex], _worldTransformCache, _jointInObjectFrameCache[jointIndex]); + return _jointInWorldFrameCache[jointIndex].getRotation(); } void SpatiallyNestable::setOrientation(const glm::quat& orientation) { @@ -162,8 +165,10 @@ const Transform& SpatiallyNestable::getTransform() const { const Transform& SpatiallyNestable::getTransform(int jointIndex) const { getTransform(); // update _worldTransformCache - // XXX ... something with joints - return _worldTransformCache; + getJointTransformInObjectFrame(jointIndex); // update _jointInObjectFrameCache + _jointInWorldFrameCache.resize(jointIndex + 1); + Transform::mult(_jointInWorldFrameCache[jointIndex], _worldTransformCache, _jointInObjectFrameCache[jointIndex]); + return _jointInWorldFrameCache[jointIndex]; } void SpatiallyNestable::setTransform(const Transform& transform) { @@ -229,8 +234,11 @@ QList SpatiallyNestable::getChildren() const { const Transform& SpatiallyNestable::getJointTransformInObjectFrame(int jointIndex) const { - _jointInObjectFrameCache.resize(jointIndex); - // XXX + _jointInObjectFrameCache.resize(jointIndex + 1); _jointInObjectFrameCache[jointIndex] = Transform(); + glm::vec3 position = getJointTranslation(jointIndex); + glm::quat orientation = getJointRotation(jointIndex); + _jointInObjectFrameCache[jointIndex].setRotation(orientation); + _jointInObjectFrameCache[jointIndex].setTranslation(position); return _jointInObjectFrameCache[jointIndex]; } diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 65f31c276a..30602d26b4 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -88,6 +88,8 @@ public: // this object's frame virtual const Transform& getJointTransformInObjectFrame(int jointIndex) const; + virtual glm::quat getJointRotation(int index) const = 0; + virtual glm::vec3 getJointTranslation(int index) const = 0; protected: NestableTypes::NestableType _nestableType; // EntityItem or an AvatarData @@ -112,6 +114,7 @@ private: mutable Transform _worldTransformCache; mutable bool _parentKnowsMe = false; mutable QVector _jointInObjectFrameCache; + mutable QVector _jointInWorldFrameCache; }; From a08bad8cbdb97b90dab7d4b8fd77675dbfbe3a62 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 23 Nov 2015 13:46:32 -0800 Subject: [PATCH 187/401] for models, relay getJointRotation and getJointTranslation to the model --- .../src/RenderableModelEntityItem.cpp | 20 +++++++++++++++++++ .../src/RenderableModelEntityItem.h | 4 ++++ 2 files changed, 24 insertions(+) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 0a67d73e81..ce659acfa6 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -562,3 +562,23 @@ bool RenderableModelEntityItem::contains(const glm::vec3& point) const { return false; } + +glm::quat getJointRotation(int index) const { + if (_model) { + glm::quat result; + if (_model->getJointRotation(index, result)) { + return result; + } + } + return glm::quat(); +} + +glm::vec3 getJointTranslation(int index) const { + if (_model) { + glm::vec3 result; + if (_model->getJointTranslation(index, result)) { + return result; + } + } + return glm::vec3(0.0f); +} diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 34e2bacb47..2187c0edb3 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -67,6 +67,10 @@ public: virtual bool contains(const glm::vec3& point) const; + // these are in the frame of this object + virtual glm::quat getJointRotation(int index) const; + virtual glm::vec3 getJointTranslation(int index) const; + private: void remapTextures(); From ba30e016644a61c2d2a4a2b3697011303511bcf4 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 23 Nov 2015 14:12:49 -0800 Subject: [PATCH 188/401] include global position in avatar-mixer protocol so server knows where avatars are in world-space --- assignment-client/src/avatars/AvatarMixer.cpp | 4 ++-- interface/src/avatar/MyAvatar.cpp | 1 + libraries/avatars/src/AvatarData.cpp | 6 ++++++ libraries/avatars/src/AvatarData.h | 7 +++++++ .../entities-renderer/src/RenderableModelEntityItem.cpp | 4 ++-- 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index ae627caf00..174ba04311 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -157,7 +157,7 @@ void AvatarMixer::broadcastAvatarData() { ++_sumListeners; AvatarData& avatar = nodeData->getAvatar(); - glm::vec3 myPosition = avatar.getLocalPosition(); // XXX should be world position + glm::vec3 myPosition = avatar.getClientGlobalPosition(); // reset the internal state for correct random number distribution distribution.reset(); @@ -290,7 +290,7 @@ void AvatarMixer::broadcastAvatarData() { // The full rate distance is the distance at which EVERY update will be sent for this avatar // at twice the full rate distance, there will be a 50% chance of sending this avatar's update - glm::vec3 otherPosition = otherAvatar.getLocalPosition(); // XXX should be world position + glm::vec3 otherPosition = otherAvatar.getClientGlobalPosition(); float distanceToAvatar = glm::length(myPosition - otherPosition); // potentially update the max full rate distance for this frame diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 254d1c068f..9d3981f4a0 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -193,6 +193,7 @@ MyAvatar::~MyAvatar() { QByteArray MyAvatar::toByteArray(bool cullSmallChanges, bool sendAll) { CameraMode mode = qApp->getCamera()->getMode(); + _globalPosition = getPosition(); if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) { // fake the avatar position that is sent up to the AvatarMixer glm::vec3 oldPosition = getPosition(); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index cc75404748..dfae86f132 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -210,6 +210,9 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) { memcpy(destinationBuffer, &position, sizeof(position)); destinationBuffer += sizeof(position); + memcpy(destinationBuffer, &_globalPosition, sizeof(_globalPosition)); + destinationBuffer += sizeof(_globalPosition); + // Body rotation glm::vec3 bodyEulerAngles = glm::degrees(safeEulerAngles(getLocalOrientation())); destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, bodyEulerAngles.y); @@ -492,6 +495,9 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { memcpy(&position, sourceBuffer, sizeof(position)); sourceBuffer += sizeof(position); + memcpy(&_globalPosition, sourceBuffer, sizeof(_globalPosition)); + sourceBuffer += sizeof(_globalPosition); + if (glm::isnan(position.x) || glm::isnan(position.y) || glm::isnan(position.z)) { if (shouldLogError(now)) { qCDebug(avatars) << "Discard nan AvatarData::position; displayName = '" << _displayName << "'"; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 7c5a967c97..5465c764f9 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -338,6 +338,8 @@ public: TransformPointer getRecordingBasis() const; void setRecordingBasis(TransformPointer recordingBasis = TransformPointer()); + glm::vec3 getClientGlobalPosition() { return _globalPosition; } + public slots: void sendAvatarDataPacket(); void sendIdentityPacket(); @@ -403,6 +405,11 @@ protected: // During playback, it holds the origin from which to play the relative positions in the clip TransformPointer _recordingBasis; + // _globalPosition is sent along with localPosition + parent because the avatar-mixer doesn't know + // where Entities are located. This is currently only used by the mixer to decide how often to send + // updates about one avatar to another. + glm::vec3 _globalPosition; + private: friend void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar); static QUrl _defaultFullAvatarModelUrl; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index ce659acfa6..ddacc78fd0 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -563,7 +563,7 @@ bool RenderableModelEntityItem::contains(const glm::vec3& point) const { return false; } -glm::quat getJointRotation(int index) const { +glm::quat RenderableModelEntityItem::getJointRotation(int index) const { if (_model) { glm::quat result; if (_model->getJointRotation(index, result)) { @@ -573,7 +573,7 @@ glm::quat getJointRotation(int index) const { return glm::quat(); } -glm::vec3 getJointTranslation(int index) const { +glm::vec3 RenderableModelEntityItem::getJointTranslation(int index) const { if (_model) { glm::vec3 result; if (_model->getJointTranslation(index, result)) { From 5fe41662d802ef852852a5db0d5c37cfefa0a837 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 23 Nov 2015 14:31:40 -0800 Subject: [PATCH 189/401] fix comment header paths --- assignment-client/src/entities/AssignmentParentFinder.cpp | 2 +- assignment-client/src/entities/AssignmentParentFinder.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/entities/AssignmentParentFinder.cpp b/assignment-client/src/entities/AssignmentParentFinder.cpp index 3e6fc2ed38..5fe4742b90 100644 --- a/assignment-client/src/entities/AssignmentParentFinder.cpp +++ b/assignment-client/src/entities/AssignmentParentFinder.cpp @@ -1,6 +1,6 @@ // // AssignmentParentFinder.cpp -// assignment-client/src/ +// assignment-client/src/entities // // Created by Seth Alves on 2015-10-22 // Copyright 2015 High Fidelity, Inc. diff --git a/assignment-client/src/entities/AssignmentParentFinder.h b/assignment-client/src/entities/AssignmentParentFinder.h index 4d2e080443..99fa58ffed 100644 --- a/assignment-client/src/entities/AssignmentParentFinder.h +++ b/assignment-client/src/entities/AssignmentParentFinder.h @@ -1,6 +1,6 @@ // // AssignmentParentFinder.h -// interface/src/ +// interface/src/entities // // Created by Seth Alves on 2015-10-21 // Copyright 2015 High Fidelity, Inc. From 712048ce51de5233cd484214e52d10a8b11a0a8f Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 24 Nov 2015 19:35:10 +0100 Subject: [PATCH 190/401] ignore other than left press events in edit.js, this makes the rightclick camera more confortable while in edit.js/edit mode --- examples/edit.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/edit.js b/examples/edit.js index 74551384c9..9b83079198 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -738,6 +738,10 @@ var mousePressStartPosition = { var mouseDown = false; function mousePressEvent(event) { + if (!event.isLeftButton) { + // If another mouse button than left is pressed ignore it + return false; + } mouseDown = true; mousePressStartPosition = { x: event.x, From bba5bf7a21012302a49269bda3efa5051f4b8bb1 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 24 Nov 2015 11:28:00 -0800 Subject: [PATCH 191/401] Trying to get the Agent to Mater more reliable --- examples/acScripts/playbackAgents.js | 48 ++++++++--- examples/acScripts/playbackMaster.js | 120 +++++++++++++++++++++------ 2 files changed, 132 insertions(+), 36 deletions(-) diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index 16dd469a89..864e821175 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -11,7 +11,6 @@ // Set the following variables to the values needed var commandChannel = "com.highfidelity.PlaybackChannel1"; -var clip_url = null; var playFromCurrentLocation = true; var useDisplayName = true; var useAttachments = true; @@ -22,6 +21,12 @@ var announceIDChannel = "com.highfidelity.playbackAgent.announceID"; var UNKNOWN_AGENT_ID = -2; var id = UNKNOWN_AGENT_ID; // unknown until aknowledged +// The time between alive messages on the command channel +var timeSinceLastAlive = 0; +var ALIVE_PERIOD = 5; +var NUM_CYCLES_BEFORE_RESET = 5; +var notifyAlive = false; + // Set position/orientation/scale here if playFromCurrentLocation is true Avatar.position = { x:0, y: 0, z: 0 }; Avatar.orientation = Quat.fromPitchYawRollDegrees(0, 0, 0); @@ -32,6 +37,7 @@ var subscribed = false; var WAIT_FOR_AUDIO_MIXER = 1; // Script. DO NOT MODIFY BEYOND THIS LINE. +var ALIVE = -1; var DO_NOTHING = 0; var PLAY = 1; var PLAY_LOOP = 2; @@ -48,17 +54,14 @@ Recording.setPlayerUseSkeletonModel(useAvatarModel); function getAction(channel, message, senderID) { if(subscribed) { + var command = JSON.parse(message); print("I'm the agent " + id + " and I received this: ID: " + command.id_key + " Action: " + command.action_key + " URL: " + command.clip_url_key); if (command.id_key == id || command.id_key == -1) { - if (command.action_key === 6) { - clip_url = command.clip_url_key; - } action = command.action_key; - print("That command was for me!"); - print("My clip is: " + clip_url); + print("That command was for me! Agent with id: " + id); } else { action = DO_NOTHING; } @@ -104,11 +107,21 @@ function getAction(channel, message, senderID) { Agent.isAvatar = false; break; case LOAD: - print("Load"); - if(clip_url !== null) { - Recording.loadRecording(clip_url); + print("Load"); + if (!Agent.isAvatar) { + Agent.isAvatar = true; + } + if(command.clip_url_key !== null) { + print("Agent #" + id + " loading clip URL: " + command.clip_url_key); + Recording.loadRecording(command.clip_url_key); + } else { + print("Agent #" + id + " loading clip URL is NULL, nothing happened"); } break; + case ALIVE: + print("Alive"); + notifyAlive = true; + break; case DO_NOTHING: break; default: @@ -136,11 +149,26 @@ function update(deltaTime) { print("I'm the agent and I am ready to receive!"); } if (subscribed && id == UNKNOWN_AGENT_ID) { - print("sending ready, id:" + id); + Messages.sendMessage(announceIDChannel, "ready"); } } + if (subscribed && id != UNKNOWN_AGENT_ID) { + timeSinceLastAlive += deltaTime; + if (notifyAlive) { + timeSinceLastAlive = 0; + notifyAlive = false; + print("Master Alive"); + } else if (timeSinceLastAlive > NUM_CYCLES_BEFORE_RESET * ALIVE_PERIOD) { + print("Master Lost, reseting Agent"); + if (Recording.isPlaying()) { + Recording.stopPlaying(); + } + Agent.isAvatar = false; + id = UNKNOWN_AGENT_ID; + } + } } Messages.messageReceived.connect(function (channel, message, senderID) { diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 4703f0e4fd..2c9d4f77eb 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -14,9 +14,8 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; var ac_number = 1; // This is the default number of ACs. Their ID need to be unique and between 0 (included) and ac_number (excluded) var names = new Array(); // It is possible to specify the name of the ACs in this array. ACs names ordered by IDs (Default name is "ACx", x = ID + 1)) -var channel = "com.highfidelity.PlaybackChannel1"; +var commandChannel = "com.highfidelity.PlaybackChannel1"; var subscribed = false; -var clip_url = null; var input_text = null; var knownAgents = new Array; // We will add our known agents here when we discover them @@ -24,9 +23,15 @@ var knownAgents = new Array; // We will add our known agents here when we discov // available playbackAgents will announce their sessionID here. var announceIDChannel = "com.highfidelity.playbackAgent.announceID"; -// Script. DO NOT MODIFY BEYOND THIS LINE. -Script.include("../libraries/toolBars.js"); +// The time between alive messages on the command channel +var timeSinceLastAlive = 0; +var ALIVE_PERIOD = 5; +// Script. DO NOT MODIFY BEYOND THIS LINE. +//Script.include("../libraries/toolBars.js"); +Script.include(HIFI_PUBLIC_BUCKET + "scripts/libraries/toolBars.js"); + +var ALIVE = -1; var DO_NOTHING = 0; var PLAY = 1; var PLAY_LOOP = 2; @@ -52,6 +57,9 @@ var playLoopIcon = new Array(); var stopIcon = new Array(); var loadIcon = new Array(); +var performanceJSON = null; +var performanceLoadedNeedUpdate = false; + setupPlayback(); function setupPlayback() { @@ -59,7 +67,7 @@ function setupPlayback() { if (ac_number === "" || ac_number === null) { ac_number = 1; } - Messages.subscribe(channel); + Messages.subscribe(commandChannel); subscribed = true; setupToolBars(); } @@ -139,7 +147,27 @@ function setupToolBars() { } } -function sendCommand(id, action) { +function loadAvatarClipsFromPerformanceJSON(performanceJSON) { + if (performanceJSON.avatarClips) { + var numClips = performanceJSON.avatarClips.length; + print("Performance file contains:" + JSON.stringify(performanceJSON)); + print("Number of clips in the performance file is: " + numClips + " Number of agents is: " + knownAgents.length); + + if (numClips > knownAgents.length) { + numClips = knownAgents.length; + } + + for (i = 0; i < numClips; i++) { + var clipURL = performanceJSON.avatarClips[i]; + print("Loading clip " + clipURL + " to Agent #" + i); + sendCommand(i, LOAD, clipURL); + } + } else { + print("Performance file cannot be interpreted:" + JSON.stringify(performanceJSON)); + } +} + +function sendCommand(id, action, argument) { if (action === SHOW) { toolBars[id].selectTool(onOffIcon[id], false); toolBars[id].setAlpha(ALPHA_ON, playIcon[id]); @@ -152,24 +180,48 @@ function sendCommand(id, action) { toolBars[id].setAlpha(ALPHA_OFF, playLoopIcon[id]); toolBars[id].setAlpha(ALPHA_OFF, stopIcon[id]); toolBars[id].setAlpha(ALPHA_OFF, loadIcon[id]); + } else if (action == ALIVE) { } else if (toolBars[id].toolSelected(onOffIcon[id])) { return; } if (id == (toolBars.length - 1)) { - id = -1; // Master command becomes broadcast. - } - - var message = { - id_key: id, - action_key: action, - clip_url_key: clip_url - }; - - if(subscribed){ - Messages.sendMessage(channel, JSON.stringify(message)); - print("Message sent!"); - clip_url = null; + + if (action == LOAD) { + if (performanceLoadedNeedUpdate == false) { + Assets.downloadData(argument, function (data) { + performanceJSON = JSON.parse(data); + performanceLoadedNeedUpdate = true; + // print("Performance file contains:" + JSON.stringify(performanceJSON)); + }); + return; + } + } else { + id = -1; + + var message = { + id_key: id, + action_key: action, + clip_url_key: argument + }; + + if(subscribed){ + Messages.sendMessage(commandChannel, JSON.stringify(message)); + print("Message sent!"); + } + } + } else { + + var message = { + id_key: id, + action_key: action, + clip_url_key: argument + }; + + if(subscribed){ + Messages.sendMessage(commandChannel, JSON.stringify(message)); + print("Message sent!"); + } } } @@ -193,8 +245,7 @@ function mousePressEvent(event) { } else if (loadIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { input_text = Window.prompt("Insert the url of the clip: ",""); if (!(input_text === "" || input_text === null)) { - clip_url = input_text; - sendCommand(i, LOAD); + sendCommand(i, LOAD, input_text); } } else { // Check individual controls @@ -214,8 +265,7 @@ function mousePressEvent(event) { } else if (loadIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { input_text = Window.prompt("Insert the url of the clip: ",""); if (!(input_text === "" || input_text === null)) { - clip_url = input_text; - sendCommand(i, LOAD); + sendCommand(i, LOAD, input_text); } } else { @@ -240,13 +290,25 @@ function moveUI() { } } -function update() { +function update(deltaTime) { var newDimensions = Controller.getViewportDimensions(); if (windowDimensions.x != newDimensions.x || windowDimensions.y != newDimensions.y) { windowDimensions = newDimensions; moveUI(); } + + if (performanceLoadedNeedUpdate) { + loadAvatarClipsFromPerformanceJSON(performanceJSON); + performanceLoadedNeedUpdate = false; + } + + timeSinceLastAlive += deltaTime; + if (timeSinceLastAlive > ALIVE_PERIOD) { + timeSinceLastAlive = 0; + print("ping alive"); + sendCommand((toolBars.length - 1), ALIVE); + } } function scriptEnding() { @@ -256,7 +318,7 @@ function scriptEnding() { } if (subscribed) { - Messages.unsubscribe(channel); + Messages.unsubscribe(commandChannel); } Messages.unsubscribe(announceIDChannel); } @@ -272,13 +334,19 @@ Messages.messageReceived.connect(function (channel, message, senderID) { if (channel == announceIDChannel && message == "ready") { // check to see if we know about this agent if (knownAgents.indexOf(senderID) < 0) { + print("New agent to be hired " + senderID); var indexOfNewAgent = knownAgents.length; knownAgents[indexOfNewAgent] = senderID; var acknowledgeMessage = senderID + "." + indexOfNewAgent; + Overlays.editOverlay(nameOverlays[indexOfNewAgent], { backgroundColor: { red: 0, green: 255, blue: 0 }, text: "Agent-Hired" } ); + print("Hired new Agent " + senderID + " #" + indexOfNewAgent); Messages.sendMessage(announceIDChannel, acknowledgeMessage); + } else { + + print("New agent still sending ready ? " + senderID); } } }); -moveUI(); \ No newline at end of file +moveUI(); From 669d3c3523afffe2074d3ea78f557964ed613108 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 24 Nov 2015 11:29:02 -0800 Subject: [PATCH 192/401] Rename several ReceivedMessage params from packet to message --- assignment-client/src/Agent.h | 4 ++-- assignment-client/src/AssignmentFactory.h | 2 +- assignment-client/src/avatars/AvatarMixer.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 46d3214d1b..44fcee2a0b 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -63,8 +63,8 @@ private slots: void scriptRequestFinished(); void executeScript(); - void handleAudioPacket(QSharedPointer packet); - void handleOctreePacket(QSharedPointer packet, SharedNodePointer senderNode); + void handleAudioPacket(QSharedPointer message); + void handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode); void handleJurisdictionPacket(QSharedPointer message, SharedNodePointer senderNode); void processAgentAvatarAndAudio(float deltaTime); diff --git a/assignment-client/src/AssignmentFactory.h b/assignment-client/src/AssignmentFactory.h index 6eeabb8f46..58afcc7727 100644 --- a/assignment-client/src/AssignmentFactory.h +++ b/assignment-client/src/AssignmentFactory.h @@ -16,7 +16,7 @@ class AssignmentFactory { public: - static ThreadedAssignment* unpackAssignment(ReceivedMessage& packet); + static ThreadedAssignment* unpackAssignment(ReceivedMessage& message); }; #endif // hifi_AssignmentFactory_h diff --git a/assignment-client/src/avatars/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h index 6d0a85fda2..00c53e916b 100644 --- a/assignment-client/src/avatars/AvatarMixer.h +++ b/assignment-client/src/avatars/AvatarMixer.h @@ -32,7 +32,7 @@ public slots: void sendStatsPacket(); private slots: - void handleAvatarDataPacket(QSharedPointer packet, SharedNodePointer senderNode); + void handleAvatarDataPacket(QSharedPointer message, SharedNodePointer senderNode); void handleAvatarIdentityPacket(QSharedPointer message, SharedNodePointer senderNode); void handleAvatarBillboardPacket(QSharedPointer message, SharedNodePointer senderNode); void handleKillAvatarPacket(QSharedPointer message); From bad01d02f82d148f343d68ea449a60b31d2b577b Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 24 Nov 2015 18:31:28 -0800 Subject: [PATCH 193/401] building the master/agent api --- examples/acScripts/AgentPoolControler.js | 214 +++++++++++++++++++++++ examples/acScripts/playbackAgents.js | 42 +++-- examples/acScripts/playbackMaster.js | 43 ++--- 3 files changed, 258 insertions(+), 41 deletions(-) create mode 100644 examples/acScripts/AgentPoolControler.js diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js new file mode 100644 index 0000000000..353480e2cf --- /dev/null +++ b/examples/acScripts/AgentPoolControler.js @@ -0,0 +1,214 @@ +// +// AgentPoolController.js +// acScripts +// +// Created by Sam Gateau on 11/23/15. +// 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 +// + +var COMMAND_CHANNEL = "com.highfidelity.PlaybackChannel1"; +var ANNOUNCE_CHANNEL = "com.highfidelity.playbackAgent.announceID"; + +// The time between alive messages on the command channel +var ALIVE_PERIOD = 1; + +var NUM_CYCLES_BEFORE_RESET = 5; + +// Service Actions +var AGENT_READY = "ready"; +var INVALID_ACTOR = -2; + +var MASTER_INDEX = -1; + +var MASTER_ALIVE = -1; + +function printDebug(message) { + print(message); +} + +(function() { + + var makeMessage = function(id, action, argument) { + var message = { + id_key: id, + action_key: action, + argument_key: argument + }; + return message; + }; + + var unpackMessage = function(message) { + return JSON.parse(message); + }; + + // master side + var MasterController = function() { + this.timeSinceLastAlive = 0; + this.knownAgents = new Array; + this.subscribed = false; + }; + + MasterController.prototype.reset = function() { + if (this.subscribed) { + this.timeSinceLastAlive = 0; + + } + + Messages.subscribe(COMMAND_CHANNEL); + Messages.subscribe(ANNOUNCE_CHANNEL); + + this.timeSinceLastAlive = 0; + + var localThis = this; + + Messages.messageReceived.connect(function (channel, message, senderID) { + printDebug("Agent received"); + if (channel == ANNOUNCE_CHANNEL) { + printDebug("Agent received"); + // localThis._processAgentMessage(message, senderID); + } + }); + + // ready to roll, enable + this.subscribed = true; + }; + + MasterController.prototype._processAgentMessage = function(message, senderID) { + if (message == AGENT_READY) { + + // check to see if we know about this agent + if (this.knownAgents.indexOf(senderID) < 0) { + + var indexOfNewAgent = this.knownAgents.length; + this.knownAgents[indexOfNewAgent] = senderID; + printDebug("New agent available to be hired " + senderID); + + var acknowledgeMessage = senderID + "." + indexOfNewAgent; + Messages.sendMessage(ANNOUNCE_CHANNEL, acknowledgeMessage); + } else { + + printDebug("New agent still sending ready ? " + senderID); + } + } + }; + + MasterController.prototype.destroy = function() { + if (this.subscribed) { + Messages.unsubscribe(ANNOUNCE_CHANNEL); + Messages.unsubscribe(COMMAND_CHANNEL); + this.timeSinceLastAlive = 0; + this.subscribed = true; + } + }; + + MasterController.prototype.sendCommand = function(target, action, argument) { + if (this.subscribed) { + var messageJSON = JSON.stringify(makeMessage(target, action, argument)); + Messages.sendMessage(COMMAND_CHANNEL, messageJSON); + printDebug("Master sent message: " + messageJSON); + } + }; + + MasterController.prototype.update = function(deltaTime) { + this.timeSinceLastAlive += deltaTime; + if (this.timeSinceLastAlive > ALIVE_PERIOD) { + this.timeSinceLastAlive = 0; + printDebug("Master ping alive"); + this.sendCommand(MASTER_INDEX, MASTER_ALIVE); + } + }; + + + this.MasterController = MasterController; + + // agent side + var AgentController = function() { + this.timeSinceLastAlive = 0; + this.subscribed = false; + this.actorIndex = INVALID_ACTOR; + this.notifyAlive = false; + }; + + AgentController.prototype.reset = function() { + if (!this.subscribed) { + Messages.subscribe(COMMAND_CHANNEL); + Messages.subscribe(ANNOUNCE_CHANNEL); + } + + this.timeSinceLastAlive = 0; + + var localThis = this; + Messages.messageReceived.connect(function (channel, message, senderID) { + if (channel == ANNOUNCE_CHANNEL) { + if (message != AGENT_READY) { + // this may be a message to hire me if i m not already + if (id == INVALID_ACTOR) { + var parts = message.split("."); + var agentID = parts[0]; + var actorIndex = parts[1]; + if (agentID == Agent.sessionUUID) { + // localThis.actorIndex = agentIndex; + Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel + } + } + } + return; + } + if (channel == COMMAND_CHANNEL) { + var command = unpackMessage(message); + printDebug("Received command = " == command); + + if (command.id_key == localThis.actorIndex || command.id_key == MASTER_INDEX) { + if (command.action_key == MASTER_ALIVE) { + // localThis.notifyAlive = true; + } else { + // localThis._processMasterMessage(command, senderID); + } + } else { + // ignored + } + return; + } + }); + + // ready to roll, enable + this.subscribed = true; + printDebug("In Reset"); + }; + + AgentController.prototype._processMasterMessage = function(command, senderID) { + printDebug("True action received = " + JSON.stringify(command) + senderID); + }; + + AgentController.prototype.update = function(deltaTime) { + this.timeSinceLastAlive += deltaTime; + if (this.timeSinceLastAlive > ALIVE_PERIOD) { + if (this.subscribed) { + printDebug("In update of client"); + if (this.actorIndex == INVALID_ACTOR) { + Messages.sendMessage(ANNOUNCE_CHANNEL, AGENT_READY); + printDebug("Client Ready"); + } else { + if (this.notifyAlive) { + this.notifyAlive = false; + printDebug("Master Alive"); + } else if (this.timeSinceLastAlive > NUM_CYCLES_BEFORE_RESET * ALIVE_PERIOD) { + printDebug("Master Lost, reseting Agent"); + this.actorIndex = UNKNOWN_AGENT_ID; + } + } + } + + this.timeSinceLastAlive = 0; + } + }; + + + this.AgentController = AgentController; +})(); + + + diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index 864e821175..96502a7816 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -8,24 +8,27 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +Agent.isAvatar = true; +Script.include("./AgentPoolControler.js"); // Set the following variables to the values needed -var commandChannel = "com.highfidelity.PlaybackChannel1"; var playFromCurrentLocation = true; var useDisplayName = true; var useAttachments = true; var useAvatarModel = true; +var agentController = new AgentController(); + // ID of the agent. Two agents can't have the same ID. -var announceIDChannel = "com.highfidelity.playbackAgent.announceID"; -var UNKNOWN_AGENT_ID = -2; -var id = UNKNOWN_AGENT_ID; // unknown until aknowledged +//var UNKNOWN_AGENT_ID = -2; +//var id = UNKNOWN_AGENT_ID; // unknown until aknowledged // The time between alive messages on the command channel -var timeSinceLastAlive = 0; +/*var timeSinceLastAlive = 0; var ALIVE_PERIOD = 5; var NUM_CYCLES_BEFORE_RESET = 5; var notifyAlive = false; +*/ // Set position/orientation/scale here if playFromCurrentLocation is true Avatar.position = { x:0, y: 0, z: 0 }; @@ -118,7 +121,7 @@ function getAction(channel, message, senderID) { print("Agent #" + id + " loading clip URL is NULL, nothing happened"); } break; - case ALIVE: + case MASTER_ALIVE: print("Alive"); notifyAlive = true; break; @@ -138,10 +141,16 @@ function getAction(channel, message, senderID) { function update(deltaTime) { - + totalTime += deltaTime; + if (totalTime > WAIT_FOR_AUDIO_MIXER) { + if (!agentController.subscribed) { + agentController.reset(); + } + } + /* + totalTime += deltaTime; - - if (totalTime > WAIT_FOR_AUDIO_MIXER) { + if (totalTime > WAIT_FOR_AUDIO_MIXER) { if (!subscribed) { Messages.subscribe(commandChannel); // command channel Messages.subscribe(announceIDChannel); // id announce channel @@ -168,9 +177,11 @@ function update(deltaTime) { Agent.isAvatar = false; id = UNKNOWN_AGENT_ID; } - } -} + }*/ + agentController.update(deltaTime); +} +/* Messages.messageReceived.connect(function (channel, message, senderID) { if (channel == announceIDChannel && message != "ready") { // If I don't yet know if my ID has been recieved, then check to see if the master has acknowledged me @@ -187,6 +198,13 @@ Messages.messageReceived.connect(function (channel, message, senderID) { if (channel == commandChannel) { getAction(channel, message, senderID); } -}); +});*/ + +function scriptEnding() { + + agentController.destroy(); +} + Script.update.connect(update); +Script.scriptEnding.connect(scriptEnding); diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 2c9d4f77eb..eb7f86518f 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -8,30 +8,22 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +Script.include("./AgentPoolControler.js"); HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; +var masterController = new MasterController(); var ac_number = 1; // This is the default number of ACs. Their ID need to be unique and between 0 (included) and ac_number (excluded) var names = new Array(); // It is possible to specify the name of the ACs in this array. ACs names ordered by IDs (Default name is "ACx", x = ID + 1)) -var commandChannel = "com.highfidelity.PlaybackChannel1"; -var subscribed = false; var input_text = null; -var knownAgents = new Array; // We will add our known agents here when we discover them - -// available playbackAgents will announce their sessionID here. -var announceIDChannel = "com.highfidelity.playbackAgent.announceID"; - -// The time between alive messages on the command channel -var timeSinceLastAlive = 0; -var ALIVE_PERIOD = 5; // Script. DO NOT MODIFY BEYOND THIS LINE. //Script.include("../libraries/toolBars.js"); Script.include(HIFI_PUBLIC_BUCKET + "scripts/libraries/toolBars.js"); -var ALIVE = -1; + var DO_NOTHING = 0; var PLAY = 1; var PLAY_LOOP = 2; @@ -67,9 +59,8 @@ function setupPlayback() { if (ac_number === "" || ac_number === null) { ac_number = 1; } - Messages.subscribe(commandChannel); - subscribed = true; setupToolBars(); + masterController.reset(); } function setupToolBars() { @@ -180,7 +171,6 @@ function sendCommand(id, action, argument) { toolBars[id].setAlpha(ALPHA_OFF, playLoopIcon[id]); toolBars[id].setAlpha(ALPHA_OFF, stopIcon[id]); toolBars[id].setAlpha(ALPHA_OFF, loadIcon[id]); - } else if (action == ALIVE) { } else if (toolBars[id].toolSelected(onOffIcon[id])) { return; } @@ -199,6 +189,8 @@ function sendCommand(id, action, argument) { } else { id = -1; + masterController.sendMessage(id, action, argument); + /* var message = { id_key: id, action_key: action, @@ -208,10 +200,11 @@ function sendCommand(id, action, argument) { if(subscribed){ Messages.sendMessage(commandChannel, JSON.stringify(message)); print("Message sent!"); - } + }*/ } } else { - + masterController.sendMessage(id, action, argument); + /* var message = { id_key: id, action_key: action, @@ -221,7 +214,7 @@ function sendCommand(id, action, argument) { if(subscribed){ Messages.sendMessage(commandChannel, JSON.stringify(message)); print("Message sent!"); - } + }*/ } } @@ -303,12 +296,7 @@ function update(deltaTime) { performanceLoadedNeedUpdate = false; } - timeSinceLastAlive += deltaTime; - if (timeSinceLastAlive > ALIVE_PERIOD) { - timeSinceLastAlive = 0; - print("ping alive"); - sendCommand((toolBars.length - 1), ALIVE); - } + masterController.update(deltaTime); } function scriptEnding() { @@ -317,10 +305,7 @@ function scriptEnding() { Overlays.deleteOverlay(nameOverlays[i]); } - if (subscribed) { - Messages.unsubscribe(commandChannel); - } - Messages.unsubscribe(announceIDChannel); + masterController.destroy(); } Controller.mousePressEvent.connect(mousePressEvent); @@ -328,7 +313,7 @@ Script.update.connect(update); Script.scriptEnding.connect(scriptEnding); - +/* Messages.subscribe(announceIDChannel); Messages.messageReceived.connect(function (channel, message, senderID) { if (channel == announceIDChannel && message == "ready") { @@ -348,5 +333,5 @@ Messages.messageReceived.connect(function (channel, message, senderID) { } }); - +*/ moveUI(); From 574eb3dc99d2e8115dbccac953ab1d3ea0333d23 Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Wed, 25 Nov 2015 02:50:12 -0800 Subject: [PATCH 194/401] Improving the Master/Agent api --- examples/acScripts/AgentPoolControler.js | 221 +++++++++++++---------- examples/acScripts/playbackAgents.js | 95 +++------- examples/acScripts/playbackMaster.js | 44 ----- 3 files changed, 147 insertions(+), 213 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index 353480e2cf..60b906381a 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -9,27 +9,26 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -var COMMAND_CHANNEL = "com.highfidelity.PlaybackChannel1"; -var ANNOUNCE_CHANNEL = "com.highfidelity.playbackAgent.announceID"; - -// The time between alive messages on the command channel -var ALIVE_PERIOD = 1; - -var NUM_CYCLES_BEFORE_RESET = 5; - -// Service Actions -var AGENT_READY = "ready"; -var INVALID_ACTOR = -2; - -var MASTER_INDEX = -1; - -var MASTER_ALIVE = -1; - function printDebug(message) { print(message); } (function() { + var COMMAND_CHANNEL = "com.highfidelity.PlaybackChannel1"; + var ANNOUNCE_CHANNEL = "com.highfidelity.playbackAgent.announceID"; + + // The time between alive messages on the command channel + var ALIVE_PERIOD = 3; + var NUM_CYCLES_BEFORE_RESET = 5; + + // Service Actions + var AGENT_READY = "ready"; + var INVALID_ACTOR = -2; + + var MASTER_INDEX = -1; + + var MASTER_ALIVE = -1; + var MASTER_FIRE_AGENT = -2; var makeMessage = function(id, action, argument) { var message = { @@ -45,38 +44,41 @@ function printDebug(message) { }; // master side + //--------------------------------- var MasterController = function() { this.timeSinceLastAlive = 0; this.knownAgents = new Array; this.subscribed = false; }; - MasterController.prototype.reset = function() { - if (this.subscribed) { - this.timeSinceLastAlive = 0; - + MasterController.prototype.destroy = function() { + if (this.subscribed) { + Messages.unsubscribe(ANNOUNCE_CHANNEL); + Messages.unsubscribe(COMMAND_CHANNEL); + this.subscribed = true; } + }; - Messages.subscribe(COMMAND_CHANNEL); - Messages.subscribe(ANNOUNCE_CHANNEL); - - this.timeSinceLastAlive = 0; - - var localThis = this; - - Messages.messageReceived.connect(function (channel, message, senderID) { - printDebug("Agent received"); - if (channel == ANNOUNCE_CHANNEL) { - printDebug("Agent received"); - // localThis._processAgentMessage(message, senderID); - } - }); + MasterController.prototype.reset = function() { + this.timeSinceLastAlive = 0; + if (!this.subscribed) { + Messages.subscribe(COMMAND_CHANNEL); + Messages.subscribe(ANNOUNCE_CHANNEL); + var localThis = this; + Messages.messageReceived.connect(function (channel, message, senderID) { + if (channel == ANNOUNCE_CHANNEL) { + localThis._processAnnounceMessage(message, senderID); + return; + } + }); + } // ready to roll, enable this.subscribed = true; + printDebug("Master Started"); }; - MasterController.prototype._processAgentMessage = function(message, senderID) { + MasterController.prototype._processAnnounceMessage = function(message, senderID) { if (message == AGENT_READY) { // check to see if we know about this agent @@ -89,20 +91,10 @@ function printDebug(message) { var acknowledgeMessage = senderID + "." + indexOfNewAgent; Messages.sendMessage(ANNOUNCE_CHANNEL, acknowledgeMessage); } else { - printDebug("New agent still sending ready ? " + senderID); } } }; - - MasterController.prototype.destroy = function() { - if (this.subscribed) { - Messages.unsubscribe(ANNOUNCE_CHANNEL); - Messages.unsubscribe(COMMAND_CHANNEL); - this.timeSinceLastAlive = 0; - this.subscribed = true; - } - }; MasterController.prototype.sendCommand = function(target, action, argument) { if (this.subscribed) { @@ -121,83 +113,109 @@ function printDebug(message) { } }; - this.MasterController = MasterController; // agent side + //--------------------------------- var AgentController = function() { + this.subscribed = false; + this.timeSinceLastAlive = 0; - this.subscribed = false; + this.numCyclesWithoutAlive = 0; this.actorIndex = INVALID_ACTOR; this.notifyAlive = false; + + this.onHired = function() {}; + this.onCommand = function(command) {}; + this.onFired = function() {}; }; + AgentController.prototype.destroy = function() { + if (this.subscribed) { + this.fire(); + Messages.unsubscribe(ANNOUNCE_CHANNEL); + Messages.unsubscribe(COMMAND_CHANNEL); + this.subscribed = true; + } + }; + AgentController.prototype.reset = function() { + // If already hired, fire + this.fired(); + if (!this.subscribed) { Messages.subscribe(COMMAND_CHANNEL); Messages.subscribe(ANNOUNCE_CHANNEL); - } - - this.timeSinceLastAlive = 0; - - var localThis = this; - Messages.messageReceived.connect(function (channel, message, senderID) { - if (channel == ANNOUNCE_CHANNEL) { - if (message != AGENT_READY) { - // this may be a message to hire me if i m not already - if (id == INVALID_ACTOR) { - var parts = message.split("."); - var agentID = parts[0]; - var actorIndex = parts[1]; - if (agentID == Agent.sessionUUID) { - // localThis.actorIndex = agentIndex; - Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel - } - } - } - return; - } - if (channel == COMMAND_CHANNEL) { - var command = unpackMessage(message); - printDebug("Received command = " == command); - - if (command.id_key == localThis.actorIndex || command.id_key == MASTER_INDEX) { - if (command.action_key == MASTER_ALIVE) { - // localThis.notifyAlive = true; - } else { - // localThis._processMasterMessage(command, senderID); - } - } else { - // ignored + var localThis = this; + Messages.messageReceived.connect(function (channel, message, senderID) { + if (channel == ANNOUNCE_CHANNEL) { + localThis._processAnnounceMessage(message, senderID); + return; } - return; - } - }); - - // ready to roll, enable + if (channel == COMMAND_CHANNEL) { + localThis._processCommandMessage(message, senderID); + return; + } + }); + } this.subscribed = true; - printDebug("In Reset"); + printDebug("Client Started"); }; - AgentController.prototype._processMasterMessage = function(command, senderID) { - printDebug("True action received = " + JSON.stringify(command) + senderID); + AgentController.prototype._processAnnounceMessage = function(message, senderID) { + //printDebug("Client " + this.actorIndex + " Received Announcement = " + message); + if (message != AGENT_READY) { + // this may be a message to hire me if i m not already + if (this.actorIndex == INVALID_ACTOR) { + var parts = message.split("."); + var agentID = parts[0]; + var actorIndex = parts[1]; + //printDebug("Client " + Agent.sessionUUID + " - " + agentID + " Hired!"); + if (agentID == Agent.sessionUUID) { + this.actorIndex = actorIndex; + printDebug("Client " + this.actorIndex + " Hired!"); + this.onHired(); + // Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel + } + } + } + } + + AgentController.prototype._processCommandMessage = function(message, senderID) { + var command = unpackMessage(message); + //printDebug("Received command = " + JSON.stringify(command)); + + if (command.id_key == localThis.actorIndex || command.id_key == MASTER_INDEX) { + if (command.action_key == MASTER_ALIVE) { + this.notifyAlive = true; + } else if (command.action_key == MASTER_FIRE_AGENT) { + printDebug("Master firing Agent"); + this.fire(); + } else { + printDebug("True action received = " + JSON.stringify(command) + senderID); + this.onCommand(command); + } + } else { + // ignored + } }; AgentController.prototype.update = function(deltaTime) { this.timeSinceLastAlive += deltaTime; - if (this.timeSinceLastAlive > ALIVE_PERIOD) { + if (this.timeSinceLastAlive > ALIVE_PERIOD) { if (this.subscribed) { - printDebug("In update of client"); if (this.actorIndex == INVALID_ACTOR) { Messages.sendMessage(ANNOUNCE_CHANNEL, AGENT_READY); - printDebug("Client Ready"); + //printDebug("Client Ready" + ANNOUNCE_CHANNEL + AGENT_READY); } else { - if (this.notifyAlive) { + this.numCyclesWithoutAlive++; + if (this.notifyAlive) { this.notifyAlive = false; + this.numCyclesWithoutAlive = 0; printDebug("Master Alive"); - } else if (this.timeSinceLastAlive > NUM_CYCLES_BEFORE_RESET * ALIVE_PERIOD) { - printDebug("Master Lost, reseting Agent"); - this.actorIndex = UNKNOWN_AGENT_ID; + } else if (this.numCyclesWithoutAlive > NUM_CYCLES_BEFORE_RESET) { + printDebug("Master Lost, firing Agent"); + this.fired(); } } } @@ -206,6 +224,19 @@ function printDebug(message) { } }; + AgentController.prototype.fired = function() { + // clear the state first + var wasHired = (this.actorIndex != INVALID_ACTOR); + this.actorIndex= INVALID_ACTOR; + this.notifyAlive = false; + this.timeSinceLastAlive = 0; + this.numCyclesWithoutAlive = 0; + // then custom fire if was hired + if (wasHired) { + this.onFired(); + } + } + this.AgentController = AgentController; })(); diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index 96502a7816..f7630cad48 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -10,6 +10,7 @@ // Agent.isAvatar = true; Script.include("./AgentPoolControler.js"); +var agentController = new AgentController(); // Set the following variables to the values needed var playFromCurrentLocation = true; @@ -17,18 +18,6 @@ var useDisplayName = true; var useAttachments = true; var useAvatarModel = true; -var agentController = new AgentController(); - -// ID of the agent. Two agents can't have the same ID. -//var UNKNOWN_AGENT_ID = -2; -//var id = UNKNOWN_AGENT_ID; // unknown until aknowledged - -// The time between alive messages on the command channel -/*var timeSinceLastAlive = 0; -var ALIVE_PERIOD = 5; -var NUM_CYCLES_BEFORE_RESET = 5; -var notifyAlive = false; -*/ // Set position/orientation/scale here if playFromCurrentLocation is true Avatar.position = { x:0, y: 0, z: 0 }; @@ -36,7 +25,6 @@ Avatar.orientation = Quat.fromPitchYawRollDegrees(0, 0, 0); Avatar.scale = 1.0; var totalTime = 0; -var subscribed = false; var WAIT_FOR_AUDIO_MIXER = 1; // Script. DO NOT MODIFY BEYOND THIS LINE. @@ -55,10 +43,10 @@ Recording.setPlayerUseAttachments(useAttachments); Recording.setPlayerUseHeadModel(false); Recording.setPlayerUseSkeletonModel(useAvatarModel); -function getAction(channel, message, senderID) { - if(subscribed) { +function getAction(command) { + if(true) { - var command = JSON.parse(message); + // var command = JSON.parse(message); print("I'm the agent " + id + " and I received this: ID: " + command.id_key + " Action: " + command.action_key + " URL: " + command.clip_url_key); if (command.id_key == id || command.id_key == -1) { @@ -114,17 +102,13 @@ function getAction(channel, message, senderID) { if (!Agent.isAvatar) { Agent.isAvatar = true; } - if(command.clip_url_key !== null) { - print("Agent #" + id + " loading clip URL: " + command.clip_url_key); - Recording.loadRecording(command.clip_url_key); + if(command.argument_key !== null) { + print("Agent #" + id + " loading clip URL: " + command.argument_key); + Recording.loadRecording(command.argument_key); } else { print("Agent #" + id + " loading clip URL is NULL, nothing happened"); } break; - case MASTER_ALIVE: - print("Alive"); - notifyAlive = true; - break; case DO_NOTHING: break; default: @@ -139,66 +123,29 @@ function getAction(channel, message, senderID) { } } +function agentHired() { + print("Agent Hired from playbackAgents.js"); +} + +function agentFired() { + print("Agent Fired from playbackAgents.js"); +} + function update(deltaTime) { - totalTime += deltaTime; - if (totalTime > WAIT_FOR_AUDIO_MIXER) { + totalTime += deltaTime; + if (totalTime > WAIT_FOR_AUDIO_MIXER) { if (!agentController.subscribed) { agentController.reset(); + agentController.onCommand = getAction; + agentController.onHired = agentHired; + agentController.onFired = agentFired; } } - /* - - totalTime += deltaTime; - if (totalTime > WAIT_FOR_AUDIO_MIXER) { - if (!subscribed) { - Messages.subscribe(commandChannel); // command channel - Messages.subscribe(announceIDChannel); // id announce channel - subscribed = true; - print("I'm the agent and I am ready to receive!"); - } - if (subscribed && id == UNKNOWN_AGENT_ID) { - - Messages.sendMessage(announceIDChannel, "ready"); - } - } - - if (subscribed && id != UNKNOWN_AGENT_ID) { - timeSinceLastAlive += deltaTime; - if (notifyAlive) { - timeSinceLastAlive = 0; - notifyAlive = false; - print("Master Alive"); - } else if (timeSinceLastAlive > NUM_CYCLES_BEFORE_RESET * ALIVE_PERIOD) { - print("Master Lost, reseting Agent"); - if (Recording.isPlaying()) { - Recording.stopPlaying(); - } - Agent.isAvatar = false; - id = UNKNOWN_AGENT_ID; - } - }*/ agentController.update(deltaTime); } -/* -Messages.messageReceived.connect(function (channel, message, senderID) { - if (channel == announceIDChannel && message != "ready") { - // If I don't yet know if my ID has been recieved, then check to see if the master has acknowledged me - if (id == UNKNOWN_AGENT_ID) { - var parts = message.split("."); - var agentID = parts[0]; - var agentIndex = parts[1]; - if (agentID == Agent.sessionUUID) { - id = agentIndex; - Messages.unsubscribe(announceIDChannel); // id announce channel - } - } - } - if (channel == commandChannel) { - getAction(channel, message, senderID); - } -});*/ + function scriptEnding() { diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index eb7f86518f..1444ae3cf1 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -190,31 +190,9 @@ function sendCommand(id, action, argument) { id = -1; masterController.sendMessage(id, action, argument); - /* - var message = { - id_key: id, - action_key: action, - clip_url_key: argument - }; - - if(subscribed){ - Messages.sendMessage(commandChannel, JSON.stringify(message)); - print("Message sent!"); - }*/ } } else { masterController.sendMessage(id, action, argument); - /* - var message = { - id_key: id, - action_key: action, - clip_url_key: argument - }; - - if(subscribed){ - Messages.sendMessage(commandChannel, JSON.stringify(message)); - print("Message sent!"); - }*/ } } @@ -312,26 +290,4 @@ Controller.mousePressEvent.connect(mousePressEvent); Script.update.connect(update); Script.scriptEnding.connect(scriptEnding); - -/* -Messages.subscribe(announceIDChannel); -Messages.messageReceived.connect(function (channel, message, senderID) { - if (channel == announceIDChannel && message == "ready") { - // check to see if we know about this agent - if (knownAgents.indexOf(senderID) < 0) { - print("New agent to be hired " + senderID); - var indexOfNewAgent = knownAgents.length; - knownAgents[indexOfNewAgent] = senderID; - var acknowledgeMessage = senderID + "." + indexOfNewAgent; - Overlays.editOverlay(nameOverlays[indexOfNewAgent], { backgroundColor: { red: 0, green: 255, blue: 0 }, text: "Agent-Hired" } ); - print("Hired new Agent " + senderID + " #" + indexOfNewAgent); - Messages.sendMessage(announceIDChannel, acknowledgeMessage); - } else { - - print("New agent still sending ready ? " + senderID); - } - - } -}); -*/ moveUI(); From cd2e610e173bbb3a82592680e1b2d212e9126e5f Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 25 Nov 2015 15:35:15 -0800 Subject: [PATCH 195/401] Remove OctreeElement's UpdateHooks --- libraries/octree/src/OctreeElement.cpp | 23 ----------------------- libraries/octree/src/OctreeElement.h | 14 -------------- 2 files changed, 37 deletions(-) diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 5f03627f1a..1313dc499d 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -115,7 +115,6 @@ OctreeElement::~OctreeElement() { void OctreeElement::markWithChangedTime() { _lastChanged = usecTimestampNow(); - notifyUpdateHooks(); // if the node has changed, notify our hooks } // This method is called by Octree when the subtree below this node @@ -551,28 +550,6 @@ void OctreeElement::notifyDeleteHooks() { _deleteHooksNotified = true; } -std::vector OctreeElement::_updateHooks; - -void OctreeElement::addUpdateHook(OctreeElementUpdateHook* hook) { - _updateHooks.push_back(hook); -} - -void OctreeElement::removeUpdateHook(OctreeElementUpdateHook* hook) { - for (unsigned int i = 0; i < _updateHooks.size(); i++) { - if (_updateHooks[i] == hook) { - _updateHooks.erase(_updateHooks.begin() + i); - return; - } - } -} - -void OctreeElement::notifyUpdateHooks() { - for (unsigned int i = 0; i < _updateHooks.size(); i++) { - _updateHooks[i]->elementUpdated(shared_from_this()); - } -} - - bool OctreeElement::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject) const { // center and radius are in meters, so we have to scale the _cube into world-frame diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index d705b64acd..ed92e8a193 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -48,13 +48,6 @@ public: virtual void elementDeleted(OctreeElementPointer element) = 0; }; -// Callers who want update hook callbacks should implement this class -class OctreeElementUpdateHook { -public: - virtual void elementUpdated(OctreeElementPointer element) = 0; -}; - - class OctreeElement: public std::enable_shared_from_this { protected: @@ -184,9 +177,6 @@ public: static void addDeleteHook(OctreeElementDeleteHook* hook); static void removeDeleteHook(OctreeElementDeleteHook* hook); - static void addUpdateHook(OctreeElementUpdateHook* hook); - static void removeUpdateHook(OctreeElementUpdateHook* hook); - static void resetPopulationStatistics(); static unsigned long getNodeCount() { return _voxelNodeCount; } static unsigned long getInternalNodeCount() { return _voxelNodeCount - _voxelNodeLeafCount; } @@ -245,7 +235,6 @@ protected: void calculateAACube(); void notifyDeleteHooks(); - void notifyUpdateHooks(); AACube _cube; /// Client and server, axis aligned box for bounds of this voxel, 48 bytes @@ -292,9 +281,6 @@ protected: static QReadWriteLock _deleteHooksLock; static std::vector _deleteHooks; - //static QReadWriteLock _updateHooksLock; - static std::vector _updateHooks; - static AtomicUIntStat _voxelNodeCount; static AtomicUIntStat _voxelNodeLeafCount; From a5b64473af481adc62d085f1417ae7e56ec1277b Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 25 Nov 2015 16:15:04 -0800 Subject: [PATCH 196/401] Fix bugs --- libraries/audio-client/src/AudioClient.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index d0f2af37af..b141c70272 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -547,8 +547,8 @@ void AudioClient::configureReverb() { p.sampleRate = _outputFormat.sampleRate(); p.roomSize = _reverbOptions->getRoomSize(); p.reverbTime = _reverbOptions->getReverbTime(); - p.highGain = -24.0f * _reverbOptions->getDamping(); - p.bandwidth = 12000.0f * _reverbOptions->getInputBandwidth(); + p.highGain = -24.0f * (1.0f - _reverbOptions->getDamping()); + p.bandwidth = 10000.0f * _reverbOptions->getInputBandwidth(); p.earlyGain = _reverbOptions->getEarlyLevel(); p.lateGain = _reverbOptions->getTailLevel(); p.wetDryMix = 100.0f * powf(10.0f, _reverbOptions->getWetLevel() * (1/20.0f)); @@ -558,7 +558,7 @@ void AudioClient::configureReverb() { p.wetDryMix = 100.0f; p.preDelay = 0.0f; p.earlyGain = -96.0f; // disable ER - p.lateGain -= 6.0f; // quieter than listener reverb + p.lateGain -= 12.0f; // quieter than listener reverb p.lateMixLeft = 0.0f; p.lateMixRight = 0.0f; _sourceReverb.setParameters(&p); @@ -811,7 +811,7 @@ void AudioClient::processReceivedSamples(const QByteArray& inputBuffer, QByteArr _desiredOutputFormat, _outputFormat); // apply stereo reverb at the listener, to the received audio - bool hasReverb = _receivedAudioStream.hasReverb(); + bool hasReverb = _reverb || _receivedAudioStream.hasReverb(); if (hasReverb) { assert(_outputFormat.channelCount() == 2); updateReverbOptions(); From 3273fbcad42f8e4dafc2b117758669d02d89783c Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 25 Nov 2015 17:10:38 -0800 Subject: [PATCH 197/401] Creating the master / agent hiring system --- examples/acScripts/AgentPoolControler.js | 448 +++++++++++++---------- examples/acScripts/playbackMaster.js | 56 +-- 2 files changed, 292 insertions(+), 212 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index 60b906381a..ec0fdf4b87 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -10,235 +10,305 @@ // function printDebug(message) { - print(message); + print(message); } (function() { - var COMMAND_CHANNEL = "com.highfidelity.PlaybackChannel1"; - var ANNOUNCE_CHANNEL = "com.highfidelity.playbackAgent.announceID"; + var COMMAND_CHANNEL = "com.highfidelity.PlaybackChannel1"; + var ANNOUNCE_CHANNEL = "com.highfidelity.playbackAgent.announceID"; - // The time between alive messages on the command channel - var ALIVE_PERIOD = 3; - var NUM_CYCLES_BEFORE_RESET = 5; + // The time between alive messages on the command channel + var ALIVE_PERIOD = 3; + var NUM_CYCLES_BEFORE_RESET = 8; - // Service Actions - var AGENT_READY = "ready"; - var INVALID_ACTOR = -2; + // Service Actions + var MASTER_ID = -1; + var AGENT_READY = "ready"; + var AGENT_LOST = "agentLost"; - var MASTER_INDEX = -1; + var INVALID_ACTOR = -2; - var MASTER_ALIVE = -1; - var MASTER_FIRE_AGENT = -2; - var makeMessage = function(id, action, argument) { - var message = { + var AGENTS_BROADCAST = -1; + var MASTER_ALIVE = -1; + var MASTER_FIRE_AGENT = -2; + + var makeUniqueUUID = function(SEUUID) { + //return SEUUID + Math.random(); + // forget complexity, just give me a four digit pin + return (Math.random() * 10000).toFixed(0); + } + + var packAnnounceMessage = function(dest, command, src) { + var message = { + dest: dest, + command: command, + src: src + }; + return JSON.stringify(message); + }; + + var unpackAnnounceMessage = function(message) { + return JSON.parse(message); + }; + + var packCommandMessage = function(id, action, argument) { + var message = { id_key: id, action_key: action, argument_key: argument - }; - return message; - }; - - var unpackMessage = function(message) { - return JSON.parse(message); - }; - - // master side - //--------------------------------- - var MasterController = function() { - this.timeSinceLastAlive = 0; - this.knownAgents = new Array; - this.subscribed = false; + }; + return JSON.stringify(message); }; - MasterController.prototype.destroy = function() { - if (this.subscribed) { - Messages.unsubscribe(ANNOUNCE_CHANNEL); - Messages.unsubscribe(COMMAND_CHANNEL); - this.subscribed = true; - } - }; + var unpackCommandMessage = function(message) { + return JSON.parse(message); + }; + + // master side + //--------------------------------- + var MasterController = function() { + this.timeSinceLastAlive = 0; + this.knownAgents = new Array; + this.hiringAgentsQueue = new Array; + this.subscribed = false; + }; - MasterController.prototype.reset = function() { - this.timeSinceLastAlive = 0; + MasterController.prototype.destroy = function() { + if (this.subscribed) { + Messages.unsubscribe(ANNOUNCE_CHANNEL); + Messages.unsubscribe(COMMAND_CHANNEL); + this.subscribed = true; + } + }; - if (!this.subscribed) { - Messages.subscribe(COMMAND_CHANNEL); - Messages.subscribe(ANNOUNCE_CHANNEL); - var localThis = this; - Messages.messageReceived.connect(function (channel, message, senderID) { - if (channel == ANNOUNCE_CHANNEL) { - localThis._processAnnounceMessage(message, senderID); - return; - } - }); - } - // ready to roll, enable - this.subscribed = true; - printDebug("Master Started"); + MasterController.prototype.reset = function() { + this.timeSinceLastAlive = 0; + + if (!this.subscribed) { + Messages.subscribe(COMMAND_CHANNEL); + Messages.subscribe(ANNOUNCE_CHANNEL); + var localThis = this; + Messages.messageReceived.connect(function (channel, message, senderID) { + if (channel == ANNOUNCE_CHANNEL) { + localThis._processAnnounceMessage(message, senderID); + return; + } + }); + } + // ready to roll, enable + this.subscribed = true; + printDebug("Master Started"); }; MasterController.prototype._processAnnounceMessage = function(message, senderID) { - if (message == AGENT_READY) { - - // check to see if we know about this agent - if (this.knownAgents.indexOf(senderID) < 0) { - - var indexOfNewAgent = this.knownAgents.length; - this.knownAgents[indexOfNewAgent] = senderID; - printDebug("New agent available to be hired " + senderID); - - var acknowledgeMessage = senderID + "." + indexOfNewAgent; - Messages.sendMessage(ANNOUNCE_CHANNEL, acknowledgeMessage); - } else { - printDebug("New agent still sending ready ? " + senderID); - } - } + var message = unpackAnnounceMessage(message); + if (message.dest == MASTER_ID) { + if (message.command == AGENT_READY) { + // check to see if we know about this agent + var agentIndex = this.knownAgents.indexOf(message.src); + if (agentIndex < 0) { + if (this.hiringAgentsQueue.length > 0) { + var hiringHandler = this.hiringAgentsQueue.pop(); + hiringHandler(message.src); + } else { + //No hiring in queue so bail + return; + } + } else { + // Master think the agent is hired but not the other way around, forget about it + printDebug("New agent still sending ready ? " + message.src + " " + agentIndex + " Forgeting about it"); + this.knownAgents[agentIndex] = INVALID_ACTOR; + } + } else if (message.command == AGENT_LOST) { + // check to see if we know about this agent + var agentIndex = this.knownAgents.indexOf(message.src); + if (agentIndex < 0) { + printDebug("Lost agent " + message.src + " " + agentIndex + " Forgeting about it"); + this.knownAgents[agentIndex] = INVALID_ACTOR; + } + } + } }; MasterController.prototype.sendCommand = function(target, action, argument) { if (this.subscribed) { - var messageJSON = JSON.stringify(makeMessage(target, action, argument)); + var messageJSON = packCommandMessage(target, action, argument); Messages.sendMessage(COMMAND_CHANNEL, messageJSON); - printDebug("Master sent message: " + messageJSON); } - }; - - MasterController.prototype.update = function(deltaTime) { - this.timeSinceLastAlive += deltaTime; - if (this.timeSinceLastAlive > ALIVE_PERIOD) { - this.timeSinceLastAlive = 0; - printDebug("Master ping alive"); - this.sendCommand(MASTER_INDEX, MASTER_ALIVE); - } - }; - - this.MasterController = MasterController; - - // agent side - //--------------------------------- - var AgentController = function() { - this.subscribed = false; - - this.timeSinceLastAlive = 0; - this.numCyclesWithoutAlive = 0; - this.actorIndex = INVALID_ACTOR; - this.notifyAlive = false; - - this.onHired = function() {}; - this.onCommand = function(command) {}; - this.onFired = function() {}; }; - AgentController.prototype.destroy = function() { - if (this.subscribed) { - this.fire(); - Messages.unsubscribe(ANNOUNCE_CHANNEL); - Messages.unsubscribe(COMMAND_CHANNEL); - this.subscribed = true; - } - }; - - AgentController.prototype.reset = function() { - // If already hired, fire - this.fired(); - - if (!this.subscribed) { - Messages.subscribe(COMMAND_CHANNEL); - Messages.subscribe(ANNOUNCE_CHANNEL); - var localThis = this; - Messages.messageReceived.connect(function (channel, message, senderID) { - if (channel == ANNOUNCE_CHANNEL) { - localThis._processAnnounceMessage(message, senderID); - return; - } - if (channel == COMMAND_CHANNEL) { - localThis._processCommandMessage(message, senderID); - return; - } - }); - } - this.subscribed = true; - printDebug("Client Started"); + MasterController.prototype.update = function(deltaTime) { + this.timeSinceLastAlive += deltaTime; + if (this.timeSinceLastAlive > ALIVE_PERIOD) { + this.timeSinceLastAlive = 0; + this.sendCommand(AGENTS_BROADCAST, MASTER_ALIVE); + } }; - AgentController.prototype._processAnnounceMessage = function(message, senderID) { - //printDebug("Client " + this.actorIndex + " Received Announcement = " + message); - if (message != AGENT_READY) { - // this may be a message to hire me if i m not already - if (this.actorIndex == INVALID_ACTOR) { - var parts = message.split("."); - var agentID = parts[0]; - var actorIndex = parts[1]; - //printDebug("Client " + Agent.sessionUUID + " - " + agentID + " Hired!"); - if (agentID == Agent.sessionUUID) { - this.actorIndex = actorIndex; - printDebug("Client " + this.actorIndex + " Hired!"); - this.onHired(); - // Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel - } - } - } - } - AgentController.prototype._processCommandMessage = function(message, senderID) { - var command = unpackMessage(message); - //printDebug("Received command = " + JSON.stringify(command)); + MasterController.prototype.hireAgent = function(onHired) { + var localThis = this; + this.hiringAgentsQueue.unshift(function(agentID) { + printDebug("hiring callback with agent " + agentID); + + var indexOfNewAgent = localThis.knownAgents.length; + localThis.knownAgents[indexOfNewAgent] = agentID; + + printDebug("New agent available to be hired " + agentID + " " + index); + var hireMessage = "HIRE." + index; + var answerMessage = packAnnounceMessage(agentID, hireMessage, MASTER_ID); + Messages.sendMessage(ANNOUNCE_CHANNEL, answerMessage); - if (command.id_key == localThis.actorIndex || command.id_key == MASTER_INDEX) { - if (command.action_key == MASTER_ALIVE) { - this.notifyAlive = true; - } else if (command.action_key == MASTER_FIRE_AGENT) { - printDebug("Master firing Agent"); - this.fire(); - } else { - printDebug("True action received = " + JSON.stringify(command) + senderID); - this.onCommand(command); - } - } else { - // ignored - } + if (onHired != null) { + onHired(index); + } + }) }; - AgentController.prototype.update = function(deltaTime) { - this.timeSinceLastAlive += deltaTime; - if (this.timeSinceLastAlive > ALIVE_PERIOD) { - if (this.subscribed) { - if (this.actorIndex == INVALID_ACTOR) { - Messages.sendMessage(ANNOUNCE_CHANNEL, AGENT_READY); - //printDebug("Client Ready" + ANNOUNCE_CHANNEL + AGENT_READY); - } else { - this.numCyclesWithoutAlive++; - if (this.notifyAlive) { - this.notifyAlive = false; - this.numCyclesWithoutAlive = 0; - printDebug("Master Alive"); - } else if (this.numCyclesWithoutAlive > NUM_CYCLES_BEFORE_RESET) { - printDebug("Master Lost, firing Agent"); - this.fired(); - } - } - } + this.MasterController = MasterController; - this.timeSinceLastAlive = 0; - } - }; + // agent side + //--------------------------------- + var AgentController = function() { + this.subscribed = false; + + this._init(); - AgentController.prototype.fired = function() { - // clear the state first - var wasHired = (this.actorIndex != INVALID_ACTOR); - this.actorIndex= INVALID_ACTOR; + this.onHired = function() {}; + this.onCommand = function(command) {}; + this.onFired = function() {}; + }; + + AgentController.prototype._init = function() { + this.actorIndex= INVALID_ACTOR; this.notifyAlive = false; this.timeSinceLastAlive = 0; this.numCyclesWithoutAlive = 0; + this.actorUUID = makeUniqueUUID(Agent.sessionUUID); + printDebug("this.actorUUID = " + this.actorUUID); + } + + AgentController.prototype.destroy = function() { + if (this.subscribed) { + this.fire(); + Messages.unsubscribe(ANNOUNCE_CHANNEL); + Messages.unsubscribe(COMMAND_CHANNEL); + this.subscribed = true; + } + }; + + AgentController.prototype.reset = function() { + // If already hired, fire + this.fired(); + + if (!this.subscribed) { + Messages.subscribe(COMMAND_CHANNEL); + Messages.subscribe(ANNOUNCE_CHANNEL); + var localThis = this; + Messages.messageReceived.connect(function (channel, message, senderID) { + if (channel == ANNOUNCE_CHANNEL) { + localThis._processAnnounceMessage(message, senderID); + return; + } + if (channel == COMMAND_CHANNEL) { + localThis._processCommandMessage(message, senderID); + return; + } + }); + } + this.subscribed = true; + printDebug("Client Started"); + }; + + AgentController.prototype._processAnnounceMessage = function(message, senderID) { + var announce = unpackCommandMessage(message); + //printDebug("Client " + this.actorIndex + " Received Announcement = " + message); + if (announce.dest == this.actorUUID) { + if (announce.command != AGENT_READY) { + // this may be a message to hire me if i m not already + if (this.actorIndex == INVALID_ACTOR) { + printDebug(announce.command); + + var parts = announce.command.split("."); + var agentID = parts[0]; + var actorIndex = parts[1]; + //printDebug("Client " + Agent.sessionUUID + " - " + agentID + " Hired!"); + // if (agentID == Agent.sessionUUID) { + this.actorIndex = actorIndex; + printDebug("Client " + this.actorIndex + " Hired!"); + this.onHired(); + // Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel + // } + } + } + } + } + + AgentController.prototype._processCommandMessage = function(message, senderID) { + var command = unpackCommandMessage(message); + //printDebug("Received command = " + JSON.stringify(command)); + + if ((command.id_key == this.actorUUID) || (command.id_key == AGENTS_BROADCAST)) { + if (command.action_key == MASTER_ALIVE) { + this.notifyAlive = true; + } else if (command.action_key == MASTER_FIRE_AGENT) { + printDebug("Master firing Agent"); + this.fire(); + } else { + printDebug("True action received = " + JSON.stringify(command) + senderID); + this.onCommand(command); + } + } else { + // ignored + } + }; + + + AgentController.prototype.update = function(deltaTime) { + this.timeSinceLastAlive += deltaTime; + if (this.timeSinceLastAlive > ALIVE_PERIOD) { + if (this.subscribed) { + if (this.actorIndex == INVALID_ACTOR) { + Messages.sendMessage(ANNOUNCE_CHANNEL, packAnnounceMessage(MASTER_ID, AGENT_READY, this.actorUUID)); + //printDebug("Client Ready" + ANNOUNCE_CHANNEL + AGENT_READY); + } else { + this.numCyclesWithoutAlive++; + if (this.notifyAlive) { + this.notifyAlive = false; + this.numCyclesWithoutAlive = 0; + printDebug("Master Alive"); + } else if (this.numCyclesWithoutAlive > NUM_CYCLES_BEFORE_RESET) { + printDebug("Master Lost, firing Agent"); + this.fired(); + } + } + } + + this.timeSinceLastAlive = 0; + } + }; + + AgentController.prototype.fired = function() { + // clear the state first + var wasHired = (this.actorIndex != INVALID_ACTOR); + + // Post a last message to master in case it still listen to warn that this agent is losing it + if (wasHired) { + Messages.sendMessage(ANNOUNCE_CHANNEL, packAnnounceMessage(MASTER_ID, AGENT_LOST, this.actorUUID)); + } + + // reset + this._init(); + // then custom fire if was hired - if (wasHired) { - this.onFired(); - } - } + if (wasHired) { + this.onFired(); + } + } - this.AgentController = AgentController; + this.AgentController = AgentController; })(); diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 1444ae3cf1..929f384514 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -54,13 +54,23 @@ var performanceLoadedNeedUpdate = false; setupPlayback(); +function onHiring(agentID, index) { + print("agent hired from playbackMaster! " + agentID + " " + index) +} + function setupPlayback() { ac_number = Window.prompt("Insert number of agents: ","1"); if (ac_number === "" || ac_number === null) { ac_number = 1; - } - setupToolBars(); + } masterController.reset(); + + for (var i = 0; i < ac_number; i++) { + masterController.hireAgent(onHiring); + } + + setupToolBars(); + } function setupToolBars() { @@ -96,13 +106,13 @@ function setupToolBars() { var playLoopWidthFactor = 1.65; playLoopIcon[i] = toolBars[i].addTool({ - imageURL: TOOL_ICON_URL + "play-and-loop.svg", - subImage: { x: 0, y: 0, width: playLoopWidthFactor * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - width: playLoopWidthFactor * Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: ALPHA_OFF, - visible: true - }, false); + imageURL: TOOL_ICON_URL + "play-and-loop.svg", + subImage: { x: 0, y: 0, width: playLoopWidthFactor * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + width: playLoopWidthFactor * Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); stopIcon[i] = toolBars[i].addTool({ imageURL: TOOL_ICON_URL + "recording-stop.svg", @@ -121,20 +131,20 @@ function setupToolBars() { }, false); nameOverlays.push(Overlays.addOverlay("text", { - backgroundColor: { red: 0, green: 0, blue: 0 }, - font: { size: TEXT_HEIGHT }, - text: (i == ac_number) ? "Master" : i + ". " + - ((i < names.length) ? names[i] : - "AC" + i), - x: 0, y: 0, - width: toolBars[i].width + ToolBar.SPACING, - height: TEXT_HEIGHT + TEXT_MARGIN, - leftMargin: TEXT_MARGIN, - topMargin: TEXT_MARGIN, - alpha: ALPHA_OFF, - backgroundAlpha: ALPHA_OFF, - visible: true - })); + backgroundColor: { red: 0, green: 0, blue: 0 }, + font: { size: TEXT_HEIGHT }, + text: (i == ac_number) ? "Master" : i + ". " + + ((i < names.length) ? names[i] : + "AC" + i), + x: 0, y: 0, + width: toolBars[i].width + ToolBar.SPACING, + height: TEXT_HEIGHT + TEXT_MARGIN, + leftMargin: TEXT_MARGIN, + topMargin: TEXT_MARGIN, + alpha: ALPHA_OFF, + backgroundAlpha: ALPHA_OFF, + visible: true + })); } } From a364e85e1dec5285b0350134274c3e32e080ec6d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 25 Nov 2015 17:21:56 -0800 Subject: [PATCH 198/401] Remove DeleteHooks --- .../src/octree/OctreeQueryNode.cpp | 2 - .../src/octree/OctreeSendThread.h | 1 - libraries/entities/src/EntityTree.cpp | 7 +--- libraries/entities/src/EntityTreeElement.cpp | 23 +--------- libraries/octree/src/OctreeElement.cpp | 33 --------------- libraries/octree/src/OctreeElement.h | 22 ++-------- libraries/octree/src/OctreeElementBag.cpp | 42 ++++--------------- libraries/octree/src/OctreeElementBag.h | 12 ++---- 8 files changed, 18 insertions(+), 124 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index f70ff62f91..10f1d2ec14 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -59,7 +59,6 @@ OctreeQueryNode::~OctreeQueryNode() { void OctreeQueryNode::nodeKilled() { _isShuttingDown = true; - elementBag.unhookNotifications(); // if our node is shutting down, then we no longer need octree element notifications if (_octreeSendThread) { // just tell our thread we want to shutdown, this is asynchronous, and fast, we don't need or want it to block // while the thread actually shuts down @@ -69,7 +68,6 @@ void OctreeQueryNode::nodeKilled() { void OctreeQueryNode::forceNodeShutdown() { _isShuttingDown = true; - elementBag.unhookNotifications(); // if our node is shutting down, then we no longer need octree element notifications if (_octreeSendThread) { // we really need to force our thread to shutdown, this is synchronous, we will block while the thread actually // shuts down because we really need it to shutdown, and it's ok if we wait for it to complete diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index 6e640942e7..6775e56820 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -17,7 +17,6 @@ #include #include -#include #include "OctreeQueryNode.h" diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 9eac14e4b4..5ac892de94 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -44,12 +44,7 @@ void EntityTree::createRootElement() { } OctreeElementPointer EntityTree::createNewElement(unsigned char* octalCode) { - EntityTreeElementPointer newElement = EntityTreeElementPointer(new EntityTreeElement(octalCode), - // see comment int EntityTreeElement::createNewElement - [=](EntityTreeElement* dyingElement) { - EntityTreeElementPointer tmpSharedPointer(dyingElement); - dyingElement->notifyDeleteHooks(); - }); + auto newElement = EntityTreeElementPointer(new EntityTreeElement(octalCode)); newElement->setTree(std::static_pointer_cast(shared_from_this())); return std::static_pointer_cast(newElement); } diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 02552ef488..8403db8b2f 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -28,29 +28,8 @@ EntityTreeElement::~EntityTreeElement() { _octreeMemoryUsage -= sizeof(EntityTreeElement); } -// This will be called primarily on addChildAt(), which means we're adding a child of our -// own type to our own tree. This means we should initialize that child with any tree and type -// specific settings that our children must have. OctreeElementPointer EntityTreeElement::createNewElement(unsigned char* octalCode) { - EntityTreeElementPointer newChild = - EntityTreeElementPointer(new EntityTreeElement(octalCode), - // This is a little bit horrible, but I haven't found a better way. The OctreeElement - // destructor used to call notifyDeleteHooks(), which calls zero or more of - // OctreeElementDeleteHook::elementDeleted - // which (now) expects an OctreeElementPointer argument. The destructor doesn't have - // access to the shared pointer (which has had its reference count drop to zero, - // or the destructor wouldn't have been called). The destructor also can't - // make a new shared pointer -- shared_from_this() is forbidden in a destructor, and - // using OctreeElementPointer(this) also fails. So, I've installed a custom deleter: - [=](EntityTreeElement* dyingElement) { - // make a new shared pointer with a reference count of 1 (and no custom deleter) - EntityTreeElementPointer tmpSharedPointer(dyingElement); - // call notifyDeleteHooks which will use shared_from_this() to get this same - // shared pointer, for use with the elementDeleted calls. - dyingElement->notifyDeleteHooks(); - // And now tmpSharedPointer's reference count drops to zero and the - // normal destructors are called. - }); + auto newChild = EntityTreeElementPointer(new EntityTreeElement(octalCode)); newChild->setTree(_myTree); return newChild; } diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 1313dc499d..f16e1dc88d 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -95,10 +95,6 @@ void OctreeElement::init(unsigned char * octalCode) { } OctreeElement::~OctreeElement() { - // We can't call notifyDeleteHooks from here: - // notifyDeleteHooks(); - // see comment in EntityTreeElement::createNewElement. - assert(_deleteHooksNotified); _voxelNodeCount--; if (isLeaf()) { _voxelNodeLeafCount--; @@ -521,35 +517,6 @@ float OctreeElement::distanceToPoint(const glm::vec3& point) const { return distance; } -QReadWriteLock OctreeElement::_deleteHooksLock; -std::vector OctreeElement::_deleteHooks; - -void OctreeElement::addDeleteHook(OctreeElementDeleteHook* hook) { - _deleteHooksLock.lockForWrite(); - _deleteHooks.push_back(hook); - _deleteHooksLock.unlock(); -} - -void OctreeElement::removeDeleteHook(OctreeElementDeleteHook* hook) { - _deleteHooksLock.lockForWrite(); - for (unsigned int i = 0; i < _deleteHooks.size(); i++) { - if (_deleteHooks[i] == hook) { - _deleteHooks.erase(_deleteHooks.begin() + i); - break; - } - } - _deleteHooksLock.unlock(); -} - -void OctreeElement::notifyDeleteHooks() { - _deleteHooksLock.lockForRead(); - for (unsigned int i = 0; i < _deleteHooks.size(); i++) { - _deleteHooks[i]->elementDeleted(shared_from_this()); - } - _deleteHooksLock.unlock(); - _deleteHooksNotified = true; -} - bool OctreeElement::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject) const { // center and radius are in meters, so we have to scale the _cube into world-frame diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index ed92e8a193..c686970c3a 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -33,20 +33,15 @@ class EncodeBitstreamParams; class Octree; class OctreeElement; class OctreeElementBag; -class OctreeElementDeleteHook; class OctreePacketData; class ReadBitstreamToTreeParams; class Shape; class VoxelSystem; -typedef std::shared_ptr OctreeElementPointer; -typedef std::shared_ptr ConstOctreeElementPointer; -typedef std::shared_ptr OctreePointer; -// Callers who want delete hook callbacks should implement this class -class OctreeElementDeleteHook { -public: - virtual void elementDeleted(OctreeElementPointer element) = 0; -}; +using OctreeElementPointer = std::shared_ptr; +using OctreeElementWeakPointer = std::weak_ptr; +using ConstOctreeElementPointer = std::shared_ptr; +using OctreePointer = std::shared_ptr; class OctreeElement: public std::enable_shared_from_this { @@ -174,9 +169,6 @@ public: bool matchesSourceUUID(const QUuid& sourceUUID) const; static uint16_t getSourceNodeUUIDKey(const QUuid& sourceUUID); - static void addDeleteHook(OctreeElementDeleteHook* hook); - static void removeDeleteHook(OctreeElementDeleteHook* hook); - static void resetPopulationStatistics(); static unsigned long getNodeCount() { return _voxelNodeCount; } static unsigned long getInternalNodeCount() { return _voxelNodeCount - _voxelNodeLeafCount; } @@ -234,7 +226,6 @@ protected: void setChildAtIndex(int childIndex, OctreeElementPointer child); void calculateAACube(); - void notifyDeleteHooks(); AACube _cube; /// Client and server, axis aligned box for bounds of this voxel, 48 bytes @@ -276,11 +267,6 @@ protected: _unknownBufferIndex : 1, _childrenExternal : 1; /// Client only, is this voxel's VBO buffer the unknown buffer index, 1 bit - bool _deleteHooksNotified = false; - - static QReadWriteLock _deleteHooksLock; - static std::vector _deleteHooks; - static AtomicUIntStat _voxelNodeCount; static AtomicUIntStat _voxelNodeLeafCount; diff --git a/libraries/octree/src/OctreeElementBag.cpp b/libraries/octree/src/OctreeElementBag.cpp index 5af63c7bb1..167c3560d6 100644 --- a/libraries/octree/src/OctreeElementBag.cpp +++ b/libraries/octree/src/OctreeElementBag.cpp @@ -12,54 +12,30 @@ #include "OctreeElementBag.h" #include -OctreeElementBag::OctreeElementBag() : - _bagElements() -{ - OctreeElement::addDeleteHook(this); - _hooked = true; -} - -OctreeElementBag::~OctreeElementBag() { - unhookNotifications(); - deleteAll(); -} - -void OctreeElementBag::unhookNotifications() { - if (_hooked) { - OctreeElement::removeDeleteHook(this); - _hooked = false; - } -} - -void OctreeElementBag::elementDeleted(OctreeElementPointer element) { - remove(element); // note: remove can safely handle nodes that aren't in it, so we don't need to check contains() -} - - void OctreeElementBag::deleteAll() { _bagElements.clear(); } - void OctreeElementBag::insert(OctreeElementPointer element) { - _bagElements.insert(element); + _bagElements.insert(element.get(), element); } OctreeElementPointer OctreeElementBag::extract() { - OctreeElementPointer result = NULL; + OctreeElementPointer result; - if (_bagElements.size() > 0) { - QSet::iterator front = _bagElements.begin(); - result = *front; - _bagElements.erase(front); + // Find the first element still alive + while (!_bagElements.empty() && !result) { + auto it = _bagElements.begin(); + result = it->lock(); + _bagElements.erase(it); } return result; } bool OctreeElementBag::contains(OctreeElementPointer element) { - return _bagElements.contains(element); + return _bagElements.contains(element.get()); } void OctreeElementBag::remove(OctreeElementPointer element) { - _bagElements.remove(element); + _bagElements.remove(element.get()); } diff --git a/libraries/octree/src/OctreeElementBag.h b/libraries/octree/src/OctreeElementBag.h index 8ef01b44a2..b5f4d5dcf5 100644 --- a/libraries/octree/src/OctreeElementBag.h +++ b/libraries/octree/src/OctreeElementBag.h @@ -17,12 +17,10 @@ #define hifi_OctreeElementBag_h #include "OctreeElement.h" +#include -class OctreeElementBag : public OctreeElementDeleteHook { - +class OctreeElementBag { public: - OctreeElementBag(); - ~OctreeElementBag(); void insert(OctreeElementPointer element); // put a element into the bag OctreeElementPointer extract(); // pull a element out of the bag (could come in any order) @@ -32,13 +30,9 @@ public: int count() const { return _bagElements.size(); } void deleteAll(); - virtual void elementDeleted(OctreeElementPointer element); - - void unhookNotifications(); private: - QSet _bagElements; - bool _hooked; + QHash _bagElements; }; typedef QMap OctreeElementExtraEncodeData; From a40ead077fb4df79b26563a502002ec1144f6992 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 25 Nov 2015 20:37:51 -0800 Subject: [PATCH 199/401] Mouth animation improvements --- interface/src/avatar/Head.cpp | 47 ++++++++++++++++++++--------------- interface/src/avatar/Head.h | 2 ++ 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index e8452583fc..b214ba2976 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -43,9 +43,11 @@ Head::Head(Avatar* owningAvatar) : _longTermAverageLoudness(-1.0f), _audioAttack(0.0f), _audioJawOpen(0.0f), + _trailingAudioJawOpen(0.0f), _mouth2(0.0f), _mouth3(0.0f), _mouth4(0.0f), + _mouthTime(0.0f), _renderLookatVectors(false), _renderLookatTarget(false), _saccade(0.0f, 0.0f, 0.0f), @@ -246,28 +248,33 @@ void Head::calculateMouthShapes() { const float JAW_OPEN_SCALE = 0.015f; const float JAW_OPEN_RATE = 0.9f; const float JAW_CLOSE_RATE = 0.90f; - float audioDelta = sqrtf(glm::max(_averageLoudness - _longTermAverageLoudness, 0.0f)) * JAW_OPEN_SCALE; - if (audioDelta > _audioJawOpen) { - _audioJawOpen += (audioDelta - _audioJawOpen) * JAW_OPEN_RATE; - } else { - _audioJawOpen *= JAW_CLOSE_RATE; - } - _audioJawOpen = glm::clamp(_audioJawOpen, 0.0f, 1.0f); + const float TIMESTEP_CONSTANT = 0.0032f; + const float MMMM_POWER = 0.10f; + const float SMILE_POWER = 0.10f; + const float FUNNEL_POWER = 0.35f; + const float MMMM_SPEED = 2.685f; + const float SMILE_SPEED = 1.0f; + const float FUNNEL_SPEED = 2.335f; + const float STOP_GAIN = 5.0f; - // _mouth2 = "mmmm" shape - // _mouth3 = "funnel" shape - // _mouth4 = "smile" shape - const float FUNNEL_PERIOD = 0.985f; - const float FUNNEL_RANDOM_PERIOD = 0.01f; - const float MMMM_POWER = 0.25f; - const float MMMM_PERIOD = 0.91f; - const float MMMM_RANDOM_PERIOD = 0.15f; - const float SMILE_PERIOD = 0.925f; - const float SMILE_RANDOM_PERIOD = 0.05f; + // From the change in loudness, decide how much to open or close the jaw + float audioDelta = sqrtf(glm::max(_averageLoudness - _longTermAverageLoudness, 0.0f)) * JAW_OPEN_SCALE; + if (audioDelta > _audioJawOpen) { + _audioJawOpen += (audioDelta - _audioJawOpen) * JAW_OPEN_RATE; + } + else { + _audioJawOpen *= JAW_CLOSE_RATE; + } + _audioJawOpen = glm::clamp(_audioJawOpen, 0.0f, 1.0f); + _trailingAudioJawOpen = glm::mix(_trailingAudioJawOpen, _audioJawOpen, 0.99f); + + // Advance time at a rate proportional to loudness, and move the mouth shapes through + // a cycle at differing speeds to create a continuous random blend of shapes. + _mouthTime += sqrtf(_averageLoudness) * TIMESTEP_CONSTANT; + _mouth2 = (sinf(_mouthTime * MMMM_SPEED) + 1.0f) * MMMM_POWER * glm::min(1.0f, _trailingAudioJawOpen * STOP_GAIN); + _mouth3 = (sinf(_mouthTime * FUNNEL_SPEED) + 1.0f) * FUNNEL_POWER * glm::min(1.0f, _trailingAudioJawOpen * STOP_GAIN); + _mouth4 = (sinf(_mouthTime * SMILE_SPEED) + 1.0f) * SMILE_POWER * glm::min(1.0f, _trailingAudioJawOpen * STOP_GAIN); - _mouth3 = glm::mix(_audioJawOpen, _mouth3, FUNNEL_PERIOD + randFloat() * FUNNEL_RANDOM_PERIOD); - _mouth2 = glm::mix(_audioJawOpen * MMMM_POWER, _mouth2, MMMM_PERIOD + randFloat() * MMMM_RANDOM_PERIOD); - _mouth4 = glm::mix(_audioJawOpen, _mouth4, SMILE_PERIOD + randFloat() * SMILE_RANDOM_PERIOD); } void Head::applyEyelidOffset(glm::quat headOrientation) { diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 1fbfceca92..93637b7d3c 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -124,9 +124,11 @@ private: float _longTermAverageLoudness; float _audioAttack; float _audioJawOpen; + float _trailingAudioJawOpen; float _mouth2; float _mouth3; float _mouth4; + float _mouthTime; bool _renderLookatVectors; bool _renderLookatTarget; glm::vec3 _saccade; From 37d3083e079ae183c63c27a9d383ccfb009e712a Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Thu, 26 Nov 2015 00:41:46 -0800 Subject: [PATCH 200/401] Getting the Actor class starting to work and usable for the playback master! --- examples/acScripts/AgentPoolControler.js | 40 ++++++++++++++++++------ examples/acScripts/playbackMaster.js | 19 ++++++++--- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index ec0fdf4b87..d528fc70fe 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -65,11 +65,22 @@ function printDebug(message) { return JSON.parse(message); }; + // Actor + //--------------------------------- + var Actor = function() { + this.agentID = INVALID_ACTOR; + this.onHired = function(actor) {}; + this.onLost = function(actor) {}; + }; + + this.Actor = Actor; + // master side //--------------------------------- var MasterController = function() { this.timeSinceLastAlive = 0; this.knownAgents = new Array; + this.hiredActors = new Array; this.hiringAgentsQueue = new Array; this.subscribed = false; }; @@ -126,6 +137,10 @@ function printDebug(message) { if (agentIndex < 0) { printDebug("Lost agent " + message.src + " " + agentIndex + " Forgeting about it"); this.knownAgents[agentIndex] = INVALID_ACTOR; + var lostActor = this.hiredActors[agentIndex]; + this.hiredActors[agentIndex] = null; + lostActor.agentID = INVALID_ACTOR; + lostActor.onLost(lostActor); } } } @@ -147,22 +162,27 @@ function printDebug(message) { }; - MasterController.prototype.hireAgent = function(onHired) { + MasterController.prototype.hireAgent = function(actor) { + if (actor == null) { + printDebug("trying to hire an agent with a null actor, abort"); + return; + } var localThis = this; this.hiringAgentsQueue.unshift(function(agentID) { - printDebug("hiring callback with agent " + agentID); - - var indexOfNewAgent = localThis.knownAgents.length; - localThis.knownAgents[indexOfNewAgent] = agentID; + printDebug("hiring callback with agent " + agentID+ " " + JSON.stringify(localThis) ); + + var indexOfNewAgent = localThis.knownAgents.push(agentID) + actor.agentID = agentID; + localThis.hiredActors.push(actor); - printDebug("New agent available to be hired " + agentID + " " + index); - var hireMessage = "HIRE." + index; + printDebug("New agent available to be hired " + agentID + " " + indexOfNewAgent); + var hireMessage = "HIRE." + indexOfNewAgent; var answerMessage = packAnnounceMessage(agentID, hireMessage, MASTER_ID); Messages.sendMessage(ANNOUNCE_CHANNEL, answerMessage); + + printDebug("message sent calling the actor" + JSON.stringify(actor) ); - if (onHired != null) { - onHired(index); - } + actor.onHired(actor); }) }; diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 929f384514..3e60fc7a0e 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -17,7 +17,7 @@ var masterController = new MasterController(); var ac_number = 1; // This is the default number of ACs. Their ID need to be unique and between 0 (included) and ac_number (excluded) var names = new Array(); // It is possible to specify the name of the ACs in this array. ACs names ordered by IDs (Default name is "ACx", x = ID + 1)) var input_text = null; - +var actors = new Array(); // Script. DO NOT MODIFY BEYOND THIS LINE. //Script.include("../libraries/toolBars.js"); @@ -54,8 +54,14 @@ var performanceLoadedNeedUpdate = false; setupPlayback(); -function onHiring(agentID, index) { - print("agent hired from playbackMaster! " + agentID + " " + index) +function onActorHired(actor) { + print("agent hired from playbackMaster! " + actor.agentID + " " + actor.index) +} + +function onActorLost(actor) { + print("agent lost from playbackMaster! " + actor.agentID + " " + actor.index) + + actors[actor.index] = null; } function setupPlayback() { @@ -66,7 +72,12 @@ function setupPlayback() { masterController.reset(); for (var i = 0; i < ac_number; i++) { - masterController.hireAgent(onHiring); + var newActor = new Actor(); + newActor.index = i; + newActor.onHired = onActorHired; + newActor.onLost = onActorLost; + masterController.hireAgent(newActor); + actors.push(newActor); } setupToolBars(); From 7df984e7b207528477d04a3e6eab5477573668f2 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 26 Nov 2015 05:30:01 -0800 Subject: [PATCH 201/401] fix deadlock when setting parentID to null --- interface/src/InterfaceParentFinder.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/InterfaceParentFinder.cpp b/interface/src/InterfaceParentFinder.cpp index 1703ffc5d1..112bae5bb8 100644 --- a/interface/src/InterfaceParentFinder.cpp +++ b/interface/src/InterfaceParentFinder.cpp @@ -19,6 +19,10 @@ SpatiallyNestableWeakPointer InterfaceParentFinder::find(QUuid parentID) const { SpatiallyNestableWeakPointer parent; + if (parentID.isNull()) { + return parent; + } + // search entities EntityTreeRenderer* treeRenderer = qApp->getEntities(); EntityTreePointer tree = treeRenderer->getTree(); From 36e293608a009ec6b1d067f8351673c728e6e555 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 26 Nov 2015 05:31:52 -0800 Subject: [PATCH 202/401] more adding parentID to edit.js --- examples/html/entityProperties.html | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index bc6a6920d1..50fb205e3d 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -223,7 +223,9 @@ var elDimensionsZ = document.getElementById("property-dim-z"); var elResetToNaturalDimensions = document.getElementById("reset-to-natural-dimensions"); var elRescaleDimensionsPct = document.getElementById("dimension-rescale-pct"); - var elRescaleDimensionsButton = document.getElementById("dimension-rescale-button"); + var elRescaleDimensionsButton = document.getElementById("dimension-rescale-button"); + + var elParentID = document.getElementById("parent-id"); var elRegistrationX = document.getElementById("property-reg-x"); var elRegistrationY = document.getElementById("property-reg-y"); @@ -453,6 +455,8 @@ elDimensionsY.value = properties.dimensions.y.toFixed(2); elDimensionsZ.value = properties.dimensions.z.toFixed(2); + elParentID.value = properties.parentID; + elRegistrationX.value = properties.registrationPoint.x.toFixed(2); elRegistrationY.value = properties.registrationPoint.y.toFixed(2); elRegistrationZ.value = properties.registrationPoint.z.toFixed(2); @@ -666,6 +670,8 @@ elDimensionsY.addEventListener('change', dimensionsChangeFunction); elDimensionsZ.addEventListener('change', dimensionsChangeFunction); + elParentID.addEventListener('change', createEmitTextPropertyUpdateFunction('parentID)); + var registrationChangeFunction = createEmitVec3PropertyUpdateFunction( 'registrationPoint', elRegistrationX, elRegistrationY, elRegistrationZ); elRegistrationX.addEventListener('change', registrationChangeFunction); @@ -1055,6 +1061,13 @@ +
+ ParentID +
+ +
+
+
Registration
From 10cf85bad975090e01cb95da7edbf2b815af7c0f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 26 Nov 2015 07:02:53 -0800 Subject: [PATCH 203/401] fix some rotation handling in EntityItem, minimize diff vs master --- libraries/entities/src/EntityItem.cpp | 132 +++++++++++++------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index c0dd79d00e..d60df17d78 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -241,7 +241,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_SIMULATION_OWNER, _simulationOwner.toByteArray()); APPEND_ENTITY_PROPERTY(PROP_POSITION, getLocalPosition()); - APPEND_ENTITY_PROPERTY(PROP_ROTATION, getRotation()); + APPEND_ENTITY_PROPERTY(PROP_ROTATION, getLocalOrientation()); APPEND_ENTITY_PROPERTY(PROP_VELOCITY, getVelocity()); APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, getAngularVelocity()); APPEND_ENTITY_PROPERTY(PROP_ACCELERATION, getAcceleration()); @@ -1045,7 +1045,7 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper COPY_ENTITY_PROPERTY_TO_PROPERTIES(simulationOwner, getSimulationOwner); COPY_ENTITY_PROPERTY_TO_PROPERTIES(position, getLocalPosition); COPY_ENTITY_PROPERTY_TO_PROPERTIES(dimensions, getDimensions); // NOTE: radius is obsolete - COPY_ENTITY_PROPERTY_TO_PROPERTIES(rotation, getRotation); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(rotation, getLocalOrientation); COPY_ENTITY_PROPERTY_TO_PROPERTIES(density, getDensity); COPY_ENTITY_PROPERTY_TO_PROPERTIES(velocity, getVelocity); COPY_ENTITY_PROPERTY_TO_PROPERTIES(gravity, getGravity); @@ -1085,7 +1085,7 @@ void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) c // a TerseUpdate includes the transform and its derivatives properties._position = getLocalPosition(); properties._velocity = _velocity; - properties._rotation = getRotation(); + properties._rotation = getLocalOrientation(); properties._angularVelocity = _angularVelocity; properties._acceleration = _acceleration; @@ -1314,27 +1314,6 @@ void EntityItem::computeShapeInfo(ShapeInfo& info) { info.setParams(getShapeType(), 0.5f * getDimensions()); } -void EntityItem::forSelfAndEachChildEntity(std::function actor) { - QQueue toProcess; - toProcess.enqueue(shared_from_this()); - - while (!toProcess.empty()) { - EntityItemPointer entity = std::static_pointer_cast(toProcess.dequeue()); - actor(entity); - foreach (SpatiallyNestablePointer child, entity->getChildren()) { - if (child && child->getNestableType() == NestableTypes::Entity) { - toProcess.enqueue(child); - } - } - } -} - -void EntityItem::parentChanged() { - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - void EntityItem::updatePosition(const glm::vec3& value) { if (shouldSuppressLocationEdits()) { return; @@ -1347,34 +1326,6 @@ void EntityItem::updatePosition(const glm::vec3& value) { } } -void EntityItem::setTransform(const Transform& transform) { - SpatiallyNestable::setTransform(transform); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - -void EntityItem::setLocalTransform(const Transform& transform) { - SpatiallyNestable::setLocalTransform(transform); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - -void EntityItem::setPosition(const glm::vec3& position) { - SpatiallyNestable::setPosition(position); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - -void EntityItem::setLocalPosition(const glm::vec3& position) { - SpatiallyNestable::setLocalPosition(position); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - void EntityItem::updateRotation(const glm::quat& rotation) { if (shouldSuppressLocationEdits()) { return; @@ -1390,20 +1341,6 @@ void EntityItem::updateRotation(const glm::quat& rotation) { } } -void EntityItem::setRotation(const glm::quat& orientation) { - SpatiallyNestable::setOrientation(orientation); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - -void EntityItem::setLocalRotation(const glm::quat& orientation) { - SpatiallyNestable::setLocalOrientation(orientation); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - void EntityItem::updateDimensions(const glm::vec3& value) { if (getDimensions() != value) { setDimensions(value); @@ -1901,3 +1838,66 @@ QList EntityItem::getActionsOfType(EntityActionType typeToG return result; } + +void EntityItem::forSelfAndEachChildEntity(std::function actor) { + QQueue toProcess; + toProcess.enqueue(shared_from_this()); + + while (!toProcess.empty()) { + EntityItemPointer entity = std::static_pointer_cast(toProcess.dequeue()); + actor(entity); + foreach (SpatiallyNestablePointer child, entity->getChildren()) { + if (child && child->getNestableType() == NestableTypes::Entity) { + toProcess.enqueue(child); + } + } + } +} + +void EntityItem::parentChanged() { + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + +void EntityItem::setTransform(const Transform& transform) { + SpatiallyNestable::setTransform(transform); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + +void EntityItem::setLocalTransform(const Transform& transform) { + SpatiallyNestable::setLocalTransform(transform); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + +void EntityItem::setPosition(const glm::vec3& position) { + SpatiallyNestable::setPosition(position); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + +void EntityItem::setLocalPosition(const glm::vec3& position) { + SpatiallyNestable::setLocalPosition(position); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + +void EntityItem::setRotation(const glm::quat& orientation) { + SpatiallyNestable::setOrientation(orientation); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} + +void EntityItem::setLocalRotation(const glm::quat& orientation) { + SpatiallyNestable::setLocalOrientation(orientation); + forSelfAndEachChildEntity([&](EntityItemPointer entity) { + entity->requiresRecalcBoxes(); + }); +} From 6062691c2a58f42486a1e28d975818582eb8e144 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 26 Nov 2015 07:04:27 -0800 Subject: [PATCH 204/401] minimize diff vs master --- libraries/entities/src/EntityItem.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index d60df17d78..24b0e7f977 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1326,6 +1326,13 @@ void EntityItem::updatePosition(const glm::vec3& value) { } } +void EntityItem::updateDimensions(const glm::vec3& value) { + if (getDimensions() != value) { + setDimensions(value); + _dirtyFlags |= (Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS); + } +} + void EntityItem::updateRotation(const glm::quat& rotation) { if (shouldSuppressLocationEdits()) { return; @@ -1341,13 +1348,6 @@ void EntityItem::updateRotation(const glm::quat& rotation) { } } -void EntityItem::updateDimensions(const glm::vec3& value) { - if (getDimensions() != value) { - setDimensions(value); - _dirtyFlags |= (Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS); - } -} - void EntityItem::updateMass(float mass) { // Setting the mass actually changes the _density (at fixed volume), however // we must protect the density range to help maintain stability of physics simulation From facf91faacf7cf6f9e5ec85ed2b91f4b7fcd8191 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 26 Nov 2015 07:13:43 -0800 Subject: [PATCH 205/401] minimize diff vs master --- libraries/avatars/src/AvatarData.cpp | 82 ++++++++++++++-------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index f7def48b9d..adfd10b2af 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -87,47 +87,6 @@ const QUrl& AvatarData::defaultFullAvatarModelUrl() { return _defaultFullAvatarModelUrl; } -float AvatarData::getBodyYaw() const { - glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); - return eulerAngles.y; -} - -void AvatarData::setBodyYaw(float bodyYaw) { - glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); - eulerAngles.y = bodyYaw; - setOrientation(glm::quat(glm::radians(eulerAngles))); -} - -float AvatarData::getBodyPitch() const { - glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); - return eulerAngles.x; -} - -void AvatarData::setBodyPitch(float bodyPitch) { - glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); - eulerAngles.x = bodyPitch; - setOrientation(glm::quat(glm::radians(eulerAngles))); -} - -float AvatarData::getBodyRoll() const { - glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); - return eulerAngles.z; -} - -void AvatarData::setBodyRoll(float bodyRoll) { - glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); - eulerAngles.z = bodyRoll; - setOrientation(glm::quat(glm::radians(eulerAngles))); -} - -void AvatarData::setPosition(const glm::vec3& position) { - SpatiallyNestable::setPosition(position); -} - -void AvatarData::setOrientation(const glm::quat& orientation) { - SpatiallyNestable::setOrientation(orientation); -} - // There are a number of possible strategies for this set of tools through endRender, below. void AvatarData::nextAttitude(glm::vec3 position, glm::quat orientation) { avatarLock.lock(); @@ -1616,3 +1575,44 @@ void AvatarData::fromFrame(const QByteArray& frameData, AvatarData& result) { #endif result.fromJson(doc.object()); } + +float AvatarData::getBodyYaw() const { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + return eulerAngles.y; +} + +void AvatarData::setBodyYaw(float bodyYaw) { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + eulerAngles.y = bodyYaw; + setOrientation(glm::quat(glm::radians(eulerAngles))); +} + +float AvatarData::getBodyPitch() const { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + return eulerAngles.x; +} + +void AvatarData::setBodyPitch(float bodyPitch) { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + eulerAngles.x = bodyPitch; + setOrientation(glm::quat(glm::radians(eulerAngles))); +} + +float AvatarData::getBodyRoll() const { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + return eulerAngles.z; +} + +void AvatarData::setBodyRoll(float bodyRoll) { + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + eulerAngles.z = bodyRoll; + setOrientation(glm::quat(glm::radians(eulerAngles))); +} + +void AvatarData::setPosition(const glm::vec3& position) { + SpatiallyNestable::setPosition(position); +} + +void AvatarData::setOrientation(const glm::quat& orientation) { + SpatiallyNestable::setOrientation(orientation); +} From eb50c9de5f7b74966e0a07822c08db12ea620154 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 29 Nov 2015 10:16:56 -0800 Subject: [PATCH 206/401] aabox delivered to scripts in properties should be in world space --- libraries/entities/src/EntityItemProperties.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 8fa760930c..a1ce826072 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -1491,10 +1491,12 @@ AABox EntityItemProperties::getAABox() const { glm::vec3 unrotatedMinRelativeToEntity = - (_dimensions * _registrationPoint); glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder; Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; - Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation()); + glm::quat worldRotation = SpatiallyNestable::localToWorld(getRotation(), _parentID, _parentJointIndex); + Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(worldRotation); // shift the extents to be relative to the position/registration point - rotatedExtentsRelativeToRegistrationPoint.shiftBy(_position); + glm::vec3 worldPosition = SpatiallyNestable::localToWorld(_position, _parentID, _parentJointIndex); + rotatedExtentsRelativeToRegistrationPoint.shiftBy(worldPosition); return AABox(rotatedExtentsRelativeToRegistrationPoint); } From 204c3d839e487775542ffa3adf1d1b4aa6fb9cf9 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 29 Nov 2015 10:17:21 -0800 Subject: [PATCH 207/401] added localToWorld calls, put locks around access to _children hashtable --- libraries/shared/src/SpatiallyNestable.cpp | 53 +++++++++++++++++++--- libraries/shared/src/SpatiallyNestable.h | 6 +++ 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 87ef7565fb..f5d05a77ad 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -76,11 +76,15 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { } void SpatiallyNestable::beParentOfChild(SpatiallyNestablePointer newChild) const { - _children[newChild->getID()] = newChild; + _childrenLock.withWriteLock([&] { + _children[newChild->getID()] = newChild; + }); } void SpatiallyNestable::forgetChild(SpatiallyNestablePointer newChild) const { - _children.remove(newChild->getID()); + _childrenLock.withWriteLock([&] { + _children.remove(newChild->getID()); + }); } void SpatiallyNestable::setParentID(const QUuid& parentID) { @@ -110,6 +114,39 @@ glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation) { return result.getRotation(); } +glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3& position, QUuid parentID, int parentJointIndex) { + QSharedPointer parentFinder = DependencyManager::get(); + auto parentWP = parentFinder->find(parentID); + auto parent = parentWP.lock(); + Transform parentTransform; + if (parent) { + parentTransform = parent->getTransform(parentJointIndex); + parentTransform.setScale(1.0f); + } + Transform positionTransform; + positionTransform.setTranslation(position); + Transform result; + Transform::mult(result, parentTransform, positionTransform); + return result.getTranslation(); +} + +glm::quat SpatiallyNestable::localToWorld(const glm::quat& orientation, QUuid parentID, int parentJointIndex) { + QSharedPointer parentFinder = DependencyManager::get(); + auto parentWP = parentFinder->find(parentID); + auto parent = parentWP.lock(); + Transform parentTransform; + if (parent) { + parentTransform = parent->getTransform(parentJointIndex); + parentTransform.setScale(1.0f); + } + Transform orientationTransform; + orientationTransform.setRotation(orientation); + Transform result; + Transform::mult(result, parentTransform, orientationTransform); + return result.getRotation(); +} + + const glm::vec3& SpatiallyNestable::getPosition() const { Transform parentTransformDescaled = getParentTransform(); glm::mat4 parentMat; @@ -223,12 +260,14 @@ void SpatiallyNestable::setLocalScale(const glm::vec3& scale) { QList SpatiallyNestable::getChildren() const { QList children; - foreach (SpatiallyNestableWeakPointer childWP, _children.values()) { - SpatiallyNestablePointer child = childWP.lock(); - if (child) { - children << child; + _childrenLock.withReadLock([&] { + foreach (SpatiallyNestableWeakPointer childWP, _children.values()) { + SpatiallyNestablePointer child = childWP.lock(); + if (child) { + children << child; + } } - } + }); return children; } diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 30602d26b4..74d9cc9a95 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -16,6 +16,7 @@ #include "Transform.h" #include "SpatialParentFinder.h" +#include "shared/ReadWriteLockable.h" class SpatiallyNestable; @@ -49,6 +50,9 @@ public: glm::vec3 worldToLocal(const glm::vec3& position); glm::quat worldToLocal(const glm::quat& orientation); + static glm::vec3 localToWorld(const glm::vec3& position, QUuid parentID, int parentJointIndex); + static glm::quat localToWorld(const glm::quat& orientation, QUuid parentID, int parentJointIndex); + // world frame virtual const Transform& getTransform() const; virtual void setTransform(const Transform& transform); @@ -101,6 +105,8 @@ protected: virtual void beParentOfChild(SpatiallyNestablePointer newChild) const; virtual void forgetChild(SpatiallyNestablePointer newChild) const; + + mutable ReadWriteLockable _childrenLock; mutable QHash _children; virtual void parentChanged() {} // called when parent pointer is updated From cf39cac7fcfb24b38a47228ad8cc46d280d68970 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 29 Nov 2015 12:50:33 -0800 Subject: [PATCH 208/401] attempt to make SpatiallyNestable data access thread-safe --- interface/src/Application.cpp | 2 +- interface/src/Application.h | 2 +- interface/src/avatar/Avatar.cpp | 4 +- interface/src/avatar/Avatar.h | 4 +- libraries/avatars/src/AvatarData.cpp | 4 +- libraries/avatars/src/AvatarData.h | 4 +- .../src/RenderableModelEntityItem.cpp | 2 +- .../src/RenderableModelEntityItem.h | 2 +- libraries/entities/src/EntityItem.cpp | 38 ++-- libraries/entities/src/EntityItem.h | 20 +- libraries/entities/src/LightEntityItem.cpp | 2 +- libraries/entities/src/LightEntityItem.h | 2 +- libraries/entities/src/TextEntityItem.cpp | 2 +- libraries/entities/src/TextEntityItem.h | 2 +- libraries/entities/src/WebEntityItem.cpp | 2 +- libraries/entities/src/WebEntityItem.h | 2 +- .../src/AbstractViewStateInterface.h | 2 +- libraries/shared/src/SpatiallyNestable.cpp | 182 +++++++++++------- libraries/shared/src/SpatiallyNestable.h | 62 +++--- 19 files changed, 187 insertions(+), 153 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1088426fcc..f5781e727d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3329,7 +3329,7 @@ MyAvatar* Application::getMyAvatar() const { return DependencyManager::get()->getMyAvatar(); } -const glm::vec3& Application::getAvatarPosition() const { +const glm::vec3 Application::getAvatarPosition() const { return getMyAvatar()->getPosition(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 730158c689..0467926b47 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -185,7 +185,7 @@ public: virtual float getSizeScale() const; virtual int getBoundaryLevelAdjust() const; virtual PickRay computePickRay(float x, float y) const; - virtual const glm::vec3& getAvatarPosition() const; + virtual const glm::vec3 getAvatarPosition() const; virtual void overrideEnvironmentData(const EnvironmentData& newData) { _environment.override(newData); } virtual void endOverrideEnvironmentData() { _environment.endOverride(); } virtual qreal getDevicePixelRatio(); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 5aa6936fee..763d44274d 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -1212,12 +1212,12 @@ glm::quat Avatar::getRightPalmRotation() { return rightRotation; } -void Avatar::setPosition(const glm::vec3& position) { +void Avatar::setPosition(const glm::vec3 position) { AvatarData::setPosition(position); updateAttitude(); } -void Avatar::setOrientation(const glm::quat& orientation) { +void Avatar::setOrientation(const glm::quat orientation) { AvatarData::setOrientation(orientation); updateAttitude(); } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index c19efe032b..51768e4e71 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -161,8 +161,8 @@ public: void setMotionState(AvatarMotionState* motionState) { _motionState = motionState; } AvatarMotionState* getMotionState() { return _motionState; } - virtual void setPosition(const glm::vec3& position); - virtual void setOrientation(const glm::quat& orientation); + virtual void setPosition(const glm::vec3 position); + virtual void setOrientation(const glm::quat orientation); public slots: diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index adfd10b2af..ec363756f6 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1609,10 +1609,10 @@ void AvatarData::setBodyRoll(float bodyRoll) { setOrientation(glm::quat(glm::radians(eulerAngles))); } -void AvatarData::setPosition(const glm::vec3& position) { +void AvatarData::setPosition(const glm::vec3 position) { SpatiallyNestable::setPosition(position); } -void AvatarData::setOrientation(const glm::quat& orientation) { +void AvatarData::setOrientation(const glm::quat orientation) { SpatiallyNestable::setOrientation(orientation); } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 9b684ec989..8db0ef5897 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -201,8 +201,8 @@ public: float getBodyRoll() const; void setBodyRoll(float bodyRoll); - virtual void setPosition(const glm::vec3& position); - virtual void setOrientation(const glm::quat& orientation); + virtual void setPosition(const glm::vec3 position); + virtual void setOrientation(const glm::quat orientation); void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time. void startCapture(); // start/end of the period in which the latest values are about to be captured for camera, etc. diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index bf3b2e7e95..393c0dc0dc 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -44,7 +44,7 @@ RenderableModelEntityItem::~RenderableModelEntityItem() { } } -void RenderableModelEntityItem::setDimensions(const glm::vec3& value) { +void RenderableModelEntityItem::setDimensions(const glm::vec3 value) { _dimensionsInitialized = true; ModelEntityItem::setDimensions(value); } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 2187c0edb3..b86692753c 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -28,7 +28,7 @@ public: virtual ~RenderableModelEntityItem(); - virtual void setDimensions(const glm::vec3& value) override; + virtual void setDimensions(const glm::vec3 value) override; virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; virtual bool setProperties(const EntityItemProperties& properties); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 24b0e7f977..64b4fc5088 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1188,7 +1188,7 @@ const Transform EntityItem::getTransformToCenter() const { return result; } -void EntityItem::setDimensions(const glm::vec3& value) { +void EntityItem::setDimensions(const glm::vec3 value) { if (value.x <= 0.0f || value.y <= 0.0f || value.z <= 0.0f) { return; } @@ -1860,44 +1860,44 @@ void EntityItem::parentChanged() { }); } -void EntityItem::setTransform(const Transform& transform) { +void EntityItem::setTransform(const Transform transform) { SpatiallyNestable::setTransform(transform); forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); + entity->requiresRecalcBoxes(); + }); } -void EntityItem::setLocalTransform(const Transform& transform) { +void EntityItem::setLocalTransform(const Transform transform) { SpatiallyNestable::setLocalTransform(transform); forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); + entity->requiresRecalcBoxes(); + }); } -void EntityItem::setPosition(const glm::vec3& position) { +void EntityItem::setPosition(const glm::vec3 position) { SpatiallyNestable::setPosition(position); forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); + entity->requiresRecalcBoxes(); + }); } -void EntityItem::setLocalPosition(const glm::vec3& position) { +void EntityItem::setLocalPosition(const glm::vec3 position) { SpatiallyNestable::setLocalPosition(position); forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); + entity->requiresRecalcBoxes(); + }); } -void EntityItem::setRotation(const glm::quat& orientation) { +void EntityItem::setRotation(const glm::quat orientation) { SpatiallyNestable::setOrientation(orientation); forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); + entity->requiresRecalcBoxes(); + }); } -void EntityItem::setLocalRotation(const glm::quat& orientation) { +void EntityItem::setLocalRotation(const glm::quat orientation) { SpatiallyNestable::setLocalOrientation(orientation); forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); + entity->requiresRecalcBoxes(); + }); } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 855f9568f1..cd5f97bee2 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -196,8 +196,8 @@ public: void setDescription(QString value) { _description = value; } /// Dimensions in meters (0.0 - TREE_SCALE) - inline const glm::vec3& getDimensions() const { return getScale(); } - virtual void setDimensions(const glm::vec3& value); + inline const glm::vec3 getDimensions() const { return getScale(); } + virtual void setDimensions(const glm::vec3 value); float getGlowLevel() const { return _glowLevel; } void setGlowLevel(float glowLevel) { _glowLevel = glowLevel; } @@ -325,15 +325,15 @@ public: /// return preferred shape type (actual physical shape may differ) virtual ShapeType getShapeType() const { return SHAPE_TYPE_NONE; } - virtual void setTransform(const Transform& transform); - virtual void setLocalTransform(const Transform& transform); - // virtual const glm::vec3& getPosition() const { return SpatiallyNestable::getPosition(); } - virtual const glm::quat& getRotation() const { return SpatiallyNestable::getOrientation(); } + virtual void setTransform(const Transform transform); + virtual void setLocalTransform(const Transform transform); + // virtual const glm::vec3 getPosition() const { return SpatiallyNestable::getPosition(); } + virtual const glm::quat getRotation() const { return SpatiallyNestable::getOrientation(); } - virtual void setPosition(const glm::vec3& position); - virtual void setLocalPosition(const glm::vec3& position); - virtual void setRotation(const glm::quat& orientation); - virtual void setLocalRotation(const glm::quat& orientation); + virtual void setPosition(const glm::vec3 position); + virtual void setLocalPosition(const glm::vec3 position); + virtual void setRotation(const glm::quat orientation); + virtual void setLocalRotation(const glm::quat orientation); // updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags void updatePosition(const glm::vec3& value); diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index ac56fc9c1f..af3110c000 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -40,7 +40,7 @@ LightEntityItem::LightEntityItem(const EntityItemID& entityItemID) : EntityItem( _cutoff = PI; } -void LightEntityItem::setDimensions(const glm::vec3& value) { +void LightEntityItem::setDimensions(const glm::vec3 value) { if (_isSpotlight) { // If we are a spotlight, treat the z value as our radius or length, and // recalculate the x/y dimensions to properly encapsulate the spotlight. diff --git a/libraries/entities/src/LightEntityItem.h b/libraries/entities/src/LightEntityItem.h index 103c462809..edb2ca7b3c 100644 --- a/libraries/entities/src/LightEntityItem.h +++ b/libraries/entities/src/LightEntityItem.h @@ -23,7 +23,7 @@ public: ALLOW_INSTANTIATION // This class can be instantiated /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately - virtual void setDimensions(const glm::vec3& value); + virtual void setDimensions(const glm::vec3 value); // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index 893329d1ce..7d1cfb5c6b 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -41,7 +41,7 @@ TextEntityItem::TextEntityItem(const EntityItemID& entityItemID) : EntityItem(en const float TEXT_ENTITY_ITEM_FIXED_DEPTH = 0.01f; -void TextEntityItem::setDimensions(const glm::vec3& value) { +void TextEntityItem::setDimensions(const glm::vec3 value) { // NOTE: Text Entities always have a "depth" of 1cm. EntityItem::setDimensions(glm::vec3(value.x, value.y, TEXT_ENTITY_ITEM_FIXED_DEPTH)); } diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index 1caceee085..2080912d92 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -23,7 +23,7 @@ public: ALLOW_INSTANTIATION // This class can be instantiated /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately - virtual void setDimensions(const glm::vec3& value); + virtual void setDimensions(const glm::vec3 value); virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; } // methods for getting/setting all properties of an entity diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp index 5f113f1de4..35189074bb 100644 --- a/libraries/entities/src/WebEntityItem.cpp +++ b/libraries/entities/src/WebEntityItem.cpp @@ -34,7 +34,7 @@ WebEntityItem::WebEntityItem(const EntityItemID& entityItemID) : EntityItem(enti const float WEB_ENTITY_ITEM_FIXED_DEPTH = 0.01f; -void WebEntityItem::setDimensions(const glm::vec3& value) { +void WebEntityItem::setDimensions(const glm::vec3 value) { // NOTE: Web Entities always have a "depth" of 1cm. EntityItem::setDimensions(glm::vec3(value.x, value.y, WEB_ENTITY_ITEM_FIXED_DEPTH)); } diff --git a/libraries/entities/src/WebEntityItem.h b/libraries/entities/src/WebEntityItem.h index 8e9d924cde..49ab009bb2 100644 --- a/libraries/entities/src/WebEntityItem.h +++ b/libraries/entities/src/WebEntityItem.h @@ -22,7 +22,7 @@ public: ALLOW_INSTANTIATION // This class can be instantiated /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately - virtual void setDimensions(const glm::vec3& value); + virtual void setDimensions(const glm::vec3 value); virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; } // methods for getting/setting all properties of an entity diff --git a/libraries/render-utils/src/AbstractViewStateInterface.h b/libraries/render-utils/src/AbstractViewStateInterface.h index b65289933c..2954c1fce4 100644 --- a/libraries/render-utils/src/AbstractViewStateInterface.h +++ b/libraries/render-utils/src/AbstractViewStateInterface.h @@ -45,7 +45,7 @@ public: virtual int getBoundaryLevelAdjust() const = 0; virtual PickRay computePickRay(float x, float y) const = 0; - virtual const glm::vec3& getAvatarPosition() const = 0; + virtual const glm::vec3 getAvatarPosition() const = 0; virtual void postLambdaEvent(std::function f) = 0; virtual qreal getDevicePixelRatio() = 0; diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index f5d05a77ad..d5e2104706 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -87,34 +87,38 @@ void SpatiallyNestable::forgetChild(SpatiallyNestablePointer newChild) const { }); } -void SpatiallyNestable::setParentID(const QUuid& parentID) { +void SpatiallyNestable::setParentID(const QUuid parentID) { if (_parentID != parentID) { _parentID = parentID; _parentKnowsMe = false; } } -glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position) { +glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3 position) { Transform parentTransform = getParentTransform(); Transform myWorldTransform; - Transform::mult(myWorldTransform, parentTransform, _transform); + _transformLock.withReadLock([&] { + Transform::mult(myWorldTransform, parentTransform, _transform); + }); myWorldTransform.setTranslation(position); Transform result; Transform::inverseMult(result, parentTransform, myWorldTransform); return result.getTranslation(); } -glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation) { +glm::quat SpatiallyNestable::worldToLocal(const glm::quat orientation) { Transform parentTransform = getParentTransform(); Transform myWorldTransform; - Transform::mult(myWorldTransform, parentTransform, _transform); + _transformLock.withReadLock([&] { + Transform::mult(myWorldTransform, parentTransform, _transform); + }); myWorldTransform.setRotation(orientation); Transform result; Transform::inverseMult(result, parentTransform, myWorldTransform); return result.getRotation(); } -glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3& position, QUuid parentID, int parentJointIndex) { +glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3 position, QUuid parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); auto parentWP = parentFinder->find(parentID); auto parent = parentWP.lock(); @@ -130,7 +134,7 @@ glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3& position, QUuid paren return result.getTranslation(); } -glm::quat SpatiallyNestable::localToWorld(const glm::quat& orientation, QUuid parentID, int parentJointIndex) { +glm::quat SpatiallyNestable::localToWorld(const glm::quat orientation, QUuid parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); auto parentWP = parentFinder->find(parentID); auto parent = parentWP.lock(); @@ -147,115 +151,152 @@ glm::quat SpatiallyNestable::localToWorld(const glm::quat& orientation, QUuid pa } -const glm::vec3& SpatiallyNestable::getPosition() const { +const glm::vec3 SpatiallyNestable::getPosition() const { Transform parentTransformDescaled = getParentTransform(); glm::mat4 parentMat; parentTransformDescaled.getMatrix(parentMat); glm::vec4 absPos = parentMat * glm::vec4(getLocalPosition(), 1.0f); - _absolutePositionCache = glm::vec3(absPos); - return _absolutePositionCache; + return glm::vec3(absPos); } -const glm::vec3& SpatiallyNestable::getPosition(int jointIndex) const { - getTransform(); // update _worldTransformCache - getJointTransformInObjectFrame(jointIndex); // update _jointInObjectFrameCache - _jointInWorldFrameCache.resize(jointIndex); - Transform::mult(_jointInWorldFrameCache[jointIndex], _worldTransformCache, _jointInObjectFrameCache[jointIndex]); - return _jointInWorldFrameCache[jointIndex].getTranslation(); +const glm::vec3 SpatiallyNestable::getPosition(int jointIndex) const { + Transform worldTransform = getTransform(); + Transform jointInObjectFrame = getJointTransformInObjectFrame(jointIndex); + Transform jointInWorldFrame; + Transform::mult(jointInWorldFrame, worldTransform, jointInObjectFrame); + return jointInWorldFrame.getTranslation(); } -void SpatiallyNestable::setPosition(const glm::vec3& position) { +void SpatiallyNestable::setPosition(const glm::vec3 position) { Transform parentTransform = getParentTransform(); Transform myWorldTransform; - Transform::mult(myWorldTransform, parentTransform, _transform); - myWorldTransform.setTranslation(position); - Transform::inverseMult(_transform, parentTransform, myWorldTransform); + _transformLock.withWriteLock([&] { + Transform::mult(myWorldTransform, parentTransform, _transform); + myWorldTransform.setTranslation(position); + Transform::inverseMult(_transform, parentTransform, myWorldTransform); + }); } -const glm::quat& SpatiallyNestable::getOrientation() const { +const glm::quat SpatiallyNestable::getOrientation() const { Transform parentTransformDescaled = getParentTransform(); - _absoluteRotationCache = parentTransformDescaled.getRotation() * getLocalOrientation(); - return _absoluteRotationCache; + return parentTransformDescaled.getRotation() * getLocalOrientation(); } -const glm::quat& SpatiallyNestable::getOrientation(int jointIndex) const { - getTransform(); // update _worldTransformCache - getJointTransformInObjectFrame(jointIndex); // update _jointInObjectFrameCache - _jointInWorldFrameCache.resize(jointIndex + 1); - Transform::mult(_jointInWorldFrameCache[jointIndex], _worldTransformCache, _jointInObjectFrameCache[jointIndex]); - return _jointInWorldFrameCache[jointIndex].getRotation(); +const glm::quat SpatiallyNestable::getOrientation(int jointIndex) const { + Transform worldTransform = getTransform(); + Transform jointInObjectFrame = getJointTransformInObjectFrame(jointIndex); + Transform jointInWorldFrame; + Transform::mult(jointInWorldFrame, worldTransform, jointInObjectFrame); + return jointInWorldFrame.getRotation(); } -void SpatiallyNestable::setOrientation(const glm::quat& orientation) { +void SpatiallyNestable::setOrientation(const glm::quat orientation) { Transform parentTransform = getParentTransform(); Transform myWorldTransform; - Transform::mult(myWorldTransform, parentTransform, _transform); - myWorldTransform.setRotation(orientation); - Transform::inverseMult(_transform, parentTransform, myWorldTransform); + _transformLock.withWriteLock([&] { + Transform::mult(myWorldTransform, parentTransform, _transform); + myWorldTransform.setRotation(orientation); + Transform::inverseMult(_transform, parentTransform, myWorldTransform); + }); } -const Transform& SpatiallyNestable::getTransform() const { +const Transform SpatiallyNestable::getTransform() const { Transform parentTransform = getParentTransform(); - Transform::mult(_worldTransformCache, parentTransform, _transform); - return _worldTransformCache; + Transform result; + _transformLock.withReadLock([&] { + Transform::mult(result, parentTransform, _transform); + }); + return result; } -const Transform& SpatiallyNestable::getTransform(int jointIndex) const { - getTransform(); // update _worldTransformCache - getJointTransformInObjectFrame(jointIndex); // update _jointInObjectFrameCache - _jointInWorldFrameCache.resize(jointIndex + 1); - Transform::mult(_jointInWorldFrameCache[jointIndex], _worldTransformCache, _jointInObjectFrameCache[jointIndex]); - return _jointInWorldFrameCache[jointIndex]; +const Transform SpatiallyNestable::getTransform(int jointIndex) const { + Transform worldTransform = getTransform(); + Transform jointInObjectFrame = getJointTransformInObjectFrame(jointIndex); + Transform jointInWorldFrame; + Transform::mult(jointInWorldFrame, worldTransform, jointInObjectFrame); + return jointInWorldFrame; } -void SpatiallyNestable::setTransform(const Transform& transform) { +void SpatiallyNestable::setTransform(const Transform transform) { Transform parentTransform = getParentTransform(); - Transform::inverseMult(_transform, parentTransform, transform); + _transformLock.withWriteLock([&] { + Transform::inverseMult(_transform, parentTransform, transform); + }); } -const glm::vec3& SpatiallyNestable::getScale() const { - return _transform.getScale(); +const glm::vec3 SpatiallyNestable::getScale() const { + glm::vec3 result; + _transformLock.withReadLock([&] { + result = _transform.getScale(); + }); + return result; } -const glm::vec3& SpatiallyNestable::getScale(int jointIndex) const { +const glm::vec3 SpatiallyNestable::getScale(int jointIndex) const { // XXX ... something with joints return getScale(); } -void SpatiallyNestable::setScale(const glm::vec3& scale) { - _transform.setScale(scale); +void SpatiallyNestable::setScale(const glm::vec3 scale) { + _transformLock.withWriteLock([&] { + _transform.setScale(scale); + }); } -const Transform& SpatiallyNestable::getLocalTransform() const { - return _transform; +const Transform SpatiallyNestable::getLocalTransform() const { + Transform result; + _transformLock.withReadLock([&] { + result =_transform; + }); + return result; } -void SpatiallyNestable::setLocalTransform(const Transform& transform) { - _transform = transform; +void SpatiallyNestable::setLocalTransform(const Transform transform) { + _transformLock.withWriteLock([&] { + _transform = transform; + }); } -const glm::vec3& SpatiallyNestable::getLocalPosition() const { - return _transform.getTranslation(); +const glm::vec3 SpatiallyNestable::getLocalPosition() const { + glm::vec3 result; + _transformLock.withReadLock([&] { + result = _transform.getTranslation(); + }); + return result; } -void SpatiallyNestable::setLocalPosition(const glm::vec3& position) { - _transform.setTranslation(position); +void SpatiallyNestable::setLocalPosition(const glm::vec3 position) { + _transformLock.withWriteLock([&] { + _transform.setTranslation(position); + }); } -const glm::quat& SpatiallyNestable::getLocalOrientation() const { - return _transform.getRotation(); +const glm::quat SpatiallyNestable::getLocalOrientation() const { + glm::quat result; + _transformLock.withReadLock([&] { + result = _transform.getRotation(); + }); + return result; } -void SpatiallyNestable::setLocalOrientation(const glm::quat& orientation) { - _transform.setRotation(orientation); +void SpatiallyNestable::setLocalOrientation(const glm::quat orientation) { + _transformLock.withWriteLock([&] { + _transform.setRotation(orientation); + }); } -const glm::vec3& SpatiallyNestable::getLocalScale() const { - return _transform.getScale(); +const glm::vec3 SpatiallyNestable::getLocalScale() const { + glm::vec3 result; + _transformLock.withReadLock([&] { + result = _transform.getScale(); + }); + return result; } -void SpatiallyNestable::setLocalScale(const glm::vec3& scale) { - _transform.setScale(scale); +void SpatiallyNestable::setLocalScale(const glm::vec3 scale) { + _transformLock.withWriteLock([&] { + _transform.setScale(scale); + }); } QList SpatiallyNestable::getChildren() const { @@ -272,12 +313,11 @@ QList SpatiallyNestable::getChildren() const { } -const Transform& SpatiallyNestable::getJointTransformInObjectFrame(int jointIndex) const { - _jointInObjectFrameCache.resize(jointIndex + 1); - _jointInObjectFrameCache[jointIndex] = Transform(); +const Transform SpatiallyNestable::getJointTransformInObjectFrame(int jointIndex) const { + Transform jointInObjectFrame; glm::vec3 position = getJointTranslation(jointIndex); glm::quat orientation = getJointRotation(jointIndex); - _jointInObjectFrameCache[jointIndex].setRotation(orientation); - _jointInObjectFrameCache[jointIndex].setTranslation(position); - return _jointInObjectFrameCache[jointIndex]; + jointInObjectFrame.setRotation(orientation); + jointInObjectFrame.setTranslation(position); + return jointInObjectFrame; } diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 74d9cc9a95..5074779d8e 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -41,57 +41,57 @@ public: virtual const QUuid& getID() const { return _id; } virtual void setID(const QUuid& id) { _id = id; } - virtual const QUuid& getParentID() const { return _parentID; } - virtual void setParentID(const QUuid& parentID); + virtual const QUuid getParentID() const { return _parentID; } + virtual void setParentID(const QUuid parentID); virtual quint16 getParentJointIndex() const { return _parentJointIndex; } virtual void setParentJointIndex(quint16 parentJointIndex) { _parentJointIndex = parentJointIndex; } - glm::vec3 worldToLocal(const glm::vec3& position); - glm::quat worldToLocal(const glm::quat& orientation); + glm::vec3 worldToLocal(const glm::vec3 position); + glm::quat worldToLocal(const glm::quat orientation); - static glm::vec3 localToWorld(const glm::vec3& position, QUuid parentID, int parentJointIndex); - static glm::quat localToWorld(const glm::quat& orientation, QUuid parentID, int parentJointIndex); + static glm::vec3 localToWorld(const glm::vec3 position, QUuid parentID, int parentJointIndex); + static glm::quat localToWorld(const glm::quat orientation, QUuid parentID, int parentJointIndex); // world frame - virtual const Transform& getTransform() const; - virtual void setTransform(const Transform& transform); + virtual const Transform getTransform() const; + virtual void setTransform(const Transform transform); virtual Transform getParentTransform() const; - virtual const glm::vec3& getPosition() const; - virtual void setPosition(const glm::vec3& position); + virtual const glm::vec3 getPosition() const; + virtual void setPosition(const glm::vec3 position); - virtual const glm::quat& getOrientation() const; - virtual const glm::quat& getOrientation(int jointIndex) const; - virtual void setOrientation(const glm::quat& orientation); + virtual const glm::quat getOrientation() const; + virtual const glm::quat getOrientation(int jointIndex) const; + virtual void setOrientation(const glm::quat orientation); - virtual const glm::vec3& getScale() const; - virtual void setScale(const glm::vec3& scale); + virtual const glm::vec3 getScale() const; + virtual void setScale(const glm::vec3 scale); // get world location of a specific joint - virtual const Transform& getTransform(int jointIndex) const; - virtual const glm::vec3& getPosition(int jointIndex) const; - virtual const glm::vec3& getScale(int jointIndex) const; + virtual const Transform getTransform(int jointIndex) const; + virtual const glm::vec3 getPosition(int jointIndex) const; + virtual const glm::vec3 getScale(int jointIndex) const; // object's parent's frame - virtual const Transform& getLocalTransform() const; - virtual void setLocalTransform(const Transform& transform); + virtual const Transform getLocalTransform() const; + virtual void setLocalTransform(const Transform transform); - virtual const glm::vec3& getLocalPosition() const; - virtual void setLocalPosition(const glm::vec3& position); + virtual const glm::vec3 getLocalPosition() const; + virtual void setLocalPosition(const glm::vec3 position); - virtual const glm::quat& getLocalOrientation() const; - virtual void setLocalOrientation(const glm::quat& orientation); + virtual const glm::quat getLocalOrientation() const; + virtual void setLocalOrientation(const glm::quat orientation); - virtual const glm::vec3& getLocalScale() const; - virtual void setLocalScale(const glm::vec3& scale); + virtual const glm::vec3 getLocalScale() const; + virtual void setLocalScale(const glm::vec3 scale); QList getChildren() const; NestableTypes::NestableType getNestableType() const { return _nestableType; } // this object's frame - virtual const Transform& getJointTransformInObjectFrame(int jointIndex) const; + virtual const Transform getJointTransformInObjectFrame(int jointIndex) const; virtual glm::quat getJointRotation(int index) const = 0; virtual glm::vec3 getJointTranslation(int index) const = 0; @@ -112,15 +112,9 @@ protected: virtual void parentChanged() {} // called when parent pointer is updated private: + mutable ReadWriteLockable _transformLock; Transform _transform; // this is to be combined with parent's world-transform to produce this' world-transform. - - // these are so we can return by reference - mutable glm::vec3 _absolutePositionCache; - mutable glm::quat _absoluteRotationCache; - mutable Transform _worldTransformCache; mutable bool _parentKnowsMe = false; - mutable QVector _jointInObjectFrameCache; - mutable QVector _jointInWorldFrameCache; }; From bbc9d5d1317ad655aa9ff5c3209770537ad9d62a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 29 Nov 2015 13:04:45 -0800 Subject: [PATCH 209/401] add missing single-quote --- examples/html/entityProperties.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 50fb205e3d..9c1c37d2f6 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -670,7 +670,7 @@ elDimensionsY.addEventListener('change', dimensionsChangeFunction); elDimensionsZ.addEventListener('change', dimensionsChangeFunction); - elParentID.addEventListener('change', createEmitTextPropertyUpdateFunction('parentID)); + elParentID.addEventListener('change', createEmitTextPropertyUpdateFunction('parentID')); var registrationChangeFunction = createEmitVec3PropertyUpdateFunction( 'registrationPoint', elRegistrationX, elRegistrationY, elRegistrationZ); From 9548b0e138e0b9ec840c3fa4f8268655ff028420 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 29 Nov 2015 13:38:27 -0800 Subject: [PATCH 210/401] get parent-id field working --- examples/html/entityProperties.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 9c1c37d2f6..bef5c825c2 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -225,7 +225,7 @@ var elRescaleDimensionsPct = document.getElementById("dimension-rescale-pct"); var elRescaleDimensionsButton = document.getElementById("dimension-rescale-button"); - var elParentID = document.getElementById("parent-id"); + var elParentID = document.getElementById("property-parent-id"); var elRegistrationX = document.getElementById("property-reg-x"); var elRegistrationY = document.getElementById("property-reg-y"); From 3f43fde4592b5a964823b2bb048868764772262b Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Mon, 30 Nov 2015 04:11:17 -0800 Subject: [PATCH 211/401] AFter 3 days on that piece of shit i just give up, js is just too hard to debug, i m very sad --- examples/acScripts/AgentPoolControler.js | 67 ++- examples/acScripts/playbackAgents.js | 48 +-- examples/acScripts/playbackMaster.js | 514 +++++++++++++---------- 3 files changed, 354 insertions(+), 275 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index d528fc70fe..8965defe9c 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -52,9 +52,9 @@ function printDebug(message) { return JSON.parse(message); }; - var packCommandMessage = function(id, action, argument) { + var packCommandMessage = function(dest, action, argument) { var message = { - id_key: id, + dest_key: dest, action_key: action, argument_key: argument }; @@ -73,6 +73,10 @@ function printDebug(message) { this.onLost = function(actor) {}; }; + Actor.prototype.isConnected = function () { + return (this.agentID != INVALID_ACTOR); + } + this.Actor = Actor; // master side @@ -129,18 +133,19 @@ function printDebug(message) { } else { // Master think the agent is hired but not the other way around, forget about it printDebug("New agent still sending ready ? " + message.src + " " + agentIndex + " Forgeting about it"); - this.knownAgents[agentIndex] = INVALID_ACTOR; + lostActor.agentID = INVALID_ACTOR; + lostActor.onLost(lostActor); + _clearAgent(agentIndex); } } else if (message.command == AGENT_LOST) { // check to see if we know about this agent var agentIndex = this.knownAgents.indexOf(message.src); - if (agentIndex < 0) { - printDebug("Lost agent " + message.src + " " + agentIndex + " Forgeting about it"); - this.knownAgents[agentIndex] = INVALID_ACTOR; - var lostActor = this.hiredActors[agentIndex]; - this.hiredActors[agentIndex] = null; + if (agentIndex >= 0) { lostActor.agentID = INVALID_ACTOR; lostActor.onLost(lostActor); + _clearAgent(agentIndex); + } else { + return; } } } @@ -186,6 +191,38 @@ function printDebug(message) { }) }; + MasterController.prototype.fireAgent = function(actor) { + // check to see if we know about this agent + printDebug("MasterController.prototype.fireAgent" + JSON.stringify(actor) + " " + JSON.stringify(this.knownAgents)); + var actorIndex = this.knownAgents.indexOf(actor.agentID); + if (actorIndex >= 0) { + printDebug("fired actor found #" + actorIndex); + + var currentAgentID = actor.agentID; + this._clearAgent(actorIndex); + printDebug("fired actor found #" + actorIndex); + + if (currentAgentID != INVALID_ACTOR) { + printDebug("fired actor is still connected, send fire command"); + this.sendCommand(currentAgentID, MASTER_FIRE_AGENT); + } + } + } + + MasterController.prototype._clearAgent = function(actorIndex) { + // check to see if we know about this agent + if (actorIndex >= 0) { + printDebug("before _clearAgent #" + actorIndex + " " + JSON.stringify(this)) + this.knownAgents.splice(actorIndex, 1); + var lostActor = this.hiredActors[actorIndex]; + this.hiredActors.splice(actorIndex, 1); + lostActor.agentID = INVALID_ACTOR; + printDebug("Clearing agent " + actorIndex + " Forgeting about it"); + printDebug("after _clearAgent #" + actorIndex + " " + JSON.stringify(this)) + + } + } + this.MasterController = MasterController; // agent side @@ -211,7 +248,7 @@ function printDebug(message) { AgentController.prototype.destroy = function() { if (this.subscribed) { - this.fire(); + this.fired(); Messages.unsubscribe(ANNOUNCE_CHANNEL); Messages.unsubscribe(COMMAND_CHANNEL); this.subscribed = true; @@ -242,7 +279,7 @@ function printDebug(message) { }; AgentController.prototype._processAnnounceMessage = function(message, senderID) { - var announce = unpackCommandMessage(message); + var announce = unpackAnnounceMessage(message); //printDebug("Client " + this.actorIndex + " Received Announcement = " + message); if (announce.dest == this.actorUUID) { if (announce.command != AGENT_READY) { @@ -251,11 +288,11 @@ function printDebug(message) { printDebug(announce.command); var parts = announce.command.split("."); - var agentID = parts[0]; - var actorIndex = parts[1]; + var commandPart0 = parts[0]; + var commandPart1 = parts[1]; //printDebug("Client " + Agent.sessionUUID + " - " + agentID + " Hired!"); // if (agentID == Agent.sessionUUID) { - this.actorIndex = actorIndex; + this.actorIndex = commandPart1; printDebug("Client " + this.actorIndex + " Hired!"); this.onHired(); // Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel @@ -269,12 +306,12 @@ function printDebug(message) { var command = unpackCommandMessage(message); //printDebug("Received command = " + JSON.stringify(command)); - if ((command.id_key == this.actorUUID) || (command.id_key == AGENTS_BROADCAST)) { + if ((command.dest_key == this.actorUUID) || (command.dest_key == AGENTS_BROADCAST)) { if (command.action_key == MASTER_ALIVE) { this.notifyAlive = true; } else if (command.action_key == MASTER_FIRE_AGENT) { printDebug("Master firing Agent"); - this.fire(); + this.fired(); } else { printDebug("True action received = " + JSON.stringify(command) + senderID); this.onCommand(command); diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index f7630cad48..ec704e35e9 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -8,7 +8,10 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + +// Agent is an avatar Agent.isAvatar = true; + Script.include("./AgentPoolControler.js"); var agentController = new AgentController(); @@ -29,7 +32,6 @@ var WAIT_FOR_AUDIO_MIXER = 1; // Script. DO NOT MODIFY BEYOND THIS LINE. var ALIVE = -1; -var DO_NOTHING = 0; var PLAY = 1; var PLAY_LOOP = 2; var STOP = 3; @@ -47,22 +49,11 @@ function getAction(command) { if(true) { // var command = JSON.parse(message); - print("I'm the agent " + id + " and I received this: ID: " + command.id_key + " Action: " + command.action_key + " URL: " + command.clip_url_key); - - if (command.id_key == id || command.id_key == -1) { - - action = command.action_key; - print("That command was for me! Agent with id: " + id); - } else { - action = DO_NOTHING; - } - - switch(action) { + print("I'm the agent " + this.actorUUID + " and I received this: Dest: " + command.dest_key + " Action: " + command.action_key + " URL: " + command.argument_key); + + switch(command.action_key) { case PLAY: print("Play"); - if (!Agent.isAvatar) { - Agent.isAvatar = true; - } if (!Recording.isPlaying()) { Recording.startPlaying(); } @@ -70,9 +61,6 @@ function getAction(command) { break; case PLAY_LOOP: print("Play loop"); - if (!Agent.isAvatar) { - Agent.isAvatar = true; - } if (!Recording.isPlaying()) { Recording.startPlaying(); } @@ -86,22 +74,15 @@ function getAction(command) { break; case SHOW: print("Show"); - if (!Agent.isAvatar) { - Agent.isAvatar = true; - } break; case HIDE: - print("Hide"); + print("Hide"); if (Recording.isPlaying()) { Recording.stopPlaying(); } - Agent.isAvatar = false; break; case LOAD: print("Load"); - if (!Agent.isAvatar) { - Agent.isAvatar = true; - } if(command.argument_key !== null) { print("Agent #" + id + " loading clip URL: " + command.argument_key); Recording.loadRecording(command.argument_key); @@ -109,26 +90,27 @@ function getAction(command) { print("Agent #" + id + " loading clip URL is NULL, nothing happened"); } break; - case DO_NOTHING: - break; default: - print("Unknown action: " + action); + print("Unknown action: " + command.action_key); break; } - - if (Recording.isPlaying()) { - Recording.play(); - } } } function agentHired() { print("Agent Hired from playbackAgents.js"); + if (Recording.isPlaying()) { + Recording.stopPlaying(); + } + Recording.setPlayerLoop(false); } function agentFired() { print("Agent Fired from playbackAgents.js"); + if (Recording.isPlaying()) { + Recording.stopPlaying(); + } } diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 3e60fc7a0e..3cf24a6071 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -14,15 +14,14 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; var masterController = new MasterController(); -var ac_number = 1; // This is the default number of ACs. Their ID need to be unique and between 0 (included) and ac_number (excluded) -var names = new Array(); // It is possible to specify the name of the ACs in this array. ACs names ordered by IDs (Default name is "ACx", x = ID + 1)) var input_text = null; -var actors = new Array(); // Script. DO NOT MODIFY BEYOND THIS LINE. //Script.include("../libraries/toolBars.js"); Script.include(HIFI_PUBLIC_BUCKET + "scripts/libraries/toolBars.js"); - +// We want small icons +Tool.IMAGE_HEIGHT /= 2; +Tool.IMAGE_WIDTH /= 2; var DO_NOTHING = 0; var PLAY = 1; @@ -41,245 +40,315 @@ var COLOR_MASTER = { red: 0, green: 0, blue: 0 }; var TEXT_HEIGHT = 12; var TEXT_MARGIN = 3; -var toolBars = new Array(); -var nameOverlays = new Array(); -var onOffIcon = new Array(); -var playIcon = new Array(); -var playLoopIcon = new Array(); -var stopIcon = new Array(); -var loadIcon = new Array(); +// Add new features to Actor class: +Actor.prototype.destroy = function() { + print("Actor.prototype.destroy"); -var performanceJSON = null; -var performanceLoadedNeedUpdate = false; - -setupPlayback(); - -function onActorHired(actor) { - print("agent hired from playbackMaster! " + actor.agentID + " " + actor.index) -} - -function onActorLost(actor) { - print("agent lost from playbackMaster! " + actor.agentID + " " + actor.index) - - actors[actor.index] = null; -} - -function setupPlayback() { - ac_number = Window.prompt("Insert number of agents: ","1"); - if (ac_number === "" || ac_number === null) { - ac_number = 1; - } - masterController.reset(); - - for (var i = 0; i < ac_number; i++) { - var newActor = new Actor(); - newActor.index = i; - newActor.onHired = onActorHired; - newActor.onLost = onActorLost; - masterController.hireAgent(newActor); - actors.push(newActor); - } - - setupToolBars(); + this.toolbar.cleanup(); + Overlays.deleteOverlay(this.nameOverlay); + print("Need to fire myself" + this.agentID); + masterController.fireAgent(this); } -function setupToolBars() { - if (toolBars.length > 0) { - print("Multiple calls to Recorder.js:setupToolBars()"); - return; - } - Tool.IMAGE_HEIGHT /= 2; - Tool.IMAGE_WIDTH /= 2; - - for (i = 0; i <= ac_number; i++) { - toolBars.push(new ToolBar(0, 0, ToolBar.HORIZONTAL)); - toolBars[i].setBack((i == ac_number) ? COLOR_MASTER : COLOR_TOOL_BAR, ALPHA_OFF); - - onOffIcon.push(toolBars[i].addTool({ - imageURL: TOOL_ICON_URL + "ac-on-off.svg", - subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - x: 0, y: 0, - width: Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: ALPHA_ON, - visible: true - }, true, true)); - - playIcon[i] = toolBars[i].addTool({ - imageURL: TOOL_ICON_URL + "play.svg", - subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - width: Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: ALPHA_OFF, - visible: true - }, false); - - var playLoopWidthFactor = 1.65; - playLoopIcon[i] = toolBars[i].addTool({ - imageURL: TOOL_ICON_URL + "play-and-loop.svg", - subImage: { x: 0, y: 0, width: playLoopWidthFactor * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, - width: playLoopWidthFactor * Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: ALPHA_OFF, - visible: true - }, false); - - stopIcon[i] = toolBars[i].addTool({ - imageURL: TOOL_ICON_URL + "recording-stop.svg", - width: Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: ALPHA_OFF, - visible: true - }, false); - - loadIcon[i] = toolBars[i].addTool({ - imageURL: TOOL_ICON_URL + "recording-upload.svg", - width: Tool.IMAGE_WIDTH, - height: Tool.IMAGE_HEIGHT, - alpha: ALPHA_OFF, - visible: true - }, false); - - nameOverlays.push(Overlays.addOverlay("text", { - backgroundColor: { red: 0, green: 0, blue: 0 }, - font: { size: TEXT_HEIGHT }, - text: (i == ac_number) ? "Master" : i + ". " + - ((i < names.length) ? names[i] : - "AC" + i), - x: 0, y: 0, - width: toolBars[i].width + ToolBar.SPACING, - height: TEXT_HEIGHT + TEXT_MARGIN, - leftMargin: TEXT_MARGIN, - topMargin: TEXT_MARGIN, - alpha: ALPHA_OFF, - backgroundAlpha: ALPHA_OFF, - visible: true - })); + +Actor.prototype.resetClip = function(clipURL, onLoadClip) { + this.clipURL = clipURL; + this.onLoadClip = onLoadClip; + if (this.isConnected()) { + this.onLoadClip(this); } } -function loadAvatarClipsFromPerformanceJSON(performanceJSON) { - if (performanceJSON.avatarClips) { - var numClips = performanceJSON.avatarClips.length; - print("Performance file contains:" + JSON.stringify(performanceJSON)); - print("Number of clips in the performance file is: " + numClips + " Number of agents is: " + knownAgents.length); - if (numClips > knownAgents.length) { - numClips = knownAgents.length; - } - - for (i = 0; i < numClips; i++) { - var clipURL = performanceJSON.avatarClips[i]; - print("Loading clip " + clipURL + " to Agent #" + i); - sendCommand(i, LOAD, clipURL); - } +Actor.prototype.onMousePressEvent = function(clickedOverlay) { + if (this.playIcon === this.toolbar.clicked(clickedOverlay, false)) { + masterController.sendCommand(this.agentID, PLAY); + } else if (this.playLoopIcon === this.toolbar.clicked(clickedOverlay, false)) { + masterController.sendCommand(this.agentID, PLAY_LOOP); + } else if (this.stopIcon === this.toolbar.clicked(clickedOverlay, false)) { + masterController.sendCommand(this.agentID, STOP); } else { - print("Performance file cannot be interpreted:" + JSON.stringify(performanceJSON)); + return false; } + + return true; } -function sendCommand(id, action, argument) { - if (action === SHOW) { - toolBars[id].selectTool(onOffIcon[id], false); - toolBars[id].setAlpha(ALPHA_ON, playIcon[id]); - toolBars[id].setAlpha(ALPHA_ON, playLoopIcon[id]); - toolBars[id].setAlpha(ALPHA_ON, stopIcon[id]); - toolBars[id].setAlpha(ALPHA_ON, loadIcon[id]); - } else if (action === HIDE) { - toolBars[id].selectTool(onOffIcon[id], true); - toolBars[id].setAlpha(ALPHA_OFF, playIcon[id]); - toolBars[id].setAlpha(ALPHA_OFF, playLoopIcon[id]); - toolBars[id].setAlpha(ALPHA_OFF, stopIcon[id]); - toolBars[id].setAlpha(ALPHA_OFF, loadIcon[id]); - } else if (toolBars[id].toolSelected(onOffIcon[id])) { - return; - } +Actor.prototype._buildUI = function() { + print("Actor.prototype._buildUI = " + JSON.stringify(this)); - if (id == (toolBars.length - 1)) { + this.toolbar = new ToolBar(0, 0, ToolBar.HORIZONTAL); - if (action == LOAD) { - if (performanceLoadedNeedUpdate == false) { - Assets.downloadData(argument, function (data) { - performanceJSON = JSON.parse(data); - performanceLoadedNeedUpdate = true; - // print("Performance file contains:" + JSON.stringify(performanceJSON)); - }); - return; - } - } else { - id = -1; - - masterController.sendMessage(id, action, argument); - } - } else { - masterController.sendMessage(id, action, argument); - } + this.toolbar.setBack(COLOR_TOOL_BAR, ALPHA_OFF); + + this.playIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "play.svg", + subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + width: Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); + + var playLoopWidthFthis = 1.65; + this.playLoopIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "play-and-loop.svg", + subImage: { x: 0, y: 0, width: playLoopWidthFthis * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + width: playLoopWidthFthis * Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); + + this.stopIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "recording-stop.svg", + width: Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); + + this.nameOverlay = Overlays.addOverlay("text", { + backgroundColor: { red: 0, green: 0, blue: 0 }, + font: { size: TEXT_HEIGHT }, + text: "AC offline", + x: 0, y: 0, + width: this.toolbar.width + ToolBar.SPACING, + height: TEXT_HEIGHT + TEXT_MARGIN, + leftMargin: TEXT_MARGIN, + topMargin: TEXT_MARGIN, + alpha: ALPHA_OFF, + backgroundAlpha: ALPHA_OFF, + visible: true + }); } -function mousePressEvent(event) { - clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); +Actor.prototype.moveUI = function(pos) { + var textSize = TEXT_HEIGHT + 2 * TEXT_MARGIN; + this.toolbar.move(pos.x, pos.y); + + Overlays.editOverlay(this.nameOverlay, { + x: this.toolbar.x - ToolBar.SPACING, + y: this.toolbar.y - textSize + }); +} + +Director = function() { + this.actors = new Array(); + this.toolbar = null; + this._buildUI(); +}; + +Director.prototype.destroy = function () { + print("Director.prototype.destroy") + this.clearActors(); + this.toolbar.cleanup(); + Overlays.deleteOverlay(this.nameOverlay); +} + +Director.prototype.clearActors = function () { + print("Director.prototype.clearActors") + for (var i = 0; i < this.actors.length; i++) { + print("Destroy actor #" + i) + this.actors[i].destroy(); + } + this.actors = new Array();// Brand new actors +} + +Director.prototype._buildUI = function () { + this.toolbar = new ToolBar(0, 0, ToolBar.HORIZONTAL); - // Check master control - var i = toolBars.length - 1; - if (onOffIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - if (toolBars[i].toolSelected(onOffIcon[i])) { - sendCommand(i, SHOW); - } else { - sendCommand(i, HIDE); - } - } else if (playIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - sendCommand(i, PLAY); - } else if (playLoopIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - sendCommand(i, PLAY_LOOP); - } else if (stopIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - sendCommand(i, STOP); - } else if (loadIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { + this.toolbar.setBack(COLOR_MASTER, ALPHA_OFF); + + this.onOffIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "ac-on-off.svg", + subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + x: 0, y: 0, + width: Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_ON, + visible: true + }, true, true); + + this.playIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "play.svg", + subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + width: Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); + + var playLoopWidthFthis = 1.65; + this.playLoopIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "play-and-loop.svg", + subImage: { x: 0, y: 0, width: playLoopWidthFthis * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, + width: playLoopWidthFthis * Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); + + this.stopIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "recording-stop.svg", + width: Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); + + this.loadIcon = this.toolbar.addTool({ + imageURL: TOOL_ICON_URL + "recording-upload.svg", + width: Tool.IMAGE_WIDTH, + height: Tool.IMAGE_HEIGHT, + alpha: ALPHA_OFF, + visible: true + }, false); + + this.nameOverlay = Overlays.addOverlay("text", { + backgroundColor: { red: 0, green: 0, blue: 0 }, + font: { size: TEXT_HEIGHT }, + text: "Master", + x: 0, y: 0, + width: this.toolbar.width + ToolBar.SPACING, + height: TEXT_HEIGHT + TEXT_MARGIN, + leftMargin: TEXT_MARGIN, + topMargin: TEXT_MARGIN, + alpha: ALPHA_OFF, + backgroundAlpha: ALPHA_OFF, + visible: true + }); +} + +Director.prototype.onMousePressEvent = function(clickedOverlay) { + if (this.onOffIcon === this.toolbar.clicked(clickedOverlay, false)) { + this.clearActors(); + return true; + } else if (this.playIcon === this.toolbar.clicked(clickedOverlay, false)) { + masterController.sendCommand(AGENTS_BROADCAST, PLAY); + } else if (this.playLoopIcon === this.toolbar.clicked(clickedOverlay, false)) { + masterController.sendCommand(AGENTS_BROADCAST, PLAY_LOOP); + } else if (this.stopIcon === this.toolbar.clicked(clickedOverlay, false)) { + masterController.sendCommand(AGENTS_BROADCAST, STOP); + } else if (this.loadIcon === this.toolbar.clicked(clickedOverlay, false)) { input_text = Window.prompt("Insert the url of the clip: ",""); if (!(input_text === "" || input_text === null)) { - sendCommand(i, LOAD, input_text); - } + print("Performance file ready to be loaded url = " + input_text); + + // FIXME: I cannot pass directly this.onPerformanceLoaded, is that exepected ? + var localThis = this; + Assets.downloadData(input_text, function(data) { localThis.onPerformanceLoaded(data); }); + } } else { // Check individual controls - for (i = 0; i < ac_number; i++) { - if (onOffIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - if (toolBars[i].toolSelected(onOffIcon[i], false)) { - sendCommand(i, SHOW); - } else { - sendCommand(i, HIDE); - } - } else if (playIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - sendCommand(i, PLAY); - } else if (playLoopIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - sendCommand(i, PLAY_LOOP); - } else if (stopIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - sendCommand(i, STOP); - } else if (loadIcon[i] === toolBars[i].clicked(clickedOverlay, false)) { - input_text = Window.prompt("Insert the url of the clip: ",""); - if (!(input_text === "" || input_text === null)) { - sendCommand(i, LOAD, input_text); - } - } else { - + for (var i = 0; i < this.actors.length; i++) { + if (this.actors[i].onMousePressEvent(clickedOverlay)) { + return true; } } + + return false; // nothing clicked from our known overlays } + + return true; +} + +Director.prototype.moveUI = function(pos) { + var textSize = TEXT_HEIGHT + 2 * TEXT_MARGIN; + var relative = { x: pos.x, y: pos.y + (this.actors.length + 1) * (Tool.IMAGE_HEIGHT + ToolBar.SPACING + textSize) }; + + this.toolbar.move(relative.x, windowDimensions.y - relative.y); + Overlays.editOverlay(this.nameOverlay, { + x: this.toolbar.x - ToolBar.SPACING, + y: this.toolbar.y - textSize + }); + + for (var i = 0; i < this.actors.length; i++) { + this.actors[i].moveUI({x: relative.x, y: windowDimensions.y - relative.y + + (i + 1) * (Tool.IMAGE_HEIGHT + ToolBar.SPACING + textSize)}); + } +} + +Director.prototype.onPerformanceLoaded = function(performanceData) { + var performanceJSON = JSON.parse(performanceData); + print("Director.prototype.onPerformanceLoaded = " + JSON.stringify(performanceJSON)); + if (performanceJSON.avatarClips != null) { + var numClips = performanceJSON.avatarClips.length; + print("Found " + numClips + "in the performance file, and currently using " + this.actors.length + " actor(s)"); + + for (var i = 0; i < numClips; i++) { + if (i < this.actors.length) { + // load correct clip to actor + } else { + this.hireActor(performanceJSON.avatarClips[i]); + } + } + + } +} + + +Director.prototype.hireActor = function(clipURL) { + print("new actor = " + this.actors.length ); + var newActor = new Actor(); + newActor.clipURL = null; + newActor.onLoadClip = function(clip) {}; + + var localThis = this; + newActor.onHired = function(actor) { + print("agent hired from Director! " + actor.agentID) + Overlays.editOverlay(actor.nameOverlay, { + text: "AC " + actor.agentID, + backgroundColor: { red: 0, green: 255, blue: 0 } + }); + + if (actor.clipURL != null) { + print("agent hired, calling load clip for url " + actor.clipURL); + actor.onLoadClip(actor); + } + }; + + newActor.onLost = function(actor) { + print("agent lost from playbackMaster! " + actor.agentID); + var index = localThis.actors.indexOf(actor); + if (index >= 0) { + localThis.actors.splice(index, 1); + } + actor.destroy(); + } + + newActor.resetClip(clipURL, function(actor) { + print("Load clip for agent" + actor.agentID + " calling load clip for url " + actor.clipURL); + masterController.sendCommand(actor.agentID, LOAD, actor.clipURL); + }); + + masterController.hireAgent(newActor); + newActor._buildUI(); + + this.actors.push(newActor); + + moveUI(); +} + + +masterController.reset(); +var director = new Director(); + +moveUI(); + + +function mousePressEvent(event) { + print("mousePressEvent"); + clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); + + // Check director and actors + director.onMousePressEvent(clickedOverlay); } function moveUI() { - var textSize = TEXT_HEIGHT + 2 * TEXT_MARGIN; - var relative = { x: 70, y: 75 + (ac_number) * (Tool.IMAGE_HEIGHT + ToolBar.SPACING + textSize) }; - - for (i = 0; i <= ac_number; i++) { - toolBars[i].move(relative.x, - windowDimensions.y - relative.y + - i * (Tool.IMAGE_HEIGHT + ToolBar.SPACING + textSize)); - - Overlays.editOverlay(nameOverlays[i], { - x: toolBars[i].x - ToolBar.SPACING, - y: toolBars[i].y - textSize - }); - } + director.moveUI({ x: 70, y: 75}); + } function update(deltaTime) { @@ -290,20 +359,12 @@ function update(deltaTime) { moveUI(); } - if (performanceLoadedNeedUpdate) { - loadAvatarClipsFromPerformanceJSON(performanceJSON); - performanceLoadedNeedUpdate = false; - } - masterController.update(deltaTime); } function scriptEnding() { - for (i = 0; i <= ac_number; i++) { - toolBars[i].cleanup(); - Overlays.deleteOverlay(nameOverlays[i]); - } - + print("cleanup") + director.destroy(); masterController.destroy(); } @@ -311,4 +372,3 @@ Controller.mousePressEvent.connect(mousePressEvent); Script.update.connect(update); Script.scriptEnding.connect(scriptEnding); -moveUI(); From ba379e8830f6fa3995de0370ed4c4d7f3b9f9360 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 30 Nov 2015 08:00:12 -0800 Subject: [PATCH 212/401] Tabs to spaces --- interface/src/avatar/Head.cpp | 2 +- interface/src/avatar/Head.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index b214ba2976..f3b96c13e6 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -266,7 +266,7 @@ void Head::calculateMouthShapes() { _audioJawOpen *= JAW_CLOSE_RATE; } _audioJawOpen = glm::clamp(_audioJawOpen, 0.0f, 1.0f); - _trailingAudioJawOpen = glm::mix(_trailingAudioJawOpen, _audioJawOpen, 0.99f); + _trailingAudioJawOpen = glm::mix(_trailingAudioJawOpen, _audioJawOpen, 0.99f); // Advance time at a rate proportional to loudness, and move the mouth shapes through // a cycle at differing speeds to create a continuous random blend of shapes. diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 93637b7d3c..ec88b295f7 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -124,11 +124,11 @@ private: float _longTermAverageLoudness; float _audioAttack; float _audioJawOpen; - float _trailingAudioJawOpen; + float _trailingAudioJawOpen; float _mouth2; float _mouth3; float _mouth4; - float _mouthTime; + float _mouthTime; bool _renderLookatVectors; bool _renderLookatTarget; glm::vec3 _saccade; From 2377875623f5c35e0df12dd0579d6049cf8fab0e Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 30 Nov 2015 08:05:25 -0800 Subject: [PATCH 213/401] Tabs to spaces v2 --- interface/src/avatar/Head.cpp | 53 +++++++++++++++++------------------ 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index f3b96c13e6..b79e502bed 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -43,11 +43,11 @@ Head::Head(Avatar* owningAvatar) : _longTermAverageLoudness(-1.0f), _audioAttack(0.0f), _audioJawOpen(0.0f), - _trailingAudioJawOpen(0.0f), + _trailingAudioJawOpen(0.0f), _mouth2(0.0f), _mouth3(0.0f), _mouth4(0.0f), - _mouthTime(0.0f), + _mouthTime(0.0f), _renderLookatVectors(false), _renderLookatTarget(false), _saccade(0.0f, 0.0f, 0.0f), @@ -248,33 +248,32 @@ void Head::calculateMouthShapes() { const float JAW_OPEN_SCALE = 0.015f; const float JAW_OPEN_RATE = 0.9f; const float JAW_CLOSE_RATE = 0.90f; - const float TIMESTEP_CONSTANT = 0.0032f; - const float MMMM_POWER = 0.10f; - const float SMILE_POWER = 0.10f; - const float FUNNEL_POWER = 0.35f; - const float MMMM_SPEED = 2.685f; - const float SMILE_SPEED = 1.0f; - const float FUNNEL_SPEED = 2.335f; - const float STOP_GAIN = 5.0f; + const float TIMESTEP_CONSTANT = 0.0032f; + const float MMMM_POWER = 0.10f; + const float SMILE_POWER = 0.10f; + const float FUNNEL_POWER = 0.35f; + const float MMMM_SPEED = 2.685f; + const float SMILE_SPEED = 1.0f; + const float FUNNEL_SPEED = 2.335f; + const float STOP_GAIN = 5.0f; - // From the change in loudness, decide how much to open or close the jaw - float audioDelta = sqrtf(glm::max(_averageLoudness - _longTermAverageLoudness, 0.0f)) * JAW_OPEN_SCALE; - if (audioDelta > _audioJawOpen) { - _audioJawOpen += (audioDelta - _audioJawOpen) * JAW_OPEN_RATE; - } - else { - _audioJawOpen *= JAW_CLOSE_RATE; - } - _audioJawOpen = glm::clamp(_audioJawOpen, 0.0f, 1.0f); - _trailingAudioJawOpen = glm::mix(_trailingAudioJawOpen, _audioJawOpen, 0.99f); - - // Advance time at a rate proportional to loudness, and move the mouth shapes through - // a cycle at differing speeds to create a continuous random blend of shapes. - _mouthTime += sqrtf(_averageLoudness) * TIMESTEP_CONSTANT; - _mouth2 = (sinf(_mouthTime * MMMM_SPEED) + 1.0f) * MMMM_POWER * glm::min(1.0f, _trailingAudioJawOpen * STOP_GAIN); - _mouth3 = (sinf(_mouthTime * FUNNEL_SPEED) + 1.0f) * FUNNEL_POWER * glm::min(1.0f, _trailingAudioJawOpen * STOP_GAIN); - _mouth4 = (sinf(_mouthTime * SMILE_SPEED) + 1.0f) * SMILE_POWER * glm::min(1.0f, _trailingAudioJawOpen * STOP_GAIN); + // From the change in loudness, decide how much to open or close the jaw + float audioDelta = sqrtf(glm::max(_averageLoudness - _longTermAverageLoudness, 0.0f)) * JAW_OPEN_SCALE; + if (audioDelta > _audioJawOpen) { + _audioJawOpen += (audioDelta - _audioJawOpen) * JAW_OPEN_RATE; + } + else { + _audioJawOpen *= JAW_CLOSE_RATE; + } + _audioJawOpen = glm::clamp(_audioJawOpen, 0.0f, 1.0f); + _trailingAudioJawOpen = glm::mix(_trailingAudioJawOpen, _audioJawOpen, 0.99f); + // Advance time at a rate proportional to loudness, and move the mouth shapes through + // a cycle at differing speeds to create a continuous random blend of shapes. + _mouthTime += sqrtf(_averageLoudness) * TIMESTEP_CONSTANT; + _mouth2 = (sinf(_mouthTime * MMMM_SPEED) + 1.0f) * MMMM_POWER * glm::min(1.0f, _trailingAudioJawOpen * STOP_GAIN); + _mouth3 = (sinf(_mouthTime * FUNNEL_SPEED) + 1.0f) * FUNNEL_POWER * glm::min(1.0f, _trailingAudioJawOpen * STOP_GAIN); + _mouth4 = (sinf(_mouthTime * SMILE_SPEED) + 1.0f) * SMILE_POWER * glm::min(1.0f, _trailingAudioJawOpen * STOP_GAIN); } void Head::applyEyelidOffset(glm::quat headOrientation) { From 4220d7a3ccb4793d80f1b2fb8d1172e747d9d1ab Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 30 Nov 2015 09:13:59 -0800 Subject: [PATCH 214/401] Add atp hash checking back in --- libraries/networking/src/AssetRequest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 63d7760ea1..78f146fa93 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -105,7 +105,7 @@ void AssetRequest::start() { Q_ASSERT(data.size() == (end - start)); // we need to check the hash of the received data to make sure it matches what we expect - if (hashData(data).toHex() == _hash || true) { + if (hashData(data).toHex() == _hash) { memcpy(_data.data() + start, data.constData(), data.size()); _totalReceived += data.size(); emit progress(_totalReceived, _info.size); From dc48b9a266c6ab055e19163f88a89aa888613175 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 30 Nov 2015 09:15:25 -0800 Subject: [PATCH 215/401] Limit progress signal in ReceivedMessage to once every 50 packets --- libraries/networking/src/ReceivedMessage.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/ReceivedMessage.cpp b/libraries/networking/src/ReceivedMessage.cpp index a01ecd2c91..5a02d86bce 100644 --- a/libraries/networking/src/ReceivedMessage.cpp +++ b/libraries/networking/src/ReceivedMessage.cpp @@ -52,10 +52,16 @@ void ReceivedMessage::setFailed() { void ReceivedMessage::appendPacket(NLPacket& packet) { Q_ASSERT_X(!_isComplete, "ReceivedMessage::appendPacket", "We should not be appending to a complete message"); + // 50 * 1500 bytes = 75 kb + const int EMIT_PROGRESS_EVERY_X_PACKETS = 50; ++_numPackets; _data.append(packet.getPayload(), packet.getPayloadSize()); - emit progress(); + + if (_numPackets % EMIT_PROGRESS_EVERY_X_PACKETS == 0) { + emit progress(); + } + if (packet.getPacketPosition() == NLPacket::PacketPosition::LAST) { _isComplete = true; emit completed(); From bb6bb85d128b899a939c84281ea0f96431114e67 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 30 Nov 2015 09:16:57 -0800 Subject: [PATCH 216/401] Update comment in ReceivedMessage --- libraries/networking/src/ReceivedMessage.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/ReceivedMessage.cpp b/libraries/networking/src/ReceivedMessage.cpp index 5a02d86bce..94afa97c04 100644 --- a/libraries/networking/src/ReceivedMessage.cpp +++ b/libraries/networking/src/ReceivedMessage.cpp @@ -52,8 +52,10 @@ void ReceivedMessage::setFailed() { void ReceivedMessage::appendPacket(NLPacket& packet) { Q_ASSERT_X(!_isComplete, "ReceivedMessage::appendPacket", "We should not be appending to a complete message"); - // 50 * 1500 bytes = 75 kb + + // Limit progress signal to every X packets const int EMIT_PROGRESS_EVERY_X_PACKETS = 50; + ++_numPackets; _data.append(packet.getPayload(), packet.getPayloadSize()); From 4add3e2e91dadb14b786b1851ea2ce0c9927565a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 30 Nov 2015 09:41:15 -0800 Subject: [PATCH 217/401] rework worldToLocal, start on allowing scripts entity position/rotation to always be in world space --- .../entities/src/EntityItemProperties.cpp | 9 +++- libraries/entities/src/EntityItemProperties.h | 4 ++ libraries/entities/src/EntityPropertyFlags.h | 3 ++ .../entities/src/EntityScriptingInterface.cpp | 48 +++++++++++++++++++ libraries/physics/src/EntityMotionState.cpp | 5 +- libraries/shared/src/SpatiallyNestable.cpp | 37 ++++++++++---- libraries/shared/src/SpatiallyNestable.h | 4 +- 7 files changed, 95 insertions(+), 15 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index a1ce826072..d08e677c48 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -355,7 +355,8 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_START, alphaStart); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_FINISH, alphaFinish); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ADDITIVE_BLENDING, additiveBlending); - + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_POSITION, localPosition); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localrotation); } // Models only @@ -473,6 +474,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_ID, parentID); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_JOINT_INDEX, parentJointIndex); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_POSITION, localPosition); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localRotation); + // FIXME - I don't think these properties are supported any more //COPY_PROPERTY_TO_QSCRIPTVALUE(glowLevel); //COPY_PROPERTY_TO_QSCRIPTVALUE(localRenderAlpha); @@ -598,6 +602,9 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(parentID, QUuid, setParentID); COPY_PROPERTY_FROM_QSCRIPTVALUE(parentJointIndex, quint16, setParentJointIndex); + COPY_PROPERTY_FROM_QSCRIPTVALUE(localPosition, glmVec3, setLocalPosition); + COPY_PROPERTY_FROM_QSCRIPTVALUE(localRotation, glmQuat, setLocalRotation); + _lastEdited = usecTimestampNow(); } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 981c1503fe..bcb48a1903 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -192,6 +192,10 @@ public: DEFINE_PROPERTY_REF(PROP_PARENT_ID, ParentID, parentID, QUuid, UNKNOWN_ENTITY_ID); DEFINE_PROPERTY_REF(PROP_PARENT_JOINT_INDEX, ParentJointIndex, parentJointIndex, quint16, 0); + // these are used when bouncing location data into and out of scripts + DEFINE_PROPERTY_REF_WITH_SETTER(PROP_LOCAL_POSITION, LocalPosition, localPosition, glmVec3, ENTITY_ITEM_ZERO_VEC3); + DEFINE_PROPERTY_REF(PROP_LOCAL_ROTATION, LocalRotation, localRotation, glmQuat, ENTITY_ITEM_DEFAULT_ROTATION); + static QString getBackgroundModeString(BackgroundMode mode); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index fd1e448aed..3bca911a56 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -154,6 +154,9 @@ enum EntityPropertyList { PROP_PARENT_ID, PROP_PARENT_JOINT_INDEX, + PROP_LOCAL_POSITION, // only used to convert values to and from scripts + PROP_LOCAL_ROTATION, // only used to convert values to and from scripts + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index bc57f2c72c..8a8150d017 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -64,6 +64,54 @@ void EntityScriptingInterface::setEntityTree(EntityTreePointer elementTree) { } } +EntityItemProperties convertLocationToScriptSemantics(EntityItemProperties entitySideProperties) { + // In EntityTree code, properties.position and properties.rotation are relative to the parent. In javascript, + // they are in world-space. The local versions are put into localPosition and localRotation and position and + // rotation are converted from local to world space. + EntityItemProperties scriptSideProperties = entitySideProperties; + scriptSideProperties.setLocalPosition(entitySideProperties.getPosition()); + scriptSideProperties.setLocalRotation(entitySideProperties.getRotation()); + + glm::vec3 worldPosition = SpatiallyNestable::localToWorld(entitySideProperties.getPosition(), + entitySideProperties.getParentID(), + entitySideProperties.getParentJointIndex()); + glm::quat worldRotation = SpatiallyNestable::localToWorld(entitySideProperties.getRotation(), + entitySideProperties.getParentID(), + entitySideProperties.getParentJointIndex()); + scriptSideProperties.setPosition(worldPosition); + scriptSideProperties.setRotation(worldRotation); + + return scriptSideProperties; +} + + +EntityItemProperties convertLocationFromScriptSemantics(EntityItemProperties scriptSideProperties) { + // convert position and rotation properties from world-space to local, unless localPosition and localRotation + // are set. If they are set, they overwrite position and rotation. + EntityItemProperties entitySideProperties = scriptSideProperties; + + if (scriptSideProperties.localPositionChanged()) { + entitySideProperties.setPosition(scriptSideProperties.getLocalPosition()); + } else if (scriptSideProperties.positionChanged()) { + glm::vec3 localPosition = SpatiallyNestable::worldToLocal(entitySideProperties.getPosition(), + entitySideProperties.getParentID(), + entitySideProperties.getParentJointIndex()); + entitySideProperties.setPosition(localPosition); + } + + if (scriptSideProperties.localRotationChanged()) { + entitySideProperties.setRotation(scriptSideProperties.getLocalRotation()); + } else if (scriptSideProperties.rotationChanged()) { + glm::quat localRotation = SpatiallyNestable::worldToLocal(entitySideProperties.getRotation(), + entitySideProperties.getParentID(), + entitySideProperties.getParentJointIndex()); + entitySideProperties.setRotation(localRotation); + } + + return entitySideProperties; +} + + QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties) { EntityItemProperties propertiesWithSimID = properties; propertiesWithSimID.setDimensionsInitialized(properties.dimensionsChanged()); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 9aa89a6a9c..707fa37192 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -455,8 +455,9 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q EntityItemProperties properties; // explicitly set the properties that changed so that they will be packed - properties.setPosition(_entity->worldToLocal(_serverPosition)); - properties.setRotation(_entity->worldToLocal(_serverRotation)); + properties.setPosition(_entity->getLocalPosition()); + properties.setRotation(_entity->getLocalOrientation()); + properties.setVelocity(_serverVelocity); properties.setAcceleration(_serverAcceleration); properties.setAngularVelocity(_serverAngularVelocity); diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index d5e2104706..4469cfd3c3 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -94,24 +94,41 @@ void SpatiallyNestable::setParentID(const QUuid parentID) { } } -glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3 position) { - Transform parentTransform = getParentTransform(); +glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3 position, QUuid parentID, int parentJointIndex) { + QSharedPointer parentFinder = DependencyManager::get(); + auto parentWP = parentFinder->find(parentID); + auto parent = parentWP.lock(); + Transform parentTransform; + if (parent) { + parentTransform = parent->getTransform(parentJointIndex); + parentTransform.setScale(1.0f); + } + + Transform positionTransform; + positionTransform.setTranslation(position); Transform myWorldTransform; - _transformLock.withReadLock([&] { - Transform::mult(myWorldTransform, parentTransform, _transform); - }); + Transform::mult(myWorldTransform, parentTransform, positionTransform); + myWorldTransform.setTranslation(position); Transform result; Transform::inverseMult(result, parentTransform, myWorldTransform); return result.getTranslation(); } -glm::quat SpatiallyNestable::worldToLocal(const glm::quat orientation) { - Transform parentTransform = getParentTransform(); +glm::quat SpatiallyNestable::worldToLocal(const glm::quat orientation, QUuid parentID, int parentJointIndex) { + QSharedPointer parentFinder = DependencyManager::get(); + auto parentWP = parentFinder->find(parentID); + auto parent = parentWP.lock(); + Transform parentTransform; + if (parent) { + parentTransform = parent->getTransform(parentJointIndex); + parentTransform.setScale(1.0f); + } + + Transform orientationTransform; + orientationTransform.setRotation(orientation); Transform myWorldTransform; - _transformLock.withReadLock([&] { - Transform::mult(myWorldTransform, parentTransform, _transform); - }); + Transform::mult(myWorldTransform, parentTransform, orientationTransform); myWorldTransform.setRotation(orientation); Transform result; Transform::inverseMult(result, parentTransform, myWorldTransform); diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 5074779d8e..bbef61b93a 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -47,8 +47,8 @@ public: virtual quint16 getParentJointIndex() const { return _parentJointIndex; } virtual void setParentJointIndex(quint16 parentJointIndex) { _parentJointIndex = parentJointIndex; } - glm::vec3 worldToLocal(const glm::vec3 position); - glm::quat worldToLocal(const glm::quat orientation); + static glm::vec3 worldToLocal(const glm::vec3 position, QUuid parentID, int parentJointIndex); + static glm::quat worldToLocal(const glm::quat orientation, QUuid parentID, int parentJointIndex); static glm::vec3 localToWorld(const glm::vec3 position, QUuid parentID, int parentJointIndex); static glm::quat localToWorld(const glm::quat orientation, QUuid parentID, int parentJointIndex); From 5019f79947eb5bc13f1fe87f867ed2e469c35073 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 30 Nov 2015 11:48:34 -0800 Subject: [PATCH 218/401] Fix header name --- libraries/octree/src/OctreeElementBag.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/octree/src/OctreeElementBag.h b/libraries/octree/src/OctreeElementBag.h index b5f4d5dcf5..c0bfa15472 100644 --- a/libraries/octree/src/OctreeElementBag.h +++ b/libraries/octree/src/OctreeElementBag.h @@ -17,7 +17,7 @@ #define hifi_OctreeElementBag_h #include "OctreeElement.h" -#include +#include class OctreeElementBag { public: From 242167ebf2fdc3dcc02e763f0dbe7239e0a58985 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 30 Nov 2015 11:52:07 -0800 Subject: [PATCH 219/401] Remove debug messages --- libraries/networking/src/AssetClient.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index b5f7f6ea18..4e7e7f24ba 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -256,15 +256,12 @@ void AssetClient::handleAssetGetReply(QSharedPointer message, S callbacks.completeCallback(true, error, message->readAll()); } else { connect(message.data(), &ReceivedMessage::progress, this, [this, length, message, callbacks]() { - qDebug() << "Progress: " << message->getSize(), length; callbacks.progressCallback(message->getSize(), length); }); connect(message.data(), &ReceivedMessage::completed, this, [this, message, error, callbacks]() { if (message->failed()) { - qDebug() << "Failed to received asset :("; callbacks.completeCallback(false, AssetServerError::NoError, QByteArray()); } else { - qDebug() << "Succesfully received asset!"; callbacks.completeCallback(true, error, message->readAll()); } }); From 5e27af507674f1347988ffb96897b77f7a3d72bd Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 30 Nov 2015 11:52:21 -0800 Subject: [PATCH 220/401] Remove old comment in PacketReceiver --- libraries/networking/src/PacketReceiver.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/networking/src/PacketReceiver.h b/libraries/networking/src/PacketReceiver.h index 46dffe3498..ff4ab3e15c 100644 --- a/libraries/networking/src/PacketReceiver.h +++ b/libraries/networking/src/PacketReceiver.h @@ -89,7 +89,6 @@ private: void registerVerifiedListener(PacketType type, QObject* listener, const QMetaMethod& slot, bool deliverPending = false); QMutex _packetListenerLock; - // TODO: replace the two following hashes with an std::vector once we switch Packet/PacketList to Message QHash _messageListenerMap; int _inPacketCount = 0; int _inByteCount = 0; From 2e76f0e0d8914a0816a5118c164fa6953dcf8f7a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 30 Nov 2015 11:52:49 -0800 Subject: [PATCH 221/401] Update ReceivedMessage progress to only trigger every 100 packets --- libraries/networking/src/ReceivedMessage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/ReceivedMessage.cpp b/libraries/networking/src/ReceivedMessage.cpp index 94afa97c04..f383257520 100644 --- a/libraries/networking/src/ReceivedMessage.cpp +++ b/libraries/networking/src/ReceivedMessage.cpp @@ -54,7 +54,7 @@ void ReceivedMessage::appendPacket(NLPacket& packet) { "We should not be appending to a complete message"); // Limit progress signal to every X packets - const int EMIT_PROGRESS_EVERY_X_PACKETS = 50; + const int EMIT_PROGRESS_EVERY_X_PACKETS = 100; ++_numPackets; From 304b105dac6025c8f8235d343da608b084d8a18b Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 30 Nov 2015 11:53:08 -0800 Subject: [PATCH 222/401] Add proper message failure handling to Connection --- libraries/networking/src/udt/Connection.cpp | 8 ++++++++ libraries/networking/src/udt/Connection.h | 2 ++ libraries/networking/src/udt/Socket.cpp | 6 ++++++ libraries/networking/src/udt/Socket.h | 1 + 4 files changed, 17 insertions(+) diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index 3bbde8380a..e63d44e72f 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -49,6 +49,11 @@ Connection::Connection(Socket* parentSocket, HifiSockAddr destination, std::uniq Connection::~Connection() { stopSendQueue(); + + // Fail any pending received messages + for (auto& pendingMessage : _pendingReceivedMessages) { + _parentSocket->messageFailed(this, pendingMessage.first); + } } void Connection::stopSendQueue() { @@ -805,6 +810,9 @@ void Connection::resetReceiveState() { _receivedControlProbeTail = false; // clear any pending received messages + for (auto& pendingMessage : _pendingReceivedMessages) { + _parentSocket->messageFailed(this, pendingMessage.first); + } _pendingReceivedMessages.clear(); } diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index d37439b6de..f8c4acd7d9 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -74,6 +74,8 @@ public: bool isActive() const { return _isActive; } + HifiSockAddr getDestination() const { return _destination; } + signals: void packetSent(); void connectionInactive(const HifiSockAddr& sockAddr); diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index d891b42ffd..8007ae66c0 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -218,6 +218,12 @@ void Socket::messageReceived(std::unique_ptr packet) { } } +void Socket::messageFailed(Connection* connection, Packet::MessageNumber messageNumber) { + if (_messageFailureHandler) { + _messageFailureHandler(connection->getDestination(), messageNumber); + } +} + void Socket::readPendingDatagrams() { int packetSizeWithHeader = -1; while ((packetSizeWithHeader = _udpSocket.pendingDatagramSize()) != -1) { diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 65a820b2bd..88db8e3d86 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -74,6 +74,7 @@ public: void setCongestionControlFactory(std::unique_ptr ccFactory); void messageReceived(std::unique_ptr packet); + void messageFailed(Connection* connection, Packet::MessageNumber messageNumber); StatsVector sampleStatsForAllConnections(); From 5849befb3d167b918b62071ca3e04657c220fd8c Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 30 Nov 2015 11:53:53 -0800 Subject: [PATCH 223/401] Add caching back to AssetRequest --- libraries/networking/src/AssetRequest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/AssetRequest.cpp b/libraries/networking/src/AssetRequest.cpp index 78f146fa93..19f91349fb 100644 --- a/libraries/networking/src/AssetRequest.cpp +++ b/libraries/networking/src/AssetRequest.cpp @@ -110,7 +110,7 @@ void AssetRequest::start() { _totalReceived += data.size(); emit progress(_totalReceived, _info.size); - //saveToCache(getUrl(), data); + saveToCache(getUrl(), data); } else { // hash doesn't match - we have an error _error = HashVerificationFailed; From 4b87e0984806e7d2cb1eb1d4346defd4ddfe2c16 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 30 Nov 2015 13:23:55 -0800 Subject: [PATCH 224/401] clean up some unneeded consts. get edit.js closer to working on parented entities --- .../entities/src/EntityItemProperties.cpp | 8 ++-- libraries/entities/src/EntityItemProperties.h | 2 +- .../entities/src/EntityScriptingInterface.cpp | 16 ++++++-- libraries/shared/src/SpatialParentFinder.h | 2 - libraries/shared/src/SpatiallyNestable.cpp | 38 +++++++++---------- libraries/shared/src/SpatiallyNestable.h | 38 +++++++++---------- 6 files changed, 55 insertions(+), 49 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index d08e677c48..2ecb42a9ce 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -356,7 +356,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_FINISH, alphaFinish); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ADDITIVE_BLENDING, additiveBlending); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_POSITION, localPosition); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localrotation); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localRotation); } // Models only @@ -1498,12 +1498,10 @@ AABox EntityItemProperties::getAABox() const { glm::vec3 unrotatedMinRelativeToEntity = - (_dimensions * _registrationPoint); glm::vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder; Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; - glm::quat worldRotation = SpatiallyNestable::localToWorld(getRotation(), _parentID, _parentJointIndex); - Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(worldRotation); + Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(_rotation); // shift the extents to be relative to the position/registration point - glm::vec3 worldPosition = SpatiallyNestable::localToWorld(_position, _parentID, _parentJointIndex); - rotatedExtentsRelativeToRegistrationPoint.shiftBy(worldPosition); + rotatedExtentsRelativeToRegistrationPoint.shiftBy(_position); return AABox(rotatedExtentsRelativeToRegistrationPoint); } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index bcb48a1903..6bb6b1914c 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -193,7 +193,7 @@ public: DEFINE_PROPERTY_REF(PROP_PARENT_JOINT_INDEX, ParentJointIndex, parentJointIndex, quint16, 0); // these are used when bouncing location data into and out of scripts - DEFINE_PROPERTY_REF_WITH_SETTER(PROP_LOCAL_POSITION, LocalPosition, localPosition, glmVec3, ENTITY_ITEM_ZERO_VEC3); + DEFINE_PROPERTY_REF(PROP_LOCAL_POSITION, LocalPosition, localPosition, glmVec3, ENTITY_ITEM_ZERO_VEC3); DEFINE_PROPERTY_REF(PROP_LOCAL_ROTATION, LocalRotation, localRotation, glmQuat, ENTITY_ITEM_DEFAULT_ROTATION); static QString getBackgroundModeString(BackgroundMode mode); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 8a8150d017..ca963aca6d 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -113,7 +113,7 @@ EntityItemProperties convertLocationFromScriptSemantics(EntityItemProperties scr QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties) { - EntityItemProperties propertiesWithSimID = properties; + EntityItemProperties propertiesWithSimID = convertLocationFromScriptSemantics(properties); propertiesWithSimID.setDimensionsInitialized(properties.dimensionsChanged()); EntityItemID id = EntityItemID(QUuid::createUuid()); @@ -159,6 +159,15 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit _entityTree->withReadLock([&] { EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(identity)); if (entity) { + if (desiredProperties.getHasProperty(PROP_POSITION) || + desiredProperties.getHasProperty(PROP_ROTATION) || + desiredProperties.getHasProperty(PROP_LOCAL_POSITION) || + desiredProperties.getHasProperty(PROP_LOCAL_ROTATION)) { + // if we are explicitly getting position or rotation, we need parent information to make sense of them. + desiredProperties.setHasProperty(PROP_PARENT_ID); + desiredProperties.setHasProperty(PROP_PARENT_JOINT_INDEX); + } + results = entity->getProperties(desiredProperties); // TODO: improve sitting points and naturalDimensions in the future, @@ -178,10 +187,11 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit }); } - return results; + return convertLocationToScriptSemantics(results); } -QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties properties) { +QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties scriptSideProperties) { + EntityItemProperties properties = convertLocationFromScriptSemantics(scriptSideProperties); EntityItemID entityID(id); // If we have a local entity tree set, then also update it. if (!_entityTree) { diff --git a/libraries/shared/src/SpatialParentFinder.h b/libraries/shared/src/SpatialParentFinder.h index 9cadbaf8ce..936d497eae 100644 --- a/libraries/shared/src/SpatialParentFinder.h +++ b/libraries/shared/src/SpatialParentFinder.h @@ -19,8 +19,6 @@ class SpatiallyNestable; using SpatiallyNestableWeakPointer = std::weak_ptr; using SpatiallyNestablePointer = std::shared_ptr; -class SpatialParentFinder; -using SpatialParentFinderPointer = std::shared_ptr; class SpatialParentFinder : public Dependency { diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 4469cfd3c3..31a0dd5647 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -94,7 +94,7 @@ void SpatiallyNestable::setParentID(const QUuid parentID) { } } -glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3 position, QUuid parentID, int parentJointIndex) { +glm::vec3 SpatiallyNestable::worldToLocal(glm::vec3 position, QUuid parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); auto parentWP = parentFinder->find(parentID); auto parent = parentWP.lock(); @@ -115,7 +115,7 @@ glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3 position, QUuid parent return result.getTranslation(); } -glm::quat SpatiallyNestable::worldToLocal(const glm::quat orientation, QUuid parentID, int parentJointIndex) { +glm::quat SpatiallyNestable::worldToLocal(glm::quat orientation, QUuid parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); auto parentWP = parentFinder->find(parentID); auto parent = parentWP.lock(); @@ -135,7 +135,7 @@ glm::quat SpatiallyNestable::worldToLocal(const glm::quat orientation, QUuid par return result.getRotation(); } -glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3 position, QUuid parentID, int parentJointIndex) { +glm::vec3 SpatiallyNestable::localToWorld(glm::vec3 position, QUuid parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); auto parentWP = parentFinder->find(parentID); auto parent = parentWP.lock(); @@ -151,7 +151,7 @@ glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3 position, QUuid parent return result.getTranslation(); } -glm::quat SpatiallyNestable::localToWorld(const glm::quat orientation, QUuid parentID, int parentJointIndex) { +glm::quat SpatiallyNestable::localToWorld(glm::quat orientation, QUuid parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); auto parentWP = parentFinder->find(parentID); auto parent = parentWP.lock(); @@ -168,7 +168,7 @@ glm::quat SpatiallyNestable::localToWorld(const glm::quat orientation, QUuid par } -const glm::vec3 SpatiallyNestable::getPosition() const { +glm::vec3 SpatiallyNestable::getPosition() const { Transform parentTransformDescaled = getParentTransform(); glm::mat4 parentMat; parentTransformDescaled.getMatrix(parentMat); @@ -176,7 +176,7 @@ const glm::vec3 SpatiallyNestable::getPosition() const { return glm::vec3(absPos); } -const glm::vec3 SpatiallyNestable::getPosition(int jointIndex) const { +glm::vec3 SpatiallyNestable::getPosition(int jointIndex) const { Transform worldTransform = getTransform(); Transform jointInObjectFrame = getJointTransformInObjectFrame(jointIndex); Transform jointInWorldFrame; @@ -184,7 +184,7 @@ const glm::vec3 SpatiallyNestable::getPosition(int jointIndex) const { return jointInWorldFrame.getTranslation(); } -void SpatiallyNestable::setPosition(const glm::vec3 position) { +void SpatiallyNestable::setPosition(glm::vec3 position) { Transform parentTransform = getParentTransform(); Transform myWorldTransform; _transformLock.withWriteLock([&] { @@ -194,12 +194,12 @@ void SpatiallyNestable::setPosition(const glm::vec3 position) { }); } -const glm::quat SpatiallyNestable::getOrientation() const { +glm::quat SpatiallyNestable::getOrientation() const { Transform parentTransformDescaled = getParentTransform(); return parentTransformDescaled.getRotation() * getLocalOrientation(); } -const glm::quat SpatiallyNestable::getOrientation(int jointIndex) const { +glm::quat SpatiallyNestable::getOrientation(int jointIndex) const { Transform worldTransform = getTransform(); Transform jointInObjectFrame = getJointTransformInObjectFrame(jointIndex); Transform jointInWorldFrame; @@ -207,7 +207,7 @@ const glm::quat SpatiallyNestable::getOrientation(int jointIndex) const { return jointInWorldFrame.getRotation(); } -void SpatiallyNestable::setOrientation(const glm::quat orientation) { +void SpatiallyNestable::setOrientation(glm::quat orientation) { Transform parentTransform = getParentTransform(); Transform myWorldTransform; _transformLock.withWriteLock([&] { @@ -241,7 +241,7 @@ void SpatiallyNestable::setTransform(const Transform transform) { }); } -const glm::vec3 SpatiallyNestable::getScale() const { +glm::vec3 SpatiallyNestable::getScale() const { glm::vec3 result; _transformLock.withReadLock([&] { result = _transform.getScale(); @@ -249,12 +249,12 @@ const glm::vec3 SpatiallyNestable::getScale() const { return result; } -const glm::vec3 SpatiallyNestable::getScale(int jointIndex) const { +glm::vec3 SpatiallyNestable::getScale(int jointIndex) const { // XXX ... something with joints return getScale(); } -void SpatiallyNestable::setScale(const glm::vec3 scale) { +void SpatiallyNestable::setScale(glm::vec3 scale) { _transformLock.withWriteLock([&] { _transform.setScale(scale); }); @@ -274,7 +274,7 @@ void SpatiallyNestable::setLocalTransform(const Transform transform) { }); } -const glm::vec3 SpatiallyNestable::getLocalPosition() const { +glm::vec3 SpatiallyNestable::getLocalPosition() const { glm::vec3 result; _transformLock.withReadLock([&] { result = _transform.getTranslation(); @@ -282,13 +282,13 @@ const glm::vec3 SpatiallyNestable::getLocalPosition() const { return result; } -void SpatiallyNestable::setLocalPosition(const glm::vec3 position) { +void SpatiallyNestable::setLocalPosition(glm::vec3 position) { _transformLock.withWriteLock([&] { _transform.setTranslation(position); }); } -const glm::quat SpatiallyNestable::getLocalOrientation() const { +glm::quat SpatiallyNestable::getLocalOrientation() const { glm::quat result; _transformLock.withReadLock([&] { result = _transform.getRotation(); @@ -296,13 +296,13 @@ const glm::quat SpatiallyNestable::getLocalOrientation() const { return result; } -void SpatiallyNestable::setLocalOrientation(const glm::quat orientation) { +void SpatiallyNestable::setLocalOrientation(glm::quat orientation) { _transformLock.withWriteLock([&] { _transform.setRotation(orientation); }); } -const glm::vec3 SpatiallyNestable::getLocalScale() const { +glm::vec3 SpatiallyNestable::getLocalScale() const { glm::vec3 result; _transformLock.withReadLock([&] { result = _transform.getScale(); @@ -310,7 +310,7 @@ const glm::vec3 SpatiallyNestable::getLocalScale() const { return result; } -void SpatiallyNestable::setLocalScale(const glm::vec3 scale) { +void SpatiallyNestable::setLocalScale(glm::vec3 scale) { _transformLock.withWriteLock([&] { _transform.setScale(scale); }); diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index bbef61b93a..962399d080 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -47,11 +47,11 @@ public: virtual quint16 getParentJointIndex() const { return _parentJointIndex; } virtual void setParentJointIndex(quint16 parentJointIndex) { _parentJointIndex = parentJointIndex; } - static glm::vec3 worldToLocal(const glm::vec3 position, QUuid parentID, int parentJointIndex); - static glm::quat worldToLocal(const glm::quat orientation, QUuid parentID, int parentJointIndex); + static glm::vec3 worldToLocal(glm::vec3 position, QUuid parentID, int parentJointIndex); + static glm::quat worldToLocal(glm::quat orientation, QUuid parentID, int parentJointIndex); - static glm::vec3 localToWorld(const glm::vec3 position, QUuid parentID, int parentJointIndex); - static glm::quat localToWorld(const glm::quat orientation, QUuid parentID, int parentJointIndex); + static glm::vec3 localToWorld(glm::vec3 position, QUuid parentID, int parentJointIndex); + static glm::quat localToWorld(glm::quat orientation, QUuid parentID, int parentJointIndex); // world frame virtual const Transform getTransform() const; @@ -59,33 +59,33 @@ public: virtual Transform getParentTransform() const; - virtual const glm::vec3 getPosition() const; - virtual void setPosition(const glm::vec3 position); + virtual glm::vec3 getPosition() const; + virtual void setPosition(glm::vec3 position); - virtual const glm::quat getOrientation() const; - virtual const glm::quat getOrientation(int jointIndex) const; - virtual void setOrientation(const glm::quat orientation); + virtual glm::quat getOrientation() const; + virtual glm::quat getOrientation(int jointIndex) const; + virtual void setOrientation(glm::quat orientation); - virtual const glm::vec3 getScale() const; - virtual void setScale(const glm::vec3 scale); + virtual glm::vec3 getScale() const; + virtual void setScale(glm::vec3 scale); // get world location of a specific joint virtual const Transform getTransform(int jointIndex) const; - virtual const glm::vec3 getPosition(int jointIndex) const; - virtual const glm::vec3 getScale(int jointIndex) const; + virtual glm::vec3 getPosition(int jointIndex) const; + virtual glm::vec3 getScale(int jointIndex) const; // object's parent's frame virtual const Transform getLocalTransform() const; virtual void setLocalTransform(const Transform transform); - virtual const glm::vec3 getLocalPosition() const; - virtual void setLocalPosition(const glm::vec3 position); + virtual glm::vec3 getLocalPosition() const; + virtual void setLocalPosition(glm::vec3 position); - virtual const glm::quat getLocalOrientation() const; - virtual void setLocalOrientation(const glm::quat orientation); + virtual glm::quat getLocalOrientation() const; + virtual void setLocalOrientation(glm::quat orientation); - virtual const glm::vec3 getLocalScale() const; - virtual void setLocalScale(const glm::vec3 scale); + virtual glm::vec3 getLocalScale() const; + virtual void setLocalScale(glm::vec3 scale); QList getChildren() const; NestableTypes::NestableType getNestableType() const { return _nestableType; } From 941dfe5bd2dcb09f4a32878f0743432acc74be01 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 30 Nov 2015 13:30:47 -0800 Subject: [PATCH 225/401] initialize _parentJointIndex --- libraries/shared/src/SpatiallyNestable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 962399d080..8805e72af5 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -99,7 +99,7 @@ protected: NestableTypes::NestableType _nestableType; // EntityItem or an AvatarData QUuid _id; QUuid _parentID; // what is this thing's transform relative to? - quint16 _parentJointIndex; // which joint of the parent is this relative to? + quint16 _parentJointIndex { 0 }; // which joint of the parent is this relative to? SpatiallyNestablePointer getParentPointer() const; mutable SpatiallyNestableWeakPointer _parent; From 89b78986d5b219bec205348840aa6e43f6306645 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 30 Nov 2015 14:01:17 -0800 Subject: [PATCH 226/401] remove some more stray const --- interface/src/avatar/Avatar.h | 4 ++-- libraries/avatars/src/AvatarData.h | 4 ++-- libraries/entities/src/EntityItem.h | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 51768e4e71..60040fd493 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -161,8 +161,8 @@ public: void setMotionState(AvatarMotionState* motionState) { _motionState = motionState; } AvatarMotionState* getMotionState() { return _motionState; } - virtual void setPosition(const glm::vec3 position); - virtual void setOrientation(const glm::quat orientation); + virtual void setPosition(glm::vec3 position); + virtual void setOrientation(glm::quat orientation); public slots: diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 8db0ef5897..0cdc285021 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -201,8 +201,8 @@ public: float getBodyRoll() const; void setBodyRoll(float bodyRoll); - virtual void setPosition(const glm::vec3 position); - virtual void setOrientation(const glm::quat orientation); + virtual void setPosition(glm::vec3 position); + virtual void setOrientation(glm::quat orientation); void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time. void startCapture(); // start/end of the period in which the latest values are about to be captured for camera, etc. diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index cd5f97bee2..bccfccc628 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -330,10 +330,10 @@ public: // virtual const glm::vec3 getPosition() const { return SpatiallyNestable::getPosition(); } virtual const glm::quat getRotation() const { return SpatiallyNestable::getOrientation(); } - virtual void setPosition(const glm::vec3 position); - virtual void setLocalPosition(const glm::vec3 position); - virtual void setRotation(const glm::quat orientation); - virtual void setLocalRotation(const glm::quat orientation); + virtual void setPosition(glm::vec3 position); + virtual void setLocalPosition(glm::vec3 position); + virtual void setRotation(glm::quat orientation); + virtual void setLocalRotation(glm::quat orientation); // updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags void updatePosition(const glm::vec3& value); From a33e57dfdb9ceb3e82d69c7601ba2d5dd4d5a773 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Nov 2015 14:06:09 -0800 Subject: [PATCH 227/401] remove audio files from history --- examples/baseball/audio/assets.txt | 23 ----------------------- examples/baseball/audio/attribution.txt | 8 -------- 2 files changed, 31 deletions(-) delete mode 100644 examples/baseball/audio/assets.txt delete mode 100644 examples/baseball/audio/attribution.txt diff --git a/examples/baseball/audio/assets.txt b/examples/baseball/audio/assets.txt deleted file mode 100644 index 225714cbe1..0000000000 --- a/examples/baseball/audio/assets.txt +++ /dev/null @@ -1,23 +0,0 @@ -crowd-boos.wav -atp:c632c92b166ade60aa16b23ff1dfdf712856caeb83bd9311980b2d5edac821af.wav - -crowd-cheers-organ.wav -atp:b8044401a846ed29f881a0b9b80cf1ba41f26327180c28fc9c70d144f9b70045.wav - -crowd-medium.wav -atp:0821bf2ac60dd2f356dfdd948e8bb89c23984dc3584612f6c815765154f02cae.wav - -baseball-hitting-bat-1.wav -atp:6f0b691a0c9c9ece6557d97fe242b1faec4020fe26efc9c17327993b513c5fe5.wav - -baseball-hitting-bat-set-1.wav -atp:5be5806205158ebdc5c3623ceb7ae73315028b51ffeae24292aff7042e3fa6a9.wav - -baseball-hitting-bat-set-2.wav -atp:e68661374e2145c480809c26134782aad11e0de456c7802170c7abccc4028873.wav - -baseball-hitting-bat-set-3.wav -atp:787e3c9af17dd3929527787176ede83d6806260e63ddd5a4cef48cd22e32c6f7.wav - -baseball-hitting-bat-set-4.wav -atp:fc65383431a6238c7a4749f0f6f061f75a604ed5e17d775ab1b2955609e67ebb.wav \ No newline at end of file diff --git a/examples/baseball/audio/attribution.txt b/examples/baseball/audio/attribution.txt deleted file mode 100644 index 760951447c..0000000000 --- a/examples/baseball/audio/attribution.txt +++ /dev/null @@ -1,8 +0,0 @@ -Baseball bat hitting sounds -https://www.freesound.org/people/SocializedArtist45/sounds/266595/ -https://www.freesound.org/people/CGEffex/sounds/93136/ - -Crowd Sounds -http://freesound.org/people/AshFox/sounds/191925/ -http://freesound.org/people/AshFox/sounds/191928/ -http://freesound.org/people/AshFox/sounds/191929/ \ No newline at end of file From 5c327edd5a8e1825e19a68a7cd5f81b3ca1cd0d4 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 30 Nov 2015 14:08:07 -0800 Subject: [PATCH 228/401] keep AvatarHashMap::findAvatar from creating bogus avatar entries. remove some more stray consts --- cmake/externals/quazip/CMakeLists.txt | 2 +- interface/src/Application.cpp | 2 +- interface/src/Application.h | 2 +- libraries/avatars/src/AvatarHashMap.cpp | 5 ++++- libraries/render-utils/src/AbstractViewStateInterface.h | 2 +- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/cmake/externals/quazip/CMakeLists.txt b/cmake/externals/quazip/CMakeLists.txt index ddac942692..eadbecd2ad 100644 --- a/cmake/externals/quazip/CMakeLists.txt +++ b/cmake/externals/quazip/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_policy(SET CMP0046 OLD) include(ExternalProject) -string(REPLACE \\ / QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH}) +# string(REPLACE \\ / QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH}) ExternalProject_Add( ${EXTERNAL_NAME} URL http://s3-us-west-1.amazonaws.com/hifi-production/dependencies/quazip-0.6.2.zip diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0220d2b56c..1fff97c916 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3329,7 +3329,7 @@ MyAvatar* Application::getMyAvatar() const { return DependencyManager::get()->getMyAvatar(); } -const glm::vec3 Application::getAvatarPosition() const { +glm::vec3 Application::getAvatarPosition() const { return getMyAvatar()->getPosition(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 0467926b47..e615eeaeaa 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -185,7 +185,7 @@ public: virtual float getSizeScale() const; virtual int getBoundaryLevelAdjust() const; virtual PickRay computePickRay(float x, float y) const; - virtual const glm::vec3 getAvatarPosition() const; + virtual glm::vec3 getAvatarPosition() const; virtual void overrideEnvironmentData(const EnvironmentData& newData) { _environment.override(newData); } virtual void endOverrideEnvironmentData() { _environment.endOverride(); } virtual qreal getDevicePixelRatio(); diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index c195ab4c32..84fff8d114 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -65,7 +65,10 @@ AvatarSharedPointer AvatarHashMap::newOrExistingAvatar(const QUuid& sessionUUID, AvatarSharedPointer AvatarHashMap::findAvatar(const QUuid& sessionUUID) { QReadLocker locker(&_hashLock); - return _avatarHash.value(sessionUUID); + if (_avatarHash.contains(sessionUUID)) { + return _avatarHash.value(sessionUUID); + } + return nullptr; } void AvatarHashMap::processAvatarDataPacket(QSharedPointer packet, SharedNodePointer sendingNode) { diff --git a/libraries/render-utils/src/AbstractViewStateInterface.h b/libraries/render-utils/src/AbstractViewStateInterface.h index 2954c1fce4..39da33ee8f 100644 --- a/libraries/render-utils/src/AbstractViewStateInterface.h +++ b/libraries/render-utils/src/AbstractViewStateInterface.h @@ -45,7 +45,7 @@ public: virtual int getBoundaryLevelAdjust() const = 0; virtual PickRay computePickRay(float x, float y) const = 0; - virtual const glm::vec3 getAvatarPosition() const = 0; + virtual glm::vec3 getAvatarPosition() const = 0; virtual void postLambdaEvent(std::function f) = 0; virtual qreal getDevicePixelRatio() = 0; From aa383455f5967dfdcdf542fcf2fa29f4111f10ad Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 30 Nov 2015 14:09:19 -0800 Subject: [PATCH 229/401] oops --- cmake/externals/quazip/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/externals/quazip/CMakeLists.txt b/cmake/externals/quazip/CMakeLists.txt index eadbecd2ad..ddac942692 100644 --- a/cmake/externals/quazip/CMakeLists.txt +++ b/cmake/externals/quazip/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_policy(SET CMP0046 OLD) include(ExternalProject) -# string(REPLACE \\ / QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH}) +string(REPLACE \\ / QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH}) ExternalProject_Add( ${EXTERNAL_NAME} URL http://s3-us-west-1.amazonaws.com/hifi-production/dependencies/quazip-0.6.2.zip From 4aaa9ca02f10f6d51c524e2423a5e59fa1889a62 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 30 Nov 2015 15:23:49 -0800 Subject: [PATCH 230/401] Make OctreeElementBag safer to use --- .../src/octree/OctreeQueryNode.cpp | 6 ++-- .../src/octree/OctreeSendThread.cpp | 4 +-- libraries/entities/src/EntityTreeElement.cpp | 2 +- libraries/entities/src/EntityTreeElement.h | 2 +- libraries/octree/src/Octree.cpp | 6 ++-- libraries/octree/src/Octree.h | 17 +++++------ libraries/octree/src/OctreeElement.h | 3 +- libraries/octree/src/OctreeElementBag.cpp | 28 +++++++++---------- libraries/octree/src/OctreeElementBag.h | 17 ++++++----- 9 files changed, 37 insertions(+), 48 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 10f1d2ec14..cff2c7ee2e 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -336,8 +336,7 @@ void OctreeQueryNode::dumpOutOfView() { int stillInView = 0; int outOfView = 0; OctreeElementBag tempBag; - while (!elementBag.isEmpty()) { - OctreeElementPointer elementToCheck = elementBag.extract(); + while (OctreeElementPointer elementToCheck = elementBag.extract()) { if (elementToCheck->isInView(_currentViewFrustum)) { tempBag.insert(elementToCheck); stillInView++; @@ -346,8 +345,7 @@ void OctreeQueryNode::dumpOutOfView() { } } if (stillInView > 0) { - while (!tempBag.isEmpty()) { - OctreeElementPointer elementToKeepInBag = tempBag.extract(); + while (OctreeElementPointer elementToKeepInBag = tempBag.extract()) { if (elementToKeepInBag->isInView(_currentViewFrustum)) { elementBag.insert(elementToKeepInBag); } diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 7c8d8f0e01..84caf9ce81 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -417,7 +417,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus quint64 startInside = usecTimestampNow(); bool lastNodeDidntFit = false; // assume each node fits - if (!nodeData->elementBag.isEmpty()) { + if (OctreeElementPointer subTree = nodeData->elementBag.extract()) { quint64 lockWaitStart = usecTimestampNow(); _myServer->getOctree()->withReadLock([&]{ @@ -425,8 +425,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart); quint64 encodeStart = usecTimestampNow(); - OctreeElementPointer subTree = nodeData->elementBag.extract(); - /* TODO: Looking for a way to prevent locking and encoding a tree that is not // going to result in any packets being sent... // diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 8403db8b2f..ff2e97e8fe 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -153,7 +153,7 @@ void EntityTreeElement::updateEncodedData(int childIndex, AppendState childAppen -void EntityTreeElement::elementEncodeComplete(EncodeBitstreamParams& params, OctreeElementBag* bag) const { +void EntityTreeElement::elementEncodeComplete(EncodeBitstreamParams& params) const { const bool wantDebug = false; if (wantDebug) { diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index 57e0bea696..d8a182156d 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -122,7 +122,7 @@ public: virtual bool shouldIncludeChildData(int childIndex, EncodeBitstreamParams& params) const; virtual bool shouldRecurseChildTree(int childIndex, EncodeBitstreamParams& params) const; virtual void updateEncodedData(int childIndex, AppendState childAppendState, EncodeBitstreamParams& params) const; - virtual void elementEncodeComplete(EncodeBitstreamParams& params, OctreeElementBag* bag) const; + virtual void elementEncodeComplete(EncodeBitstreamParams& params) const; bool alreadyFullyEncoded(EncodeBitstreamParams& params) const; diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 6f73be360f..c02a034778 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -1736,7 +1736,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // If our element is completed let the element know so it can do any cleanup it of extra wants if (elementAppendState == OctreeElement::COMPLETED) { - element->elementEncodeComplete(params, &bag); + element->elementEncodeComplete(params); } return bytesAtThisLevel; @@ -2104,9 +2104,7 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElementPointer element) int bytesWritten = 0; bool lastPacketWritten = false; - while (!elementBag.isEmpty()) { - OctreeElementPointer subTree = elementBag.extract(); - + while (OctreeElementPointer subTree = elementBag.extract()) { EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); withReadLock([&] { params.extraEncodeData = &extraEncodeData; diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 5ebb991d49..d9cf17d7de 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -18,16 +18,6 @@ #include #include -class CoverageMap; -class ReadBitstreamToTreeParams; -class Octree; -class OctreeElement; -class OctreeElementBag; -class OctreePacketData; -class Shape; -typedef std::shared_ptr OctreePointer; - - #include #include @@ -38,6 +28,13 @@ typedef std::shared_ptr OctreePointer; #include "OctreePacketData.h" #include "OctreeSceneStats.h" +class CoverageMap; +class ReadBitstreamToTreeParams; +class Octree; +class OctreeElement; +class OctreePacketData; +class Shape; +using OctreePointer = std::shared_ptr; extern QVector PERSIST_EXTENSIONS; diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index c686970c3a..3c25ec0850 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -32,7 +32,6 @@ using AtomicUIntStat = std::atomic; class EncodeBitstreamParams; class Octree; class OctreeElement; -class OctreeElementBag; class OctreePacketData; class ReadBitstreamToTreeParams; class Shape; @@ -91,7 +90,7 @@ public: virtual bool shouldRecurseChildTree(int childIndex, EncodeBitstreamParams& params) const { return true; } virtual void updateEncodedData(int childIndex, AppendState childAppendState, EncodeBitstreamParams& params) const { } - virtual void elementEncodeComplete(EncodeBitstreamParams& params, OctreeElementBag* bag) const { } + virtual void elementEncodeComplete(EncodeBitstreamParams& params) const { } /// Override to serialize the state of this element. This is used for persistance and for transmission across the network. virtual AppendState appendElementData(OctreePacketData* packetData, EncodeBitstreamParams& params) const diff --git a/libraries/octree/src/OctreeElementBag.cpp b/libraries/octree/src/OctreeElementBag.cpp index 167c3560d6..4634c05a06 100644 --- a/libraries/octree/src/OctreeElementBag.cpp +++ b/libraries/octree/src/OctreeElementBag.cpp @@ -13,29 +13,29 @@ #include void OctreeElementBag::deleteAll() { - _bagElements.clear(); + _bagElements = Bag(); +} + +bool OctreeElementBag::isEmpty() { + // Pop all expired front elements + while (!_bagElements.empty() && _bagElements.front().expired()) { + _bagElements.pop(); + } + + return _bagElements.empty(); } void OctreeElementBag::insert(OctreeElementPointer element) { - _bagElements.insert(element.get(), element); + _bagElements.push(element); } OctreeElementPointer OctreeElementBag::extract() { OctreeElementPointer result; // Find the first element still alive - while (!_bagElements.empty() && !result) { - auto it = _bagElements.begin(); - result = it->lock(); - _bagElements.erase(it); + while (!result && !_bagElements.empty()) { + result = _bagElements.front().lock(); // Grab head's shared_ptr + _bagElements.pop(); } return result; } - -bool OctreeElementBag::contains(OctreeElementPointer element) { - return _bagElements.contains(element.get()); -} - -void OctreeElementBag::remove(OctreeElementPointer element) { - _bagElements.remove(element.get()); -} diff --git a/libraries/octree/src/OctreeElementBag.h b/libraries/octree/src/OctreeElementBag.h index c0bfa15472..02423b640c 100644 --- a/libraries/octree/src/OctreeElementBag.h +++ b/libraries/octree/src/OctreeElementBag.h @@ -16,25 +16,24 @@ #ifndef hifi_OctreeElementBag_h #define hifi_OctreeElementBag_h +#include + #include "OctreeElement.h" -#include class OctreeElementBag { + using Bag = std::queue; + public: - void insert(OctreeElementPointer element); // put a element into the bag OctreeElementPointer extract(); // pull a element out of the bag (could come in any order) - bool contains(OctreeElementPointer element); // is this element in the bag? - void remove(OctreeElementPointer element); // remove a specific element from the bag - bool isEmpty() const { return _bagElements.isEmpty(); } - int count() const { return _bagElements.size(); } - + bool isEmpty(); + void deleteAll(); private: - QHash _bagElements; + Bag _bagElements; }; -typedef QMap OctreeElementExtraEncodeData; +using OctreeElementExtraEncodeData = QMap; #endif // hifi_OctreeElementBag_h From 2acfbd0f8f79b5dfb1f3be96298c007992f47259 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Nov 2015 15:52:03 -0800 Subject: [PATCH 231/401] revert accidental CCD change --- libraries/physics/src/ObjectMotionState.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 1199c3792a..7389d18143 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -135,7 +135,12 @@ void ObjectMotionState::updateCCDConfiguration() { btVector3 center; btScalar radius; _shape->getBoundingSphere(center, radius); - _body->setCcdMotionThreshold(radius / 4.0f); + _body->setCcdMotionThreshold(radius * RADIUS_MOTION_THRESHOLD_MULTIPLIER); + + // TODO: Ideally the swept sphere radius would be contained by the object. Using the bounding sphere + // radius works well for spherical objects, but may cause issues with other shapes. For arbitrary + // objects we may want to consider a different approach, such as grouping rigid bodies together. + _body->setCcdSweptSphereRadius(radius); } else { // Disable CCD From b1a69bb2cf877a58e58124df496986f85c245e97 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Nov 2015 15:52:10 -0800 Subject: [PATCH 232/401] cleanup spacing in ScriptEngine --- libraries/script-engine/src/ScriptEngine.cpp | 56 +++++++++++--------- libraries/script-engine/src/ScriptEngine.h | 2 +- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 214374af49..d578db7ca8 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -65,9 +65,9 @@ static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine){ qCDebug(scriptengine).noquote() << "script:print()<<" << message; // noquote() so that \n is treated as newline message = message.replace("\\", "\\\\") - .replace("\n", "\\n") - .replace("\r", "\\r") - .replace("'", "\\'"); + .replace("\n", "\\n") + .replace("\r", "\\r") + .replace("'", "\\'"); engine->evaluate("Script.print('" + message + "')"); return QScriptValue(); @@ -123,11 +123,11 @@ static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName } ScriptEngine::ScriptEngine(const QString& scriptContents, const QString& fileNameString, bool wantSignals) : -_scriptContents(scriptContents), -_timerFunctionMap(), -_wantSignals(wantSignals), -_fileNameString(fileNameString), -_arrayBufferClass(new ArrayBufferClass(this)) + _scriptContents(scriptContents), + _timerFunctionMap(), + _wantSignals(wantSignals), + _fileNameString(fileNameString), + _arrayBufferClass(new ArrayBufferClass(this)) { _allScriptsMutex.lock(); _allKnownScriptEngines.insert(this); @@ -495,7 +495,7 @@ void ScriptEngine::registerGetterSetter(const QString& name, QScriptEngine::Func if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING qDebug() << "*** WARNING *** ScriptEngine::registerGetterSetter() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - " name:" << name << "parent:" << parent; + " name:" << name << "parent:" << parent; #endif QMetaObject::invokeMethod(this, "registerGetterSetter", Q_ARG(const QString&, name), @@ -528,7 +528,7 @@ void ScriptEngine::removeEventHandler(const EntityItemID& entityID, const QStrin if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING qDebug() << "*** WARNING *** ScriptEngine::removeEventHandler() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - "entityID:" << entityID << " eventName:" << eventName; + "entityID:" << entityID << " eventName:" << eventName; #endif QMetaObject::invokeMethod(this, "removeEventHandler", Q_ARG(const EntityItemID&, entityID), @@ -955,7 +955,7 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac void ScriptEngine::include(const QString& includeFile, QScriptValue callback) { if (_stoppingAllScripts) { qCDebug(scriptengine) << "Script.include() while shutting down is ignored... " - << "includeFile:" << includeFile << "parent script:" << getFilename(); + << "includeFile:" << includeFile << "parent script:" << getFilename(); return; // bail early } @@ -970,7 +970,7 @@ void ScriptEngine::include(const QString& includeFile, QScriptValue callback) { void ScriptEngine::load(const QString& loadFile) { if (_stoppingAllScripts) { qCDebug(scriptengine) << "Script.load() while shutting down is ignored... " - << "loadFile:" << loadFile << "parent script:" << getFilename(); + << "loadFile:" << loadFile << "parent script:" << getFilename(); return; // bail early } @@ -1016,7 +1016,7 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING qDebug() << "*** WARNING *** ScriptEngine::loadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - "entityID:" << entityID << "entityScript:" << entityScript <<"forceRedownload:" << forceRedownload; + "entityID:" << entityID << "entityScript:" << entityScript <<"forceRedownload:" << forceRedownload; #endif QMetaObject::invokeMethod(this, "loadEntityScript", @@ -1027,18 +1027,20 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& } #ifdef THREAD_DEBUGGING qDebug() << "ScriptEngine::loadEntityScript() called on correct thread [" << thread() << "] " - "entityID:" << entityID << "entityScript:" << entityScript << "forceRedownload:" << forceRedownload; + "entityID:" << entityID << "entityScript:" << entityScript << "forceRedownload:" << forceRedownload; #endif // If we've been called our known entityScripts should not know about us.. assert(!_entityScripts.contains(entityID)); #ifdef THREAD_DEBUGGING - qDebug() << "ScriptEngine::loadEntityScript() calling scriptCache->getScriptContents() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; + qDebug() << "ScriptEngine::loadEntityScript() calling scriptCache->getScriptContents() on thread [" + << QThread::currentThread() << "] expected thread [" << thread() << "]"; #endif DependencyManager::get()->getScriptContents(entityScript, [=](const QString& scriptOrURL, const QString& contents, bool isURL, bool success) { #ifdef THREAD_DEBUGGING - qDebug() << "ScriptEngine::entityScriptContentAvailable() IN LAMBDA contentAvailable on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; + qDebug() << "ScriptEngine::entityScriptContentAvailable() IN LAMBDA contentAvailable on thread [" + << QThread::currentThread() << "] expected thread [" << thread() << "]"; #endif this->entityScriptContentAvailable(entityID, scriptOrURL, contents, isURL, success); @@ -1091,11 +1093,13 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co if (!testConstructor.isFunction()) { qCDebug(scriptengine) << "ScriptEngine::loadEntityScript() entity:" << entityID << "\n" - " NOT CONSTRUCTOR\n" - " SCRIPT:" << scriptOrURL; + " NOT CONSTRUCTOR\n" + " SCRIPT:" << scriptOrURL; + if (!isFileUrl) { scriptCache->addScriptToBadScriptList(scriptOrURL); } + return; // done processing script } @@ -1121,7 +1125,7 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) { if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING qDebug() << "*** WARNING *** ScriptEngine::unloadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - "entityID:" << entityID; + "entityID:" << entityID; #endif QMetaObject::invokeMethod(this, "unloadEntityScript", @@ -1130,7 +1134,7 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID) { } #ifdef THREAD_DEBUGGING qDebug() << "ScriptEngine::unloadEntityScript() called on correct thread [" << thread() << "] " - "entityID:" << entityID; + "entityID:" << entityID; #endif if (_entityScripts.contains(entityID)) { @@ -1195,7 +1199,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - "entityID:" << entityID << "methodName:" << methodName; + "entityID:" << entityID << "methodName:" << methodName; #endif QMetaObject::invokeMethod(this, "callEntityScriptMethod", @@ -1206,7 +1210,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS } #ifdef THREAD_DEBUGGING qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] " - "entityID:" << entityID << "methodName:" << methodName; + "entityID:" << entityID << "methodName:" << methodName; #endif refreshFileScript(entityID); @@ -1227,7 +1231,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent"; + "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent"; #endif QMetaObject::invokeMethod(this, "callEntityScriptMethod", @@ -1238,7 +1242,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS } #ifdef THREAD_DEBUGGING qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] " - "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent"; + "entityID:" << entityID << "methodName:" << methodName << "event: mouseEvent"; #endif refreshFileScript(entityID); @@ -1259,7 +1263,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING qDebug() << "*** WARNING *** ScriptEngine::callEntityScriptMethod() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision"; + "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision"; #endif QMetaObject::invokeMethod(this, "callEntityScriptMethod", @@ -1271,7 +1275,7 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS } #ifdef THREAD_DEBUGGING qDebug() << "ScriptEngine::callEntityScriptMethod() called on correct thread [" << thread() << "] " - "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision"; + "entityID:" << entityID << "methodName:" << methodName << "otherID:" << otherID << "collision: collision"; #endif refreshFileScript(entityID); diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index 59befbdd9f..90b99d46fd 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -145,7 +145,7 @@ public: // NOTE - this is used by the TypedArray implemetation. we need to review this for thread safety ArrayBufferClass* getArrayBufferClass() { return _arrayBufferClass; } - public slots: +public slots: void callAnimationStateHandler(QScriptValue callback, AnimVariantMap parameters, QStringList names, bool useNames, AnimVariantResultHandler resultHandler); signals: From 733665d722c75d64f8e7d04135591a006bb7880e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Nov 2015 15:53:42 -0800 Subject: [PATCH 233/401] fix spacing in baseballCrowd.js --- examples/acScripts/baseballCrowd.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/acScripts/baseballCrowd.js b/examples/acScripts/baseballCrowd.js index bc8965e54d..de9b53f9ec 100644 --- a/examples/acScripts/baseballCrowd.js +++ b/examples/acScripts/baseballCrowd.js @@ -11,10 +11,10 @@ var chatter = SoundCache.getSound("atp:d9978e693035d4e2b5c7b546c8cccfb2dde5677834d9eed5206ccb2da55b4732.wav"); var extras = [ - SoundCache.getSound("atp:1ee58f4d929fdef7c2989cd8be964952a24cdd653d80f57b6a89a2ae8e3029e1.wav"), // zorba - SoundCache.getSound("atp:cefaba2d5f1a378382ee046716bffcf6b6a40676649b23a1e81a996efe22d7d3.wav"), // charge - SoundCache.getSound("atp:fb41e37f8f8f7b78e546ac78800df6e39edaa09b2df4bfa0afdd8d749dac38b8.wav"), // take me out to the ball game - SoundCache.getSound("atp:44a83a788ccfd2924e35c902c34808b24dbd0309d000299ce01a355f91cf8115.wav") // clapping + SoundCache.getSound("atp:1ee58f4d929fdef7c2989cd8be964952a24cdd653d80f57b6a89a2ae8e3029e1.wav"), // zorba + SoundCache.getSound("atp:cefaba2d5f1a378382ee046716bffcf6b6a40676649b23a1e81a996efe22d7d3.wav"), // charge + SoundCache.getSound("atp:fb41e37f8f8f7b78e546ac78800df6e39edaa09b2df4bfa0afdd8d749dac38b8.wav"), // take me out to the ball game + SoundCache.getSound("atp:44a83a788ccfd2924e35c902c34808b24dbd0309d000299ce01a355f91cf8115.wav") // clapping ]; var CHATTER_VOLUME = 0.20 @@ -34,8 +34,8 @@ function playRandomExtras() { if ((!currentInjector || !currentInjector.isPlaying) && (Math.random() < (1.0 / 1800.0))) { // play a random extra sound about every 30s currentInjector = Audio.playSound( - extras[Math.floor(Math.random() * extras.length)], - { volume: EXTRA_VOLUME } + extras[Math.floor(Math.random() * extras.length)], + { volume: EXTRA_VOLUME } ); } } From c3f3639374398fc76a9327d24426d05d47dbf66e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Nov 2015 15:57:10 -0800 Subject: [PATCH 234/401] more spacing adjustments in ScriptEngine.cpp --- libraries/script-engine/src/ScriptEngine.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index d578db7ca8..96cbd79b52 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -636,7 +636,7 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi QScriptValue result; #ifdef THREAD_DEBUGGING qDebug() << "*** WARNING *** ScriptEngine::evaluate() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - "sourceCode:" << sourceCode << " fileName:" << fileName << "lineNumber:" << lineNumber; + "sourceCode:" << sourceCode << " fileName:" << fileName << "lineNumber:" << lineNumber; #endif QMetaObject::invokeMethod(this, "evaluate", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QScriptValue, result), @@ -1015,7 +1015,8 @@ void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QStrin void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& entityScript, bool forceRedownload) { if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING - qDebug() << "*** WARNING *** ScriptEngine::loadEntityScript() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " + qDebug() << "*** WARNING *** ScriptEngine::loadEntityScript() called on wrong thread [" + << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " "entityID:" << entityID << "entityScript:" << entityScript <<"forceRedownload:" << forceRedownload; #endif @@ -1052,8 +1053,10 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, const QString& scriptOrURL, const QString& contents, bool isURL, bool success) { if (QThread::currentThread() != thread()) { #ifdef THREAD_DEBUGGING - qDebug() << "*** WARNING *** ScriptEngine::entityScriptContentAvailable() called on wrong thread [" << QThread::currentThread() << "], invoking on correct thread [" << thread() << "] " - "entityID:" << entityID << "scriptOrURL:" << scriptOrURL << "contents:" << contents << "isURL:" << isURL << "success:" << success; + qDebug() << "*** WARNING *** ScriptEngine::entityScriptContentAvailable() called on wrong thread [" + << QThread::currentThread() << "], invoking on correct thread [" << thread() + << "] " "entityID:" << entityID << "scriptOrURL:" << scriptOrURL << "contents:" + << contents << "isURL:" << isURL << "success:" << success; #endif QMetaObject::invokeMethod(this, "entityScriptContentAvailable", From 1b1efe53d9dc2aa3913135bd7acfad4b196d83d4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Nov 2015 15:59:12 -0800 Subject: [PATCH 235/401] fix for two space indentation in createBatButton.js --- examples/baseball/createBatButton.js | 90 ++++++++++++++-------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index f16f126f2c..75f3dee26e 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -20,58 +20,58 @@ this.dropBats(); }; this.startFarTrigger = function() { - this.dropBats(); + this.dropBats(); }; this.dropBats = function() { - // if the bat box is near us, grab it's position - var nearby = Entities.findEntities(this.position, 20); + // if the bat box is near us, grab it's position + var nearby = Entities.findEntities(this.position, 20); - nearby.forEach(function(id) { - var properties = Entities.getEntityProperties(id, ["name", "position"]); - if (properties.name && properties.name == "Bat Box") { - boxPosition = properties.position; - } - }); + nearby.forEach(function(id) { + var properties = Entities.getEntityProperties(id, ["name", "position"]); + if (properties.name && properties.name == "Bat Box") { + boxPosition = properties.position; + } + }); - var BAT_DROP_HEIGHT = 2.0; + var BAT_DROP_HEIGHT = 2.0; - var dropPosition; + var dropPosition; - if (!boxPosition) { - // we got no bat box position, drop in front of the avatar instead - } else { - // drop the bat above the bat box - dropPosition = Vec3.sum(boxPosition, { x: 0.0, y: BAT_DROP_HEIGHT, z: 0.0}); - } - - var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; - var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; - var SCRIPT_URL = "http://rawgit.com/birarda/hifi/baseball/examples/baseball/bat.js" - - var batUserData = { - grabbableKey: { - spatialKey: { - relativePosition: { x: 0.9, y: 0, z: 0 }, - relativeRotation: Quat.fromPitchYawRollDegrees(0, 0, 45), - perHandRelativePosition: { x: 0.0, y: -0.05, z: -0.04 }, - perHandRelativeRotation: Quat.fromPitchYawRollDegrees(0, 0, 0) - } + if (!boxPosition) { + // we got no bat box position, drop in front of the avatar instead + } else { + // drop the bat above the bat box + dropPosition = Vec3.sum(boxPosition, { x: 0.0, y: BAT_DROP_HEIGHT, z: 0.0}); } - } - // add the fresh bat at the drop position - var bat = Entities.addEntity({ - name: 'Bat', - type: "Model", - modelURL: BAT_MODEL, - position: dropPosition, - compoundShapeURL: BAT_COLLISION_HULL, - collisionsWillMove: true, - velocity: { x: 0, y: 0.05, z: 0}, // workaround for gravity not taking effect on add - gravity: { x: 0, y: -9.81, z: 0}, - rotation: Quat.fromPitchYawRollDegrees(0.0, 0.0, -90.0), - script: SCRIPT_URL, - userData: JSON.stringify(batUserData) - }); + var BAT_MODEL = "atp:c47deaae09cca927f6bc9cca0e8bbe77fc618f8c3f2b49899406a63a59f885cb.fbx"; + var BAT_COLLISION_HULL = "atp:9eafceb7510c41d50661130090de7e0632aa4da236ebda84a0059a4be2130e0c.obj"; + var SCRIPT_URL = "http://rawgit.com/birarda/hifi/baseball/examples/baseball/bat.js" + + var batUserData = { + grabbableKey: { + spatialKey: { + relativePosition: { x: 0.9, y: 0, z: 0 }, + relativeRotation: Quat.fromPitchYawRollDegrees(0, 0, 45), + perHandRelativePosition: { x: 0.0, y: -0.05, z: -0.04 }, + perHandRelativeRotation: Quat.fromPitchYawRollDegrees(0, 0, 0) + } + } + } + + // add the fresh bat at the drop position + var bat = Entities.addEntity({ + name: 'Bat', + type: "Model", + modelURL: BAT_MODEL, + position: dropPosition, + compoundShapeURL: BAT_COLLISION_HULL, + collisionsWillMove: true, + velocity: { x: 0, y: 0.05, z: 0}, // workaround for gravity not taking effect on add + gravity: { x: 0, y: -9.81, z: 0}, + rotation: Quat.fromPitchYawRollDegrees(0.0, 0.0, -90.0), + script: SCRIPT_URL, + userData: JSON.stringify(batUserData) + }); }; }); From 0ed249f0e7ff9e2eff2412871de1f7b7a45fb896 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 30 Nov 2015 15:59:49 -0800 Subject: [PATCH 236/401] Update script path include in firework.js --- examples/baseball/firework.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index 89287c5a8b..bc1d0910cf 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include("http://rawgit.com/huffman/hifi/baseball/examples/baseball/utils.js"); +Script.include("utils.js"); var emitters = []; From 6fe370c4ef908f596a7f955179706293b0725e7f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 30 Nov 2015 16:00:15 -0800 Subject: [PATCH 237/401] Remove old comment in firework.js --- examples/baseball/firework.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/baseball/firework.js b/examples/baseball/firework.js index bc1d0910cf..a78e1595eb 100644 --- a/examples/baseball/firework.js +++ b/examples/baseball/firework.js @@ -136,5 +136,3 @@ playFireworkShow = function(position, numberOfFireworks, duration) { }(randomPosition), Math.random() * duration) } } - -//playFireworkShow(10, 2000); From 9b54924524783b3731c2a09f562705902f6ad2a5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 30 Nov 2015 16:21:14 -0800 Subject: [PATCH 238/401] edit.js can now manipulate children without flipping the table --- .../entities/src/EntityItemProperties.cpp | 4 ++++ libraries/entities/src/EntityItemProperties.h | 2 ++ .../entities/src/EntityScriptingInterface.cpp | 23 ++++++++++++++++++- libraries/shared/src/SpatiallyNestable.cpp | 3 +++ libraries/shared/src/SpatiallyNestable.h | 2 +- 5 files changed, 32 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 2ecb42a9ce..52f98be208 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -1789,3 +1789,7 @@ QList EntityItemProperties::listChangedProperties() { return out; } + +bool EntityItemProperties::parentDependentPropertyChanged() { + return localPositionChanged() || positionChanged() || localRotationChanged() || rotationChanged(); +} diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 6bb6b1914c..11d29c5d57 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -83,6 +83,8 @@ public: { return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; } EntityPropertyFlags getChangedProperties() const; + bool parentDependentPropertyChanged(); // was there a changed in a property that requires parent info to interpret? + AACube getMaximumAACube() const; AABox getAABox() const; diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index ca963aca6d..39da57f3a8 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -201,10 +201,31 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties script bool updatedEntity = false; _entityTree->withWriteLock([&] { + if (scriptSideProperties.parentDependentPropertyChanged()) { + // if the script sets a location property but didn't include parent information, grab the needed + // properties from the entity. + bool recompute = false; + EntityItemPointer entity = nullptr; + if (!scriptSideProperties.parentIDChanged()) { + entity = _entityTree->findEntityByEntityItemID(entityID); + scriptSideProperties.setParentID(entity->getParentID()); + recompute = true; + } + if (!scriptSideProperties.parentJointIndexChanged()) { + if (!entity) { + entity = _entityTree->findEntityByEntityItemID(entityID); + } + scriptSideProperties.setParentJointIndex(entity->getParentJointIndex()); + recompute = true; + } + if (recompute) { + properties = convertLocationFromScriptSemantics(scriptSideProperties); + } + } + updatedEntity = _entityTree->updateEntity(entityID, properties); }); - if (!updatedEntity) { return QUuid(); } diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 31a0dd5647..9b2e809063 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -218,6 +218,7 @@ void SpatiallyNestable::setOrientation(glm::quat orientation) { } const Transform SpatiallyNestable::getTransform() const { + // return a world-space transform for this object's location Transform parentTransform = getParentTransform(); Transform result; _transformLock.withReadLock([&] { @@ -227,6 +228,8 @@ const Transform SpatiallyNestable::getTransform() const { } const Transform SpatiallyNestable::getTransform(int jointIndex) const { + // this returns the world-space transform for this object. It find its parent's transform (which may + // cause this object's parent to query its parent, etc) and multiplies this object's local transform onto it. Transform worldTransform = getTransform(); Transform jointInObjectFrame = getJointTransformInObjectFrame(jointIndex); Transform jointInWorldFrame; diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 8805e72af5..6e0afa24a5 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -69,7 +69,7 @@ public: virtual glm::vec3 getScale() const; virtual void setScale(glm::vec3 scale); - // get world location of a specific joint + // get world-frame values for a specific joint virtual const Transform getTransform(int jointIndex) const; virtual glm::vec3 getPosition(int jointIndex) const; virtual glm::vec3 getScale(int jointIndex) const; From f7537e3dc374d4014c6f27b9031e8a06899dfee9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Nov 2015 16:44:14 -0800 Subject: [PATCH 239/401] add initial version of asset description --- examples/baseball/assets.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 examples/baseball/assets.yml diff --git a/examples/baseball/assets.yml b/examples/baseball/assets.yml new file mode 100644 index 0000000000..c17715179f --- /dev/null +++ b/examples/baseball/assets.yml @@ -0,0 +1,17 @@ +assets: + crowd-boos.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/crowd-boos.wav" + atp_url: "atp:c632c92b166ade60aa16b23ff1dfdf712856caeb83bd9311980b2d5edac821af.wav" + attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + crowd-cheers-organ.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/crowd-cheers-organ.wav" + atp_url: "atp:b8044401a846ed29f881a0b9b80cf1ba41f26327180c28fc9c70d144f9b70045.wav" + attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + crowd-medium.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/crowd-medium.wav" + atp_url: "atp:0821bf2ac60dd2f356dfdd948e8bb89c23984dc3584612f6c815765154f02cae.wav" + attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + baseball-hitting-bat-1.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-1.wav" + atp_url: "atp:6f0b691a0c9c9ece6557d97fe242b1faec4020fe26efc9c17327993b513c5fe5.wav" + attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" From 4a80e72d14587f893a45c33b919277ff4c2e9fca Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Nov 2015 16:48:05 -0800 Subject: [PATCH 240/401] complete attribution for removed files --- examples/baseball/assets.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/examples/baseball/assets.yml b/examples/baseball/assets.yml index c17715179f..2b1aa1d203 100644 --- a/examples/baseball/assets.yml +++ b/examples/baseball/assets.yml @@ -14,4 +14,20 @@ assets: baseball-hitting-bat-1.wav: s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-1.wav" atp_url: "atp:6f0b691a0c9c9ece6557d97fe242b1faec4020fe26efc9c17327993b513c5fe5.wav" - attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + attribution: "CC BY 3.0 - Credit: https://www.freesound.org/people/SocializedArtist45/" + baseball-hitting-bat-set-1.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-1.wav" + atp_url: "atp:5be5806205158ebdc5c3623ceb7ae73315028b51ffeae24292aff7042e3fa6a9.wav" + attribution: "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" + baseball-hitting-bat-set-2.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-2.wav" + atp_url: "atp:e68661374e2145c480809c26134782aad11e0de456c7802170c7abccc4028873.wav" + attribution: "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" + baseball-hitting-bat-set-3.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-3.wav" + atp_url: "atp:787e3c9af17dd3929527787176ede83d6806260e63ddd5a4cef48cd22e32c6f7.wav" + attribution: "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" + baseball-hitting-bat-set-4.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-4.wav" + atp_url: "atp:fc65383431a6238c7a4749f0f6f061f75a604ed5e17d775ab1b2955609e67ebb.wav" + attribution: "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" From 3402585d1ac2b053c4708025765afe9d40c5eb26 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 30 Nov 2015 16:54:29 -0800 Subject: [PATCH 241/401] fix a crash from previous commit --- libraries/avatars/src/AvatarData.cpp | 12 +++++++-- .../entities/src/EntityScriptingInterface.cpp | 26 +++++++------------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index ec363756f6..a7a3e74663 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -90,8 +90,10 @@ const QUrl& AvatarData::defaultFullAvatarModelUrl() { // There are a number of possible strategies for this set of tools through endRender, below. void AvatarData::nextAttitude(glm::vec3 position, glm::quat orientation) { avatarLock.lock(); - SpatiallyNestable::setPosition(position); - SpatiallyNestable::setOrientation(orientation); + Transform trans; + trans.setTranslation(position); + trans.setRotation(orientation); + SpatiallyNestable::setTransform(trans); avatarLock.unlock(); updateAttitude(); } @@ -478,6 +480,12 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { } // TODO is this safe? will the floats not exactly match? + // Andrew says: + // Yes, there is a possibility that the transmitted will not quite match the extracted despite being originally + // extracted from the exact same quaternion. I followed the code through and it appears the risk is that the + // avatar's SkeletonModel might fall into the CPU expensive part of Model::updateClusterMatrices() when otherwise it + // would not have required it. However, we know we can update many simultaneously animating avatars, and most + // avatars will be moving constantly anyway, so I don't think we need to worry. if (getBodyYaw() != yaw || getBodyPitch() != pitch || getBodyRoll() != roll) { _hasNewJointRotations = true; glm::vec3 eulerAngles(pitch, yaw, roll); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 39da57f3a8..9cb816be1f 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -191,7 +191,7 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit } QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties scriptSideProperties) { - EntityItemProperties properties = convertLocationFromScriptSemantics(scriptSideProperties); + EntityItemProperties properties = scriptSideProperties; EntityItemID entityID(id); // If we have a local entity tree set, then also update it. if (!_entityTree) { @@ -204,25 +204,17 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties script if (scriptSideProperties.parentDependentPropertyChanged()) { // if the script sets a location property but didn't include parent information, grab the needed // properties from the entity. - bool recompute = false; - EntityItemPointer entity = nullptr; - if (!scriptSideProperties.parentIDChanged()) { - entity = _entityTree->findEntityByEntityItemID(entityID); - scriptSideProperties.setParentID(entity->getParentID()); - recompute = true; - } - if (!scriptSideProperties.parentJointIndexChanged()) { - if (!entity) { - entity = _entityTree->findEntityByEntityItemID(entityID); + if (!scriptSideProperties.parentIDChanged() || !scriptSideProperties.parentJointIndexChanged()) { + EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); + if (entity && !scriptSideProperties.parentIDChanged()) { + properties.setParentID(entity->getParentID()); + } + if (entity && !scriptSideProperties.parentJointIndexChanged()) { + properties.setParentJointIndex(entity->getParentJointIndex()); } - scriptSideProperties.setParentJointIndex(entity->getParentJointIndex()); - recompute = true; - } - if (recompute) { - properties = convertLocationFromScriptSemantics(scriptSideProperties); } } - + properties = convertLocationFromScriptSemantics(properties); updatedEntity = _entityTree->updateEntity(entityID, properties); }); From c451ede05176b9ffbc54a4f1818fcf1491b0eb9a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Nov 2015 16:59:13 -0800 Subject: [PATCH 242/401] add crowd noises to assets yaml --- examples/baseball/assets.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/examples/baseball/assets.yml b/examples/baseball/assets.yml index 2b1aa1d203..a9ee455b23 100644 --- a/examples/baseball/assets.yml +++ b/examples/baseball/assets.yml @@ -31,3 +31,23 @@ assets: s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-4.wav" atp_url: "atp:fc65383431a6238c7a4749f0f6f061f75a604ed5e17d775ab1b2955609e67ebb.wav" attribution: "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" + chatter-loop.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/chatter-loop.wav" + atp_url: "atp:d9978e693035d4e2b5c7b546c8cccfb2dde5677834d9eed5206ccb2da55b4732.wav" + attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + zorba-organ.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/zorba-organ.wav" + atp_url: "atp:1ee58f4d929fdef7c2989cd8be964952a24cdd653d80f57b6a89a2ae8e3029e1.wav" + attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + charge-organ.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/charge-organ.wav" + atp_url: "atp:cefaba2d5f1a378382ee046716bffcf6b6a40676649b23a1e81a996efe22d7d3.wav" + attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + ball-game.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/ball-game.wav" + atp_url: "atp:fb41e37f8f8f7b78e546ac78800df6e39edaa09b2df4bfa0afdd8d749dac38b8.wav" + attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + clapping.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/clapping.wav" + atp_url: "atp:44a83a788ccfd2924e35c902c34808b24dbd0309d000299ce01a355f91cf8115.wav" + attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" From cba09beff4eae99146f09b890b77d4cb7104c88d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Nov 2015 17:02:30 -0800 Subject: [PATCH 243/401] add pop sounds (which don't require attribution) --- examples/baseball/assets.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/examples/baseball/assets.yml b/examples/baseball/assets.yml index a9ee455b23..f7ba1cb158 100644 --- a/examples/baseball/assets.yml +++ b/examples/baseball/assets.yml @@ -51,3 +51,15 @@ assets: s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/clapping.wav" atp_url: "atp:44a83a788ccfd2924e35c902c34808b24dbd0309d000299ce01a355f91cf8115.wav" attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + pop1.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop1.wav" + atp_url: "atp:a2bf79c95fe74c2c6c9188acc7230f7cd1b0f6008f2c81954ecd93eca0497ec6.wav" + pop2.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop2.wav" + atp_url: "atp:901067ebc2cda4c0d86ec02fcca2ed901e85f9097ad68bbde78b4cad8eaf2ed7.wav" + pop3.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop3.wav" + atp_url: "atp:830312930577cb1ea36ba2d743e957debbacceb441b20addead5a6faa05a3771.wav" + pop4.wav: + s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop4.wav" + atp_url: "atp:62e80d0a9f084cf731bcc66ca6e9020ee88587417071a281eee3167307b53560.wav" From 52fb7116561ab72d80b75153368d9977c5e59b37 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 30 Nov 2015 17:06:09 -0800 Subject: [PATCH 244/401] Move baseballCrowd to correct directory --- examples/{acScripts => baseball}/baseballCrowd.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/{acScripts => baseball}/baseballCrowd.js (100%) diff --git a/examples/acScripts/baseballCrowd.js b/examples/baseball/baseballCrowd.js similarity index 100% rename from examples/acScripts/baseballCrowd.js rename to examples/baseball/baseballCrowd.js From 52dc2cf7469ff1e1626ddee52d1d152c6ee2d0f0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 30 Nov 2015 17:17:06 -0800 Subject: [PATCH 245/401] change the assets file to json --- examples/baseball/assets.json | 85 +++++++++++++++++++++++++++++++++++ examples/baseball/assets.yml | 65 --------------------------- 2 files changed, 85 insertions(+), 65 deletions(-) create mode 100644 examples/baseball/assets.json delete mode 100644 examples/baseball/assets.yml diff --git a/examples/baseball/assets.json b/examples/baseball/assets.json new file mode 100644 index 0000000000..037eb616d2 --- /dev/null +++ b/examples/baseball/assets.json @@ -0,0 +1,85 @@ +{ + "assets": { + "crowd-boos.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/crowd-boos.wav", + "atp_url": "atp:c632c92b166ade60aa16b23ff1dfdf712856caeb83bd9311980b2d5edac821af.wav", + "attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + }, + "crowd-cheers-organ.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/crowd-cheers-organ.wav", + "atp_url": "atp:b8044401a846ed29f881a0b9b80cf1ba41f26327180c28fc9c70d144f9b70045.wav", + "attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + }, + "crowd-medium.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/crowd-medium.wav", + "atp_url": "atp:0821bf2ac60dd2f356dfdd948e8bb89c23984dc3584612f6c815765154f02cae.wav", + "attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + }, + "baseball-hitting-bat-1.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-1.wav", + "atp_url": "atp:6f0b691a0c9c9ece6557d97fe242b1faec4020fe26efc9c17327993b513c5fe5.wav", + "attribution": "CC BY 3.0 - Credit: https://www.freesound.org/people/SocializedArtist45/" + }, + "baseball-hitting-bat-set-1.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-1.wav", + "atp_url": "atp:5be5806205158ebdc5c3623ceb7ae73315028b51ffeae24292aff7042e3fa6a9.wav", + "attribution": "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" + }, + "baseball-hitting-bat-set-2.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-2.wav", + "atp_url": "atp:e68661374e2145c480809c26134782aad11e0de456c7802170c7abccc4028873.wav", + "attribution": "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" + }, + "baseball-hitting-bat-set-3.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-3.wav", + "atp_url": "atp:787e3c9af17dd3929527787176ede83d6806260e63ddd5a4cef48cd22e32c6f7.wav", + "attribution": "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" + }, + "baseball-hitting-bat-set-4.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-4.wav", + "atp_url": "atp:fc65383431a6238c7a4749f0f6f061f75a604ed5e17d775ab1b2955609e67ebb.wav", + "attribution": "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" + }, + "chatter-loop.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/chatter-loop.wav", + "atp_url": "atp:d9978e693035d4e2b5c7b546c8cccfb2dde5677834d9eed5206ccb2da55b4732.wav", + "attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + }, + "zorba-organ.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/zorba-organ.wav", + "atp_url": "atp:1ee58f4d929fdef7c2989cd8be964952a24cdd653d80f57b6a89a2ae8e3029e1.wav", + "attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + }, + "charge-organ.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/charge-organ.wav", + "atp_url": "atp:cefaba2d5f1a378382ee046716bffcf6b6a40676649b23a1e81a996efe22d7d3.wav", + "attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + }, + "ball-game.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/ball-game.wav", + "atp_url": "atp:fb41e37f8f8f7b78e546ac78800df6e39edaa09b2df4bfa0afdd8d749dac38b8.wav", + "attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + }, + "clapping.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/clapping.wav", + "atp_url": "atp:44a83a788ccfd2924e35c902c34808b24dbd0309d000299ce01a355f91cf8115.wav", + "attribution": "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" + }, + "pop1.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop1.wav", + "atp_url": "atp:a2bf79c95fe74c2c6c9188acc7230f7cd1b0f6008f2c81954ecd93eca0497ec6.wav" + }, + "pop2.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop2.wav", + "atp_url": "atp:901067ebc2cda4c0d86ec02fcca2ed901e85f9097ad68bbde78b4cad8eaf2ed7.wav" + }, + "pop3.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop3.wav", + "atp_url": "atp:830312930577cb1ea36ba2d743e957debbacceb441b20addead5a6faa05a3771.wav" + }, + "pop4.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop4.wav", + "atp_url": "atp:62e80d0a9f084cf731bcc66ca6e9020ee88587417071a281eee3167307b53560.wav" + } + } +} diff --git a/examples/baseball/assets.yml b/examples/baseball/assets.yml deleted file mode 100644 index f7ba1cb158..0000000000 --- a/examples/baseball/assets.yml +++ /dev/null @@ -1,65 +0,0 @@ -assets: - crowd-boos.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/crowd-boos.wav" - atp_url: "atp:c632c92b166ade60aa16b23ff1dfdf712856caeb83bd9311980b2d5edac821af.wav" - attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" - crowd-cheers-organ.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/crowd-cheers-organ.wav" - atp_url: "atp:b8044401a846ed29f881a0b9b80cf1ba41f26327180c28fc9c70d144f9b70045.wav" - attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" - crowd-medium.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/crowd-medium.wav" - atp_url: "atp:0821bf2ac60dd2f356dfdd948e8bb89c23984dc3584612f6c815765154f02cae.wav" - attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" - baseball-hitting-bat-1.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-1.wav" - atp_url: "atp:6f0b691a0c9c9ece6557d97fe242b1faec4020fe26efc9c17327993b513c5fe5.wav" - attribution: "CC BY 3.0 - Credit: https://www.freesound.org/people/SocializedArtist45/" - baseball-hitting-bat-set-1.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-1.wav" - atp_url: "atp:5be5806205158ebdc5c3623ceb7ae73315028b51ffeae24292aff7042e3fa6a9.wav" - attribution: "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" - baseball-hitting-bat-set-2.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-2.wav" - atp_url: "atp:e68661374e2145c480809c26134782aad11e0de456c7802170c7abccc4028873.wav" - attribution: "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" - baseball-hitting-bat-set-3.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-3.wav" - atp_url: "atp:787e3c9af17dd3929527787176ede83d6806260e63ddd5a4cef48cd22e32c6f7.wav" - attribution: "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" - baseball-hitting-bat-set-4.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/baseball-hitting-bat-set-4.wav" - atp_url: "atp:fc65383431a6238c7a4749f0f6f061f75a604ed5e17d775ab1b2955609e67ebb.wav" - attribution: "CC BY 3.0 - Credit: CGEffex - https://www.freesound.org/people/CGEffex/" - chatter-loop.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/chatter-loop.wav" - atp_url: "atp:d9978e693035d4e2b5c7b546c8cccfb2dde5677834d9eed5206ccb2da55b4732.wav" - attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" - zorba-organ.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/zorba-organ.wav" - atp_url: "atp:1ee58f4d929fdef7c2989cd8be964952a24cdd653d80f57b6a89a2ae8e3029e1.wav" - attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" - charge-organ.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/charge-organ.wav" - atp_url: "atp:cefaba2d5f1a378382ee046716bffcf6b6a40676649b23a1e81a996efe22d7d3.wav" - attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" - ball-game.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/ball-game.wav" - atp_url: "atp:fb41e37f8f8f7b78e546ac78800df6e39edaa09b2df4bfa0afdd8d749dac38b8.wav" - attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" - clapping.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/clapping.wav" - atp_url: "atp:44a83a788ccfd2924e35c902c34808b24dbd0309d000299ce01a355f91cf8115.wav" - attribution: "CC BY 3.0 - Credit: Alyssa Galindo - http://freesound.org/people/AshFox/" - pop1.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop1.wav" - atp_url: "atp:a2bf79c95fe74c2c6c9188acc7230f7cd1b0f6008f2c81954ecd93eca0497ec6.wav" - pop2.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop2.wav" - atp_url: "atp:901067ebc2cda4c0d86ec02fcca2ed901e85f9097ad68bbde78b4cad8eaf2ed7.wav" - pop3.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop3.wav" - atp_url: "atp:830312930577cb1ea36ba2d743e957debbacceb441b20addead5a6faa05a3771.wav" - pop4.wav: - s3_url: "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop4.wav" - atp_url: "atp:62e80d0a9f084cf731bcc66ca6e9020ee88587417071a281eee3167307b53560.wav" From a94b6667b16f73d364c168b6f61a7c809b0ba420 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 27 Nov 2015 14:49:47 -0800 Subject: [PATCH 246/401] Moving most of GLCanvas to gl library --- interface/src/GLCanvas.cpp | 107 ++---------------------------- interface/src/GLCanvas.h | 26 ++------ libraries/gl/src/gl/GLHelpers.cpp | 40 ++++++++--- libraries/gl/src/gl/GLHelpers.h | 7 +- libraries/gl/src/gl/GLWidget.cpp | 107 ++++++++++++++++++++++++++++++ libraries/gl/src/gl/GLWidget.h | 36 ++++++++++ 6 files changed, 187 insertions(+), 136 deletions(-) create mode 100644 libraries/gl/src/gl/GLWidget.cpp create mode 100644 libraries/gl/src/gl/GLWidget.h diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index d9cde868a9..0b4c6dde3d 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -9,54 +9,15 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +// FIXME ordering of headers #include "Application.h" #include "GLCanvas.h" -#include -#include #include #include "MainWindow.h" #include "Menu.h" -static QGLFormat& getDesiredGLFormat() { - // Specify an OpenGL 3.3 format using the Core profile. - // That is, no old-school fixed pipeline functionality - static QGLFormat glFormat; - static std::once_flag once; - std::call_once(once, [] { - glFormat.setVersion(4, 1); - glFormat.setProfile(QGLFormat::CoreProfile); // Requires >=Qt-4.8.0 - glFormat.setSampleBuffers(false); - glFormat.setDepth(false); - glFormat.setStencil(false); - }); - return glFormat; -} - -GLCanvas::GLCanvas() : QGLWidget(getDesiredGLFormat()) { -#ifdef Q_OS_LINUX - // Cause GLCanvas::eventFilter to be called. - // It wouldn't hurt to do this on Mac and PC too; but apparently it's only needed on linux. - qApp->installEventFilter(this); -#endif -} - -int GLCanvas::getDeviceWidth() const { - return width() * (windowHandle() ? (float)windowHandle()->devicePixelRatio() : 1.0f); -} - -int GLCanvas::getDeviceHeight() const { - return height() * (windowHandle() ? (float)windowHandle()->devicePixelRatio() : 1.0f); -} - -void GLCanvas::initializeGL() { - setAttribute(Qt::WA_AcceptTouchEvents); - setAcceptDrops(true); - // Note, we *DO NOT* want Qt to automatically swap buffers for us. This results in the "ringing" bug mentioned in WL#19514 when we're throttling the framerate. - setAutoBufferSwap(false); -} - void GLCanvas::paintGL() { PROFILE_RANGE(__FUNCTION__); @@ -74,68 +35,8 @@ void GLCanvas::resizeGL(int width, int height) { } bool GLCanvas::event(QEvent* event) { - switch (event->type()) { - case QEvent::MouseMove: - case QEvent::MouseButtonPress: - case QEvent::MouseButtonRelease: - case QEvent::MouseButtonDblClick: - case QEvent::KeyPress: - case QEvent::KeyRelease: - case QEvent::FocusIn: - case QEvent::FocusOut: - case QEvent::Resize: - case QEvent::TouchBegin: - case QEvent::TouchEnd: - case QEvent::TouchUpdate: - case QEvent::Wheel: - case QEvent::DragEnter: - case QEvent::Drop: - if (QCoreApplication::sendEvent(QCoreApplication::instance(), event)) { - return true; - } - break; - case QEvent::Paint: - // Ignore paint events that occur after we've decided to quit - if (qApp->isAboutToQuit()) { - return true; - } - break; - - default: - break; + if (QEvent::Paint == event->type() && qApp->isAboutToQuit()) { + return true; } - return QGLWidget::event(event); -} - - -// Pressing Alt (and Meta) key alone activates the menubar because its style inherits the -// SHMenuBarAltKeyNavigation from QWindowsStyle. This makes it impossible for a scripts to -// receive keyPress events for the Alt (and Meta) key in a reliable manner. -// -// This filter catches events before QMenuBar can steal the keyboard focus. -// The idea was borrowed from -// http://www.archivum.info/qt-interest@trolltech.com/2006-09/00053/Re-(Qt4)-Alt-key-focus-QMenuBar-(solved).html - -bool GLCanvas::eventFilter(QObject*, QEvent* event) { - switch (event->type()) { - case QEvent::KeyPress: - case QEvent::KeyRelease: - case QEvent::ShortcutOverride: - { - QKeyEvent* keyEvent = static_cast(event); - if (keyEvent->key() == Qt::Key_Alt || keyEvent->key() == Qt::Key_Meta) { - if (event->type() == QEvent::KeyPress) { - keyPressEvent(keyEvent); - } else if (event->type() == QEvent::KeyRelease) { - keyReleaseEvent(keyEvent); - } else { - QGLWidget::event(event); - } - return true; - } - } - default: - break; - } - return false; + return GLWidget::event(event); } diff --git a/interface/src/GLCanvas.h b/interface/src/GLCanvas.h index 73c5b5e8bf..0442159eeb 100644 --- a/interface/src/GLCanvas.h +++ b/interface/src/GLCanvas.h @@ -12,31 +12,15 @@ #ifndef hifi_GLCanvas_h #define hifi_GLCanvas_h -#include -#include -#include +#include /// customized canvas that simply forwards requests/events to the singleton application -class GLCanvas : public QGLWidget { +class GLCanvas : public GLWidget { Q_OBJECT - -public: - GLCanvas(); - - int getDeviceWidth() const; - int getDeviceHeight() const; - QSize getDeviceSize() const { return QSize(getDeviceWidth(), getDeviceHeight()); } - protected: - - virtual void initializeGL(); - virtual void paintGL(); - virtual void resizeGL(int width, int height); - virtual bool event(QEvent* event); - -private slots: - bool eventFilter(QObject*, QEvent* event); - + virtual void paintGL() override; + virtual void resizeGL(int width, int height) override; + virtual bool event(QEvent* event) override; }; diff --git a/libraries/gl/src/gl/GLHelpers.cpp b/libraries/gl/src/gl/GLHelpers.cpp index f67f9e9120..9022f0ffcc 100644 --- a/libraries/gl/src/gl/GLHelpers.cpp +++ b/libraries/gl/src/gl/GLHelpers.cpp @@ -1,15 +1,37 @@ #include "GLHelpers.h" +#include -QSurfaceFormat getDefaultOpenGlSurfaceFormat() { - QSurfaceFormat format; - // Qt Quick may need a depth and stencil buffer. Always make sure these are available. - format.setDepthBufferSize(DEFAULT_GL_DEPTH_BUFFER_BITS); - format.setStencilBufferSize(DEFAULT_GL_STENCIL_BUFFER_BITS); - format.setVersion(4, 1); +#include +#include + +const QSurfaceFormat& getDefaultOpenGlSurfaceFormat() { + static QSurfaceFormat format; + static std::once_flag once; + std::call_once(once, [] { + // Qt Quick may need a depth and stencil buffer. Always make sure these are available. + format.setDepthBufferSize(DEFAULT_GL_DEPTH_BUFFER_BITS); + format.setStencilBufferSize(DEFAULT_GL_STENCIL_BUFFER_BITS); + format.setVersion(4, 1); #ifdef DEBUG - format.setOption(QSurfaceFormat::DebugContext); + format.setOption(QSurfaceFormat::DebugContext); #endif - format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); - return format; + format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile); + }); + return format; +} + +const QGLFormat& getDefaultGLFormat() { + // Specify an OpenGL 3.3 format using the Core profile. + // That is, no old-school fixed pipeline functionality + static QGLFormat glFormat; + static std::once_flag once; + std::call_once(once, [] { + glFormat.setVersion(4, 1); + glFormat.setProfile(QGLFormat::CoreProfile); // Requires >=Qt-4.8.0 + glFormat.setSampleBuffers(false); + glFormat.setDepth(false); + glFormat.setStencil(false); + }); + return glFormat; } diff --git a/libraries/gl/src/gl/GLHelpers.h b/libraries/gl/src/gl/GLHelpers.h index dc9f0f3140..de9e8f5d85 100644 --- a/libraries/gl/src/gl/GLHelpers.h +++ b/libraries/gl/src/gl/GLHelpers.h @@ -10,14 +10,15 @@ #ifndef hifi_GLHelpers_h #define hifi_GLHelpers_h -#include - // 16 bits of depth precision #define DEFAULT_GL_DEPTH_BUFFER_BITS 16 // 8 bits of stencil buffer (typically you really only need 1 bit for functionality // but GL implementations usually just come with buffer sizes in multiples of 8) #define DEFAULT_GL_STENCIL_BUFFER_BITS 8 -QSurfaceFormat getDefaultOpenGlSurfaceFormat(); +class QSurfaceFormat; +class QGLFormat; +const QSurfaceFormat& getDefaultOpenGlSurfaceFormat(); +const QGLFormat& getDefaultGLFormat(); #endif diff --git a/libraries/gl/src/gl/GLWidget.cpp b/libraries/gl/src/gl/GLWidget.cpp new file mode 100644 index 0000000000..b274b39da7 --- /dev/null +++ b/libraries/gl/src/gl/GLWidget.cpp @@ -0,0 +1,107 @@ +// +// GLWidget.cpp +// interface/src +// +// Created by Stephen Birarda on 8/14/13. +// Copyright 2013 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 "GLWidget.h" + +#include + +#include +#include +#include + +#include +#include + +#include "GLHelpers.h" + +GLWidget::GLWidget() : QGLWidget(getDefaultGLFormat()) { +#ifdef Q_OS_LINUX + // Cause GLWidget::eventFilter to be called. + // It wouldn't hurt to do this on Mac and PC too; but apparently it's only needed on linux. + qApp->installEventFilter(this); +#endif +} + +int GLWidget::getDeviceWidth() const { + return width() * (windowHandle() ? (float)windowHandle()->devicePixelRatio() : 1.0f); +} + +int GLWidget::getDeviceHeight() const { + return height() * (windowHandle() ? (float)windowHandle()->devicePixelRatio() : 1.0f); +} + +void GLWidget::initializeGL() { + setAttribute(Qt::WA_AcceptTouchEvents); + setAcceptDrops(true); + // Note, we *DO NOT* want Qt to automatically swap buffers for us. This results in the "ringing" bug mentioned in WL#19514 when we're throttling the framerate. + setAutoBufferSwap(false); +} + +bool GLWidget::event(QEvent* event) { + switch (event->type()) { + case QEvent::MouseMove: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::KeyPress: + case QEvent::KeyRelease: + case QEvent::FocusIn: + case QEvent::FocusOut: + case QEvent::Resize: + case QEvent::TouchBegin: + case QEvent::TouchEnd: + case QEvent::TouchUpdate: + case QEvent::Wheel: + case QEvent::DragEnter: + case QEvent::Drop: + if (QCoreApplication::sendEvent(QCoreApplication::instance(), event)) { + return true; + } + break; + + default: + break; + } + return QGLWidget::event(event); +} + + +// Pressing Alt (and Meta) key alone activates the menubar because its style inherits the +// SHMenuBarAltKeyNavigation from QWindowsStyle. This makes it impossible for a scripts to +// receive keyPress events for the Alt (and Meta) key in a reliable manner. +// +// This filter catches events before QMenuBar can steal the keyboard focus. +// The idea was borrowed from +// http://www.archivum.info/qt-interest@trolltech.com/2006-09/00053/Re-(Qt4)-Alt-key-focus-QMenuBar-(solved).html + +bool GLWidget::eventFilter(QObject*, QEvent* event) { + switch (event->type()) { + case QEvent::KeyPress: + case QEvent::KeyRelease: + case QEvent::ShortcutOverride: + { + QKeyEvent* keyEvent = static_cast(event); + if (keyEvent->key() == Qt::Key_Alt || keyEvent->key() == Qt::Key_Meta) { + if (event->type() == QEvent::KeyPress) { + keyPressEvent(keyEvent); + } else if (event->type() == QEvent::KeyRelease) { + keyReleaseEvent(keyEvent); + } else { + QGLWidget::event(event); + } + return true; + } + } + default: + break; + } + return false; +} diff --git a/libraries/gl/src/gl/GLWidget.h b/libraries/gl/src/gl/GLWidget.h new file mode 100644 index 0000000000..040ce542e9 --- /dev/null +++ b/libraries/gl/src/gl/GLWidget.h @@ -0,0 +1,36 @@ +// +// GLWidget.h +// interface/src +// +// Created by Stephen Birarda on 8/14/13. +// Copyright 2013 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_GLWidget_h +#define hifi_GLWidget_h + +#include + +/// customized canvas that simply forwards requests/events to the singleton application +class GLWidget : public QGLWidget { + Q_OBJECT + +public: + GLWidget(); + int getDeviceWidth() const; + int getDeviceHeight() const; + QSize getDeviceSize() const { return QSize(getDeviceWidth(), getDeviceHeight()); } + +protected: + virtual void initializeGL() override; + virtual bool event(QEvent* event) override; + +private slots: + virtual bool eventFilter(QObject*, QEvent* event) override; +}; + + +#endif // hifi_GLCanvas_h From 8d9eeb3897f532cf5c7cf483fa597af47ae85234 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 30 Nov 2015 18:04:34 -0800 Subject: [PATCH 247/401] Have separate left/right hold action offset --- interface/src/avatar/AvatarActionHold.cpp | 151 ++++++++++------------ interface/src/avatar/AvatarActionHold.h | 12 +- interface/src/avatar/AvatarManager.cpp | 2 +- 3 files changed, 73 insertions(+), 92 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index a30ba35e4a..bff6af7337 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -33,63 +33,46 @@ AvatarActionHold::~AvatarActionHold() { } std::shared_ptr AvatarActionHold::getTarget(glm::quat& rotation, glm::vec3& position) { - std::shared_ptr holdingAvatar = nullptr; + auto avatarManager = DependencyManager::get(); + auto holdingAvatar = std::static_pointer_cast(avatarManager->getAvatarBySessionID(_holderID)); + + if (!holdingAvatar) { + return holdingAvatar; + } withTryReadLock([&]{ - QSharedPointer avatarManager = DependencyManager::get(); - AvatarSharedPointer holdingAvatarData = avatarManager->getAvatarBySessionID(_holderID); - holdingAvatar = std::static_pointer_cast(holdingAvatarData); - - if (holdingAvatar) { - bool isRightHand = (_hand == "right"); - glm::vec3 palmPosition { Vectors::ZERO }; - glm::quat palmRotation { Quaternions::IDENTITY }; - - - static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); - if (_ignoreIK && holdingAvatar->isMyAvatar()) { - // We cannot ignore other avatars IK and this is not the point of this option - // This is meant to make the grabbing behavior more reactive. - if (isRightHand) { - palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getPosition(); - palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getRotation(); - } else { - palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getPosition(); - palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getRotation(); - palmRotation *= yFlip; // Match right hand frame of reference - } - } else { - if (isRightHand) { - palmPosition = holdingAvatar->getRightPalmPosition(); - palmRotation = holdingAvatar->getRightPalmRotation(); - } else { - palmPosition = holdingAvatar->getLeftPalmPosition(); - palmRotation = holdingAvatar->getLeftPalmRotation(); - palmRotation *= yFlip; // Match right hand frame of reference - } - } - - rotation = palmRotation * _relativeRotation; - position = palmPosition + rotation * _relativePosition; + bool isRightHand = (_hand == "right"); + glm::vec3 palmPosition { Vectors::ZERO }; + glm::quat palmRotation { Quaternions::IDENTITY }; + if (_ignoreIK && holdingAvatar->isMyAvatar()) { + // We cannot ignore other avatars IK and this is not the point of this option + // This is meant to make the grabbing behavior more reactive. if (isRightHand) { - rotation *= _perHandRelativeRotation; - position += rotation * _perHandRelativePosition; + palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getPosition(); + palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::RightHand).getRotation(); } else { - auto mirroredRotation = _perHandRelativeRotation; - auto mirroredPosition = _perHandRelativePosition; - - // Mirror along z axis - auto eulerAngles = safeEulerAngles(mirroredRotation); - eulerAngles.x *= -1; - eulerAngles.y *= -1; - mirroredRotation = glm::quat(eulerAngles); - - mirroredPosition.z *= -1; - - rotation *= mirroredRotation; - position += rotation * mirroredPosition; + palmPosition = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getPosition(); + palmRotation = holdingAvatar->getHand()->getCopyOfPalmData(HandData::LeftHand).getRotation(); } + } else { + if (isRightHand) { + palmPosition = holdingAvatar->getRightPalmPosition(); + palmRotation = holdingAvatar->getRightPalmRotation(); + } else { + palmPosition = holdingAvatar->getLeftPalmPosition(); + palmRotation = holdingAvatar->getLeftPalmRotation(); + } + } + + if (isRightHand) { + rotation = palmRotation * _rightRelativeRotation; + position = palmPosition + rotation * _rightRelativePosition; + } else { + static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); + palmRotation *= yFlip; // Match right hand frame of reference + rotation = palmRotation * _leftRelativeRotation; + position = palmPosition + rotation * _leftRelativePosition; } }); @@ -192,10 +175,10 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) { } bool AvatarActionHold::updateArguments(QVariantMap arguments) { - glm::vec3 relativePosition; - glm::quat relativeRotation; - glm::vec3 perHandRelativePosition; - glm::quat perHandRelativeRotation; + glm::vec3 leftRelativePosition; + glm::quat leftRelativeRotation; + glm::vec3 rightRelativePosition; + glm::quat rightRelativeRotation; float timeScale; QString hand; QUuid holderID; @@ -207,29 +190,27 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { bool somethingChanged = ObjectAction::updateArguments(arguments); withReadLock([&]{ bool ok = true; - relativePosition = EntityActionInterface::extractVec3Argument("hold", arguments, "relativePosition", ok, false); + leftRelativePosition = EntityActionInterface::extractVec3Argument("hold", arguments, "leftRelativePosition", ok, false); if (!ok) { - relativePosition = _relativePosition; + leftRelativePosition = _leftRelativePosition; } ok = true; - relativeRotation = EntityActionInterface::extractQuatArgument("hold", arguments, "relativeRotation", ok, false); + leftRelativeRotation = EntityActionInterface::extractQuatArgument("hold", arguments, "leftRelativeRotation", ok, false); if (!ok) { - relativeRotation = _relativeRotation; + leftRelativeRotation = _leftRelativeRotation; } ok = true; - perHandRelativePosition = EntityActionInterface::extractVec3Argument("hold", arguments, - "perHandRelativePosition", ok, false); + rightRelativePosition = EntityActionInterface::extractVec3Argument("hold", arguments, "rightRelativePosition", ok, false); if (!ok) { - perHandRelativePosition = _perHandRelativePosition; + rightRelativePosition = _rightRelativePosition; } ok = true; - perHandRelativeRotation = EntityActionInterface::extractQuatArgument("hold", arguments, - "perHandRelativeRotation", ok, false); + rightRelativeRotation = EntityActionInterface::extractQuatArgument("hold", arguments, "rightRelativeRotation", ok, false); if (!ok) { - perHandRelativeRotation = _perHandRelativeRotation; + rightRelativeRotation = _rightRelativeRotation; } ok = true; @@ -268,10 +249,10 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { } if (somethingChanged || - relativePosition != _relativePosition || - relativeRotation != _relativeRotation || - perHandRelativePosition != _perHandRelativePosition || - perHandRelativeRotation != _perHandRelativeRotation || + leftRelativePosition != _leftRelativePosition || + leftRelativeRotation != _leftRelativeRotation || + rightRelativePosition != _rightRelativePosition || + rightRelativeRotation != _rightRelativeRotation || timeScale != _linearTimeScale || hand != _hand || holderID != _holderID || @@ -284,10 +265,10 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { if (needUpdate) { withWriteLock([&] { - _relativePosition = relativePosition; - _relativeRotation = relativeRotation; - _perHandRelativePosition = perHandRelativePosition; - _perHandRelativeRotation = perHandRelativeRotation; + _leftRelativePosition = leftRelativePosition; + _leftRelativeRotation = leftRelativeRotation; + _rightRelativePosition = rightRelativePosition; + _rightRelativeRotation = rightRelativeRotation; const float MIN_TIMESCALE = 0.1f; _linearTimeScale = glm::max(MIN_TIMESCALE, timeScale); _angularTimeScale = _linearTimeScale; @@ -314,10 +295,10 @@ QVariantMap AvatarActionHold::getArguments() { QVariantMap arguments = ObjectAction::getArguments(); withReadLock([&]{ arguments["holderID"] = _holderID; - arguments["relativePosition"] = glmToQMap(_relativePosition); - arguments["relativeRotation"] = glmToQMap(_relativeRotation); - arguments["perHandRelativePosition"] = glmToQMap(_perHandRelativePosition); - arguments["perHandRelativeRotation"] = glmToQMap(_perHandRelativeRotation); + arguments["leftRelativePosition"] = glmToQMap(_leftRelativePosition); + arguments["leftRelativeRotation"] = glmToQMap(_leftRelativeRotation); + arguments["rightRelativePosition"] = glmToQMap(_rightRelativePosition); + arguments["rightRelativeRotation"] = glmToQMap(_rightRelativeRotation); arguments["timeScale"] = _linearTimeScale; arguments["hand"] = _hand; arguments["kinematic"] = _kinematic; @@ -337,10 +318,10 @@ QByteArray AvatarActionHold::serialize() const { dataStream << AvatarActionHold::holdVersion; dataStream << _holderID; - dataStream << _relativePosition; - dataStream << _relativeRotation; - dataStream << _perHandRelativePosition; - dataStream << _perHandRelativeRotation; + dataStream << _leftRelativePosition; + dataStream << _leftRelativeRotation; + dataStream << _rightRelativePosition; + dataStream << _rightRelativeRotation; dataStream << _linearTimeScale; dataStream << _hand; @@ -372,10 +353,10 @@ void AvatarActionHold::deserialize(QByteArray serializedArguments) { withWriteLock([&]{ dataStream >> _holderID; - dataStream >> _relativePosition; - dataStream >> _relativeRotation; - dataStream >> _perHandRelativePosition; - dataStream >> _perHandRelativeRotation; + dataStream >> _leftRelativePosition; + dataStream >> _leftRelativeRotation; + dataStream >> _rightRelativePosition; + dataStream >> _rightRelativeRotation; dataStream >> _linearTimeScale; _angularTimeScale = _linearTimeScale; dataStream >> _hand; diff --git a/interface/src/avatar/AvatarActionHold.h b/interface/src/avatar/AvatarActionHold.h index c9563e5e88..d3aad19384 100644 --- a/interface/src/avatar/AvatarActionHold.h +++ b/interface/src/avatar/AvatarActionHold.h @@ -41,12 +41,12 @@ private: static const uint16_t holdVersion; void doKinematicUpdate(float deltaTimeStep); - - glm::vec3 _relativePosition { 0.0f }; - glm::quat _relativeRotation; - glm::vec3 _perHandRelativePosition { 0.0f }; - glm::quat _perHandRelativeRotation; - + + glm::vec3 _leftRelativePosition{ Vectors::ZERO }; + glm::quat _leftRelativeRotation{ Quaternions::IDENTITY }; + glm::vec3 _rightRelativePosition{ Vectors::ZERO }; + glm::quat _rightRelativeRotation{ Quaternions::IDENTITY }; + QString _hand { "right" }; QUuid _holderID; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 9df597109c..9fc6855d3b 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -402,7 +402,7 @@ void AvatarManager::updateAvatarRenderStatus(bool shouldRenderAvatars) { AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID) { if (sessionID == _myAvatar->getSessionUUID()) { - return std::static_pointer_cast(_myAvatar); + return _myAvatar; } return findAvatar(sessionID); From 4025504749b5d02a02fc590bca99be5c55d6bb69 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 30 Nov 2015 18:21:14 -0800 Subject: [PATCH 248/401] Fix merge error --- libraries/audio/src/Sound.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index 742d26b500..5447ca6213 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -30,9 +30,6 @@ public: const QByteArray& getByteArray() { return _byteArray; } -signals: - void ready(); - signals: void ready(); From d0e1ec3a86a23d9571e748cf67b7f0b9a9774152 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 30 Nov 2015 18:26:04 -0800 Subject: [PATCH 249/401] Fix merge error --- libraries/audio/src/Sound.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index 742d26b500..91dbef8c6a 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -29,9 +29,6 @@ public: bool isReady() const { return _isReady; } const QByteArray& getByteArray() { return _byteArray; } - -signals: - void ready(); signals: void ready(); From 0023c034c41a57e14bbe7322fd58bd471a367c7e Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Sun, 29 Nov 2015 00:42:46 -0800 Subject: [PATCH 250/401] Fixing naming of GL classes --- interface/src/Application.cpp | 4 +-- interface/src/Application.h | 4 +-- .../display-plugins/OpenGLDisplayPlugin.cpp | 1 - .../openvr/OpenVrDisplayPlugin.cpp | 1 - .../stereo/InterleavedStereoDisplayPlugin.cpp | 11 +------- .../stereo/SideBySideStereoDisplayPlugin.cpp | 12 +------- libraries/gl/src/gl/GLEscrow.h | 8 +++++- libraries/gl/src/gl/GLWidget.cpp | 8 ++++++ libraries/gl/src/gl/GLWidget.h | 2 ++ .../gl/src/gl/{GlWindow.cpp => GLWindow.cpp} | 28 ++++++++++++------- .../gl/src/gl/{GlWindow.h => GLWindow.h} | 13 +++++---- ...reenGlCanvas.cpp => OffscreenGLCanvas.cpp} | 14 +++++----- ...ffscreenGlCanvas.h => OffscreenGLCanvas.h} | 14 +++++----- libraries/gl/src/gl/OffscreenQmlSurface.cpp | 6 ++-- .../src/OculusLegacyDisplayPlugin.cpp | 1 - 15 files changed, 65 insertions(+), 62 deletions(-) rename libraries/gl/src/gl/{GlWindow.cpp => GLWindow.cpp} (69%) rename libraries/gl/src/gl/{GlWindow.h => GLWindow.h} (63%) rename libraries/gl/src/gl/{OffscreenGlCanvas.cpp => OffscreenGLCanvas.cpp} (86%) rename libraries/gl/src/gl/{OffscreenGlCanvas.h => OffscreenGLCanvas.h} (77%) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5ac14ac0ec..708f8ee5ee 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -78,7 +78,7 @@ #include #include #include -#include +#include #include #include #include @@ -616,7 +616,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : // enable mouse tracking; otherwise, we only get drag events _glWidget->setMouseTracking(true); - _offscreenContext = new OffscreenGlCanvas(); + _offscreenContext = new OffscreenGLCanvas(); _offscreenContext->create(_glWidget->context()->contextHandle()); _offscreenContext->makeCurrent(); initializeGL(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 730158c689..6e8df65032 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -65,7 +65,7 @@ #include "ui/ToolWindow.h" #include "UndoStackScriptingInterface.h" -class OffscreenGlCanvas; +class OffscreenGLCanvas; class GLCanvas; class FaceTracker; class MainWindow; @@ -421,7 +421,7 @@ private: bool _dependencyManagerIsSetup; - OffscreenGlCanvas* _offscreenContext { nullptr }; + OffscreenGLCanvas* _offscreenContext { nullptr }; DisplayPluginPointer _displayPlugin; InputPluginList _activeInputPlugins; diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 3ef882fe76..01cb0961e4 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -10,7 +10,6 @@ #include #include -#include #include diff --git a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp index bb39c7bb7a..4278165e25 100644 --- a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include diff --git a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp index 6e14a158d4..72921b4f90 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp @@ -8,15 +8,6 @@ #include "InterleavedStereoDisplayPlugin.h" -#include -#include - -#include -#include -#include - -#include - static const char * INTERLEAVED_TEXTURED_VS = R"VS(#version 410 core #pragma line __LINE__ @@ -81,4 +72,4 @@ void InterleavedStereoDisplayPlugin::display( _program->Bind(); Uniform(*_program, "textureSize").SetValue(sceneSize); WindowOpenGLDisplayPlugin::display(finalTexture, sceneSize); -} \ No newline at end of file +} diff --git a/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp index 5ba113420d..12865cf4cd 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/stereo/SideBySideStereoDisplayPlugin.cpp @@ -7,17 +7,7 @@ // #include "SideBySideStereoDisplayPlugin.h" - -#include -#include -#include - -#include -#include -#include - -#include -#include +#include const QString SideBySideStereoDisplayPlugin::NAME("3D TV - Side by Side Stereo"); diff --git a/libraries/gl/src/gl/GLEscrow.h b/libraries/gl/src/gl/GLEscrow.h index 54b124ae3c..db9f033de8 100644 --- a/libraries/gl/src/gl/GLEscrow.h +++ b/libraries/gl/src/gl/GLEscrow.h @@ -87,6 +87,11 @@ public: _recycler = recycler; } + size_t depth() { + Lock lock(_mutex); + return _submits.size(); + } + // Submit a new resource from the producer context // returns the number of prior submissions that were // never consumed before becoming available. @@ -124,7 +129,7 @@ public: } return result; } - + // If fetch returns a non-zero value, it's the responsibility of the // client to release it at some point void release(T t, GLsync readSync = 0) { @@ -175,6 +180,7 @@ private: // May be called on any thread, but must be inside a locked section void pop(Deque& deque) { + Lock lock(_mutex); auto& item = deque.front(); _trash.push_front(item); deque.pop_front(); diff --git a/libraries/gl/src/gl/GLWidget.cpp b/libraries/gl/src/gl/GLWidget.cpp index b274b39da7..ec08d70e7a 100644 --- a/libraries/gl/src/gl/GLWidget.cpp +++ b/libraries/gl/src/gl/GLWidget.cpp @@ -45,6 +45,14 @@ void GLWidget::initializeGL() { setAutoBufferSwap(false); } +void GLWidget::paintEvent(QPaintEvent* event) { + QWidget::paintEvent(event); +} + +void GLWidget::resizeEvent(QResizeEvent* event) { + QWidget::resizeEvent(event); +} + bool GLWidget::event(QEvent* event) { switch (event->type()) { case QEvent::MouseMove: diff --git a/libraries/gl/src/gl/GLWidget.h b/libraries/gl/src/gl/GLWidget.h index 040ce542e9..5c4f4305cc 100644 --- a/libraries/gl/src/gl/GLWidget.h +++ b/libraries/gl/src/gl/GLWidget.h @@ -27,6 +27,8 @@ public: protected: virtual void initializeGL() override; virtual bool event(QEvent* event) override; + virtual void paintEvent(QPaintEvent* event) override; + virtual void resizeEvent(QResizeEvent* event) override; private slots: virtual bool eventFilter(QObject*, QEvent* event) override; diff --git a/libraries/gl/src/gl/GlWindow.cpp b/libraries/gl/src/gl/GLWindow.cpp similarity index 69% rename from libraries/gl/src/gl/GlWindow.cpp rename to libraries/gl/src/gl/GLWindow.cpp index 40a5bedf7e..42914fed59 100644 --- a/libraries/gl/src/gl/GlWindow.cpp +++ b/libraries/gl/src/gl/GLWindow.cpp @@ -6,17 +6,18 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "GlWindow.h" +#include "GLWindow.h" #include #include #include "GLHelpers.h" -GlWindow::GlWindow(QOpenGLContext* shareContext) : GlWindow(getDefaultOpenGlSurfaceFormat(), shareContext) { +void GLWindow::createContext(QOpenGLContext* shareContext) { + createContext(getDefaultOpenGlSurfaceFormat(), shareContext); } -GlWindow::GlWindow(const QSurfaceFormat& format, QOpenGLContext* shareContext) { +void GLWindow::createContext(const QSurfaceFormat& format, QOpenGLContext* shareContext) { setSurfaceType(QSurface::OpenGLSurface); setFormat(format); _context = new QOpenGLContext; @@ -27,13 +28,15 @@ GlWindow::GlWindow(const QSurfaceFormat& format, QOpenGLContext* shareContext) { _context->create(); } -GlWindow::~GlWindow() { - _context->doneCurrent(); - _context->deleteLater(); - _context = nullptr; +GLWindow::~GLWindow() { + if (_context) { + _context->doneCurrent(); + _context->deleteLater(); + _context = nullptr; + } } -bool GlWindow::makeCurrent() { +bool GLWindow::makeCurrent() { bool makeCurrentResult = _context->makeCurrent(this); Q_ASSERT(makeCurrentResult); @@ -49,11 +52,16 @@ bool GlWindow::makeCurrent() { return makeCurrentResult; } -void GlWindow::doneCurrent() { +void GLWindow::doneCurrent() { _context->doneCurrent(); } -void GlWindow::swapBuffers() { +void GLWindow::swapBuffers() { _context->swapBuffers(this); } +QOpenGLContext* GLWindow::context() const { + return _context; +} + + diff --git a/libraries/gl/src/gl/GlWindow.h b/libraries/gl/src/gl/GLWindow.h similarity index 63% rename from libraries/gl/src/gl/GlWindow.h rename to libraries/gl/src/gl/GLWindow.h index 4956177725..bccfcd7320 100644 --- a/libraries/gl/src/gl/GlWindow.h +++ b/libraries/gl/src/gl/GLWindow.h @@ -7,8 +7,8 @@ // #pragma once -#ifndef hifi_GlWindow_h -#define hifi_GlWindow_h +#ifndef hifi_GLWindow_h +#define hifi_GLWindow_h #include #include @@ -16,14 +16,15 @@ class QOpenGLContext; class QOpenGLDebugLogger; -class GlWindow : public QWindow { +class GLWindow : public QWindow { public: - GlWindow(QOpenGLContext* shareContext = nullptr); - GlWindow(const QSurfaceFormat& format, QOpenGLContext* shareContext = nullptr); - virtual ~GlWindow(); + virtual ~GLWindow(); + void createContext(QOpenGLContext* shareContext = nullptr); + void createContext(const QSurfaceFormat& format, QOpenGLContext* shareContext = nullptr); bool makeCurrent(); void doneCurrent(); void swapBuffers(); + QOpenGLContext* context() const; private: std::once_flag _reportOnce; QOpenGLContext* _context{ nullptr }; diff --git a/libraries/gl/src/gl/OffscreenGlCanvas.cpp b/libraries/gl/src/gl/OffscreenGLCanvas.cpp similarity index 86% rename from libraries/gl/src/gl/OffscreenGlCanvas.cpp rename to libraries/gl/src/gl/OffscreenGLCanvas.cpp index e5c1ee4c4a..b8c9b9e117 100644 --- a/libraries/gl/src/gl/OffscreenGlCanvas.cpp +++ b/libraries/gl/src/gl/OffscreenGLCanvas.cpp @@ -1,5 +1,5 @@ // -// OffscreenGlCanvas.cpp +// OffscreenGLCanvas.cpp // interface/src/renderer // // Created by Bradley Austin Davis on 2014/04/09. @@ -10,7 +10,7 @@ // -#include "OffscreenGlCanvas.h" +#include "OffscreenGLCanvas.h" #include #include @@ -18,10 +18,10 @@ #include "GLHelpers.h" -OffscreenGlCanvas::OffscreenGlCanvas() : _context(new QOpenGLContext), _offscreenSurface(new QOffscreenSurface){ +OffscreenGLCanvas::OffscreenGLCanvas() : _context(new QOpenGLContext), _offscreenSurface(new QOffscreenSurface){ } -OffscreenGlCanvas::~OffscreenGlCanvas() { +OffscreenGLCanvas::~OffscreenGLCanvas() { #ifdef DEBUG if (_logger) { makeCurrent(); @@ -32,7 +32,7 @@ OffscreenGlCanvas::~OffscreenGlCanvas() { _context->doneCurrent(); } -void OffscreenGlCanvas::create(QOpenGLContext* sharedContext) { +void OffscreenGLCanvas::create(QOpenGLContext* sharedContext) { if (nullptr != sharedContext) { sharedContext->doneCurrent(); _context->setShareContext(sharedContext); @@ -45,7 +45,7 @@ void OffscreenGlCanvas::create(QOpenGLContext* sharedContext) { } -bool OffscreenGlCanvas::makeCurrent() { +bool OffscreenGLCanvas::makeCurrent() { bool result = _context->makeCurrent(_offscreenSurface); Q_ASSERT(result); @@ -72,7 +72,7 @@ bool OffscreenGlCanvas::makeCurrent() { return result; } -void OffscreenGlCanvas::doneCurrent() { +void OffscreenGLCanvas::doneCurrent() { _context->doneCurrent(); } diff --git a/libraries/gl/src/gl/OffscreenGlCanvas.h b/libraries/gl/src/gl/OffscreenGLCanvas.h similarity index 77% rename from libraries/gl/src/gl/OffscreenGlCanvas.h rename to libraries/gl/src/gl/OffscreenGLCanvas.h index 94014adf98..e278f550f0 100644 --- a/libraries/gl/src/gl/OffscreenGlCanvas.h +++ b/libraries/gl/src/gl/OffscreenGLCanvas.h @@ -1,5 +1,5 @@ // -// OffscreenGlCanvas.h +// OffscreenGLCanvas.h // interface/src/renderer // // Created by Bradley Austin Davis on 2014/04/09. @@ -9,8 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #pragma once -#ifndef hifi_OffscreenGlCanvas_h -#define hifi_OffscreenGlCanvas_h +#ifndef hifi_OffscreenGLCanvas_h +#define hifi_OffscreenGLCanvas_h #include #include @@ -19,10 +19,10 @@ class QOpenGLContext; class QOffscreenSurface; class QOpenGLDebugLogger; -class OffscreenGlCanvas : public QObject { +class OffscreenGLCanvas : public QObject { public: - OffscreenGlCanvas(); - ~OffscreenGlCanvas(); + OffscreenGLCanvas(); + ~OffscreenGLCanvas(); void create(QOpenGLContext* sharedContext = nullptr); bool makeCurrent(); void doneCurrent(); @@ -40,4 +40,4 @@ protected: }; -#endif // hifi_OffscreenGlCanvas_h +#endif // hifi_OffscreenGLCanvas_h diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index e8a950a16b..f2eb112dc7 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -23,7 +23,7 @@ #include #include "GLEscrow.h" -#include "OffscreenGlCanvas.h" +#include "OffscreenGLCanvas.h" // FIXME move to threaded rendering with Qt 5.5 //#define QML_THREADED @@ -64,12 +64,12 @@ static const QEvent::Type STOP = QEvent::Type(QEvent::User + 4); static const QEvent::Type UPDATE = QEvent::Type(QEvent::User + 5); #endif -class OffscreenQmlRenderer : public OffscreenGlCanvas { +class OffscreenQmlRenderer : public OffscreenGLCanvas { friend class OffscreenQmlSurface; public: OffscreenQmlRenderer(OffscreenQmlSurface* surface, QOpenGLContext* shareContext) : _surface(surface) { - OffscreenGlCanvas::create(shareContext); + OffscreenGLCanvas::create(shareContext); #ifdef QML_THREADED // Qt 5.5 _renderControl->prepareThread(_renderThread); diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp index ddf251778f..f0398158b4 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include From 1b197987ecd9a0a1241455243cc3a66e650fb14e Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 30 Nov 2015 18:34:40 -0800 Subject: [PATCH 251/401] MOnday spent on improving the Agent/Clint coordination, but still bugs --- examples/acScripts/AgentPoolControler.js | 285 +++++++++++++---------- examples/acScripts/playbackAgents.js | 25 +- examples/acScripts/playbackMaster.js | 61 +++-- 3 files changed, 217 insertions(+), 154 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index 8965defe9c..c7ecd70ad1 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -14,8 +14,8 @@ function printDebug(message) { } (function() { - var COMMAND_CHANNEL = "com.highfidelity.PlaybackChannel1"; - var ANNOUNCE_CHANNEL = "com.highfidelity.playbackAgent.announceID"; + var SERVICE_CHANNEL = "com.highfidelity.playback.service"; + var COMMAND_CHANNEL = "com.highfidelity.playback.command"; // The time between alive messages on the command channel var ALIVE_PERIOD = 3; @@ -23,15 +23,15 @@ function printDebug(message) { // Service Actions var MASTER_ID = -1; - var AGENT_READY = "ready"; - var AGENT_LOST = "agentLost"; + var INVALID_AGENT = -2; - var INVALID_ACTOR = -2; + var BROADCAST_AGENTS = -3; - - var AGENTS_BROADCAST = -1; - var MASTER_ALIVE = -1; - var MASTER_FIRE_AGENT = -2; + var MASTER_ALIVE = "MASTER_ALIVE"; + var AGENT_ALIVE = "AGENT_ALIVE"; + var AGENT_READY = "READY"; + var MASTER_HIRE_AGENT = "HIRE" + var MASTER_FIRE_AGENT = "FIRE"; var makeUniqueUUID = function(SEUUID) { //return SEUUID + Math.random(); @@ -39,7 +39,7 @@ function printDebug(message) { return (Math.random() * 10000).toFixed(0); } - var packAnnounceMessage = function(dest, command, src) { + var packServiceMessage = function(dest, command, src) { var message = { dest: dest, command: command, @@ -48,7 +48,7 @@ function printDebug(message) { return JSON.stringify(message); }; - var unpackAnnounceMessage = function(message) { + var unpackServiceMessage = function(message) { return JSON.parse(message); }; @@ -68,13 +68,27 @@ function printDebug(message) { // Actor //--------------------------------- var Actor = function() { - this.agentID = INVALID_ACTOR; + this.agentID = INVALID_AGENT; + this.lastAliveCycle = 0; this.onHired = function(actor) {}; - this.onLost = function(actor) {}; + this.onFired = function(actor) {}; }; Actor.prototype.isConnected = function () { - return (this.agentID != INVALID_ACTOR); + return (this.agentID != INVALID_AGENT); + } + + Actor.prototype.alive = function () { + printDebug("Agent UUID =" + this.agentID + " Alive was " + this.lastAliveCycle); + this.lastAliveCycle = 0; + } + Actor.prototype.incrementAliveCycle = function () { + printDebug("Actor.prototype.incrementAliveCycle UUID =" + this.agentID + " Alive pre increment " + this.lastAliveCycle); + if (this.isConnected()) { + this.lastAliveCycle++; + printDebug("Agent UUID =" + this.agentID + " Alive incremented " + this.lastAliveCycle); + } + return this.lastAliveCycle; } this.Actor = Actor; @@ -91,7 +105,7 @@ function printDebug(message) { MasterController.prototype.destroy = function() { if (this.subscribed) { - Messages.unsubscribe(ANNOUNCE_CHANNEL); + Messages.unsubscribe(SERVICE_CHANNEL); Messages.unsubscribe(COMMAND_CHANNEL); this.subscribed = true; } @@ -102,11 +116,11 @@ function printDebug(message) { if (!this.subscribed) { Messages.subscribe(COMMAND_CHANNEL); - Messages.subscribe(ANNOUNCE_CHANNEL); + Messages.subscribe(SERVICE_CHANNEL); var localThis = this; Messages.messageReceived.connect(function (channel, message, senderID) { - if (channel == ANNOUNCE_CHANNEL) { - localThis._processAnnounceMessage(message, senderID); + if (channel == SERVICE_CHANNEL) { + localThis._processServiceMessage(message, senderID); return; } }); @@ -116,45 +130,59 @@ function printDebug(message) { printDebug("Master Started"); }; - MasterController.prototype._processAnnounceMessage = function(message, senderID) { - var message = unpackAnnounceMessage(message); + MasterController.prototype._processServiceMessage = function(message, senderID) { + var message = unpackServiceMessage(message); if (message.dest == MASTER_ID) { if (message.command == AGENT_READY) { // check to see if we know about this agent var agentIndex = this.knownAgents.indexOf(message.src); if (agentIndex < 0) { - if (this.hiringAgentsQueue.length > 0) { - var hiringHandler = this.hiringAgentsQueue.pop(); - hiringHandler(message.src); - } else { - //No hiring in queue so bail - return; - } + this._onAgentAvailableForHiring(message.src); } else { // Master think the agent is hired but not the other way around, forget about it printDebug("New agent still sending ready ? " + message.src + " " + agentIndex + " Forgeting about it"); - lostActor.agentID = INVALID_ACTOR; - lostActor.onLost(lostActor); - _clearAgent(agentIndex); + this._removeAgent(agentIndex); } - } else if (message.command == AGENT_LOST) { + } else if (message.command == AGENT_ALIVE) { // check to see if we know about this agent var agentIndex = this.knownAgents.indexOf(message.src); if (agentIndex >= 0) { - lostActor.agentID = INVALID_ACTOR; - lostActor.onLost(lostActor); - _clearAgent(agentIndex); + // yes so reset its alive beat + this.hiredActors[agentIndex].alive(); + return; } else { return; } } } }; - - MasterController.prototype.sendCommand = function(target, action, argument) { + + MasterController.prototype._onAgentAvailableForHiring = function(agentID) { + if (this.hiringAgentsQueue.length == 0) { + printDebug("No Actor on the hiring queue"); + return; + } + + printDebug("MasterController.prototype._onAgentAvailableForHiring " + agentID); + var newActor = this.hiringAgentsQueue.pop(); + + var indexOfNewAgent = this.knownAgents.push(agentID); + newActor.alive(); + newActor.agentID = agentID; + this.hiredActors.push(newActor); + + printDebug("New agent available to be hired " + agentID + " " + indexOfNewAgent); + Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(agentID, MASTER_HIRE_AGENT, MASTER_ID)); + printDebug("message sent calling the actor" + JSON.stringify(newActor) ); + + newActor.onHired(newActor); + } + + MasterController.prototype.sendCommand = function(target, action, argument) { if (this.subscribed) { - var messageJSON = packCommandMessage(target, action, argument); - Messages.sendMessage(COMMAND_CHANNEL, messageJSON); + var command = packCommandMessage(target, action, argument); + printDebug(command); + Messages.sendMessage(COMMAND_CHANNEL, command); } }; @@ -162,7 +190,31 @@ function printDebug(message) { this.timeSinceLastAlive += deltaTime; if (this.timeSinceLastAlive > ALIVE_PERIOD) { this.timeSinceLastAlive = 0; - this.sendCommand(AGENTS_BROADCAST, MASTER_ALIVE); + Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(BROADCAST_AGENTS, MASTER_ALIVE, MASTER_ID)); + + printDebug("checking the agents status"); + { + // Check for alive connected agents + var lostAgents = new Array(); + for (var i = 0; i < this.hiredActors.length; i++) { + var actor = this.hiredActors[i]; + printDebug("checking :" + JSON.stringify(actor)); + var lastAlive = actor.incrementAliveCycle() + if (lastAlive > NUM_CYCLES_BEFORE_RESET) { + printDebug("Agent Lost, firing Agent"); + lostAgents.push(actor); + } + } + + // now fire gathered lost agents + if (lostAgents.length > 0) { + printDebug("Firing " + lostAgents.length + " agents" + JSON.stringify(lostAgents)); + + for (var i = 0; i < lostAgents.length; i++) { + this.fireAgent(lostAgents[l]); + } + } + } } }; @@ -172,54 +224,51 @@ function printDebug(message) { printDebug("trying to hire an agent with a null actor, abort"); return; } - var localThis = this; - this.hiringAgentsQueue.unshift(function(agentID) { - printDebug("hiring callback with agent " + agentID+ " " + JSON.stringify(localThis) ); - - var indexOfNewAgent = localThis.knownAgents.push(agentID) - actor.agentID = agentID; - localThis.hiredActors.push(actor); - - printDebug("New agent available to be hired " + agentID + " " + indexOfNewAgent); - var hireMessage = "HIRE." + indexOfNewAgent; - var answerMessage = packAnnounceMessage(agentID, hireMessage, MASTER_ID); - Messages.sendMessage(ANNOUNCE_CHANNEL, answerMessage); - - printDebug("message sent calling the actor" + JSON.stringify(actor) ); - - actor.onHired(actor); - }) + if (actor.isConnected()) { + printDebug("trying to hire an agent already connected, abort"); + return; + } + this.hiringAgentsQueue.unshift(actor); }; MasterController.prototype.fireAgent = function(actor) { // check to see if we know about this agent printDebug("MasterController.prototype.fireAgent" + JSON.stringify(actor) + " " + JSON.stringify(this.knownAgents)); + + var waitingIndex = this.hiringAgentsQueue.indexOf(actor); + if (waitingIndex >= 0) { + printDebug("MasterController.prototype.fireAgent found actor on waiting queue #" + waitingIndex); + this.hiringAgentsQueue.splice(waitingIndex, 1); + } + var actorIndex = this.knownAgents.indexOf(actor.agentID); if (actorIndex >= 0) { printDebug("fired actor found #" + actorIndex); - - var currentAgentID = actor.agentID; - this._clearAgent(actorIndex); - printDebug("fired actor found #" + actorIndex); - - if (currentAgentID != INVALID_ACTOR) { - printDebug("fired actor is still connected, send fire command"); - this.sendCommand(currentAgentID, MASTER_FIRE_AGENT); - } + this._removeAgent(actorIndex); } } - MasterController.prototype._clearAgent = function(actorIndex) { + MasterController.prototype._removeAgent = function(actorIndex) { // check to see if we know about this agent if (actorIndex >= 0) { - printDebug("before _clearAgent #" + actorIndex + " " + JSON.stringify(this)) + printDebug("before _removeAgent #" + actorIndex + " " + JSON.stringify(this)) this.knownAgents.splice(actorIndex, 1); + var lostActor = this.hiredActors[actorIndex]; this.hiredActors.splice(actorIndex, 1); - lostActor.agentID = INVALID_ACTOR; - printDebug("Clearing agent " + actorIndex + " Forgeting about it"); - printDebug("after _clearAgent #" + actorIndex + " " + JSON.stringify(this)) + var lostAgentID = lostActor.agentID; + lostActor.agentID = INVALID_AGENT; + + printDebug("Clearing agent " + actorIndex + " Forgeting about it"); + printDebug("after _removeAgent #" + actorIndex + " " + JSON.stringify(this)) + + if (lostAgentID != INVALID_AGENT) { + printDebug("fired actor is still connected, send fire command"); + Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(lostAgentID, MASTER_FIRE_AGENT, MASTER_ID)); + } + + lostActor.onFired(lostActor); } } @@ -238,18 +287,17 @@ function printDebug(message) { }; AgentController.prototype._init = function() { - this.actorIndex= INVALID_ACTOR; - this.notifyAlive = false; + this.isHired= false; this.timeSinceLastAlive = 0; this.numCyclesWithoutAlive = 0; - this.actorUUID = makeUniqueUUID(Agent.sessionUUID); - printDebug("this.actorUUID = " + this.actorUUID); + this.agentUUID = makeUniqueUUID(Agent.sessionUUID); + printDebug("this.agentUUID = " + this.agentUUID); } AgentController.prototype.destroy = function() { if (this.subscribed) { this.fired(); - Messages.unsubscribe(ANNOUNCE_CHANNEL); + Messages.unsubscribe(SERVICE_CHANNEL); Messages.unsubscribe(COMMAND_CHANNEL); this.subscribed = true; } @@ -261,11 +309,11 @@ function printDebug(message) { if (!this.subscribed) { Messages.subscribe(COMMAND_CHANNEL); - Messages.subscribe(ANNOUNCE_CHANNEL); + Messages.subscribe(SERVICE_CHANNEL); var localThis = this; Messages.messageReceived.connect(function (channel, message, senderID) { - if (channel == ANNOUNCE_CHANNEL) { - localThis._processAnnounceMessage(message, senderID); + if (channel == SERVICE_CHANNEL) { + localThis._processServiceMessage(message, senderID); return; } if (channel == COMMAND_CHANNEL) { @@ -278,44 +326,39 @@ function printDebug(message) { printDebug("Client Started"); }; - AgentController.prototype._processAnnounceMessage = function(message, senderID) { - var announce = unpackAnnounceMessage(message); - //printDebug("Client " + this.actorIndex + " Received Announcement = " + message); - if (announce.dest == this.actorUUID) { + AgentController.prototype._processServiceMessage = function(message, senderID) { + var announce = unpackServiceMessage(message); + //printDebug("Client " + this.agentUUID + " Received Announcement = " + message); + if (announce.dest == this.agentUUID) { if (announce.command != AGENT_READY) { - // this may be a message to hire me if i m not already - if (this.actorIndex == INVALID_ACTOR) { + var parts = announce.command.split("."); + + // this is potnetially a message to hire me if i m not already + if (!this.isHired && (parts[0] == MASTER_HIRE_AGENT)) { printDebug(announce.command); + this.isHired = true; + printDebug("Client Hired by master UUID" + senderID); + this.onHired(); + return; + } - var parts = announce.command.split("."); - var commandPart0 = parts[0]; - var commandPart1 = parts[1]; - //printDebug("Client " + Agent.sessionUUID + " - " + agentID + " Hired!"); - // if (agentID == Agent.sessionUUID) { - this.actorIndex = commandPart1; - printDebug("Client " + this.actorIndex + " Hired!"); - this.onHired(); - // Messages.unsubscribe(ANNOUNCE_CHANNEL); // id announce channel - // } + if (this.isHired && (parts[0] == MASTER_FIRE_AGENT)) { + printDebug("Client Fired by master UUID" + senderID); + this.fired(); + return; } } + } else if (announce.src == MASTER_ID && announce.command == MASTER_ALIVE) { + this.numCyclesWithoutAlive = 0; + return; } } AgentController.prototype._processCommandMessage = function(message, senderID) { var command = unpackCommandMessage(message); - //printDebug("Received command = " + JSON.stringify(command)); - - if ((command.dest_key == this.actorUUID) || (command.dest_key == AGENTS_BROADCAST)) { - if (command.action_key == MASTER_ALIVE) { - this.notifyAlive = true; - } else if (command.action_key == MASTER_FIRE_AGENT) { - printDebug("Master firing Agent"); - this.fired(); - } else { - printDebug("True action received = " + JSON.stringify(command) + senderID); - this.onCommand(command); - } + if ((command.dest_key == this.agentUUID) || (command.dest_key == BROADCAST_AGENTS)) { + printDebug("Command received = " + JSON.stringify(command) + senderID); + this.onCommand(command); } else { // ignored } @@ -326,17 +369,18 @@ function printDebug(message) { this.timeSinceLastAlive += deltaTime; if (this.timeSinceLastAlive > ALIVE_PERIOD) { if (this.subscribed) { - if (this.actorIndex == INVALID_ACTOR) { - Messages.sendMessage(ANNOUNCE_CHANNEL, packAnnounceMessage(MASTER_ID, AGENT_READY, this.actorUUID)); - //printDebug("Client Ready" + ANNOUNCE_CHANNEL + AGENT_READY); + if (!this.isHired) { + Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(MASTER_ID, AGENT_READY, this.agentUUID)); + //printDebug("Client Ready" + SERVICE_CHANNEL + AGENT_READY); } else { + + // Send alive beat + Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(MASTER_ID, AGENT_ALIVE, this.agentUUID)); + + // Listen for master beat this.numCyclesWithoutAlive++; - if (this.notifyAlive) { - this.notifyAlive = false; - this.numCyclesWithoutAlive = 0; - printDebug("Master Alive"); - } else if (this.numCyclesWithoutAlive > NUM_CYCLES_BEFORE_RESET) { - printDebug("Master Lost, firing Agent"); + if (this.numCyclesWithoutAlive > NUM_CYCLES_BEFORE_RESET) { + printDebug("Master Lost, self firing Agent"); this.fired(); } } @@ -348,12 +392,7 @@ function printDebug(message) { AgentController.prototype.fired = function() { // clear the state first - var wasHired = (this.actorIndex != INVALID_ACTOR); - - // Post a last message to master in case it still listen to warn that this agent is losing it - if (wasHired) { - Messages.sendMessage(ANNOUNCE_CHANNEL, packAnnounceMessage(MASTER_ID, AGENT_LOST, this.actorUUID)); - } + var wasHired = this.isHired; // reset this._init(); @@ -366,6 +405,10 @@ function printDebug(message) { this.AgentController = AgentController; + + + + this.BROADCAST_AGENTS = BROADCAST_AGENTS; })(); diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index ec704e35e9..67fe8c733e 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -31,7 +31,6 @@ var totalTime = 0; var WAIT_FOR_AUDIO_MIXER = 1; // Script. DO NOT MODIFY BEYOND THIS LINE. -var ALIVE = -1; var PLAY = 1; var PLAY_LOOP = 2; var STOP = 3; @@ -45,11 +44,11 @@ Recording.setPlayerUseAttachments(useAttachments); Recording.setPlayerUseHeadModel(false); Recording.setPlayerUseSkeletonModel(useAvatarModel); -function getAction(command) { +function agentCommand(command) { if(true) { // var command = JSON.parse(message); - print("I'm the agent " + this.actorUUID + " and I received this: Dest: " + command.dest_key + " Action: " + command.action_key + " URL: " + command.argument_key); + print("I'm the agent " + this.agentUUID + " and I received this: Dest: " + command.dest_key + " Action: " + command.action_key + " URL: " + command.argument_key); switch(command.action_key) { case PLAY: @@ -82,13 +81,19 @@ function getAction(command) { } break; case LOAD: - print("Load"); - if(command.argument_key !== null) { + { + print("Load" + command.argument_key); + print("Agent #" + command.dest_key + " loading clip URL: " + command.argument_key); + Recording.loadRecording(command.argument_key); + print("After Load" + command.argument_key); + + /*if(command.argument_key == null) { + print("Agent #" + id + " loading clip URL is NULL, nothing happened"); + } else *{ print("Agent #" + id + " loading clip URL: " + command.argument_key); Recording.loadRecording(command.argument_key); - } else { - print("Agent #" + id + " loading clip URL is NULL, nothing happened"); - } + }*/ + } break; default: print("Unknown action: " + command.action_key); @@ -102,7 +107,7 @@ function agentHired() { print("Agent Hired from playbackAgents.js"); if (Recording.isPlaying()) { Recording.stopPlaying(); - } + } Recording.setPlayerLoop(false); } @@ -119,7 +124,7 @@ function update(deltaTime) { if (totalTime > WAIT_FOR_AUDIO_MIXER) { if (!agentController.subscribed) { agentController.reset(); - agentController.onCommand = getAction; + agentController.onCommand = agentCommand; agentController.onHired = agentHired; agentController.onFired = agentFired; } diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 3cf24a6071..7486256f07 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -23,7 +23,6 @@ Script.include(HIFI_PUBLIC_BUCKET + "scripts/libraries/toolBars.js"); Tool.IMAGE_HEIGHT /= 2; Tool.IMAGE_WIDTH /= 2; -var DO_NOTHING = 0; var PLAY = 1; var PLAY_LOOP = 2; var STOP = 3; @@ -149,10 +148,10 @@ Director.prototype.destroy = function () { Director.prototype.clearActors = function () { print("Director.prototype.clearActors") - for (var i = 0; i < this.actors.length; i++) { - print("Destroy actor #" + i) - this.actors[i].destroy(); + while (this.actors.length > 0) { + this.actors.pop().destroy(); } + this.actors = new Array();// Brand new actors } @@ -222,23 +221,40 @@ Director.prototype._buildUI = function () { } Director.prototype.onMousePressEvent = function(clickedOverlay) { - if (this.onOffIcon === this.toolbar.clicked(clickedOverlay, false)) { + if (this.playIcon === this.toolbar.clicked(clickedOverlay, false)) { + print("master play"); + masterController.sendCommand(BROADCAST_AGENTS, PLAY); + } else if (this.onOffIcon === this.toolbar.clicked(clickedOverlay, false)) { this.clearActors(); return true; - } else if (this.playIcon === this.toolbar.clicked(clickedOverlay, false)) { - masterController.sendCommand(AGENTS_BROADCAST, PLAY); } else if (this.playLoopIcon === this.toolbar.clicked(clickedOverlay, false)) { - masterController.sendCommand(AGENTS_BROADCAST, PLAY_LOOP); + masterController.sendCommand(BROADCAST_AGENTS, PLAY_LOOP); } else if (this.stopIcon === this.toolbar.clicked(clickedOverlay, false)) { - masterController.sendCommand(AGENTS_BROADCAST, STOP); - } else if (this.loadIcon === this.toolbar.clicked(clickedOverlay, false)) { + masterController.sendCommand(BROADCAST_AGENTS, STOP); + } else if (this.loadIcon === this.toolbar.clicked(clickedOverlay, false)) { input_text = Window.prompt("Insert the url of the clip: ",""); if (!(input_text === "" || input_text === null)) { print("Performance file ready to be loaded url = " + input_text); - - // FIXME: I cannot pass directly this.onPerformanceLoaded, is that exepected ? - var localThis = this; - Assets.downloadData(input_text, function(data) { localThis.onPerformanceLoaded(data); }); + var urlpartition = input_text.split("."); + print(urlpartition[0]); + print(urlpartition[1]); + + if ((urlpartition.length > 1) && (urlpartition[urlpartition.length - 1] === "hfr")) { + print("detected a unique clip url"); + var oneClipPerformance = new Object(); + oneClipPerformance.avatarClips = new Array(); + oneClipPerformance.avatarClips[0] = input_text; + + print(JSON.stringify(oneClipPerformance)); + + // we make a local simple performance file with a single clip and pipe in directly + this.onPerformanceLoaded(oneClipPerformance); + return true; + } else { + // FIXME: I cannot pass directly this.onPerformanceLoaded, is that exepected ? + var localThis = this; + Assets.downloadData(input_text, function(data) { localThis.onPerformanceLoaded(JSON.parse(data)); }); + } } } else { // Check individual controls @@ -270,19 +286,17 @@ Director.prototype.moveUI = function(pos) { } } -Director.prototype.onPerformanceLoaded = function(performanceData) { - var performanceJSON = JSON.parse(performanceData); +Director.prototype.onPerformanceLoaded = function(performanceJSON) { + // First fire all the current actors + this.clearActors(); + print("Director.prototype.onPerformanceLoaded = " + JSON.stringify(performanceJSON)); if (performanceJSON.avatarClips != null) { var numClips = performanceJSON.avatarClips.length; print("Found " + numClips + "in the performance file, and currently using " + this.actors.length + " actor(s)"); for (var i = 0; i < numClips; i++) { - if (i < this.actors.length) { - // load correct clip to actor - } else { - this.hireActor(performanceJSON.avatarClips[i]); - } + this.hireActor(performanceJSON.avatarClips[i]); } } @@ -309,13 +323,14 @@ Director.prototype.hireActor = function(clipURL) { } }; - newActor.onLost = function(actor) { - print("agent lost from playbackMaster! " + actor.agentID); + newActor.onFired = function(actor) { + print("agent fired from playbackMaster! " + actor.agentID); var index = localThis.actors.indexOf(actor); if (index >= 0) { localThis.actors.splice(index, 1); } actor.destroy(); + moveUI(); } newActor.resetClip(clipURL, function(actor) { From 921cd94c0794caace610ff3d0dcbbbf0723b19fb Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Tue, 1 Dec 2015 00:15:12 -0800 Subject: [PATCH 252/401] Finally a more stable api and playback use case --- examples/acScripts/AgentPoolControler.js | 20 ++++---------- examples/acScripts/playbackAgents.js | 35 ++++++------------------ examples/acScripts/playbackMaster.js | 15 ++++++---- 3 files changed, 23 insertions(+), 47 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index c7ecd70ad1..74ee12922a 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -192,27 +192,22 @@ function printDebug(message) { this.timeSinceLastAlive = 0; Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(BROADCAST_AGENTS, MASTER_ALIVE, MASTER_ID)); - printDebug("checking the agents status"); { // Check for alive connected agents var lostAgents = new Array(); for (var i = 0; i < this.hiredActors.length; i++) { var actor = this.hiredActors[i]; - printDebug("checking :" + JSON.stringify(actor)); var lastAlive = actor.incrementAliveCycle() if (lastAlive > NUM_CYCLES_BEFORE_RESET) { - printDebug("Agent Lost, firing Agent"); - lostAgents.push(actor); + printDebug("Agent Lost, firing Agent #" + i + JSON.stringify(actor)); + lostAgents.push(i); } } - // now fire gathered lost agents - if (lostAgents.length > 0) { + // now fire gathered lost agents from end to begin + while (lostAgents.length > 0) { printDebug("Firing " + lostAgents.length + " agents" + JSON.stringify(lostAgents)); - - for (var i = 0; i < lostAgents.length; i++) { - this.fireAgent(lostAgents[l]); - } + this.fireAgent(this.hiredActors[lostAgents.pop()]); } } } @@ -251,7 +246,7 @@ function printDebug(message) { MasterController.prototype._removeAgent = function(actorIndex) { // check to see if we know about this agent if (actorIndex >= 0) { - printDebug("before _removeAgent #" + actorIndex + " " + JSON.stringify(this)) + printDebug("MasterController.prototype._removeAgent #" + actorIndex + " " + JSON.stringify(this)) this.knownAgents.splice(actorIndex, 1); var lostActor = this.hiredActors[actorIndex]; @@ -259,9 +254,6 @@ function printDebug(message) { var lostAgentID = lostActor.agentID; lostActor.agentID = INVALID_AGENT; - - printDebug("Clearing agent " + actorIndex + " Forgeting about it"); - printDebug("after _removeAgent #" + actorIndex + " " + JSON.stringify(this)) if (lostAgentID != INVALID_AGENT) { printDebug("fired actor is still connected, send fire command"); diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index 67fe8c733e..64c25ec0a8 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -9,9 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// Agent is an avatar -Agent.isAvatar = true; - Script.include("./AgentPoolControler.js"); var agentController = new AgentController(); @@ -34,8 +31,6 @@ var WAIT_FOR_AUDIO_MIXER = 1; var PLAY = 1; var PLAY_LOOP = 2; var STOP = 3; -var SHOW = 4; -var HIDE = 5; var LOAD = 6; Recording.setPlayFromCurrentLocation(playFromCurrentLocation); @@ -71,28 +66,13 @@ function agentCommand(command) { Recording.stopPlaying(); } break; - case SHOW: - print("Show"); - break; - case HIDE: - print("Hide"); - if (Recording.isPlaying()) { - Recording.stopPlaying(); - } - break; case LOAD: { print("Load" + command.argument_key); print("Agent #" + command.dest_key + " loading clip URL: " + command.argument_key); Recording.loadRecording(command.argument_key); print("After Load" + command.argument_key); - - /*if(command.argument_key == null) { - print("Agent #" + id + " loading clip URL is NULL, nothing happened"); - } else *{ - print("Agent #" + id + " loading clip URL: " + command.argument_key); - Recording.loadRecording(command.argument_key); - }*/ + Recording.setPlayerTime(0); } break; default: @@ -105,17 +85,18 @@ function agentCommand(command) { function agentHired() { print("Agent Hired from playbackAgents.js"); - if (Recording.isPlaying()) { - Recording.stopPlaying(); - } + Agent.isAvatar = true; + Recording.stopPlaying(); Recording.setPlayerLoop(false); + Recording.setPlayerTime(0); } function agentFired() { print("Agent Fired from playbackAgents.js"); - if (Recording.isPlaying()) { - Recording.stopPlaying(); - } + Recording.stopPlaying(); + Recording.setPlayerTime(0); + Recording.setPlayerLoop(false); + Agent.isAvatar = false; } diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 7486256f07..d66a09d633 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -26,8 +26,6 @@ Tool.IMAGE_WIDTH /= 2; var PLAY = 1; var PLAY_LOOP = 2; var STOP = 3; -var SHOW = 4; -var HIDE = 5; var LOAD = 6; var windowDimensions = Controller.getViewportDimensions(); @@ -42,10 +40,6 @@ var TEXT_MARGIN = 3; // Add new features to Actor class: Actor.prototype.destroy = function() { print("Actor.prototype.destroy"); - - this.toolbar.cleanup(); - Overlays.deleteOverlay(this.nameOverlay); - print("Need to fire myself" + this.agentID); masterController.fireAgent(this); } @@ -123,6 +117,11 @@ Actor.prototype._buildUI = function() { }); } +Actor.prototype._destroyUI = function() { + this.toolbar.cleanup(); + Overlays.deleteOverlay(this.nameOverlay); +} + Actor.prototype.moveUI = function(pos) { var textSize = TEXT_HEIGHT + 2 * TEXT_MARGIN; this.toolbar.move(pos.x, pos.y); @@ -329,6 +328,9 @@ Director.prototype.hireActor = function(clipURL) { if (index >= 0) { localThis.actors.splice(index, 1); } + + actor._destroyUI(); + actor.destroy(); moveUI(); } @@ -338,6 +340,7 @@ Director.prototype.hireActor = function(clipURL) { masterController.sendCommand(actor.agentID, LOAD, actor.clipURL); }); + masterController.hireAgent(newActor); newActor._buildUI(); From e25e6b5003a38ffc1a56035ec9a1b0e5ead2521c Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Tue, 1 Dec 2015 06:44:56 -0800 Subject: [PATCH 253/401] Test script with sliders for all reverb parameters --- examples/utilities/tools/reverbTest.js | 69 ++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 examples/utilities/tools/reverbTest.js diff --git a/examples/utilities/tools/reverbTest.js b/examples/utilities/tools/reverbTest.js new file mode 100644 index 0000000000..f399a40cc0 --- /dev/null +++ b/examples/utilities/tools/reverbTest.js @@ -0,0 +1,69 @@ +// +// reverbTest.js +// examples +// +// Created by Ken Cooke on 11/23/2015. +// 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 +// + +Script.include("cookies.js"); + +var audioOptions = new AudioEffectOptions({ + maxRoomSize: 50, + roomSize: 50, + reverbTime: 4, + damping: 0.50, + inputBandwidth: 0.8, + earlyLevel: 0, + tailLevel: 0, + dryLevel: 0, + wetLevel: 0 +}); + +AudioDevice.setReverbOptions(audioOptions); +AudioDevice.setReverb(true); +print("Reverb is ON."); + +var panel = new Panel(10, 200); + +var parameters = [ + { name: "roomSize", min: 0, max: 100, units: " feet" }, + { name: "reverbTime", min: 0, max: 10, units: " sec" }, + { name: "damping", min: 0, max: 1, units: " " }, + { name: "inputBandwidth", min: 0, max: 1, units: " " }, + { name: "earlyLevel", min: -48, max: 0, units: " dB" }, + { name: "tailLevel", min: -48, max: 0, units: " dB" }, + { name: "wetLevel", min: -48, max: 0, units: " dB" }, +] + +function setter(name) { + return function(value) { audioOptions[name] = value; AudioDevice.setReverbOptions(audioOptions); } +} + +function getter(name) { + return function() { return audioOptions[name]; } +} + +function displayer(units) { + return function(value) { return (value).toFixed(1) + units; }; +} + +// create a slider for each parameter +for (var i = 0; i < parameters.length; i++) { + var p = parameters[i]; + panel.newSlider(p.name, p.min, p.max, setter(p.name), getter(p.name), displayer(p.units)); +} + +Controller.mouseMoveEvent.connect(function panelMouseMoveEvent(event) { return panel.mouseMoveEvent(event); }); +Controller.mousePressEvent.connect( function panelMousePressEvent(event) { return panel.mousePressEvent(event); }); +Controller.mouseReleaseEvent.connect(function(event) { return panel.mouseReleaseEvent(event); }); + +function scriptEnding() { + panel.destroy(); + AudioDevice.setReverb(false); + print("Reverb is OFF."); +} +Script.scriptEnding.connect(scriptEnding); From 05862eff0060c713747aa47b1e76837402145898 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 1 Dec 2015 10:22:42 -0800 Subject: [PATCH 254/401] add fire sounds to assets JSON --- examples/baseball/assets.json | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/examples/baseball/assets.json b/examples/baseball/assets.json index 037eb616d2..aa0626edfc 100644 --- a/examples/baseball/assets.json +++ b/examples/baseball/assets.json @@ -80,6 +80,26 @@ "pop4.wav": { "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/pop4.wav", "atp_url": "atp:62e80d0a9f084cf731bcc66ca6e9020ee88587417071a281eee3167307b53560.wav" + }, + "fire1.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire1.wav", + "atp_url": "atp:ee6afe565576c4546c6d6cd89c1af532484c9b60ab30574d6b40c2df022f7260.wav", + "attribution": "CC BY 3.0 - Credirt: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" + }, + "fire2.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire2.wav", + "atp_url": "atp:91ef19ba1c78be82d3fd06530cd05ceb90d1e75f4204c66819c208c55da049ef.wav", + "attribution": "CC BY 3.0 - Credirt: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" + }, + "fire3.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire3.wav", + "atp_url": "atp:ee56993daf775012cf49293bfd5971eec7e5c396642f8bfbea902ba8f47b56cd.wav", + "attribution": "CC BY 3.0 - Credirt: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" + }, + "fire4.wav": { + "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire4.wav", + "atp_url": "atp:37775d267f00f82242a7e7f61f3f3d7bf64a54c5a3799e7f2540fa5f6b79bd02.wav", + "attribution": "CC BY 3.0 - Credirt: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" } } } From ab6367ff4e6e486643870c5d85a868663739210e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 1 Dec 2015 11:13:01 -0800 Subject: [PATCH 255/401] remove debug option for disabling physics updates --- .../utilities/tools/developerMenuItems.js | 8 +----- libraries/entities/src/EntityItem.cpp | 1 - libraries/entities/src/EntityItem.h | 25 +------------------ .../entities/src/EntityScriptingInterface.cpp | 19 ++++---------- .../entities/src/EntityScriptingInterface.h | 3 --- libraries/physics/src/EntityMotionState.cpp | 20 ++++++--------- 6 files changed, 14 insertions(+), 62 deletions(-) diff --git a/examples/utilities/tools/developerMenuItems.js b/examples/utilities/tools/developerMenuItems.js index ef8be8aaa9..477cbd671b 100644 --- a/examples/utilities/tools/developerMenuItems.js +++ b/examples/utilities/tools/developerMenuItems.js @@ -19,7 +19,6 @@ var createdStereoInputMenuItem = false; var DEVELOPER_MENU = "Developer"; var ENTITIES_MENU = DEVELOPER_MENU + " > Entities"; -var COLLISION_UPDATES_TO_SERVER = "Don't send collision updates to server"; var RENDER_MENU = DEVELOPER_MENU + " > Render"; var ENTITIES_ITEM = "Entities"; @@ -66,7 +65,6 @@ function setupMenus() { Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Don't Do Precision Picking", isCheckable: true, isChecked: false }); Menu.addMenuItem({ menuName: "Developer > Entities", menuItemName: "Disable Light Entities", isCheckable: true, isChecked: false }); */ - Menu.addMenuItem({ menuName: ENTITIES_MENU, menuItemName: COLLISION_UPDATES_TO_SERVER, isCheckable: true, isChecked: false }); } if (!Menu.menuExists(RENDER_MENU)) { @@ -112,11 +110,7 @@ function setupMenus() { Menu.menuItemEvent.connect(function (menuItem) { print("menuItemEvent() in JS... menuItem=" + menuItem); - if (menuItem == COLLISION_UPDATES_TO_SERVER) { - var dontSendUpdates = Menu.isOptionChecked(COLLISION_UPDATES_TO_SERVER); - print(" dontSendUpdates... checked=" + dontSendUpdates); - Entities.setSendPhysicsUpdates(!dontSendUpdates); - } else if (menuItem == ENTITIES_ITEM) { + if (menuItem == ENTITIES_ITEM) { Scene.shouldRenderEntities = Menu.isOptionChecked(ENTITIES_ITEM); } else if (menuItem == AVATARS_ITEM) { Scene.shouldRenderAvatars = Menu.isOptionChecked(AVATARS_ITEM); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 992b6a1bdd..a70a8c0428 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -32,7 +32,6 @@ #include "EntityActionFactoryInterface.h" -bool EntityItem::_sendPhysicsUpdates = true; int EntityItem::_maxActionsDataSize = 800; quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index d80de4d427..854acb7fe0 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -48,25 +48,6 @@ namespace render { class PendingChanges; } -/* -// these thesholds determine what updates will be ignored (client and server) -const float IGNORE_POSITION_DELTA = 0.0001f; -const float IGNORE_DIMENSIONS_DELTA = 0.0005f; -const float IGNORE_ALIGNMENT_DOT = 0.99997f; -const float IGNORE_LINEAR_VELOCITY_DELTA = 0.001f; -const float IGNORE_DAMPING_DELTA = 0.001f; -const float IGNORE_GRAVITY_DELTA = 0.001f; -const float IGNORE_ANGULAR_VELOCITY_DELTA = 0.0002f; - -// these thresholds determine what updates will activate the physical object -const float ACTIVATION_POSITION_DELTA = 0.005f; -const float ACTIVATION_DIMENSIONS_DELTA = 0.005f; -const float ACTIVATION_ALIGNMENT_DOT = 0.99990f; -const float ACTIVATION_LINEAR_VELOCITY_DELTA = 0.01f; -const float ACTIVATION_GRAVITY_DELTA = 0.1f; -const float ACTIVATION_ANGULAR_VELOCITY_DELTA = 0.03f; -*/ - #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0; #define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { }; @@ -194,7 +175,7 @@ public: virtual bool supportsDetailedRayIntersection() const { return false; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, + bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const { return true; } @@ -387,9 +368,6 @@ public: EntityTreePointer getTree() const; bool wantTerseEditLogging(); - static void setSendPhysicsUpdates(bool value) { _sendPhysicsUpdates = value; } - static bool getSendPhysicsUpdates() { return _sendPhysicsUpdates; } - glm::mat4 getEntityToWorldMatrix() const; glm::mat4 getWorldToEntityMatrix() const; glm::vec3 worldToEntity(const glm::vec3& point) const; @@ -432,7 +410,6 @@ protected: const QByteArray getActionDataInternal() const; void setActionDataInternal(QByteArray actionData); - static bool _sendPhysicsUpdates; EntityTypes::EntityType _type; QUuid _id; quint64 _lastSimulated; // last time this entity called simulate(), this includes velocity, angular velocity, diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index bc57f2c72c..611a484142 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -167,8 +167,8 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties proper if (hasTerseUpdateChanges) { entity->getAllTerseUpdateProperties(properties); } - // TODO: if we knew that ONLY TerseUpdate properties have changed in properties AND the object - // is dynamic AND it is active in the physics simulation then we could chose to NOT queue an update + // TODO: if we knew that ONLY TerseUpdate properties have changed in properties AND the object + // is dynamic AND it is active in the physics simulation then we could chose to NOT queue an update // and instead let the physics simulation decide when to send a terse update. This would remove // the "slide-no-rotate" glitch (and typical a double-update) that we see during the "poke rolling // balls" test. However, even if we solve this problem we still need to provide a "slerp the visible @@ -333,15 +333,6 @@ bool EntityScriptingInterface::getDrawZoneBoundaries() const { return ZoneEntityItem::getDrawZoneBoundaries(); } -void EntityScriptingInterface::setSendPhysicsUpdates(bool value) { - EntityItem::setSendPhysicsUpdates(value); -} - -bool EntityScriptingInterface::getSendPhysicsUpdates() const { - return EntityItem::getSendPhysicsUpdates(); -} - - RayToEntityIntersectionResult::RayToEntityIntersectionResult() : intersects(false), accurate(true), // assume it's accurate @@ -548,16 +539,16 @@ bool EntityScriptingInterface::appendPoint(QUuid entityID, const glm::vec3& poin if (!entity) { qCDebug(entities) << "EntityScriptingInterface::setPoints no entity with ID" << entityID; } - + EntityTypes::EntityType entityType = entity->getType(); - + if (entityType == EntityTypes::Line) { return setPoints(entityID, [point](LineEntityItem& lineEntity) -> bool { return (LineEntityItem*)lineEntity.appendPoint(point); }); } - + return false; } diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 8a4414a596..84688ab24a 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -127,9 +127,6 @@ public slots: Q_INVOKABLE void setDrawZoneBoundaries(bool value); Q_INVOKABLE bool getDrawZoneBoundaries() const; - Q_INVOKABLE void setSendPhysicsUpdates(bool value); - Q_INVOKABLE bool getSendPhysicsUpdates() const; - Q_INVOKABLE bool setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value); Q_INVOKABLE bool setVoxel(QUuid entityID, const glm::vec3& position, int value); Q_INVOKABLE bool setAllVoxels(QUuid entityID, int value); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 34439e57ce..dead822994 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -492,20 +492,14 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q _nextOwnershipBid = now + USECS_BETWEEN_OWNERSHIP_BIDS; } - if (EntityItem::getSendPhysicsUpdates()) { - EntityItemID id(_entity->getID()); - EntityEditPacketSender* entityPacketSender = static_cast(packetSender); - #ifdef WANT_DEBUG - qCDebug(physics) << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()..."; - #endif + EntityItemID id(_entity->getID()); + EntityEditPacketSender* entityPacketSender = static_cast(packetSender); + #ifdef WANT_DEBUG + qCDebug(physics) << "EntityMotionState::sendUpdate()... calling queueEditEntityMessage()..."; + #endif - entityPacketSender->queueEditEntityMessage(PacketType::EntityEdit, id, properties); - _entity->setLastBroadcast(usecTimestampNow()); - } else { - #ifdef WANT_DEBUG - qCDebug(physics) << "EntityMotionState::sendUpdate()... NOT sending update as requested."; - #endif - } + entityPacketSender->queueEditEntityMessage(PacketType::EntityEdit, id, properties); + _entity->setLastBroadcast(usecTimestampNow()); _lastStep = step; } From 4d84362757bbeb0fd7f6f86f5f6768f33ea835ac Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 1 Dec 2015 11:30:56 -0800 Subject: [PATCH 256/401] Fix ScriptEngine setting _isFinished when it shouldn't --- libraries/script-engine/src/ScriptEngine.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 995a92bf83..895a572434 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -673,7 +673,6 @@ void ScriptEngine::run() { } _isRunning = true; - _isFinished = false; if (_wantSignals) { emit runningStateChanged(); } From 70dd8ec19a518da29f384a6fa1a3264b733fbe05 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Dec 2015 11:44:42 -0800 Subject: [PATCH 257/401] Remove left/right relative pos/rot from c++ --- interface/src/avatar/AvatarActionHold.cpp | 76 ++++++------------- interface/src/avatar/AvatarActionHold.h | 9 +-- .../networking/src/udt/PacketHeaders.cpp | 2 +- libraries/networking/src/udt/PacketHeaders.h | 1 - 4 files changed, 26 insertions(+), 62 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index bff6af7337..8a59f91bc8 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -65,15 +65,13 @@ std::shared_ptr AvatarActionHold::getTarget(glm::quat& rotation, glm::ve } } - if (isRightHand) { - rotation = palmRotation * _rightRelativeRotation; - position = palmPosition + rotation * _rightRelativePosition; - } else { + if (!isRightHand) { static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); palmRotation *= yFlip; // Match right hand frame of reference - rotation = palmRotation * _leftRelativeRotation; - position = palmPosition + rotation * _leftRelativePosition; } + + rotation = palmRotation * _relativeRotation; + position = palmPosition + rotation * _relativePosition; }); return holdingAvatar; @@ -175,10 +173,8 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) { } bool AvatarActionHold::updateArguments(QVariantMap arguments) { - glm::vec3 leftRelativePosition; - glm::quat leftRelativeRotation; - glm::vec3 rightRelativePosition; - glm::quat rightRelativeRotation; + glm::vec3 relativePosition; + glm::quat relativeRotation; float timeScale; QString hand; QUuid holderID; @@ -190,27 +186,15 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { bool somethingChanged = ObjectAction::updateArguments(arguments); withReadLock([&]{ bool ok = true; - leftRelativePosition = EntityActionInterface::extractVec3Argument("hold", arguments, "leftRelativePosition", ok, false); + relativePosition = EntityActionInterface::extractVec3Argument("hold", arguments, "relativePosition", ok, false); if (!ok) { - leftRelativePosition = _leftRelativePosition; + relativePosition = _relativePosition; } - + ok = true; - leftRelativeRotation = EntityActionInterface::extractQuatArgument("hold", arguments, "leftRelativeRotation", ok, false); + relativeRotation = EntityActionInterface::extractQuatArgument("hold", arguments, "relativeRotation", ok, false); if (!ok) { - leftRelativeRotation = _leftRelativeRotation; - } - - ok = true; - rightRelativePosition = EntityActionInterface::extractVec3Argument("hold", arguments, "rightRelativePosition", ok, false); - if (!ok) { - rightRelativePosition = _rightRelativePosition; - } - - ok = true; - rightRelativeRotation = EntityActionInterface::extractQuatArgument("hold", arguments, "rightRelativeRotation", ok, false); - if (!ok) { - rightRelativeRotation = _rightRelativeRotation; + relativeRotation = _relativeRotation; } ok = true; @@ -234,25 +218,17 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { if (!ok) { _kinematic = false; } - + ok = true; kinematicSetVelocity = EntityActionInterface::extractBooleanArgument("hold", arguments, "kinematicSetVelocity", ok, false); if (!ok) { _kinematicSetVelocity = false; } - - ok = true; - ignoreIK = EntityActionInterface::extractBooleanArgument("hold", arguments, "ignoreIK", ok, false); - if (!ok) { - _ignoreIK = true; - } if (somethingChanged || - leftRelativePosition != _leftRelativePosition || - leftRelativeRotation != _leftRelativeRotation || - rightRelativePosition != _rightRelativePosition || - rightRelativeRotation != _rightRelativeRotation || + relativePosition != _relativePosition || + relativeRotation != _relativeRotation || timeScale != _linearTimeScale || hand != _hand || holderID != _holderID || @@ -265,10 +241,8 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { if (needUpdate) { withWriteLock([&] { - _leftRelativePosition = leftRelativePosition; - _leftRelativeRotation = leftRelativeRotation; - _rightRelativePosition = rightRelativePosition; - _rightRelativeRotation = rightRelativeRotation; + _relativePosition = relativePosition; + _relativeRotation = relativeRotation; const float MIN_TIMESCALE = 0.1f; _linearTimeScale = glm::max(MIN_TIMESCALE, timeScale); _angularTimeScale = _linearTimeScale; @@ -295,10 +269,8 @@ QVariantMap AvatarActionHold::getArguments() { QVariantMap arguments = ObjectAction::getArguments(); withReadLock([&]{ arguments["holderID"] = _holderID; - arguments["leftRelativePosition"] = glmToQMap(_leftRelativePosition); - arguments["leftRelativeRotation"] = glmToQMap(_leftRelativeRotation); - arguments["rightRelativePosition"] = glmToQMap(_rightRelativePosition); - arguments["rightRelativeRotation"] = glmToQMap(_rightRelativeRotation); + arguments["relativePosition"] = glmToQMap(_relativePosition); + arguments["relativeRotation"] = glmToQMap(_relativeRotation); arguments["timeScale"] = _linearTimeScale; arguments["hand"] = _hand; arguments["kinematic"] = _kinematic; @@ -318,10 +290,8 @@ QByteArray AvatarActionHold::serialize() const { dataStream << AvatarActionHold::holdVersion; dataStream << _holderID; - dataStream << _leftRelativePosition; - dataStream << _leftRelativeRotation; - dataStream << _rightRelativePosition; - dataStream << _rightRelativeRotation; + dataStream << _relativePosition; + dataStream << _relativeRotation; dataStream << _linearTimeScale; dataStream << _hand; @@ -353,10 +323,8 @@ void AvatarActionHold::deserialize(QByteArray serializedArguments) { withWriteLock([&]{ dataStream >> _holderID; - dataStream >> _leftRelativePosition; - dataStream >> _leftRelativeRotation; - dataStream >> _rightRelativePosition; - dataStream >> _rightRelativeRotation; + dataStream >> _relativePosition; + dataStream >> _relativeRotation; dataStream >> _linearTimeScale; _angularTimeScale = _linearTimeScale; dataStream >> _hand; diff --git a/interface/src/avatar/AvatarActionHold.h b/interface/src/avatar/AvatarActionHold.h index d3aad19384..8a6948dde2 100644 --- a/interface/src/avatar/AvatarActionHold.h +++ b/interface/src/avatar/AvatarActionHold.h @@ -38,15 +38,12 @@ public: std::shared_ptr getTarget(glm::quat& rotation, glm::vec3& position); private: - static const uint16_t holdVersion; - void doKinematicUpdate(float deltaTimeStep); - glm::vec3 _leftRelativePosition{ Vectors::ZERO }; - glm::quat _leftRelativeRotation{ Quaternions::IDENTITY }; - glm::vec3 _rightRelativePosition{ Vectors::ZERO }; - glm::quat _rightRelativeRotation{ Quaternions::IDENTITY }; + static const uint16_t holdVersion; + glm::vec3 _relativePosition { Vectors::ZERO }; + glm::quat _relativeRotation { Quaternions::IDENTITY }; QString _hand { "right" }; QUuid _holderID; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 7bb3a1e46f..2f685b7e08 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -41,7 +41,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityAdd: case PacketType::EntityEdit: case PacketType::EntityData: - return VERSION_ENTITIES_ACTIONS_PER_HAND_OFFSET; + return VERSION_ENTITIES_POLYLINE_TEXTURE; case PacketType::AvatarData: case PacketType::BulkAvatarData: default: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 5610d31661..23df89b3d7 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -160,6 +160,5 @@ const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP = 47; const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP_BIS = 48; const PacketVersion VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING = 49; const PacketVersion VERSION_ENTITIES_POLYLINE_TEXTURE = 50; -const PacketVersion VERSION_ENTITIES_ACTIONS_PER_HAND_OFFSET = 51; #endif // hifi_PacketHeaders_h From ff3ae852459e599dee20b69cd7ad4f83d578f9d2 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 1 Dec 2015 12:36:49 -0800 Subject: [PATCH 258/401] Separating the ui to get the url from the actual loading to maybe avoid playbackMaster.js crash? --- examples/acScripts/AgentPoolControler.js | 22 +++++---- examples/acScripts/playbackMaster.js | 59 ++++++++++++++++-------- 2 files changed, 53 insertions(+), 28 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index 74ee12922a..e5917ea93e 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -141,7 +141,7 @@ function printDebug(message) { } else { // Master think the agent is hired but not the other way around, forget about it printDebug("New agent still sending ready ? " + message.src + " " + agentIndex + " Forgeting about it"); - this._removeAgent(agentIndex); + this._removeHiredAgent(agentIndex); } } else if (message.command == AGENT_ALIVE) { // check to see if we know about this agent @@ -199,7 +199,7 @@ function printDebug(message) { var actor = this.hiredActors[i]; var lastAlive = actor.incrementAliveCycle() if (lastAlive > NUM_CYCLES_BEFORE_RESET) { - printDebug("Agent Lost, firing Agent #" + i + JSON.stringify(actor)); + printDebug("Agent Lost, firing Agent #" + i + " ID " + actor.agentID); lostAgents.push(i); } } @@ -228,25 +228,31 @@ function printDebug(message) { MasterController.prototype.fireAgent = function(actor) { // check to see if we know about this agent - printDebug("MasterController.prototype.fireAgent" + JSON.stringify(actor) + " " + JSON.stringify(this.knownAgents)); + printDebug("MasterController.prototype.fireAgent" + actor.agentID); + // Try the waiting list first var waitingIndex = this.hiringAgentsQueue.indexOf(actor); if (waitingIndex >= 0) { - printDebug("MasterController.prototype.fireAgent found actor on waiting queue #" + waitingIndex); - this.hiringAgentsQueue.splice(waitingIndex, 1); + printDebug("fireAgent found actor on waiting queue #" + waitingIndex); + var lostActor = this.hiringAgentsQueue.splice(waitingIndex, 1); + if (lostActor.length) { + lostActor[0].onFired(lostActor[0]); + } + return; } + // then the hired agents var actorIndex = this.knownAgents.indexOf(actor.agentID); if (actorIndex >= 0) { printDebug("fired actor found #" + actorIndex); - this._removeAgent(actorIndex); + this._removeHiredAgent(actorIndex); } } - MasterController.prototype._removeAgent = function(actorIndex) { + MasterController.prototype._removeHiredAgent = function(actorIndex) { // check to see if we know about this agent if (actorIndex >= 0) { - printDebug("MasterController.prototype._removeAgent #" + actorIndex + " " + JSON.stringify(this)) + printDebug("MasterController.prototype._removeHiredAgent #" + this.knownAgents[actorIndex]) this.knownAgents.splice(actorIndex, 1); var lostActor = this.hiredActors[actorIndex]; diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index d66a09d633..5115dc9871 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -61,6 +61,8 @@ Actor.prototype.onMousePressEvent = function(clickedOverlay) { masterController.sendCommand(this.agentID, PLAY_LOOP); } else if (this.stopIcon === this.toolbar.clicked(clickedOverlay, false)) { masterController.sendCommand(this.agentID, STOP); + } else if (this.nameOverlay === clickedOverlay) { + print("Actor: " + JSON.stringify(this)); } else { return false; } @@ -136,6 +138,8 @@ Director = function() { this.actors = new Array(); this.toolbar = null; this._buildUI(); + this.requestPerformanceLoad = false; + this.performanceURL = ""; }; Director.prototype.destroy = function () { @@ -234,27 +238,11 @@ Director.prototype.onMousePressEvent = function(clickedOverlay) { input_text = Window.prompt("Insert the url of the clip: ",""); if (!(input_text === "" || input_text === null)) { print("Performance file ready to be loaded url = " + input_text); - var urlpartition = input_text.split("."); - print(urlpartition[0]); - print(urlpartition[1]); - - if ((urlpartition.length > 1) && (urlpartition[urlpartition.length - 1] === "hfr")) { - print("detected a unique clip url"); - var oneClipPerformance = new Object(); - oneClipPerformance.avatarClips = new Array(); - oneClipPerformance.avatarClips[0] = input_text; - - print(JSON.stringify(oneClipPerformance)); - - // we make a local simple performance file with a single clip and pipe in directly - this.onPerformanceLoaded(oneClipPerformance); - return true; - } else { - // FIXME: I cannot pass directly this.onPerformanceLoaded, is that exepected ? - var localThis = this; - Assets.downloadData(input_text, function(data) { localThis.onPerformanceLoaded(JSON.parse(data)); }); - } + this.requestPerformanceLoad = true; + this.performanceURL = input_text; } + } else if (this.nameOverlay === clickedOverlay) { + print("Director: " + JSON.stringify(this)); } else { // Check individual controls for (var i = 0; i < this.actors.length; i++) { @@ -285,6 +273,32 @@ Director.prototype.moveUI = function(pos) { } } + +Director.prototype.reloadPerformance = function() { + this.requestPerformanceLoad = false; + + var urlpartition = this.performanceURL.split("."); + print(urlpartition[0]); + print(urlpartition[1]); + + if ((urlpartition.length > 1) && (urlpartition[urlpartition.length - 1] === "hfr")) { + print("detected a unique clip url"); + var oneClipPerformance = new Object(); + oneClipPerformance.avatarClips = new Array(); + oneClipPerformance.avatarClips[0] = input_text; + + print(JSON.stringify(oneClipPerformance)); + + // we make a local simple performance file with a single clip and pipe in directly + this.onPerformanceLoaded(oneClipPerformance); + return true; + } else { + // FIXME: I cannot pass directly this.onPerformanceLoaded, is that exepected ? + var localThis = this; + Assets.downloadData(input_text, function(data) { localThis.onPerformanceLoaded(JSON.parse(data)); }); + } +} + Director.prototype.onPerformanceLoaded = function(performanceJSON) { // First fire all the current actors this.clearActors(); @@ -377,6 +391,11 @@ function update(deltaTime) { moveUI(); } + if (director.requestPerformanceLoad) { + print("reloadPerformance " + director.performanceURL); + director.reloadPerformance(); + } + masterController.update(deltaTime); } From 97454ae4466dc60faf86774ca4b417fee866b6b8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Dec 2015 12:10:49 -0800 Subject: [PATCH 259/401] Update handControllerGrab.js --- examples/controllers/handControllerGrab.js | 68 +++++++++++----------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 0812dc8980..fca668c5e0 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -200,6 +200,34 @@ function entityIsGrabbedByOther(entityID) { return false; } +function getSpatialOffsetPosition(hand, spatialKey) { + if (hand !== RIGHT_HAND && spatialKey.leftRelativePosition) { + return spatialKey.leftRelativePosition; + } + if (hand === RIGHT_HAND && spatialKey.rightRelativePosition) { + return spatialKey.rightRelativePosition; + } + if (spatialKey.relativePosition) { + return spatialKey.relativePosition; + } + + return Vec3.ZERO; +} + +function getSpatialOffsetRotation(hand, spatialKey) { + if (hand !== RIGHT_HAND && spatialKey.leftRelativeRotation) { + return spatialKey.leftRelativeRotation; + } + if (hand === RIGHT_HAND && spatialKey.rightRelativeRotation) { + return spatialKey.rightRelativeRotation; + } + if (spatialKey.relativeRotation) { + return spatialKey.relativeRotation; + } + + return Quat.IDENTITY; +} + function MyController(hand) { this.hand = hand; if (this.hand === RIGHT_HAND) { @@ -223,17 +251,8 @@ function MyController(hand) { this.rawTriggerValue = 0; this.rawBumperValue = 0; - this.offsetPosition = { - x: 0.0, - y: 0.0, - z: 0.0 - }; - this.offsetRotation = { - x: 0.0, - y: 0.0, - z: 0.0, - w: 1.0 - }; + this.offsetPosition = Vec3.ZERO; + this.offsetRotation = Quat.IDENTITY; var _this = this; @@ -767,12 +786,8 @@ function MyController(hand) { if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { // if an object is "equipped" and has a spatialKey, use it. - if (grabbableData.spatialKey.relativePosition) { - this.offsetPosition = grabbableData.spatialKey.relativePosition; - } - if (grabbableData.spatialKey.relativeRotation) { - this.offsetRotation = grabbableData.spatialKey.relativeRotation; - } + this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); + this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); } else { var objectRotation = grabbedProperties.rotation; this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); @@ -895,23 +910,8 @@ function MyController(hand) { var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); // use a spring to pull the object to where it will be when equipped - var relativeRotation = { - x: 0.0, - y: 0.0, - z: 0.0, - w: 1.0 - }; - var relativePosition = { - x: 0.0, - y: 0.0, - z: 0.0 - }; - if (grabbableData.spatialKey.relativePosition) { - relativePosition = grabbableData.spatialKey.relativePosition; - } - if (grabbableData.spatialKey.relativeRotation) { - relativeRotation = grabbableData.spatialKey.relativeRotation; - } + var relativeRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + var relativePosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); var handRotation = this.getHandRotation(); var handPosition = this.getHandPosition(); var targetRotation = Quat.multiply(handRotation, relativeRotation); From e6763c2208f1fc404f7a0fd7e137d0920e764bc7 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Dec 2015 15:03:25 -0800 Subject: [PATCH 260/401] Update bow's relative position --- examples/toybox/bow/bow.js | 13 +++++++++---- examples/toybox/bow/createBow.js | 13 +++++++++---- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/examples/toybox/bow/bow.js b/examples/toybox/bow/bow.js index 14e3ed86ec..90199fb70f 100644 --- a/examples/toybox/bow/bow.js +++ b/examples/toybox/bow/bow.js @@ -67,12 +67,17 @@ } var BOW_SPATIAL_KEY = { - relativePosition: { - x: 0, + leftRelativePosition: { + x: 0.05, y: 0.06, - z: 0.11 + z: -0.05 }, - relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, 90) + rightRelativePosition: { + x: -0.05, + y: 0.06, + z: -0.05 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(0, 90, -90) } diff --git a/examples/toybox/bow/createBow.js b/examples/toybox/bow/createBow.js index 880b0920e8..9a9ed98c20 100644 --- a/examples/toybox/bow/createBow.js +++ b/examples/toybox/bow/createBow.js @@ -48,12 +48,17 @@ var bow = Entities.addEntity({ grabbableKey: { invertSolidWhileHeld: true, spatialKey: { - relativePosition: { - x: 0, + leftRelativePosition: { + x: 0.05, y: 0.06, - z: 0.11 + z: -0.05 }, - relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, 90) + rightRelativePosition: { + x: -0.05, + y: 0.06, + z: -0.05 + }, + relativeRotation: Quat.fromPitchYawRollDegrees(0, 90, -90) } } }) From 0b93e637e8be2bf18f720d1f6032547eee0dd16e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Dec 2015 15:13:46 -0800 Subject: [PATCH 261/401] Update bat rotation --- examples/baseball/createBatButton.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/examples/baseball/createBatButton.js b/examples/baseball/createBatButton.js index 75f3dee26e..bbd2bea9f2 100644 --- a/examples/baseball/createBatButton.js +++ b/examples/baseball/createBatButton.js @@ -51,10 +51,9 @@ var batUserData = { grabbableKey: { spatialKey: { - relativePosition: { x: 0.9, y: 0, z: 0 }, - relativeRotation: Quat.fromPitchYawRollDegrees(0, 0, 45), - perHandRelativePosition: { x: 0.0, y: -0.05, z: -0.04 }, - perHandRelativeRotation: Quat.fromPitchYawRollDegrees(0, 0, 0) + leftRelativePosition: { x: 0.9, y: 0.05, z: -0.05 }, + rightRelativePosition: { x: 0.9, y: 0.05, z: 0.05 }, + relativeRotation: Quat.fromPitchYawRollDegrees(0, 0, 45) } } } From 99065f10fa8eb9ce9987902fc8fcfccb2be023ce Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 1 Dec 2015 12:27:09 -0800 Subject: [PATCH 262/401] Avatar Warning fixes on linux --- interface/src/Application.cpp | 1 - interface/src/avatar/MyAvatar.cpp | 5 ++++- interface/src/avatar/SkeletonModel.cpp | 6 ------ 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5ac14ac0ec..f18c6c87ca 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2577,7 +2577,6 @@ void Application::setAvatarUpdateThreading(bool isThreaded) { return; } - auto myAvatar = getMyAvatar(); if (_avatarUpdate) { _avatarUpdate->terminate(); // Must be before we shutdown anim graph. } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 39b09fb9de..029aefcac4 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1808,7 +1808,10 @@ glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const { int neckIndex = _rig->indexOfJoint("Neck"); int hipsIndex = _rig->indexOfJoint("Hips"); - glm::vec3 rigMiddleEyePos = leftEyeIndex != -1 ? _rig->getAbsoluteDefaultPose(leftEyeIndex).trans : DEFAULT_RIG_MIDDLE_EYE_POS; + glm::vec3 rigMiddleEyePos = DEFAULT_RIG_MIDDLE_EYE_POS; + if (leftEyeIndex >= 0 && rightEyeIndex >= 0) { + rigMiddleEyePos = (_rig->getAbsoluteDefaultPose(leftEyeIndex).trans + _rig->getAbsoluteDefaultPose(rightEyeIndex).trans) / 2.0f; + } glm::vec3 rigNeckPos = neckIndex != -1 ? _rig->getAbsoluteDefaultPose(neckIndex).trans : DEFAULT_RIG_NECK_POS; glm::vec3 rigHipsPos = hipsIndex != -1 ? _rig->getAbsoluteDefaultPose(hipsIndex).trans : DEFAULT_RIG_HIPS_POS; diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index d438e6f528..342f8315e1 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -42,7 +42,6 @@ SkeletonModel::~SkeletonModel() { void SkeletonModel::initJointStates() { const FBXGeometry& geometry = _geometry->getFBXGeometry(); - glm::mat4 geometryOffset = geometry.offset; glm::mat4 modelOffset = glm::scale(_scale) * glm::translate(_offset); _rig->initJointStates(geometry, modelOffset); @@ -237,11 +236,6 @@ void SkeletonModel::applyPalmData(int jointIndex, const PalmData& palm) { if (parentJointIndex == -1) { return; } - - // the palm's position must be transformed into the model-frame - glm::quat inverseRotation = glm::inverse(_rotation); - glm::vec3 palmPosition = inverseRotation * (palm.getPosition() - _translation); - glm::quat palmRotation = inverseRotation * palm.getRotation(); } bool SkeletonModel::getLeftHandPosition(glm::vec3& position) const { From 86af28dbab66cd3558428000d5368252035998ee Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 1 Dec 2015 18:18:18 -0800 Subject: [PATCH 263/401] Fighting for one hour with the ready message being misunderstood by master --- examples/acScripts/AgentPoolControler.js | 67 +++++++++++++----------- examples/acScripts/playbackMaster.js | 44 +++++++++------- 2 files changed, 60 insertions(+), 51 deletions(-) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolControler.js index e5917ea93e..830a8fe1e3 100644 --- a/examples/acScripts/AgentPoolControler.js +++ b/examples/acScripts/AgentPoolControler.js @@ -131,21 +131,21 @@ function printDebug(message) { }; MasterController.prototype._processServiceMessage = function(message, senderID) { - var message = unpackServiceMessage(message); - if (message.dest == MASTER_ID) { - if (message.command == AGENT_READY) { + var service = unpackServiceMessage(message); + if (service.dest == MASTER_ID) { + if (service.command == AGENT_READY) { // check to see if we know about this agent - var agentIndex = this.knownAgents.indexOf(message.src); + var agentIndex = this.knownAgents.indexOf(service.src); if (agentIndex < 0) { - this._onAgentAvailableForHiring(message.src); + this._onAgentAvailableForHiring(service.src); } else { // Master think the agent is hired but not the other way around, forget about it - printDebug("New agent still sending ready ? " + message.src + " " + agentIndex + " Forgeting about it"); - this._removeHiredAgent(agentIndex); + printDebug("New agent still sending ready ? " + service.src + " " + agentIndex + " Forgeting about it"); + // this._removeHiredAgent(agentIndex); } - } else if (message.command == AGENT_ALIVE) { + } else if (service.command == AGENT_ALIVE) { // check to see if we know about this agent - var agentIndex = this.knownAgents.indexOf(message.src); + var agentIndex = this.knownAgents.indexOf(service.src); if (agentIndex >= 0) { // yes so reset its alive beat this.hiredActors[agentIndex].alive(); @@ -171,8 +171,10 @@ function printDebug(message) { newActor.agentID = agentID; this.hiredActors.push(newActor); - printDebug("New agent available to be hired " + agentID + " " + indexOfNewAgent); - Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(agentID, MASTER_HIRE_AGENT, MASTER_ID)); + printDebug("New agent available to be hired " + agentID + " " + indexOfNewAgent); + var serviceMessage = packServiceMessage(agentID, MASTER_HIRE_AGENT, MASTER_ID); + printDebug("serviceMessage = " + serviceMessage); + Messages.sendMessage(SERVICE_CHANNEL, serviceMessage); printDebug("message sent calling the actor" + JSON.stringify(newActor) ); newActor.onHired(newActor); @@ -276,7 +278,6 @@ function printDebug(message) { //--------------------------------- var AgentController = function() { this.subscribed = false; - this._init(); this.onHired = function() {}; @@ -325,40 +326,42 @@ function printDebug(message) { }; AgentController.prototype._processServiceMessage = function(message, senderID) { - var announce = unpackServiceMessage(message); - //printDebug("Client " + this.agentUUID + " Received Announcement = " + message); - if (announce.dest == this.agentUUID) { - if (announce.command != AGENT_READY) { - var parts = announce.command.split("."); + var service = unpackServiceMessage(message); + printDebug("Client " + this.agentUUID + " Received message = " + message); + if (service.dest == this.agentUUID) { + if (service.command != AGENT_READY) { - // this is potnetially a message to hire me if i m not already - if (!this.isHired && (parts[0] == MASTER_HIRE_AGENT)) { - printDebug(announce.command); + // this is potentially a message to hire me if i m not already + if (!this.isHired && (service.command == MASTER_HIRE_AGENT)) { + printDebug(service.command); this.isHired = true; - printDebug("Client Hired by master UUID" + senderID); - this.onHired(); + printDebug("Client Hired by master UUID" + service.src); + this.onHired(); + this.alive(); return; } - if (this.isHired && (parts[0] == MASTER_FIRE_AGENT)) { + // Or maybe a message to fire me if i m not hired + if (this.isHired && (service.command == MASTER_FIRE_AGENT)) { printDebug("Client Fired by master UUID" + senderID); this.fired(); return; } } - } else if (announce.src == MASTER_ID && announce.command == MASTER_ALIVE) { + } else if ((service.src == MASTER_ID) && (service.command == MASTER_ALIVE)) { this.numCyclesWithoutAlive = 0; return; } } AgentController.prototype._processCommandMessage = function(message, senderID) { - var command = unpackCommandMessage(message); - if ((command.dest_key == this.agentUUID) || (command.dest_key == BROADCAST_AGENTS)) { - printDebug("Command received = " + JSON.stringify(command) + senderID); - this.onCommand(command); - } else { - // ignored + // ONly work if hired + if (this.isHired) { + var command = unpackCommandMessage(message); + if ((command.dest_key == this.agentUUID) || (command.dest_key == BROADCAST_AGENTS)) { + printDebug("Command received = " + JSON.stringify(command) + senderID); + this.onCommand(command); + } } }; @@ -370,9 +373,9 @@ function printDebug(message) { if (!this.isHired) { Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(MASTER_ID, AGENT_READY, this.agentUUID)); //printDebug("Client Ready" + SERVICE_CHANNEL + AGENT_READY); - } else { - + } else { // Send alive beat + printDebug("beat !"); Messages.sendMessage(SERVICE_CHANNEL, packServiceMessage(MASTER_ID, AGENT_ALIVE, this.agentUUID)); // Listen for master beat diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index 5115dc9871..a88b699bf8 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -275,28 +275,34 @@ Director.prototype.moveUI = function(pos) { Director.prototype.reloadPerformance = function() { - this.requestPerformanceLoad = false; - - var urlpartition = this.performanceURL.split("."); - print(urlpartition[0]); - print(urlpartition[1]); + this.requestPerformanceLoad = false; - if ((urlpartition.length > 1) && (urlpartition[urlpartition.length - 1] === "hfr")) { - print("detected a unique clip url"); - var oneClipPerformance = new Object(); - oneClipPerformance.avatarClips = new Array(); - oneClipPerformance.avatarClips[0] = input_text; + if (this.performanceURL[0] == '{') { + var jsonPerformance = JSON.parse(this.performanceURL); + this.onPerformanceLoaded(jsonPerformance); + } else { - print(JSON.stringify(oneClipPerformance)); + var urlpartition = this.performanceURL.split("."); + print(urlpartition[0]); + print(urlpartition[1]); - // we make a local simple performance file with a single clip and pipe in directly - this.onPerformanceLoaded(oneClipPerformance); - return true; - } else { - // FIXME: I cannot pass directly this.onPerformanceLoaded, is that exepected ? - var localThis = this; - Assets.downloadData(input_text, function(data) { localThis.onPerformanceLoaded(JSON.parse(data)); }); - } + if ((urlpartition.length > 1) && (urlpartition[urlpartition.length - 1] === "hfr")) { + print("detected a unique clip url"); + var oneClipPerformance = new Object(); + oneClipPerformance.avatarClips = new Array(); + oneClipPerformance.avatarClips[0] = input_text; + + print(JSON.stringify(oneClipPerformance)); + + // we make a local simple performance file with a single clip and pipe in directly + this.onPerformanceLoaded(oneClipPerformance); + return true; + } else { + // FIXME: I cannot pass directly this.onPerformanceLoaded, is that exepected ? + var localThis = this; + Assets.downloadData(input_text, function(data) { localThis.onPerformanceLoaded(JSON.parse(data)); }); + } + } } Director.prototype.onPerformanceLoaded = function(performanceJSON) { From 0bc914bf1986bb1792456795efe4e57fc6c0e3a9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Dec 2015 19:33:44 -0800 Subject: [PATCH 264/401] Don't grab subTree outside lock --- assignment-client/src/octree/OctreeSendThread.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 84caf9ce81..b1fd37fe85 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -417,10 +417,15 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus quint64 startInside = usecTimestampNow(); bool lastNodeDidntFit = false; // assume each node fits - if (OctreeElementPointer subTree = nodeData->elementBag.extract()) { + if (!nodeData->elementBag.isEmpty()) { quint64 lockWaitStart = usecTimestampNow(); _myServer->getOctree()->withReadLock([&]{ + OctreeElementPointer subTree = nodeData->elementBag.extract(); + if (!subTree) { + return; + } + quint64 lockWaitEnd = usecTimestampNow(); lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart); quint64 encodeStart = usecTimestampNow(); From be2f14cae580d675b1cea1c499a256f38aa91cc4 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 1 Dec 2015 21:50:01 -0800 Subject: [PATCH 265/401] Review fix --- interface/src/avatar/Head.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index b79e502bed..a22bbfca0b 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -261,8 +261,7 @@ void Head::calculateMouthShapes() { float audioDelta = sqrtf(glm::max(_averageLoudness - _longTermAverageLoudness, 0.0f)) * JAW_OPEN_SCALE; if (audioDelta > _audioJawOpen) { _audioJawOpen += (audioDelta - _audioJawOpen) * JAW_OPEN_RATE; - } - else { + } else { _audioJawOpen *= JAW_CLOSE_RATE; } _audioJawOpen = glm::clamp(_audioJawOpen, 0.0f, 1.0f); From f005afd7c021fe30570d9aa7394162091d597d9f Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 2 Dec 2015 09:33:47 -0800 Subject: [PATCH 266/401] Fix stdint.h includes --- libraries/audio/src/AudioReverb.h | 2 +- libraries/audio/src/AudioSRC.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/audio/src/AudioReverb.h b/libraries/audio/src/AudioReverb.h index 92e9c0009b..639d62d8ec 100644 --- a/libraries/audio/src/AudioReverb.h +++ b/libraries/audio/src/AudioReverb.h @@ -9,7 +9,7 @@ #ifndef hifi_AudioReverb_h #define hifi_AudioReverb_h -#include "stdint.h" +#include typedef struct ReverbParameters { diff --git a/libraries/audio/src/AudioSRC.h b/libraries/audio/src/AudioSRC.h index 5b00ca9e77..920ea8aef0 100644 --- a/libraries/audio/src/AudioSRC.h +++ b/libraries/audio/src/AudioSRC.h @@ -12,7 +12,7 @@ #ifndef hifi_AudioSRC_h #define hifi_AudioSRC_h -#include "stdint.h" +#include class AudioSRC { From c3e2d920ee4180fc6997fd661167bba80788c3ec Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 2 Dec 2015 09:45:51 -0800 Subject: [PATCH 267/401] Move timing at the top --- assignment-client/src/octree/OctreeSendThread.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index b1fd37fe85..94d82b463e 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -421,14 +421,14 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus quint64 lockWaitStart = usecTimestampNow(); _myServer->getOctree()->withReadLock([&]{ + quint64 lockWaitEnd = usecTimestampNow(); + lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart); + quint64 encodeStart = usecTimestampNow(); + OctreeElementPointer subTree = nodeData->elementBag.extract(); if (!subTree) { return; } - - quint64 lockWaitEnd = usecTimestampNow(); - lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart); - quint64 encodeStart = usecTimestampNow(); /* TODO: Looking for a way to prevent locking and encoding a tree that is not // going to result in any packets being sent... From b6398a79309889e6fb0f6e396c7dd8693d28ca5d Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 2 Dec 2015 09:51:52 -0800 Subject: [PATCH 268/401] fix PlayRecordingOnAC.js to use new API --- examples/acScripts/PlayRecordingOnAC.js | 27 +++++++++---------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/examples/acScripts/PlayRecordingOnAC.js b/examples/acScripts/PlayRecordingOnAC.js index b7ae2c7329..0961f65079 100644 --- a/examples/acScripts/PlayRecordingOnAC.js +++ b/examples/acScripts/PlayRecordingOnAC.js @@ -10,20 +10,17 @@ // -var filename = "http://your.recording.url"; +var recordingFile = "http://your.recording.url"; var playFromCurrentLocation = true; var loop = true; -Avatar.skeletonModelURL = "https://hifi-public.s3.amazonaws.com/marketplace/contents/e21c0b95-e502-4d15-8c41-ea2fc40f1125/3585ddf674869a67d31d5964f7b52de1.fst?1427169998"; - // Set position here if playFromCurrentLocation is true Avatar.position = { x:1, y: 1, z: 1 }; Avatar.orientation = Quat.fromPitchYawRollDegrees(0, 0, 0); Avatar.scale = 1.0; - Agent.isAvatar = true; -Avatar.loadRecording(filename); +Recording.loadRecording(recordingFile); count = 300; // This is necessary to wait for the audio mixer to connect function update(event) { @@ -32,22 +29,18 @@ function update(event) { return; } if (count == 0) { - Avatar.setPlayFromCurrentLocation(playFromCurrentLocation); - Avatar.setPlayerLoop(loop); - Avatar.setPlayerUseDisplayName(true); - Avatar.setPlayerUseAttachments(true); - Avatar.setPlayerUseHeadModel(false); - Avatar.setPlayerUseSkeletonModel(true); - Avatar.startPlaying(); - Avatar.play(); + Recording.setPlayFromCurrentLocation(playFromCurrentLocation); + Recording.setPlayerLoop(loop); + Recording.setPlayerUseDisplayName(true); + Recording.setPlayerUseAttachments(true); + Recording.setPlayerUseHeadModel(false); + Recording.setPlayerUseSkeletonModel(true); + Recording.startPlaying(); Vec3.print("Playing from ", Avatar.position); - count--; } - if (Avatar.isPlaying()) { - Avatar.play(); - } else { + if (!Recording.isPlaying()) { Script.update.disconnect(update); } } From 586ed51436aec549d011d97c8923b0ad1dd3bfc4 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 2 Dec 2015 09:56:16 -0800 Subject: [PATCH 269/401] rename AgentPoolCOntroller.js --- .../acScripts/{AgentPoolControler.js => AgentPoolController.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/acScripts/{AgentPoolControler.js => AgentPoolController.js} (100%) diff --git a/examples/acScripts/AgentPoolControler.js b/examples/acScripts/AgentPoolController.js similarity index 100% rename from examples/acScripts/AgentPoolControler.js rename to examples/acScripts/AgentPoolController.js From 0b05a341a842c89b3bef25ebb6034e08859850f0 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 2 Dec 2015 10:18:02 -0800 Subject: [PATCH 270/401] MyAvatar::reset() improvements Body should not orient under the HMD body without changing the HMD view point. It's more predictable and less likely to make you sick. It also should reset the height of the character to cancel out squatting, if the HMD position is low. --- interface/src/avatar/MyAvatar.cpp | 33 ++++++++++++++----------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 029aefcac4..eca39a0a44 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -232,30 +232,27 @@ void MyAvatar::reset(bool andReload) { setThrust(glm::vec3(0.0f)); if (andReload) { - // Get fresh data, in case we're really slow and out of wack. - _hmdSensorMatrix = qApp->getHMDSensorPose(); - _hmdSensorPosition = extractTranslation(_hmdSensorMatrix); - _hmdSensorOrientation = glm::quat_cast(_hmdSensorMatrix); - - // Reset body position/orientation under the head. + // derive the desired body orientation from the *old* hmd orientation, before the sensor reset. auto newBodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation.. + + // transform this body into world space auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix; - glm::vec3 worldBodyPos = extractTranslation(worldBodyMatrix); - glm::quat worldBodyRot = glm::normalize(glm::quat_cast(worldBodyMatrix)); - - // FIXME: Hack to retain the previous behavior wrt height. - // I'd like to make the body match head height, but that will have to wait for separate PR. - worldBodyPos.y = getPosition().y; + auto worldBodyPos = extractTranslation(worldBodyMatrix); + auto worldBodyRot = glm::normalize(glm::quat_cast(worldBodyMatrix)); + // this will become our new position. setPosition(worldBodyPos); setOrientation(worldBodyRot); - // If there is any discrepency between positioning and the head (as there is in initial deriveBodyFromHMDSensor), - // we can make that right by setting _bodySensorMatrix = newBodySensorMatrix. - // However, doing so will make the head want to point to the previous body orientation, as cached above. - //_bodySensorMatrix = newBodySensorMatrix; - //updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes - qApp->setRawAvatarUpdateThreading(); + // now sample the new hmd orientation AFTER sensor reset. + updateFromHMDSensorMatrix(qApp->getHMDSensorPose()); + + // update the body in sensor space using the new hmd sensor sample + _bodySensorMatrix = deriveBodyFromHMDSensor(); + + // rebuild the sensor to world matrix such that, the HMD will point in the desired orientation. + // i.e. the along avatar's current position and orientation. + updateSensorToWorldMatrix(); } } From 0ae70603168a54d18fd0f4b57f8abf0abc5c420b Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 2 Dec 2015 10:23:31 -0800 Subject: [PATCH 271/401] the correct includes --- examples/acScripts/playbackAgents.js | 2 +- examples/acScripts/playbackMaster.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/acScripts/playbackAgents.js b/examples/acScripts/playbackAgents.js index 64c25ec0a8..cf805623de 100644 --- a/examples/acScripts/playbackAgents.js +++ b/examples/acScripts/playbackAgents.js @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include("./AgentPoolControler.js"); +Script.include("./AgentPoolController.js"); var agentController = new AgentController(); // Set the following variables to the values needed diff --git a/examples/acScripts/playbackMaster.js b/examples/acScripts/playbackMaster.js index a88b699bf8..dff0b1d852 100644 --- a/examples/acScripts/playbackMaster.js +++ b/examples/acScripts/playbackMaster.js @@ -8,7 +8,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -Script.include("./AgentPoolControler.js"); +Script.include("./AgentPoolController.js"); HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; From f18fc84c2df8140cbe5afbe10437b4563549456d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 2 Dec 2015 10:46:10 -0800 Subject: [PATCH 272/401] fix debug build --- interface/src/avatar/Avatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 4dff61cedc..83e2324080 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -725,7 +725,7 @@ glm::vec3 Avatar::getDisplayNamePosition() const { const float HEAD_PROPORTION = 0.75f; float billboardSize = getBillboardSize(); - DEBUG_VALUE("_position =", _position); + DEBUG_VALUE("_position =", getPosition()); DEBUG_VALUE("billboardSize =", billboardSize); namePosition = getPosition() + bodyUpDirection * (billboardSize * HEAD_PROPORTION); } From fbd754943010c6746fd6a5f34b25dd1773f81f41 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 2 Dec 2015 11:05:06 -0800 Subject: [PATCH 273/401] Better reverb script defaults --- examples/utilities/tools/reverbTest.js | 4 ++-- libraries/audio/src/AudioEffectOptions.h | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/utilities/tools/reverbTest.js b/examples/utilities/tools/reverbTest.js index f399a40cc0..32c28a993f 100644 --- a/examples/utilities/tools/reverbTest.js +++ b/examples/utilities/tools/reverbTest.js @@ -19,8 +19,8 @@ var audioOptions = new AudioEffectOptions({ inputBandwidth: 0.8, earlyLevel: 0, tailLevel: 0, - dryLevel: 0, - wetLevel: 0 + dryLevel: -6, + wetLevel: -6 }); AudioDevice.setReverbOptions(audioOptions); diff --git a/libraries/audio/src/AudioEffectOptions.h b/libraries/audio/src/AudioEffectOptions.h index 97aac7c82c..be5e1cca5e 100644 --- a/libraries/audio/src/AudioEffectOptions.h +++ b/libraries/audio/src/AudioEffectOptions.h @@ -15,6 +15,8 @@ #include #include +#include "AudioReverb.h" + class AudioEffectOptions : public QObject { Q_OBJECT From 018050344746581d6b39a434dc3182027b093314 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 2 Dec 2015 12:07:38 -0800 Subject: [PATCH 274/401] removed collision sound url --- unpublishedScripts/hiddenEntityReset.js | 1 - unpublishedScripts/masterReset.js | 1 - 2 files changed, 2 deletions(-) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index 982c65fc08..0c15100aaa 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -241,7 +241,6 @@ gravity: BOW_GRAVITY, shapeType: 'compound', compoundShapeURL: COLLISION_HULL_URL, - collisionSoundURL: "http://hifi-public.s3.amazonaws.com/sounds/bow_fall.L.wav", script: bowScriptURL, userData: JSON.stringify({ resetMe: { diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 6e89e12d41..2aa29eb94e 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -220,7 +220,6 @@ MasterReset = function() { gravity: BOW_GRAVITY, shapeType: 'compound', compoundShapeURL: COLLISION_HULL_URL, - collisionSoundURL: "http://hifi-public.s3.amazonaws.com/sounds/bow_fall.L.wav", script: bowScriptURL, userData: JSON.stringify({ resetMe: { From 6d953a65dd2a44ee94906adc2e21424edcb0e205 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 2 Dec 2015 12:09:21 -0800 Subject: [PATCH 275/401] changed restitution to 0 --- unpublishedScripts/hiddenEntityReset.js | 2 ++ unpublishedScripts/masterReset.js | 2 ++ 2 files changed, 4 insertions(+) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index 0c15100aaa..48745715f9 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -655,6 +655,7 @@ y: -3.5, z: 0 }, + restitution: 0, velocity: { x: 0, y: -0.01, @@ -1188,6 +1189,7 @@ collisionsWillMove: true, collisionSoundURL: "http://hifi-public.s3.amazonaws.com/sounds/SpryPntCnDrp1.L.wav", shapeType: 'box', + restitution: 0, gravity: { x: 0, y: -3.0, diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 2aa29eb94e..6a870f988f 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -635,6 +635,7 @@ MasterReset = function() { y: -3.5, z: 0 }, + restitution: 0, velocity: { x: 0, y: -0.01, @@ -1173,6 +1174,7 @@ MasterReset = function() { y: -3.0, z: 0 }, + restitution: 0, velocity: { x: 0, y: -1, From 861393910a47a367799567e0641769731ecc4e00 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Wed, 2 Dec 2015 12:12:57 -0800 Subject: [PATCH 276/401] Add an avatar LOD preference called "Minimum Avatar Display Distance" --- interface/src/avatar/AvatarManager.cpp | 13 ++++- interface/src/avatar/AvatarManager.h | 4 +- interface/src/ui/PreferencesDialog.cpp | 2 + interface/ui/preferencesDialog.ui | 79 ++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 9df597109c..e094f2e263 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -27,6 +27,8 @@ #include #include +#include +#include #include #include "Application.h" @@ -35,7 +37,6 @@ #include "Menu.h" #include "MyAvatar.h" #include "SceneScriptingInterface.h" -#include // 70 times per second - target is 60hz, but this helps account for any small deviations // in the update loop @@ -75,6 +76,13 @@ AvatarManager::AvatarManager(QObject* parent) : packetReceiver.registerListener(PacketType::AvatarBillboard, this, "processAvatarBillboardPacket"); } +const float SMALLEST_REASONABLE_HORIZON = 5.0f; // meters +Setting::Handle avatarRenderDistanceHighLimit("avatarRenderDistanceHighLimit", 1.0f / SMALLEST_REASONABLE_HORIZON); +void AvatarManager::setRenderDistanceHighLimit(float newValue) { + avatarRenderDistanceHighLimit.set(newValue); + _renderDistanceController.setControlledValueHighLimit(newValue); +} + void AvatarManager::init() { _myAvatar->init(); { @@ -93,8 +101,7 @@ void AvatarManager::init() { const float target_fps = qApp->getTargetFrameRate(); _renderDistanceController.setMeasuredValueSetpoint(target_fps); - const float SMALLEST_REASONABLE_HORIZON = 5.0f; // meters - _renderDistanceController.setControlledValueHighLimit(1.0f / SMALLEST_REASONABLE_HORIZON); + _renderDistanceController.setControlledValueHighLimit(avatarRenderDistanceHighLimit.get()); _renderDistanceController.setControlledValueLowLimit(1.0f / (float) TREE_SCALE); // Advice for tuning parameters: // See PIDController.h. There's a section on tuning in the reference. diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 96383b7e60..ddc40d8490 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -70,6 +70,8 @@ public: // Expose results and parameter-tuning operations to other systems, such as stats and javascript. Q_INVOKABLE float getRenderDistance() { return _renderDistance; } + Q_INVOKABLE float getRenderDistanceLowLimit() { return _renderDistanceController.getControlledValueLowLimit(); } + Q_INVOKABLE float getRenderDistanceHighLimit() { return _renderDistanceController.getControlledValueHighLimit(); } Q_INVOKABLE int getNumberInRenderRange() { return _renderedAvatarCount; } Q_INVOKABLE bool getRenderDistanceControllerIsLogging() { return _renderDistanceController.getIsLogging(); } Q_INVOKABLE void setRenderDistanceControllerHistory(QString label, int size) { return _renderDistanceController.setHistorySize(label, size); } @@ -77,7 +79,7 @@ public: Q_INVOKABLE void setRenderDistanceKI(float newValue) { _renderDistanceController.setKI(newValue); } Q_INVOKABLE void setRenderDistanceKD(float newValue) { _renderDistanceController.setKD(newValue); } Q_INVOKABLE void setRenderDistanceLowLimit(float newValue) { _renderDistanceController.setControlledValueLowLimit(newValue); } - Q_INVOKABLE void setRenderDistanceHighLimit(float newValue) { _renderDistanceController.setControlledValueHighLimit(newValue); } + Q_INVOKABLE void setRenderDistanceHighLimit(float newValue); public slots: void setShouldShowReceiveStats(bool shouldShowReceiveStats) { _shouldShowReceiveStats = shouldShowReceiveStats; } diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index c37755b823..69ece359e9 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -204,6 +204,7 @@ void PreferencesDialog::loadPreferences() { auto lodManager = DependencyManager::get(); ui.desktopMinimumFPSSpin->setValue(lodManager->getDesktopLODDecreaseFPS()); ui.hmdMinimumFPSSpin->setValue(lodManager->getHMDLODDecreaseFPS()); + ui.avatarRenderSmallestReasonableHorizon->setValue(1.0f / DependencyManager::get()->getRenderDistanceHighLimit()); } void PreferencesDialog::savePreferences() { @@ -294,4 +295,5 @@ void PreferencesDialog::savePreferences() { auto lodManager = DependencyManager::get(); lodManager->setDesktopLODDecreaseFPS(ui.desktopMinimumFPSSpin->value()); lodManager->setHMDLODDecreaseFPS(ui.hmdMinimumFPSSpin->value()); + DependencyManager::get()->setRenderDistanceHighLimit(1.0f / ui.avatarRenderSmallestReasonableHorizon->value()); } diff --git a/interface/ui/preferencesDialog.ui b/interface/ui/preferencesDialog.ui index a1137a2bf2..e6a5e2228d 100644 --- a/interface/ui/preferencesDialog.ui +++ b/interface/ui/preferencesDialog.ui @@ -912,6 +912,85 @@ + + + + 0 + + + 7 + + + 0 + + + 7 + + + + + + Arial + + + + + + + Minimum Avatar Display Distance + + + 0 + + + + + + + + Arial + + + + Qt::Horizontal + + + + 0 + 0 + + + + + + + + + 100 + 0 + + + + + 95 + 36 + + + + + Arial + + + + 5 + + + 32768 + + + + + From a9438490fe4ef4cf7a2ba60c0c2d981ada3b6f6a Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Wed, 2 Dec 2015 12:53:19 -0800 Subject: [PATCH 277/401] update butterfly model --- examples/example/entities/butterflies.js | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/examples/example/entities/butterflies.js b/examples/example/entities/butterflies.js index 3a78a2fc1c..9d53fc0ebf 100644 --- a/examples/example/entities/butterflies.js +++ b/examples/example/entities/butterflies.js @@ -32,7 +32,7 @@ function randVector(a, b) { var startTimeInSeconds = new Date().getTime() / 1000; -var NATURAL_SIZE_OF_BUTTERFLY = { x: 1.0, y: 0.4, z: 0.2 }; +var NATURAL_SIZE_OF_BUTTERFLY = { x:0.5, y: 0.2, z: 0.1 }; var lifeTime = 3600; // One hour lifespan var range = 7.0; // Over what distance in meters do you want the flock to fly around @@ -65,8 +65,8 @@ function addButterfly() { var color = { red: 100, green: 100, blue: 100 }; var size = 0; - var MINSIZE = 0.06; - var RANGESIZE = 0.2; + var MINSIZE = 0.01; + var RANGESIZE = 0.05; var maxSize = MINSIZE + RANGESIZE; size = MINSIZE + Math.random() * RANGESIZE; @@ -74,7 +74,7 @@ function addButterfly() { var dimensions = Vec3.multiply(NATURAL_SIZE_OF_BUTTERFLY, (size / maxSize)); var GRAVITY = -0.2; - var newFrameRate = 20 + Math.random() * 30; + var newFrameRate = 29 + Math.random() * 30; var properties = { type: "Model", lifetime: lifeTime, @@ -86,17 +86,13 @@ function addButterfly() { dimensions: dimensions, color: color, animation: { - url: "http://public.highfidelity.io/models/content/butterfly/butterfly.fbx", - firstFrame: 0, + url: "http://hifi-content.s3.amazonaws.com/james/butterfly/butterfly.fbx", fps: newFrameRate, - currentFrame: 0, - hold: false, - lastFrame: 10000, loop: true, running: true, startAutomatically:false }, - modelURL: "http://public.highfidelity.io/models/content/butterfly/butterfly.fbx" + modelURL: "http://hifi-content.s3.amazonaws.com/james/butterfly/butterfly.fbx" }; butterflies.push(Entities.addEntity(properties)); } From d9eddbe738328bc211cd51c2507275db102f5976 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 2 Dec 2015 13:32:56 -0800 Subject: [PATCH 278/401] Remove unnecessary ptr get() in PacketList --- libraries/networking/src/udt/PacketList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/PacketList.cpp b/libraries/networking/src/udt/PacketList.cpp index ca4dd68a6d..e4212ccb88 100644 --- a/libraries/networking/src/udt/PacketList.cpp +++ b/libraries/networking/src/udt/PacketList.cpp @@ -51,7 +51,7 @@ PacketList::PacketList(PacketList&& other) : } HifiSockAddr PacketList::getSenderSockAddr() const { - return _packets.size() > 0 ? _packets.front().get()->getSenderSockAddr() : HifiSockAddr(); + return _packets.size() > 0 ? _packets.front()->getSenderSockAddr() : HifiSockAddr(); } void PacketList::startSegment() { From 08ba535c384a62a09ca67583409405694038e9df Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 2 Dec 2015 13:43:05 -0800 Subject: [PATCH 279/401] add some basic send tracking --- .../src/entities/EntityServer.cpp | 46 +++++++++++++++++++ assignment-client/src/entities/EntityServer.h | 6 +++ .../src/octree/OctreeSendThread.cpp | 6 +++ assignment-client/src/octree/OctreeServer.cpp | 5 ++ assignment-client/src/octree/OctreeServer.h | 2 + libraries/entities/src/EntityItem.cpp | 5 ++ libraries/octree/src/Octree.h | 2 + 7 files changed, 72 insertions(+) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 6508f09f72..28e852af6a 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -266,3 +266,49 @@ void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio tree->setWantEditLogging(wantEditLogging); tree->setWantTerseEditLogging(wantTerseEditLogging); } + +void EntityServer::trackSend(const QUuid& dataID, const QUuid& viewerNode) { + QWriteLocker locker(&_viewerSendingStatsLock); + _viewerSendingStats[viewerNode] = usecTimestampNow(); +} + + +QString EntityServer::serverSubclassStats() { + QLocale locale(QLocale::English); + QString statsString; + + // display memory usage stats + statsString += "Entity Server Memory Statistics\r\n"; + statsString += QString().sprintf("EntityTreeElement size... %ld bytes\r\n", sizeof(EntityTreeElement)); + statsString += QString().sprintf(" EntityItem size... %ld bytes\r\n", sizeof(EntityItem)); + statsString += "\r\n\r\n"; + + statsString += "Entity Server Sending to Viewer Statistics\r\n"; + statsString += "----- Viewer Node ID ----------------- ---------- Last Sent To ----------\r\n"; + + int viewers = 0; + const int COLUMN_WIDTH = 24; + + { + QReadLocker locker(&_viewerSendingStatsLock); + quint64 now = usecTimestampNow(); + + for (auto key : _viewerSendingStats.keys()) { + quint64 lastSentAt = _viewerSendingStats[key]; + quint64 elapsed = now - lastSentAt; + double msecsAgo = (double)(elapsed / USECS_PER_MSEC); + statsString += key.toString(); + statsString += " "; + statsString += QString("%1 msecs ago\r\n") + .arg(locale.toString((double)msecsAgo).rightJustified(COLUMN_WIDTH, ' ')); + + viewers++; + } + } + if (viewers < 1) { + statsString += " no viewers... \r\n"; + } + statsString += "\r\n\r\n"; + + return statsString; +} diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h index d9795316c4..ab7ca038cf 100644 --- a/assignment-client/src/entities/EntityServer.h +++ b/assignment-client/src/entities/EntityServer.h @@ -44,6 +44,9 @@ public: virtual void entityCreated(const EntityItem& newEntity, const SharedNodePointer& senderNode) override; virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject) override; + virtual QString serverSubclassStats(); + + virtual void trackSend(const QUuid& dataID, const QUuid& viewerNode); public slots: void pruneDeletedEntities(); @@ -57,6 +60,9 @@ private slots: private: EntitySimulation* _entitySimulation; QTimer* _pruneDeletedEntitiesTimer = nullptr; + + QReadWriteLock _viewerSendingStatsLock; + QMap _viewerSendingStats; }; #endif // hifi_EntityServer_h diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 94d82b463e..fc3731f063 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -467,6 +467,12 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus isFullScene, &nodeData->stats, _myServer->getJurisdiction(), &nodeData->extraEncodeData); + // Our trackSend() function is implemented by the server subclass, and will be called back + // during the encodeTreeBitstream() as new entities/data elements are sent + params.trackSend = [this](const QUuid& id) { + _myServer->trackSend(id, _nodeUUID); + }; + // TODO: should this include the lock time or not? This stat is sent down to the client, // it seems like it may be a good idea to include the lock time as part of the encode time // are reported to client. Since you can encode without the lock diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 7cd3e59edf..c5072d0175 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -821,6 +821,11 @@ bool OctreeServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url .arg(locale.toString((uint)checkSum).rightJustified(16, ' ')); statsString += "\r\n\r\n"; + + statsString += serverSubclassStats(); + + statsString += "\r\n\r\n"; + statsString += "\r\n"; statsString += ""; diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 1aea9c960e..6c11a53bd2 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -79,6 +79,8 @@ public: virtual void beforeRun() { } virtual bool hasSpecialPacketsToSend(const SharedNodePointer& node) { return false; } virtual int sendSpecialPackets(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent) { return 0; } + virtual QString serverSubclassStats() { return QString(); } + virtual void trackSend(const QUuid& dataID, const QUuid& viewerNode) { } static float SKIP_TIME; // use this for trackXXXTime() calls for non-times diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index a70a8c0428..cde1012fb0 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -311,6 +311,11 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet entityTreeElementExtraEncodeData->entities.insert(getEntityItemID(), propertiesDidntFit); } + // if any part of our entity was sent, call trackSend + if (appendState != OctreeElement::NONE) { + params.trackSend(getID()); + } + return appendState; } diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index d9cf17d7de..118ea79b6e 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -176,6 +176,8 @@ public: case OCCLUDED: return QString("OCCLUDED"); break; } } + + std::function trackSend { [](const QUuid&){} }; }; class ReadElementBufferToTreeArgs { From 9c0b4bc2a2be713a32fd4b269e03d377896cdf18 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 2 Dec 2015 14:09:47 -0800 Subject: [PATCH 280/401] Fix for model entities with non-uniform scaled mesh Logic which extracted rotations from a non-uniformly scaled matrices was sometimes incorrect. This should fix the roads in Qbit as well as the blocks in toybox. --- libraries/animation/src/AnimPose.cpp | 5 ++++- libraries/render-utils/src/Model.cpp | 2 +- libraries/shared/src/GLMHelpers.cpp | 11 +++-------- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/libraries/animation/src/AnimPose.cpp b/libraries/animation/src/AnimPose.cpp index 5914031a3a..0c6af2d5bd 100644 --- a/libraries/animation/src/AnimPose.cpp +++ b/libraries/animation/src/AnimPose.cpp @@ -11,6 +11,7 @@ #include "AnimPose.h" #include #include +#include const AnimPose AnimPose::identity = AnimPose(glm::vec3(1.0f), glm::quat(), @@ -18,7 +19,9 @@ const AnimPose AnimPose::identity = AnimPose(glm::vec3(1.0f), AnimPose::AnimPose(const glm::mat4& mat) { scale = extractScale(mat); - rot = glmExtractRotation(mat); + // quat_cast doesn't work so well with scaled matrices, so cancel it out. + glm::mat4 tmp = glm::scale(mat, 1.0f / scale); + rot = glm::normalize(glm::quat_cast(tmp)); trans = extractTranslation(mat); } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 0070b99591..7ab1129e2e 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -928,7 +928,7 @@ void Model::simulate(float deltaTime, bool fullUpdate) { //virtual void Model::updateRig(float deltaTime, glm::mat4 parentTransform) { _needsUpdateClusterMatrices = true; - _rig->updateAnimations(deltaTime, parentTransform); + _rig->updateAnimations(deltaTime, parentTransform); } void Model::simulateInternal(float deltaTime) { // update the world space transforms for all joints diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index 7c5ba6bb48..e6fbe5e5cc 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -279,14 +279,9 @@ glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) { glm::quat glmExtractRotation(const glm::mat4& matrix) { glm::vec3 scale = extractScale(matrix); - float maxScale = std::max(std::max(scale.x, scale.y), scale.z); - if (maxScale > 1.01f || maxScale <= 0.99f) { - // quat_cast doesn't work so well with scaled matrices, so cancel it out. - glm::mat4 tmp = glm::scale(matrix, 1.0f / scale); - return glm::normalize(glm::quat_cast(tmp)); - } else { - return glm::normalize(glm::quat_cast(matrix)); - } + // quat_cast doesn't work so well with scaled matrices, so cancel it out. + glm::mat4 tmp = glm::scale(matrix, 1.0f / scale); + return glm::normalize(glm::quat_cast(tmp)); } glm::vec3 extractScale(const glm::mat4& matrix) { From 1e51a902046304ea8f6619e79a319ef1578c440e Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 2 Dec 2015 14:37:41 -0800 Subject: [PATCH 281/401] add edit times and entity ids to the viewer stats --- .../src/entities/EntityServer.cpp | 41 ++++++++++++++----- assignment-client/src/entities/EntityServer.h | 10 ++++- .../src/octree/OctreeSendThread.cpp | 4 +- assignment-client/src/octree/OctreeServer.h | 2 +- libraries/entities/src/EntityItem.cpp | 2 +- libraries/octree/src/Octree.h | 2 +- 6 files changed, 43 insertions(+), 18 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 28e852af6a..2b53cc9314 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -267,9 +267,14 @@ void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio tree->setWantTerseEditLogging(wantTerseEditLogging); } -void EntityServer::trackSend(const QUuid& dataID, const QUuid& viewerNode) { + +// FIXME - this stats tracking is somewhat temporary to debug the Whiteboard issues. It's not a bad +// set of stats to have, but we'd probably want a different data-structure if we keep it very long. +// Since this version uses a single shared QMap for all senders, there can be a fair amount of lock +// contention on this QWriteLocker +void EntityServer::trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode) { QWriteLocker locker(&_viewerSendingStatsLock); - _viewerSendingStats[viewerNode] = usecTimestampNow(); + _viewerSendingStats[viewerNode][dataID] = { usecTimestampNow(), dataLastEdited }; } @@ -284,7 +289,8 @@ QString EntityServer::serverSubclassStats() { statsString += "\r\n\r\n"; statsString += "Entity Server Sending to Viewer Statistics\r\n"; - statsString += "----- Viewer Node ID ----------------- ---------- Last Sent To ----------\r\n"; + statsString += "----- Viewer Node ID ----------------- ----- Entity ID ---------------------- " + "---------- Last Sent To ---------- ---------- Last Edited -----------\r\n"; int viewers = 0; const int COLUMN_WIDTH = 24; @@ -293,15 +299,28 @@ QString EntityServer::serverSubclassStats() { QReadLocker locker(&_viewerSendingStatsLock); quint64 now = usecTimestampNow(); - for (auto key : _viewerSendingStats.keys()) { - quint64 lastSentAt = _viewerSendingStats[key]; - quint64 elapsed = now - lastSentAt; - double msecsAgo = (double)(elapsed / USECS_PER_MSEC); - statsString += key.toString(); - statsString += " "; - statsString += QString("%1 msecs ago\r\n") - .arg(locale.toString((double)msecsAgo).rightJustified(COLUMN_WIDTH, ' ')); + for (auto viewerID : _viewerSendingStats.keys()) { + statsString += viewerID.toString() + "\r\n"; + auto viewerData = _viewerSendingStats[viewerID]; + for (auto entityID : viewerData.keys()) { + ViewerSendingStats stats = viewerData[entityID]; + + quint64 elapsedSinceSent = now - stats.lastSent; + double sentMsecsAgo = (double)(elapsedSinceSent / USECS_PER_MSEC); + + quint64 elapsedSinceEdit = now - stats.lastEdited; + double editMsecsAgo = (double)(elapsedSinceEdit / USECS_PER_MSEC); + + statsString += " "; // the viewerID spacing + statsString += entityID.toString(); + statsString += " "; + statsString += QString("%1 msecs ago") + .arg(locale.toString((double)sentMsecsAgo).rightJustified(COLUMN_WIDTH, ' ')); + statsString += QString("%1 msecs ago") + .arg(locale.toString((double)editMsecsAgo).rightJustified(COLUMN_WIDTH, ' ')); + statsString += "\r\n"; + } viewers++; } } diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h index ab7ca038cf..d39e966430 100644 --- a/assignment-client/src/entities/EntityServer.h +++ b/assignment-client/src/entities/EntityServer.h @@ -21,6 +21,12 @@ #include "EntityTree.h" /// Handles assignments of type EntityServer - sending entities to various clients. + +struct ViewerSendingStats { + quint64 lastSent; + quint64 lastEdited; +}; + class EntityServer : public OctreeServer, public NewlyCreatedEntityHook { Q_OBJECT public: @@ -46,7 +52,7 @@ public: virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject) override; virtual QString serverSubclassStats(); - virtual void trackSend(const QUuid& dataID, const QUuid& viewerNode); + virtual void trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode); public slots: void pruneDeletedEntities(); @@ -62,7 +68,7 @@ private: QTimer* _pruneDeletedEntitiesTimer = nullptr; QReadWriteLock _viewerSendingStatsLock; - QMap _viewerSendingStats; + QMap> _viewerSendingStats; }; #endif // hifi_EntityServer_h diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index fc3731f063..0a32f574de 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -469,8 +469,8 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // Our trackSend() function is implemented by the server subclass, and will be called back // during the encodeTreeBitstream() as new entities/data elements are sent - params.trackSend = [this](const QUuid& id) { - _myServer->trackSend(id, _nodeUUID); + params.trackSend = [this](const QUuid& dataID, quint64 dataEdited) { + _myServer->trackSend(dataID, dataEdited, _nodeUUID); }; // TODO: should this include the lock time or not? This stat is sent down to the client, diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 6c11a53bd2..9876f5147c 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -80,7 +80,7 @@ public: virtual bool hasSpecialPacketsToSend(const SharedNodePointer& node) { return false; } virtual int sendSpecialPackets(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent) { return 0; } virtual QString serverSubclassStats() { return QString(); } - virtual void trackSend(const QUuid& dataID, const QUuid& viewerNode) { } + virtual void trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode) { } static float SKIP_TIME; // use this for trackXXXTime() calls for non-times diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index cde1012fb0..0120b7c0ca 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -313,7 +313,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet // if any part of our entity was sent, call trackSend if (appendState != OctreeElement::NONE) { - params.trackSend(getID()); + params.trackSend(getID(), getLastEdited()); } return appendState; diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 118ea79b6e..514a9b391b 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -177,7 +177,7 @@ public: } } - std::function trackSend { [](const QUuid&){} }; + std::function trackSend { [](const QUuid&, quint64){} }; }; class ReadElementBufferToTreeArgs { From 4497d21aecde9b69babd1434252c599ed76f1f56 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 2 Dec 2015 14:49:04 -0800 Subject: [PATCH 282/401] remove nodes that disconnect from out viewer stats --- assignment-client/src/entities/EntityServer.cpp | 10 +++++++--- assignment-client/src/entities/EntityServer.h | 1 + assignment-client/src/octree/OctreeServer.cpp | 2 ++ assignment-client/src/octree/OctreeServer.h | 1 + 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index 2b53cc9314..f37e8cf3f7 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -269,14 +269,18 @@ void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio // FIXME - this stats tracking is somewhat temporary to debug the Whiteboard issues. It's not a bad -// set of stats to have, but we'd probably want a different data-structure if we keep it very long. -// Since this version uses a single shared QMap for all senders, there can be a fair amount of lock -// contention on this QWriteLocker +// set of stats to have, but we'd probably want a different data structure if we keep it very long. +// Since this version uses a single shared QMap for all senders, there could be some lock contention +// on this QWriteLocker void EntityServer::trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode) { QWriteLocker locker(&_viewerSendingStatsLock); _viewerSendingStats[viewerNode][dataID] = { usecTimestampNow(), dataLastEdited }; } +void EntityServer::trackViewerGone(const QUuid& viewerNode) { + QWriteLocker locker(&_viewerSendingStatsLock); + _viewerSendingStats.remove(viewerNode); +} QString EntityServer::serverSubclassStats() { QLocale locale(QLocale::English); diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h index d39e966430..89b445c449 100644 --- a/assignment-client/src/entities/EntityServer.h +++ b/assignment-client/src/entities/EntityServer.h @@ -53,6 +53,7 @@ public: virtual QString serverSubclassStats(); virtual void trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode); + virtual void trackViewerGone(const QUuid& viewerNode); public slots: void pruneDeletedEntities(); diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index c5072d0175..dead61d65a 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1184,6 +1184,8 @@ void OctreeServer::nodeKilled(SharedNodePointer node) { if (usecsElapsed > 1000) { qDebug() << qPrintable(_safeServerName) << "server nodeKilled() took: " << usecsElapsed << " usecs for node:" << *node; } + + trackViewerGone(node->getUUID()); } void OctreeServer::forceNodeShutdown(SharedNodePointer node) { diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 9876f5147c..f3a5191335 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -81,6 +81,7 @@ public: virtual int sendSpecialPackets(const SharedNodePointer& node, OctreeQueryNode* queryNode, int& packetsSent) { return 0; } virtual QString serverSubclassStats() { return QString(); } virtual void trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode) { } + virtual void trackViewerGone(const QUuid& viewerNode) { } static float SKIP_TIME; // use this for trackXXXTime() calls for non-times From 0f3722a05cc0793b385592182b88d4939672be76 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 3 Dec 2015 13:14:22 +1300 Subject: [PATCH 283/401] Fix Leap Motion calibration avatar pose --- examples/controllers/leap/leapHands.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/examples/controllers/leap/leapHands.js b/examples/controllers/leap/leapHands.js index 7835df7452..96c3c05adf 100644 --- a/examples/controllers/leap/leapHands.js +++ b/examples/controllers/leap/leapHands.js @@ -166,10 +166,8 @@ var leapHands = (function () { MyAvatar.clearJointData("LeftHand"); MyAvatar.clearJointData("LeftForeArm"); - MyAvatar.clearJointData("LeftArm"); MyAvatar.clearJointData("RightHand"); MyAvatar.clearJointData("RightForeArm"); - MyAvatar.clearJointData("RightArm"); calibrationStatus = CALIBRATED; print("Leap Motion: Calibrated"); @@ -193,12 +191,10 @@ var leapHands = (function () { } // Set avatar arms vertical, forearms horizontal, as "zero" position for calibration - MyAvatar.setJointRotation("LeftArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 0.0)); - MyAvatar.setJointRotation("LeftForeArm", Quat.fromPitchYawRollDegrees(0.0, 90.0, 90.0)); - MyAvatar.setJointRotation("LeftHand", Quat.fromPitchYawRollRadians(0.0, 0.0, 0.0)); - MyAvatar.setJointRotation("RightArm", Quat.fromPitchYawRollDegrees(90.0, 0.0, 0.0)); - MyAvatar.setJointRotation("RightForeArm", Quat.fromPitchYawRollDegrees(0.0, -90.0, -90.0)); - MyAvatar.setJointRotation("RightHand", Quat.fromPitchYawRollRadians(0.0, 0.0, 0.0)); + MyAvatar.setJointRotation("LeftForeArm", Quat.fromPitchYawRollDegrees(0.0, 0.0, 90.0)); + MyAvatar.setJointRotation("LeftHand", Quat.fromPitchYawRollDegrees(0.0, 90.0, 0.0)); + MyAvatar.setJointRotation("RightForeArm", Quat.fromPitchYawRollDegrees(0.0, 0.0, -90.0)); + MyAvatar.setJointRotation("RightHand", Quat.fromPitchYawRollDegrees(0.0, -90.0, 0.0)); // Wait for arms to assume their positions before calculating Script.setTimeout(finishCalibration, CALIBRATION_TIME); From b56cf58e337550094b6f811caa1bbec106acb7e5 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 2 Dec 2015 16:55:04 -0800 Subject: [PATCH 284/401] Fix for mirrored transforms in FBX models extractScale will now return negative scale for left-handed matrices. --- libraries/shared/src/GLMHelpers.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index e6fbe5e5cc..257ef2f00e 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -285,7 +285,14 @@ glm::quat glmExtractRotation(const glm::mat4& matrix) { } glm::vec3 extractScale(const glm::mat4& matrix) { - return glm::vec3(glm::length(matrix[0]), glm::length(matrix[1]), glm::length(matrix[2])); + glm::mat3 m(matrix); + float det = glm::determinant(m); + if (det < 0) { + // left handed matrix, flip sign to compensate. + return glm::vec3(-glm::length(m[0]), glm::length(m[1]), glm::length(m[2])); + } else { + return glm::vec3(glm::length(m[0]), glm::length(m[1]), glm::length(m[2])); + } } float extractUniformScale(const glm::mat4& matrix) { From a0dcf72a3bb249f5b645be8338d9bcecb5c62296 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 3 Dec 2015 14:09:46 +1300 Subject: [PATCH 285/401] Use animation handlers to control hand position and orientation --- examples/controllers/leap/leapHands.js | 50 +++++++++++++++++++++----- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/examples/controllers/leap/leapHands.js b/examples/controllers/leap/leapHands.js index 96c3c05adf..bd8765e376 100644 --- a/examples/controllers/leap/leapHands.js +++ b/examples/controllers/leap/leapHands.js @@ -20,6 +20,9 @@ var leapHands = (function () { hasHandAndWristJoints, handToWristOffset = [], // For avatars without a wrist joint we control an estimate of a proper hand joint position HAND_OFFSET = 0.4, // Relative distance of wrist to hand versus wrist to index finger knuckle + handAnimationStateHandlers, + handAnimationStateFunctions, + handAnimationStateProperties, hands, wrists, NUM_HANDS = 2, // 0 = left; 1 = right @@ -125,6 +128,26 @@ var leapHands = (function () { */ } + function animateLeftHand() { + var ROTATION_AND_POSITION = 0; + + return { + leftHandType: ROTATION_AND_POSITION, + leftHandPosition: hands[0].position, + leftHandRotation: hands[0].rotation + }; + } + + function animateRightHand() { + var ROTATION_AND_POSITION = 0; + + return { + rightHandType: ROTATION_AND_POSITION, + rightHandPosition: hands[1].position, + rightHandRotation: hands[1].rotation + }; + } + function finishCalibration() { var avatarPosition, handPosition, @@ -315,6 +338,13 @@ var leapHands = (function () { ] ]; + handAnimationStateHandlers = [null, null]; + handAnimationStateFunctions = [animateLeftHand, animateRightHand]; + handAnimationStateProperties = [ + ["leftHandType", "leftHandPosition", "leftHandRotation"], + ["rightHandType", "rightHandPosition", "rightHandPosition"] + ]; + setIsOnHMD(); settingsTimer = Script.setInterval(checkSettings, 2000); @@ -344,6 +374,12 @@ var leapHands = (function () { return; } + // Hand animation handlers ... + if (handAnimationStateHandlers[h] === null) { + handAnimationStateHandlers[h] = MyAvatar.addAnimationStateHandler(handAnimationStateFunctions[h], + handAnimationStateProperties[h]); + } + // Hand position ... handOffset = hands[h].controller.getAbsTranslation(); handRotation = hands[h].controller.getAbsRotation(); @@ -454,14 +490,9 @@ var leapHands = (function () { hands[h].inactiveCount += 1; if (hands[h].inactiveCount === MAX_HAND_INACTIVE_COUNT) { - if (h === 0) { - MyAvatar.clearJointData("LeftHand"); - MyAvatar.clearJointData("LeftForeArm"); - MyAvatar.clearJointData("LeftArm"); - } else { - MyAvatar.clearJointData("RightHand"); - MyAvatar.clearJointData("RightForeArm"); - MyAvatar.clearJointData("RightArm"); + if (handAnimationStateHandlers[h] !== null) { + MyAvatar.removeAnimationStateHandler(handAnimationStateHandlers[h]); + handAnimationStateHandlers[h] = null; } } } @@ -479,6 +510,9 @@ var leapHands = (function () { for (h = 0; h < NUM_HANDS; h += 1) { Controller.releaseInputController(hands[h].controller); Controller.releaseInputController(wrists[h].controller); + if (handAnimationStateHandlers[h] !== null) { + MyAvatar.removeAnimationStateHandler(handAnimationStateHandlers[h]); + } for (i = 0; i < NUM_FINGERS; i += 1) { for (j = 0; j < NUM_FINGER_JOINTS; j += 1) { if (fingers[h][i][j].controller !== null) { From 4f836568ad43ed2a0b8833fbbf35acad7f5c2f52 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 2 Dec 2015 17:26:32 -0800 Subject: [PATCH 286/401] Tests to verify AnimPose decomposition is working. --- tests/animation/src/AnimTests.cpp | 91 +++++++++++++++++++++++++++---- tests/animation/src/AnimTests.h | 1 + 2 files changed, 82 insertions(+), 10 deletions(-) diff --git a/tests/animation/src/AnimTests.cpp b/tests/animation/src/AnimTests.cpp index 1b5bb4739a..64db3f6154 100644 --- a/tests/animation/src/AnimTests.cpp +++ b/tests/animation/src/AnimTests.cpp @@ -194,10 +194,7 @@ void AnimTests::testVariant() { auto floatVarNegative = AnimVariant(-1.0f); auto vec3Var = AnimVariant(glm::vec3(1.0f, -2.0f, 3.0f)); auto quatVar = AnimVariant(glm::quat(1.0f, 2.0f, -3.0f, 4.0f)); - auto mat4Var = AnimVariant(glm::mat4(glm::vec4(1.0f, 2.0f, 3.0f, 4.0f), - glm::vec4(5.0f, 6.0f, -7.0f, 8.0f), - glm::vec4(9.0f, 10.0f, 11.0f, 12.0f), - glm::vec4(13.0f, 14.0f, 15.0f, 16.0f))); + QVERIFY(defaultVar.isBool()); QVERIFY(defaultVar.getBool() == false); @@ -232,12 +229,6 @@ void AnimTests::testVariant() { QVERIFY(q.x == 2.0f); QVERIFY(q.y == -3.0f); QVERIFY(q.z == 4.0f); - - QVERIFY(mat4Var.isMat4()); - auto m = mat4Var.getMat4(); - QVERIFY(m[0].x == 1.0f); - QVERIFY(m[1].z == -7.0f); - QVERIFY(m[3].w == 16.0f); } void AnimTests::testAccumulateTime() { @@ -323,3 +314,83 @@ void AnimTests::testAccumulateTimeWithParameters(float startFrame, float endFram QVERIFY(!triggers.empty() && triggers[0] == "testNodeOnLoop"); triggers.clear(); } + + +void AnimTests::testAnimPose() { + const float PI = (float)M_PI; + const glm::quat ROT_X_90 = glm::angleAxis(PI / 2.0f, glm::vec3(1.0f, 0.0f, 0.0f)); + const glm::quat ROT_Y_180 = glm::angleAxis(PI, glm::vec3(0.0f, 1.0, 0.0f)); + const glm::quat ROT_Z_30 = glm::angleAxis(PI / 6.0f, glm::vec3(1.0f, 0.0f, 0.0f)); + + std::vector scaleVec = { + glm::vec3(1), + glm::vec3(2.0f, 1.0f, 1.0f), + glm::vec3(1.0f, 0.5f, 1.0f), + glm::vec3(1.0f, 1.0f, 1.5f), + glm::vec3(2.0f, 0.5f, 1.5f), + glm::vec3(-2.0f, 0.5f, 1.5f), + glm::vec3(2.0f, -0.5f, 1.5f), + glm::vec3(2.0f, 0.5f, -1.5f), + glm::vec3(-2.0f, -0.5f, -1.5f), + }; + + std::vector rotVec = { + glm::quat(), + ROT_X_90, + ROT_Y_180, + ROT_Z_30, + ROT_X_90 * ROT_Y_180 * ROT_Z_30, + -ROT_Y_180 + }; + + std::vector transVec = { + glm::vec3(), + glm::vec3(10.0f, 0.0f, 0.0f), + glm::vec3(0.0f, 5.0f, 0.0f), + glm::vec3(0.0f, 0.0f, 7.5f), + glm::vec3(10.0f, 5.0f, 7.5f), + glm::vec3(-10.0f, 5.0f, 7.5f), + glm::vec3(10.0f, -5.0f, 7.5f), + glm::vec3(10.0f, 5.0f, -7.5f) + }; + + const float EPSILON = 0.001f; + + for (auto& scale : scaleVec) { + for (auto& rot : rotVec) { + for (auto& trans : transVec) { + + // build a matrix the old fashioned way. + glm::mat4 scaleMat = glm::scale(glm::mat4(), scale); + glm::mat4 rotTransMat = createMatFromQuatAndPos(rot, trans); + glm::mat4 rawMat = rotTransMat * scaleMat; + + // use an anim pose to build a matrix by parts. + AnimPose pose(scale, rot, trans); + glm::mat4 poseMat = pose; + + QCOMPARE_WITH_ABS_ERROR(rawMat, poseMat, EPSILON); + } + } + } + + for (auto& scale : scaleVec) { + for (auto& rot : rotVec) { + for (auto& trans : transVec) { + + // build a matrix the old fashioned way. + glm::mat4 scaleMat = glm::scale(glm::mat4(), scale); + glm::mat4 rotTransMat = createMatFromQuatAndPos(rot, trans); + glm::mat4 rawMat = rotTransMat * scaleMat; + + // use an anim pose to decompse a matrix into parts + AnimPose pose(rawMat); + + // now build a new matrix from those parts. + glm::mat4 poseMat = pose; + + QCOMPARE_WITH_ABS_ERROR(rawMat, poseMat, EPSILON); + } + } + } +} diff --git a/tests/animation/src/AnimTests.h b/tests/animation/src/AnimTests.h index 7bd05369c7..a07217b91a 100644 --- a/tests/animation/src/AnimTests.h +++ b/tests/animation/src/AnimTests.h @@ -26,6 +26,7 @@ private slots: void testLoader(); void testVariant(); void testAccumulateTime(); + void testAnimPose(); }; #endif // hifi_AnimTests_h From dec4cd012e62fdf62d5fed843f087d7084d66d26 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Wed, 2 Dec 2015 18:26:09 -0800 Subject: [PATCH 287/401] made ping pong gun have restitution of 0 --- unpublishedScripts/hiddenEntityReset.js | 1 + unpublishedScripts/masterReset.js | 1 + 2 files changed, 2 insertions(+) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index 48745715f9..7e1391780d 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -1027,6 +1027,7 @@ y: -9.8, z: 0 }, + restitution: 0, dimensions: { x: 0.08, y: 0.21, diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 6a870f988f..2fbeb94865 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -1007,6 +1007,7 @@ MasterReset = function() { y: -9.8, z: 0 }, + restitution: 0, dimensions: { x: 0.08, y: 0.21, From 7a05a664f4e05d1d6334d625060afd2353a6c001 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 2 Dec 2015 16:47:48 -0800 Subject: [PATCH 288/401] Updating GPU for 64 bit --- libraries/gpu/src/gpu/Batch.cpp | 6 +- libraries/gpu/src/gpu/Batch.h | 16 ++-- libraries/gpu/src/gpu/Format.h | 2 +- libraries/gpu/src/gpu/GLBackend.cpp | 46 +++++----- libraries/gpu/src/gpu/GLBackend.h | 90 ++++++++++---------- libraries/gpu/src/gpu/GLBackendBuffer.cpp | 2 +- libraries/gpu/src/gpu/GLBackendInput.cpp | 18 ++-- libraries/gpu/src/gpu/GLBackendOutput.cpp | 6 +- libraries/gpu/src/gpu/GLBackendPipeline.cpp | 6 +- libraries/gpu/src/gpu/GLBackendQuery.cpp | 6 +- libraries/gpu/src/gpu/GLBackendState.cpp | 4 +- libraries/gpu/src/gpu/GLBackendTransform.cpp | 22 ++--- libraries/gpu/src/gpu/Resource.h | 4 +- libraries/gpu/src/gpu/Stream.h | 15 ++-- 14 files changed, 121 insertions(+), 122 deletions(-) diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index 2e3ea7fc36..80b3a4f158 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -80,9 +80,9 @@ void Batch::clear() { _framebuffers.clear(); } -uint32 Batch::cacheData(uint32 size, const void* data) { - uint32 offset = _data.size(); - uint32 numBytes = size; +size_t Batch::cacheData(size_t size, const void* data) { + size_t offset = _data.size(); + size_t numBytes = size; _data.resize(offset + numBytes); memcpy(_data.data() + offset, data, size); diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 8397f92da6..258f6d6488 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -334,7 +334,7 @@ public: NUM_COMMANDS, }; typedef std::vector Commands; - typedef std::vector CommandOffsets; + typedef std::vector CommandOffsets; const Commands& getCommands() const { return _commands; } const CommandOffsets& getCommandOffsets() const { return _commandOffsets; } @@ -342,11 +342,13 @@ public: class Param { public: union { + size_t _size; int32 _int; uint32 _uint; - float _float; - char _chars[4]; + float _float; + char _chars[sizeof(size_t)]; }; + Param(size_t val) : _size(val) {} Param(int32 val) : _int(val) {} Param(uint32 val) : _uint(val) {} Param(float val) : _float(val) {} @@ -370,8 +372,8 @@ public: std::vector< Cache > _items; size_t size() const { return _items.size(); } - uint32 cache(const Data& data) { - uint32 offset = _items.size(); + size_t cache(const Data& data) { + size_t offset = _items.size(); _items.push_back(Cache(data)); return offset; } @@ -403,8 +405,8 @@ public: // FOr example Mat4s are going there typedef unsigned char Byte; typedef std::vector Bytes; - uint32 cacheData(uint32 size, const void* data); - Byte* editData(uint32 offset) { + size_t cacheData(size_t size, const void* data); + Byte* editData(size_t offset) { if (offset >= _data.size()) { return 0; } diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index ff0fd9faea..3022f47b51 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -33,7 +33,7 @@ typedef char int8; typedef unsigned char Byte; -typedef uint32 Offset; +typedef size_t Offset; typedef glm::mat4 Mat4; typedef glm::mat3 Mat3; diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index e49a3ba6c0..d4f3c5c4b3 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -304,7 +304,7 @@ void GLBackend::syncCache() { glEnable(GL_LINE_SMOOTH); } -void GLBackend::do_draw(Batch& batch, uint32 paramOffset) { +void GLBackend::do_draw(Batch& batch, size_t paramOffset) { updateInput(); updateTransform(); updatePipeline(); @@ -317,7 +317,7 @@ void GLBackend::do_draw(Batch& batch, uint32 paramOffset) { (void) CHECK_GL_ERROR(); } -void GLBackend::do_drawIndexed(Batch& batch, uint32 paramOffset) { +void GLBackend::do_drawIndexed(Batch& batch, size_t paramOffset) { updateInput(); updateTransform(); updatePipeline(); @@ -336,7 +336,7 @@ void GLBackend::do_drawIndexed(Batch& batch, uint32 paramOffset) { (void) CHECK_GL_ERROR(); } -void GLBackend::do_drawInstanced(Batch& batch, uint32 paramOffset) { +void GLBackend::do_drawInstanced(Batch& batch, size_t paramOffset) { updateInput(); updateTransform(); updatePipeline(); @@ -351,7 +351,7 @@ void GLBackend::do_drawInstanced(Batch& batch, uint32 paramOffset) { (void) CHECK_GL_ERROR(); } -void GLBackend::do_drawIndexedInstanced(Batch& batch, uint32 paramOffset) { +void GLBackend::do_drawIndexedInstanced(Batch& batch, size_t paramOffset) { updateInput(); updateTransform(); updatePipeline(); @@ -378,7 +378,7 @@ void GLBackend::do_drawIndexedInstanced(Batch& batch, uint32 paramOffset) { } -void GLBackend::do_multiDrawIndirect(Batch& batch, uint32 paramOffset) { +void GLBackend::do_multiDrawIndirect(Batch& batch, size_t paramOffset) { #if (GPU_INPUT_PROFILE == GPU_CORE_43) updateInput(); updateTransform(); @@ -387,7 +387,7 @@ void GLBackend::do_multiDrawIndirect(Batch& batch, uint32 paramOffset) { uint commandCount = batch._params[paramOffset + 0]._uint; GLenum mode = _primitiveToGLmode[(Primitive)batch._params[paramOffset + 1]._uint]; - glMultiDrawArraysIndirect(mode, reinterpret_cast(_input._indirectBufferOffset), commandCount, _input._indirectBufferStride); + glMultiDrawArraysIndirect(mode, reinterpret_cast(_input._indirectBufferOffset), commandCount, (GLsizei)_input._indirectBufferStride); #else // FIXME implement the slow path #endif @@ -395,7 +395,7 @@ void GLBackend::do_multiDrawIndirect(Batch& batch, uint32 paramOffset) { } -void GLBackend::do_multiDrawIndexedIndirect(Batch& batch, uint32 paramOffset) { +void GLBackend::do_multiDrawIndexedIndirect(Batch& batch, size_t paramOffset) { #if (GPU_INPUT_PROFILE == GPU_CORE_43) updateInput(); updateTransform(); @@ -405,7 +405,7 @@ void GLBackend::do_multiDrawIndexedIndirect(Batch& batch, uint32 paramOffset) { GLenum mode = _primitiveToGLmode[(Primitive)batch._params[paramOffset + 1]._uint]; GLenum indexType = _elementTypeToGLType[_input._indexBufferType]; - glMultiDrawElementsIndirect(mode, indexType, reinterpret_cast(_input._indirectBufferOffset), commandCount, _input._indirectBufferStride); + glMultiDrawElementsIndirect(mode, indexType, reinterpret_cast(_input._indirectBufferOffset), commandCount, (GLsizei)_input._indirectBufferStride); #else // FIXME implement the slow path #endif @@ -413,11 +413,11 @@ void GLBackend::do_multiDrawIndexedIndirect(Batch& batch, uint32 paramOffset) { } -void GLBackend::do_resetStages(Batch& batch, uint32 paramOffset) { +void GLBackend::do_resetStages(Batch& batch, size_t paramOffset) { resetStages(); } -void GLBackend::do_runLambda(Batch& batch, uint32 paramOffset) { +void GLBackend::do_runLambda(Batch& batch, size_t paramOffset) { std::function f = batch._lambdas.get(batch._params[paramOffset]._uint); f(); } @@ -455,7 +455,7 @@ void Batch::_glActiveBindTexture(GLenum unit, GLenum target, GLuint texture) { DO_IT_NOW(_glActiveBindTexture, 3); } -void GLBackend::do_glActiveBindTexture(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glActiveBindTexture(Batch& batch, size_t paramOffset) { glActiveTexture(batch._params[paramOffset + 2]._uint); glBindTexture( batch._params[paramOffset + 1]._uint, @@ -474,7 +474,7 @@ void Batch::_glUniform1i(GLint location, GLint v0) { DO_IT_NOW(_glUniform1i, 1); } -void GLBackend::do_glUniform1i(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glUniform1i(Batch& batch, size_t paramOffset) { if (_pipeline._program == 0) { // We should call updatePipeline() to bind the program but we are not doing that // because these uniform setters are deprecated and we don;t want to create side effect @@ -497,7 +497,7 @@ void Batch::_glUniform1f(GLint location, GLfloat v0) { DO_IT_NOW(_glUniform1f, 1); } -void GLBackend::do_glUniform1f(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glUniform1f(Batch& batch, size_t paramOffset) { if (_pipeline._program == 0) { // We should call updatePipeline() to bind the program but we are not doing that // because these uniform setters are deprecated and we don;t want to create side effect @@ -521,7 +521,7 @@ void Batch::_glUniform2f(GLint location, GLfloat v0, GLfloat v1) { DO_IT_NOW(_glUniform2f, 1); } -void GLBackend::do_glUniform2f(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glUniform2f(Batch& batch, size_t paramOffset) { if (_pipeline._program == 0) { // We should call updatePipeline() to bind the program but we are not doing that // because these uniform setters are deprecated and we don;t want to create side effect @@ -546,7 +546,7 @@ void Batch::_glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) { DO_IT_NOW(_glUniform3f, 1); } -void GLBackend::do_glUniform3f(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glUniform3f(Batch& batch, size_t paramOffset) { if (_pipeline._program == 0) { // We should call updatePipeline() to bind the program but we are not doing that // because these uniform setters are deprecated and we don;t want to create side effect @@ -575,7 +575,7 @@ void Batch::_glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLf } -void GLBackend::do_glUniform4f(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glUniform4f(Batch& batch, size_t paramOffset) { if (_pipeline._program == 0) { // We should call updatePipeline() to bind the program but we are not doing that // because these uniform setters are deprecated and we don;t want to create side effect @@ -601,7 +601,7 @@ void Batch::_glUniform3fv(GLint location, GLsizei count, const GLfloat* value) { DO_IT_NOW(_glUniform3fv, 3); } -void GLBackend::do_glUniform3fv(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glUniform3fv(Batch& batch, size_t paramOffset) { if (_pipeline._program == 0) { // We should call updatePipeline() to bind the program but we are not doing that // because these uniform setters are deprecated and we don;t want to create side effect @@ -627,7 +627,7 @@ void Batch::_glUniform4fv(GLint location, GLsizei count, const GLfloat* value) { DO_IT_NOW(_glUniform4fv, 3); } -void GLBackend::do_glUniform4fv(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glUniform4fv(Batch& batch, size_t paramOffset) { if (_pipeline._program == 0) { // We should call updatePipeline() to bind the program but we are not doing that // because these uniform setters are deprecated and we don;t want to create side effect @@ -653,7 +653,7 @@ void Batch::_glUniform4iv(GLint location, GLsizei count, const GLint* value) { DO_IT_NOW(_glUniform4iv, 3); } -void GLBackend::do_glUniform4iv(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glUniform4iv(Batch& batch, size_t paramOffset) { if (_pipeline._program == 0) { // We should call updatePipeline() to bind the program but we are not doing that // because these uniform setters are deprecated and we don;t want to create side effect @@ -679,7 +679,7 @@ void Batch::_glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpo DO_IT_NOW(_glUniformMatrix4fv, 4); } -void GLBackend::do_glUniformMatrix4fv(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glUniformMatrix4fv(Batch& batch, size_t paramOffset) { if (_pipeline._program == 0) { // We should call updatePipeline() to bind the program but we are not doing that // because these uniform setters are deprecated and we don;t want to create side effect @@ -704,7 +704,7 @@ void Batch::_glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) DO_IT_NOW(_glColor4f, 4); } -void GLBackend::do_glColor4f(Batch& batch, uint32 paramOffset) { +void GLBackend::do_glColor4f(Batch& batch, size_t paramOffset) { glm::vec4 newColor( batch._params[paramOffset + 3]._float, @@ -720,14 +720,14 @@ void GLBackend::do_glColor4f(Batch& batch, uint32 paramOffset) { } -void GLBackend::do_pushProfileRange(Batch& batch, uint32 paramOffset) { +void GLBackend::do_pushProfileRange(Batch& batch, size_t paramOffset) { #if defined(NSIGHT_FOUND) auto name = batch._profileRanges.get(batch._params[paramOffset]._uint); nvtxRangePush(name.c_str()); #endif } -void GLBackend::do_popProfileRange(Batch& batch, uint32 paramOffset) { +void GLBackend::do_popProfileRange(Batch& batch, size_t paramOffset) { #if defined(NSIGHT_FOUND) nvtxRangePop(); #endif diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h index 9f1e17205c..f44fbe6c0d 100644 --- a/libraries/gpu/src/gpu/GLBackend.h +++ b/libraries/gpu/src/gpu/GLBackend.h @@ -195,17 +195,17 @@ public: static const int MAX_NUM_ATTRIBUTES = Stream::NUM_INPUT_SLOTS; static const int MAX_NUM_INPUT_BUFFERS = 16; - uint32 getNumInputBuffers() const { return _input._invalidBuffers.size(); } + size_t getNumInputBuffers() const { return _input._invalidBuffers.size(); } // this is the maximum per shader stage on the low end apple // TODO make it platform dependant at init time static const int MAX_NUM_UNIFORM_BUFFERS = 12; - uint32 getMaxNumUniformBuffers() const { return MAX_NUM_UNIFORM_BUFFERS; } + size_t getMaxNumUniformBuffers() const { return MAX_NUM_UNIFORM_BUFFERS; } // this is the maximum per shader stage on the low end apple // TODO make it platform dependant at init time static const int MAX_NUM_RESOURCE_TEXTURES = 16; - uint32 getMaxNumResourceTextures() const { return MAX_NUM_RESOURCE_TEXTURES; } + size_t getMaxNumResourceTextures() const { return MAX_NUM_RESOURCE_TEXTURES; } // The State setters called by the GLState::Commands when a new state is assigned void do_setStateFillMode(int32 mode); @@ -248,18 +248,18 @@ protected: Stats _stats; // Draw Stage - void do_draw(Batch& batch, uint32 paramOffset); - void do_drawIndexed(Batch& batch, uint32 paramOffset); - void do_drawInstanced(Batch& batch, uint32 paramOffset); - void do_drawIndexedInstanced(Batch& batch, uint32 paramOffset); - void do_multiDrawIndirect(Batch& batch, uint32 paramOffset); - void do_multiDrawIndexedIndirect(Batch& batch, uint32 paramOffset); + void do_draw(Batch& batch, size_t paramOffset); + void do_drawIndexed(Batch& batch, size_t paramOffset); + void do_drawInstanced(Batch& batch, size_t paramOffset); + void do_drawIndexedInstanced(Batch& batch, size_t paramOffset); + void do_multiDrawIndirect(Batch& batch, size_t paramOffset); + void do_multiDrawIndexedIndirect(Batch& batch, size_t paramOffset); // Input Stage - void do_setInputFormat(Batch& batch, uint32 paramOffset); - void do_setInputBuffer(Batch& batch, uint32 paramOffset); - void do_setIndexBuffer(Batch& batch, uint32 paramOffset); - void do_setIndirectBuffer(Batch& batch, uint32 paramOffset); + void do_setInputFormat(Batch& batch, size_t paramOffset); + void do_setInputBuffer(Batch& batch, size_t paramOffset); + void do_setIndexBuffer(Batch& batch, size_t paramOffset); + void do_setIndirectBuffer(Batch& batch, size_t paramOffset); void initInput(); void killInput(); @@ -310,11 +310,11 @@ protected: } _input; // Transform Stage - void do_setModelTransform(Batch& batch, uint32 paramOffset); - void do_setViewTransform(Batch& batch, uint32 paramOffset); - void do_setProjectionTransform(Batch& batch, uint32 paramOffset); - void do_setViewportTransform(Batch& batch, uint32 paramOffset); - void do_setDepthRangeTransform(Batch& batch, uint32 paramOffset); + void do_setModelTransform(Batch& batch, size_t paramOffset); + void do_setViewTransform(Batch& batch, size_t paramOffset); + void do_setProjectionTransform(Batch& batch, size_t paramOffset); + void do_setViewportTransform(Batch& batch, size_t paramOffset); + void do_setDepthRangeTransform(Batch& batch, size_t paramOffset); void initTransform(); void killTransform(); @@ -362,7 +362,7 @@ protected: // Uniform Stage - void do_setUniformBuffer(Batch& batch, uint32 paramOffset); + void do_setUniformBuffer(Batch& batch, size_t paramOffset); void releaseUniformBuffer(uint32_t slot); void resetUniformStage(); @@ -375,7 +375,7 @@ protected: } _uniform; // Resource Stage - void do_setResourceTexture(Batch& batch, uint32 paramOffset); + void do_setResourceTexture(Batch& batch, size_t paramOffset); void releaseResourceTexture(uint32_t slot); void resetResourceStage(); @@ -390,9 +390,9 @@ protected: size_t _commandIndex{ 0 }; // Pipeline Stage - void do_setPipeline(Batch& batch, uint32 paramOffset); - void do_setStateBlendFactor(Batch& batch, uint32 paramOffset); - void do_setStateScissorRect(Batch& batch, uint32 paramOffset); + void do_setPipeline(Batch& batch, size_t paramOffset); + void do_setStateBlendFactor(Batch& batch, size_t paramOffset); + void do_setStateScissorRect(Batch& batch, size_t paramOffset); // Standard update pipeline check that the current Program and current State or good to go for a void updatePipeline(); @@ -429,9 +429,9 @@ protected: } _pipeline; // Output stage - void do_setFramebuffer(Batch& batch, uint32 paramOffset); - void do_clearFramebuffer(Batch& batch, uint32 paramOffset); - void do_blit(Batch& batch, uint32 paramOffset); + void do_setFramebuffer(Batch& batch, size_t paramOffset); + void do_clearFramebuffer(Batch& batch, size_t paramOffset); + void do_blit(Batch& batch, size_t paramOffset); // Synchronize the state cache of this Backend with the actual real state of the GL Context void syncOutputStateCache(); @@ -446,9 +446,9 @@ protected: } _output; // Query section - void do_beginQuery(Batch& batch, uint32 paramOffset); - void do_endQuery(Batch& batch, uint32 paramOffset); - void do_getQuery(Batch& batch, uint32 paramOffset); + void do_beginQuery(Batch& batch, size_t paramOffset); + void do_endQuery(Batch& batch, size_t paramOffset); + void do_getQuery(Batch& batch, size_t paramOffset); void resetQueryStage(); struct QueryStageState { @@ -456,33 +456,33 @@ protected: }; // Reset stages - void do_resetStages(Batch& batch, uint32 paramOffset); + void do_resetStages(Batch& batch, size_t paramOffset); - void do_runLambda(Batch& batch, uint32 paramOffset); + void do_runLambda(Batch& batch, size_t paramOffset); void resetStages(); // TODO: As long as we have gl calls explicitely issued from interface // code, we need to be able to record and batch these calls. THe long // term strategy is to get rid of any GL calls in favor of the HIFI GPU API - void do_glActiveBindTexture(Batch& batch, uint32 paramOffset); + void do_glActiveBindTexture(Batch& batch, size_t paramOffset); - void do_glUniform1i(Batch& batch, uint32 paramOffset); - void do_glUniform1f(Batch& batch, uint32 paramOffset); - void do_glUniform2f(Batch& batch, uint32 paramOffset); - void do_glUniform3f(Batch& batch, uint32 paramOffset); - void do_glUniform4f(Batch& batch, uint32 paramOffset); - void do_glUniform3fv(Batch& batch, uint32 paramOffset); - void do_glUniform4fv(Batch& batch, uint32 paramOffset); - void do_glUniform4iv(Batch& batch, uint32 paramOffset); - void do_glUniformMatrix4fv(Batch& batch, uint32 paramOffset); + void do_glUniform1i(Batch& batch, size_t paramOffset); + void do_glUniform1f(Batch& batch, size_t paramOffset); + void do_glUniform2f(Batch& batch, size_t paramOffset); + void do_glUniform3f(Batch& batch, size_t paramOffset); + void do_glUniform4f(Batch& batch, size_t paramOffset); + void do_glUniform3fv(Batch& batch, size_t paramOffset); + void do_glUniform4fv(Batch& batch, size_t paramOffset); + void do_glUniform4iv(Batch& batch, size_t paramOffset); + void do_glUniformMatrix4fv(Batch& batch, size_t paramOffset); - void do_glColor4f(Batch& batch, uint32 paramOffset); + void do_glColor4f(Batch& batch, size_t paramOffset); - void do_pushProfileRange(Batch& batch, uint32 paramOffset); - void do_popProfileRange(Batch& batch, uint32 paramOffset); + void do_pushProfileRange(Batch& batch, size_t paramOffset); + void do_popProfileRange(Batch& batch, size_t paramOffset); - typedef void (GLBackend::*CommandCall)(Batch&, uint32); + typedef void (GLBackend::*CommandCall)(Batch&, size_t); static CommandCall _commandCalls[Batch::NUM_COMMANDS]; }; diff --git a/libraries/gpu/src/gpu/GLBackendBuffer.cpp b/libraries/gpu/src/gpu/GLBackendBuffer.cpp index 3eeedc5dc3..49aeeca38e 100755 --- a/libraries/gpu/src/gpu/GLBackendBuffer.cpp +++ b/libraries/gpu/src/gpu/GLBackendBuffer.cpp @@ -46,7 +46,7 @@ GLBackend::GLBuffer* GLBackend::syncGPUObject(const Buffer& buffer) { glBufferData(GL_ARRAY_BUFFER, buffer.getSysmem().getSize(), buffer.getSysmem().readData(), GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); object->_stamp = buffer.getSysmem().getStamp(); - object->_size = buffer.getSysmem().getSize(); + object->_size = (GLuint)buffer.getSysmem().getSize(); //} (void) CHECK_GL_ERROR(); diff --git a/libraries/gpu/src/gpu/GLBackendInput.cpp b/libraries/gpu/src/gpu/GLBackendInput.cpp index 5cdcf0adc6..75f4be3cbe 100755 --- a/libraries/gpu/src/gpu/GLBackendInput.cpp +++ b/libraries/gpu/src/gpu/GLBackendInput.cpp @@ -12,7 +12,7 @@ using namespace gpu; -void GLBackend::do_setInputFormat(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setInputFormat(Batch& batch, size_t paramOffset) { Stream::FormatPointer format = batch._streamFormats.get(batch._params[paramOffset]._uint); if (format != _input._format) { @@ -21,7 +21,7 @@ void GLBackend::do_setInputFormat(Batch& batch, uint32 paramOffset) { } } -void GLBackend::do_setInputBuffer(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setInputBuffer(Batch& batch, size_t paramOffset) { Offset stride = batch._params[paramOffset + 0]._uint; Offset offset = batch._params[paramOffset + 1]._uint; BufferPointer buffer = batch._buffers.get(batch._params[paramOffset + 2]._uint); @@ -232,14 +232,14 @@ void GLBackend::updateInput() { GLenum type = _elementTypeToGLType[attrib._element.getType()]; // GLenum perLocationStride = strides[bufferNum]; GLenum perLocationStride = attrib._element.getLocationSize(); - GLuint stride = strides[bufferNum]; - GLuint pointer = attrib._offset + offsets[bufferNum]; + GLuint stride = (GLuint)strides[bufferNum]; + GLuint pointer = (GLuint)(attrib._offset + offsets[bufferNum]); GLboolean isNormalized = attrib._element.isNormalized(); for (size_t locNum = 0; locNum < locationCount; ++locNum) { - glVertexAttribPointer(slot + locNum, count, type, isNormalized, stride, - reinterpret_cast(pointer + perLocationStride * locNum)); - glVertexAttribDivisor(slot + locNum, attrib._frequency); + glVertexAttribPointer(slot + (GLuint)locNum, count, type, isNormalized, stride, + reinterpret_cast(pointer + perLocationStride * (GLuint)locNum)); + glVertexAttribDivisor(slot + (GLuint)locNum, attrib._frequency); } // TODO: Support properly the IAttrib version @@ -287,7 +287,7 @@ void GLBackend::resetInputStage() { } -void GLBackend::do_setIndexBuffer(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setIndexBuffer(Batch& batch, size_t paramOffset) { _input._indexBufferType = (Type)batch._params[paramOffset + 2]._uint; _input._indexBufferOffset = batch._params[paramOffset + 0]._uint; @@ -304,7 +304,7 @@ void GLBackend::do_setIndexBuffer(Batch& batch, uint32 paramOffset) { (void) CHECK_GL_ERROR(); } -void GLBackend::do_setIndirectBuffer(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setIndirectBuffer(Batch& batch, size_t paramOffset) { _input._indirectBufferOffset = batch._params[paramOffset + 1]._uint; _input._indirectBufferStride = batch._params[paramOffset + 2]._uint; diff --git a/libraries/gpu/src/gpu/GLBackendOutput.cpp b/libraries/gpu/src/gpu/GLBackendOutput.cpp index 2bcd7e31d8..3ae8ee5435 100755 --- a/libraries/gpu/src/gpu/GLBackendOutput.cpp +++ b/libraries/gpu/src/gpu/GLBackendOutput.cpp @@ -196,7 +196,7 @@ void GLBackend::resetOutputStage() { } } -void GLBackend::do_setFramebuffer(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setFramebuffer(Batch& batch, size_t paramOffset) { auto framebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint); if (_output._framebuffer != framebuffer) { auto newFBO = getFramebufferID(framebuffer); @@ -208,7 +208,7 @@ void GLBackend::do_setFramebuffer(Batch& batch, uint32 paramOffset) { } } -void GLBackend::do_clearFramebuffer(Batch& batch, uint32 paramOffset) { +void GLBackend::do_clearFramebuffer(Batch& batch, size_t paramOffset) { if (_stereo._enable && !_pipeline._stateCache.scissorEnable) { qWarning("Clear without scissor in stereo mode"); } @@ -298,7 +298,7 @@ void GLBackend::do_clearFramebuffer(Batch& batch, uint32 paramOffset) { (void) CHECK_GL_ERROR(); } -void GLBackend::do_blit(Batch& batch, uint32 paramOffset) { +void GLBackend::do_blit(Batch& batch, size_t paramOffset) { auto srcframebuffer = batch._framebuffers.get(batch._params[paramOffset]._uint); Vec4i srcvp; for (size_t i = 0; i < 4; ++i) { diff --git a/libraries/gpu/src/gpu/GLBackendPipeline.cpp b/libraries/gpu/src/gpu/GLBackendPipeline.cpp index 8dd5242c3a..8601c7512b 100755 --- a/libraries/gpu/src/gpu/GLBackendPipeline.cpp +++ b/libraries/gpu/src/gpu/GLBackendPipeline.cpp @@ -57,7 +57,7 @@ GLBackend::GLPipeline* GLBackend::syncGPUObject(const Pipeline& pipeline) { return object; } -void GLBackend::do_setPipeline(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setPipeline(Batch& batch, size_t paramOffset) { PipelinePointer pipeline = batch._pipelines.get(batch._params[paramOffset + 0]._uint); if (_pipeline._pipeline == pipeline) { @@ -168,7 +168,7 @@ void GLBackend::resetUniformStage() { } } -void GLBackend::do_setUniformBuffer(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setUniformBuffer(Batch& batch, size_t paramOffset) { GLuint slot = batch._params[paramOffset + 3]._uint; BufferPointer uniformBuffer = batch._buffers.get(batch._params[paramOffset + 2]._uint); GLintptr rangeStart = batch._params[paramOffset + 1]._uint; @@ -237,7 +237,7 @@ void GLBackend::resetResourceStage() { } } -void GLBackend::do_setResourceTexture(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setResourceTexture(Batch& batch, size_t paramOffset) { GLuint slot = batch._params[paramOffset + 1]._uint; TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint); diff --git a/libraries/gpu/src/gpu/GLBackendQuery.cpp b/libraries/gpu/src/gpu/GLBackendQuery.cpp index 5772a09943..0a76d38963 100644 --- a/libraries/gpu/src/gpu/GLBackendQuery.cpp +++ b/libraries/gpu/src/gpu/GLBackendQuery.cpp @@ -60,7 +60,7 @@ GLuint GLBackend::getQueryID(const QueryPointer& query) { } } -void GLBackend::do_beginQuery(Batch& batch, uint32 paramOffset) { +void GLBackend::do_beginQuery(Batch& batch, size_t paramOffset) { auto query = batch._queries.get(batch._params[paramOffset]._uint); GLQuery* glquery = syncGPUObject(*query); if (glquery) { @@ -74,7 +74,7 @@ void GLBackend::do_beginQuery(Batch& batch, uint32 paramOffset) { } } -void GLBackend::do_endQuery(Batch& batch, uint32 paramOffset) { +void GLBackend::do_endQuery(Batch& batch, size_t paramOffset) { auto query = batch._queries.get(batch._params[paramOffset]._uint); GLQuery* glquery = syncGPUObject(*query); if (glquery) { @@ -88,7 +88,7 @@ void GLBackend::do_endQuery(Batch& batch, uint32 paramOffset) { } } -void GLBackend::do_getQuery(Batch& batch, uint32 paramOffset) { +void GLBackend::do_getQuery(Batch& batch, size_t paramOffset) { auto query = batch._queries.get(batch._params[paramOffset]._uint); GLQuery* glquery = syncGPUObject(*query); if (glquery) { diff --git a/libraries/gpu/src/gpu/GLBackendState.cpp b/libraries/gpu/src/gpu/GLBackendState.cpp index 895d0a0027..64bd87c876 100644 --- a/libraries/gpu/src/gpu/GLBackendState.cpp +++ b/libraries/gpu/src/gpu/GLBackendState.cpp @@ -763,7 +763,7 @@ void GLBackend::do_setStateColorWriteMask(uint32 mask) { } -void GLBackend::do_setStateBlendFactor(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setStateBlendFactor(Batch& batch, size_t paramOffset) { Vec4 factor(batch._params[paramOffset + 0]._float, batch._params[paramOffset + 1]._float, @@ -774,7 +774,7 @@ void GLBackend::do_setStateBlendFactor(Batch& batch, uint32 paramOffset) { (void) CHECK_GL_ERROR(); } -void GLBackend::do_setStateScissorRect(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setStateScissorRect(Batch& batch, size_t paramOffset) { Vec4i rect; memcpy(&rect, batch.editData(batch._params[paramOffset]._uint), sizeof(Vec4i)); diff --git a/libraries/gpu/src/gpu/GLBackendTransform.cpp b/libraries/gpu/src/gpu/GLBackendTransform.cpp index 963cab778f..686b52296f 100755 --- a/libraries/gpu/src/gpu/GLBackendTransform.cpp +++ b/libraries/gpu/src/gpu/GLBackendTransform.cpp @@ -15,22 +15,22 @@ using namespace gpu; // Transform Stage -void GLBackend::do_setModelTransform(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setModelTransform(Batch& batch, size_t paramOffset) { _transform._model = batch._transforms.get(batch._params[paramOffset]._uint); _transform._invalidModel = true; } -void GLBackend::do_setViewTransform(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setViewTransform(Batch& batch, size_t paramOffset) { _transform._view = batch._transforms.get(batch._params[paramOffset]._uint); _transform._invalidView = true; } -void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setProjectionTransform(Batch& batch, size_t paramOffset) { memcpy(&_transform._projection, batch.editData(batch._params[paramOffset]._uint), sizeof(Mat4)); _transform._invalidProj = true; } -void GLBackend::do_setViewportTransform(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setViewportTransform(Batch& batch, size_t paramOffset) { memcpy(&_transform._viewport, batch.editData(batch._params[paramOffset]._uint), sizeof(Vec4i)); ivec4& vp = _transform._viewport; @@ -49,7 +49,7 @@ void GLBackend::do_setViewportTransform(Batch& batch, uint32 paramOffset) { _transform._invalidViewport = true; } -void GLBackend::do_setDepthRangeTransform(Batch& batch, uint32 paramOffset) { +void GLBackend::do_setDepthRangeTransform(Batch& batch, size_t paramOffset) { Vec2 depthRange(batch._params[paramOffset + 0]._float, batch._params[paramOffset + 1]._float); @@ -142,7 +142,8 @@ void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const Stereo } void GLBackend::TransformStageState::transfer() const { - static QByteArray bufferData; + // FIXME not thread safe + static std::vector bufferData; if (!_cameras.empty()) { glBindBuffer(GL_UNIFORM_BUFFER, _cameraBuffer); bufferData.resize(_cameraUboSize * _cameras.size()); @@ -168,22 +169,23 @@ void GLBackend::TransformStageState::transfer() const { } void GLBackend::TransformStageState::update(size_t commandIndex, const StereoState& stereo) const { - int offset = -1; + static const size_t INVALID_OFFSET = (size_t)-1; + size_t offset = INVALID_OFFSET; while ((_objectsItr != _objectOffsets.end()) && (commandIndex >= (*_objectsItr).first)) { offset = (*_objectsItr).second; ++_objectsItr; } - if (offset >= 0) { + if (offset != INVALID_OFFSET) { glBindBufferRange(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT, _objectBuffer, offset, sizeof(Backend::TransformObject)); } - offset = -1; + offset = INVALID_OFFSET; while ((_camerasItr != _cameraOffsets.end()) && (commandIndex >= (*_camerasItr).first)) { offset = (*_camerasItr).second; ++_camerasItr; } - if (offset >= 0) { + if (offset != INVALID_OFFSET) { // We include both camera offsets for stereo if (stereo._enable && stereo._pass) { offset += _cameraUboSize; diff --git a/libraries/gpu/src/gpu/Resource.h b/libraries/gpu/src/gpu/Resource.h index 8d53d6e2e7..794ee680f4 100644 --- a/libraries/gpu/src/gpu/Resource.h +++ b/libraries/gpu/src/gpu/Resource.h @@ -26,9 +26,9 @@ namespace gpu { class Resource { public: - typedef unsigned int Size; + typedef size_t Size; - static const Size NOT_ALLOCATED = -1; + static const Size NOT_ALLOCATED = (Size)-1; // The size in bytes of data stored in the resource virtual Size getSize() const = 0; diff --git a/libraries/gpu/src/gpu/Stream.h b/libraries/gpu/src/gpu/Stream.h index 492af5f62a..4fff3b651d 100644 --- a/libraries/gpu/src/gpu/Stream.h +++ b/libraries/gpu/src/gpu/Stream.h @@ -93,19 +93,14 @@ public: }; typedef std::map< Slot, ChannelInfo > ChannelMap; - Format() : - _attributes(), - _elementTotalSize(0) {} - ~Format() {} - - uint32 getNumAttributes() const { return _attributes.size(); } + size_t getNumAttributes() const { return _attributes.size(); } const AttributeMap& getAttributes() const { return _attributes; } - uint8 getNumChannels() const { return _channels.size(); } + size_t getNumChannels() const { return _channels.size(); } const ChannelMap& getChannels() const { return _channels; } Offset getChannelStride(Slot channel) const { return _channels.at(channel)._stride; } - uint32 getElementTotalSize() const { return _elementTotalSize; } + size_t getElementTotalSize() const { return _elementTotalSize; } bool setAttribute(Slot slot, Slot channel, Element element, Offset offset = 0, Frequency frequency = PER_VERTEX); bool setAttribute(Slot slot, Frequency frequency = PER_VERTEX); @@ -115,7 +110,7 @@ public: protected: AttributeMap _attributes; ChannelMap _channels; - uint32 _elementTotalSize; + uint32 _elementTotalSize { 0 }; void evaluateCache(); }; @@ -140,7 +135,7 @@ public: const Buffers& getBuffers() const { return _buffers; } const Offsets& getOffsets() const { return _offsets; } const Strides& getStrides() const { return _strides; } - uint32 getNumBuffers() const { return _buffers.size(); } + size_t getNumBuffers() const { return _buffers.size(); } BufferStream makeRangedStream(uint32 offset, uint32 count = -1) const; From 55799403c99dffebddcf4ecafed0423d20bbcad4 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 2 Dec 2015 21:52:06 -0800 Subject: [PATCH 289/401] 64 bit support for Leap Motion on windows --- cmake/modules/FindLeapMotion.cmake | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/cmake/modules/FindLeapMotion.cmake b/cmake/modules/FindLeapMotion.cmake index eafb031a07..b5d6fe1b69 100644 --- a/cmake/modules/FindLeapMotion.cmake +++ b/cmake/modules/FindLeapMotion.cmake @@ -18,10 +18,16 @@ hifi_library_search_hints("leapmotion") find_path(LEAPMOTION_INCLUDE_DIRS Leap.h PATH_SUFFIXES include HINTS ${LEAPMOTION_SEARCH_DIRS}) if (WIN32) - find_library(LEAPMOTION_LIBRARY_DEBUG Leapd PATH_SUFFIXES lib/x86 HINTS ${LEAPMOTION_SEARCH_DIRS}) - find_library(LEAPMOTION_LIBRARY_RELEASE Leap PATH_SUFFIXES lib/x86 HINTS ${LEAPMOTION_SEARCH_DIRS}) - - find_path(LEAPMOTION_DLL_PATH Leap.dll PATH_SUFFIXES lib/x86 HINTS ${LEAPMOTION_SEARCH_DIRS}) + + if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") + set(ARCH_DIR "x64") + else() + set(ARCH_DIR "x86") + endif() + + find_library(LEAPMOTION_LIBRARY_DEBUG Leapd PATH_SUFFIXES "lib/${ARCH_DIR}" HINTS ${LEAPMOTION_SEARCH_DIRS}) + find_library(LEAPMOTION_LIBRARY_RELEASE Leap PATH_SUFFIXES "lib/${ARCH_DIR}" HINTS ${LEAPMOTION_SEARCH_DIRS}) + find_path(LEAPMOTION_DLL_PATH Leap.dll PATH_SUFFIXES "lib/${ARCH_DIR}" HINTS ${LEAPMOTION_SEARCH_DIRS}) elseif (APPLE) find_library(LEAPMOTION_LIBRARY_RELEASE Leap PATH_SUFFIXES lib HINTS ${LEAPMOTION_SEARCH_DIRS}) endif () From b122586ea5d5144661b9ad89fb7772f4ba5d85b6 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 3 Dec 2015 08:08:04 -0800 Subject: [PATCH 290/401] remove camera cycle and context menu from standard mapping --- interface/resources/controllers/standard.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json index d4988fc00d..e3f7726755 100644 --- a/interface/resources/controllers/standard.json +++ b/interface/resources/controllers/standard.json @@ -32,9 +32,6 @@ { "from": [ "Standard.A", "Standard.B", "Standard.X", "Standard.Y" ], "to": "Standard.RightPrimaryThumb" }, { "from": "Standard.Start", "to": "Standard.RightSecondaryThumb" }, - { "from": "Standard.LeftSecondaryThumb", "to": "Actions.CycleCamera" }, - { "from": "Standard.RightSecondaryThumb", "to": "Actions.ContextMenu" }, - { "from": "Standard.LT", "to": "Actions.LeftHandClick" }, { "from": "Standard.RT", "to": "Actions.RightHandClick" }, From 2d804555dec92c105bea303d13630c8b3e3740a6 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 3 Dec 2015 08:59:15 -0800 Subject: [PATCH 291/401] minor cleanups --- libraries/shared/src/SpatiallyNestable.cpp | 37 ++++++++-------------- libraries/shared/src/SpatiallyNestable.h | 2 ++ 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 9b2e809063..688ed831e3 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -40,18 +40,17 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { return nullptr; } - SpatiallyNestableConstPointer constThisPointer = shared_from_this(); - SpatiallyNestablePointer thisPointer = std::const_pointer_cast(constThisPointer); // ermahgerd !!! - if (parent && parent->getID() == _parentID) { // parent pointer is up-to-date if (!_parentKnowsMe) { - parent->beParentOfChild(thisPointer); + parent->beParentOfChild(getThisPointer()); _parentKnowsMe = true; } return parent; } + SpatiallyNestablePointer thisPointer = getThisPointer(); + if (parent) { // we have a parent pointer but our _parentID doesn't indicate this parent. parent->forgetChild(thisPointer); @@ -167,21 +166,12 @@ glm::quat SpatiallyNestable::localToWorld(glm::quat orientation, QUuid parentID, return result.getRotation(); } - glm::vec3 SpatiallyNestable::getPosition() const { - Transform parentTransformDescaled = getParentTransform(); - glm::mat4 parentMat; - parentTransformDescaled.getMatrix(parentMat); - glm::vec4 absPos = parentMat * glm::vec4(getLocalPosition(), 1.0f); - return glm::vec3(absPos); + return getTransform().getTranslation(); } glm::vec3 SpatiallyNestable::getPosition(int jointIndex) const { - Transform worldTransform = getTransform(); - Transform jointInObjectFrame = getJointTransformInObjectFrame(jointIndex); - Transform jointInWorldFrame; - Transform::mult(jointInWorldFrame, worldTransform, jointInObjectFrame); - return jointInWorldFrame.getTranslation(); + return getTransform(jointIndex).getTranslation(); } void SpatiallyNestable::setPosition(glm::vec3 position) { @@ -195,16 +185,11 @@ void SpatiallyNestable::setPosition(glm::vec3 position) { } glm::quat SpatiallyNestable::getOrientation() const { - Transform parentTransformDescaled = getParentTransform(); - return parentTransformDescaled.getRotation() * getLocalOrientation(); + return getTransform().getRotation(); } glm::quat SpatiallyNestable::getOrientation(int jointIndex) const { - Transform worldTransform = getTransform(); - Transform jointInObjectFrame = getJointTransformInObjectFrame(jointIndex); - Transform jointInWorldFrame; - Transform::mult(jointInWorldFrame, worldTransform, jointInObjectFrame); - return jointInWorldFrame.getRotation(); + return getTransform(jointIndex).getRotation(); } void SpatiallyNestable::setOrientation(glm::quat orientation) { @@ -228,7 +213,7 @@ const Transform SpatiallyNestable::getTransform() const { } const Transform SpatiallyNestable::getTransform(int jointIndex) const { - // this returns the world-space transform for this object. It find its parent's transform (which may + // this returns the world-space transform for this object. It finds its parent's transform (which may // cause this object's parent to query its parent, etc) and multiplies this object's local transform onto it. Transform worldTransform = getTransform(); Transform jointInObjectFrame = getJointTransformInObjectFrame(jointIndex); @@ -341,3 +326,9 @@ const Transform SpatiallyNestable::getJointTransformInObjectFrame(int jointIndex jointInObjectFrame.setTranslation(position); return jointInObjectFrame; } + +SpatiallyNestablePointer SpatiallyNestable::getThisPointer() const { + SpatiallyNestableConstPointer constThisPointer = shared_from_this(); + SpatiallyNestablePointer thisPointer = std::const_pointer_cast(constThisPointer); // ermahgerd !!! + return thisPointer; +} diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 6e0afa24a5..b7c04e8563 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -95,6 +95,8 @@ public: virtual glm::quat getJointRotation(int index) const = 0; virtual glm::vec3 getJointTranslation(int index) const = 0; + SpatiallyNestablePointer getThisPointer() const; + protected: NestableTypes::NestableType _nestableType; // EntityItem or an AvatarData QUuid _id; From c0bd54e8a25786d904d81648cf82d3dcc148427c Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 3 Dec 2015 09:05:26 -0800 Subject: [PATCH 292/401] change hydra secondary thumb to 0 button --- interface/resources/controllers/hydra.json | 9 ++++----- interface/resources/controllers/standard.json | 3 +++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/interface/resources/controllers/hydra.json b/interface/resources/controllers/hydra.json index b517d1bad5..0193612d27 100644 --- a/interface/resources/controllers/hydra.json +++ b/interface/resources/controllers/hydra.json @@ -13,12 +13,11 @@ { "from": "Hydra.RB", "to": "Standard.RB" }, { "from": "Hydra.RS", "to": "Standard.RS" }, - { "from": [ "Hydra.L3", "Hydra.L4" ], "to": "Standard.LeftPrimaryThumb" }, - { "from": [ "Hydra.L1", "Hydra.L2" ], "to": "Standard.LeftSecondaryThumb" }, - - { "from": [ "Hydra.R3", "Hydra.R4" ], "to": "Standard.RightPrimaryThumb" }, - { "from": [ "Hydra.R1", "Hydra.R2" ], "to": "Standard.RightSecondaryThumb" }, + { "from": [ "Hydra.L1", "Hydra.L2", "Hydra.L3", "Hydra.L4" ], "to": "Standard.LeftPrimaryThumb" }, + { "from": [ "Hydra.L0" ], "to": "Standard.LeftSecondaryThumb" }, + { "from": [ "Hydra.R1", "Hydra.R2", "Hydra.R3", "Hydra.R4" ], "to": "Standard.RightPrimaryThumb" }, + { "from": [ "Hydra.R0" ], "to": "Standard.RightSecondaryThumb" }, { "from": "Hydra.LeftHand", "to": "Standard.LeftHand" }, { "from": "Hydra.RightHand", "to": "Standard.RightHand" } diff --git a/interface/resources/controllers/standard.json b/interface/resources/controllers/standard.json index e3f7726755..d4988fc00d 100644 --- a/interface/resources/controllers/standard.json +++ b/interface/resources/controllers/standard.json @@ -32,6 +32,9 @@ { "from": [ "Standard.A", "Standard.B", "Standard.X", "Standard.Y" ], "to": "Standard.RightPrimaryThumb" }, { "from": "Standard.Start", "to": "Standard.RightSecondaryThumb" }, + { "from": "Standard.LeftSecondaryThumb", "to": "Actions.CycleCamera" }, + { "from": "Standard.RightSecondaryThumb", "to": "Actions.ContextMenu" }, + { "from": "Standard.LT", "to": "Actions.LeftHandClick" }, { "from": "Standard.RT", "to": "Actions.RightHandClick" }, From 38545237872ecb47ed7a2528c8b6ecd7cf80a52d Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 3 Dec 2015 09:17:41 -0800 Subject: [PATCH 293/401] Fixing 32 bit build breakage --- libraries/gpu/src/gpu/Batch.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 258f6d6488..da1f13151e 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -342,13 +342,17 @@ public: class Param { public: union { +#if (QT_POINTER_SIZE == 8) size_t _size; +#endif int32 _int; uint32 _uint; float _float; char _chars[sizeof(size_t)]; }; +#if (QT_POINTER_SIZE == 8) Param(size_t val) : _size(val) {} +#endif Param(int32 val) : _int(val) {} Param(uint32 val) : _uint(val) {} Param(float val) : _float(val) {} From ce882a9c112ea1eb91ae2a1a0713e60cf9a5f96d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 3 Dec 2015 09:43:36 -0800 Subject: [PATCH 294/401] Replace QSharedPointer ctor with ::create --- assignment-client/src/Agent.cpp | 2 +- interface/src/octree/OctreePacketProcessor.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 51e25dbb13..d10b0c8cfb 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -91,7 +91,7 @@ void Agent::handleOctreePacket(QSharedPointer message, SharedNo memcpy(buffer.get(), message->getRawMessage() + statsMessageLength, piggyBackedSizeWithHeader); auto newPacket = NLPacket::fromReceivedPacket(std::move(buffer), piggyBackedSizeWithHeader, message->getSenderSockAddr()); - message = QSharedPointer(new ReceivedMessage(*newPacket)); + message = QSharedPointer::create(*newPacket); } else { return; // bail since no piggyback data } diff --git a/interface/src/octree/OctreePacketProcessor.cpp b/interface/src/octree/OctreePacketProcessor.cpp index b565bdfd88..f93011a2f4 100644 --- a/interface/src/octree/OctreePacketProcessor.cpp +++ b/interface/src/octree/OctreePacketProcessor.cpp @@ -57,7 +57,7 @@ void OctreePacketProcessor::processPacket(QSharedPointer messag qDebug() << "Got piggyback, read " << piggybackBytes << " bytes"; auto newPacket = NLPacket::fromReceivedPacket(std::move(buffer), piggybackBytes, message->getSenderSockAddr()); - message = QSharedPointer(new ReceivedMessage(*newPacket.release())); + message = QSharedPointer::create(*newPacket.release()); } else { // Note... stats packets don't have sequence numbers, so we don't want to send those to trackIncomingVoxelPacket() return; // bail since no piggyback data From 667d2b728e6d7e6ce977b20831ec9399040f3c08 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 3 Dec 2015 09:52:56 -0800 Subject: [PATCH 295/401] Fix uninitialized xColor value when converting script value --- libraries/entities/src/EntityItemPropertiesMacros.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index b3299b6fe6..ca67aadbd6 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -257,7 +257,7 @@ inline glmQuat glmQuat_convertFromScriptValue(const QScriptValue& v, bool& isVal } inline xColor xColor_convertFromScriptValue(const QScriptValue& v, bool& isValid) { - xColor newValue; + xColor newValue { 255, 255, 255 }; isValid = false; /// assume it can't be converted QScriptValue r = v.property("red"); QScriptValue g = v.property("green"); From 0c05ffe9cea631efba6cc8479c3bc4bbe406593a Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 3 Dec 2015 10:20:04 -0800 Subject: [PATCH 296/401] remove coverage map and occulusion culling, since it was always disabled --- .../src/octree/OctreeQueryNode.h | 2 - .../src/octree/OctreeSendThread.cpp | 7 +- interface/src/Application.cpp | 1 - libraries/octree/src/CoverageMap.cpp | 542 ------------------ libraries/octree/src/CoverageMap.h | 120 ---- libraries/octree/src/CoverageMapV2.cpp | 251 -------- libraries/octree/src/CoverageMapV2.h | 72 --- libraries/octree/src/Octree.cpp | 101 +--- libraries/octree/src/Octree.h | 9 - libraries/octree/src/OctreeHeadlessViewer.cpp | 1 - libraries/octree/src/OctreeQuery.cpp | 2 - libraries/octree/src/OctreeQuery.h | 5 +- 12 files changed, 6 insertions(+), 1107 deletions(-) delete mode 100644 libraries/octree/src/CoverageMap.cpp delete mode 100644 libraries/octree/src/CoverageMap.h delete mode 100644 libraries/octree/src/CoverageMapV2.cpp delete mode 100644 libraries/octree/src/CoverageMapV2.h diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 0c691a06a2..75c841851f 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -14,7 +14,6 @@ #include -#include #include #include #include @@ -55,7 +54,6 @@ public: void setMaxLevelReached(int maxLevelReached) { _maxLevelReachedInLastSearch = maxLevelReached; } OctreeElementBag elementBag; - CoverageMap map; OctreeElementExtraEncodeData extraEncodeData; ViewFrustum& getCurrentViewFrustum() { return _currentViewFrustum; } diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 0a32f574de..f873ee4808 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -350,7 +350,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus if (nodeData->moveShouldDump() || nodeData->hasLodChanged()) { nodeData->dumpOutOfView(); } - nodeData->map.erase(); } if (!viewFrustumChanged && !nodeData->getWantDelta()) { @@ -451,9 +450,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus } */ - bool wantOcclusionCulling = nodeData->getWantOcclusionCulling(); - CoverageMap* coverageMap = wantOcclusionCulling ? &nodeData->map : IGNORE_COVERAGE_MAP; - float octreeSizeScale = nodeData->getOctreeSizeScale(); int boundaryLevelAdjustClient = nodeData->getBoundaryLevelAdjust(); @@ -462,7 +458,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor, WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, - wantOcclusionCulling, coverageMap, boundaryLevelAdjust, octreeSizeScale, + boundaryLevelAdjust, octreeSizeScale, nodeData->getLastTimeBagEmpty(), isFullScene, &nodeData->stats, _myServer->getJurisdiction(), &nodeData->extraEncodeData); @@ -634,7 +630,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus if (nodeData->elementBag.isEmpty()) { nodeData->updateLastKnownViewFrustum(); nodeData->setViewSent(true); - nodeData->map.erase(); // It would be nice if we could save this, and only reset it when the view frustum changes } } // end if bag wasn't empty, and so we sent stuff... diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ef10ad4464..68a809688a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3076,7 +3076,6 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node _octreeQuery.setWantLowResMoving(true); _octreeQuery.setWantColor(true); _octreeQuery.setWantDelta(true); - _octreeQuery.setWantOcclusionCulling(false); _octreeQuery.setWantCompression(true); _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); diff --git a/libraries/octree/src/CoverageMap.cpp b/libraries/octree/src/CoverageMap.cpp deleted file mode 100644 index 626d4bcf1a..0000000000 --- a/libraries/octree/src/CoverageMap.cpp +++ /dev/null @@ -1,542 +0,0 @@ -// -// CoverageMap.cpp -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 06/11/13. -// Copyright 2013 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 - -#include - -#include "OctreeLogging.h" -#include "CoverageMap.h" - -int CoverageMap::_mapCount = 0; -int CoverageMap::_checkMapRootCalls = 0; -int CoverageMap::_notAllInView = 0; -bool CoverageMap::wantDebugging = false; - -const int MAX_POLYGONS_PER_REGION = 50; - -const BoundingBox CoverageMap::ROOT_BOUNDING_BOX = BoundingBox(glm::vec2(-1.0f,-1.0f), glm::vec2(2.0f,2.0f)); - -// Coverage Map's polygon coordinates are from -1 to 1 in the following mapping to screen space. -// -// (0,0) (windowWidth, 0) -// -1,1 1,1 -// +-----------------------+ -// | | | -// | | | -// | -1,0 | | -// |-----------+-----------| -// | 0,0 | -// | | | -// | | | -// | | | -// +-----------------------+ -// -1,-1 1,-1 -// (0,windowHeight) (windowWidth,windowHeight) -// - -// Choosing a minimum sized polygon. Since we know a typical window is approximately 1500 pixels wide -// then a pixel on our screen will be ~ 2.0/1500 or 0.0013 "units" wide, similarly pixels are typically -// about that tall as well. If we say that polygons should be at least 10x10 pixels to be considered "big enough" -// then we can calculate a reasonable polygon area -const int TYPICAL_SCREEN_WIDTH_IN_PIXELS = 1500; -const int MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS = 10; -const float TYPICAL_SCREEN_PIXEL_WIDTH = (2.0f / TYPICAL_SCREEN_WIDTH_IN_PIXELS); -const float CoverageMap::MINIMUM_POLYGON_AREA_TO_STORE = (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS) * - (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS); - -CoverageMap::CoverageMap(BoundingBox boundingBox, bool isRoot, bool managePolygons) : - _isRoot(isRoot), - _myBoundingBox(boundingBox), - _managePolygons(managePolygons), - _topHalf (boundingBox.topHalf() , false, managePolygons, TOP_HALF ), - _bottomHalf (boundingBox.bottomHalf(), false, managePolygons, BOTTOM_HALF ), - _leftHalf (boundingBox.leftHalf() , false, managePolygons, LEFT_HALF ), - _rightHalf (boundingBox.rightHalf() , false, managePolygons, RIGHT_HALF ), - _remainder (boundingBox, isRoot, managePolygons, REMAINDER ) -{ - _mapCount++; - init(); -}; - -CoverageMap::~CoverageMap() { - erase(); -}; - -void CoverageMap::printStats() { - qCDebug(octree, "CoverageMap::printStats()..."); - qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f", (double)MINIMUM_POLYGON_AREA_TO_STORE); - qCDebug(octree, "_mapCount=%d",_mapCount); - qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls); - qCDebug(octree, "_notAllInView=%d",_notAllInView); - qCDebug(octree, "_maxPolygonsUsed=%d",CoverageRegion::_maxPolygonsUsed); - qCDebug(octree, "_totalPolygons=%d",CoverageRegion::_totalPolygons); - qCDebug(octree, "_occlusionTests=%d",CoverageRegion::_occlusionTests); - qCDebug(octree, "_regionSkips=%d",CoverageRegion::_regionSkips); - qCDebug(octree, "_tooSmallSkips=%d",CoverageRegion::_tooSmallSkips); - qCDebug(octree, "_regionFullSkips=%d",CoverageRegion::_regionFullSkips); - qCDebug(octree, "_outOfOrderPolygon=%d",CoverageRegion::_outOfOrderPolygon); - qCDebug(octree, "_clippedPolygons=%d",CoverageRegion::_clippedPolygons); -} - -void CoverageMap::erase() { - // tell our regions to erase() - _topHalf.erase(); - _bottomHalf.erase(); - _leftHalf.erase(); - _rightHalf.erase(); - _remainder.erase(); - - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (_childMaps[i]) { - delete _childMaps[i]; - _childMaps[i] = NULL; - } - } - - if (_isRoot && wantDebugging) { - qCDebug(octree, "CoverageMap last to be deleted..."); - printStats(); - - CoverageRegion::_maxPolygonsUsed = 0; - CoverageRegion::_totalPolygons = 0; - CoverageRegion::_occlusionTests = 0; - CoverageRegion::_regionSkips = 0; - CoverageRegion::_tooSmallSkips = 0; - CoverageRegion::_regionFullSkips = 0; - CoverageRegion::_outOfOrderPolygon = 0; - CoverageRegion::_clippedPolygons = 0; - _mapCount = 0; - _checkMapRootCalls = 0; - _notAllInView = 0; - } -} - -void CoverageMap::init() { - memset(_childMaps,0,sizeof(_childMaps)); -} - -// 0 = bottom, right -// 1 = bottom, left -// 2 = top, right -// 3 = top, left -BoundingBox CoverageMap::getChildBoundingBox(int childIndex) { - const int LEFT_BIT = 1; - const int TOP_BIT = 2; - // initialize to our corner, and half our size - BoundingBox result(_myBoundingBox.corner,_myBoundingBox.size/2.0f); - // if our "left" bit is set, then add size.x to the corner - if ((childIndex & LEFT_BIT) == LEFT_BIT) { - result.corner.x += result.size.x; - } - // if our "top" bit is set, then add size.y to the corner - if ((childIndex & TOP_BIT) == TOP_BIT) { - result.corner.y += result.size.y; - } - return result; -} - -int CoverageMap::getPolygonCount() const { - return (_topHalf.getPolygonCount() + - _bottomHalf.getPolygonCount() + - _leftHalf.getPolygonCount() + - _rightHalf.getPolygonCount() + - _remainder.getPolygonCount()); -} - -OctreeProjectedPolygon* CoverageMap::getPolygon(int index) const { - int base = 0; - if ((index - base) < _topHalf.getPolygonCount()) { - return _topHalf.getPolygon((index - base)); - } - base += _topHalf.getPolygonCount(); - - if ((index - base) < _bottomHalf.getPolygonCount()) { - return _bottomHalf.getPolygon((index - base)); - } - base += _bottomHalf.getPolygonCount(); - - if ((index - base) < _leftHalf.getPolygonCount()) { - return _leftHalf.getPolygon((index - base)); - } - base += _leftHalf.getPolygonCount(); - - if ((index - base) < _rightHalf.getPolygonCount()) { - return _rightHalf.getPolygon((index - base)); - } - base += _rightHalf.getPolygonCount(); - - if ((index - base) < _remainder.getPolygonCount()) { - return _remainder.getPolygon((index - base)); - } - return NULL; -} - - - -// possible results = STORED/NOT_STORED, OCCLUDED, DOESNT_FIT -CoverageMapStorageResult CoverageMap::checkMap(OctreeProjectedPolygon* polygon, bool storeIt) { - - if (_isRoot) { - _checkMapRootCalls++; - } - - // short circuit: we don't handle polygons that aren't all in view, so, if the polygon in question is - // not in view, then we just discard it with a DOESNT_FIT, this saves us time checking values later. - if (!polygon->getAllInView()) { - _notAllInView++; - return DOESNT_FIT; - } - - BoundingBox polygonBox(polygon->getBoundingBox()); - if (_isRoot || _myBoundingBox.contains(polygonBox)) { - - CoverageMapStorageResult result = NOT_STORED; - CoverageRegion* storeIn = &_remainder; - - // Check each half of the box independently - const bool useRegions = true; // for now we will continue to use regions - if (useRegions) { - if (_topHalf.contains(polygonBox)) { - result = _topHalf.checkRegion(polygon, polygonBox, storeIt); - storeIn = &_topHalf; - } else if (_bottomHalf.contains(polygonBox)) { - result = _bottomHalf.checkRegion(polygon, polygonBox, storeIt); - storeIn = &_bottomHalf; - } else if (_leftHalf.contains(polygonBox)) { - result = _leftHalf.checkRegion(polygon, polygonBox, storeIt); - storeIn = &_leftHalf; - } else if (_rightHalf.contains(polygonBox)) { - result = _rightHalf.checkRegion(polygon, polygonBox, storeIt); - storeIn = &_rightHalf; - } - } - - // if we got this far, there are one of two possibilities, either a polygon doesn't fit - // in one of the halves, or it did fit, but it wasn't occluded by anything only in that - // half. In either of these cases, we want to check our remainder region to see if its - // occluded by anything there - if (!(result == STORED || result == OCCLUDED)) { - result = _remainder.checkRegion(polygon, polygonBox, storeIt); - } - - // It's possible that this first set of checks might have resulted in an out of order polygon - // in which case we just return.. - if (result == STORED || result == OCCLUDED) { - - /* - if (result == STORED) - qCDebug(octree, "CoverageMap2::checkMap()... STORED\n"); - else - qCDebug(octree, "CoverageMap2::checkMap()... OCCLUDED\n"); - */ - - return result; - } - - // if we made it here, then it means the polygon being stored is not occluded - // at this level of the quad tree, so we can continue to insert it into the map. - // First we check to see if it fits in any of our sub maps - const bool useChildMaps = true; // for now we will continue to use child maps - if (useChildMaps) { - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - BoundingBox childMapBoundingBox = getChildBoundingBox(i); - if (childMapBoundingBox.contains(polygon->getBoundingBox())) { - // if no child map exists yet, then create it - if (!_childMaps[i]) { - _childMaps[i] = new CoverageMap(childMapBoundingBox, NOT_ROOT, _managePolygons); - } - result = _childMaps[i]->checkMap(polygon, storeIt); - - /* - switch (result) { - case STORED: - qCDebug(octree, "checkMap() = STORED\n"); - break; - case NOT_STORED: - qCDebug(octree, "checkMap() = NOT_STORED\n"); - break; - case OCCLUDED: - qCDebug(octree, "checkMap() = OCCLUDED\n"); - break; - default: - qCDebug(octree, "checkMap() = ????? \n"); - break; - } - */ - - return result; - } - } - } - // if we got this far, then the polygon is in our bounding box, but doesn't fit in - // any of our child bounding boxes, so we should add it here. - if (storeIt) { - if (polygon->getBoundingBox().area() > CoverageMap::MINIMUM_POLYGON_AREA_TO_STORE) { - if (storeIn->getPolygonCount() < MAX_POLYGONS_PER_REGION) { - storeIn->storeInArray(polygon); - return STORED; - } else { - CoverageRegion::_regionFullSkips++; - return NOT_STORED; - } - } else { - CoverageRegion::_tooSmallSkips++; - return NOT_STORED; - } - } else { - return NOT_STORED; - } - } - return DOESNT_FIT; -} - - -CoverageRegion::CoverageRegion(BoundingBox boundingBox, bool isRoot, bool managePolygons, RegionName regionName) : - _isRoot(isRoot), - _myBoundingBox(boundingBox), - _managePolygons(managePolygons), - _regionName(regionName) -{ - init(); -}; - -CoverageRegion::~CoverageRegion() { - erase(); -}; - -void CoverageRegion::init() { - _polygonCount = 0; - _polygonArraySize = 0; - _polygons = NULL; - _polygonDistances = NULL; - _polygonSizes = NULL; -} - - -void CoverageRegion::erase() { - -/** - if (_polygonCount) { - qCDebug(octree, "CoverageRegion::erase()...\n"); - qCDebug(octree, "_polygonCount=%d\n",_polygonCount); - _myBoundingBox.printDebugDetails(getRegionName()); - //for (int i = 0; i < _polygonCount; i++) { - // qCDebug(octree, "_polygons[%d]=",i); - // _polygons[i]->getBoundingBox().printDebugDetails(); - //} - } -**/ - // If we're in charge of managing the polygons, then clean them up first - if (_polygons && _managePolygons) { - for (int i = 0; i < _polygonCount; i++) { - delete _polygons[i]; - _polygons[i] = NULL; // do we need to do this? - } - } - - // Now, clean up our local storage - _polygonCount = 0; - _polygonArraySize = 0; - if (_polygons) { - delete[] _polygons; - _polygons = NULL; - } - if (_polygonDistances) { - delete[] _polygonDistances; - _polygonDistances = NULL; - } - if (_polygonSizes) { - delete[] _polygonSizes; - _polygonSizes = NULL; - } -} - -void CoverageRegion::growPolygonArray() { - OctreeProjectedPolygon** newPolygons = new OctreeProjectedPolygon*[_polygonArraySize + DEFAULT_GROW_SIZE]; - float* newDistances = new float[_polygonArraySize + DEFAULT_GROW_SIZE]; - float* newSizes = new float[_polygonArraySize + DEFAULT_GROW_SIZE]; - - - if (_polygons) { - memcpy(newPolygons, _polygons, sizeof(OctreeProjectedPolygon*) * _polygonCount); - delete[] _polygons; - memcpy(newDistances, _polygonDistances, sizeof(float) * _polygonCount); - delete[] _polygonDistances; - memcpy(newSizes, _polygonSizes, sizeof(float) * _polygonCount); - delete[] _polygonSizes; - } - _polygons = newPolygons; - _polygonDistances = newDistances; - _polygonSizes = newSizes; - _polygonArraySize = _polygonArraySize + DEFAULT_GROW_SIZE; -} - -const char* CoverageRegion::getRegionName() const { - switch (_regionName) { - case TOP_HALF: - return "TOP_HALF"; - case BOTTOM_HALF: - return "BOTTOM_HALF"; - case LEFT_HALF: - return "LEFT_HALF"; - case RIGHT_HALF: - return "RIGHT_HALF"; - default: - case REMAINDER: - return "REMAINDER"; - } - return "REMAINDER"; -} - -int CoverageRegion::_maxPolygonsUsed = 0; -int CoverageRegion::_totalPolygons = 0; -int CoverageRegion::_occlusionTests = 0; -int CoverageRegion::_regionSkips = 0; -int CoverageRegion::_tooSmallSkips = 0; -int CoverageRegion::_regionFullSkips = 0; -int CoverageRegion::_outOfOrderPolygon = 0; -int CoverageRegion::_clippedPolygons = 0; - - -bool CoverageRegion::mergeItemsInArray(OctreeProjectedPolygon* seed, bool seedInArray) { - for (int i = 0; i < _polygonCount; i++) { - OctreeProjectedPolygon* otherPolygon = _polygons[i]; - if (otherPolygon->canMerge(*seed)) { - otherPolygon->merge(*seed); - - if (seedInArray) { - int* IGNORED_ADDRESS = NULL; - // remove this otherOtherPolygon for our polygon array - _polygonCount = removeFromSortedArrays((void*)seed, - (void**)_polygons, _polygonDistances, IGNORED_ADDRESS, - _polygonCount, _polygonArraySize); - _totalPolygons--; - } - - // clean up - if (_managePolygons) { - delete seed; - } - - // Now run again using our newly merged polygon as the seed - mergeItemsInArray(otherPolygon, true); - - return true; - } - } - return false; -} - -// just handles storage in the array, doesn't test for occlusion or -// determining if this is the correct map to store in! -void CoverageRegion::storeInArray(OctreeProjectedPolygon* polygon) { - - _currentCoveredBounds.explandToInclude(polygon->getBoundingBox()); - - - // Before we actually store this polygon in the array, check to see if this polygon can be merged to any of the existing - // polygons already in our array. - if (mergeItemsInArray(polygon, false)) { - return; // exit early - } - - // only after we attempt to merge! - _totalPolygons++; - - if (_polygonArraySize < _polygonCount + 1) { - growPolygonArray(); - } - - // As an experiment we're going to see if we get an improvement by storing the polygons in coverage area sorted order - // this means the bigger polygons are earlier in the array. We should have a higher probability of being occluded earlier - // in the list. We still check to see if the polygon is "in front" of the target polygon before we test occlusion. Since - // sometimes things come out of order. - const bool SORT_BY_SIZE = false; - const int IGNORED = 0; - int* IGNORED_ADDRESS = NULL; - if (SORT_BY_SIZE) { - // This old code assumes that polygons will always be added in z-buffer order, but that doesn't seem to - // be a good assumption. So instead, we will need to sort this by distance. Use a binary search to find the - // insertion point in this array, and shift the array accordingly - float area = polygon->getBoundingBox().area(); - float reverseArea = 4.0f - area; - _polygonCount = insertIntoSortedArrays((void*)polygon, reverseArea, IGNORED, - (void**)_polygons, _polygonSizes, IGNORED_ADDRESS, - _polygonCount, _polygonArraySize); - } else { - _polygonCount = insertIntoSortedArrays((void*)polygon, polygon->getDistance(), IGNORED, - (void**)_polygons, _polygonDistances, IGNORED_ADDRESS, - _polygonCount, _polygonArraySize); - } - - // Debugging and Optimization Tuning code. - if (_polygonCount > _maxPolygonsUsed) { - _maxPolygonsUsed = _polygonCount; - } -} - - - -CoverageMapStorageResult CoverageRegion::checkRegion(OctreeProjectedPolygon* polygon, const BoundingBox& polygonBox, bool storeIt) { - - CoverageMapStorageResult result = DOESNT_FIT; - - if (_isRoot || _myBoundingBox.contains(polygonBox)) { - result = NOT_STORED; // if we got here, then we DO fit... - - // only actually check the polygons if this polygon is in the covered bounds for this region - if (!_currentCoveredBounds.contains(polygonBox)) { - _regionSkips += _polygonCount; - } else { - // check to make sure this polygon isn't occluded by something at this level - for (int i = 0; i < _polygonCount; i++) { - OctreeProjectedPolygon* polygonAtThisLevel = _polygons[i]; - - // Check to make sure that the polygon in question is "behind" the polygon in the list - // otherwise, we don't need to test it's occlusion (although, it means we've potentially - // added an item previously that may be occluded??? Is that possible? Maybe not, because two - // voxels can't have the exact same outline. So one occludes the other, they can't both occlude - // each other. - - _occlusionTests++; - if (polygonAtThisLevel->occludes(*polygon)) { - // if the polygonAtThisLevel is actually behind the one we're inserting, then we don't - // want to report our inserted one as occluded, but we do want to add our inserted one. - if (polygonAtThisLevel->getDistance() >= polygon->getDistance()) { - _outOfOrderPolygon++; - if (storeIt) { - if (polygon->getBoundingBox().area() > CoverageMap::MINIMUM_POLYGON_AREA_TO_STORE) { - if (getPolygonCount() < MAX_POLYGONS_PER_REGION) { - storeInArray(polygon); - return STORED; - } else { - CoverageRegion::_regionFullSkips++; - return NOT_STORED; - } - } else { - _tooSmallSkips++; - return NOT_STORED; - } - } else { - return NOT_STORED; - } - } - // this polygon is occluded by a closer polygon, so don't store it, and let the caller know - return OCCLUDED; - } - } - } - } - return result; -} diff --git a/libraries/octree/src/CoverageMap.h b/libraries/octree/src/CoverageMap.h deleted file mode 100644 index bff6bb1078..0000000000 --- a/libraries/octree/src/CoverageMap.h +++ /dev/null @@ -1,120 +0,0 @@ -// -// CoverageMap.h -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 06/11/13. -// Copyright 2013 High Fidelity, Inc. -// -// 2D CoverageMap Quad tree for storage of OctreeProjectedPolygons -// -// 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_CoverageMap_h -#define hifi_CoverageMap_h - -#include -#include "OctreeProjectedPolygon.h" - -typedef enum {STORED, OCCLUDED, DOESNT_FIT, NOT_STORED} CoverageMapStorageResult; -typedef enum {TOP_HALF, BOTTOM_HALF, LEFT_HALF, RIGHT_HALF, REMAINDER} RegionName; - -class CoverageRegion { - -public: - - CoverageRegion(BoundingBox boundingBox, bool isRoot, bool managePolygons = true, RegionName regionName = REMAINDER); - ~CoverageRegion(); - - CoverageMapStorageResult checkRegion(OctreeProjectedPolygon* polygon, const BoundingBox& polygonBox, bool storeIt); - void storeInArray(OctreeProjectedPolygon* polygon); - - bool contains(const BoundingBox& box) const { return _myBoundingBox.contains(box); }; - void erase(); // erase the coverage region - - static int _maxPolygonsUsed; - static int _totalPolygons; - static int _occlusionTests; - static int _regionSkips; - static int _tooSmallSkips; - static int _regionFullSkips; - static int _outOfOrderPolygon; - static int _clippedPolygons; - - - const char* getRegionName() const; - - int getPolygonCount() const { return _polygonCount; }; - OctreeProjectedPolygon* getPolygon(int index) const { return _polygons[index]; }; - -private: - void init(); - - bool _isRoot; // is this map the root, if so, it never returns DOESNT_FIT - BoundingBox _myBoundingBox; - BoundingBox _currentCoveredBounds; // area in this region currently covered by some polygon - bool _managePolygons; // will the coverage map delete the polygons on destruct - RegionName _regionName; - int _polygonCount; // how many polygons at this level - int _polygonArraySize; // how much room is there to store polygons at this level - OctreeProjectedPolygon** _polygons; - - // we will use one or the other of these depending on settings in the code. - float* _polygonDistances; - float* _polygonSizes; - void growPolygonArray(); - static const int DEFAULT_GROW_SIZE = 100; - - bool mergeItemsInArray(OctreeProjectedPolygon* seed, bool seedInArray); - -}; - -class CoverageMap { - -public: - static const int NUMBER_OF_CHILDREN = 4; - static const bool NOT_ROOT=false; - static const bool IS_ROOT=true; - static const BoundingBox ROOT_BOUNDING_BOX; - static const float MINIMUM_POLYGON_AREA_TO_STORE; - - CoverageMap(BoundingBox boundingBox = ROOT_BOUNDING_BOX, bool isRoot = IS_ROOT, bool managePolygons = true); - ~CoverageMap(); - - CoverageMapStorageResult checkMap(OctreeProjectedPolygon* polygon, bool storeIt = true); - - BoundingBox getChildBoundingBox(int childIndex); - - void erase(); // erase the coverage map - void printStats(); - - static bool wantDebugging; - - int getPolygonCount() const; - OctreeProjectedPolygon* getPolygon(int index) const; - CoverageMap* getChild(int childIndex) const { return _childMaps[childIndex]; }; - -private: - void init(); - - bool _isRoot; // is this map the root, if so, it never returns DOESNT_FIT - BoundingBox _myBoundingBox; - CoverageMap* _childMaps[NUMBER_OF_CHILDREN]; - bool _managePolygons; // will the coverage map delete the polygons on destruct - - // We divide the map into 5 regions representing each possible half of the map, and the whole map - // this allows us to keep the list of polygons shorter - CoverageRegion _topHalf; - CoverageRegion _bottomHalf; - CoverageRegion _leftHalf; - CoverageRegion _rightHalf; - CoverageRegion _remainder; - - static int _mapCount; - static int _checkMapRootCalls; - static int _notAllInView; -}; - - -#endif // hifi_CoverageMap_h diff --git a/libraries/octree/src/CoverageMapV2.cpp b/libraries/octree/src/CoverageMapV2.cpp deleted file mode 100644 index 8467ea1ee9..0000000000 --- a/libraries/octree/src/CoverageMapV2.cpp +++ /dev/null @@ -1,251 +0,0 @@ -// -// CoverageMapV2.cpp -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 06/11/13. -// Copyright 2013 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 - -#include - -#include - -#include "OctreeLogging.h" -#include "CoverageMapV2.h" - -int CoverageMapV2::_mapCount = 0; -int CoverageMapV2::_checkMapRootCalls = 0; -int CoverageMapV2::_notAllInView = 0; -bool CoverageMapV2::wantDebugging = false; - -const BoundingBox CoverageMapV2::ROOT_BOUNDING_BOX = BoundingBox(glm::vec2(-1.0f,-1.0f), glm::vec2(2.0f,2.0f)); - -// Coverage Map's polygon coordinates are from -1 to 1 in the following mapping to screen space. -// -// (0,0) (windowWidth, 0) -// -1,1 1,1 -// +-----------------------+ -// | | | -// | | | -// | -1,0 | | -// |-----------+-----------| -// | 0,0 | -// | | | -// | | | -// | | | -// +-----------------------+ -// -1,-1 1,-1 -// (0,windowHeight) (windowWidth,windowHeight) -// - -// Choosing a minimum sized polygon. Since we know a typical window is approximately 1500 pixels wide -// then a pixel on our screen will be ~ 2.0/1500 or 0.0013 "units" wide, similarly pixels are typically -// about that tall as well. If we say that polygons should be at least 10x10 pixels to be considered "big enough" -// then we can calculate a reasonable polygon area -const int TYPICAL_SCREEN_WIDTH_IN_PIXELS = 1500; -const int MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS = 10; -const float TYPICAL_SCREEN_PIXEL_WIDTH = (2.0f / TYPICAL_SCREEN_WIDTH_IN_PIXELS); -const float CoverageMapV2::MINIMUM_POLYGON_AREA_TO_STORE = (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS) * - (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS); -const float CoverageMapV2::NOT_COVERED = FLT_MAX; -const float CoverageMapV2::MINIMUM_OCCLUSION_CHECK_AREA = MINIMUM_POLYGON_AREA_TO_STORE/10.0f; // one quarter the size of poly - - -CoverageMapV2::CoverageMapV2(BoundingBox boundingBox, bool isRoot, bool isCovered, float coverageDistance) : - _isRoot(isRoot), - _myBoundingBox(boundingBox), - _isCovered(isCovered), - _coveredDistance(coverageDistance) -{ - _mapCount++; - init(); -}; - -CoverageMapV2::~CoverageMapV2() { - erase(); -}; - -void CoverageMapV2::erase() { - - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (_childMaps[i]) { - delete _childMaps[i]; - _childMaps[i] = NULL; - } - } - - if (_isRoot && wantDebugging) { - qCDebug(octree, "CoverageMapV2 last to be deleted..."); - qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f", (double)MINIMUM_POLYGON_AREA_TO_STORE); - qCDebug(octree, "_mapCount=%d",_mapCount); - qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls); - qCDebug(octree, "_notAllInView=%d",_notAllInView); - _mapCount = 0; - _checkMapRootCalls = 0; - _notAllInView = 0; - } -} - -void CoverageMapV2::init() { - memset(_childMaps,0,sizeof(_childMaps)); -} - -// 0 = bottom, left -// 1 = bottom, right -// 2 = top, left -// 3 = top, right -BoundingBox CoverageMapV2::getChildBoundingBox(int childIndex) { - const int RIGHT_BIT = 1; - const int TOP_BIT = 2; - // initialize to our corner, and half our size - BoundingBox result(_myBoundingBox.corner,_myBoundingBox.size/2.0f); - // if our "right" bit is set, then add size.x to the corner - if ((childIndex & RIGHT_BIT) == RIGHT_BIT) { - result.corner.x += result.size.x; - } - // if our "top" bit is set, then add size.y to the corner - if ((childIndex & TOP_BIT) == TOP_BIT) { - result.corner.y += result.size.y; - } - return result; -} - -// possible results = STORED/NOT_STORED, OCCLUDED, DOESNT_FIT -CoverageMapV2StorageResult CoverageMapV2::checkMap(const OctreeProjectedPolygon* polygon, bool storeIt) { - assert(_isRoot); // you can only call this on the root map!!! - _checkMapRootCalls++; - - // short circuit: if we're the root node (only case we're here), and we're covered, and this polygon is deeper than our - // covered depth, then this polygon is occluded! - if (_isCovered && _coveredDistance < polygon->getDistance()) { - return V2_OCCLUDED; - } - - // short circuit: we don't handle polygons that aren't all in view, so, if the polygon in question is - // not in view, then we just discard it with a DOESNT_FIT, this saves us time checking values later. - if (!polygon->getAllInView()) { - _notAllInView++; - return V2_DOESNT_FIT; - } - - // Here's where we recursively check the polygon against the coverage map. We need to maintain two pieces of state. - // The first state is: have we seen at least one "fully occluded" map items. If we haven't then we don't track the covered - // state of the polygon. - // The second piece of state is: Are all of our "fully occluded" map items "covered". If even one of these occluded map - // items is not covered, then our polygon is not covered. - bool seenOccludedMapNodes = false; - bool allOccludedMapNodesCovered = false; - - recurseMap(polygon, storeIt, seenOccludedMapNodes, allOccludedMapNodesCovered); - - // Ok, no matter how we were called, if all our occluded map nodes are covered, then we know this polygon - // is occluded, otherwise, we will report back to the caller about whether or not we stored the polygon - if (allOccludedMapNodesCovered) { - return V2_OCCLUDED; - } - if (storeIt) { - return V2_STORED; // otherwise report that we STORED it - } - return V2_NOT_STORED; // unless we weren't asked to store it, then we didn't -} - -void CoverageMapV2::recurseMap(const OctreeProjectedPolygon* polygon, bool storeIt, - bool& seenOccludedMapNodes, bool& allOccludedMapNodesCovered) { - - // if we are really small, then we act like we don't intersect, this allows us to stop - // recusing as we get to the smalles edge of the polygon - if (_myBoundingBox.area() < MINIMUM_OCCLUSION_CHECK_AREA) { - return; // stop recursion, we're done! - } - - // Determine if this map node intersects the polygon and/or is fully covered by the polygon - // There are a couple special cases: If we're the root, we are assumed to intersect with all - // polygons. Also, any map node that is fully occluded also intersects. - bool nodeIsCoveredByPolygon = polygon->occludes(_myBoundingBox); - bool nodeIsIntersectedByPolygon = nodeIsCoveredByPolygon || _isRoot || polygon->intersects(_myBoundingBox); - - // If we don't intersect, then we can just return, we're done recursing - if (!nodeIsIntersectedByPolygon) { - return; // stop recursion, we're done! - } - - // At this point, we know our node intersects with the polygon. If this node is covered, then we want to treat it - // as if the node was fully covered, because this allows us to short circuit further recursion... - if (_isCovered && _coveredDistance < polygon->getDistance()) { - nodeIsCoveredByPolygon = true; // fake it till you make it - } - - // If this node in the map is fully covered by our polygon, then we don't need to recurse any further, but - // we do need to do some bookkeeping. - if (nodeIsCoveredByPolygon) { - // If this is the very first fully covered node we've seen, then we're initialize our allOccludedMapNodesCovered - // to be our current covered state. This has the following effect: if this node isn't already covered, then by - // definition, we know that at least one node for this polygon isn't covered, and therefore we aren't fully covered. - if (!seenOccludedMapNodes) { - allOccludedMapNodesCovered = (_isCovered && _coveredDistance < polygon->getDistance()); - // We need to mark that we've seen at least one node of our polygon! ;) - seenOccludedMapNodes = true; - } else { - // If this is our second or later node of our polygon, then we need to track our allOccludedMapNodesCovered state - allOccludedMapNodesCovered = allOccludedMapNodesCovered && - (_isCovered && _coveredDistance < polygon->getDistance()); - } - - // if we're in store mode then we want to record that this node is covered. - if (storeIt) { - _isCovered = true; - // store the minimum distance of our previous known distance, or our current polygon's distance. This is because - // we know that we're at least covered at this distance, but if we had previously identified that we're covered - // at a shallower distance, then we want to maintain that distance - _coveredDistance = std::min(polygon->getDistance(), _coveredDistance); - - // Note: this might be a good chance to delete child maps, but we're not going to do that at this point because - // we're trying to maintain the known distances in the lower portion of the tree. - } - - // and since this node of the quad map is covered, we can safely stop recursion. because we know all smaller map - // nodes will also be covered. - return; - } - - // If we got here, then it means we know that this node is not fully covered by the polygon, but it does intersect - // with the polygon. - - // Another case is that we aren't yet marked as covered, and so we should recurse and process smaller quad tree nodes. - // Note: we use this to determine if we can collapse the child quad trees and mark this node as covered - bool allChildrenOccluded = true; - float maxChildCoveredDepth = NOT_COVERED; - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - BoundingBox childMapBoundingBox = getChildBoundingBox(i); - // if no child map exists yet, then create it - if (!_childMaps[i]) { - // children get created with the coverage state of their parent. - _childMaps[i] = new CoverageMapV2(childMapBoundingBox, NOT_ROOT, _isCovered, _coveredDistance); - } - - _childMaps[i]->recurseMap(polygon, storeIt, seenOccludedMapNodes, allOccludedMapNodesCovered); - - // if so far, all of our children are covered, then record our furthest coverage distance - if (allChildrenOccluded && _childMaps[i]->_isCovered) { - maxChildCoveredDepth = std::max(maxChildCoveredDepth, _childMaps[i]->_coveredDistance); - } else { - // otherwise, at least one of our children is not covered, so not all are covered - allChildrenOccluded = false; - } - } - // if all the children are covered, this makes our quad tree "shallower" because it records that - // entire quad is covered, it uses the "furthest" z-order so that if a shalower polygon comes through - // we won't assume its occluded - if (allChildrenOccluded && storeIt) { - _isCovered = true; - _coveredDistance = maxChildCoveredDepth; - } - - // normal exit case... return... -} diff --git a/libraries/octree/src/CoverageMapV2.h b/libraries/octree/src/CoverageMapV2.h deleted file mode 100644 index fc9a3ea70e..0000000000 --- a/libraries/octree/src/CoverageMapV2.h +++ /dev/null @@ -1,72 +0,0 @@ -// -// CoverageMapV2.h -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 06/11/13. -// Copyright 2013 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_CoverageMapV2_h -#define hifi_CoverageMapV2_h - -#include - -#include "OctreeProjectedPolygon.h" - -typedef enum { - V2_DOESNT_FIT, V2_STORED, V2_NOT_STORED, - V2_INTERSECT, V2_NO_INTERSECT, - V2_OCCLUDED, V2_NOT_OCCLUDED -} CoverageMapV2StorageResult; - -class CoverageMapV2 { - -public: - static const int NUMBER_OF_CHILDREN = 4; - static const bool NOT_ROOT = false; - static const bool IS_ROOT = true; - static const BoundingBox ROOT_BOUNDING_BOX; - static const float MINIMUM_POLYGON_AREA_TO_STORE; - static const float NOT_COVERED; - static const float MINIMUM_OCCLUSION_CHECK_AREA; - static bool wantDebugging; - - CoverageMapV2(BoundingBox boundingBox = ROOT_BOUNDING_BOX, bool isRoot = IS_ROOT, - bool isCovered = false, float coverageDistance = NOT_COVERED); - ~CoverageMapV2(); - - CoverageMapV2StorageResult checkMap(const OctreeProjectedPolygon* polygon, bool storeIt = true); - - BoundingBox getChildBoundingBox(int childIndex); - const BoundingBox& getBoundingBox() const { return _myBoundingBox; }; - CoverageMapV2* getChild(int childIndex) const { return _childMaps[childIndex]; }; - bool isCovered() const { return _isCovered; }; - - void erase(); // erase the coverage map - - void render(); - - -private: - void recurseMap(const OctreeProjectedPolygon* polygon, bool storeIt, - bool& seenOccludedMapNodes, bool& allOccludedMapNodesCovered); - - void init(); - - bool _isRoot; - BoundingBox _myBoundingBox; - CoverageMapV2* _childMaps[NUMBER_OF_CHILDREN]; - - bool _isCovered; - float _coveredDistance; - - static int _mapCount; - static int _checkMapRootCalls; - static int _notAllInView; -}; - - -#endif // hifi_CoverageMapV2_h diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index c02a034778..1960537ced 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -41,7 +41,6 @@ #include #include -#include "CoverageMap.h" #include "OctreeConstants.h" #include "OctreeElementBag.h" #include "Octree.h" @@ -1103,31 +1102,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, params.stopReason = EncodeBitstreamParams::NO_CHANGE; return bytesAtThisLevel; } - - // If the user also asked for occlusion culling, check if this element is occluded, but only if it's not a leaf. - // leaf occlusion is handled down below when we check child nodes - if (params.wantOcclusionCulling && !element->isLeaf()) { - OctreeProjectedPolygon* voxelPolygon = - new OctreeProjectedPolygon(params.viewFrustum->getProjectedPolygon(element->getAACube())); - - // In order to check occlusion culling, the shadow has to be "all in view" otherwise, we will ignore occlusion - // culling and proceed as normal - if (voxelPolygon->getAllInView()) { - CoverageMapStorageResult result = params.map->checkMap(voxelPolygon, false); - delete voxelPolygon; // cleanup - if (result == OCCLUDED) { - if (params.stats) { - params.stats->skippedOccluded(element); - } - params.stopReason = EncodeBitstreamParams::OCCLUDED; - return bytesAtThisLevel; - } - } else { - // If this shadow wasn't "all in view" then we ignored it for occlusion culling, but - // we do need to clean up memory and proceed as normal... - delete voxelPolygon; - } - } } bool keepDiggingDeeper = true; // Assuming we're in view we have a great work ethic, we're always ready for more! @@ -1190,20 +1164,10 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, } } - if (params.wantOcclusionCulling) { - if (childElement) { - float distance = params.viewFrustum ? childElement->distanceToCamera(*params.viewFrustum) : 0; - - currentCount = insertOctreeElementIntoSortedArrays(childElement, distance, i, - sortedChildren, (float*)&distancesToChildren, - (int*)&indexOfChildren, currentCount, NUMBER_OF_CHILDREN); - } - } else { - sortedChildren[i] = childElement; - indexOfChildren[i] = i; - distancesToChildren[i] = 0.0f; - currentCount++; - } + sortedChildren[i] = childElement; + indexOfChildren[i] = i; + distancesToChildren[i] = 0.0f; + currentCount++; // track stats // must check childElement here, because it could be we got here with no childElement @@ -1255,36 +1219,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, bool childIsOccluded = false; // assume it's not occluded - // If the user also asked for occlusion culling, check if this element is occluded - if (params.wantOcclusionCulling && childElement->isLeaf()) { - // Don't check occlusion here, just add them to our distance ordered array... - - // FIXME params.ViewFrustum is used here, but later it is checked against nullptr. - OctreeProjectedPolygon* voxelPolygon = new OctreeProjectedPolygon( - params.viewFrustum->getProjectedPolygon(childElement->getAACube())); - - // In order to check occlusion culling, the shadow has to be "all in view" otherwise, we ignore occlusion - // culling and proceed as normal - if (voxelPolygon->getAllInView()) { - CoverageMapStorageResult result = params.map->checkMap(voxelPolygon, true); - - // In all cases where the shadow wasn't stored, we need to free our own memory. - // In the case where it is stored, the CoverageMap will free memory for us later. - if (result != STORED) { - delete voxelPolygon; - } - - // If while attempting to add this voxel's shadow, we determined it was occluded, then - // we don't need to process it further and we can exit early. - if (result == OCCLUDED) { - childIsOccluded = true; - } - } else { - delete voxelPolygon; - } - } // wants occlusion culling & isLeaf() - - bool shouldRender = !params.viewFrustum ? true : childElement->calculateShouldRender(params.viewFrustum, @@ -1613,33 +1547,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, } // end if (childTreeBytesOut == 0) } // end if (oneAtBit(childrenExistInPacketBits, originalIndex)) } // end for - - // reshuffle here... - if (continueThisLevel && params.wantOcclusionCulling) { - unsigned char tempReshuffleBuffer[MAX_OCTREE_UNCOMRESSED_PACKET_SIZE]; - - unsigned char* tempBufferTo = &tempReshuffleBuffer[0]; // this is our temporary destination - - // iterate through our childrenExistInPacketBits, these will be the sections of the packet that we copied subTree - // details into. Unfortunately, they're in distance sorted order, not original index order. we need to put them - // back into original distance order - for (int originalIndex = 0; originalIndex < NUMBER_OF_CHILDREN; originalIndex++) { - if (oneAtBit(childrenExistInPacketBits, originalIndex)) { - int thisSliceSize = recursiveSliceSizes[originalIndex]; - const unsigned char* thisSliceStarts = recursiveSliceStarts[originalIndex]; - - memcpy(tempBufferTo, thisSliceStarts, thisSliceSize); - tempBufferTo += thisSliceSize; - } - } - - // now that all slices are back in the correct order, copy them to the correct output buffer - continueThisLevel = packetData->updatePriorBytes(firstRecursiveSliceOffset, &tempReshuffleBuffer[0], allSlicesSize); - if (!continueThisLevel) { - qCDebug(octree) << "WARNING UNEXPECTED CASE: Failed to update recursive slice!!!"; - qCDebug(octree) << "This is not expected!!!! -- continueThisLevel=FALSE...."; - } - } } // end keepDiggingDeeper // If we made it this far, then we've written all of our child data... if this element is the root diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 514a9b391b..5f5aa1432a 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -28,7 +28,6 @@ #include "OctreePacketData.h" #include "OctreeSceneStats.h" -class CoverageMap; class ReadBitstreamToTreeParams; class Octree; class OctreeElement; @@ -57,8 +56,6 @@ const bool NO_COLOR = false; const bool WANT_COLOR = true; const bool COLLAPSE_EMPTY_TREE = true; const bool DONT_COLLAPSE = false; -const bool NO_OCCLUSION_CULLING = false; -const bool WANT_OCCLUSION_CULLING = true; const int DONT_CHOP = 0; const int NO_BOUNDARY_ADJUST = 0; @@ -80,13 +77,11 @@ public: int chopLevels; bool deltaViewFrustum; const ViewFrustum* lastViewFrustum; - bool wantOcclusionCulling; int boundaryLevelAdjust; float octreeElementSizeScale; quint64 lastViewFrustumSent; bool forceSendScene; OctreeSceneStats* stats; - CoverageMap* map; JurisdictionMap* jurisdictionMap; OctreeElementExtraEncodeData* extraEncodeData; @@ -113,8 +108,6 @@ public: int chopLevels = 0, bool deltaViewFrustum = false, const ViewFrustum* lastViewFrustum = IGNORE_VIEW_FRUSTUM, - bool wantOcclusionCulling = NO_OCCLUSION_CULLING, - CoverageMap* map = IGNORE_COVERAGE_MAP, int boundaryLevelAdjust = NO_BOUNDARY_ADJUST, float octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE, quint64 lastViewFrustumSent = IGNORE_LAST_SENT, @@ -130,13 +123,11 @@ public: chopLevels(chopLevels), deltaViewFrustum(deltaViewFrustum), lastViewFrustum(lastViewFrustum), - wantOcclusionCulling(wantOcclusionCulling), boundaryLevelAdjust(boundaryLevelAdjust), octreeElementSizeScale(octreeElementSizeScale), lastViewFrustumSent(lastViewFrustumSent), forceSendScene(forceSendScene), stats(stats), - map(map), jurisdictionMap(jurisdictionMap), extraEncodeData(extraEncodeData), stopReason(UNKNOWN) diff --git a/libraries/octree/src/OctreeHeadlessViewer.cpp b/libraries/octree/src/OctreeHeadlessViewer.cpp index 88a77a4c53..b18f219d4d 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.cpp +++ b/libraries/octree/src/OctreeHeadlessViewer.cpp @@ -53,7 +53,6 @@ void OctreeHeadlessViewer::queryOctree() { _octreeQuery.setWantLowResMoving(true); _octreeQuery.setWantColor(true); _octreeQuery.setWantDelta(true); - _octreeQuery.setWantOcclusionCulling(false); _octreeQuery.setWantCompression(true); // TODO: should be on by default _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index e8beb0404c..2739b4a0d1 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -43,7 +43,6 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { if (_wantLowResMoving) { setAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); } if (_wantColor) { setAtBit(bitItems, WANT_COLOR_AT_BIT); } if (_wantDelta) { setAtBit(bitItems, WANT_DELTA_AT_BIT); } - if (_wantOcclusionCulling) { setAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT); } if (_wantCompression) { setAtBit(bitItems, WANT_COMPRESSION); } *destinationBuffer++ = bitItems; @@ -86,7 +85,6 @@ int OctreeQuery::parseData(NLPacket& packet) { _wantLowResMoving = oneAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); _wantColor = oneAtBit(bitItems, WANT_COLOR_AT_BIT); _wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT); - _wantOcclusionCulling = oneAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT); _wantCompression = oneAtBit(bitItems, WANT_COMPRESSION); // desired Max Octree PPS diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index 86474ffc02..9605cbfb5d 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -37,7 +37,7 @@ typedef unsigned long long quint64; const int WANT_LOW_RES_MOVING_BIT = 0; const int WANT_COLOR_AT_BIT = 1; const int WANT_DELTA_AT_BIT = 2; -const int WANT_OCCLUSION_CULLING_BIT = 3; +const int UNUSED_BIT = 3; // unused... available for new feature const int WANT_COMPRESSION = 4; // 5th bit class OctreeQuery : public NodeData { @@ -74,7 +74,6 @@ public: bool getWantColor() const { return _wantColor; } bool getWantDelta() const { return _wantDelta; } bool getWantLowResMoving() const { return _wantLowResMoving; } - bool getWantOcclusionCulling() const { return _wantOcclusionCulling; } bool getWantCompression() const { return _wantCompression; } int getMaxQueryPacketsPerSecond() const { return _maxQueryPPS; } float getOctreeSizeScale() const { return _octreeElementSizeScale; } @@ -84,7 +83,6 @@ public slots: void setWantLowResMoving(bool wantLowResMoving) { _wantLowResMoving = wantLowResMoving; } void setWantColor(bool wantColor) { _wantColor = wantColor; } void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; } - void setWantOcclusionCulling(bool wantOcclusionCulling) { _wantOcclusionCulling = wantOcclusionCulling; } void setWantCompression(bool wantCompression) { _wantCompression = wantCompression; } void setMaxQueryPacketsPerSecond(int maxQueryPPS) { _maxQueryPPS = maxQueryPPS; } void setOctreeSizeScale(float octreeSizeScale) { _octreeElementSizeScale = octreeSizeScale; } @@ -104,7 +102,6 @@ protected: bool _wantColor = true; bool _wantDelta = true; bool _wantLowResMoving = true; - bool _wantOcclusionCulling = false; bool _wantCompression = false; int _maxQueryPPS = DEFAULT_MAX_OCTREE_PPS; float _octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE; /// used for LOD calculations From 2cea593fbdaa4cb2f673cfed9b82d60372d5e556 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 3 Dec 2015 10:20:40 -0800 Subject: [PATCH 297/401] Remove RealSense & MIDI --- cmake/modules/FindRSSDK.cmake | 33 ---- cmake/modules/FindRtMidi.cmake | 30 --- interface/CMakeLists.txt | 9 +- interface/external/rssdk/readme.txt | 9 - interface/external/rtmidi/readme.txt | 43 ----- interface/src/Application.cpp | 14 -- interface/src/Menu.cpp | 7 - interface/src/Menu.h | 1 - interface/src/devices/MIDIManager.cpp | 73 -------- interface/src/devices/MIDIManager.h | 58 ------ interface/src/devices/RealSense.cpp | 259 -------------------------- interface/src/devices/RealSense.h | 65 ------- 12 files changed, 1 insertion(+), 600 deletions(-) delete mode 100644 cmake/modules/FindRSSDK.cmake delete mode 100644 cmake/modules/FindRtMidi.cmake delete mode 100644 interface/external/rssdk/readme.txt delete mode 100644 interface/external/rtmidi/readme.txt delete mode 100644 interface/src/devices/MIDIManager.cpp delete mode 100644 interface/src/devices/MIDIManager.h delete mode 100644 interface/src/devices/RealSense.cpp delete mode 100644 interface/src/devices/RealSense.h diff --git a/cmake/modules/FindRSSDK.cmake b/cmake/modules/FindRSSDK.cmake deleted file mode 100644 index c31b0efcd9..0000000000 --- a/cmake/modules/FindRSSDK.cmake +++ /dev/null @@ -1,33 +0,0 @@ -# Try to find the RSSDK library -# -# You must provide a RSSDK_ROOT_DIR which contains lib and include directories -# -# Once done this will define -# -# RSSDK_FOUND - system found RSSDK -# RSSDK_INCLUDE_DIRS - the RSSDK include directory -# RSSDK_LIBRARIES - Link this to use RSSDK -# -# Created on 12/7/2014 by Thijs Wenker -# Copyright (c) 2014 High Fidelity -# - -include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") -hifi_library_search_hints("rssdk") - -find_path(RSSDK_INCLUDE_DIRS pxcbase.h PATH_SUFFIXES include HINTS ${RSSDK_SEARCH_DIRS}) - -if (WIN32) - find_library(RSSDK_LIBRARY_DEBUG libpxc_d PATH_SUFFIXES lib/Win32 HINTS ${RSSDK_SEARCH_DIRS}) - find_library(RSSDK_LIBRARY_RELEASE libpxc PATH_SUFFIXES lib/Win32 HINTS ${RSSDK_SEARCH_DIRS}) -endif () - -include(SelectLibraryConfigurations) -select_library_configurations(RSSDK) - -set(RSSDK_LIBRARIES "${RSSDK_LIBRARY}") - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(RSSDK DEFAULT_MSG RSSDK_INCLUDE_DIRS RSSDK_LIBRARIES) - -mark_as_advanced(RSSDK_INCLUDE_DIRS RSSDK_LIBRARIES RSSDK_SEARCH_DIRS) diff --git a/cmake/modules/FindRtMidi.cmake b/cmake/modules/FindRtMidi.cmake deleted file mode 100644 index 213c990b52..0000000000 --- a/cmake/modules/FindRtMidi.cmake +++ /dev/null @@ -1,30 +0,0 @@ -# -# FindRtMidi.cmake -# -# Try to find the RtMidi library -# -# You can provide a RTMIDI_ROOT_DIR which contains lib and include directories -# -# Once done this will define -# -# RTMIDI_FOUND - system found RtMidi -# RTMIDI_INCLUDE_DIRS - the RtMidi include directory -# RTMIDI_LIBRARIES - link to this to use RtMidi -# -# Created on 6/30/2014 by Stephen Birarda -# 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("${MACRO_DIR}/HifiLibrarySearchHints.cmake") -hifi_library_search_hints("rtmidi") - -find_path(RTMIDI_INCLUDE_DIRS RtMidi.h PATH_SUFFIXES include HINTS ${RTMIDI_SEARCH_DIRS}) -find_library(RTMIDI_LIBRARIES NAMES rtmidi PATH_SUFFIXES lib HINTS ${RTMIDI_SEARCH_DIRS}) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(RtMidi DEFAULT_MSG RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES) - -mark_as_advanced(RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES RTMIDI_SEARCH_DIRS) \ No newline at end of file diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 67ce3f3df8..573fc1ce1e 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -2,7 +2,7 @@ set(TARGET_NAME interface) project(${TARGET_NAME}) # set a default root dir for each of our optional externals if it was not passed -set(OPTIONAL_EXTERNALS "LeapMotion" "RtMidi" "RSSDK") +set(OPTIONAL_EXTERNALS "LeapMotion") if(WIN32) list(APPEND OPTIONAL_EXTERNALS "3DConnexionClient") @@ -161,13 +161,6 @@ foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) endif () endforeach() -# special OS X modifications for RtMidi library -if (RTMIDI_FOUND AND NOT DISABLE_RTMIDI AND APPLE) - find_library(CoreMIDI CoreMIDI) - add_definitions(-D__MACOSX_CORE__) - target_link_libraries(${TARGET_NAME} ${CoreMIDI}) -endif () - # include headers for interface and InterfaceConfig. include_directories("${PROJECT_SOURCE_DIR}/src") diff --git a/interface/external/rssdk/readme.txt b/interface/external/rssdk/readme.txt deleted file mode 100644 index fe2246e32a..0000000000 --- a/interface/external/rssdk/readme.txt +++ /dev/null @@ -1,9 +0,0 @@ - -Instructions for adding the Intel Realsense (RSSDK) to Interface -Thijs Wenker, December 19, 2014 - -This is Windows only for now. - -1. Download the SDK at https://software.intel.com/en-us/intel-realsense-sdk/download - -2. Copy the `lib` and `include` folder inside this directory \ No newline at end of file diff --git a/interface/external/rtmidi/readme.txt b/interface/external/rtmidi/readme.txt deleted file mode 100644 index 3b9d6603a9..0000000000 --- a/interface/external/rtmidi/readme.txt +++ /dev/null @@ -1,43 +0,0 @@ - -Instructions for adding the RtMidi library to Interface -Stephen Birarda, June 30, 2014 - -1. Download the RtMidi tarball from High Fidelity S3. - http://public.highfidelity.io/dependencies/rtmidi-2.1.0.tar.gz - -2. Copy RtMidi.h to externals/rtmidi/include. - -3. Compile the RtMidi library. - -3. Copy either librtmidi.dylib (dynamic) or librtmidi.a (static) to externals/rtmidi/lib - -4. Delete your build directory, run cmake and build, and you should be all set. - -========================= - -RtMidi: realtime MIDI i/o C++ classes
-Copyright (c) 2003-2014 Gary P. Scavone - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation files -(the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of the Software, -and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -Any person wishing to distribute modifications to the Software is -asked to send the modifications to the original developer so that -they can be incorporated into the canonical version. This is, -however, not a binding provision of this license. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR -ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF -CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ef10ad4464..0c913bfaef 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -110,8 +110,6 @@ #include "devices/EyeTracker.h" #include "devices/Faceshift.h" #include "devices/Leapmotion.h" -#include "devices/MIDIManager.h" -#include "devices/RealSense.h" #include "DiscoverabilityManager.h" #include "GLCanvas.h" #include "InterfaceActionFactory.h" @@ -719,12 +717,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : // set the local loopback interface for local sounds from audio scripts AudioScriptingInterface::getInstance().setLocalAudioInterface(audioIO.data()); -#ifdef HAVE_RTMIDI - // setup the MIDIManager - MIDIManager& midiManagerInstance = MIDIManager::getInstance(); - midiManagerInstance.openDefaultPort(); -#endif - this->installEventFilter(this); // initialize our face trackers after loading the menu settings @@ -970,7 +962,6 @@ Application::~Application() { nodeThread->wait(); Leapmotion::destroy(); - RealSense::destroy(); #if 0 ConnexionClient::getInstance().destroy(); @@ -2519,7 +2510,6 @@ void Application::init() { qCDebug(interfaceapp) << "Loaded settings"; Leapmotion::init(); - RealSense::init(); // fire off an immediate domain-server check in now that settings are loaded DependencyManager::get()->sendDomainServerCheckIn(); @@ -4069,10 +4059,6 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("Scene", DependencyManager::get().data()); scriptEngine->registerGlobalObject("ScriptDiscoveryService", this->getRunningScriptsWidget()); - -#ifdef HAVE_RTMIDI - scriptEngine->registerGlobalObject("MIDI", &MIDIManager::getInstance()); -#endif } bool Application::canAcceptURL(const QString& urlString) { diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d0c8b502c5..48204464fc 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -29,7 +29,6 @@ #include "avatar/AvatarManager.h" #include "devices/DdeFaceTracker.h" #include "devices/Faceshift.h" -#include "devices/RealSense.h" #include "input-plugins/SpacemouseManager.h" #include "MainWindow.h" #include "scripting/MenuScriptingInterface.h" @@ -462,12 +461,6 @@ Menu::Menu() { MenuWrapper* leapOptionsMenu = handOptionsMenu->addMenu("Leap Motion"); addCheckableActionToQMenuAndActionHash(leapOptionsMenu, MenuOption::LeapMotionOnHMD, 0, false); -#ifdef HAVE_RSSDK - MenuWrapper* realSenseOptionsMenu = handOptionsMenu->addMenu("RealSense"); - addActionToQMenuAndActionHash(realSenseOptionsMenu, MenuOption::LoadRSSDKFile, 0, - RealSense::getInstance(), SLOT(loadRSSDKFile())); -#endif - MenuWrapper* networkMenu = developerMenu->addMenu("Network"); addActionToQMenuAndActionHash(networkMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches())); addCheckableActionToQMenuAndActionHash(networkMenu, MenuOption::DisableNackPackets, 0, false, diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 6b51987479..a30c5d434b 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -211,7 +211,6 @@ namespace MenuOption { const QString LeapMotionOnHMD = "Leap Motion on HMD"; const QString LoadScript = "Open and Run Script File..."; const QString LoadScriptURL = "Open and Run Script from URL..."; - const QString LoadRSSDKFile = "Load .rssdk file"; const QString LodTools = "LOD Tools"; const QString Login = "Login"; const QString Log = "Log"; diff --git a/interface/src/devices/MIDIManager.cpp b/interface/src/devices/MIDIManager.cpp deleted file mode 100644 index a21f5d49f5..0000000000 --- a/interface/src/devices/MIDIManager.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// -// MIDIManager.cpp -// -// -// Created by Stephen Birarda on 2014-06-30. -// 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 "InterfaceLogging.h" -#include "MIDIManager.h" - -MIDIManager& MIDIManager::getInstance() { - static MIDIManager sharedInstance; - return sharedInstance; -} - -void MIDIManager::midiCallback(double deltaTime, std::vector* message, void* userData) { -#ifdef HAVE_RTMIDI - - MIDIEvent callbackEvent; - callbackEvent.deltaTime = deltaTime; - - callbackEvent.type = message->at(0); - - if (message->size() > 1) { - callbackEvent.data1 = message->at(1); - } - - if (message->size() > 2) { - callbackEvent.data2 = message->at(2); - } - - emit getInstance().midiEvent(callbackEvent); -#endif -} - -MIDIManager::~MIDIManager() { -#ifdef HAVE_RTMIDI - delete _midiInput; -#endif -} - -#ifdef HAVE_RTMIDI -const int DEFAULT_MIDI_PORT = 0; -#endif - -void MIDIManager::openDefaultPort() { -#ifdef HAVE_RTMIDI - if (!_midiInput) { - _midiInput = new RtMidiIn(); - - if (_midiInput->getPortCount() > 0) { - qCDebug(interfaceapp) << "MIDIManager opening port" << DEFAULT_MIDI_PORT; - - _midiInput->openPort(DEFAULT_MIDI_PORT); - - // don't ignore sysex, timing, or active sensing messages - _midiInput->ignoreTypes(false, false, false); - - _midiInput->setCallback(&MIDIManager::midiCallback); - } else { - qCDebug(interfaceapp) << "MIDIManager openDefaultPort called but there are no ports available."; - delete _midiInput; - _midiInput = NULL; - } - } -#endif -} diff --git a/interface/src/devices/MIDIManager.h b/interface/src/devices/MIDIManager.h deleted file mode 100644 index 9fc55d11da..0000000000 --- a/interface/src/devices/MIDIManager.h +++ /dev/null @@ -1,58 +0,0 @@ -// -// MIDIManager.h -// interface/src/devices -// -// Created by Stephen Birarda on 2014-06-30. -// 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_MIDIManager_h -#define hifi_MIDIManager_h - -#include -#include - -#include - -#ifdef HAVE_RTMIDI -#include -#endif - -class MIDIManager : public QObject { - Q_OBJECT - - Q_PROPERTY(unsigned int NoteOn READ NoteOn) - Q_PROPERTY(unsigned int NoteOff READ NoteOff) - Q_PROPERTY(unsigned int ModWheel READ ModWheel) - Q_PROPERTY(unsigned int PitchWheel READ PitchWheel) - -public: - static MIDIManager& getInstance(); - static void midiCallback(double deltaTime, std::vector* message, void* userData); - - ~MIDIManager(); - - void openDefaultPort(); -#ifdef HAVE_RTMIDI - bool hasDevice() const { return !!_midiInput; } -#endif -public slots: - unsigned int NoteOn() const { return 144; } - unsigned int NoteOff() const { return 128; } - unsigned int ModWheel() const { return 176; } - unsigned int PitchWheel() const { return 224; } -signals: - void midiEvent(const MIDIEvent& event); - -private: -#ifdef HAVE_RTMIDI - RtMidiIn* _midiInput; -#endif -}; - - -#endif // hifi_MIDIManager_h - diff --git a/interface/src/devices/RealSense.cpp b/interface/src/devices/RealSense.cpp deleted file mode 100644 index ce28e40f2b..0000000000 --- a/interface/src/devices/RealSense.cpp +++ /dev/null @@ -1,259 +0,0 @@ -// -// RealSense.cpp -// interface/src/devices -// -// Created by Thijs Wenker on 12/10/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 "Application.h" -#include "RealSense.h" -#include "MainWindow.h" -#include "Menu.h" -#include "SharedUtil.h" - -#ifdef HAVE_RSSDK -const int PALMROOT_NUM_JOINTS = 3; -const int FINGER_NUM_JOINTS = 4; -#endif // HAVE_RSSDK - -const DeviceTracker::Name RealSense::NAME = "RealSense"; - -// find the index of a joint from -// the side: true = right -// the finger & the bone: -// finger in [0..4] : bone in [0..3] a finger phalange -// [-1] up the hand branch : bone in [0..1] <=> [ hand, forearm] -MotionTracker::Index evalRealSenseJointIndex(bool isRightSide, int finger, int bone) { -#ifdef HAVE_RSSDK - MotionTracker::Index offset = 1 // start after root - + (int(isRightSide) * PXCHandData::NUMBER_OF_JOINTS) // then offset for side - + PALMROOT_NUM_JOINTS; // then add the arm/forearm/hand chain - if (finger >= 0) { - // from there go down in the correct finger and bone - return offset + (finger * FINGER_NUM_JOINTS) + bone; - } else { - // or go back up for the correct root bone - return offset - 1 - bone; - } -#else - return -1; -#endif // HAVE_RSSDK -} - -// static -void RealSense::init() { - DeviceTracker* device = DeviceTracker::getDevice(NAME); - if (!device) { - // create a new RealSense and register it - RealSense* realSense = new RealSense(); - DeviceTracker::registerDevice(NAME, realSense); - } -} - -// static -void RealSense::destroy() { - DeviceTracker::destroyDevice(NAME); -} - -// static -RealSense* RealSense::getInstance() { - DeviceTracker* device = DeviceTracker::getDevice(NAME); - if (!device) { - // create a new RealSense and register it - RealSense* realSense = new RealSense(); - DeviceTracker::registerDevice(NAME, realSense); - } - return dynamic_cast< RealSense* > (device); -} - -RealSense::RealSense() : - MotionTracker(), - _active(false) -{ -#ifdef HAVE_RSSDK - _handData = NULL; - _session = PXCSession_Create(); - initSession(false, NULL); - - // Create the RealSense joint hierarchy - std::vector< Semantic > sides; - sides.push_back("joint_L_"); - sides.push_back("joint_R_"); - - std::vector< Semantic > rootBones; - rootBones.push_back("wrist"); - rootBones.push_back("hand"); - - std::vector< Semantic > fingers; - fingers.push_back("thumb"); - fingers.push_back("index"); - fingers.push_back("middle"); - fingers.push_back("ring"); - fingers.push_back("pinky"); - - std::vector< Semantic > fingerBones; - fingerBones.push_back("1"); - fingerBones.push_back("2"); - fingerBones.push_back("3"); - fingerBones.push_back("4"); - - std::vector< Index > palms; - for (unsigned int s = 0; s < sides.size(); s++) { - Index rootJoint = 0; - for (unsigned int rb = 0; rb < rootBones.size(); rb++) { - rootJoint = addJoint(sides[s] + rootBones[rb], rootJoint); - } - - // capture the hand index for debug - palms.push_back(rootJoint); - - for (unsigned int f = 0; f < fingers.size(); f++) { - for (unsigned int b = 0; b < fingerBones.size(); b++) { - rootJoint = addJoint(sides[s] + fingers[f] + fingerBones[b], rootJoint); - } - } - } -#endif // HAVE_RSSDK -} - -RealSense::~RealSense() { -#ifdef HAVE_RSSDK - _manager->Release(); -#endif // HAVE_RSSDK -} - -void RealSense::initSession(bool playback, QString filename) { -#ifdef HAVE_RSSDK - _active = false; - _properlyInitialized = false; - if (_handData != NULL) { - _handData->Release(); - _handController->Release(); - _session->Release(); - _config->Release(); - } - _manager = _session->CreateSenseManager(); - if (playback) { - _manager->QueryCaptureManager()->SetFileName(filename.toStdWString().c_str(), false); - } - _manager->QueryCaptureManager()->SetRealtime(!playback); - _manager->EnableHand(0); - _handController = _manager->QueryHand(); - - if (_manager->Init() == PXC_STATUS_NO_ERROR) { - _handData = _handController->CreateOutput(); - - PXCCapture::Device *device = _manager->QueryCaptureManager()->QueryDevice(); - PXCCapture::DeviceInfo dinfo; - _manager->QueryCaptureManager()->QueryDevice()->QueryDeviceInfo(&dinfo); - if (dinfo.model == PXCCapture::DEVICE_MODEL_IVCAM) - { - device->SetDepthConfidenceThreshold(1); - device->SetMirrorMode(PXCCapture::Device::MIRROR_MODE_DISABLED); - device->SetIVCAMFilterOption(6); - } - _properlyInitialized = true; - } - - _config = _handController->CreateActiveConfiguration(); - _config->EnableStabilizer(true); - _config->SetTrackingMode(PXCHandData::TRACKING_MODE_FULL_HAND); - _config->ApplyChanges(); -#endif // HAVE_RSSDK -} - -#ifdef HAVE_RSSDK -glm::quat quatFromPXCPoint4DF32(const PXCPoint4DF32& basis) { - return glm::normalize(glm::quat(basis.w, basis.x, basis.y, basis.z) * glm::quat(glm::vec3(0, M_PI, 0))); -} - -glm::vec3 vec3FromPXCPoint3DF32(const PXCPoint3DF32& vec) { - return glm::vec3(-vec.x, vec.y, -vec.z); -} -#endif // HAVE_RSSDK - -void RealSense::update() { -#ifdef HAVE_RSSDK - bool wasActive = _active; - _active = _manager->IsConnected() && _properlyInitialized; - if (_active || wasActive) { - // Go through all the joints and increment their counter since last update. - // Increment all counters once after controller first becomes inactive so that each joint reports itself as inactive. - // TODO C++11 for (auto jointIt = _jointsArray.begin(); jointIt != _jointsArray.end(); jointIt++) { - for (JointTracker::Vector::iterator jointIt = _jointsArray.begin(); jointIt != _jointsArray.end(); jointIt++) { - (*jointIt).tickNewFrame(); - } - } - - if (!_active) { - return; - } - - pxcStatus sts = _manager->AcquireFrame(true); - _handData->Update(); - PXCHandData::JointData nodes[2][PXCHandData::NUMBER_OF_JOINTS] = {}; - PXCHandData::ExtremityData extremitiesPointsNodes[2][PXCHandData::NUMBER_OF_EXTREMITIES] = {}; - for (pxcI32 i = 0; i < _handData->QueryNumberOfHands(); i++) { - PXCHandData::IHand* handData; - if (_handData->QueryHandData(PXCHandData::ACCESS_ORDER_BY_TIME, i, handData) == PXC_STATUS_NO_ERROR) { - int rightSide = handData->QueryBodySide() == PXCHandData::BODY_SIDE_RIGHT; - PXCHandData::JointData jointData; - JointTracker* parentJointTracker = _jointsArray.data(); - //Iterate Joints - int rootBranchIndex = -1; - JointTracker* palmJoint = NULL; - for (int j = 0; j < PXCHandData::NUMBER_OF_JOINTS; j++) { - handData->QueryTrackedJoint((PXCHandData::JointType)j, jointData); - nodes[i][j] = jointData; - if (j == PXCHandData::JOINT_WRIST) { - JointTracker* wrist = editJointTracker(evalRealSenseJointIndex(rightSide, rootBranchIndex, 1)); // 1 is the index of the wrist joint - wrist->editAbsFrame().setTranslation(vec3FromPXCPoint3DF32(jointData.positionWorld)); - wrist->editAbsFrame().setRotation(quatFromPXCPoint4DF32(jointData.globalOrientation)); - wrist->updateLocFromAbsTransform(parentJointTracker); - wrist->activeFrame(); - parentJointTracker = wrist; - continue; - } else if (j == PXCHandData::JOINT_CENTER) { - palmJoint = editJointTracker(evalRealSenseJointIndex(rightSide, rootBranchIndex, 0)); // 0 is the index of the palm joint - palmJoint->editAbsFrame().setTranslation(vec3FromPXCPoint3DF32(jointData.positionWorld)); - palmJoint->editAbsFrame().setRotation(quatFromPXCPoint4DF32(jointData.globalOrientation)); - palmJoint->updateLocFromAbsTransform(parentJointTracker); - palmJoint->activeFrame(); - parentJointTracker = palmJoint; - continue; - } - int finger_index = j - PALMROOT_NUM_JOINTS; - int finger = finger_index / FINGER_NUM_JOINTS; - int finger_bone = finger_index % FINGER_NUM_JOINTS; - JointTracker* ljointTracker = editJointTracker(evalRealSenseJointIndex(rightSide, finger, finger_bone)); - if (jointData.confidence > 0) { - ljointTracker->editAbsFrame().setTranslation(vec3FromPXCPoint3DF32(jointData.positionWorld)); - ljointTracker->editAbsFrame().setRotation(quatFromPXCPoint4DF32(jointData.globalOrientation)); - ljointTracker->updateLocFromAbsTransform(parentJointTracker); - ljointTracker->activeFrame(); - } - if (finger_bone == (FINGER_NUM_JOINTS - 1)) { - parentJointTracker = palmJoint; - continue; - } - parentJointTracker = ljointTracker; - } - } - } - _manager->ReleaseFrame(); -#endif // HAVE_RSSDK -} - -void RealSense::loadRSSDKFile() { - QString locationDir(QStandardPaths::displayName(QStandardPaths::DesktopLocation)); - QString fileNameString = QFileDialog::getOpenFileName(qApp->getWindow(), tr("Open RSSDK clip"), - locationDir, - tr("RSSDK Recordings (*.rssdk)")); - if (!fileNameString.isEmpty()) { - initSession(true, fileNameString); - } -} diff --git a/interface/src/devices/RealSense.h b/interface/src/devices/RealSense.h deleted file mode 100644 index c958ab1e53..0000000000 --- a/interface/src/devices/RealSense.h +++ /dev/null @@ -1,65 +0,0 @@ -// -// RealSense.h -// interface/src/devices -// -// Created by Thijs Wenker on 12/10/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_RealSense_h -#define hifi_RealSense_h - -#include - -#include "MotionTracker.h" - -#ifdef HAVE_RSSDK -#include -#include -#include -#include -#include -#endif - -/// Handles interaction with the RealSense skeleton tracking suit. -class RealSense : public QObject, public MotionTracker { - Q_OBJECT - -public: - static const Name NAME; - - static void init(); - static void destroy(); - - /// RealSense MotionTracker factory - static RealSense* getInstance(); - - bool isActive() const { return _active; } - - virtual void update(); - -public slots: - void loadRSSDKFile(); - -protected: - RealSense(); - virtual ~RealSense(); - - void initSession(bool playback, QString filename); - -private: -#ifdef HAVE_RSSDK - PXCSession* _session; - PXCSenseManager* _manager; - PXCHandModule* _handController; - PXCHandData* _handData; - PXCHandConfiguration* _config; -#endif - bool _properlyInitialized; - bool _active; -}; - -#endif // hifi_RealSense_h From 6f79b381f96abf39682d985e1a67370e4dbef4cb Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 3 Dec 2015 11:00:06 -0800 Subject: [PATCH 298/401] working toward making children of avatar joints work --- libraries/entities/src/EntityItem.cpp | 77 +++------------------- libraries/entities/src/EntityItem.h | 15 ++--- libraries/shared/src/SpatiallyNestable.cpp | 41 +++++++++++- libraries/shared/src/SpatiallyNestable.h | 9 ++- 4 files changed, 59 insertions(+), 83 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index f169554a2c..e286275fed 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1319,9 +1319,6 @@ void EntityItem::updatePosition(const glm::vec3& value) { } if (getLocalPosition() != value) { setLocalPosition(value); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->_dirtyFlags |= Simulation::DIRTY_POSITION; - }); } } @@ -1337,10 +1334,12 @@ void EntityItem::updateRotation(const glm::quat& rotation) { return; } if (getLocalOrientation() != rotation) { - setLocalRotation(rotation); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->_dirtyFlags |= Simulation::DIRTY_ROTATION; - if (this->getID() != entity->getID()) { + setLocalOrientation(rotation); + _dirtyFlags |= Simulation::DIRTY_ROTATION; + forEachDescendant([&](SpatiallyNestablePointer object) { + if (object->getNestableType() == NestableTypes::Entity) { + EntityItemPointer entity = std::static_pointer_cast(object); + entity->_dirtyFlags |= Simulation::DIRTY_ROTATION; entity->_dirtyFlags |= Simulation::DIRTY_POSITION; } }); @@ -1838,65 +1837,7 @@ QList EntityItem::getActionsOfType(EntityActionType typeToG return result; } -void EntityItem::forSelfAndEachChildEntity(std::function actor) { - QQueue toProcess; - toProcess.enqueue(shared_from_this()); - - while (!toProcess.empty()) { - EntityItemPointer entity = std::static_pointer_cast(toProcess.dequeue()); - actor(entity); - foreach (SpatiallyNestablePointer child, entity->getChildren()) { - if (child && child->getNestableType() == NestableTypes::Entity) { - toProcess.enqueue(child); - } - } - } -} - -void EntityItem::parentChanged() { - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - -void EntityItem::setTransform(const Transform transform) { - SpatiallyNestable::setTransform(transform); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - -void EntityItem::setLocalTransform(const Transform transform) { - SpatiallyNestable::setLocalTransform(transform); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - -void EntityItem::setPosition(const glm::vec3 position) { - SpatiallyNestable::setPosition(position); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - -void EntityItem::setLocalPosition(const glm::vec3 position) { - SpatiallyNestable::setLocalPosition(position); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - -void EntityItem::setRotation(const glm::quat orientation) { - SpatiallyNestable::setOrientation(orientation); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); -} - -void EntityItem::setLocalRotation(const glm::quat orientation) { - SpatiallyNestable::setLocalOrientation(orientation); - forSelfAndEachChildEntity([&](EntityItemPointer entity) { - entity->requiresRecalcBoxes(); - }); +void EntityItem::locationChanged() { + requiresRecalcBoxes(); + SpatiallyNestable::locationChanged(); // tell all the children, also } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index cbaa152c7f..761208cb06 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -306,15 +306,9 @@ public: /// return preferred shape type (actual physical shape may differ) virtual ShapeType getShapeType() const { return SHAPE_TYPE_NONE; } - virtual void setTransform(const Transform transform); - virtual void setLocalTransform(const Transform transform); - // virtual const glm::vec3 getPosition() const { return SpatiallyNestable::getPosition(); } - virtual const glm::quat getRotation() const { return SpatiallyNestable::getOrientation(); } - - virtual void setPosition(glm::vec3 position); - virtual void setLocalPosition(glm::vec3 position); - virtual void setRotation(glm::quat orientation); - virtual void setLocalRotation(glm::quat orientation); + // these are only needed because the names don't match + virtual const glm::quat getRotation() const { return getOrientation(); } + virtual void setRotation(glm::quat orientation) { setOrientation(orientation); } // updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags void updatePosition(const glm::vec3& value); @@ -393,8 +387,7 @@ protected: const QByteArray getActionDataInternal() const; void setActionDataInternal(QByteArray actionData); - void forSelfAndEachChildEntity(std::function actor); - virtual void parentChanged(); + virtual void locationChanged(); EntityTypes::EntityType _type; quint64 _lastSimulated; // last time this entity called simulate(), this includes velocity, angular velocity, // and physics changes diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 688ed831e3..a0280943de 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "DependencyManager.h" #include "SpatiallyNestable.h" @@ -91,6 +93,7 @@ void SpatiallyNestable::setParentID(const QUuid parentID) { _parentID = parentID; _parentKnowsMe = false; } + parentChanged(); } glm::vec3 SpatiallyNestable::worldToLocal(glm::vec3 position, QUuid parentID, int parentJointIndex) { @@ -182,6 +185,7 @@ void SpatiallyNestable::setPosition(glm::vec3 position) { myWorldTransform.setTranslation(position); Transform::inverseMult(_transform, parentTransform, myWorldTransform); }); + locationChanged(); } glm::quat SpatiallyNestable::getOrientation() const { @@ -200,6 +204,7 @@ void SpatiallyNestable::setOrientation(glm::quat orientation) { myWorldTransform.setRotation(orientation); Transform::inverseMult(_transform, parentTransform, myWorldTransform); }); + locationChanged(); } const Transform SpatiallyNestable::getTransform() const { @@ -227,6 +232,7 @@ void SpatiallyNestable::setTransform(const Transform transform) { _transformLock.withWriteLock([&] { Transform::inverseMult(_transform, parentTransform, transform); }); + locationChanged(); } glm::vec3 SpatiallyNestable::getScale() const { @@ -246,6 +252,7 @@ void SpatiallyNestable::setScale(glm::vec3 scale) { _transformLock.withWriteLock([&] { _transform.setScale(scale); }); + dimensionsChanged(); } const Transform SpatiallyNestable::getLocalTransform() const { @@ -260,6 +267,7 @@ void SpatiallyNestable::setLocalTransform(const Transform transform) { _transformLock.withWriteLock([&] { _transform = transform; }); + locationChanged(); } glm::vec3 SpatiallyNestable::getLocalPosition() const { @@ -274,6 +282,7 @@ void SpatiallyNestable::setLocalPosition(glm::vec3 position) { _transformLock.withWriteLock([&] { _transform.setTranslation(position); }); + locationChanged(); } glm::quat SpatiallyNestable::getLocalOrientation() const { @@ -288,6 +297,7 @@ void SpatiallyNestable::setLocalOrientation(glm::quat orientation) { _transformLock.withWriteLock([&] { _transform.setRotation(orientation); }); + locationChanged(); } glm::vec3 SpatiallyNestable::getLocalScale() const { @@ -302,12 +312,13 @@ void SpatiallyNestable::setLocalScale(glm::vec3 scale) { _transformLock.withWriteLock([&] { _transform.setScale(scale); }); + dimensionsChanged(); } QList SpatiallyNestable::getChildren() const { QList children; _childrenLock.withReadLock([&] { - foreach (SpatiallyNestableWeakPointer childWP, _children.values()) { + foreach(SpatiallyNestableWeakPointer childWP, _children.values()) { SpatiallyNestablePointer child = childWP.lock(); if (child) { children << child; @@ -317,7 +328,6 @@ QList SpatiallyNestable::getChildren() const { return children; } - const Transform SpatiallyNestable::getJointTransformInObjectFrame(int jointIndex) const { Transform jointInObjectFrame; glm::vec3 position = getJointTranslation(jointIndex); @@ -332,3 +342,30 @@ SpatiallyNestablePointer SpatiallyNestable::getThisPointer() const { SpatiallyNestablePointer thisPointer = std::const_pointer_cast(constThisPointer); // ermahgerd !!! return thisPointer; } + +void SpatiallyNestable::forEachChild(std::function actor) { + foreach(SpatiallyNestablePointer child, getChildren()) { + actor(child); + } +} + +void SpatiallyNestable::forEachDescendant(std::function actor) { + QQueue toProcess; + foreach(SpatiallyNestablePointer child, getChildren()) { + toProcess.enqueue(child); + } + + while (!toProcess.empty()) { + SpatiallyNestablePointer object = toProcess.dequeue(); + actor(object); + foreach (SpatiallyNestablePointer child, object->getChildren()) { + toProcess.enqueue(child); + } + } +} + +void SpatiallyNestable::locationChanged() { + forEachChild([&](SpatiallyNestablePointer object) { + object->locationChanged(); + }); +} diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index b7c04e8563..f750860037 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -92,8 +92,8 @@ public: // this object's frame virtual const Transform getJointTransformInObjectFrame(int jointIndex) const; - virtual glm::quat getJointRotation(int index) const = 0; - virtual glm::vec3 getJointTranslation(int index) const = 0; + virtual glm::quat getJointRotation(int index) const { assert(false); } + virtual glm::vec3 getJointTranslation(int index) const { assert(false); } SpatiallyNestablePointer getThisPointer() const; @@ -112,6 +112,11 @@ protected: mutable QHash _children; virtual void parentChanged() {} // called when parent pointer is updated + virtual void locationChanged(); // called when a this object's location has changed + virtual void dimensionsChanged() {} // called when a this object's dimensions have changed + + void forEachChild(std::function actor); + void forEachDescendant(std::function actor); private: mutable ReadWriteLockable _transformLock; From cf5c8c08e25c21aea9930e2180ea16ae31a3df79 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 3 Dec 2015 11:10:22 -0800 Subject: [PATCH 299/401] update toys to be inverted while held --- examples/toybox/doll/createDoll.js | 21 +++++++++++++++---- .../toybox/flashlight/createFlashlight.js | 21 +++++++++++++++---- .../toybox/ping_pong_gun/createPingPongGun.js | 7 ++++++- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/examples/toybox/doll/createDoll.js b/examples/toybox/doll/createDoll.js index ffd840f4ea..52ba5a5291 100644 --- a/examples/toybox/doll/createDoll.js +++ b/examples/toybox/doll/createDoll.js @@ -15,12 +15,20 @@ function createDoll() { var scriptURL = Script.resolvePath("doll.js"); - var center = Vec3.sum(Vec3.sum(MyAvatar.position, { x: 0, y: 0.5, z: 0 }), Vec3.multiply(0.5, Quat.getFront(Camera.getOrientation()))); + var center = Vec3.sum(Vec3.sum(MyAvatar.position, { + x: 0, + y: 0.5, + z: 0 + }), Vec3.multiply(0.5, Quat.getFront(Camera.getOrientation()))); - var naturalDimensions = { x: 1.63, y: 1.67, z: 0.26}; + var naturalDimensions = { + x: 1.63, + y: 1.67, + z: 0.26 + }; var desiredDimensions = Vec3.multiply(naturalDimensions, 0.15); - + var doll = Entities.addEntity({ type: "Model", name: "doll", @@ -39,7 +47,12 @@ function createDoll() { y: 0, z: 0 }, - collisionsWillMove: true + collisionsWillMove: true, + userData: JSON.stringify({ + grabbableKey: { + invertSolidWhileHeld: true + } + }) }); return doll; } diff --git a/examples/toybox/flashlight/createFlashlight.js b/examples/toybox/flashlight/createFlashlight.js index b049d2632e..108d519d3e 100644 --- a/examples/toybox/flashlight/createFlashlight.js +++ b/examples/toybox/flashlight/createFlashlight.js @@ -18,14 +18,27 @@ var scriptURL = Script.resolvePath('flashlight.js'); var modelURL = "https://hifi-public.s3.amazonaws.com/models/props/flashlight.fbx"; -var center = Vec3.sum(Vec3.sum(MyAvatar.position, {x: 0, y: 0.5, z: 0}), Vec3.multiply(0.5, Quat.getFront(Camera.getOrientation()))); +var center = Vec3.sum(Vec3.sum(MyAvatar.position, { + x: 0, + y: 0.5, + z: 0 +}), Vec3.multiply(0.5, Quat.getFront(Camera.getOrientation()))); var flashlight = Entities.addEntity({ type: "Model", modelURL: modelURL, position: center, - dimensions: { x: 0.08, y: 0.30, z: 0.08}, + dimensions: { + x: 0.08, + y: 0.30, + z: 0.08 + }, collisionsWillMove: true, shapeType: 'box', - script: scriptURL -}); + script: scriptURL, + userData: JSON.stringify({ + grabbableKey: { + invertSolidWhileHeld: true + } + }) +}); \ No newline at end of file diff --git a/examples/toybox/ping_pong_gun/createPingPongGun.js b/examples/toybox/ping_pong_gun/createPingPongGun.js index 705671e784..4b93842896 100644 --- a/examples/toybox/ping_pong_gun/createPingPongGun.js +++ b/examples/toybox/ping_pong_gun/createPingPongGun.js @@ -35,7 +35,12 @@ var pingPongGun = Entities.addEntity({ z: 0.47 }, collisionsWillMove: true, - collisionSoundURL: COLLISION_SOUND_URL + collisionSoundURL: COLLISION_SOUND_URL, + userData: JSON.stringify({ + grabbableKey: { + invertSolidWhileHeld: true + } + }) }); function cleanUp() { From 849a8707d2a1a91faa57ad4f809435e8904b8531 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 3 Dec 2015 11:05:28 -0800 Subject: [PATCH 300/401] remove wantsColor support since its always true and required for entities --- .../src/octree/OctreeQueryNode.cpp | 1 - .../src/octree/OctreeQueryNode.h | 2 +- .../src/octree/OctreeSendThread.cpp | 3 +- interface/src/Application.cpp | 1 - libraries/octree/src/Octree.cpp | 115 ++++++++---------- libraries/octree/src/Octree.h | 10 +- libraries/octree/src/OctreeHeadlessViewer.cpp | 1 - libraries/octree/src/OctreeQuery.cpp | 2 - libraries/octree/src/OctreeQuery.h | 7 +- libraries/octree/src/OctreeRenderer.cpp | 2 +- libraries/octree/src/OctreeSceneStats.cpp | 6 +- libraries/octree/src/OctreeSceneStats.h | 2 +- libraries/shared/src/OctalCode.cpp | 23 ---- libraries/shared/src/OctalCode.h | 2 - 14 files changed, 62 insertions(+), 115 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index cff2c7ee2e..06e9834804 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -179,7 +179,6 @@ void OctreeQueryNode::resetOctreePacket() { // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. - _currentPacketIsColor = getWantColor(); _currentPacketIsCompressed = getWantCompression(); OCTREE_PACKET_FLAGS flags = 0; if (_currentPacketIsColor) { diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 75c841851f..4140d42a5f 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -78,7 +78,7 @@ public: bool getCurrentPacketIsColor() const { return _currentPacketIsColor; } bool getCurrentPacketIsCompressed() const { return _currentPacketIsCompressed; } bool getCurrentPacketFormatMatches() { - return (getCurrentPacketIsColor() == getWantColor() && getCurrentPacketIsCompressed() == getWantCompression()); + return (getCurrentPacketIsCompressed() == getWantCompression()); } bool hasLodChanged() const { return _lodChanged; } diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index f873ee4808..efc81d6a21 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -321,7 +321,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // If we're starting a fresh packet, then... // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. - bool wantColor = nodeData->getWantColor(); bool wantCompression = nodeData->getWantCompression(); // If we have a packet waiting, and our desired want color, doesn't match the current waiting packets color @@ -456,7 +455,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus int boundaryLevelAdjust = boundaryLevelAdjustClient + (viewFrustumChanged && nodeData->getWantLowResMoving() ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); - EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor, + EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, boundaryLevelAdjust, octreeSizeScale, nodeData->getLastTimeBagEmpty(), diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 68a809688a..4b3775933d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3074,7 +3074,6 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. _octreeQuery.setWantLowResMoving(true); - _octreeQuery.setWantColor(true); _octreeQuery.setWantDelta(true); _octreeQuery.setWantCompression(true); diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 1960537ced..64a2eaccc4 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -950,9 +950,9 @@ int Octree::encodeTreeBitstream(OctreeElementPointer element, // if childBytesWritten == 1 then something went wrong... that's not possible assert(childBytesWritten != 1); - // if includeColor and childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some + // if childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some // reason couldn't be written... so reset them here... This isn't true for the non-color included case - if (suppressEmptySubtrees() && params.includeColor && childBytesWritten == 2) { + if (suppressEmptySubtrees() && childBytesWritten == 2) { childBytesWritten = 0; //params.stopReason = EncodeBitstreamParams::UNKNOWN; // possibly should be DIDNT_FIT... } @@ -1293,7 +1293,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // NOW might be a good time to give our tree subclass and this element a chance to set up and check any extra encode data element->initializeExtraEncodeData(params); - // write the child element data... NOTE: includeColor means include element data + // write the child element data... // NOTE: the format of the bitstream is generally this: // [octalcode] // [bitmask for existence of child data] @@ -1303,65 +1303,63 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // N x [ ... tree for children ...] // // This section of the code, is writing the "N x [child data]" portion of this bitstream - if (params.includeColor) { - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (oneAtBit(childrenDataBits, i)) { - OctreeElementPointer childElement = element->getChildAtIndex(i); + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { + if (oneAtBit(childrenDataBits, i)) { + OctreeElementPointer childElement = element->getChildAtIndex(i); - // the childrenDataBits were set up by the in view/LOD logic, it may contain children that we've already - // processed and sent the data bits for. Let our tree subclass determine if it really wants to send the - // data for this child at this point - if (childElement && element->shouldIncludeChildData(i, params)) { + // the childrenDataBits were set up by the in view/LOD logic, it may contain children that we've already + // processed and sent the data bits for. Let our tree subclass determine if it really wants to send the + // data for this child at this point + if (childElement && element->shouldIncludeChildData(i, params)) { - int bytesBeforeChild = packetData->getUncompressedSize(); + int bytesBeforeChild = packetData->getUncompressedSize(); - // a childElement may "partially" write it's data. for example, the model server where the entire - // contents of the element may be larger than can fit in a single MTU/packetData. In this case, - // we want to allow the appendElementData() to respond that it produced partial data, which should be - // written, but that the childElement needs to be reprocessed in an additional pass or passes - // to be completed. - LevelDetails childDataLevelKey = packetData->startLevel(); + // a childElement may "partially" write it's data. for example, the model server where the entire + // contents of the element may be larger than can fit in a single MTU/packetData. In this case, + // we want to allow the appendElementData() to respond that it produced partial data, which should be + // written, but that the childElement needs to be reprocessed in an additional pass or passes + // to be completed. + LevelDetails childDataLevelKey = packetData->startLevel(); - OctreeElement::AppendState childAppendState = childElement->appendElementData(packetData, params); + OctreeElement::AppendState childAppendState = childElement->appendElementData(packetData, params); - // allow our tree subclass to do any additional bookkeeping it needs to do with encoded data state - element->updateEncodedData(i, childAppendState, params); + // allow our tree subclass to do any additional bookkeeping it needs to do with encoded data state + element->updateEncodedData(i, childAppendState, params); - // Continue this level so long as some part of this child element was appended. - bool childFit = (childAppendState != OctreeElement::NONE); + // Continue this level so long as some part of this child element was appended. + bool childFit = (childAppendState != OctreeElement::NONE); - // some datatypes (like Voxels) assume that all child data will fit, if it doesn't fit - // the data type wants to bail on this element level completely - if (!childFit && mustIncludeAllChildData()) { - continueThisLevel = false; - break; - } + // some datatypes (like Voxels) assume that all child data will fit, if it doesn't fit + // the data type wants to bail on this element level completely + if (!childFit && mustIncludeAllChildData()) { + continueThisLevel = false; + break; + } - // If the child was partially or fully appended, then mark the actualChildrenDataBits as including - // this child data - if (childFit) { - actualChildrenDataBits += (1 << (7 - i)); - continueThisLevel = packetData->endLevel(childDataLevelKey); - } else { - packetData->discardLevel(childDataLevelKey); - elementAppendState = OctreeElement::PARTIAL; - params.stopReason = EncodeBitstreamParams::DIDNT_FIT; - } + // If the child was partially or fully appended, then mark the actualChildrenDataBits as including + // this child data + if (childFit) { + actualChildrenDataBits += (1 << (7 - i)); + continueThisLevel = packetData->endLevel(childDataLevelKey); + } else { + packetData->discardLevel(childDataLevelKey); + elementAppendState = OctreeElement::PARTIAL; + params.stopReason = EncodeBitstreamParams::DIDNT_FIT; + } - // If this child was partially appended, then consider this element to be partially appended - if (childAppendState == OctreeElement::PARTIAL) { - elementAppendState = OctreeElement::PARTIAL; - params.stopReason = EncodeBitstreamParams::DIDNT_FIT; - } + // If this child was partially appended, then consider this element to be partially appended + if (childAppendState == OctreeElement::PARTIAL) { + elementAppendState = OctreeElement::PARTIAL; + params.stopReason = EncodeBitstreamParams::DIDNT_FIT; + } - int bytesAfterChild = packetData->getUncompressedSize(); + int bytesAfterChild = packetData->getUncompressedSize(); - bytesAtThisLevel += (bytesAfterChild - bytesBeforeChild); // keep track of byte count for this child + bytesAtThisLevel += (bytesAfterChild - bytesBeforeChild); // keep track of byte count for this child - // don't need to check childElement here, because we can't get here with no childElement - if (params.stats && (childAppendState != OctreeElement::NONE)) { - params.stats->colorSent(childElement); - } + // don't need to check childElement here, because we can't get here with no childElement + if (params.stats && (childAppendState != OctreeElement::NONE)) { + params.stats->colorSent(childElement); } } } @@ -1500,17 +1498,10 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // so, if the child returns 2 bytes out, we can actually consider that an empty tree also!! // // we can make this act like no bytes out, by just resetting the bytes out in this case - if (suppressEmptySubtrees() && params.includeColor && !params.includeExistsBits && childTreeBytesOut == 2) { + if (suppressEmptySubtrees() && !params.includeExistsBits && childTreeBytesOut == 2) { childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees } - // We used to try to collapse trees that didn't contain any data, but this does appear to create a problem - // in detecting element deletion. So, I've commented this out but left it in here as a warning to anyone else - // about not attempting to add this optimization back in, without solving the element deletion case. - // We need to send these bitMasks in case the exists in tree bitmask is indicating the deletion of a tree - //if (params.includeColor && params.includeExistsBits && childTreeBytesOut == 3) { - // childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees - //} bytesAtThisLevel += childTreeBytesOut; @@ -1530,7 +1521,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // If this is the last of the child exists bits, then we're actually be rolling out the entire tree if (params.stats && childrenExistInPacketBits == 0) { - params.stats->childBitsRemoved(params.includeExistsBits, params.includeColor); + params.stats->childBitsRemoved(params.includeExistsBits); } if (!continueThisLevel) { @@ -1825,7 +1816,7 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr unsigned char* dataAt = entireFileDataSection; - ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, + ReadBitstreamToTreeParams args(NO_EXISTS_BITS, NULL, 0, SharedNodePointer(), wantImportProgress, gotVersion); readBitstreamToTree(dataAt, dataLength, args); @@ -1864,7 +1855,7 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr unsigned char* dataAt = fileChunk; unsigned long dataLength = chunkLength; - ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, + ReadBitstreamToTreeParams args(NO_EXISTS_BITS, NULL, 0, SharedNodePointer(), wantImportProgress, gotVersion); readBitstreamToTree(dataAt, dataLength, args); @@ -2012,7 +2003,7 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElementPointer element) bool lastPacketWritten = false; while (OctreeElementPointer subTree = elementBag.extract()) { - EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); + EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, NO_EXISTS_BITS); withReadLock([&] { params.extraEncodeData = &extraEncodeData; bytesWritten = encodeTreeBitstream(subTree, &packetData, elementBag, params); diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 5f5aa1432a..3ca8528a2f 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -52,8 +52,6 @@ typedef QHash CubeList; const bool NO_EXISTS_BITS = false; const bool WANT_EXISTS_BITS = true; -const bool NO_COLOR = false; -const bool WANT_COLOR = true; const bool COLLAPSE_EMPTY_TREE = true; const bool DONT_COLLAPSE = false; @@ -72,7 +70,6 @@ public: int maxEncodeLevel; int maxLevelReached; const ViewFrustum* viewFrustum; - bool includeColor; bool includeExistsBits; int chopLevels; bool deltaViewFrustum; @@ -103,7 +100,6 @@ public: EncodeBitstreamParams( int maxEncodeLevel = INT_MAX, const ViewFrustum* viewFrustum = IGNORE_VIEW_FRUSTUM, - bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, int chopLevels = 0, bool deltaViewFrustum = false, @@ -118,7 +114,6 @@ public: maxEncodeLevel(maxEncodeLevel), maxLevelReached(0), viewFrustum(viewFrustum), - includeColor(includeColor), includeExistsBits(includeExistsBits), chopLevels(chopLevels), deltaViewFrustum(deltaViewFrustum), @@ -181,7 +176,6 @@ public: class ReadBitstreamToTreeParams { public: - bool includeColor; bool includeExistsBits; OctreeElementPointer destinationElement; QUuid sourceUUID; @@ -192,14 +186,12 @@ public: int entitiesPerPacket = 0; ReadBitstreamToTreeParams( - bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, OctreeElementPointer destinationElement = NULL, QUuid sourceUUID = QUuid(), SharedNodePointer sourceNode = SharedNodePointer(), bool wantImportProgress = false, PacketVersion bitstreamVersion = 0) : - includeColor(includeColor), includeExistsBits(includeExistsBits), destinationElement(destinationElement), sourceUUID(sourceUUID), @@ -306,7 +298,7 @@ public: Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL); // Note: this assumes the fileFormat is the HIO individual voxels code files - void loadOctreeFile(const char* fileName, bool wantColorRandomizer); + void loadOctreeFile(const char* fileName); // Octree exporters void writeToFile(const char* filename, OctreeElementPointer element = NULL, QString persistAsFileType = "svo"); diff --git a/libraries/octree/src/OctreeHeadlessViewer.cpp b/libraries/octree/src/OctreeHeadlessViewer.cpp index b18f219d4d..f1c2172d86 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.cpp +++ b/libraries/octree/src/OctreeHeadlessViewer.cpp @@ -51,7 +51,6 @@ void OctreeHeadlessViewer::queryOctree() { // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. _octreeQuery.setWantLowResMoving(true); - _octreeQuery.setWantColor(true); _octreeQuery.setWantDelta(true); _octreeQuery.setWantCompression(true); // TODO: should be on by default diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index 2739b4a0d1..c431d66bf2 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -41,7 +41,6 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { // bitMask of less than byte wide items unsigned char bitItems = 0; if (_wantLowResMoving) { setAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); } - if (_wantColor) { setAtBit(bitItems, WANT_COLOR_AT_BIT); } if (_wantDelta) { setAtBit(bitItems, WANT_DELTA_AT_BIT); } if (_wantCompression) { setAtBit(bitItems, WANT_COMPRESSION); } @@ -83,7 +82,6 @@ int OctreeQuery::parseData(NLPacket& packet) { unsigned char bitItems = 0; bitItems = (unsigned char)*sourceBuffer++; _wantLowResMoving = oneAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); - _wantColor = oneAtBit(bitItems, WANT_COLOR_AT_BIT); _wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT); _wantCompression = oneAtBit(bitItems, WANT_COMPRESSION); diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index 9605cbfb5d..71c9361e68 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -35,9 +35,9 @@ typedef unsigned long long quint64; // First bitset const int WANT_LOW_RES_MOVING_BIT = 0; -const int WANT_COLOR_AT_BIT = 1; +const int UNUSED_BIT_1 = 1; // unused... available for new feature const int WANT_DELTA_AT_BIT = 2; -const int UNUSED_BIT = 3; // unused... available for new feature +const int UNUSED_BIT_3 = 3; // unused... available for new feature const int WANT_COMPRESSION = 4; // 5th bit class OctreeQuery : public NodeData { @@ -71,7 +71,6 @@ public: void setCameraEyeOffsetPosition(const glm::vec3& eyeOffsetPosition) { _cameraEyeOffsetPosition = eyeOffsetPosition; } // related to Octree Sending strategies - bool getWantColor() const { return _wantColor; } bool getWantDelta() const { return _wantDelta; } bool getWantLowResMoving() const { return _wantLowResMoving; } bool getWantCompression() const { return _wantCompression; } @@ -81,7 +80,6 @@ public: public slots: void setWantLowResMoving(bool wantLowResMoving) { _wantLowResMoving = wantLowResMoving; } - void setWantColor(bool wantColor) { _wantColor = wantColor; } void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; } void setWantCompression(bool wantCompression) { _wantCompression = wantCompression; } void setMaxQueryPacketsPerSecond(int maxQueryPPS) { _maxQueryPPS = maxQueryPPS; } @@ -99,7 +97,6 @@ protected: glm::vec3 _cameraEyeOffsetPosition = glm::vec3(0.0f); // octree server sending items - bool _wantColor = true; bool _wantDelta = true; bool _wantLowResMoving = true; bool _wantCompression = false; diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp index b7be4cf3e7..c65359f12f 100644 --- a/libraries/octree/src/OctreeRenderer.cpp +++ b/libraries/octree/src/OctreeRenderer.cpp @@ -115,7 +115,7 @@ void OctreeRenderer::processDatagram(NLPacket& packet, SharedNodePointer sourceN if (sectionLength) { // ask the VoxelTree to read the bitstream into the tree - ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, + ReadBitstreamToTreeParams args(WANT_EXISTS_BITS, NULL, sourceUUID, sourceNode, false, packet.getVersion()); quint64 startUncompress, startLock = usecTimestampNow(); quint64 startReadBitsteam, endReadBitsteam; diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index 22352fbe3b..c70e0e4935 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -371,14 +371,12 @@ void OctreeSceneStats::existsInPacketBitsWritten() { _existsInPacketBitsWritten++; } -void OctreeSceneStats::childBitsRemoved(bool includesExistsBits, bool includesColors) { +void OctreeSceneStats::childBitsRemoved(bool includesExistsBits) { _existsInPacketBitsWritten--; if (includesExistsBits) { _existsBitsWritten--; } - if (includesColors) { - _colorBitsWritten--; - } + _colorBitsWritten--; _treesRemoved++; } diff --git a/libraries/octree/src/OctreeSceneStats.h b/libraries/octree/src/OctreeSceneStats.h index bdb4ef206a..f8ecf93106 100644 --- a/libraries/octree/src/OctreeSceneStats.h +++ b/libraries/octree/src/OctreeSceneStats.h @@ -89,7 +89,7 @@ public: void existsInPacketBitsWritten(); /// Fix up tracking statistics in case where bitmasks were removed for some reason - void childBitsRemoved(bool includesExistsBits, bool includesColors); + void childBitsRemoved(bool includesExistsBits); /// Pack the details of the statistics into a buffer for sending as a network packet int packIntoPacket(); diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index 0b77683d4c..1fa18903cb 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -264,29 +264,6 @@ unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLev return newCode; } -unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode, - bool includeColorSpace) { - - int oldCodeLength = numberOfThreeBitSectionsInCode(originalOctalCode); - int newParentCodeLength = numberOfThreeBitSectionsInCode(newParentOctalCode); - int newCodeLength = newParentCodeLength + oldCodeLength; - int bufferLength = newCodeLength + (includeColorSpace ? SIZE_OF_COLOR_DATA : 0); - unsigned char* newCode = new unsigned char[bufferLength]; - *newCode = newCodeLength; // set the length byte - - // copy parent code section first - for (int sectionFromParent = 0; sectionFromParent < newParentCodeLength; sectionFromParent++) { - char sectionValue = getOctalCodeSectionValue(newParentOctalCode, sectionFromParent); - setOctalCodeSectionValue(newCode, sectionFromParent, sectionValue); - } - // copy original code section next - for (int sectionFromOriginal = 0; sectionFromOriginal < oldCodeLength; sectionFromOriginal++) { - char sectionValue = getOctalCodeSectionValue(originalOctalCode, sectionFromOriginal); - setOctalCodeSectionValue(newCode, sectionFromOriginal + newParentCodeLength, sectionValue); - } - return newCode; -} - bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* possibleDescendent, int descendentsChild) { if (!possibleAncestor || !possibleDescendent) { return false; diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index 9229157c3d..09766b685a 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -36,8 +36,6 @@ const int UNKNOWN_OCTCODE_LENGTH = -2; int numberOfThreeBitSectionsInCode(const unsigned char* octalCode, int maxBytes = UNKNOWN_OCTCODE_LENGTH); unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLevels); -unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode, - bool includeColorSpace = false); const int CHECK_NODE_ONLY = -1; bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* possibleDescendent, From fbca1c975402624ffec58bdf282838995ca5a17b Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Thu, 3 Dec 2015 11:12:28 -0800 Subject: [PATCH 301/401] another toy --- examples/toybox/basketball/createSingleBasketball.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/toybox/basketball/createSingleBasketball.js b/examples/toybox/basketball/createSingleBasketball.js index a1e0140553..6765e5e075 100644 --- a/examples/toybox/basketball/createSingleBasketball.js +++ b/examples/toybox/basketball/createSingleBasketball.js @@ -47,7 +47,12 @@ function makeBasketball() { modelURL: basketballURL, restitution: 1.0, damping: 0.00001, - shapeType: "sphere" + shapeType: "sphere", + userData: JSON.stringify({ + grabbableKey: { + invertSolidWhileHeld: true + } + }) }); originalPosition = position; } From e5b1cfa920d5a09b2e2b1375a0f797f4d21cf9a9 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 3 Dec 2015 11:15:04 -0800 Subject: [PATCH 302/401] fix windows build --- libraries/shared/src/SpatiallyNestable.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index f750860037..f3056d9a4f 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -92,8 +92,8 @@ public: // this object's frame virtual const Transform getJointTransformInObjectFrame(int jointIndex) const; - virtual glm::quat getJointRotation(int index) const { assert(false); } - virtual glm::vec3 getJointTranslation(int index) const { assert(false); } + virtual glm::quat getJointRotation(int index) const { assert(false); return glm::quat(); } + virtual glm::vec3 getJointTranslation(int index) const { assert(false); return glm::vec3(); } SpatiallyNestablePointer getThisPointer() const; From 1a5bc5d11148185e67ca09a69a427ac7773796fa Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 3 Dec 2015 12:40:24 -0800 Subject: [PATCH 303/401] removing optional compression --- assignment-client/src/octree/OctreeQueryNode.cpp | 9 ++------- assignment-client/src/octree/OctreeQueryNode.h | 4 +--- assignment-client/src/octree/OctreeSendThread.cpp | 14 ++++---------- interface/src/Application.cpp | 1 - libraries/entities/src/EntityItemProperties.cpp | 4 +++- libraries/octree/src/OctreeHeadlessViewer.cpp | 1 - libraries/octree/src/OctreePacketData.cpp | 9 +++++---- libraries/octree/src/OctreePacketData.h | 6 +++--- libraries/octree/src/OctreeQuery.cpp | 2 -- libraries/octree/src/OctreeQuery.h | 5 +---- 10 files changed, 19 insertions(+), 36 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 06e9834804..cafba8c083 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -179,14 +179,9 @@ void OctreeQueryNode::resetOctreePacket() { // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. - _currentPacketIsCompressed = getWantCompression(); OCTREE_PACKET_FLAGS flags = 0; - if (_currentPacketIsColor) { - setAtBit(flags, PACKET_IS_COLOR_BIT); - } - if (_currentPacketIsCompressed) { - setAtBit(flags, PACKET_IS_COMPRESSED_BIT); - } + setAtBit(flags, PACKET_IS_COLOR_BIT); + setAtBit(flags, PACKET_IS_COMPRESSED_BIT); _octreePacket->reset(); diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 4140d42a5f..67298296e9 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -77,9 +77,7 @@ public: bool getCurrentPacketIsColor() const { return _currentPacketIsColor; } bool getCurrentPacketIsCompressed() const { return _currentPacketIsCompressed; } - bool getCurrentPacketFormatMatches() { - return (getCurrentPacketIsCompressed() == getWantCompression()); - } + bool getCurrentPacketFormatMatches() { return (getCurrentPacketIsCompressed() == true); } // FIXME bool hasLodChanged() const { return _lodChanged; } diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index efc81d6a21..d01117dff6 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -321,7 +321,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // If we're starting a fresh packet, then... // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. - bool wantCompression = nodeData->getWantCompression(); // If we have a packet waiting, and our desired want color, doesn't match the current waiting packets color // then let's just send that waiting packet. @@ -332,10 +331,8 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus nodeData->resetOctreePacket(); } int targetSize = MAX_OCTREE_PACKET_DATA_SIZE; - if (wantCompression) { - targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); - } - _packetData.changeSettings(wantCompression, targetSize); + targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); + _packetData.changeSettings(targetSize); } const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL; @@ -551,10 +548,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus packetsSentThisInterval += handlePacketSend(nodeData, trueBytesSent, truePacketsSent); quint64 packetSendingEnd = usecTimestampNow(); packetSendingElapsedUsec = (float)(packetSendingEnd - packetSendingStart); - - if (wantCompression) { - targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); - } + targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); } else { // If we're in compressed mode, then we want to see if we have room for more in this wire packet. // but we've finalized the _packetData, so we want to start a new section, we will do that by @@ -564,7 +558,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // a larger compressed size then uncompressed size targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE) - COMPRESS_PADDING; } - _packetData.changeSettings(nodeData->getWantCompression(), targetSize); // will do reset + _packetData.changeSettings(targetSize); // will do reset } OctreeServer::trackTreeWaitTime(lockWaitElapsedUsec); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4b3775933d..053ef5b7a7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3075,7 +3075,6 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. _octreeQuery.setWantLowResMoving(true); _octreeQuery.setWantDelta(true); - _octreeQuery.setWantCompression(true); _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); _octreeQuery.setCameraOrientation(_viewFrustum.getOrientation()); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 78a4f3e8b6..30bee83482 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -790,7 +790,9 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue // bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties, QByteArray& buffer) { - OctreePacketData ourDataPacket(false, buffer.size()); // create a packetData object to add out packet details too. + + // FIXME - remove non-compressed OctreePacketData and handle compressed edit packets + OctreePacketData ourDataPacket(buffer.size(), false); // create a packetData object to add out packet details too. OctreePacketData* packetData = &ourDataPacket; // we want a pointer to this so we can use our APPEND_ENTITY_PROPERTY macro bool success = true; // assume the best diff --git a/libraries/octree/src/OctreeHeadlessViewer.cpp b/libraries/octree/src/OctreeHeadlessViewer.cpp index f1c2172d86..7b80d315f1 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.cpp +++ b/libraries/octree/src/OctreeHeadlessViewer.cpp @@ -52,7 +52,6 @@ void OctreeHeadlessViewer::queryOctree() { // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. _octreeQuery.setWantLowResMoving(true); _octreeQuery.setWantDelta(true); - _octreeQuery.setWantCompression(true); // TODO: should be on by default _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); _octreeQuery.setCameraOrientation(_viewFrustum.getOrientation()); diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index 811e96fcf4..f4fbf9bd97 100644 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -23,12 +23,13 @@ AtomicUIntStat OctreePacketData::_totalBytesOfValues { 0 }; AtomicUIntStat OctreePacketData::_totalBytesOfPositions { 0 }; AtomicUIntStat OctreePacketData::_totalBytesOfRawData { 0 }; -OctreePacketData::OctreePacketData(bool enableCompression, int targetSize) { - changeSettings(enableCompression, targetSize); // does reset... +OctreePacketData::OctreePacketData(int targetSize, bool enableCompression) { + changeSettings(targetSize); // does reset... + _enableCompression = enableCompression; // FIXME } -void OctreePacketData::changeSettings(bool enableCompression, unsigned int targetSize) { - _enableCompression = enableCompression; +void OctreePacketData::changeSettings(unsigned int targetSize) { + _enableCompression = true; // FIXME _targetSize = std::min(MAX_OCTREE_UNCOMRESSED_PACKET_SIZE, targetSize); reset(); } diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 2c86d518ad..fb53b3472f 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -83,11 +83,11 @@ private: /// Handles packing of the data portion of PacketType_OCTREE_DATA messages. class OctreePacketData { public: - OctreePacketData(bool enableCompression = false, int maxFinalizedSize = MAX_OCTREE_PACKET_DATA_SIZE); + OctreePacketData(int maxFinalizedSize = MAX_OCTREE_PACKET_DATA_SIZE, bool enableCompression = true); ~OctreePacketData(); /// change compression and target size settings - void changeSettings(bool enableCompression = false, unsigned int targetSize = MAX_OCTREE_PACKET_DATA_SIZE); + void changeSettings(unsigned int targetSize = MAX_OCTREE_PACKET_DATA_SIZE); /// reset completely, all data is discarded void reset(); @@ -262,7 +262,7 @@ private: bool append(unsigned char byte); unsigned int _targetSize; - bool _enableCompression; + bool _enableCompression { true }; // FIXME - these will always be compressed, so remove this option unsigned char _uncompressed[MAX_OCTREE_UNCOMRESSED_PACKET_SIZE]; int _bytesInUse; diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index c431d66bf2..8449e3083a 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -42,7 +42,6 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { unsigned char bitItems = 0; if (_wantLowResMoving) { setAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); } if (_wantDelta) { setAtBit(bitItems, WANT_DELTA_AT_BIT); } - if (_wantCompression) { setAtBit(bitItems, WANT_COMPRESSION); } *destinationBuffer++ = bitItems; @@ -83,7 +82,6 @@ int OctreeQuery::parseData(NLPacket& packet) { bitItems = (unsigned char)*sourceBuffer++; _wantLowResMoving = oneAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); _wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT); - _wantCompression = oneAtBit(bitItems, WANT_COMPRESSION); // desired Max Octree PPS memcpy(&_maxQueryPPS, sourceBuffer, sizeof(_maxQueryPPS)); diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index 71c9361e68..962a8e1425 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -38,7 +38,7 @@ const int WANT_LOW_RES_MOVING_BIT = 0; const int UNUSED_BIT_1 = 1; // unused... available for new feature const int WANT_DELTA_AT_BIT = 2; const int UNUSED_BIT_3 = 3; // unused... available for new feature -const int WANT_COMPRESSION = 4; // 5th bit +const int UNUSED_BIT_4 = 4; // 5th bit, unused... available for new feature class OctreeQuery : public NodeData { Q_OBJECT @@ -73,7 +73,6 @@ public: // related to Octree Sending strategies bool getWantDelta() const { return _wantDelta; } bool getWantLowResMoving() const { return _wantLowResMoving; } - bool getWantCompression() const { return _wantCompression; } int getMaxQueryPacketsPerSecond() const { return _maxQueryPPS; } float getOctreeSizeScale() const { return _octreeElementSizeScale; } int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } @@ -81,7 +80,6 @@ public: public slots: void setWantLowResMoving(bool wantLowResMoving) { _wantLowResMoving = wantLowResMoving; } void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; } - void setWantCompression(bool wantCompression) { _wantCompression = wantCompression; } void setMaxQueryPacketsPerSecond(int maxQueryPPS) { _maxQueryPPS = maxQueryPPS; } void setOctreeSizeScale(float octreeSizeScale) { _octreeElementSizeScale = octreeSizeScale; } void setBoundaryLevelAdjust(int boundaryLevelAdjust) { _boundaryLevelAdjust = boundaryLevelAdjust; } @@ -99,7 +97,6 @@ protected: // octree server sending items bool _wantDelta = true; bool _wantLowResMoving = true; - bool _wantCompression = false; int _maxQueryPPS = DEFAULT_MAX_OCTREE_PPS; float _octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE; /// used for LOD calculations int _boundaryLevelAdjust = 0; /// used for LOD calculations From cc80dfb9e17d0dfae836eb13f8fa018fa51c28eb Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 3 Dec 2015 11:08:56 -0800 Subject: [PATCH 304/401] Fixing case on gl surface format helper --- libraries/gl/src/gl/GLHelpers.cpp | 2 +- libraries/gl/src/gl/GLHelpers.h | 2 +- libraries/gl/src/gl/GLWidget.cpp | 7 +++---- libraries/gl/src/gl/GLWidget.h | 8 +++----- libraries/gl/src/gl/GLWindow.cpp | 2 +- libraries/gl/src/gl/OffscreenGLCanvas.cpp | 2 +- tests/shaders/src/main.cpp | 2 +- 7 files changed, 11 insertions(+), 14 deletions(-) diff --git a/libraries/gl/src/gl/GLHelpers.cpp b/libraries/gl/src/gl/GLHelpers.cpp index 9022f0ffcc..6ad7f816b8 100644 --- a/libraries/gl/src/gl/GLHelpers.cpp +++ b/libraries/gl/src/gl/GLHelpers.cpp @@ -5,7 +5,7 @@ #include #include -const QSurfaceFormat& getDefaultOpenGlSurfaceFormat() { +const QSurfaceFormat& getDefaultOpenGLSurfaceFormat() { static QSurfaceFormat format; static std::once_flag once; std::call_once(once, [] { diff --git a/libraries/gl/src/gl/GLHelpers.h b/libraries/gl/src/gl/GLHelpers.h index de9e8f5d85..335272d991 100644 --- a/libraries/gl/src/gl/GLHelpers.h +++ b/libraries/gl/src/gl/GLHelpers.h @@ -19,6 +19,6 @@ class QSurfaceFormat; class QGLFormat; -const QSurfaceFormat& getDefaultOpenGlSurfaceFormat(); +const QSurfaceFormat& getDefaultOpenGLSurfaceFormat(); const QGLFormat& getDefaultGLFormat(); #endif diff --git a/libraries/gl/src/gl/GLWidget.cpp b/libraries/gl/src/gl/GLWidget.cpp index ec08d70e7a..310675c01f 100644 --- a/libraries/gl/src/gl/GLWidget.cpp +++ b/libraries/gl/src/gl/GLWidget.cpp @@ -1,9 +1,8 @@ // -// GLWidget.cpp -// interface/src // -// Created by Stephen Birarda on 8/14/13. -// Copyright 2013 High Fidelity, Inc. +// Created by Bradley Austin Davis on 2015/12/03 +// Derived from interface/src/GLCanvas.cpp created by Stephen Birarda on 8/14/13. +// Copyright 2013-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 diff --git a/libraries/gl/src/gl/GLWidget.h b/libraries/gl/src/gl/GLWidget.h index 5c4f4305cc..df4a73ac50 100644 --- a/libraries/gl/src/gl/GLWidget.h +++ b/libraries/gl/src/gl/GLWidget.h @@ -1,9 +1,7 @@ // -// GLWidget.h -// interface/src -// -// Created by Stephen Birarda on 8/14/13. -// Copyright 2013 High Fidelity, Inc. +// Created by Bradley Austin Davis on 2015/12/03 +// Derived from interface/src/GLCanvas.h created by Stephen Birarda on 8/14/13. +// Copyright 2013-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 diff --git a/libraries/gl/src/gl/GLWindow.cpp b/libraries/gl/src/gl/GLWindow.cpp index 42914fed59..78c7666d25 100644 --- a/libraries/gl/src/gl/GLWindow.cpp +++ b/libraries/gl/src/gl/GLWindow.cpp @@ -14,7 +14,7 @@ #include "GLHelpers.h" void GLWindow::createContext(QOpenGLContext* shareContext) { - createContext(getDefaultOpenGlSurfaceFormat(), shareContext); + createContext(getDefaultOpenGLSurfaceFormat(), shareContext); } void GLWindow::createContext(const QSurfaceFormat& format, QOpenGLContext* shareContext) { diff --git a/libraries/gl/src/gl/OffscreenGLCanvas.cpp b/libraries/gl/src/gl/OffscreenGLCanvas.cpp index b8c9b9e117..640c8ed5f5 100644 --- a/libraries/gl/src/gl/OffscreenGLCanvas.cpp +++ b/libraries/gl/src/gl/OffscreenGLCanvas.cpp @@ -37,7 +37,7 @@ void OffscreenGLCanvas::create(QOpenGLContext* sharedContext) { sharedContext->doneCurrent(); _context->setShareContext(sharedContext); } - _context->setFormat(getDefaultOpenGlSurfaceFormat()); + _context->setFormat(getDefaultOpenGLSurfaceFormat()); _context->create(); _offscreenSurface->setFormat(_context->format()); diff --git a/tests/shaders/src/main.cpp b/tests/shaders/src/main.cpp index 3edff67d66..f65cd9b5aa 100644 --- a/tests/shaders/src/main.cpp +++ b/tests/shaders/src/main.cpp @@ -128,7 +128,7 @@ protected: public: QTestWindow() { setSurfaceType(QSurface::OpenGLSurface); - QSurfaceFormat format = getDefaultOpenGlSurfaceFormat(); + QSurfaceFormat format = getDefaultOpenGLSurfaceFormat(); setFormat(format); _context = new QOpenGLContext; _context->setFormat(format); From 4a8649c202b5b02f49be6ee4f55f6328d4d466f0 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 3 Dec 2015 14:23:16 -0800 Subject: [PATCH 305/401] Change get/setRenderDistanceLow/HighLimit and avatarRenderDistanceHighLimit to get/setRenderDistanceInverseLow/HighLimit and avatarRenderDistanceInverseHighLimit. --- interface/src/avatar/AvatarManager.cpp | 8 ++++---- interface/src/avatar/AvatarManager.h | 8 ++++---- interface/src/ui/PreferencesDialog.cpp | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index e094f2e263..eeb5bbd55f 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -77,9 +77,9 @@ AvatarManager::AvatarManager(QObject* parent) : } const float SMALLEST_REASONABLE_HORIZON = 5.0f; // meters -Setting::Handle avatarRenderDistanceHighLimit("avatarRenderDistanceHighLimit", 1.0f / SMALLEST_REASONABLE_HORIZON); -void AvatarManager::setRenderDistanceHighLimit(float newValue) { - avatarRenderDistanceHighLimit.set(newValue); +Setting::Handle avatarRenderDistanceInverseHighLimit("avatarRenderDistanceHighLimit", 1.0f / SMALLEST_REASONABLE_HORIZON); +void AvatarManager::setRenderDistanceInverseHighLimit(float newValue) { + avatarRenderDistanceInverseHighLimit.set(newValue); _renderDistanceController.setControlledValueHighLimit(newValue); } @@ -101,7 +101,7 @@ void AvatarManager::init() { const float target_fps = qApp->getTargetFrameRate(); _renderDistanceController.setMeasuredValueSetpoint(target_fps); - _renderDistanceController.setControlledValueHighLimit(avatarRenderDistanceHighLimit.get()); + _renderDistanceController.setControlledValueHighLimit(avatarRenderDistanceInverseHighLimit.get()); _renderDistanceController.setControlledValueLowLimit(1.0f / (float) TREE_SCALE); // Advice for tuning parameters: // See PIDController.h. There's a section on tuning in the reference. diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index ddc40d8490..84a4bc44b8 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -70,16 +70,16 @@ public: // Expose results and parameter-tuning operations to other systems, such as stats and javascript. Q_INVOKABLE float getRenderDistance() { return _renderDistance; } - Q_INVOKABLE float getRenderDistanceLowLimit() { return _renderDistanceController.getControlledValueLowLimit(); } - Q_INVOKABLE float getRenderDistanceHighLimit() { return _renderDistanceController.getControlledValueHighLimit(); } + Q_INVOKABLE float getRenderDistanceInverseLowLimit() { return _renderDistanceController.getControlledValueLowLimit(); } + Q_INVOKABLE float getRenderDistanceInverseHighLimit() { return _renderDistanceController.getControlledValueHighLimit(); } Q_INVOKABLE int getNumberInRenderRange() { return _renderedAvatarCount; } Q_INVOKABLE bool getRenderDistanceControllerIsLogging() { return _renderDistanceController.getIsLogging(); } Q_INVOKABLE void setRenderDistanceControllerHistory(QString label, int size) { return _renderDistanceController.setHistorySize(label, size); } Q_INVOKABLE void setRenderDistanceKP(float newValue) { _renderDistanceController.setKP(newValue); } Q_INVOKABLE void setRenderDistanceKI(float newValue) { _renderDistanceController.setKI(newValue); } Q_INVOKABLE void setRenderDistanceKD(float newValue) { _renderDistanceController.setKD(newValue); } - Q_INVOKABLE void setRenderDistanceLowLimit(float newValue) { _renderDistanceController.setControlledValueLowLimit(newValue); } - Q_INVOKABLE void setRenderDistanceHighLimit(float newValue); + Q_INVOKABLE void setRenderDistanceInverseLowLimit(float newValue) { _renderDistanceController.setControlledValueLowLimit(newValue); } + Q_INVOKABLE void setRenderDistanceInverseHighLimit(float newValue); public slots: void setShouldShowReceiveStats(bool shouldShowReceiveStats) { _shouldShowReceiveStats = shouldShowReceiveStats; } diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 69ece359e9..5d01893873 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -204,7 +204,7 @@ void PreferencesDialog::loadPreferences() { auto lodManager = DependencyManager::get(); ui.desktopMinimumFPSSpin->setValue(lodManager->getDesktopLODDecreaseFPS()); ui.hmdMinimumFPSSpin->setValue(lodManager->getHMDLODDecreaseFPS()); - ui.avatarRenderSmallestReasonableHorizon->setValue(1.0f / DependencyManager::get()->getRenderDistanceHighLimit()); + ui.avatarRenderSmallestReasonableHorizon->setValue(1.0f / DependencyManager::get()->getRenderDistanceInverseHighLimit()); } void PreferencesDialog::savePreferences() { @@ -295,5 +295,5 @@ void PreferencesDialog::savePreferences() { auto lodManager = DependencyManager::get(); lodManager->setDesktopLODDecreaseFPS(ui.desktopMinimumFPSSpin->value()); lodManager->setHMDLODDecreaseFPS(ui.hmdMinimumFPSSpin->value()); - DependencyManager::get()->setRenderDistanceHighLimit(1.0f / ui.avatarRenderSmallestReasonableHorizon->value()); + DependencyManager::get()->setRenderDistanceInverseHighLimit(1.0f / ui.avatarRenderSmallestReasonableHorizon->value()); } From 3da80f58610be08f3a2551f9a243687c34c8784c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 24 Nov 2015 09:28:48 -0800 Subject: [PATCH 306/401] gpu::Shader::create* return shared_ptr --- interface/src/Stars.cpp | 16 +++---- .../RenderableParticleEffectEntityItem.cpp | 19 ++++----- .../src/RenderablePolyLineEntityItem.cpp | 8 ++-- .../src/RenderablePolyVoxEntityItem.cpp | 8 ++-- libraries/gpu/src/gpu/Pipeline.cpp | 8 ++-- libraries/gpu/src/gpu/Pipeline.h | 6 ++- libraries/gpu/src/gpu/Shader.cpp | 22 ++++------ libraries/gpu/src/gpu/Shader.h | 6 +-- libraries/gpu/src/gpu/StandardShaderLib.cpp | 16 +++---- libraries/model/src/model/Skybox.cpp | 8 ++-- .../procedural/src/procedural/Procedural.cpp | 8 ++-- .../src/AmbientOcclusionEffect.cpp | 32 +++++++------- libraries/render-utils/src/AnimDebugDraw.cpp | 8 ++-- .../render-utils/src/AntialiasingEffect.cpp | 16 +++---- .../src/DeferredLightingEffect.cpp | 22 +++++----- libraries/render-utils/src/Environment.cpp | 8 ++-- libraries/render-utils/src/GeometryCache.cpp | 12 +++--- libraries/render-utils/src/HitEffect.cpp | 8 ++-- libraries/render-utils/src/ModelRender.cpp | 42 +++++++++---------- .../render-utils/src/RenderDeferredTask.cpp | 14 +++---- libraries/render-utils/src/text/Font.cpp | 8 ++-- libraries/render/src/render/DrawStatus.cpp | 16 +++---- tests/gpu-test/src/main.cpp | 8 ++-- tests/render-utils/src/main.cpp | 6 +-- tests/shaders/src/main.cpp | 6 +-- 25 files changed, 163 insertions(+), 168 deletions(-) diff --git a/interface/src/Stars.cpp b/interface/src/Stars.cpp index 6145529b52..c8fd5188e2 100644 --- a/interface/src/Stars.cpp +++ b/interface/src/Stars.cpp @@ -130,9 +130,9 @@ void Stars::render(RenderArgs* renderArgs, float alpha) { std::call_once(once, [&] { { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(standardTransformPNTC_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(starsGrid_frag))); - auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)); + auto ps = gpu::Shader::createPixel(std::string(starsGrid_frag)); + auto program = gpu::Shader::createProgram(vs, ps); gpu::Shader::makeProgram((*program)); _timeSlot = program->getBuffers().findLocation(UNIFORM_TIME_NAME); if (_timeSlot == gpu::Shader::INVALID_LOCATION) { @@ -143,12 +143,12 @@ void Stars::render(RenderArgs* renderArgs, float alpha) { state->setDepthTest(gpu::State::DepthTest(false)); state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); - _gridPipeline.reset(gpu::Pipeline::create(program, state)); + _gridPipeline = gpu::Pipeline::create(program, state); } { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(stars_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(stars_frag))); - auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(stars_vert)); + auto ps = gpu::Shader::createPixel(std::string(stars_frag)); + auto program = gpu::Shader::createProgram(vs, ps); gpu::Shader::makeProgram((*program)); auto state = gpu::StatePointer(new gpu::State()); // enable decal blend @@ -156,7 +156,7 @@ void Stars::render(RenderArgs* renderArgs, float alpha) { state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); state->setAntialiasedLineEnable(true); // line smoothing also smooth points state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); - _starsPipeline.reset(gpu::Pipeline::create(program, state)); + _starsPipeline = gpu::Pipeline::create(program, state); } diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 05fca343fd..787b04811b 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -334,10 +334,10 @@ void RenderableParticleEffectEntityItem::createPipelines() { state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, destinationColorBlendArg, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - auto vertShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(untextured_particle_vert))); - auto fragShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(untextured_particle_frag))); - auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vertShader, fragShader)); - _untexturedPipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + auto vertShader = gpu::Shader::createVertex(std::string(untextured_particle_vert)); + auto fragShader = gpu::Shader::createPixel(std::string(untextured_particle_frag)); + auto program = gpu::Shader::createProgram(vertShader, fragShader); + _untexturedPipeline = gpu::Pipeline::create(program, state); } if (!_texturedPipeline) { auto state = std::make_shared(); @@ -349,17 +349,16 @@ void RenderableParticleEffectEntityItem::createPipelines() { state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, destinationColorBlendArg, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - auto vertShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(textured_particle_vert))); + auto vertShader = gpu::Shader::createVertex(std::string(textured_particle_vert)); gpu::ShaderPointer fragShader; if (_additiveBlending) { - fragShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(textured_particle_frag))); + fragShader = gpu::Shader::createPixel(std::string(textured_particle_frag)); } else { //If we are sorting and have no additive blending, we want to discard pixels with low alpha to avoid inter-particle entity artifacts - fragShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(textured_particle_alpha_discard_frag))); + fragShader = gpu::Shader::createPixel(std::string(textured_particle_alpha_discard_frag)); } - auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vertShader, fragShader)); - _texturedPipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); - + auto program = gpu::Shader::createProgram(vertShader, fragShader); + _texturedPipeline = gpu::Pipeline::create(program, state); } } diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index 036d37a95b..30b1544e15 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -50,9 +50,9 @@ void RenderablePolyLineEntityItem::createPipeline() { _format->setAttribute(gpu::Stream::COLOR, 0, gpu::Element::COLOR_RGBA_32, COLOR_OFFSET); _format->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), TEXTURE_OFFSET); - auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(paintStroke_vert))); - auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(paintStroke_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS)); + auto VS = gpu::Shader::createVertex(std::string(paintStroke_vert)); + auto PS = gpu::Shader::createPixel(std::string(paintStroke_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(VS, PS); gpu::Shader::BindingSet slotBindings; PAINTSTROKE_GPU_SLOT = 0; @@ -64,7 +64,7 @@ void RenderablePolyLineEntityItem::createPipeline() { state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + _pipeline = gpu::Pipeline::create(program, state); } void RenderablePolyLineEntityItem::updateGeometry() { diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 16252eb453..c38378fc7c 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -477,8 +477,8 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { _meshLock.unlock(); if (!_pipeline) { - gpu::ShaderPointer vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(polyvox_vert))); - gpu::ShaderPointer pixelShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(polyvox_frag))); + gpu::ShaderPointer vertexShader = gpu::Shader::createVertex(std::string(polyvox_vert)); + gpu::ShaderPointer pixelShader = gpu::Shader::createPixel(std::string(polyvox_frag)); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), MATERIAL_GPU_SLOT)); @@ -486,14 +486,14 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { slotBindings.insert(gpu::Shader::Binding(std::string("yMap"), 1)); slotBindings.insert(gpu::Shader::Binding(std::string("zMap"), 2)); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader); gpu::Shader::makeProgram(*program, slotBindings); auto state = std::make_shared(); state->setCullMode(gpu::State::CULL_BACK); state->setDepthTest(true, true, gpu::LESS_EQUAL); - _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + _pipeline = gpu::Pipeline::create(program, state); } gpu::Batch& batch = *args->_batch; diff --git a/libraries/gpu/src/gpu/Pipeline.cpp b/libraries/gpu/src/gpu/Pipeline.cpp index 501cb3fea4..e5d991f181 100755 --- a/libraries/gpu/src/gpu/Pipeline.cpp +++ b/libraries/gpu/src/gpu/Pipeline.cpp @@ -15,9 +15,7 @@ using namespace gpu; -Pipeline::Pipeline(): - _program(), - _state() +Pipeline::Pipeline() { } @@ -25,8 +23,8 @@ Pipeline::~Pipeline() { } -Pipeline* Pipeline::create(const ShaderPointer& program, const StatePointer& state) { - Pipeline* pipeline = new Pipeline(); +Pipeline::Pointer Pipeline::create(const ShaderPointer& program, const StatePointer& state) { + auto pipeline = Pointer(new Pipeline()); pipeline->_program = program; pipeline->_state = state; diff --git a/libraries/gpu/src/gpu/Pipeline.h b/libraries/gpu/src/gpu/Pipeline.h index 73e9a29913..adc65a0c66 100755 --- a/libraries/gpu/src/gpu/Pipeline.h +++ b/libraries/gpu/src/gpu/Pipeline.h @@ -22,7 +22,9 @@ namespace gpu { class Pipeline { public: - static Pipeline* create(const ShaderPointer& program, const StatePointer& state); + using Pointer = std::shared_ptr< Pipeline >; + + static Pointer create(const ShaderPointer& program, const StatePointer& state); ~Pipeline(); const ShaderPointer& getProgram() const { return _program; } @@ -44,7 +46,7 @@ protected: friend class Backend; }; -typedef std::shared_ptr< Pipeline > PipelinePointer; +typedef Pipeline::Pointer PipelinePointer; typedef std::vector< PipelinePointer > Pipelines; }; diff --git a/libraries/gpu/src/gpu/Shader.cpp b/libraries/gpu/src/gpu/Shader.cpp index 60bcbdaed0..ddb3a0d755 100755 --- a/libraries/gpu/src/gpu/Shader.cpp +++ b/libraries/gpu/src/gpu/Shader.cpp @@ -36,24 +36,20 @@ Shader::~Shader() { } -Shader* Shader::createVertex(const Source& source) { - Shader* shader = new Shader(VERTEX, source); - return shader; +Shader::Pointer Shader::createVertex(const Source& source) { + return Pointer(new Shader(VERTEX, source)); } -Shader* Shader::createPixel(const Source& source) { - Shader* shader = new Shader(PIXEL, source); - return shader; +Shader::Pointer Shader::createPixel(const Source& source) { + return Pointer(new Shader(PIXEL, source)); } -Shader* Shader::createProgram(Pointer& vertexShader, Pointer& pixelShader) { - if (vertexShader && vertexShader->getType() == VERTEX) { - if (pixelShader && pixelShader->getType() == PIXEL) { - Shader* shader = new Shader(PROGRAM, vertexShader, pixelShader); - return shader; - } +Shader::Pointer Shader::createProgram(Pointer& vertexShader, Pointer& pixelShader) { + if (vertexShader && vertexShader->getType() == VERTEX && + pixelShader && pixelShader->getType() == PIXEL) { + return Pointer(new Shader(PROGRAM, vertexShader, pixelShader)); } - return nullptr; + return Pointer(); } void Shader::defineSlots(const SlotSet& uniforms, const SlotSet& buffers, const SlotSet& textures, const SlotSet& samplers, const SlotSet& inputs, const SlotSet& outputs) { diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h index 55812c6166..bceb00c71e 100755 --- a/libraries/gpu/src/gpu/Shader.h +++ b/libraries/gpu/src/gpu/Shader.h @@ -108,10 +108,10 @@ public: PROGRAM, }; - static Shader* createVertex(const Source& source); - static Shader* createPixel(const Source& source); + static Pointer createVertex(const Source& source); + static Pointer createPixel(const Source& source); - static Shader* createProgram(Pointer& vertexShader, Pointer& pixelShader); + static Pointer createProgram(Pointer& vertexShader, Pointer& pixelShader); ~Shader(); diff --git a/libraries/gpu/src/gpu/StandardShaderLib.cpp b/libraries/gpu/src/gpu/StandardShaderLib.cpp index 864bff08c9..81500347fd 100755 --- a/libraries/gpu/src/gpu/StandardShaderLib.cpp +++ b/libraries/gpu/src/gpu/StandardShaderLib.cpp @@ -39,7 +39,7 @@ ShaderPointer StandardShaderLib::getProgram(GetShader getVS, GetShader getPS) { } else { auto vs = (getVS)(); auto ps = (getPS)(); - auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto program = gpu::Shader::createProgram(vs, ps); if (program) { // Program created, let's try to make it if (gpu::Shader::makeProgram((*program))) { @@ -59,42 +59,42 @@ ShaderPointer StandardShaderLib::getProgram(GetShader getVS, GetShader getPS) { ShaderPointer StandardShaderLib::getDrawUnitQuadTexcoordVS() { if (!_drawUnitQuadTexcoordVS) { - _drawUnitQuadTexcoordVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(DrawUnitQuadTexcoord_vert))); + _drawUnitQuadTexcoordVS = gpu::Shader::createVertex(std::string(DrawUnitQuadTexcoord_vert)); } return _drawUnitQuadTexcoordVS; } ShaderPointer StandardShaderLib::getDrawTransformUnitQuadVS() { if (!_drawTransformUnitQuadVS) { - _drawTransformUnitQuadVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(DrawTransformUnitQuad_vert))); + _drawTransformUnitQuadVS = gpu::Shader::createVertex(std::string(DrawTransformUnitQuad_vert)); } return _drawTransformUnitQuadVS; } ShaderPointer StandardShaderLib::getDrawTexcoordRectTransformUnitQuadVS() { if (!_drawTexcoordRectTransformUnitQuadVS) { - _drawTexcoordRectTransformUnitQuadVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(DrawTexcoordRectTransformUnitQuad_vert))); + _drawTexcoordRectTransformUnitQuadVS = gpu::Shader::createVertex(std::string(DrawTexcoordRectTransformUnitQuad_vert)); } return _drawTexcoordRectTransformUnitQuadVS; } ShaderPointer StandardShaderLib::getDrawViewportQuadTransformTexcoordVS() { if (!_drawViewportQuadTransformTexcoordVS) { - _drawViewportQuadTransformTexcoordVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(DrawViewportQuadTransformTexcoord_vert))); + _drawViewportQuadTransformTexcoordVS = gpu::Shader::createVertex(std::string(DrawViewportQuadTransformTexcoord_vert)); } return _drawViewportQuadTransformTexcoordVS; } ShaderPointer StandardShaderLib::getDrawTexturePS() { if (!_drawTexturePS) { - _drawTexturePS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(DrawTexture_frag))); + _drawTexturePS = gpu::Shader::createPixel(std::string(DrawTexture_frag)); } return _drawTexturePS; } ShaderPointer StandardShaderLib::getDrawTextureOpaquePS() { if (!_drawTextureOpaquePS) { - _drawTextureOpaquePS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(DrawTextureOpaque_frag))); + _drawTextureOpaquePS = gpu::Shader::createPixel(std::string(DrawTextureOpaque_frag)); } return _drawTextureOpaquePS; } @@ -103,7 +103,7 @@ ShaderPointer StandardShaderLib::getDrawTextureOpaquePS() { ShaderPointer StandardShaderLib::getDrawColoredTexturePS() { if (!_drawColoredTexturePS) { - _drawColoredTexturePS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(DrawColoredTexture_frag))); + _drawColoredTexturePS = gpu::Shader::createPixel(std::string(DrawColoredTexture_frag)); } return _drawColoredTexturePS; } diff --git a/libraries/model/src/model/Skybox.cpp b/libraries/model/src/model/Skybox.cpp index 21b40a54c8..3e445933fa 100755 --- a/libraries/model/src/model/Skybox.cpp +++ b/libraries/model/src/model/Skybox.cpp @@ -88,9 +88,9 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky } { - auto skyVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(Skybox_vert))); - auto skyFS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(Skybox_frag))); - auto skyShader = gpu::ShaderPointer(gpu::Shader::createProgram(skyVS, skyFS)); + auto skyVS = gpu::Shader::createVertex(std::string(Skybox_vert)); + auto skyFS = gpu::Shader::createPixel(std::string(Skybox_frag)); + auto skyShader = gpu::Shader::createProgram(skyVS, skyFS); gpu::Shader::BindingSet bindings; bindings.insert(gpu::Shader::Binding(std::string("cubeMap"), SKYBOX_SKYMAP_SLOT)); @@ -102,7 +102,7 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky auto skyState = std::make_shared(); skyState->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP)); - thePipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, skyState)); + thePipeline = gpu::Pipeline::create(skyShader, skyState); } }); diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index a0020d21f3..69a433d5e1 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -170,7 +170,7 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm if (!_pipeline || _pipelineDirty) { _pipelineDirty = true; if (!_vertexShader) { - _vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(_vertexSource)); + _vertexShader = gpu::Shader::createVertex(_vertexSource); } // Build the fragment shader @@ -193,8 +193,8 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm fragmentShaderSource.replace(replaceIndex, PROCEDURAL_BLOCK.size(), _shaderSource.toLocal8Bit().data()); } //qDebug() << "FragmentShader:\n" << fragmentShaderSource.c_str(); - _fragmentShader = gpu::ShaderPointer(gpu::Shader::createPixel(fragmentShaderSource)); - _shader = gpu::ShaderPointer(gpu::Shader::createProgram(_vertexShader, _fragmentShader)); + _fragmentShader = gpu::Shader::createPixel(fragmentShaderSource); + _shader = gpu::Shader::createProgram(_vertexShader, _fragmentShader); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("iChannel0"), 0)); @@ -203,7 +203,7 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm slotBindings.insert(gpu::Shader::Binding(std::string("iChannel3"), 3)); gpu::Shader::makeProgram(*_shader, slotBindings); - _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(_shader, _state)); + _pipeline = gpu::Pipeline::create(_shader, _state); for (size_t i = 0; i < NUM_STANDARD_UNIFORMS; ++i) { const std::string& name = STANDARD_UNIFORM_NAMES[i]; _standardUniformSlots[i] = _shader->getUniforms().findLocation(name); diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 456a6430a7..e54f55fc94 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -37,9 +37,9 @@ AmbientOcclusion::AmbientOcclusion() { const gpu::PipelinePointer& AmbientOcclusion::getOcclusionPipeline() { if (!_occlusionPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(ambient_occlusion_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(ambient_occlusion_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(ambient_occlusion_vert)); + auto ps = gpu::Shader::createPixel(std::string(ambient_occlusion_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("depthTexture"), 0)); @@ -78,16 +78,16 @@ const gpu::PipelinePointer& AmbientOcclusion::getOcclusionPipeline() { _occlusionTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); // Good to go add the brand new pipeline - _occlusionPipeline.reset(gpu::Pipeline::create(program, state)); + _occlusionPipeline = gpu::Pipeline::create(program, state); } return _occlusionPipeline; } const gpu::PipelinePointer& AmbientOcclusion::getVBlurPipeline() { if (!_vBlurPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(gaussian_blur_vertical_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(gaussian_blur_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(gaussian_blur_vertical_vert)); + auto ps = gpu::Shader::createPixel(std::string(gaussian_blur_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; gpu::Shader::makeProgram(*program, slotBindings); @@ -111,16 +111,16 @@ const gpu::PipelinePointer& AmbientOcclusion::getVBlurPipeline() { _vBlurTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); // Good to go add the brand new pipeline - _vBlurPipeline.reset(gpu::Pipeline::create(program, state)); + _vBlurPipeline = gpu::Pipeline::create(program, state); } return _vBlurPipeline; } const gpu::PipelinePointer& AmbientOcclusion::getHBlurPipeline() { if (!_hBlurPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(gaussian_blur_horizontal_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(gaussian_blur_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(gaussian_blur_horizontal_vert)); + auto ps = gpu::Shader::createPixel(std::string(gaussian_blur_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; gpu::Shader::makeProgram(*program, slotBindings); @@ -144,16 +144,16 @@ const gpu::PipelinePointer& AmbientOcclusion::getHBlurPipeline() { _hBlurTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); // Good to go add the brand new pipeline - _hBlurPipeline.reset(gpu::Pipeline::create(program, state)); + _hBlurPipeline = gpu::Pipeline::create(program, state); } return _hBlurPipeline; } const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() { if (!_blendPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(ambient_occlusion_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(occlusion_blend_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(ambient_occlusion_vert)); + auto ps = gpu::Shader::createPixel(std::string(occlusion_blend_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("blurredOcclusionTexture"), 0)); @@ -169,7 +169,7 @@ const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() { gpu::State::INV_SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::SRC_ALPHA); // Good to go add the brand new pipeline - _blendPipeline.reset(gpu::Pipeline::create(program, state)); + _blendPipeline = gpu::Pipeline::create(program, state); } return _blendPipeline; } diff --git a/libraries/render-utils/src/AnimDebugDraw.cpp b/libraries/render-utils/src/AnimDebugDraw.cpp index d110576c0d..d17676fe90 100644 --- a/libraries/render-utils/src/AnimDebugDraw.cpp +++ b/libraries/render-utils/src/AnimDebugDraw.cpp @@ -95,10 +95,10 @@ AnimDebugDraw::AnimDebugDraw() : state->setBlendFunction(false, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - auto vertShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(animdebugdraw_vert))); - auto fragShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(animdebugdraw_frag))); - auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vertShader, fragShader)); - _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + auto vertShader = gpu::Shader::createVertex(std::string(animdebugdraw_vert)); + auto fragShader = gpu::Shader::createPixel(std::string(animdebugdraw_frag)); + auto program = gpu::Shader::createProgram(vertShader, fragShader); + _pipeline = gpu::Pipeline::create(program, state); _animDebugDrawData = std::make_shared(); _animDebugDrawPayload = std::make_shared(_animDebugDrawData); diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp index aaef67542f..d4707c172d 100644 --- a/libraries/render-utils/src/AntialiasingEffect.cpp +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -34,9 +34,9 @@ Antialiasing::Antialiasing() { const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() { if (!_antialiasingPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(fxaa_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(fxaa_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(fxaa_vert)); + auto ps = gpu::Shader::createPixel(std::string(fxaa_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("colorTexture"), 0)); @@ -59,7 +59,7 @@ const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() { _antialiasingTexture = gpu::TexturePointer(gpu::Texture::create2D(format, width, height, defaultSampler)); // Good to go add the brand new pipeline - _antialiasingPipeline.reset(gpu::Pipeline::create(program, state)); + _antialiasingPipeline = gpu::Pipeline::create(program, state); } int w = DependencyManager::get()->getFrameBufferSize().width(); @@ -73,9 +73,9 @@ const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() { const gpu::PipelinePointer& Antialiasing::getBlendPipeline() { if (!_blendPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(fxaa_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(fxaa_blend_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(fxaa_vert)); + auto ps = gpu::Shader::createPixel(std::string(fxaa_blend_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("colorTexture"), 0)); @@ -87,7 +87,7 @@ const gpu::PipelinePointer& Antialiasing::getBlendPipeline() { state->setDepthTest(false, false, gpu::LESS_EQUAL); // Good to go add the brand new pipeline - _blendPipeline.reset(gpu::Pipeline::create(program, state)); + _blendPipeline = gpu::Pipeline::create(program, state); } return _blendPipeline; } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 57e3129ef8..342471454d 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -87,18 +87,18 @@ gpu::PipelinePointer DeferredLightingEffect::getPipeline(SimpleProgramKey config gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader; - gpu::PipelinePointer pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + gpu::PipelinePointer pipeline = gpu::Pipeline::create(program, state); _simplePrograms.insert(config, pipeline); return pipeline; } void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { - auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(simple_vert))); - auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_textured_frag))); - auto PSEmissive = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_textured_emisive_frag))); + auto VS = gpu::Shader::createVertex(std::string(simple_vert)); + auto PS = gpu::Shader::createPixel(std::string(simple_textured_frag)); + auto PSEmissive = gpu::Shader::createPixel(std::string(simple_textured_emisive_frag)); - _simpleShader = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS)); - _emissiveShader = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PSEmissive)); + _simpleShader = gpu::Shader::createProgram(VS, PS); + _emissiveShader = gpu::Shader::createProgram(VS, PSEmissive); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT)); @@ -150,7 +150,7 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); blitState->setColorWriteMask(true, true, true, false); - _blitLightBuffer = gpu::PipelinePointer(gpu::Pipeline::create(blitProgram, blitState)); + _blitLightBuffer = gpu::Pipeline::create(blitProgram, blitState); } // Allocate a global light representing the Global Directional light casting shadow (the sun) and the ambient light @@ -721,10 +721,10 @@ void DeferredLightingEffect::setupTransparent(RenderArgs* args, int lightBufferU } static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& pipeline, LightLocationsPtr& locations) { - auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(vertSource))); - auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(fragSource))); + auto VS = gpu::Shader::createVertex(std::string(vertSource)); + auto PS = gpu::Shader::createPixel(std::string(fragSource)); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS)); + gpu::ShaderPointer program = gpu::Shader::createProgram(VS, PS); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), 0)); @@ -769,7 +769,7 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo } else { state->setCullMode(gpu::State::CULL_BACK); } - pipeline.reset(gpu::Pipeline::create(program, state)); + pipeline = gpu::Pipeline::create(program, state); } diff --git a/libraries/render-utils/src/Environment.cpp b/libraries/render-utils/src/Environment.cpp index b26d402fa3..f7327a2b72 100644 --- a/libraries/render-utils/src/Environment.cpp +++ b/libraries/render-utils/src/Environment.cpp @@ -51,10 +51,10 @@ void Environment::init() { void Environment::setupAtmosphereProgram(const char* vertSource, const char* fragSource, gpu::PipelinePointer& pipeline, int* locations) { - auto VS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(vertSource))); - auto PS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(fragSource))); + auto VS = gpu::Shader::createVertex(std::string(vertSource)); + auto PS = gpu::Shader::createPixel(std::string(fragSource)); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(VS, PS)); + gpu::ShaderPointer program = gpu::Shader::createProgram(VS, PS); gpu::Shader::BindingSet slotBindings; gpu::Shader::makeProgram(*program, slotBindings); @@ -67,7 +67,7 @@ void Environment::setupAtmosphereProgram(const char* vertSource, const char* fra gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + pipeline = gpu::Pipeline::create(program, state); locations[CAMERA_POS_LOCATION] = program->getUniforms().findLocation("v3CameraPos"); locations[LIGHT_POS_LOCATION] = program->getUniforms().findLocation("v3LightPos"); diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index eed52fccbc..75b3b91c10 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -1701,9 +1701,9 @@ void GeometryCache::renderLine(gpu::Batch& batch, const glm::vec2& p1, const glm void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { if (!_standardDrawPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(standardTransformPNTC_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(standardDrawTexture_frag))); - auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(standardTransformPNTC_vert)); + auto ps = gpu::Shader::createPixel(std::string(standardDrawTexture_frag)); + auto program = gpu::Shader::createProgram(vs, ps); gpu::Shader::makeProgram((*program)); auto state = std::make_shared(); @@ -1712,14 +1712,14 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { // enable decal blend state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); - _standardDrawPipeline.reset(gpu::Pipeline::create(program, state)); + _standardDrawPipeline = gpu::Pipeline::create(program, state); auto stateNoBlend = std::make_shared(); auto noBlendPS = gpu::StandardShaderLib::getDrawTextureOpaquePS(); - auto programNoBlend = gpu::ShaderPointer(gpu::Shader::createProgram(vs, noBlendPS)); + auto programNoBlend = gpu::Shader::createProgram(vs, noBlendPS); gpu::Shader::makeProgram((*programNoBlend)); - _standardDrawPipelineNoBlend.reset(gpu::Pipeline::create(programNoBlend, stateNoBlend)); + _standardDrawPipelineNoBlend = gpu::Pipeline::create(programNoBlend, stateNoBlend); } if (noBlend) { batch.setPipeline(_standardDrawPipelineNoBlend); diff --git a/libraries/render-utils/src/HitEffect.cpp b/libraries/render-utils/src/HitEffect.cpp index 06bd07b456..7e8b5f5fa0 100644 --- a/libraries/render-utils/src/HitEffect.cpp +++ b/libraries/render-utils/src/HitEffect.cpp @@ -36,9 +36,9 @@ HitEffect::HitEffect() { const gpu::PipelinePointer& HitEffect::getHitEffectPipeline() { if (!_hitEffectPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(hit_effect_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(hit_effect_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(hit_effect_vert)); + auto ps = gpu::Shader::createPixel(std::string(hit_effect_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; @@ -54,7 +54,7 @@ const gpu::PipelinePointer& HitEffect::getHitEffectPipeline() { gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); // Good to go add the brand new pipeline - _hitEffectPipeline.reset(gpu::Pipeline::create(program, state)); + _hitEffectPipeline = gpu::Pipeline::create(program, state); } return _hitEffectPipeline; } diff --git a/libraries/render-utils/src/ModelRender.cpp b/libraries/render-utils/src/ModelRender.cpp index c614fae67a..73f3d715b6 100644 --- a/libraries/render-utils/src/ModelRender.cpp +++ b/libraries/render-utils/src/ModelRender.cpp @@ -42,26 +42,26 @@ ModelRender::RenderPipelineLib ModelRender::_renderPipelineLib; const ModelRender::RenderPipelineLib& ModelRender::getRenderPipelineLib() { if (_renderPipelineLib.empty()) { // Vertex shaders - auto modelVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_vert))); - auto modelNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_normal_map_vert))); - auto modelLightmapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_lightmap_vert))); - auto modelLightmapNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert))); - auto modelShadowVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_shadow_vert))); - auto skinModelVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_vert))); - auto skinModelNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_normal_map_vert))); - auto skinModelShadowVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_shadow_vert))); + auto modelVertex = gpu::Shader::createVertex(std::string(model_vert)); + auto modelNormalMapVertex = gpu::Shader::createVertex(std::string(model_normal_map_vert)); + auto modelLightmapVertex = gpu::Shader::createVertex(std::string(model_lightmap_vert)); + auto modelLightmapNormalMapVertex = gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert)); + auto modelShadowVertex = gpu::Shader::createVertex(std::string(model_shadow_vert)); + auto skinModelVertex = gpu::Shader::createVertex(std::string(skin_model_vert)); + auto skinModelNormalMapVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_vert)); + auto skinModelShadowVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert)); // Pixel shaders - auto modelPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_frag))); - auto modelNormalMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_normal_map_frag))); - auto modelSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_specular_map_frag))); - auto modelNormalSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_normal_specular_map_frag))); - auto modelTranslucentPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_translucent_frag))); - auto modelShadowPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_shadow_frag))); - auto modelLightmapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_frag))); - auto modelLightmapNormalMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag))); - auto modelLightmapSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag))); - auto modelLightmapNormalSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag))); + auto modelPixel = gpu::Shader::createPixel(std::string(model_frag)); + auto modelNormalMapPixel = gpu::Shader::createPixel(std::string(model_normal_map_frag)); + auto modelSpecularMapPixel = gpu::Shader::createPixel(std::string(model_specular_map_frag)); + auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_frag)); + auto modelTranslucentPixel = gpu::Shader::createPixel(std::string(model_translucent_frag)); + auto modelShadowPixel = gpu::Shader::createPixel(std::string(model_shadow_frag)); + auto modelLightmapPixel = gpu::Shader::createPixel(std::string(model_lightmap_frag)); + auto modelLightmapNormalMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag)); + auto modelLightmapSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag)); + auto modelLightmapNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag)); // Fill the renderPipelineLib @@ -181,7 +181,7 @@ void ModelRender::RenderPipelineLib::addRenderPipeline(ModelRender::RenderKey ke slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), ModelRender::LIGHT_BUFFER_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT)); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader); gpu::Shader::makeProgram(*program, slotBindings); @@ -209,7 +209,7 @@ void ModelRender::RenderPipelineLib::addRenderPipeline(ModelRender::RenderKey ke gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); // Good to go add the brand new pipeline - auto pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + auto pipeline = gpu::Pipeline::create(program, state); insert(value_type(key.getRaw(), RenderPipeline(pipeline, locations))); @@ -221,7 +221,7 @@ void ModelRender::RenderPipelineLib::addRenderPipeline(ModelRender::RenderKey ke wireframeState->setFillMode(gpu::State::FILL_LINE); // create a new RenderPipeline with the same shader side and the wireframe state - auto wireframePipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, wireframeState)); + auto wireframePipeline = gpu::Pipeline::create(program, wireframeState); insert(value_type(wireframeKey.getRaw(), RenderPipeline(wireframePipeline, locations))); } } diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index e65018ad3d..1430651c86 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -231,16 +231,16 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const gpu::PipelinePointer DrawOverlay3D::_opaquePipeline; const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() { if (!_opaquePipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(overlay3D_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(overlay3D_frag))); - auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(overlay3D_vert)); + auto ps = gpu::Shader::createPixel(std::string(overlay3D_frag)); + auto program = gpu::Shader::createProgram(vs, ps); auto state = std::make_shared(); state->setDepthTest(false); // additive blending state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - _opaquePipeline.reset(gpu::Pipeline::create(program, state)); + _opaquePipeline = gpu::Pipeline::create(program, state); } return _opaquePipeline; } @@ -307,8 +307,8 @@ const gpu::PipelinePointer& DrawStencilDeferred::getOpaquePipeline() { if (!_opaquePipeline) { const gpu::int8 STENCIL_OPAQUE = 1; auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS(); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(drawOpaqueStencil_frag))); - auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto ps = gpu::Shader::createPixel(std::string(drawOpaqueStencil_frag)); + auto program = gpu::Shader::createProgram(vs, ps); gpu::Shader::makeProgram((*program)); @@ -318,7 +318,7 @@ const gpu::PipelinePointer& DrawStencilDeferred::getOpaquePipeline() { state->setStencilTest(true, 0xFF, gpu::State::StencilTest(STENCIL_OPAQUE, 0xFF, gpu::ALWAYS, gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_REPLACE)); state->setColorWriteMask(0); - _opaquePipeline.reset(gpu::Pipeline::create(program, state)); + _opaquePipeline = gpu::Pipeline::create(program, state); } return _opaquePipeline; } diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp index 0157d873d3..5587185ead 100644 --- a/libraries/render-utils/src/text/Font.cpp +++ b/libraries/render-utils/src/text/Font.cpp @@ -216,9 +216,9 @@ void Font::setupGPU() { // Setup render pipeline { - auto vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(sdf_text3D_vert))); - auto pixelShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(sdf_text3D_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader)); + auto vertexShader = gpu::Shader::createVertex(std::string(sdf_text3D_vert)); + auto pixelShader = gpu::Shader::createPixel(std::string(sdf_text3D_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader); gpu::Shader::BindingSet slotBindings; gpu::Shader::makeProgram(*program, slotBindings); @@ -233,7 +233,7 @@ void Font::setupGPU() { state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + _pipeline = gpu::Pipeline::create(program, state); } // Sanity checks diff --git a/libraries/render/src/render/DrawStatus.cpp b/libraries/render/src/render/DrawStatus.cpp index 5e8fd74e5f..3f37ce378b 100644 --- a/libraries/render/src/render/DrawStatus.cpp +++ b/libraries/render/src/render/DrawStatus.cpp @@ -31,9 +31,9 @@ using namespace render; const gpu::PipelinePointer DrawStatus::getDrawItemBoundsPipeline() { if (!_drawItemBoundsPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(drawItemBounds_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(drawItemBounds_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(drawItemBounds_vert)); + auto ps = gpu::Shader::createPixel(std::string(drawItemBounds_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; gpu::Shader::makeProgram(*program, slotBindings); @@ -51,16 +51,16 @@ const gpu::PipelinePointer DrawStatus::getDrawItemBoundsPipeline() { gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); // Good to go add the brand new pipeline - _drawItemBoundsPipeline.reset(gpu::Pipeline::create(program, state)); + _drawItemBoundsPipeline = gpu::Pipeline::create(program, state); } return _drawItemBoundsPipeline; } const gpu::PipelinePointer DrawStatus::getDrawItemStatusPipeline() { if (!_drawItemStatusPipeline) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(drawItemStatus_vert))); - auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(drawItemStatus_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps)); + auto vs = gpu::Shader::createVertex(std::string(drawItemStatus_vert)); + auto ps = gpu::Shader::createPixel(std::string(drawItemStatus_frag)); + gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("iconStatusMap"), 0)); @@ -81,7 +81,7 @@ const gpu::PipelinePointer DrawStatus::getDrawItemStatusPipeline() { gpu::State::DEST_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ZERO); // Good to go add the brand new pipeline - _drawItemStatusPipeline.reset(gpu::Pipeline::create(program, state)); + _drawItemStatusPipeline = gpu::Pipeline::create(program, state); } return _drawItemStatusPipeline; } diff --git a/tests/gpu-test/src/main.cpp b/tests/gpu-test/src/main.cpp index 80c2dbf8e9..47ed582f3c 100644 --- a/tests/gpu-test/src/main.cpp +++ b/tests/gpu-test/src/main.cpp @@ -85,9 +85,9 @@ public: uint32_t toCompactColor(const glm::vec4& color); gpu::ShaderPointer makeShader(const std::string & vertexShaderSrc, const std::string & fragmentShaderSrc, const gpu::Shader::BindingSet & bindings) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(vertexShaderSrc)); - auto fs = gpu::ShaderPointer(gpu::Shader::createPixel(fragmentShaderSrc)); - auto shader = gpu::ShaderPointer(gpu::Shader::createProgram(vs, fs)); + auto vs = gpu::Shader::createVertex(vertexShaderSrc); + auto fs = gpu::Shader::createPixel(fragmentShaderSrc); + auto shader = gpu::Shader::createProgram(vs, fs); if (!gpu::Shader::makeProgram(*shader, bindings)) { printf("Could not compile shader\n"); exit(-1); @@ -172,7 +172,7 @@ public: auto state = std::make_shared(); state->setMultisampleEnable(true); state->setDepthTest(gpu::State::DepthTest { true }); - _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(shader, state)); + _pipeline = gpu::Pipeline::create(shader, state); _instanceLocation = _pipeline->getProgram()->getUniforms().findLocation("Instanced"); // Clear screen diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index 0fa261db8d..7ae2bd1166 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -170,9 +170,9 @@ static const glm::vec3 COLORS[4] = { { 1.0, 1.0, 1.0 }, { 0.5, 1.0, 0.5 }, { void testShaderBuild(const char* vs_src, const char * fs_src) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(vs_src))); - auto fs = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(fs_src))); - auto pr = gpu::ShaderPointer(gpu::Shader::createProgram(vs, fs)); + auto vs = gpu::Shader::createVertex(std::string(vs_src)); + auto fs = gpu::Shader::createPixel(std::string(fs_src)); + auto pr = gpu::Shader::createProgram(vs, fs); gpu::Shader::makeProgram(*pr); } diff --git a/tests/shaders/src/main.cpp b/tests/shaders/src/main.cpp index 3edff67d66..f162aae89a 100644 --- a/tests/shaders/src/main.cpp +++ b/tests/shaders/src/main.cpp @@ -160,9 +160,9 @@ public: }; void testShaderBuild(const char* vs_src, const char * fs_src) { - auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(vs_src))); - auto fs = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(fs_src))); - auto pr = gpu::ShaderPointer(gpu::Shader::createProgram(vs, fs)); + auto vs = gpu::Shader::createVertex(std::string(vs_src)); + auto fs = gpu::Shader::createPixel(std::string(fs_src)); + auto pr = gpu::Shader::createProgram(vs, fs); if (!gpu::Shader::makeProgram(*pr)) { throw std::runtime_error("Failed to compile shader"); } From a600df5ea646c0e41639e5aed07ac550aad672b4 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 3 Dec 2015 16:04:39 -0800 Subject: [PATCH 307/401] try a different method of exagerating hand motion onto distanly held object --- examples/controllers/handControllerGrab.js | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index ebfa248f58..5763115bfc 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -34,7 +34,7 @@ var BUMPER_ON_VALUE = 0.5; // distant manipulation // -var DISTANCE_HOLDING_RADIUS_FACTOR = 5; // multiplied by distance between hand and object +var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did @@ -659,6 +659,12 @@ function MyController(hand) { this.handRelativePreviousPosition = Vec3.subtract(handControllerPosition, MyAvatar.position); this.handPreviousRotation = handRotation; + // compute a constant based on the initial conditions which we use below to exagerate hand motion onto the held object + this.radiusScalar = Math.log(Vec3.distance(this.currentObjectPosition, handControllerPosition) + 1.0); + if (this.radiusScalar < 1.0) { + this.radiusScalar = 1.0; + } + this.actionID = NULL_ACTION_ID; this.actionID = Entities.addAction("spring", this.grabbedEntity, { targetPosition: this.currentObjectPosition, @@ -689,8 +695,6 @@ function MyController(hand) { this.currentAvatarOrientation = MyAvatar.orientation; this.overlayLineOff(); - - }; this.continueDistanceHolding = function() { @@ -719,8 +723,12 @@ function MyController(hand) { this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); // the action was set up on a previous call. update the targets. - var radius = Math.max(Vec3.distance(this.currentObjectPosition, handControllerPosition) * - DISTANCE_HOLDING_RADIUS_FACTOR, DISTANCE_HOLDING_RADIUS_FACTOR); + var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) * + this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR; + if (radius < 1.0) { + radius = 1.0; + } + // how far did avatar move this timestep? var currentPosition = MyAvatar.position; var avatarDeltaPosition = Vec3.subtract(currentPosition, this.currentAvatarPosition); @@ -751,11 +759,11 @@ function MyController(hand) { var handMoved = Vec3.subtract(handToAvatar, this.handRelativePreviousPosition); this.handRelativePreviousPosition = handToAvatar; - // magnify the hand movement but not the change from avatar movement & rotation + // magnify the hand movement but not the change from avatar movement & rotation handMoved = Vec3.subtract(handMoved, handMovementFromTurning); var superHandMoved = Vec3.multiply(handMoved, radius); - // Move the object by the magnified amount and then by amount from avatar movement & rotation + // Move the object by the magnified amount and then by amount from avatar movement & rotation var newObjectPosition = Vec3.sum(this.currentObjectPosition, superHandMoved); newObjectPosition = Vec3.sum(newObjectPosition, avatarDeltaPosition); newObjectPosition = Vec3.sum(newObjectPosition, objectMovementFromTurning); From 1b42c5a172267efe7e4b7ba92ff586e675e49ded Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Thu, 3 Dec 2015 16:16:01 -0800 Subject: [PATCH 308/401] Make MyAvatar.get/setAnimGraphUrl take a url(!), and make setting it actually do something. --- interface/src/avatar/MyAvatar.cpp | 18 +++++++++++++++--- interface/src/avatar/MyAvatar.h | 6 +++--- interface/src/ui/PreferencesDialog.cpp | 2 +- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index eca39a0a44..1b1dc563c9 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1283,6 +1283,15 @@ void MyAvatar::initHeadBones() { } } +void MyAvatar::setAnimGraphUrl(const QUrl& url) { + if (_animGraphUrl == url) { + return; + } + destroyAnimGraph(); + _animGraphUrl = url; + initAnimGraph(); +} + void MyAvatar::initAnimGraph() { // avatar.json // https://gist.github.com/hyperlogic/7d6a0892a7319c69e2b9 @@ -1299,16 +1308,19 @@ void MyAvatar::initAnimGraph() { // or run a local web-server // python -m SimpleHTTPServer& //auto graphUrl = QUrl("http://localhost:8000/avatar.json"); - auto graphUrl = QUrl(_animGraphUrl.isEmpty() ? - QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_full/avatar-animation.json") : - _animGraphUrl); + auto graphUrl =_animGraphUrl.isEmpty() ? + QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_full/avatar-animation.json") : + QUrl(_animGraphUrl); + qCDebug(interfaceapp) << "*** FIXME initAnimGraph" << graphUrl.toString(); _rig->initAnimGraph(graphUrl); _bodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation.. updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes + qCDebug(interfaceapp) << "*** FIXME initAnimGraph ready" << graphUrl.toString(); } void MyAvatar::destroyAnimGraph() { + qCDebug(interfaceapp) << "*** FIXME destroyAnimGraph" << _animGraphUrl.toString(); _rig->destroyAnimGraph(); } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 13575388e3..3698ac02dc 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -253,13 +253,13 @@ public slots: virtual void rebuildSkeletonBody() override; - const QString& getAnimGraphUrl() const { return _animGraphUrl; } + Q_INVOKABLE QUrl getAnimGraphUrl() const { return _animGraphUrl; } void setEnableDebugDrawDefaultPose(bool isEnabled); void setEnableDebugDrawAnimPose(bool isEnabled); void setEnableDebugDrawPosition(bool isEnabled); void setEnableMeshVisible(bool isEnabled); - void setAnimGraphUrl(const QString& url) { _animGraphUrl = url; } + Q_INVOKABLE void setAnimGraphUrl(const QUrl& url); glm::vec3 getPositionForAudio(); glm::quat getOrientationForAudio(); @@ -360,7 +360,7 @@ private: // Avatar Preferences QUrl _fullAvatarURLFromPreferences; QString _fullAvatarModelName; - QString _animGraphUrl {""}; + QUrl _animGraphUrl {""}; // cache of the current HMD sensor position and orientation // in sensor space. diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index c37755b823..a82fb39be7 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -190,7 +190,7 @@ void PreferencesDialog::loadPreferences() { ui.leanScaleSpin->setValue(myAvatar->getLeanScale()); ui.avatarScaleSpin->setValue(myAvatar->getScale()); - ui.avatarAnimationEdit->setText(myAvatar->getAnimGraphUrl()); + ui.avatarAnimationEdit->setText(myAvatar->getAnimGraphUrl().toString()); ui.maxOctreePPSSpin->setValue(qApp->getMaxOctreePacketsPerSecond()); From 1d01f083240b38796871c83b8fef333a48c0827c Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 3 Dec 2015 16:27:35 -0800 Subject: [PATCH 309/401] Fix compiler warnings --- libraries/audio/src/AudioReverb.cpp | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/libraries/audio/src/AudioReverb.cpp b/libraries/audio/src/AudioReverb.cpp index f06bbe76ed..f9e891ec30 100644 --- a/libraries/audio/src/AudioReverb.cpp +++ b/libraries/audio/src/AudioReverb.cpp @@ -34,6 +34,7 @@ inline static int MULHI(int a, int b) { #endif static const float PHI = 0.6180339887f; // maximum allpass diffusion +static const float TWOPI = 6.283185307f; static const double PI = 3.14159265358979323846; static const double SQRT2 = 1.41421356237309504880; @@ -383,7 +384,7 @@ static void BQPeakAbovePi(double coef[5], double w0, double dbgain, double Q) { // Biquad Peaking EQ using analog matching. // Supports full range of w0. // -static void BQPeak(double coef[5], double w0, double dbgain, double Q) { +void BQPeak(double coef[5], double w0, double dbgain, double Q) { w0 = MAX(w0, 0.0); // allow w0 > pi Q = MIN(MAX(Q, 1.0e-6), 1.0e+6); @@ -402,7 +403,7 @@ static void BQPeak(double coef[5], double w0, double dbgain, double Q) { // // Biquad Shelf using analog matching. // -static void BQShelf(double coef[5], double w0, double dbgain, double resonance, int isHigh) { +void BQShelf(double coef[5], double w0, double dbgain, double resonance, int isHigh) { double G, G1; double wpi, wn, wd; double wna, wda; @@ -499,7 +500,7 @@ static void BQShelf(double coef[5], double w0, double dbgain, double resonance, // Biquad Lowpass/Highpass using analog matching. // Q = sqrt(0.5) = 2nd order Butterworth // -static void BQFilter(double coef[5], double w0, int isHigh) { +void BQFilter(double coef[5], double w0, int isHigh) { double G1; double wpi, wn, wd; double wna, wda; @@ -587,7 +588,7 @@ static void BQFilter(double coef[5], double w0, int isHigh) { // PoleZero Shelf. For Lowpass/Highpass, setCoef dbgain to -100dB. // NOTE: w0 always sets the pole frequency (3dB corner from unity gain) // -static void PZShelf(double coef[3], double w0, double dbgain, int isHigh) { +void PZShelf(double coef[3], double w0, double dbgain, int isHigh) { double G, G0, G1; double b0, b1, a0, a1; double temp, scale; @@ -653,7 +654,7 @@ public: // lowpass filter, -3dB @ freq double coef[5]; - BQFilter(coef, PI * freq / (0.5 * sampleRate), 0); + BQFilter(coef, TWOPI * freq / sampleRate, 0); _b0 = (float)coef[0]; _b1 = (float)coef[1]; _b2 = (float)coef[2]; @@ -661,7 +662,7 @@ public: _a2 = (float)coef[4]; // DC-blocking filter, -3dB @ 10Hz - _alpha = (float)(1.0 - exp(-PI * 10.0 / (0.5 * sampleRate))); + _alpha = 1.0f - expf(-TWOPI * 10.0f / sampleRate); } void process(float input0, float input1, float& output0, float& output1) { @@ -807,11 +808,13 @@ public: freq = MIN(freq, 1/16.0f * sampleRate); freq = MAX(freq, 1/16777216.0f * sampleRate); - // amplitude slightly less than 1.0 - _y0 = (int32_t)(0.000 * FIXQ31); - _y1 = (int32_t)(0.999 * cos(PI * freq / sampleRate) * FIXQ31); + double w = PI * (double)freq / (double)sampleRate; - _k = (int32_t)(2.0 * sin(PI * freq / sampleRate) * FIXQ32); + // amplitude slightly less than 1.0 + _y0 = 0; + _y1 = (int32_t)(0.999 * cos(w) * FIXQ31); + + _k = (int32_t)(2.0 * sin(w) * FIXQ32); } void setGain(int32_t gain) { @@ -985,8 +988,8 @@ public: freq1 = MIN(MAX(freq1, 1.0f), 24000.0f); double coefLo[3], coefHi[3]; - PZShelf(coefLo, PI * freq0 / (0.5 * sampleRate), dBgain0, 0); // low shelf - PZShelf(coefHi, PI * freq1 / (0.5 * sampleRate), dBgain1, 1); // high shelf + PZShelf(coefLo, TWOPI * freq0 / sampleRate, dBgain0, 0); // low shelf + PZShelf(coefHi, TWOPI * freq1 / sampleRate, dBgain1, 1); // high shelf // convolve into a single biquad _b0 = (float)(coefLo[0] * coefHi[0]); @@ -1407,7 +1410,7 @@ void ReverbImpl::setParameters(ReverbParameters *p) { // Modulation _lfo.setFreq(p->modRate, sampleRate); - _lfo.setGain((int32_t)MIN(MAX(p->modDepth * (1/100.0) * FIXQ31, 0.0), 0X7fffffff)); + _lfo.setGain((int32_t)MIN(MAX((double)p->modDepth * (1/100.0) * FIXQ31, 0.0), (double)0x7fffffff)); // // Set delays From 187c213f416bb2a29d9e5f40ea916b3dc863c281 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Thu, 3 Dec 2015 16:42:57 -0800 Subject: [PATCH 310/401] reset skeleton --- interface/src/avatar/MyAvatar.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 1b1dc563c9..2ccaf2d1c8 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1288,6 +1288,7 @@ void MyAvatar::setAnimGraphUrl(const QUrl& url) { return; } destroyAnimGraph(); + _skeletonModel.reset(); // Why is this necessary? Without this, we crash in the next render. _animGraphUrl = url; initAnimGraph(); } @@ -1311,16 +1312,13 @@ void MyAvatar::initAnimGraph() { auto graphUrl =_animGraphUrl.isEmpty() ? QUrl::fromLocalFile(PathUtils::resourcesPath() + "meshes/defaultAvatar_full/avatar-animation.json") : QUrl(_animGraphUrl); - qCDebug(interfaceapp) << "*** FIXME initAnimGraph" << graphUrl.toString(); _rig->initAnimGraph(graphUrl); _bodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation.. updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes - qCDebug(interfaceapp) << "*** FIXME initAnimGraph ready" << graphUrl.toString(); } void MyAvatar::destroyAnimGraph() { - qCDebug(interfaceapp) << "*** FIXME destroyAnimGraph" << _animGraphUrl.toString(); _rig->destroyAnimGraph(); } From 528b8e5d3f452937dba766f4fcb5f28bb06d9afe Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 3 Dec 2015 16:45:01 -0800 Subject: [PATCH 311/401] fix warnings --- libraries/octree/src/Octree.cpp | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 64a2eaccc4..6da59f00a3 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -1438,15 +1438,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // we know the last thing we wrote to the packet was our childrenExistInPacketBits. Let's remember where that was! int childExistsPlaceHolder = packetData->getUncompressedByteOffset(sizeof(childrenExistInPacketBits)); - // we are also going to recurse these child trees in "distance" sorted order, but we need to pack them in the - // final packet in standard order. So what we're going to do is keep track of how big each subtree was in bytes, - // and then later reshuffle these sections of our output buffer back into normal order. This allows us to make - // a single recursive pass in distance sorted order, but retain standard order in our encoded packet - int recursiveSliceSizes[NUMBER_OF_CHILDREN]; - const unsigned char* recursiveSliceStarts[NUMBER_OF_CHILDREN]; - int firstRecursiveSliceOffset = packetData->getUncompressedByteOffset(); - int allSlicesSize = 0; - // for each child element in Distance sorted order..., check to see if they exist, are colored, and in view, and if so // add them to our distance ordered array of children for (int indexByDistance = 0; indexByDistance < currentCount; indexByDistance++) { @@ -1456,9 +1447,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, if (oneAtBit(childrenExistInPacketBits, originalIndex)) { int thisLevel = currentEncodeLevel; - // remember this for reshuffling - recursiveSliceStarts[originalIndex] = packetData->getUncompressedData() + packetData->getUncompressedSize(); - int childTreeBytesOut = 0; // NOTE: some octree styles (like models and particles) will store content in parent elements, and child @@ -1478,10 +1466,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, } } - // remember this for reshuffling - recursiveSliceSizes[originalIndex] = childTreeBytesOut; - allSlicesSize += childTreeBytesOut; - // if the child wrote 0 bytes, it means that nothing below exists or was in view, or we ran out of space, // basically, the children below don't contain any info. From 17b5ade9c039b7d76a4bc4f8a42c1f810cc8f22f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 3 Dec 2015 16:45:46 -0800 Subject: [PATCH 312/401] allow moving distantly grabbed objects with head --- examples/controllers/handControllerGrab.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 5763115bfc..bcb76716d9 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -37,6 +37,7 @@ var BUMPER_ON_VALUE = 0.5; var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did +var MOVE_WITH_HEAD = false; // experimental head-controll of distantly held objects var NO_INTERSECT_COLOR = { red: 10, @@ -658,6 +659,7 @@ function MyController(hand) { this.currentObjectTime = now; this.handRelativePreviousPosition = Vec3.subtract(handControllerPosition, MyAvatar.position); this.handPreviousRotation = handRotation; + this.currentCameraOrientation = Camera.orientation; // compute a constant based on the initial conditions which we use below to exagerate hand motion onto the held object this.radiusScalar = Math.log(Vec3.distance(this.currentObjectPosition, handControllerPosition) + 1.0); @@ -785,6 +787,16 @@ function MyController(hand) { Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); + // mix in head motion + if (MOVE_WITH_HEAD) { + var objDistance = Vec3.length(objectToAvatar); + var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { x: 0.0, y: 0.0, z: objDistance }); + var after = Vec3.multiplyQbyV(Camera.orientation, { x: 0.0, y: 0.0, z: objDistance }); + var change = Vec3.subtract(before, after); + this.currentCameraOrientation = Camera.orientation; + this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change); + } + Entities.updateAction(this.grabbedEntity, this.actionID, { targetPosition: this.currentObjectPosition, linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, From 5a75a1717437c60f750503f3f42274462837687a Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 3 Dec 2015 17:40:41 -0800 Subject: [PATCH 313/401] Revert "Cruft removal" --- .../src/octree/OctreeQueryNode.cpp | 10 +- .../src/octree/OctreeQueryNode.h | 6 +- .../src/octree/OctreeSendThread.cpp | 24 +- interface/src/Application.cpp | 3 + .../entities/src/EntityItemProperties.cpp | 4 +- libraries/octree/src/CoverageMap.cpp | 542 ++++++++++++++++++ libraries/octree/src/CoverageMap.h | 120 ++++ libraries/octree/src/CoverageMapV2.cpp | 251 ++++++++ libraries/octree/src/CoverageMapV2.h | 72 +++ libraries/octree/src/Octree.cpp | 232 ++++++-- libraries/octree/src/Octree.h | 19 +- libraries/octree/src/OctreeHeadlessViewer.cpp | 3 + libraries/octree/src/OctreePacketData.cpp | 9 +- libraries/octree/src/OctreePacketData.h | 6 +- libraries/octree/src/OctreeQuery.cpp | 6 + libraries/octree/src/OctreeQuery.h | 15 +- libraries/octree/src/OctreeRenderer.cpp | 2 +- libraries/octree/src/OctreeSceneStats.cpp | 6 +- libraries/octree/src/OctreeSceneStats.h | 2 +- libraries/shared/src/OctalCode.cpp | 23 + libraries/shared/src/OctalCode.h | 2 + 21 files changed, 1272 insertions(+), 85 deletions(-) create mode 100644 libraries/octree/src/CoverageMap.cpp create mode 100644 libraries/octree/src/CoverageMap.h create mode 100644 libraries/octree/src/CoverageMapV2.cpp create mode 100644 libraries/octree/src/CoverageMapV2.h diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index cafba8c083..cff2c7ee2e 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -179,9 +179,15 @@ void OctreeQueryNode::resetOctreePacket() { // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. + _currentPacketIsColor = getWantColor(); + _currentPacketIsCompressed = getWantCompression(); OCTREE_PACKET_FLAGS flags = 0; - setAtBit(flags, PACKET_IS_COLOR_BIT); - setAtBit(flags, PACKET_IS_COMPRESSED_BIT); + if (_currentPacketIsColor) { + setAtBit(flags, PACKET_IS_COLOR_BIT); + } + if (_currentPacketIsCompressed) { + setAtBit(flags, PACKET_IS_COMPRESSED_BIT); + } _octreePacket->reset(); diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 67298296e9..0c691a06a2 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -14,6 +14,7 @@ #include +#include #include #include #include @@ -54,6 +55,7 @@ public: void setMaxLevelReached(int maxLevelReached) { _maxLevelReachedInLastSearch = maxLevelReached; } OctreeElementBag elementBag; + CoverageMap map; OctreeElementExtraEncodeData extraEncodeData; ViewFrustum& getCurrentViewFrustum() { return _currentViewFrustum; } @@ -77,7 +79,9 @@ public: bool getCurrentPacketIsColor() const { return _currentPacketIsColor; } bool getCurrentPacketIsCompressed() const { return _currentPacketIsCompressed; } - bool getCurrentPacketFormatMatches() { return (getCurrentPacketIsCompressed() == true); } // FIXME + bool getCurrentPacketFormatMatches() { + return (getCurrentPacketIsColor() == getWantColor() && getCurrentPacketIsCompressed() == getWantCompression()); + } bool hasLodChanged() const { return _lodChanged; } diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index d01117dff6..0a32f574de 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -321,6 +321,8 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // If we're starting a fresh packet, then... // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. + bool wantColor = nodeData->getWantColor(); + bool wantCompression = nodeData->getWantCompression(); // If we have a packet waiting, and our desired want color, doesn't match the current waiting packets color // then let's just send that waiting packet. @@ -331,8 +333,10 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus nodeData->resetOctreePacket(); } int targetSize = MAX_OCTREE_PACKET_DATA_SIZE; - targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); - _packetData.changeSettings(targetSize); + if (wantCompression) { + targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); + } + _packetData.changeSettings(wantCompression, targetSize); } const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL; @@ -346,6 +350,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus if (nodeData->moveShouldDump() || nodeData->hasLodChanged()) { nodeData->dumpOutOfView(); } + nodeData->map.erase(); } if (!viewFrustumChanged && !nodeData->getWantDelta()) { @@ -446,15 +451,18 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus } */ + bool wantOcclusionCulling = nodeData->getWantOcclusionCulling(); + CoverageMap* coverageMap = wantOcclusionCulling ? &nodeData->map : IGNORE_COVERAGE_MAP; + float octreeSizeScale = nodeData->getOctreeSizeScale(); int boundaryLevelAdjustClient = nodeData->getBoundaryLevelAdjust(); int boundaryLevelAdjust = boundaryLevelAdjustClient + (viewFrustumChanged && nodeData->getWantLowResMoving() ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); - EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), + EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor, WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, - boundaryLevelAdjust, octreeSizeScale, + wantOcclusionCulling, coverageMap, boundaryLevelAdjust, octreeSizeScale, nodeData->getLastTimeBagEmpty(), isFullScene, &nodeData->stats, _myServer->getJurisdiction(), &nodeData->extraEncodeData); @@ -548,7 +556,10 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus packetsSentThisInterval += handlePacketSend(nodeData, trueBytesSent, truePacketsSent); quint64 packetSendingEnd = usecTimestampNow(); packetSendingElapsedUsec = (float)(packetSendingEnd - packetSendingStart); - targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); + + if (wantCompression) { + targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); + } } else { // If we're in compressed mode, then we want to see if we have room for more in this wire packet. // but we've finalized the _packetData, so we want to start a new section, we will do that by @@ -558,7 +569,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // a larger compressed size then uncompressed size targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE) - COMPRESS_PADDING; } - _packetData.changeSettings(targetSize); // will do reset + _packetData.changeSettings(nodeData->getWantCompression(), targetSize); // will do reset } OctreeServer::trackTreeWaitTime(lockWaitElapsedUsec); @@ -623,6 +634,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus if (nodeData->elementBag.isEmpty()) { nodeData->updateLastKnownViewFrustum(); nodeData->setViewSent(true); + nodeData->map.erase(); // It would be nice if we could save this, and only reset it when the view frustum changes } } // end if bag wasn't empty, and so we sent stuff... diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 199fdecb8e..e6678c8758 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3074,7 +3074,10 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. _octreeQuery.setWantLowResMoving(true); + _octreeQuery.setWantColor(true); _octreeQuery.setWantDelta(true); + _octreeQuery.setWantOcclusionCulling(false); + _octreeQuery.setWantCompression(true); _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); _octreeQuery.setCameraOrientation(_viewFrustum.getOrientation()); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 30bee83482..78a4f3e8b6 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -790,9 +790,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue // bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties, QByteArray& buffer) { - - // FIXME - remove non-compressed OctreePacketData and handle compressed edit packets - OctreePacketData ourDataPacket(buffer.size(), false); // create a packetData object to add out packet details too. + OctreePacketData ourDataPacket(false, buffer.size()); // create a packetData object to add out packet details too. OctreePacketData* packetData = &ourDataPacket; // we want a pointer to this so we can use our APPEND_ENTITY_PROPERTY macro bool success = true; // assume the best diff --git a/libraries/octree/src/CoverageMap.cpp b/libraries/octree/src/CoverageMap.cpp new file mode 100644 index 0000000000..626d4bcf1a --- /dev/null +++ b/libraries/octree/src/CoverageMap.cpp @@ -0,0 +1,542 @@ +// +// CoverageMap.cpp +// libraries/octree/src +// +// Created by Brad Hefta-Gaub on 06/11/13. +// Copyright 2013 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 + +#include + +#include "OctreeLogging.h" +#include "CoverageMap.h" + +int CoverageMap::_mapCount = 0; +int CoverageMap::_checkMapRootCalls = 0; +int CoverageMap::_notAllInView = 0; +bool CoverageMap::wantDebugging = false; + +const int MAX_POLYGONS_PER_REGION = 50; + +const BoundingBox CoverageMap::ROOT_BOUNDING_BOX = BoundingBox(glm::vec2(-1.0f,-1.0f), glm::vec2(2.0f,2.0f)); + +// Coverage Map's polygon coordinates are from -1 to 1 in the following mapping to screen space. +// +// (0,0) (windowWidth, 0) +// -1,1 1,1 +// +-----------------------+ +// | | | +// | | | +// | -1,0 | | +// |-----------+-----------| +// | 0,0 | +// | | | +// | | | +// | | | +// +-----------------------+ +// -1,-1 1,-1 +// (0,windowHeight) (windowWidth,windowHeight) +// + +// Choosing a minimum sized polygon. Since we know a typical window is approximately 1500 pixels wide +// then a pixel on our screen will be ~ 2.0/1500 or 0.0013 "units" wide, similarly pixels are typically +// about that tall as well. If we say that polygons should be at least 10x10 pixels to be considered "big enough" +// then we can calculate a reasonable polygon area +const int TYPICAL_SCREEN_WIDTH_IN_PIXELS = 1500; +const int MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS = 10; +const float TYPICAL_SCREEN_PIXEL_WIDTH = (2.0f / TYPICAL_SCREEN_WIDTH_IN_PIXELS); +const float CoverageMap::MINIMUM_POLYGON_AREA_TO_STORE = (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS) * + (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS); + +CoverageMap::CoverageMap(BoundingBox boundingBox, bool isRoot, bool managePolygons) : + _isRoot(isRoot), + _myBoundingBox(boundingBox), + _managePolygons(managePolygons), + _topHalf (boundingBox.topHalf() , false, managePolygons, TOP_HALF ), + _bottomHalf (boundingBox.bottomHalf(), false, managePolygons, BOTTOM_HALF ), + _leftHalf (boundingBox.leftHalf() , false, managePolygons, LEFT_HALF ), + _rightHalf (boundingBox.rightHalf() , false, managePolygons, RIGHT_HALF ), + _remainder (boundingBox, isRoot, managePolygons, REMAINDER ) +{ + _mapCount++; + init(); +}; + +CoverageMap::~CoverageMap() { + erase(); +}; + +void CoverageMap::printStats() { + qCDebug(octree, "CoverageMap::printStats()..."); + qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f", (double)MINIMUM_POLYGON_AREA_TO_STORE); + qCDebug(octree, "_mapCount=%d",_mapCount); + qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls); + qCDebug(octree, "_notAllInView=%d",_notAllInView); + qCDebug(octree, "_maxPolygonsUsed=%d",CoverageRegion::_maxPolygonsUsed); + qCDebug(octree, "_totalPolygons=%d",CoverageRegion::_totalPolygons); + qCDebug(octree, "_occlusionTests=%d",CoverageRegion::_occlusionTests); + qCDebug(octree, "_regionSkips=%d",CoverageRegion::_regionSkips); + qCDebug(octree, "_tooSmallSkips=%d",CoverageRegion::_tooSmallSkips); + qCDebug(octree, "_regionFullSkips=%d",CoverageRegion::_regionFullSkips); + qCDebug(octree, "_outOfOrderPolygon=%d",CoverageRegion::_outOfOrderPolygon); + qCDebug(octree, "_clippedPolygons=%d",CoverageRegion::_clippedPolygons); +} + +void CoverageMap::erase() { + // tell our regions to erase() + _topHalf.erase(); + _bottomHalf.erase(); + _leftHalf.erase(); + _rightHalf.erase(); + _remainder.erase(); + + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { + if (_childMaps[i]) { + delete _childMaps[i]; + _childMaps[i] = NULL; + } + } + + if (_isRoot && wantDebugging) { + qCDebug(octree, "CoverageMap last to be deleted..."); + printStats(); + + CoverageRegion::_maxPolygonsUsed = 0; + CoverageRegion::_totalPolygons = 0; + CoverageRegion::_occlusionTests = 0; + CoverageRegion::_regionSkips = 0; + CoverageRegion::_tooSmallSkips = 0; + CoverageRegion::_regionFullSkips = 0; + CoverageRegion::_outOfOrderPolygon = 0; + CoverageRegion::_clippedPolygons = 0; + _mapCount = 0; + _checkMapRootCalls = 0; + _notAllInView = 0; + } +} + +void CoverageMap::init() { + memset(_childMaps,0,sizeof(_childMaps)); +} + +// 0 = bottom, right +// 1 = bottom, left +// 2 = top, right +// 3 = top, left +BoundingBox CoverageMap::getChildBoundingBox(int childIndex) { + const int LEFT_BIT = 1; + const int TOP_BIT = 2; + // initialize to our corner, and half our size + BoundingBox result(_myBoundingBox.corner,_myBoundingBox.size/2.0f); + // if our "left" bit is set, then add size.x to the corner + if ((childIndex & LEFT_BIT) == LEFT_BIT) { + result.corner.x += result.size.x; + } + // if our "top" bit is set, then add size.y to the corner + if ((childIndex & TOP_BIT) == TOP_BIT) { + result.corner.y += result.size.y; + } + return result; +} + +int CoverageMap::getPolygonCount() const { + return (_topHalf.getPolygonCount() + + _bottomHalf.getPolygonCount() + + _leftHalf.getPolygonCount() + + _rightHalf.getPolygonCount() + + _remainder.getPolygonCount()); +} + +OctreeProjectedPolygon* CoverageMap::getPolygon(int index) const { + int base = 0; + if ((index - base) < _topHalf.getPolygonCount()) { + return _topHalf.getPolygon((index - base)); + } + base += _topHalf.getPolygonCount(); + + if ((index - base) < _bottomHalf.getPolygonCount()) { + return _bottomHalf.getPolygon((index - base)); + } + base += _bottomHalf.getPolygonCount(); + + if ((index - base) < _leftHalf.getPolygonCount()) { + return _leftHalf.getPolygon((index - base)); + } + base += _leftHalf.getPolygonCount(); + + if ((index - base) < _rightHalf.getPolygonCount()) { + return _rightHalf.getPolygon((index - base)); + } + base += _rightHalf.getPolygonCount(); + + if ((index - base) < _remainder.getPolygonCount()) { + return _remainder.getPolygon((index - base)); + } + return NULL; +} + + + +// possible results = STORED/NOT_STORED, OCCLUDED, DOESNT_FIT +CoverageMapStorageResult CoverageMap::checkMap(OctreeProjectedPolygon* polygon, bool storeIt) { + + if (_isRoot) { + _checkMapRootCalls++; + } + + // short circuit: we don't handle polygons that aren't all in view, so, if the polygon in question is + // not in view, then we just discard it with a DOESNT_FIT, this saves us time checking values later. + if (!polygon->getAllInView()) { + _notAllInView++; + return DOESNT_FIT; + } + + BoundingBox polygonBox(polygon->getBoundingBox()); + if (_isRoot || _myBoundingBox.contains(polygonBox)) { + + CoverageMapStorageResult result = NOT_STORED; + CoverageRegion* storeIn = &_remainder; + + // Check each half of the box independently + const bool useRegions = true; // for now we will continue to use regions + if (useRegions) { + if (_topHalf.contains(polygonBox)) { + result = _topHalf.checkRegion(polygon, polygonBox, storeIt); + storeIn = &_topHalf; + } else if (_bottomHalf.contains(polygonBox)) { + result = _bottomHalf.checkRegion(polygon, polygonBox, storeIt); + storeIn = &_bottomHalf; + } else if (_leftHalf.contains(polygonBox)) { + result = _leftHalf.checkRegion(polygon, polygonBox, storeIt); + storeIn = &_leftHalf; + } else if (_rightHalf.contains(polygonBox)) { + result = _rightHalf.checkRegion(polygon, polygonBox, storeIt); + storeIn = &_rightHalf; + } + } + + // if we got this far, there are one of two possibilities, either a polygon doesn't fit + // in one of the halves, or it did fit, but it wasn't occluded by anything only in that + // half. In either of these cases, we want to check our remainder region to see if its + // occluded by anything there + if (!(result == STORED || result == OCCLUDED)) { + result = _remainder.checkRegion(polygon, polygonBox, storeIt); + } + + // It's possible that this first set of checks might have resulted in an out of order polygon + // in which case we just return.. + if (result == STORED || result == OCCLUDED) { + + /* + if (result == STORED) + qCDebug(octree, "CoverageMap2::checkMap()... STORED\n"); + else + qCDebug(octree, "CoverageMap2::checkMap()... OCCLUDED\n"); + */ + + return result; + } + + // if we made it here, then it means the polygon being stored is not occluded + // at this level of the quad tree, so we can continue to insert it into the map. + // First we check to see if it fits in any of our sub maps + const bool useChildMaps = true; // for now we will continue to use child maps + if (useChildMaps) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { + BoundingBox childMapBoundingBox = getChildBoundingBox(i); + if (childMapBoundingBox.contains(polygon->getBoundingBox())) { + // if no child map exists yet, then create it + if (!_childMaps[i]) { + _childMaps[i] = new CoverageMap(childMapBoundingBox, NOT_ROOT, _managePolygons); + } + result = _childMaps[i]->checkMap(polygon, storeIt); + + /* + switch (result) { + case STORED: + qCDebug(octree, "checkMap() = STORED\n"); + break; + case NOT_STORED: + qCDebug(octree, "checkMap() = NOT_STORED\n"); + break; + case OCCLUDED: + qCDebug(octree, "checkMap() = OCCLUDED\n"); + break; + default: + qCDebug(octree, "checkMap() = ????? \n"); + break; + } + */ + + return result; + } + } + } + // if we got this far, then the polygon is in our bounding box, but doesn't fit in + // any of our child bounding boxes, so we should add it here. + if (storeIt) { + if (polygon->getBoundingBox().area() > CoverageMap::MINIMUM_POLYGON_AREA_TO_STORE) { + if (storeIn->getPolygonCount() < MAX_POLYGONS_PER_REGION) { + storeIn->storeInArray(polygon); + return STORED; + } else { + CoverageRegion::_regionFullSkips++; + return NOT_STORED; + } + } else { + CoverageRegion::_tooSmallSkips++; + return NOT_STORED; + } + } else { + return NOT_STORED; + } + } + return DOESNT_FIT; +} + + +CoverageRegion::CoverageRegion(BoundingBox boundingBox, bool isRoot, bool managePolygons, RegionName regionName) : + _isRoot(isRoot), + _myBoundingBox(boundingBox), + _managePolygons(managePolygons), + _regionName(regionName) +{ + init(); +}; + +CoverageRegion::~CoverageRegion() { + erase(); +}; + +void CoverageRegion::init() { + _polygonCount = 0; + _polygonArraySize = 0; + _polygons = NULL; + _polygonDistances = NULL; + _polygonSizes = NULL; +} + + +void CoverageRegion::erase() { + +/** + if (_polygonCount) { + qCDebug(octree, "CoverageRegion::erase()...\n"); + qCDebug(octree, "_polygonCount=%d\n",_polygonCount); + _myBoundingBox.printDebugDetails(getRegionName()); + //for (int i = 0; i < _polygonCount; i++) { + // qCDebug(octree, "_polygons[%d]=",i); + // _polygons[i]->getBoundingBox().printDebugDetails(); + //} + } +**/ + // If we're in charge of managing the polygons, then clean them up first + if (_polygons && _managePolygons) { + for (int i = 0; i < _polygonCount; i++) { + delete _polygons[i]; + _polygons[i] = NULL; // do we need to do this? + } + } + + // Now, clean up our local storage + _polygonCount = 0; + _polygonArraySize = 0; + if (_polygons) { + delete[] _polygons; + _polygons = NULL; + } + if (_polygonDistances) { + delete[] _polygonDistances; + _polygonDistances = NULL; + } + if (_polygonSizes) { + delete[] _polygonSizes; + _polygonSizes = NULL; + } +} + +void CoverageRegion::growPolygonArray() { + OctreeProjectedPolygon** newPolygons = new OctreeProjectedPolygon*[_polygonArraySize + DEFAULT_GROW_SIZE]; + float* newDistances = new float[_polygonArraySize + DEFAULT_GROW_SIZE]; + float* newSizes = new float[_polygonArraySize + DEFAULT_GROW_SIZE]; + + + if (_polygons) { + memcpy(newPolygons, _polygons, sizeof(OctreeProjectedPolygon*) * _polygonCount); + delete[] _polygons; + memcpy(newDistances, _polygonDistances, sizeof(float) * _polygonCount); + delete[] _polygonDistances; + memcpy(newSizes, _polygonSizes, sizeof(float) * _polygonCount); + delete[] _polygonSizes; + } + _polygons = newPolygons; + _polygonDistances = newDistances; + _polygonSizes = newSizes; + _polygonArraySize = _polygonArraySize + DEFAULT_GROW_SIZE; +} + +const char* CoverageRegion::getRegionName() const { + switch (_regionName) { + case TOP_HALF: + return "TOP_HALF"; + case BOTTOM_HALF: + return "BOTTOM_HALF"; + case LEFT_HALF: + return "LEFT_HALF"; + case RIGHT_HALF: + return "RIGHT_HALF"; + default: + case REMAINDER: + return "REMAINDER"; + } + return "REMAINDER"; +} + +int CoverageRegion::_maxPolygonsUsed = 0; +int CoverageRegion::_totalPolygons = 0; +int CoverageRegion::_occlusionTests = 0; +int CoverageRegion::_regionSkips = 0; +int CoverageRegion::_tooSmallSkips = 0; +int CoverageRegion::_regionFullSkips = 0; +int CoverageRegion::_outOfOrderPolygon = 0; +int CoverageRegion::_clippedPolygons = 0; + + +bool CoverageRegion::mergeItemsInArray(OctreeProjectedPolygon* seed, bool seedInArray) { + for (int i = 0; i < _polygonCount; i++) { + OctreeProjectedPolygon* otherPolygon = _polygons[i]; + if (otherPolygon->canMerge(*seed)) { + otherPolygon->merge(*seed); + + if (seedInArray) { + int* IGNORED_ADDRESS = NULL; + // remove this otherOtherPolygon for our polygon array + _polygonCount = removeFromSortedArrays((void*)seed, + (void**)_polygons, _polygonDistances, IGNORED_ADDRESS, + _polygonCount, _polygonArraySize); + _totalPolygons--; + } + + // clean up + if (_managePolygons) { + delete seed; + } + + // Now run again using our newly merged polygon as the seed + mergeItemsInArray(otherPolygon, true); + + return true; + } + } + return false; +} + +// just handles storage in the array, doesn't test for occlusion or +// determining if this is the correct map to store in! +void CoverageRegion::storeInArray(OctreeProjectedPolygon* polygon) { + + _currentCoveredBounds.explandToInclude(polygon->getBoundingBox()); + + + // Before we actually store this polygon in the array, check to see if this polygon can be merged to any of the existing + // polygons already in our array. + if (mergeItemsInArray(polygon, false)) { + return; // exit early + } + + // only after we attempt to merge! + _totalPolygons++; + + if (_polygonArraySize < _polygonCount + 1) { + growPolygonArray(); + } + + // As an experiment we're going to see if we get an improvement by storing the polygons in coverage area sorted order + // this means the bigger polygons are earlier in the array. We should have a higher probability of being occluded earlier + // in the list. We still check to see if the polygon is "in front" of the target polygon before we test occlusion. Since + // sometimes things come out of order. + const bool SORT_BY_SIZE = false; + const int IGNORED = 0; + int* IGNORED_ADDRESS = NULL; + if (SORT_BY_SIZE) { + // This old code assumes that polygons will always be added in z-buffer order, but that doesn't seem to + // be a good assumption. So instead, we will need to sort this by distance. Use a binary search to find the + // insertion point in this array, and shift the array accordingly + float area = polygon->getBoundingBox().area(); + float reverseArea = 4.0f - area; + _polygonCount = insertIntoSortedArrays((void*)polygon, reverseArea, IGNORED, + (void**)_polygons, _polygonSizes, IGNORED_ADDRESS, + _polygonCount, _polygonArraySize); + } else { + _polygonCount = insertIntoSortedArrays((void*)polygon, polygon->getDistance(), IGNORED, + (void**)_polygons, _polygonDistances, IGNORED_ADDRESS, + _polygonCount, _polygonArraySize); + } + + // Debugging and Optimization Tuning code. + if (_polygonCount > _maxPolygonsUsed) { + _maxPolygonsUsed = _polygonCount; + } +} + + + +CoverageMapStorageResult CoverageRegion::checkRegion(OctreeProjectedPolygon* polygon, const BoundingBox& polygonBox, bool storeIt) { + + CoverageMapStorageResult result = DOESNT_FIT; + + if (_isRoot || _myBoundingBox.contains(polygonBox)) { + result = NOT_STORED; // if we got here, then we DO fit... + + // only actually check the polygons if this polygon is in the covered bounds for this region + if (!_currentCoveredBounds.contains(polygonBox)) { + _regionSkips += _polygonCount; + } else { + // check to make sure this polygon isn't occluded by something at this level + for (int i = 0; i < _polygonCount; i++) { + OctreeProjectedPolygon* polygonAtThisLevel = _polygons[i]; + + // Check to make sure that the polygon in question is "behind" the polygon in the list + // otherwise, we don't need to test it's occlusion (although, it means we've potentially + // added an item previously that may be occluded??? Is that possible? Maybe not, because two + // voxels can't have the exact same outline. So one occludes the other, they can't both occlude + // each other. + + _occlusionTests++; + if (polygonAtThisLevel->occludes(*polygon)) { + // if the polygonAtThisLevel is actually behind the one we're inserting, then we don't + // want to report our inserted one as occluded, but we do want to add our inserted one. + if (polygonAtThisLevel->getDistance() >= polygon->getDistance()) { + _outOfOrderPolygon++; + if (storeIt) { + if (polygon->getBoundingBox().area() > CoverageMap::MINIMUM_POLYGON_AREA_TO_STORE) { + if (getPolygonCount() < MAX_POLYGONS_PER_REGION) { + storeInArray(polygon); + return STORED; + } else { + CoverageRegion::_regionFullSkips++; + return NOT_STORED; + } + } else { + _tooSmallSkips++; + return NOT_STORED; + } + } else { + return NOT_STORED; + } + } + // this polygon is occluded by a closer polygon, so don't store it, and let the caller know + return OCCLUDED; + } + } + } + } + return result; +} diff --git a/libraries/octree/src/CoverageMap.h b/libraries/octree/src/CoverageMap.h new file mode 100644 index 0000000000..bff6bb1078 --- /dev/null +++ b/libraries/octree/src/CoverageMap.h @@ -0,0 +1,120 @@ +// +// CoverageMap.h +// libraries/octree/src +// +// Created by Brad Hefta-Gaub on 06/11/13. +// Copyright 2013 High Fidelity, Inc. +// +// 2D CoverageMap Quad tree for storage of OctreeProjectedPolygons +// +// 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_CoverageMap_h +#define hifi_CoverageMap_h + +#include +#include "OctreeProjectedPolygon.h" + +typedef enum {STORED, OCCLUDED, DOESNT_FIT, NOT_STORED} CoverageMapStorageResult; +typedef enum {TOP_HALF, BOTTOM_HALF, LEFT_HALF, RIGHT_HALF, REMAINDER} RegionName; + +class CoverageRegion { + +public: + + CoverageRegion(BoundingBox boundingBox, bool isRoot, bool managePolygons = true, RegionName regionName = REMAINDER); + ~CoverageRegion(); + + CoverageMapStorageResult checkRegion(OctreeProjectedPolygon* polygon, const BoundingBox& polygonBox, bool storeIt); + void storeInArray(OctreeProjectedPolygon* polygon); + + bool contains(const BoundingBox& box) const { return _myBoundingBox.contains(box); }; + void erase(); // erase the coverage region + + static int _maxPolygonsUsed; + static int _totalPolygons; + static int _occlusionTests; + static int _regionSkips; + static int _tooSmallSkips; + static int _regionFullSkips; + static int _outOfOrderPolygon; + static int _clippedPolygons; + + + const char* getRegionName() const; + + int getPolygonCount() const { return _polygonCount; }; + OctreeProjectedPolygon* getPolygon(int index) const { return _polygons[index]; }; + +private: + void init(); + + bool _isRoot; // is this map the root, if so, it never returns DOESNT_FIT + BoundingBox _myBoundingBox; + BoundingBox _currentCoveredBounds; // area in this region currently covered by some polygon + bool _managePolygons; // will the coverage map delete the polygons on destruct + RegionName _regionName; + int _polygonCount; // how many polygons at this level + int _polygonArraySize; // how much room is there to store polygons at this level + OctreeProjectedPolygon** _polygons; + + // we will use one or the other of these depending on settings in the code. + float* _polygonDistances; + float* _polygonSizes; + void growPolygonArray(); + static const int DEFAULT_GROW_SIZE = 100; + + bool mergeItemsInArray(OctreeProjectedPolygon* seed, bool seedInArray); + +}; + +class CoverageMap { + +public: + static const int NUMBER_OF_CHILDREN = 4; + static const bool NOT_ROOT=false; + static const bool IS_ROOT=true; + static const BoundingBox ROOT_BOUNDING_BOX; + static const float MINIMUM_POLYGON_AREA_TO_STORE; + + CoverageMap(BoundingBox boundingBox = ROOT_BOUNDING_BOX, bool isRoot = IS_ROOT, bool managePolygons = true); + ~CoverageMap(); + + CoverageMapStorageResult checkMap(OctreeProjectedPolygon* polygon, bool storeIt = true); + + BoundingBox getChildBoundingBox(int childIndex); + + void erase(); // erase the coverage map + void printStats(); + + static bool wantDebugging; + + int getPolygonCount() const; + OctreeProjectedPolygon* getPolygon(int index) const; + CoverageMap* getChild(int childIndex) const { return _childMaps[childIndex]; }; + +private: + void init(); + + bool _isRoot; // is this map the root, if so, it never returns DOESNT_FIT + BoundingBox _myBoundingBox; + CoverageMap* _childMaps[NUMBER_OF_CHILDREN]; + bool _managePolygons; // will the coverage map delete the polygons on destruct + + // We divide the map into 5 regions representing each possible half of the map, and the whole map + // this allows us to keep the list of polygons shorter + CoverageRegion _topHalf; + CoverageRegion _bottomHalf; + CoverageRegion _leftHalf; + CoverageRegion _rightHalf; + CoverageRegion _remainder; + + static int _mapCount; + static int _checkMapRootCalls; + static int _notAllInView; +}; + + +#endif // hifi_CoverageMap_h diff --git a/libraries/octree/src/CoverageMapV2.cpp b/libraries/octree/src/CoverageMapV2.cpp new file mode 100644 index 0000000000..8467ea1ee9 --- /dev/null +++ b/libraries/octree/src/CoverageMapV2.cpp @@ -0,0 +1,251 @@ +// +// CoverageMapV2.cpp +// libraries/octree/src +// +// Created by Brad Hefta-Gaub on 06/11/13. +// Copyright 2013 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 + +#include + +#include + +#include "OctreeLogging.h" +#include "CoverageMapV2.h" + +int CoverageMapV2::_mapCount = 0; +int CoverageMapV2::_checkMapRootCalls = 0; +int CoverageMapV2::_notAllInView = 0; +bool CoverageMapV2::wantDebugging = false; + +const BoundingBox CoverageMapV2::ROOT_BOUNDING_BOX = BoundingBox(glm::vec2(-1.0f,-1.0f), glm::vec2(2.0f,2.0f)); + +// Coverage Map's polygon coordinates are from -1 to 1 in the following mapping to screen space. +// +// (0,0) (windowWidth, 0) +// -1,1 1,1 +// +-----------------------+ +// | | | +// | | | +// | -1,0 | | +// |-----------+-----------| +// | 0,0 | +// | | | +// | | | +// | | | +// +-----------------------+ +// -1,-1 1,-1 +// (0,windowHeight) (windowWidth,windowHeight) +// + +// Choosing a minimum sized polygon. Since we know a typical window is approximately 1500 pixels wide +// then a pixel on our screen will be ~ 2.0/1500 or 0.0013 "units" wide, similarly pixels are typically +// about that tall as well. If we say that polygons should be at least 10x10 pixels to be considered "big enough" +// then we can calculate a reasonable polygon area +const int TYPICAL_SCREEN_WIDTH_IN_PIXELS = 1500; +const int MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS = 10; +const float TYPICAL_SCREEN_PIXEL_WIDTH = (2.0f / TYPICAL_SCREEN_WIDTH_IN_PIXELS); +const float CoverageMapV2::MINIMUM_POLYGON_AREA_TO_STORE = (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS) * + (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS); +const float CoverageMapV2::NOT_COVERED = FLT_MAX; +const float CoverageMapV2::MINIMUM_OCCLUSION_CHECK_AREA = MINIMUM_POLYGON_AREA_TO_STORE/10.0f; // one quarter the size of poly + + +CoverageMapV2::CoverageMapV2(BoundingBox boundingBox, bool isRoot, bool isCovered, float coverageDistance) : + _isRoot(isRoot), + _myBoundingBox(boundingBox), + _isCovered(isCovered), + _coveredDistance(coverageDistance) +{ + _mapCount++; + init(); +}; + +CoverageMapV2::~CoverageMapV2() { + erase(); +}; + +void CoverageMapV2::erase() { + + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { + if (_childMaps[i]) { + delete _childMaps[i]; + _childMaps[i] = NULL; + } + } + + if (_isRoot && wantDebugging) { + qCDebug(octree, "CoverageMapV2 last to be deleted..."); + qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f", (double)MINIMUM_POLYGON_AREA_TO_STORE); + qCDebug(octree, "_mapCount=%d",_mapCount); + qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls); + qCDebug(octree, "_notAllInView=%d",_notAllInView); + _mapCount = 0; + _checkMapRootCalls = 0; + _notAllInView = 0; + } +} + +void CoverageMapV2::init() { + memset(_childMaps,0,sizeof(_childMaps)); +} + +// 0 = bottom, left +// 1 = bottom, right +// 2 = top, left +// 3 = top, right +BoundingBox CoverageMapV2::getChildBoundingBox(int childIndex) { + const int RIGHT_BIT = 1; + const int TOP_BIT = 2; + // initialize to our corner, and half our size + BoundingBox result(_myBoundingBox.corner,_myBoundingBox.size/2.0f); + // if our "right" bit is set, then add size.x to the corner + if ((childIndex & RIGHT_BIT) == RIGHT_BIT) { + result.corner.x += result.size.x; + } + // if our "top" bit is set, then add size.y to the corner + if ((childIndex & TOP_BIT) == TOP_BIT) { + result.corner.y += result.size.y; + } + return result; +} + +// possible results = STORED/NOT_STORED, OCCLUDED, DOESNT_FIT +CoverageMapV2StorageResult CoverageMapV2::checkMap(const OctreeProjectedPolygon* polygon, bool storeIt) { + assert(_isRoot); // you can only call this on the root map!!! + _checkMapRootCalls++; + + // short circuit: if we're the root node (only case we're here), and we're covered, and this polygon is deeper than our + // covered depth, then this polygon is occluded! + if (_isCovered && _coveredDistance < polygon->getDistance()) { + return V2_OCCLUDED; + } + + // short circuit: we don't handle polygons that aren't all in view, so, if the polygon in question is + // not in view, then we just discard it with a DOESNT_FIT, this saves us time checking values later. + if (!polygon->getAllInView()) { + _notAllInView++; + return V2_DOESNT_FIT; + } + + // Here's where we recursively check the polygon against the coverage map. We need to maintain two pieces of state. + // The first state is: have we seen at least one "fully occluded" map items. If we haven't then we don't track the covered + // state of the polygon. + // The second piece of state is: Are all of our "fully occluded" map items "covered". If even one of these occluded map + // items is not covered, then our polygon is not covered. + bool seenOccludedMapNodes = false; + bool allOccludedMapNodesCovered = false; + + recurseMap(polygon, storeIt, seenOccludedMapNodes, allOccludedMapNodesCovered); + + // Ok, no matter how we were called, if all our occluded map nodes are covered, then we know this polygon + // is occluded, otherwise, we will report back to the caller about whether or not we stored the polygon + if (allOccludedMapNodesCovered) { + return V2_OCCLUDED; + } + if (storeIt) { + return V2_STORED; // otherwise report that we STORED it + } + return V2_NOT_STORED; // unless we weren't asked to store it, then we didn't +} + +void CoverageMapV2::recurseMap(const OctreeProjectedPolygon* polygon, bool storeIt, + bool& seenOccludedMapNodes, bool& allOccludedMapNodesCovered) { + + // if we are really small, then we act like we don't intersect, this allows us to stop + // recusing as we get to the smalles edge of the polygon + if (_myBoundingBox.area() < MINIMUM_OCCLUSION_CHECK_AREA) { + return; // stop recursion, we're done! + } + + // Determine if this map node intersects the polygon and/or is fully covered by the polygon + // There are a couple special cases: If we're the root, we are assumed to intersect with all + // polygons. Also, any map node that is fully occluded also intersects. + bool nodeIsCoveredByPolygon = polygon->occludes(_myBoundingBox); + bool nodeIsIntersectedByPolygon = nodeIsCoveredByPolygon || _isRoot || polygon->intersects(_myBoundingBox); + + // If we don't intersect, then we can just return, we're done recursing + if (!nodeIsIntersectedByPolygon) { + return; // stop recursion, we're done! + } + + // At this point, we know our node intersects with the polygon. If this node is covered, then we want to treat it + // as if the node was fully covered, because this allows us to short circuit further recursion... + if (_isCovered && _coveredDistance < polygon->getDistance()) { + nodeIsCoveredByPolygon = true; // fake it till you make it + } + + // If this node in the map is fully covered by our polygon, then we don't need to recurse any further, but + // we do need to do some bookkeeping. + if (nodeIsCoveredByPolygon) { + // If this is the very first fully covered node we've seen, then we're initialize our allOccludedMapNodesCovered + // to be our current covered state. This has the following effect: if this node isn't already covered, then by + // definition, we know that at least one node for this polygon isn't covered, and therefore we aren't fully covered. + if (!seenOccludedMapNodes) { + allOccludedMapNodesCovered = (_isCovered && _coveredDistance < polygon->getDistance()); + // We need to mark that we've seen at least one node of our polygon! ;) + seenOccludedMapNodes = true; + } else { + // If this is our second or later node of our polygon, then we need to track our allOccludedMapNodesCovered state + allOccludedMapNodesCovered = allOccludedMapNodesCovered && + (_isCovered && _coveredDistance < polygon->getDistance()); + } + + // if we're in store mode then we want to record that this node is covered. + if (storeIt) { + _isCovered = true; + // store the minimum distance of our previous known distance, or our current polygon's distance. This is because + // we know that we're at least covered at this distance, but if we had previously identified that we're covered + // at a shallower distance, then we want to maintain that distance + _coveredDistance = std::min(polygon->getDistance(), _coveredDistance); + + // Note: this might be a good chance to delete child maps, but we're not going to do that at this point because + // we're trying to maintain the known distances in the lower portion of the tree. + } + + // and since this node of the quad map is covered, we can safely stop recursion. because we know all smaller map + // nodes will also be covered. + return; + } + + // If we got here, then it means we know that this node is not fully covered by the polygon, but it does intersect + // with the polygon. + + // Another case is that we aren't yet marked as covered, and so we should recurse and process smaller quad tree nodes. + // Note: we use this to determine if we can collapse the child quad trees and mark this node as covered + bool allChildrenOccluded = true; + float maxChildCoveredDepth = NOT_COVERED; + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { + BoundingBox childMapBoundingBox = getChildBoundingBox(i); + // if no child map exists yet, then create it + if (!_childMaps[i]) { + // children get created with the coverage state of their parent. + _childMaps[i] = new CoverageMapV2(childMapBoundingBox, NOT_ROOT, _isCovered, _coveredDistance); + } + + _childMaps[i]->recurseMap(polygon, storeIt, seenOccludedMapNodes, allOccludedMapNodesCovered); + + // if so far, all of our children are covered, then record our furthest coverage distance + if (allChildrenOccluded && _childMaps[i]->_isCovered) { + maxChildCoveredDepth = std::max(maxChildCoveredDepth, _childMaps[i]->_coveredDistance); + } else { + // otherwise, at least one of our children is not covered, so not all are covered + allChildrenOccluded = false; + } + } + // if all the children are covered, this makes our quad tree "shallower" because it records that + // entire quad is covered, it uses the "furthest" z-order so that if a shalower polygon comes through + // we won't assume its occluded + if (allChildrenOccluded && storeIt) { + _isCovered = true; + _coveredDistance = maxChildCoveredDepth; + } + + // normal exit case... return... +} diff --git a/libraries/octree/src/CoverageMapV2.h b/libraries/octree/src/CoverageMapV2.h new file mode 100644 index 0000000000..fc9a3ea70e --- /dev/null +++ b/libraries/octree/src/CoverageMapV2.h @@ -0,0 +1,72 @@ +// +// CoverageMapV2.h +// libraries/octree/src +// +// Created by Brad Hefta-Gaub on 06/11/13. +// Copyright 2013 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_CoverageMapV2_h +#define hifi_CoverageMapV2_h + +#include + +#include "OctreeProjectedPolygon.h" + +typedef enum { + V2_DOESNT_FIT, V2_STORED, V2_NOT_STORED, + V2_INTERSECT, V2_NO_INTERSECT, + V2_OCCLUDED, V2_NOT_OCCLUDED +} CoverageMapV2StorageResult; + +class CoverageMapV2 { + +public: + static const int NUMBER_OF_CHILDREN = 4; + static const bool NOT_ROOT = false; + static const bool IS_ROOT = true; + static const BoundingBox ROOT_BOUNDING_BOX; + static const float MINIMUM_POLYGON_AREA_TO_STORE; + static const float NOT_COVERED; + static const float MINIMUM_OCCLUSION_CHECK_AREA; + static bool wantDebugging; + + CoverageMapV2(BoundingBox boundingBox = ROOT_BOUNDING_BOX, bool isRoot = IS_ROOT, + bool isCovered = false, float coverageDistance = NOT_COVERED); + ~CoverageMapV2(); + + CoverageMapV2StorageResult checkMap(const OctreeProjectedPolygon* polygon, bool storeIt = true); + + BoundingBox getChildBoundingBox(int childIndex); + const BoundingBox& getBoundingBox() const { return _myBoundingBox; }; + CoverageMapV2* getChild(int childIndex) const { return _childMaps[childIndex]; }; + bool isCovered() const { return _isCovered; }; + + void erase(); // erase the coverage map + + void render(); + + +private: + void recurseMap(const OctreeProjectedPolygon* polygon, bool storeIt, + bool& seenOccludedMapNodes, bool& allOccludedMapNodesCovered); + + void init(); + + bool _isRoot; + BoundingBox _myBoundingBox; + CoverageMapV2* _childMaps[NUMBER_OF_CHILDREN]; + + bool _isCovered; + float _coveredDistance; + + static int _mapCount; + static int _checkMapRootCalls; + static int _notAllInView; +}; + + +#endif // hifi_CoverageMapV2_h diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 6da59f00a3..c02a034778 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -41,6 +41,7 @@ #include #include +#include "CoverageMap.h" #include "OctreeConstants.h" #include "OctreeElementBag.h" #include "Octree.h" @@ -950,9 +951,9 @@ int Octree::encodeTreeBitstream(OctreeElementPointer element, // if childBytesWritten == 1 then something went wrong... that's not possible assert(childBytesWritten != 1); - // if childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some + // if includeColor and childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some // reason couldn't be written... so reset them here... This isn't true for the non-color included case - if (suppressEmptySubtrees() && childBytesWritten == 2) { + if (suppressEmptySubtrees() && params.includeColor && childBytesWritten == 2) { childBytesWritten = 0; //params.stopReason = EncodeBitstreamParams::UNKNOWN; // possibly should be DIDNT_FIT... } @@ -1102,6 +1103,31 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, params.stopReason = EncodeBitstreamParams::NO_CHANGE; return bytesAtThisLevel; } + + // If the user also asked for occlusion culling, check if this element is occluded, but only if it's not a leaf. + // leaf occlusion is handled down below when we check child nodes + if (params.wantOcclusionCulling && !element->isLeaf()) { + OctreeProjectedPolygon* voxelPolygon = + new OctreeProjectedPolygon(params.viewFrustum->getProjectedPolygon(element->getAACube())); + + // In order to check occlusion culling, the shadow has to be "all in view" otherwise, we will ignore occlusion + // culling and proceed as normal + if (voxelPolygon->getAllInView()) { + CoverageMapStorageResult result = params.map->checkMap(voxelPolygon, false); + delete voxelPolygon; // cleanup + if (result == OCCLUDED) { + if (params.stats) { + params.stats->skippedOccluded(element); + } + params.stopReason = EncodeBitstreamParams::OCCLUDED; + return bytesAtThisLevel; + } + } else { + // If this shadow wasn't "all in view" then we ignored it for occlusion culling, but + // we do need to clean up memory and proceed as normal... + delete voxelPolygon; + } + } } bool keepDiggingDeeper = true; // Assuming we're in view we have a great work ethic, we're always ready for more! @@ -1164,10 +1190,20 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, } } - sortedChildren[i] = childElement; - indexOfChildren[i] = i; - distancesToChildren[i] = 0.0f; - currentCount++; + if (params.wantOcclusionCulling) { + if (childElement) { + float distance = params.viewFrustum ? childElement->distanceToCamera(*params.viewFrustum) : 0; + + currentCount = insertOctreeElementIntoSortedArrays(childElement, distance, i, + sortedChildren, (float*)&distancesToChildren, + (int*)&indexOfChildren, currentCount, NUMBER_OF_CHILDREN); + } + } else { + sortedChildren[i] = childElement; + indexOfChildren[i] = i; + distancesToChildren[i] = 0.0f; + currentCount++; + } // track stats // must check childElement here, because it could be we got here with no childElement @@ -1219,6 +1255,36 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, bool childIsOccluded = false; // assume it's not occluded + // If the user also asked for occlusion culling, check if this element is occluded + if (params.wantOcclusionCulling && childElement->isLeaf()) { + // Don't check occlusion here, just add them to our distance ordered array... + + // FIXME params.ViewFrustum is used here, but later it is checked against nullptr. + OctreeProjectedPolygon* voxelPolygon = new OctreeProjectedPolygon( + params.viewFrustum->getProjectedPolygon(childElement->getAACube())); + + // In order to check occlusion culling, the shadow has to be "all in view" otherwise, we ignore occlusion + // culling and proceed as normal + if (voxelPolygon->getAllInView()) { + CoverageMapStorageResult result = params.map->checkMap(voxelPolygon, true); + + // In all cases where the shadow wasn't stored, we need to free our own memory. + // In the case where it is stored, the CoverageMap will free memory for us later. + if (result != STORED) { + delete voxelPolygon; + } + + // If while attempting to add this voxel's shadow, we determined it was occluded, then + // we don't need to process it further and we can exit early. + if (result == OCCLUDED) { + childIsOccluded = true; + } + } else { + delete voxelPolygon; + } + } // wants occlusion culling & isLeaf() + + bool shouldRender = !params.viewFrustum ? true : childElement->calculateShouldRender(params.viewFrustum, @@ -1293,7 +1359,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // NOW might be a good time to give our tree subclass and this element a chance to set up and check any extra encode data element->initializeExtraEncodeData(params); - // write the child element data... + // write the child element data... NOTE: includeColor means include element data // NOTE: the format of the bitstream is generally this: // [octalcode] // [bitmask for existence of child data] @@ -1303,63 +1369,65 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // N x [ ... tree for children ...] // // This section of the code, is writing the "N x [child data]" portion of this bitstream - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (oneAtBit(childrenDataBits, i)) { - OctreeElementPointer childElement = element->getChildAtIndex(i); + if (params.includeColor) { + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { + if (oneAtBit(childrenDataBits, i)) { + OctreeElementPointer childElement = element->getChildAtIndex(i); - // the childrenDataBits were set up by the in view/LOD logic, it may contain children that we've already - // processed and sent the data bits for. Let our tree subclass determine if it really wants to send the - // data for this child at this point - if (childElement && element->shouldIncludeChildData(i, params)) { + // the childrenDataBits were set up by the in view/LOD logic, it may contain children that we've already + // processed and sent the data bits for. Let our tree subclass determine if it really wants to send the + // data for this child at this point + if (childElement && element->shouldIncludeChildData(i, params)) { - int bytesBeforeChild = packetData->getUncompressedSize(); + int bytesBeforeChild = packetData->getUncompressedSize(); - // a childElement may "partially" write it's data. for example, the model server where the entire - // contents of the element may be larger than can fit in a single MTU/packetData. In this case, - // we want to allow the appendElementData() to respond that it produced partial data, which should be - // written, but that the childElement needs to be reprocessed in an additional pass or passes - // to be completed. - LevelDetails childDataLevelKey = packetData->startLevel(); + // a childElement may "partially" write it's data. for example, the model server where the entire + // contents of the element may be larger than can fit in a single MTU/packetData. In this case, + // we want to allow the appendElementData() to respond that it produced partial data, which should be + // written, but that the childElement needs to be reprocessed in an additional pass or passes + // to be completed. + LevelDetails childDataLevelKey = packetData->startLevel(); - OctreeElement::AppendState childAppendState = childElement->appendElementData(packetData, params); + OctreeElement::AppendState childAppendState = childElement->appendElementData(packetData, params); - // allow our tree subclass to do any additional bookkeeping it needs to do with encoded data state - element->updateEncodedData(i, childAppendState, params); + // allow our tree subclass to do any additional bookkeeping it needs to do with encoded data state + element->updateEncodedData(i, childAppendState, params); - // Continue this level so long as some part of this child element was appended. - bool childFit = (childAppendState != OctreeElement::NONE); + // Continue this level so long as some part of this child element was appended. + bool childFit = (childAppendState != OctreeElement::NONE); - // some datatypes (like Voxels) assume that all child data will fit, if it doesn't fit - // the data type wants to bail on this element level completely - if (!childFit && mustIncludeAllChildData()) { - continueThisLevel = false; - break; - } + // some datatypes (like Voxels) assume that all child data will fit, if it doesn't fit + // the data type wants to bail on this element level completely + if (!childFit && mustIncludeAllChildData()) { + continueThisLevel = false; + break; + } - // If the child was partially or fully appended, then mark the actualChildrenDataBits as including - // this child data - if (childFit) { - actualChildrenDataBits += (1 << (7 - i)); - continueThisLevel = packetData->endLevel(childDataLevelKey); - } else { - packetData->discardLevel(childDataLevelKey); - elementAppendState = OctreeElement::PARTIAL; - params.stopReason = EncodeBitstreamParams::DIDNT_FIT; - } + // If the child was partially or fully appended, then mark the actualChildrenDataBits as including + // this child data + if (childFit) { + actualChildrenDataBits += (1 << (7 - i)); + continueThisLevel = packetData->endLevel(childDataLevelKey); + } else { + packetData->discardLevel(childDataLevelKey); + elementAppendState = OctreeElement::PARTIAL; + params.stopReason = EncodeBitstreamParams::DIDNT_FIT; + } - // If this child was partially appended, then consider this element to be partially appended - if (childAppendState == OctreeElement::PARTIAL) { - elementAppendState = OctreeElement::PARTIAL; - params.stopReason = EncodeBitstreamParams::DIDNT_FIT; - } + // If this child was partially appended, then consider this element to be partially appended + if (childAppendState == OctreeElement::PARTIAL) { + elementAppendState = OctreeElement::PARTIAL; + params.stopReason = EncodeBitstreamParams::DIDNT_FIT; + } - int bytesAfterChild = packetData->getUncompressedSize(); + int bytesAfterChild = packetData->getUncompressedSize(); - bytesAtThisLevel += (bytesAfterChild - bytesBeforeChild); // keep track of byte count for this child + bytesAtThisLevel += (bytesAfterChild - bytesBeforeChild); // keep track of byte count for this child - // don't need to check childElement here, because we can't get here with no childElement - if (params.stats && (childAppendState != OctreeElement::NONE)) { - params.stats->colorSent(childElement); + // don't need to check childElement here, because we can't get here with no childElement + if (params.stats && (childAppendState != OctreeElement::NONE)) { + params.stats->colorSent(childElement); + } } } } @@ -1438,6 +1506,15 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // we know the last thing we wrote to the packet was our childrenExistInPacketBits. Let's remember where that was! int childExistsPlaceHolder = packetData->getUncompressedByteOffset(sizeof(childrenExistInPacketBits)); + // we are also going to recurse these child trees in "distance" sorted order, but we need to pack them in the + // final packet in standard order. So what we're going to do is keep track of how big each subtree was in bytes, + // and then later reshuffle these sections of our output buffer back into normal order. This allows us to make + // a single recursive pass in distance sorted order, but retain standard order in our encoded packet + int recursiveSliceSizes[NUMBER_OF_CHILDREN]; + const unsigned char* recursiveSliceStarts[NUMBER_OF_CHILDREN]; + int firstRecursiveSliceOffset = packetData->getUncompressedByteOffset(); + int allSlicesSize = 0; + // for each child element in Distance sorted order..., check to see if they exist, are colored, and in view, and if so // add them to our distance ordered array of children for (int indexByDistance = 0; indexByDistance < currentCount; indexByDistance++) { @@ -1447,6 +1524,9 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, if (oneAtBit(childrenExistInPacketBits, originalIndex)) { int thisLevel = currentEncodeLevel; + // remember this for reshuffling + recursiveSliceStarts[originalIndex] = packetData->getUncompressedData() + packetData->getUncompressedSize(); + int childTreeBytesOut = 0; // NOTE: some octree styles (like models and particles) will store content in parent elements, and child @@ -1466,6 +1546,10 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, } } + // remember this for reshuffling + recursiveSliceSizes[originalIndex] = childTreeBytesOut; + allSlicesSize += childTreeBytesOut; + // if the child wrote 0 bytes, it means that nothing below exists or was in view, or we ran out of space, // basically, the children below don't contain any info. @@ -1482,10 +1566,17 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // so, if the child returns 2 bytes out, we can actually consider that an empty tree also!! // // we can make this act like no bytes out, by just resetting the bytes out in this case - if (suppressEmptySubtrees() && !params.includeExistsBits && childTreeBytesOut == 2) { + if (suppressEmptySubtrees() && params.includeColor && !params.includeExistsBits && childTreeBytesOut == 2) { childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees } + // We used to try to collapse trees that didn't contain any data, but this does appear to create a problem + // in detecting element deletion. So, I've commented this out but left it in here as a warning to anyone else + // about not attempting to add this optimization back in, without solving the element deletion case. + // We need to send these bitMasks in case the exists in tree bitmask is indicating the deletion of a tree + //if (params.includeColor && params.includeExistsBits && childTreeBytesOut == 3) { + // childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees + //} bytesAtThisLevel += childTreeBytesOut; @@ -1505,7 +1596,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // If this is the last of the child exists bits, then we're actually be rolling out the entire tree if (params.stats && childrenExistInPacketBits == 0) { - params.stats->childBitsRemoved(params.includeExistsBits); + params.stats->childBitsRemoved(params.includeExistsBits, params.includeColor); } if (!continueThisLevel) { @@ -1522,6 +1613,33 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, } // end if (childTreeBytesOut == 0) } // end if (oneAtBit(childrenExistInPacketBits, originalIndex)) } // end for + + // reshuffle here... + if (continueThisLevel && params.wantOcclusionCulling) { + unsigned char tempReshuffleBuffer[MAX_OCTREE_UNCOMRESSED_PACKET_SIZE]; + + unsigned char* tempBufferTo = &tempReshuffleBuffer[0]; // this is our temporary destination + + // iterate through our childrenExistInPacketBits, these will be the sections of the packet that we copied subTree + // details into. Unfortunately, they're in distance sorted order, not original index order. we need to put them + // back into original distance order + for (int originalIndex = 0; originalIndex < NUMBER_OF_CHILDREN; originalIndex++) { + if (oneAtBit(childrenExistInPacketBits, originalIndex)) { + int thisSliceSize = recursiveSliceSizes[originalIndex]; + const unsigned char* thisSliceStarts = recursiveSliceStarts[originalIndex]; + + memcpy(tempBufferTo, thisSliceStarts, thisSliceSize); + tempBufferTo += thisSliceSize; + } + } + + // now that all slices are back in the correct order, copy them to the correct output buffer + continueThisLevel = packetData->updatePriorBytes(firstRecursiveSliceOffset, &tempReshuffleBuffer[0], allSlicesSize); + if (!continueThisLevel) { + qCDebug(octree) << "WARNING UNEXPECTED CASE: Failed to update recursive slice!!!"; + qCDebug(octree) << "This is not expected!!!! -- continueThisLevel=FALSE...."; + } + } } // end keepDiggingDeeper // If we made it this far, then we've written all of our child data... if this element is the root @@ -1800,7 +1918,7 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr unsigned char* dataAt = entireFileDataSection; - ReadBitstreamToTreeParams args(NO_EXISTS_BITS, NULL, 0, + ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, SharedNodePointer(), wantImportProgress, gotVersion); readBitstreamToTree(dataAt, dataLength, args); @@ -1839,7 +1957,7 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr unsigned char* dataAt = fileChunk; unsigned long dataLength = chunkLength; - ReadBitstreamToTreeParams args(NO_EXISTS_BITS, NULL, 0, + ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, SharedNodePointer(), wantImportProgress, gotVersion); readBitstreamToTree(dataAt, dataLength, args); @@ -1987,7 +2105,7 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElementPointer element) bool lastPacketWritten = false; while (OctreeElementPointer subTree = elementBag.extract()) { - EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, NO_EXISTS_BITS); + EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); withReadLock([&] { params.extraEncodeData = &extraEncodeData; bytesWritten = encodeTreeBitstream(subTree, &packetData, elementBag, params); diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 3ca8528a2f..514a9b391b 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -28,6 +28,7 @@ #include "OctreePacketData.h" #include "OctreeSceneStats.h" +class CoverageMap; class ReadBitstreamToTreeParams; class Octree; class OctreeElement; @@ -52,8 +53,12 @@ typedef QHash CubeList; const bool NO_EXISTS_BITS = false; const bool WANT_EXISTS_BITS = true; +const bool NO_COLOR = false; +const bool WANT_COLOR = true; const bool COLLAPSE_EMPTY_TREE = true; const bool DONT_COLLAPSE = false; +const bool NO_OCCLUSION_CULLING = false; +const bool WANT_OCCLUSION_CULLING = true; const int DONT_CHOP = 0; const int NO_BOUNDARY_ADJUST = 0; @@ -70,15 +75,18 @@ public: int maxEncodeLevel; int maxLevelReached; const ViewFrustum* viewFrustum; + bool includeColor; bool includeExistsBits; int chopLevels; bool deltaViewFrustum; const ViewFrustum* lastViewFrustum; + bool wantOcclusionCulling; int boundaryLevelAdjust; float octreeElementSizeScale; quint64 lastViewFrustumSent; bool forceSendScene; OctreeSceneStats* stats; + CoverageMap* map; JurisdictionMap* jurisdictionMap; OctreeElementExtraEncodeData* extraEncodeData; @@ -100,10 +108,13 @@ public: EncodeBitstreamParams( int maxEncodeLevel = INT_MAX, const ViewFrustum* viewFrustum = IGNORE_VIEW_FRUSTUM, + bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, int chopLevels = 0, bool deltaViewFrustum = false, const ViewFrustum* lastViewFrustum = IGNORE_VIEW_FRUSTUM, + bool wantOcclusionCulling = NO_OCCLUSION_CULLING, + CoverageMap* map = IGNORE_COVERAGE_MAP, int boundaryLevelAdjust = NO_BOUNDARY_ADJUST, float octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE, quint64 lastViewFrustumSent = IGNORE_LAST_SENT, @@ -114,15 +125,18 @@ public: maxEncodeLevel(maxEncodeLevel), maxLevelReached(0), viewFrustum(viewFrustum), + includeColor(includeColor), includeExistsBits(includeExistsBits), chopLevels(chopLevels), deltaViewFrustum(deltaViewFrustum), lastViewFrustum(lastViewFrustum), + wantOcclusionCulling(wantOcclusionCulling), boundaryLevelAdjust(boundaryLevelAdjust), octreeElementSizeScale(octreeElementSizeScale), lastViewFrustumSent(lastViewFrustumSent), forceSendScene(forceSendScene), stats(stats), + map(map), jurisdictionMap(jurisdictionMap), extraEncodeData(extraEncodeData), stopReason(UNKNOWN) @@ -176,6 +190,7 @@ public: class ReadBitstreamToTreeParams { public: + bool includeColor; bool includeExistsBits; OctreeElementPointer destinationElement; QUuid sourceUUID; @@ -186,12 +201,14 @@ public: int entitiesPerPacket = 0; ReadBitstreamToTreeParams( + bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, OctreeElementPointer destinationElement = NULL, QUuid sourceUUID = QUuid(), SharedNodePointer sourceNode = SharedNodePointer(), bool wantImportProgress = false, PacketVersion bitstreamVersion = 0) : + includeColor(includeColor), includeExistsBits(includeExistsBits), destinationElement(destinationElement), sourceUUID(sourceUUID), @@ -298,7 +315,7 @@ public: Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL); // Note: this assumes the fileFormat is the HIO individual voxels code files - void loadOctreeFile(const char* fileName); + void loadOctreeFile(const char* fileName, bool wantColorRandomizer); // Octree exporters void writeToFile(const char* filename, OctreeElementPointer element = NULL, QString persistAsFileType = "svo"); diff --git a/libraries/octree/src/OctreeHeadlessViewer.cpp b/libraries/octree/src/OctreeHeadlessViewer.cpp index 7b80d315f1..88a77a4c53 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.cpp +++ b/libraries/octree/src/OctreeHeadlessViewer.cpp @@ -51,7 +51,10 @@ void OctreeHeadlessViewer::queryOctree() { // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. _octreeQuery.setWantLowResMoving(true); + _octreeQuery.setWantColor(true); _octreeQuery.setWantDelta(true); + _octreeQuery.setWantOcclusionCulling(false); + _octreeQuery.setWantCompression(true); // TODO: should be on by default _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); _octreeQuery.setCameraOrientation(_viewFrustum.getOrientation()); diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index f4fbf9bd97..811e96fcf4 100644 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -23,13 +23,12 @@ AtomicUIntStat OctreePacketData::_totalBytesOfValues { 0 }; AtomicUIntStat OctreePacketData::_totalBytesOfPositions { 0 }; AtomicUIntStat OctreePacketData::_totalBytesOfRawData { 0 }; -OctreePacketData::OctreePacketData(int targetSize, bool enableCompression) { - changeSettings(targetSize); // does reset... - _enableCompression = enableCompression; // FIXME +OctreePacketData::OctreePacketData(bool enableCompression, int targetSize) { + changeSettings(enableCompression, targetSize); // does reset... } -void OctreePacketData::changeSettings(unsigned int targetSize) { - _enableCompression = true; // FIXME +void OctreePacketData::changeSettings(bool enableCompression, unsigned int targetSize) { + _enableCompression = enableCompression; _targetSize = std::min(MAX_OCTREE_UNCOMRESSED_PACKET_SIZE, targetSize); reset(); } diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index fb53b3472f..2c86d518ad 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -83,11 +83,11 @@ private: /// Handles packing of the data portion of PacketType_OCTREE_DATA messages. class OctreePacketData { public: - OctreePacketData(int maxFinalizedSize = MAX_OCTREE_PACKET_DATA_SIZE, bool enableCompression = true); + OctreePacketData(bool enableCompression = false, int maxFinalizedSize = MAX_OCTREE_PACKET_DATA_SIZE); ~OctreePacketData(); /// change compression and target size settings - void changeSettings(unsigned int targetSize = MAX_OCTREE_PACKET_DATA_SIZE); + void changeSettings(bool enableCompression = false, unsigned int targetSize = MAX_OCTREE_PACKET_DATA_SIZE); /// reset completely, all data is discarded void reset(); @@ -262,7 +262,7 @@ private: bool append(unsigned char byte); unsigned int _targetSize; - bool _enableCompression { true }; // FIXME - these will always be compressed, so remove this option + bool _enableCompression; unsigned char _uncompressed[MAX_OCTREE_UNCOMRESSED_PACKET_SIZE]; int _bytesInUse; diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index 8449e3083a..e8beb0404c 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -41,7 +41,10 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { // bitMask of less than byte wide items unsigned char bitItems = 0; if (_wantLowResMoving) { setAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); } + if (_wantColor) { setAtBit(bitItems, WANT_COLOR_AT_BIT); } if (_wantDelta) { setAtBit(bitItems, WANT_DELTA_AT_BIT); } + if (_wantOcclusionCulling) { setAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT); } + if (_wantCompression) { setAtBit(bitItems, WANT_COMPRESSION); } *destinationBuffer++ = bitItems; @@ -81,7 +84,10 @@ int OctreeQuery::parseData(NLPacket& packet) { unsigned char bitItems = 0; bitItems = (unsigned char)*sourceBuffer++; _wantLowResMoving = oneAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); + _wantColor = oneAtBit(bitItems, WANT_COLOR_AT_BIT); _wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT); + _wantOcclusionCulling = oneAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT); + _wantCompression = oneAtBit(bitItems, WANT_COMPRESSION); // desired Max Octree PPS memcpy(&_maxQueryPPS, sourceBuffer, sizeof(_maxQueryPPS)); diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index 962a8e1425..86474ffc02 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -35,10 +35,10 @@ typedef unsigned long long quint64; // First bitset const int WANT_LOW_RES_MOVING_BIT = 0; -const int UNUSED_BIT_1 = 1; // unused... available for new feature +const int WANT_COLOR_AT_BIT = 1; const int WANT_DELTA_AT_BIT = 2; -const int UNUSED_BIT_3 = 3; // unused... available for new feature -const int UNUSED_BIT_4 = 4; // 5th bit, unused... available for new feature +const int WANT_OCCLUSION_CULLING_BIT = 3; +const int WANT_COMPRESSION = 4; // 5th bit class OctreeQuery : public NodeData { Q_OBJECT @@ -71,15 +71,21 @@ public: void setCameraEyeOffsetPosition(const glm::vec3& eyeOffsetPosition) { _cameraEyeOffsetPosition = eyeOffsetPosition; } // related to Octree Sending strategies + bool getWantColor() const { return _wantColor; } bool getWantDelta() const { return _wantDelta; } bool getWantLowResMoving() const { return _wantLowResMoving; } + bool getWantOcclusionCulling() const { return _wantOcclusionCulling; } + bool getWantCompression() const { return _wantCompression; } int getMaxQueryPacketsPerSecond() const { return _maxQueryPPS; } float getOctreeSizeScale() const { return _octreeElementSizeScale; } int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } public slots: void setWantLowResMoving(bool wantLowResMoving) { _wantLowResMoving = wantLowResMoving; } + void setWantColor(bool wantColor) { _wantColor = wantColor; } void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; } + void setWantOcclusionCulling(bool wantOcclusionCulling) { _wantOcclusionCulling = wantOcclusionCulling; } + void setWantCompression(bool wantCompression) { _wantCompression = wantCompression; } void setMaxQueryPacketsPerSecond(int maxQueryPPS) { _maxQueryPPS = maxQueryPPS; } void setOctreeSizeScale(float octreeSizeScale) { _octreeElementSizeScale = octreeSizeScale; } void setBoundaryLevelAdjust(int boundaryLevelAdjust) { _boundaryLevelAdjust = boundaryLevelAdjust; } @@ -95,8 +101,11 @@ protected: glm::vec3 _cameraEyeOffsetPosition = glm::vec3(0.0f); // octree server sending items + bool _wantColor = true; bool _wantDelta = true; bool _wantLowResMoving = true; + bool _wantOcclusionCulling = false; + bool _wantCompression = false; int _maxQueryPPS = DEFAULT_MAX_OCTREE_PPS; float _octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE; /// used for LOD calculations int _boundaryLevelAdjust = 0; /// used for LOD calculations diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp index c65359f12f..b7be4cf3e7 100644 --- a/libraries/octree/src/OctreeRenderer.cpp +++ b/libraries/octree/src/OctreeRenderer.cpp @@ -115,7 +115,7 @@ void OctreeRenderer::processDatagram(NLPacket& packet, SharedNodePointer sourceN if (sectionLength) { // ask the VoxelTree to read the bitstream into the tree - ReadBitstreamToTreeParams args(WANT_EXISTS_BITS, NULL, + ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, sourceUUID, sourceNode, false, packet.getVersion()); quint64 startUncompress, startLock = usecTimestampNow(); quint64 startReadBitsteam, endReadBitsteam; diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index c70e0e4935..22352fbe3b 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -371,12 +371,14 @@ void OctreeSceneStats::existsInPacketBitsWritten() { _existsInPacketBitsWritten++; } -void OctreeSceneStats::childBitsRemoved(bool includesExistsBits) { +void OctreeSceneStats::childBitsRemoved(bool includesExistsBits, bool includesColors) { _existsInPacketBitsWritten--; if (includesExistsBits) { _existsBitsWritten--; } - _colorBitsWritten--; + if (includesColors) { + _colorBitsWritten--; + } _treesRemoved++; } diff --git a/libraries/octree/src/OctreeSceneStats.h b/libraries/octree/src/OctreeSceneStats.h index f8ecf93106..bdb4ef206a 100644 --- a/libraries/octree/src/OctreeSceneStats.h +++ b/libraries/octree/src/OctreeSceneStats.h @@ -89,7 +89,7 @@ public: void existsInPacketBitsWritten(); /// Fix up tracking statistics in case where bitmasks were removed for some reason - void childBitsRemoved(bool includesExistsBits); + void childBitsRemoved(bool includesExistsBits, bool includesColors); /// Pack the details of the statistics into a buffer for sending as a network packet int packIntoPacket(); diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index 1fa18903cb..0b77683d4c 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -264,6 +264,29 @@ unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLev return newCode; } +unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode, + bool includeColorSpace) { + + int oldCodeLength = numberOfThreeBitSectionsInCode(originalOctalCode); + int newParentCodeLength = numberOfThreeBitSectionsInCode(newParentOctalCode); + int newCodeLength = newParentCodeLength + oldCodeLength; + int bufferLength = newCodeLength + (includeColorSpace ? SIZE_OF_COLOR_DATA : 0); + unsigned char* newCode = new unsigned char[bufferLength]; + *newCode = newCodeLength; // set the length byte + + // copy parent code section first + for (int sectionFromParent = 0; sectionFromParent < newParentCodeLength; sectionFromParent++) { + char sectionValue = getOctalCodeSectionValue(newParentOctalCode, sectionFromParent); + setOctalCodeSectionValue(newCode, sectionFromParent, sectionValue); + } + // copy original code section next + for (int sectionFromOriginal = 0; sectionFromOriginal < oldCodeLength; sectionFromOriginal++) { + char sectionValue = getOctalCodeSectionValue(originalOctalCode, sectionFromOriginal); + setOctalCodeSectionValue(newCode, sectionFromOriginal + newParentCodeLength, sectionValue); + } + return newCode; +} + bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* possibleDescendent, int descendentsChild) { if (!possibleAncestor || !possibleDescendent) { return false; diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index 09766b685a..9229157c3d 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -36,6 +36,8 @@ const int UNKNOWN_OCTCODE_LENGTH = -2; int numberOfThreeBitSectionsInCode(const unsigned char* octalCode, int maxBytes = UNKNOWN_OCTCODE_LENGTH); unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLevels); +unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode, + bool includeColorSpace = false); const int CHECK_NODE_ONLY = -1; bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* possibleDescendent, From aad4743bf0bdc860fcba4caeef65e7b7999c80d3 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 3 Dec 2015 18:06:50 -0800 Subject: [PATCH 314/401] Completely remove Gverb from cmake --- cmake/externals/gverb/CMakeLists.txt | 31 --------------------------- libraries/audio-client/CMakeLists.txt | 5 ----- 2 files changed, 36 deletions(-) delete mode 100644 cmake/externals/gverb/CMakeLists.txt diff --git a/cmake/externals/gverb/CMakeLists.txt b/cmake/externals/gverb/CMakeLists.txt deleted file mode 100644 index 4da19e1d31..0000000000 --- a/cmake/externals/gverb/CMakeLists.txt +++ /dev/null @@ -1,31 +0,0 @@ -set(EXTERNAL_NAME gverb) - -if (ANDROID) - set(ANDROID_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DANDROID_NATIVE_API_LEVEL=19") -endif () - -include(ExternalProject) -ExternalProject_Add( - ${EXTERNAL_NAME} - URL http://hifi-public.s3.amazonaws.com/dependencies/gverb-master.zip - URL_MD5 8b16d586390a2102804e46b87820dfc6 - CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_INSTALL_PREFIX:PATH= - BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build - LOG_DOWNLOAD 1 - LOG_CONFIGURE 1 - LOG_BUILD 1 -) - -# Hide this external target (for ide users) -set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") - -ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) - -string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) -set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE FILEPATH "Path to gverb include directory") - -if (WIN32) - set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${INSTALL_DIR}/lib/gverb.lib CACHE FILEPATH "List of gverb libraries") -else () - set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${INSTALL_DIR}/lib/libgverb.a CACHE FILEPATH "List of gverb libraries") -endif () \ No newline at end of file diff --git a/libraries/audio-client/CMakeLists.txt b/libraries/audio-client/CMakeLists.txt index 90937edc5d..2c0fc0a9cd 100644 --- a/libraries/audio-client/CMakeLists.txt +++ b/libraries/audio-client/CMakeLists.txt @@ -6,11 +6,6 @@ link_hifi_libraries(audio) target_include_directories(${TARGET_NAME} PUBLIC "${HIFI_LIBRARY_DIR}/audio/src") # have CMake grab externals for us -add_dependency_external_projects(gverb) -find_package(Gverb REQUIRED) -target_link_libraries(${TARGET_NAME} ${GVERB_LIBRARIES}) -target_include_directories(${TARGET_NAME} PRIVATE ${GVERB_INCLUDE_DIRS}) - if (APPLE) find_library(CoreAudio CoreAudio) find_library(CoreFoundation CoreFoundation) From 81fb4476bc1621d78aa20a5d10018bd4974e8dac Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 3 Dec 2015 10:20:04 -0800 Subject: [PATCH 315/401] remove coverage map and occulusion culling, since it was always disabled --- .../src/octree/OctreeQueryNode.h | 2 - .../src/octree/OctreeSendThread.cpp | 7 +- interface/src/Application.cpp | 1 - libraries/octree/src/CoverageMap.cpp | 542 ------------------ libraries/octree/src/CoverageMap.h | 120 ---- libraries/octree/src/CoverageMapV2.cpp | 251 -------- libraries/octree/src/CoverageMapV2.h | 72 --- libraries/octree/src/Octree.cpp | 101 +--- libraries/octree/src/Octree.h | 9 - libraries/octree/src/OctreeHeadlessViewer.cpp | 1 - libraries/octree/src/OctreeQuery.cpp | 2 - libraries/octree/src/OctreeQuery.h | 5 +- 12 files changed, 6 insertions(+), 1107 deletions(-) delete mode 100644 libraries/octree/src/CoverageMap.cpp delete mode 100644 libraries/octree/src/CoverageMap.h delete mode 100644 libraries/octree/src/CoverageMapV2.cpp delete mode 100644 libraries/octree/src/CoverageMapV2.h diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 0c691a06a2..75c841851f 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -14,7 +14,6 @@ #include -#include #include #include #include @@ -55,7 +54,6 @@ public: void setMaxLevelReached(int maxLevelReached) { _maxLevelReachedInLastSearch = maxLevelReached; } OctreeElementBag elementBag; - CoverageMap map; OctreeElementExtraEncodeData extraEncodeData; ViewFrustum& getCurrentViewFrustum() { return _currentViewFrustum; } diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 0a32f574de..f873ee4808 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -350,7 +350,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus if (nodeData->moveShouldDump() || nodeData->hasLodChanged()) { nodeData->dumpOutOfView(); } - nodeData->map.erase(); } if (!viewFrustumChanged && !nodeData->getWantDelta()) { @@ -451,9 +450,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus } */ - bool wantOcclusionCulling = nodeData->getWantOcclusionCulling(); - CoverageMap* coverageMap = wantOcclusionCulling ? &nodeData->map : IGNORE_COVERAGE_MAP; - float octreeSizeScale = nodeData->getOctreeSizeScale(); int boundaryLevelAdjustClient = nodeData->getBoundaryLevelAdjust(); @@ -462,7 +458,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor, WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, - wantOcclusionCulling, coverageMap, boundaryLevelAdjust, octreeSizeScale, + boundaryLevelAdjust, octreeSizeScale, nodeData->getLastTimeBagEmpty(), isFullScene, &nodeData->stats, _myServer->getJurisdiction(), &nodeData->extraEncodeData); @@ -634,7 +630,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus if (nodeData->elementBag.isEmpty()) { nodeData->updateLastKnownViewFrustum(); nodeData->setViewSent(true); - nodeData->map.erase(); // It would be nice if we could save this, and only reset it when the view frustum changes } } // end if bag wasn't empty, and so we sent stuff... diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e6678c8758..67a220311b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3076,7 +3076,6 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node _octreeQuery.setWantLowResMoving(true); _octreeQuery.setWantColor(true); _octreeQuery.setWantDelta(true); - _octreeQuery.setWantOcclusionCulling(false); _octreeQuery.setWantCompression(true); _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); diff --git a/libraries/octree/src/CoverageMap.cpp b/libraries/octree/src/CoverageMap.cpp deleted file mode 100644 index 626d4bcf1a..0000000000 --- a/libraries/octree/src/CoverageMap.cpp +++ /dev/null @@ -1,542 +0,0 @@ -// -// CoverageMap.cpp -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 06/11/13. -// Copyright 2013 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 - -#include - -#include "OctreeLogging.h" -#include "CoverageMap.h" - -int CoverageMap::_mapCount = 0; -int CoverageMap::_checkMapRootCalls = 0; -int CoverageMap::_notAllInView = 0; -bool CoverageMap::wantDebugging = false; - -const int MAX_POLYGONS_PER_REGION = 50; - -const BoundingBox CoverageMap::ROOT_BOUNDING_BOX = BoundingBox(glm::vec2(-1.0f,-1.0f), glm::vec2(2.0f,2.0f)); - -// Coverage Map's polygon coordinates are from -1 to 1 in the following mapping to screen space. -// -// (0,0) (windowWidth, 0) -// -1,1 1,1 -// +-----------------------+ -// | | | -// | | | -// | -1,0 | | -// |-----------+-----------| -// | 0,0 | -// | | | -// | | | -// | | | -// +-----------------------+ -// -1,-1 1,-1 -// (0,windowHeight) (windowWidth,windowHeight) -// - -// Choosing a minimum sized polygon. Since we know a typical window is approximately 1500 pixels wide -// then a pixel on our screen will be ~ 2.0/1500 or 0.0013 "units" wide, similarly pixels are typically -// about that tall as well. If we say that polygons should be at least 10x10 pixels to be considered "big enough" -// then we can calculate a reasonable polygon area -const int TYPICAL_SCREEN_WIDTH_IN_PIXELS = 1500; -const int MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS = 10; -const float TYPICAL_SCREEN_PIXEL_WIDTH = (2.0f / TYPICAL_SCREEN_WIDTH_IN_PIXELS); -const float CoverageMap::MINIMUM_POLYGON_AREA_TO_STORE = (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS) * - (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS); - -CoverageMap::CoverageMap(BoundingBox boundingBox, bool isRoot, bool managePolygons) : - _isRoot(isRoot), - _myBoundingBox(boundingBox), - _managePolygons(managePolygons), - _topHalf (boundingBox.topHalf() , false, managePolygons, TOP_HALF ), - _bottomHalf (boundingBox.bottomHalf(), false, managePolygons, BOTTOM_HALF ), - _leftHalf (boundingBox.leftHalf() , false, managePolygons, LEFT_HALF ), - _rightHalf (boundingBox.rightHalf() , false, managePolygons, RIGHT_HALF ), - _remainder (boundingBox, isRoot, managePolygons, REMAINDER ) -{ - _mapCount++; - init(); -}; - -CoverageMap::~CoverageMap() { - erase(); -}; - -void CoverageMap::printStats() { - qCDebug(octree, "CoverageMap::printStats()..."); - qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f", (double)MINIMUM_POLYGON_AREA_TO_STORE); - qCDebug(octree, "_mapCount=%d",_mapCount); - qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls); - qCDebug(octree, "_notAllInView=%d",_notAllInView); - qCDebug(octree, "_maxPolygonsUsed=%d",CoverageRegion::_maxPolygonsUsed); - qCDebug(octree, "_totalPolygons=%d",CoverageRegion::_totalPolygons); - qCDebug(octree, "_occlusionTests=%d",CoverageRegion::_occlusionTests); - qCDebug(octree, "_regionSkips=%d",CoverageRegion::_regionSkips); - qCDebug(octree, "_tooSmallSkips=%d",CoverageRegion::_tooSmallSkips); - qCDebug(octree, "_regionFullSkips=%d",CoverageRegion::_regionFullSkips); - qCDebug(octree, "_outOfOrderPolygon=%d",CoverageRegion::_outOfOrderPolygon); - qCDebug(octree, "_clippedPolygons=%d",CoverageRegion::_clippedPolygons); -} - -void CoverageMap::erase() { - // tell our regions to erase() - _topHalf.erase(); - _bottomHalf.erase(); - _leftHalf.erase(); - _rightHalf.erase(); - _remainder.erase(); - - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (_childMaps[i]) { - delete _childMaps[i]; - _childMaps[i] = NULL; - } - } - - if (_isRoot && wantDebugging) { - qCDebug(octree, "CoverageMap last to be deleted..."); - printStats(); - - CoverageRegion::_maxPolygonsUsed = 0; - CoverageRegion::_totalPolygons = 0; - CoverageRegion::_occlusionTests = 0; - CoverageRegion::_regionSkips = 0; - CoverageRegion::_tooSmallSkips = 0; - CoverageRegion::_regionFullSkips = 0; - CoverageRegion::_outOfOrderPolygon = 0; - CoverageRegion::_clippedPolygons = 0; - _mapCount = 0; - _checkMapRootCalls = 0; - _notAllInView = 0; - } -} - -void CoverageMap::init() { - memset(_childMaps,0,sizeof(_childMaps)); -} - -// 0 = bottom, right -// 1 = bottom, left -// 2 = top, right -// 3 = top, left -BoundingBox CoverageMap::getChildBoundingBox(int childIndex) { - const int LEFT_BIT = 1; - const int TOP_BIT = 2; - // initialize to our corner, and half our size - BoundingBox result(_myBoundingBox.corner,_myBoundingBox.size/2.0f); - // if our "left" bit is set, then add size.x to the corner - if ((childIndex & LEFT_BIT) == LEFT_BIT) { - result.corner.x += result.size.x; - } - // if our "top" bit is set, then add size.y to the corner - if ((childIndex & TOP_BIT) == TOP_BIT) { - result.corner.y += result.size.y; - } - return result; -} - -int CoverageMap::getPolygonCount() const { - return (_topHalf.getPolygonCount() + - _bottomHalf.getPolygonCount() + - _leftHalf.getPolygonCount() + - _rightHalf.getPolygonCount() + - _remainder.getPolygonCount()); -} - -OctreeProjectedPolygon* CoverageMap::getPolygon(int index) const { - int base = 0; - if ((index - base) < _topHalf.getPolygonCount()) { - return _topHalf.getPolygon((index - base)); - } - base += _topHalf.getPolygonCount(); - - if ((index - base) < _bottomHalf.getPolygonCount()) { - return _bottomHalf.getPolygon((index - base)); - } - base += _bottomHalf.getPolygonCount(); - - if ((index - base) < _leftHalf.getPolygonCount()) { - return _leftHalf.getPolygon((index - base)); - } - base += _leftHalf.getPolygonCount(); - - if ((index - base) < _rightHalf.getPolygonCount()) { - return _rightHalf.getPolygon((index - base)); - } - base += _rightHalf.getPolygonCount(); - - if ((index - base) < _remainder.getPolygonCount()) { - return _remainder.getPolygon((index - base)); - } - return NULL; -} - - - -// possible results = STORED/NOT_STORED, OCCLUDED, DOESNT_FIT -CoverageMapStorageResult CoverageMap::checkMap(OctreeProjectedPolygon* polygon, bool storeIt) { - - if (_isRoot) { - _checkMapRootCalls++; - } - - // short circuit: we don't handle polygons that aren't all in view, so, if the polygon in question is - // not in view, then we just discard it with a DOESNT_FIT, this saves us time checking values later. - if (!polygon->getAllInView()) { - _notAllInView++; - return DOESNT_FIT; - } - - BoundingBox polygonBox(polygon->getBoundingBox()); - if (_isRoot || _myBoundingBox.contains(polygonBox)) { - - CoverageMapStorageResult result = NOT_STORED; - CoverageRegion* storeIn = &_remainder; - - // Check each half of the box independently - const bool useRegions = true; // for now we will continue to use regions - if (useRegions) { - if (_topHalf.contains(polygonBox)) { - result = _topHalf.checkRegion(polygon, polygonBox, storeIt); - storeIn = &_topHalf; - } else if (_bottomHalf.contains(polygonBox)) { - result = _bottomHalf.checkRegion(polygon, polygonBox, storeIt); - storeIn = &_bottomHalf; - } else if (_leftHalf.contains(polygonBox)) { - result = _leftHalf.checkRegion(polygon, polygonBox, storeIt); - storeIn = &_leftHalf; - } else if (_rightHalf.contains(polygonBox)) { - result = _rightHalf.checkRegion(polygon, polygonBox, storeIt); - storeIn = &_rightHalf; - } - } - - // if we got this far, there are one of two possibilities, either a polygon doesn't fit - // in one of the halves, or it did fit, but it wasn't occluded by anything only in that - // half. In either of these cases, we want to check our remainder region to see if its - // occluded by anything there - if (!(result == STORED || result == OCCLUDED)) { - result = _remainder.checkRegion(polygon, polygonBox, storeIt); - } - - // It's possible that this first set of checks might have resulted in an out of order polygon - // in which case we just return.. - if (result == STORED || result == OCCLUDED) { - - /* - if (result == STORED) - qCDebug(octree, "CoverageMap2::checkMap()... STORED\n"); - else - qCDebug(octree, "CoverageMap2::checkMap()... OCCLUDED\n"); - */ - - return result; - } - - // if we made it here, then it means the polygon being stored is not occluded - // at this level of the quad tree, so we can continue to insert it into the map. - // First we check to see if it fits in any of our sub maps - const bool useChildMaps = true; // for now we will continue to use child maps - if (useChildMaps) { - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - BoundingBox childMapBoundingBox = getChildBoundingBox(i); - if (childMapBoundingBox.contains(polygon->getBoundingBox())) { - // if no child map exists yet, then create it - if (!_childMaps[i]) { - _childMaps[i] = new CoverageMap(childMapBoundingBox, NOT_ROOT, _managePolygons); - } - result = _childMaps[i]->checkMap(polygon, storeIt); - - /* - switch (result) { - case STORED: - qCDebug(octree, "checkMap() = STORED\n"); - break; - case NOT_STORED: - qCDebug(octree, "checkMap() = NOT_STORED\n"); - break; - case OCCLUDED: - qCDebug(octree, "checkMap() = OCCLUDED\n"); - break; - default: - qCDebug(octree, "checkMap() = ????? \n"); - break; - } - */ - - return result; - } - } - } - // if we got this far, then the polygon is in our bounding box, but doesn't fit in - // any of our child bounding boxes, so we should add it here. - if (storeIt) { - if (polygon->getBoundingBox().area() > CoverageMap::MINIMUM_POLYGON_AREA_TO_STORE) { - if (storeIn->getPolygonCount() < MAX_POLYGONS_PER_REGION) { - storeIn->storeInArray(polygon); - return STORED; - } else { - CoverageRegion::_regionFullSkips++; - return NOT_STORED; - } - } else { - CoverageRegion::_tooSmallSkips++; - return NOT_STORED; - } - } else { - return NOT_STORED; - } - } - return DOESNT_FIT; -} - - -CoverageRegion::CoverageRegion(BoundingBox boundingBox, bool isRoot, bool managePolygons, RegionName regionName) : - _isRoot(isRoot), - _myBoundingBox(boundingBox), - _managePolygons(managePolygons), - _regionName(regionName) -{ - init(); -}; - -CoverageRegion::~CoverageRegion() { - erase(); -}; - -void CoverageRegion::init() { - _polygonCount = 0; - _polygonArraySize = 0; - _polygons = NULL; - _polygonDistances = NULL; - _polygonSizes = NULL; -} - - -void CoverageRegion::erase() { - -/** - if (_polygonCount) { - qCDebug(octree, "CoverageRegion::erase()...\n"); - qCDebug(octree, "_polygonCount=%d\n",_polygonCount); - _myBoundingBox.printDebugDetails(getRegionName()); - //for (int i = 0; i < _polygonCount; i++) { - // qCDebug(octree, "_polygons[%d]=",i); - // _polygons[i]->getBoundingBox().printDebugDetails(); - //} - } -**/ - // If we're in charge of managing the polygons, then clean them up first - if (_polygons && _managePolygons) { - for (int i = 0; i < _polygonCount; i++) { - delete _polygons[i]; - _polygons[i] = NULL; // do we need to do this? - } - } - - // Now, clean up our local storage - _polygonCount = 0; - _polygonArraySize = 0; - if (_polygons) { - delete[] _polygons; - _polygons = NULL; - } - if (_polygonDistances) { - delete[] _polygonDistances; - _polygonDistances = NULL; - } - if (_polygonSizes) { - delete[] _polygonSizes; - _polygonSizes = NULL; - } -} - -void CoverageRegion::growPolygonArray() { - OctreeProjectedPolygon** newPolygons = new OctreeProjectedPolygon*[_polygonArraySize + DEFAULT_GROW_SIZE]; - float* newDistances = new float[_polygonArraySize + DEFAULT_GROW_SIZE]; - float* newSizes = new float[_polygonArraySize + DEFAULT_GROW_SIZE]; - - - if (_polygons) { - memcpy(newPolygons, _polygons, sizeof(OctreeProjectedPolygon*) * _polygonCount); - delete[] _polygons; - memcpy(newDistances, _polygonDistances, sizeof(float) * _polygonCount); - delete[] _polygonDistances; - memcpy(newSizes, _polygonSizes, sizeof(float) * _polygonCount); - delete[] _polygonSizes; - } - _polygons = newPolygons; - _polygonDistances = newDistances; - _polygonSizes = newSizes; - _polygonArraySize = _polygonArraySize + DEFAULT_GROW_SIZE; -} - -const char* CoverageRegion::getRegionName() const { - switch (_regionName) { - case TOP_HALF: - return "TOP_HALF"; - case BOTTOM_HALF: - return "BOTTOM_HALF"; - case LEFT_HALF: - return "LEFT_HALF"; - case RIGHT_HALF: - return "RIGHT_HALF"; - default: - case REMAINDER: - return "REMAINDER"; - } - return "REMAINDER"; -} - -int CoverageRegion::_maxPolygonsUsed = 0; -int CoverageRegion::_totalPolygons = 0; -int CoverageRegion::_occlusionTests = 0; -int CoverageRegion::_regionSkips = 0; -int CoverageRegion::_tooSmallSkips = 0; -int CoverageRegion::_regionFullSkips = 0; -int CoverageRegion::_outOfOrderPolygon = 0; -int CoverageRegion::_clippedPolygons = 0; - - -bool CoverageRegion::mergeItemsInArray(OctreeProjectedPolygon* seed, bool seedInArray) { - for (int i = 0; i < _polygonCount; i++) { - OctreeProjectedPolygon* otherPolygon = _polygons[i]; - if (otherPolygon->canMerge(*seed)) { - otherPolygon->merge(*seed); - - if (seedInArray) { - int* IGNORED_ADDRESS = NULL; - // remove this otherOtherPolygon for our polygon array - _polygonCount = removeFromSortedArrays((void*)seed, - (void**)_polygons, _polygonDistances, IGNORED_ADDRESS, - _polygonCount, _polygonArraySize); - _totalPolygons--; - } - - // clean up - if (_managePolygons) { - delete seed; - } - - // Now run again using our newly merged polygon as the seed - mergeItemsInArray(otherPolygon, true); - - return true; - } - } - return false; -} - -// just handles storage in the array, doesn't test for occlusion or -// determining if this is the correct map to store in! -void CoverageRegion::storeInArray(OctreeProjectedPolygon* polygon) { - - _currentCoveredBounds.explandToInclude(polygon->getBoundingBox()); - - - // Before we actually store this polygon in the array, check to see if this polygon can be merged to any of the existing - // polygons already in our array. - if (mergeItemsInArray(polygon, false)) { - return; // exit early - } - - // only after we attempt to merge! - _totalPolygons++; - - if (_polygonArraySize < _polygonCount + 1) { - growPolygonArray(); - } - - // As an experiment we're going to see if we get an improvement by storing the polygons in coverage area sorted order - // this means the bigger polygons are earlier in the array. We should have a higher probability of being occluded earlier - // in the list. We still check to see if the polygon is "in front" of the target polygon before we test occlusion. Since - // sometimes things come out of order. - const bool SORT_BY_SIZE = false; - const int IGNORED = 0; - int* IGNORED_ADDRESS = NULL; - if (SORT_BY_SIZE) { - // This old code assumes that polygons will always be added in z-buffer order, but that doesn't seem to - // be a good assumption. So instead, we will need to sort this by distance. Use a binary search to find the - // insertion point in this array, and shift the array accordingly - float area = polygon->getBoundingBox().area(); - float reverseArea = 4.0f - area; - _polygonCount = insertIntoSortedArrays((void*)polygon, reverseArea, IGNORED, - (void**)_polygons, _polygonSizes, IGNORED_ADDRESS, - _polygonCount, _polygonArraySize); - } else { - _polygonCount = insertIntoSortedArrays((void*)polygon, polygon->getDistance(), IGNORED, - (void**)_polygons, _polygonDistances, IGNORED_ADDRESS, - _polygonCount, _polygonArraySize); - } - - // Debugging and Optimization Tuning code. - if (_polygonCount > _maxPolygonsUsed) { - _maxPolygonsUsed = _polygonCount; - } -} - - - -CoverageMapStorageResult CoverageRegion::checkRegion(OctreeProjectedPolygon* polygon, const BoundingBox& polygonBox, bool storeIt) { - - CoverageMapStorageResult result = DOESNT_FIT; - - if (_isRoot || _myBoundingBox.contains(polygonBox)) { - result = NOT_STORED; // if we got here, then we DO fit... - - // only actually check the polygons if this polygon is in the covered bounds for this region - if (!_currentCoveredBounds.contains(polygonBox)) { - _regionSkips += _polygonCount; - } else { - // check to make sure this polygon isn't occluded by something at this level - for (int i = 0; i < _polygonCount; i++) { - OctreeProjectedPolygon* polygonAtThisLevel = _polygons[i]; - - // Check to make sure that the polygon in question is "behind" the polygon in the list - // otherwise, we don't need to test it's occlusion (although, it means we've potentially - // added an item previously that may be occluded??? Is that possible? Maybe not, because two - // voxels can't have the exact same outline. So one occludes the other, they can't both occlude - // each other. - - _occlusionTests++; - if (polygonAtThisLevel->occludes(*polygon)) { - // if the polygonAtThisLevel is actually behind the one we're inserting, then we don't - // want to report our inserted one as occluded, but we do want to add our inserted one. - if (polygonAtThisLevel->getDistance() >= polygon->getDistance()) { - _outOfOrderPolygon++; - if (storeIt) { - if (polygon->getBoundingBox().area() > CoverageMap::MINIMUM_POLYGON_AREA_TO_STORE) { - if (getPolygonCount() < MAX_POLYGONS_PER_REGION) { - storeInArray(polygon); - return STORED; - } else { - CoverageRegion::_regionFullSkips++; - return NOT_STORED; - } - } else { - _tooSmallSkips++; - return NOT_STORED; - } - } else { - return NOT_STORED; - } - } - // this polygon is occluded by a closer polygon, so don't store it, and let the caller know - return OCCLUDED; - } - } - } - } - return result; -} diff --git a/libraries/octree/src/CoverageMap.h b/libraries/octree/src/CoverageMap.h deleted file mode 100644 index bff6bb1078..0000000000 --- a/libraries/octree/src/CoverageMap.h +++ /dev/null @@ -1,120 +0,0 @@ -// -// CoverageMap.h -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 06/11/13. -// Copyright 2013 High Fidelity, Inc. -// -// 2D CoverageMap Quad tree for storage of OctreeProjectedPolygons -// -// 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_CoverageMap_h -#define hifi_CoverageMap_h - -#include -#include "OctreeProjectedPolygon.h" - -typedef enum {STORED, OCCLUDED, DOESNT_FIT, NOT_STORED} CoverageMapStorageResult; -typedef enum {TOP_HALF, BOTTOM_HALF, LEFT_HALF, RIGHT_HALF, REMAINDER} RegionName; - -class CoverageRegion { - -public: - - CoverageRegion(BoundingBox boundingBox, bool isRoot, bool managePolygons = true, RegionName regionName = REMAINDER); - ~CoverageRegion(); - - CoverageMapStorageResult checkRegion(OctreeProjectedPolygon* polygon, const BoundingBox& polygonBox, bool storeIt); - void storeInArray(OctreeProjectedPolygon* polygon); - - bool contains(const BoundingBox& box) const { return _myBoundingBox.contains(box); }; - void erase(); // erase the coverage region - - static int _maxPolygonsUsed; - static int _totalPolygons; - static int _occlusionTests; - static int _regionSkips; - static int _tooSmallSkips; - static int _regionFullSkips; - static int _outOfOrderPolygon; - static int _clippedPolygons; - - - const char* getRegionName() const; - - int getPolygonCount() const { return _polygonCount; }; - OctreeProjectedPolygon* getPolygon(int index) const { return _polygons[index]; }; - -private: - void init(); - - bool _isRoot; // is this map the root, if so, it never returns DOESNT_FIT - BoundingBox _myBoundingBox; - BoundingBox _currentCoveredBounds; // area in this region currently covered by some polygon - bool _managePolygons; // will the coverage map delete the polygons on destruct - RegionName _regionName; - int _polygonCount; // how many polygons at this level - int _polygonArraySize; // how much room is there to store polygons at this level - OctreeProjectedPolygon** _polygons; - - // we will use one or the other of these depending on settings in the code. - float* _polygonDistances; - float* _polygonSizes; - void growPolygonArray(); - static const int DEFAULT_GROW_SIZE = 100; - - bool mergeItemsInArray(OctreeProjectedPolygon* seed, bool seedInArray); - -}; - -class CoverageMap { - -public: - static const int NUMBER_OF_CHILDREN = 4; - static const bool NOT_ROOT=false; - static const bool IS_ROOT=true; - static const BoundingBox ROOT_BOUNDING_BOX; - static const float MINIMUM_POLYGON_AREA_TO_STORE; - - CoverageMap(BoundingBox boundingBox = ROOT_BOUNDING_BOX, bool isRoot = IS_ROOT, bool managePolygons = true); - ~CoverageMap(); - - CoverageMapStorageResult checkMap(OctreeProjectedPolygon* polygon, bool storeIt = true); - - BoundingBox getChildBoundingBox(int childIndex); - - void erase(); // erase the coverage map - void printStats(); - - static bool wantDebugging; - - int getPolygonCount() const; - OctreeProjectedPolygon* getPolygon(int index) const; - CoverageMap* getChild(int childIndex) const { return _childMaps[childIndex]; }; - -private: - void init(); - - bool _isRoot; // is this map the root, if so, it never returns DOESNT_FIT - BoundingBox _myBoundingBox; - CoverageMap* _childMaps[NUMBER_OF_CHILDREN]; - bool _managePolygons; // will the coverage map delete the polygons on destruct - - // We divide the map into 5 regions representing each possible half of the map, and the whole map - // this allows us to keep the list of polygons shorter - CoverageRegion _topHalf; - CoverageRegion _bottomHalf; - CoverageRegion _leftHalf; - CoverageRegion _rightHalf; - CoverageRegion _remainder; - - static int _mapCount; - static int _checkMapRootCalls; - static int _notAllInView; -}; - - -#endif // hifi_CoverageMap_h diff --git a/libraries/octree/src/CoverageMapV2.cpp b/libraries/octree/src/CoverageMapV2.cpp deleted file mode 100644 index 8467ea1ee9..0000000000 --- a/libraries/octree/src/CoverageMapV2.cpp +++ /dev/null @@ -1,251 +0,0 @@ -// -// CoverageMapV2.cpp -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 06/11/13. -// Copyright 2013 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 - -#include - -#include - -#include "OctreeLogging.h" -#include "CoverageMapV2.h" - -int CoverageMapV2::_mapCount = 0; -int CoverageMapV2::_checkMapRootCalls = 0; -int CoverageMapV2::_notAllInView = 0; -bool CoverageMapV2::wantDebugging = false; - -const BoundingBox CoverageMapV2::ROOT_BOUNDING_BOX = BoundingBox(glm::vec2(-1.0f,-1.0f), glm::vec2(2.0f,2.0f)); - -// Coverage Map's polygon coordinates are from -1 to 1 in the following mapping to screen space. -// -// (0,0) (windowWidth, 0) -// -1,1 1,1 -// +-----------------------+ -// | | | -// | | | -// | -1,0 | | -// |-----------+-----------| -// | 0,0 | -// | | | -// | | | -// | | | -// +-----------------------+ -// -1,-1 1,-1 -// (0,windowHeight) (windowWidth,windowHeight) -// - -// Choosing a minimum sized polygon. Since we know a typical window is approximately 1500 pixels wide -// then a pixel on our screen will be ~ 2.0/1500 or 0.0013 "units" wide, similarly pixels are typically -// about that tall as well. If we say that polygons should be at least 10x10 pixels to be considered "big enough" -// then we can calculate a reasonable polygon area -const int TYPICAL_SCREEN_WIDTH_IN_PIXELS = 1500; -const int MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS = 10; -const float TYPICAL_SCREEN_PIXEL_WIDTH = (2.0f / TYPICAL_SCREEN_WIDTH_IN_PIXELS); -const float CoverageMapV2::MINIMUM_POLYGON_AREA_TO_STORE = (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS) * - (TYPICAL_SCREEN_PIXEL_WIDTH * MINIMUM_POLYGON_AREA_SIDE_IN_PIXELS); -const float CoverageMapV2::NOT_COVERED = FLT_MAX; -const float CoverageMapV2::MINIMUM_OCCLUSION_CHECK_AREA = MINIMUM_POLYGON_AREA_TO_STORE/10.0f; // one quarter the size of poly - - -CoverageMapV2::CoverageMapV2(BoundingBox boundingBox, bool isRoot, bool isCovered, float coverageDistance) : - _isRoot(isRoot), - _myBoundingBox(boundingBox), - _isCovered(isCovered), - _coveredDistance(coverageDistance) -{ - _mapCount++; - init(); -}; - -CoverageMapV2::~CoverageMapV2() { - erase(); -}; - -void CoverageMapV2::erase() { - - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (_childMaps[i]) { - delete _childMaps[i]; - _childMaps[i] = NULL; - } - } - - if (_isRoot && wantDebugging) { - qCDebug(octree, "CoverageMapV2 last to be deleted..."); - qCDebug(octree, "MINIMUM_POLYGON_AREA_TO_STORE=%f", (double)MINIMUM_POLYGON_AREA_TO_STORE); - qCDebug(octree, "_mapCount=%d",_mapCount); - qCDebug(octree, "_checkMapRootCalls=%d",_checkMapRootCalls); - qCDebug(octree, "_notAllInView=%d",_notAllInView); - _mapCount = 0; - _checkMapRootCalls = 0; - _notAllInView = 0; - } -} - -void CoverageMapV2::init() { - memset(_childMaps,0,sizeof(_childMaps)); -} - -// 0 = bottom, left -// 1 = bottom, right -// 2 = top, left -// 3 = top, right -BoundingBox CoverageMapV2::getChildBoundingBox(int childIndex) { - const int RIGHT_BIT = 1; - const int TOP_BIT = 2; - // initialize to our corner, and half our size - BoundingBox result(_myBoundingBox.corner,_myBoundingBox.size/2.0f); - // if our "right" bit is set, then add size.x to the corner - if ((childIndex & RIGHT_BIT) == RIGHT_BIT) { - result.corner.x += result.size.x; - } - // if our "top" bit is set, then add size.y to the corner - if ((childIndex & TOP_BIT) == TOP_BIT) { - result.corner.y += result.size.y; - } - return result; -} - -// possible results = STORED/NOT_STORED, OCCLUDED, DOESNT_FIT -CoverageMapV2StorageResult CoverageMapV2::checkMap(const OctreeProjectedPolygon* polygon, bool storeIt) { - assert(_isRoot); // you can only call this on the root map!!! - _checkMapRootCalls++; - - // short circuit: if we're the root node (only case we're here), and we're covered, and this polygon is deeper than our - // covered depth, then this polygon is occluded! - if (_isCovered && _coveredDistance < polygon->getDistance()) { - return V2_OCCLUDED; - } - - // short circuit: we don't handle polygons that aren't all in view, so, if the polygon in question is - // not in view, then we just discard it with a DOESNT_FIT, this saves us time checking values later. - if (!polygon->getAllInView()) { - _notAllInView++; - return V2_DOESNT_FIT; - } - - // Here's where we recursively check the polygon against the coverage map. We need to maintain two pieces of state. - // The first state is: have we seen at least one "fully occluded" map items. If we haven't then we don't track the covered - // state of the polygon. - // The second piece of state is: Are all of our "fully occluded" map items "covered". If even one of these occluded map - // items is not covered, then our polygon is not covered. - bool seenOccludedMapNodes = false; - bool allOccludedMapNodesCovered = false; - - recurseMap(polygon, storeIt, seenOccludedMapNodes, allOccludedMapNodesCovered); - - // Ok, no matter how we were called, if all our occluded map nodes are covered, then we know this polygon - // is occluded, otherwise, we will report back to the caller about whether or not we stored the polygon - if (allOccludedMapNodesCovered) { - return V2_OCCLUDED; - } - if (storeIt) { - return V2_STORED; // otherwise report that we STORED it - } - return V2_NOT_STORED; // unless we weren't asked to store it, then we didn't -} - -void CoverageMapV2::recurseMap(const OctreeProjectedPolygon* polygon, bool storeIt, - bool& seenOccludedMapNodes, bool& allOccludedMapNodesCovered) { - - // if we are really small, then we act like we don't intersect, this allows us to stop - // recusing as we get to the smalles edge of the polygon - if (_myBoundingBox.area() < MINIMUM_OCCLUSION_CHECK_AREA) { - return; // stop recursion, we're done! - } - - // Determine if this map node intersects the polygon and/or is fully covered by the polygon - // There are a couple special cases: If we're the root, we are assumed to intersect with all - // polygons. Also, any map node that is fully occluded also intersects. - bool nodeIsCoveredByPolygon = polygon->occludes(_myBoundingBox); - bool nodeIsIntersectedByPolygon = nodeIsCoveredByPolygon || _isRoot || polygon->intersects(_myBoundingBox); - - // If we don't intersect, then we can just return, we're done recursing - if (!nodeIsIntersectedByPolygon) { - return; // stop recursion, we're done! - } - - // At this point, we know our node intersects with the polygon. If this node is covered, then we want to treat it - // as if the node was fully covered, because this allows us to short circuit further recursion... - if (_isCovered && _coveredDistance < polygon->getDistance()) { - nodeIsCoveredByPolygon = true; // fake it till you make it - } - - // If this node in the map is fully covered by our polygon, then we don't need to recurse any further, but - // we do need to do some bookkeeping. - if (nodeIsCoveredByPolygon) { - // If this is the very first fully covered node we've seen, then we're initialize our allOccludedMapNodesCovered - // to be our current covered state. This has the following effect: if this node isn't already covered, then by - // definition, we know that at least one node for this polygon isn't covered, and therefore we aren't fully covered. - if (!seenOccludedMapNodes) { - allOccludedMapNodesCovered = (_isCovered && _coveredDistance < polygon->getDistance()); - // We need to mark that we've seen at least one node of our polygon! ;) - seenOccludedMapNodes = true; - } else { - // If this is our second or later node of our polygon, then we need to track our allOccludedMapNodesCovered state - allOccludedMapNodesCovered = allOccludedMapNodesCovered && - (_isCovered && _coveredDistance < polygon->getDistance()); - } - - // if we're in store mode then we want to record that this node is covered. - if (storeIt) { - _isCovered = true; - // store the minimum distance of our previous known distance, or our current polygon's distance. This is because - // we know that we're at least covered at this distance, but if we had previously identified that we're covered - // at a shallower distance, then we want to maintain that distance - _coveredDistance = std::min(polygon->getDistance(), _coveredDistance); - - // Note: this might be a good chance to delete child maps, but we're not going to do that at this point because - // we're trying to maintain the known distances in the lower portion of the tree. - } - - // and since this node of the quad map is covered, we can safely stop recursion. because we know all smaller map - // nodes will also be covered. - return; - } - - // If we got here, then it means we know that this node is not fully covered by the polygon, but it does intersect - // with the polygon. - - // Another case is that we aren't yet marked as covered, and so we should recurse and process smaller quad tree nodes. - // Note: we use this to determine if we can collapse the child quad trees and mark this node as covered - bool allChildrenOccluded = true; - float maxChildCoveredDepth = NOT_COVERED; - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - BoundingBox childMapBoundingBox = getChildBoundingBox(i); - // if no child map exists yet, then create it - if (!_childMaps[i]) { - // children get created with the coverage state of their parent. - _childMaps[i] = new CoverageMapV2(childMapBoundingBox, NOT_ROOT, _isCovered, _coveredDistance); - } - - _childMaps[i]->recurseMap(polygon, storeIt, seenOccludedMapNodes, allOccludedMapNodesCovered); - - // if so far, all of our children are covered, then record our furthest coverage distance - if (allChildrenOccluded && _childMaps[i]->_isCovered) { - maxChildCoveredDepth = std::max(maxChildCoveredDepth, _childMaps[i]->_coveredDistance); - } else { - // otherwise, at least one of our children is not covered, so not all are covered - allChildrenOccluded = false; - } - } - // if all the children are covered, this makes our quad tree "shallower" because it records that - // entire quad is covered, it uses the "furthest" z-order so that if a shalower polygon comes through - // we won't assume its occluded - if (allChildrenOccluded && storeIt) { - _isCovered = true; - _coveredDistance = maxChildCoveredDepth; - } - - // normal exit case... return... -} diff --git a/libraries/octree/src/CoverageMapV2.h b/libraries/octree/src/CoverageMapV2.h deleted file mode 100644 index fc9a3ea70e..0000000000 --- a/libraries/octree/src/CoverageMapV2.h +++ /dev/null @@ -1,72 +0,0 @@ -// -// CoverageMapV2.h -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 06/11/13. -// Copyright 2013 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_CoverageMapV2_h -#define hifi_CoverageMapV2_h - -#include - -#include "OctreeProjectedPolygon.h" - -typedef enum { - V2_DOESNT_FIT, V2_STORED, V2_NOT_STORED, - V2_INTERSECT, V2_NO_INTERSECT, - V2_OCCLUDED, V2_NOT_OCCLUDED -} CoverageMapV2StorageResult; - -class CoverageMapV2 { - -public: - static const int NUMBER_OF_CHILDREN = 4; - static const bool NOT_ROOT = false; - static const bool IS_ROOT = true; - static const BoundingBox ROOT_BOUNDING_BOX; - static const float MINIMUM_POLYGON_AREA_TO_STORE; - static const float NOT_COVERED; - static const float MINIMUM_OCCLUSION_CHECK_AREA; - static bool wantDebugging; - - CoverageMapV2(BoundingBox boundingBox = ROOT_BOUNDING_BOX, bool isRoot = IS_ROOT, - bool isCovered = false, float coverageDistance = NOT_COVERED); - ~CoverageMapV2(); - - CoverageMapV2StorageResult checkMap(const OctreeProjectedPolygon* polygon, bool storeIt = true); - - BoundingBox getChildBoundingBox(int childIndex); - const BoundingBox& getBoundingBox() const { return _myBoundingBox; }; - CoverageMapV2* getChild(int childIndex) const { return _childMaps[childIndex]; }; - bool isCovered() const { return _isCovered; }; - - void erase(); // erase the coverage map - - void render(); - - -private: - void recurseMap(const OctreeProjectedPolygon* polygon, bool storeIt, - bool& seenOccludedMapNodes, bool& allOccludedMapNodesCovered); - - void init(); - - bool _isRoot; - BoundingBox _myBoundingBox; - CoverageMapV2* _childMaps[NUMBER_OF_CHILDREN]; - - bool _isCovered; - float _coveredDistance; - - static int _mapCount; - static int _checkMapRootCalls; - static int _notAllInView; -}; - - -#endif // hifi_CoverageMapV2_h diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index c02a034778..1960537ced 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -41,7 +41,6 @@ #include #include -#include "CoverageMap.h" #include "OctreeConstants.h" #include "OctreeElementBag.h" #include "Octree.h" @@ -1103,31 +1102,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, params.stopReason = EncodeBitstreamParams::NO_CHANGE; return bytesAtThisLevel; } - - // If the user also asked for occlusion culling, check if this element is occluded, but only if it's not a leaf. - // leaf occlusion is handled down below when we check child nodes - if (params.wantOcclusionCulling && !element->isLeaf()) { - OctreeProjectedPolygon* voxelPolygon = - new OctreeProjectedPolygon(params.viewFrustum->getProjectedPolygon(element->getAACube())); - - // In order to check occlusion culling, the shadow has to be "all in view" otherwise, we will ignore occlusion - // culling and proceed as normal - if (voxelPolygon->getAllInView()) { - CoverageMapStorageResult result = params.map->checkMap(voxelPolygon, false); - delete voxelPolygon; // cleanup - if (result == OCCLUDED) { - if (params.stats) { - params.stats->skippedOccluded(element); - } - params.stopReason = EncodeBitstreamParams::OCCLUDED; - return bytesAtThisLevel; - } - } else { - // If this shadow wasn't "all in view" then we ignored it for occlusion culling, but - // we do need to clean up memory and proceed as normal... - delete voxelPolygon; - } - } } bool keepDiggingDeeper = true; // Assuming we're in view we have a great work ethic, we're always ready for more! @@ -1190,20 +1164,10 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, } } - if (params.wantOcclusionCulling) { - if (childElement) { - float distance = params.viewFrustum ? childElement->distanceToCamera(*params.viewFrustum) : 0; - - currentCount = insertOctreeElementIntoSortedArrays(childElement, distance, i, - sortedChildren, (float*)&distancesToChildren, - (int*)&indexOfChildren, currentCount, NUMBER_OF_CHILDREN); - } - } else { - sortedChildren[i] = childElement; - indexOfChildren[i] = i; - distancesToChildren[i] = 0.0f; - currentCount++; - } + sortedChildren[i] = childElement; + indexOfChildren[i] = i; + distancesToChildren[i] = 0.0f; + currentCount++; // track stats // must check childElement here, because it could be we got here with no childElement @@ -1255,36 +1219,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, bool childIsOccluded = false; // assume it's not occluded - // If the user also asked for occlusion culling, check if this element is occluded - if (params.wantOcclusionCulling && childElement->isLeaf()) { - // Don't check occlusion here, just add them to our distance ordered array... - - // FIXME params.ViewFrustum is used here, but later it is checked against nullptr. - OctreeProjectedPolygon* voxelPolygon = new OctreeProjectedPolygon( - params.viewFrustum->getProjectedPolygon(childElement->getAACube())); - - // In order to check occlusion culling, the shadow has to be "all in view" otherwise, we ignore occlusion - // culling and proceed as normal - if (voxelPolygon->getAllInView()) { - CoverageMapStorageResult result = params.map->checkMap(voxelPolygon, true); - - // In all cases where the shadow wasn't stored, we need to free our own memory. - // In the case where it is stored, the CoverageMap will free memory for us later. - if (result != STORED) { - delete voxelPolygon; - } - - // If while attempting to add this voxel's shadow, we determined it was occluded, then - // we don't need to process it further and we can exit early. - if (result == OCCLUDED) { - childIsOccluded = true; - } - } else { - delete voxelPolygon; - } - } // wants occlusion culling & isLeaf() - - bool shouldRender = !params.viewFrustum ? true : childElement->calculateShouldRender(params.viewFrustum, @@ -1613,33 +1547,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, } // end if (childTreeBytesOut == 0) } // end if (oneAtBit(childrenExistInPacketBits, originalIndex)) } // end for - - // reshuffle here... - if (continueThisLevel && params.wantOcclusionCulling) { - unsigned char tempReshuffleBuffer[MAX_OCTREE_UNCOMRESSED_PACKET_SIZE]; - - unsigned char* tempBufferTo = &tempReshuffleBuffer[0]; // this is our temporary destination - - // iterate through our childrenExistInPacketBits, these will be the sections of the packet that we copied subTree - // details into. Unfortunately, they're in distance sorted order, not original index order. we need to put them - // back into original distance order - for (int originalIndex = 0; originalIndex < NUMBER_OF_CHILDREN; originalIndex++) { - if (oneAtBit(childrenExistInPacketBits, originalIndex)) { - int thisSliceSize = recursiveSliceSizes[originalIndex]; - const unsigned char* thisSliceStarts = recursiveSliceStarts[originalIndex]; - - memcpy(tempBufferTo, thisSliceStarts, thisSliceSize); - tempBufferTo += thisSliceSize; - } - } - - // now that all slices are back in the correct order, copy them to the correct output buffer - continueThisLevel = packetData->updatePriorBytes(firstRecursiveSliceOffset, &tempReshuffleBuffer[0], allSlicesSize); - if (!continueThisLevel) { - qCDebug(octree) << "WARNING UNEXPECTED CASE: Failed to update recursive slice!!!"; - qCDebug(octree) << "This is not expected!!!! -- continueThisLevel=FALSE...."; - } - } } // end keepDiggingDeeper // If we made it this far, then we've written all of our child data... if this element is the root diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 514a9b391b..5f5aa1432a 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -28,7 +28,6 @@ #include "OctreePacketData.h" #include "OctreeSceneStats.h" -class CoverageMap; class ReadBitstreamToTreeParams; class Octree; class OctreeElement; @@ -57,8 +56,6 @@ const bool NO_COLOR = false; const bool WANT_COLOR = true; const bool COLLAPSE_EMPTY_TREE = true; const bool DONT_COLLAPSE = false; -const bool NO_OCCLUSION_CULLING = false; -const bool WANT_OCCLUSION_CULLING = true; const int DONT_CHOP = 0; const int NO_BOUNDARY_ADJUST = 0; @@ -80,13 +77,11 @@ public: int chopLevels; bool deltaViewFrustum; const ViewFrustum* lastViewFrustum; - bool wantOcclusionCulling; int boundaryLevelAdjust; float octreeElementSizeScale; quint64 lastViewFrustumSent; bool forceSendScene; OctreeSceneStats* stats; - CoverageMap* map; JurisdictionMap* jurisdictionMap; OctreeElementExtraEncodeData* extraEncodeData; @@ -113,8 +108,6 @@ public: int chopLevels = 0, bool deltaViewFrustum = false, const ViewFrustum* lastViewFrustum = IGNORE_VIEW_FRUSTUM, - bool wantOcclusionCulling = NO_OCCLUSION_CULLING, - CoverageMap* map = IGNORE_COVERAGE_MAP, int boundaryLevelAdjust = NO_BOUNDARY_ADJUST, float octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE, quint64 lastViewFrustumSent = IGNORE_LAST_SENT, @@ -130,13 +123,11 @@ public: chopLevels(chopLevels), deltaViewFrustum(deltaViewFrustum), lastViewFrustum(lastViewFrustum), - wantOcclusionCulling(wantOcclusionCulling), boundaryLevelAdjust(boundaryLevelAdjust), octreeElementSizeScale(octreeElementSizeScale), lastViewFrustumSent(lastViewFrustumSent), forceSendScene(forceSendScene), stats(stats), - map(map), jurisdictionMap(jurisdictionMap), extraEncodeData(extraEncodeData), stopReason(UNKNOWN) diff --git a/libraries/octree/src/OctreeHeadlessViewer.cpp b/libraries/octree/src/OctreeHeadlessViewer.cpp index 88a77a4c53..b18f219d4d 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.cpp +++ b/libraries/octree/src/OctreeHeadlessViewer.cpp @@ -53,7 +53,6 @@ void OctreeHeadlessViewer::queryOctree() { _octreeQuery.setWantLowResMoving(true); _octreeQuery.setWantColor(true); _octreeQuery.setWantDelta(true); - _octreeQuery.setWantOcclusionCulling(false); _octreeQuery.setWantCompression(true); // TODO: should be on by default _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index e8beb0404c..2739b4a0d1 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -43,7 +43,6 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { if (_wantLowResMoving) { setAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); } if (_wantColor) { setAtBit(bitItems, WANT_COLOR_AT_BIT); } if (_wantDelta) { setAtBit(bitItems, WANT_DELTA_AT_BIT); } - if (_wantOcclusionCulling) { setAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT); } if (_wantCompression) { setAtBit(bitItems, WANT_COMPRESSION); } *destinationBuffer++ = bitItems; @@ -86,7 +85,6 @@ int OctreeQuery::parseData(NLPacket& packet) { _wantLowResMoving = oneAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); _wantColor = oneAtBit(bitItems, WANT_COLOR_AT_BIT); _wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT); - _wantOcclusionCulling = oneAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT); _wantCompression = oneAtBit(bitItems, WANT_COMPRESSION); // desired Max Octree PPS diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index 86474ffc02..9605cbfb5d 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -37,7 +37,7 @@ typedef unsigned long long quint64; const int WANT_LOW_RES_MOVING_BIT = 0; const int WANT_COLOR_AT_BIT = 1; const int WANT_DELTA_AT_BIT = 2; -const int WANT_OCCLUSION_CULLING_BIT = 3; +const int UNUSED_BIT = 3; // unused... available for new feature const int WANT_COMPRESSION = 4; // 5th bit class OctreeQuery : public NodeData { @@ -74,7 +74,6 @@ public: bool getWantColor() const { return _wantColor; } bool getWantDelta() const { return _wantDelta; } bool getWantLowResMoving() const { return _wantLowResMoving; } - bool getWantOcclusionCulling() const { return _wantOcclusionCulling; } bool getWantCompression() const { return _wantCompression; } int getMaxQueryPacketsPerSecond() const { return _maxQueryPPS; } float getOctreeSizeScale() const { return _octreeElementSizeScale; } @@ -84,7 +83,6 @@ public slots: void setWantLowResMoving(bool wantLowResMoving) { _wantLowResMoving = wantLowResMoving; } void setWantColor(bool wantColor) { _wantColor = wantColor; } void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; } - void setWantOcclusionCulling(bool wantOcclusionCulling) { _wantOcclusionCulling = wantOcclusionCulling; } void setWantCompression(bool wantCompression) { _wantCompression = wantCompression; } void setMaxQueryPacketsPerSecond(int maxQueryPPS) { _maxQueryPPS = maxQueryPPS; } void setOctreeSizeScale(float octreeSizeScale) { _octreeElementSizeScale = octreeSizeScale; } @@ -104,7 +102,6 @@ protected: bool _wantColor = true; bool _wantDelta = true; bool _wantLowResMoving = true; - bool _wantOcclusionCulling = false; bool _wantCompression = false; int _maxQueryPPS = DEFAULT_MAX_OCTREE_PPS; float _octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE; /// used for LOD calculations From f472b515c3e39397f1705be2b8915d8eb379055b Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 3 Dec 2015 11:05:28 -0800 Subject: [PATCH 316/401] remove wantsColor support since its always true and required for entities --- .../src/octree/OctreeQueryNode.cpp | 1 - .../src/octree/OctreeQueryNode.h | 2 +- .../src/octree/OctreeSendThread.cpp | 3 +- interface/src/Application.cpp | 1 - libraries/octree/src/Octree.cpp | 115 ++++++++---------- libraries/octree/src/Octree.h | 10 +- libraries/octree/src/OctreeHeadlessViewer.cpp | 1 - libraries/octree/src/OctreeQuery.cpp | 2 - libraries/octree/src/OctreeQuery.h | 7 +- libraries/octree/src/OctreeRenderer.cpp | 2 +- libraries/octree/src/OctreeSceneStats.cpp | 6 +- libraries/octree/src/OctreeSceneStats.h | 2 +- libraries/shared/src/OctalCode.cpp | 23 ---- libraries/shared/src/OctalCode.h | 2 - 14 files changed, 62 insertions(+), 115 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index cff2c7ee2e..06e9834804 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -179,7 +179,6 @@ void OctreeQueryNode::resetOctreePacket() { // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. - _currentPacketIsColor = getWantColor(); _currentPacketIsCompressed = getWantCompression(); OCTREE_PACKET_FLAGS flags = 0; if (_currentPacketIsColor) { diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 75c841851f..4140d42a5f 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -78,7 +78,7 @@ public: bool getCurrentPacketIsColor() const { return _currentPacketIsColor; } bool getCurrentPacketIsCompressed() const { return _currentPacketIsCompressed; } bool getCurrentPacketFormatMatches() { - return (getCurrentPacketIsColor() == getWantColor() && getCurrentPacketIsCompressed() == getWantCompression()); + return (getCurrentPacketIsCompressed() == getWantCompression()); } bool hasLodChanged() const { return _lodChanged; } diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index f873ee4808..efc81d6a21 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -321,7 +321,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // If we're starting a fresh packet, then... // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. - bool wantColor = nodeData->getWantColor(); bool wantCompression = nodeData->getWantCompression(); // If we have a packet waiting, and our desired want color, doesn't match the current waiting packets color @@ -456,7 +455,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus int boundaryLevelAdjust = boundaryLevelAdjustClient + (viewFrustumChanged && nodeData->getWantLowResMoving() ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); - EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor, + EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, boundaryLevelAdjust, octreeSizeScale, nodeData->getLastTimeBagEmpty(), diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 67a220311b..627f48f7cc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3074,7 +3074,6 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. _octreeQuery.setWantLowResMoving(true); - _octreeQuery.setWantColor(true); _octreeQuery.setWantDelta(true); _octreeQuery.setWantCompression(true); diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 1960537ced..64a2eaccc4 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -950,9 +950,9 @@ int Octree::encodeTreeBitstream(OctreeElementPointer element, // if childBytesWritten == 1 then something went wrong... that's not possible assert(childBytesWritten != 1); - // if includeColor and childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some + // if childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some // reason couldn't be written... so reset them here... This isn't true for the non-color included case - if (suppressEmptySubtrees() && params.includeColor && childBytesWritten == 2) { + if (suppressEmptySubtrees() && childBytesWritten == 2) { childBytesWritten = 0; //params.stopReason = EncodeBitstreamParams::UNKNOWN; // possibly should be DIDNT_FIT... } @@ -1293,7 +1293,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // NOW might be a good time to give our tree subclass and this element a chance to set up and check any extra encode data element->initializeExtraEncodeData(params); - // write the child element data... NOTE: includeColor means include element data + // write the child element data... // NOTE: the format of the bitstream is generally this: // [octalcode] // [bitmask for existence of child data] @@ -1303,65 +1303,63 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // N x [ ... tree for children ...] // // This section of the code, is writing the "N x [child data]" portion of this bitstream - if (params.includeColor) { - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (oneAtBit(childrenDataBits, i)) { - OctreeElementPointer childElement = element->getChildAtIndex(i); + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { + if (oneAtBit(childrenDataBits, i)) { + OctreeElementPointer childElement = element->getChildAtIndex(i); - // the childrenDataBits were set up by the in view/LOD logic, it may contain children that we've already - // processed and sent the data bits for. Let our tree subclass determine if it really wants to send the - // data for this child at this point - if (childElement && element->shouldIncludeChildData(i, params)) { + // the childrenDataBits were set up by the in view/LOD logic, it may contain children that we've already + // processed and sent the data bits for. Let our tree subclass determine if it really wants to send the + // data for this child at this point + if (childElement && element->shouldIncludeChildData(i, params)) { - int bytesBeforeChild = packetData->getUncompressedSize(); + int bytesBeforeChild = packetData->getUncompressedSize(); - // a childElement may "partially" write it's data. for example, the model server where the entire - // contents of the element may be larger than can fit in a single MTU/packetData. In this case, - // we want to allow the appendElementData() to respond that it produced partial data, which should be - // written, but that the childElement needs to be reprocessed in an additional pass or passes - // to be completed. - LevelDetails childDataLevelKey = packetData->startLevel(); + // a childElement may "partially" write it's data. for example, the model server where the entire + // contents of the element may be larger than can fit in a single MTU/packetData. In this case, + // we want to allow the appendElementData() to respond that it produced partial data, which should be + // written, but that the childElement needs to be reprocessed in an additional pass or passes + // to be completed. + LevelDetails childDataLevelKey = packetData->startLevel(); - OctreeElement::AppendState childAppendState = childElement->appendElementData(packetData, params); + OctreeElement::AppendState childAppendState = childElement->appendElementData(packetData, params); - // allow our tree subclass to do any additional bookkeeping it needs to do with encoded data state - element->updateEncodedData(i, childAppendState, params); + // allow our tree subclass to do any additional bookkeeping it needs to do with encoded data state + element->updateEncodedData(i, childAppendState, params); - // Continue this level so long as some part of this child element was appended. - bool childFit = (childAppendState != OctreeElement::NONE); + // Continue this level so long as some part of this child element was appended. + bool childFit = (childAppendState != OctreeElement::NONE); - // some datatypes (like Voxels) assume that all child data will fit, if it doesn't fit - // the data type wants to bail on this element level completely - if (!childFit && mustIncludeAllChildData()) { - continueThisLevel = false; - break; - } + // some datatypes (like Voxels) assume that all child data will fit, if it doesn't fit + // the data type wants to bail on this element level completely + if (!childFit && mustIncludeAllChildData()) { + continueThisLevel = false; + break; + } - // If the child was partially or fully appended, then mark the actualChildrenDataBits as including - // this child data - if (childFit) { - actualChildrenDataBits += (1 << (7 - i)); - continueThisLevel = packetData->endLevel(childDataLevelKey); - } else { - packetData->discardLevel(childDataLevelKey); - elementAppendState = OctreeElement::PARTIAL; - params.stopReason = EncodeBitstreamParams::DIDNT_FIT; - } + // If the child was partially or fully appended, then mark the actualChildrenDataBits as including + // this child data + if (childFit) { + actualChildrenDataBits += (1 << (7 - i)); + continueThisLevel = packetData->endLevel(childDataLevelKey); + } else { + packetData->discardLevel(childDataLevelKey); + elementAppendState = OctreeElement::PARTIAL; + params.stopReason = EncodeBitstreamParams::DIDNT_FIT; + } - // If this child was partially appended, then consider this element to be partially appended - if (childAppendState == OctreeElement::PARTIAL) { - elementAppendState = OctreeElement::PARTIAL; - params.stopReason = EncodeBitstreamParams::DIDNT_FIT; - } + // If this child was partially appended, then consider this element to be partially appended + if (childAppendState == OctreeElement::PARTIAL) { + elementAppendState = OctreeElement::PARTIAL; + params.stopReason = EncodeBitstreamParams::DIDNT_FIT; + } - int bytesAfterChild = packetData->getUncompressedSize(); + int bytesAfterChild = packetData->getUncompressedSize(); - bytesAtThisLevel += (bytesAfterChild - bytesBeforeChild); // keep track of byte count for this child + bytesAtThisLevel += (bytesAfterChild - bytesBeforeChild); // keep track of byte count for this child - // don't need to check childElement here, because we can't get here with no childElement - if (params.stats && (childAppendState != OctreeElement::NONE)) { - params.stats->colorSent(childElement); - } + // don't need to check childElement here, because we can't get here with no childElement + if (params.stats && (childAppendState != OctreeElement::NONE)) { + params.stats->colorSent(childElement); } } } @@ -1500,17 +1498,10 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // so, if the child returns 2 bytes out, we can actually consider that an empty tree also!! // // we can make this act like no bytes out, by just resetting the bytes out in this case - if (suppressEmptySubtrees() && params.includeColor && !params.includeExistsBits && childTreeBytesOut == 2) { + if (suppressEmptySubtrees() && !params.includeExistsBits && childTreeBytesOut == 2) { childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees } - // We used to try to collapse trees that didn't contain any data, but this does appear to create a problem - // in detecting element deletion. So, I've commented this out but left it in here as a warning to anyone else - // about not attempting to add this optimization back in, without solving the element deletion case. - // We need to send these bitMasks in case the exists in tree bitmask is indicating the deletion of a tree - //if (params.includeColor && params.includeExistsBits && childTreeBytesOut == 3) { - // childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees - //} bytesAtThisLevel += childTreeBytesOut; @@ -1530,7 +1521,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // If this is the last of the child exists bits, then we're actually be rolling out the entire tree if (params.stats && childrenExistInPacketBits == 0) { - params.stats->childBitsRemoved(params.includeExistsBits, params.includeColor); + params.stats->childBitsRemoved(params.includeExistsBits); } if (!continueThisLevel) { @@ -1825,7 +1816,7 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr unsigned char* dataAt = entireFileDataSection; - ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, + ReadBitstreamToTreeParams args(NO_EXISTS_BITS, NULL, 0, SharedNodePointer(), wantImportProgress, gotVersion); readBitstreamToTree(dataAt, dataLength, args); @@ -1864,7 +1855,7 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr unsigned char* dataAt = fileChunk; unsigned long dataLength = chunkLength; - ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, + ReadBitstreamToTreeParams args(NO_EXISTS_BITS, NULL, 0, SharedNodePointer(), wantImportProgress, gotVersion); readBitstreamToTree(dataAt, dataLength, args); @@ -2012,7 +2003,7 @@ void Octree::writeToSVOFile(const char* fileName, OctreeElementPointer element) bool lastPacketWritten = false; while (OctreeElementPointer subTree = elementBag.extract()) { - EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); + EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, NO_EXISTS_BITS); withReadLock([&] { params.extraEncodeData = &extraEncodeData; bytesWritten = encodeTreeBitstream(subTree, &packetData, elementBag, params); diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 5f5aa1432a..3ca8528a2f 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -52,8 +52,6 @@ typedef QHash CubeList; const bool NO_EXISTS_BITS = false; const bool WANT_EXISTS_BITS = true; -const bool NO_COLOR = false; -const bool WANT_COLOR = true; const bool COLLAPSE_EMPTY_TREE = true; const bool DONT_COLLAPSE = false; @@ -72,7 +70,6 @@ public: int maxEncodeLevel; int maxLevelReached; const ViewFrustum* viewFrustum; - bool includeColor; bool includeExistsBits; int chopLevels; bool deltaViewFrustum; @@ -103,7 +100,6 @@ public: EncodeBitstreamParams( int maxEncodeLevel = INT_MAX, const ViewFrustum* viewFrustum = IGNORE_VIEW_FRUSTUM, - bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, int chopLevels = 0, bool deltaViewFrustum = false, @@ -118,7 +114,6 @@ public: maxEncodeLevel(maxEncodeLevel), maxLevelReached(0), viewFrustum(viewFrustum), - includeColor(includeColor), includeExistsBits(includeExistsBits), chopLevels(chopLevels), deltaViewFrustum(deltaViewFrustum), @@ -181,7 +176,6 @@ public: class ReadBitstreamToTreeParams { public: - bool includeColor; bool includeExistsBits; OctreeElementPointer destinationElement; QUuid sourceUUID; @@ -192,14 +186,12 @@ public: int entitiesPerPacket = 0; ReadBitstreamToTreeParams( - bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, OctreeElementPointer destinationElement = NULL, QUuid sourceUUID = QUuid(), SharedNodePointer sourceNode = SharedNodePointer(), bool wantImportProgress = false, PacketVersion bitstreamVersion = 0) : - includeColor(includeColor), includeExistsBits(includeExistsBits), destinationElement(destinationElement), sourceUUID(sourceUUID), @@ -306,7 +298,7 @@ public: Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL); // Note: this assumes the fileFormat is the HIO individual voxels code files - void loadOctreeFile(const char* fileName, bool wantColorRandomizer); + void loadOctreeFile(const char* fileName); // Octree exporters void writeToFile(const char* filename, OctreeElementPointer element = NULL, QString persistAsFileType = "svo"); diff --git a/libraries/octree/src/OctreeHeadlessViewer.cpp b/libraries/octree/src/OctreeHeadlessViewer.cpp index b18f219d4d..f1c2172d86 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.cpp +++ b/libraries/octree/src/OctreeHeadlessViewer.cpp @@ -51,7 +51,6 @@ void OctreeHeadlessViewer::queryOctree() { // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. _octreeQuery.setWantLowResMoving(true); - _octreeQuery.setWantColor(true); _octreeQuery.setWantDelta(true); _octreeQuery.setWantCompression(true); // TODO: should be on by default diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index 2739b4a0d1..c431d66bf2 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -41,7 +41,6 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { // bitMask of less than byte wide items unsigned char bitItems = 0; if (_wantLowResMoving) { setAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); } - if (_wantColor) { setAtBit(bitItems, WANT_COLOR_AT_BIT); } if (_wantDelta) { setAtBit(bitItems, WANT_DELTA_AT_BIT); } if (_wantCompression) { setAtBit(bitItems, WANT_COMPRESSION); } @@ -83,7 +82,6 @@ int OctreeQuery::parseData(NLPacket& packet) { unsigned char bitItems = 0; bitItems = (unsigned char)*sourceBuffer++; _wantLowResMoving = oneAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); - _wantColor = oneAtBit(bitItems, WANT_COLOR_AT_BIT); _wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT); _wantCompression = oneAtBit(bitItems, WANT_COMPRESSION); diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index 9605cbfb5d..71c9361e68 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -35,9 +35,9 @@ typedef unsigned long long quint64; // First bitset const int WANT_LOW_RES_MOVING_BIT = 0; -const int WANT_COLOR_AT_BIT = 1; +const int UNUSED_BIT_1 = 1; // unused... available for new feature const int WANT_DELTA_AT_BIT = 2; -const int UNUSED_BIT = 3; // unused... available for new feature +const int UNUSED_BIT_3 = 3; // unused... available for new feature const int WANT_COMPRESSION = 4; // 5th bit class OctreeQuery : public NodeData { @@ -71,7 +71,6 @@ public: void setCameraEyeOffsetPosition(const glm::vec3& eyeOffsetPosition) { _cameraEyeOffsetPosition = eyeOffsetPosition; } // related to Octree Sending strategies - bool getWantColor() const { return _wantColor; } bool getWantDelta() const { return _wantDelta; } bool getWantLowResMoving() const { return _wantLowResMoving; } bool getWantCompression() const { return _wantCompression; } @@ -81,7 +80,6 @@ public: public slots: void setWantLowResMoving(bool wantLowResMoving) { _wantLowResMoving = wantLowResMoving; } - void setWantColor(bool wantColor) { _wantColor = wantColor; } void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; } void setWantCompression(bool wantCompression) { _wantCompression = wantCompression; } void setMaxQueryPacketsPerSecond(int maxQueryPPS) { _maxQueryPPS = maxQueryPPS; } @@ -99,7 +97,6 @@ protected: glm::vec3 _cameraEyeOffsetPosition = glm::vec3(0.0f); // octree server sending items - bool _wantColor = true; bool _wantDelta = true; bool _wantLowResMoving = true; bool _wantCompression = false; diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp index b7be4cf3e7..c65359f12f 100644 --- a/libraries/octree/src/OctreeRenderer.cpp +++ b/libraries/octree/src/OctreeRenderer.cpp @@ -115,7 +115,7 @@ void OctreeRenderer::processDatagram(NLPacket& packet, SharedNodePointer sourceN if (sectionLength) { // ask the VoxelTree to read the bitstream into the tree - ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, + ReadBitstreamToTreeParams args(WANT_EXISTS_BITS, NULL, sourceUUID, sourceNode, false, packet.getVersion()); quint64 startUncompress, startLock = usecTimestampNow(); quint64 startReadBitsteam, endReadBitsteam; diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index 22352fbe3b..c70e0e4935 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -371,14 +371,12 @@ void OctreeSceneStats::existsInPacketBitsWritten() { _existsInPacketBitsWritten++; } -void OctreeSceneStats::childBitsRemoved(bool includesExistsBits, bool includesColors) { +void OctreeSceneStats::childBitsRemoved(bool includesExistsBits) { _existsInPacketBitsWritten--; if (includesExistsBits) { _existsBitsWritten--; } - if (includesColors) { - _colorBitsWritten--; - } + _colorBitsWritten--; _treesRemoved++; } diff --git a/libraries/octree/src/OctreeSceneStats.h b/libraries/octree/src/OctreeSceneStats.h index bdb4ef206a..f8ecf93106 100644 --- a/libraries/octree/src/OctreeSceneStats.h +++ b/libraries/octree/src/OctreeSceneStats.h @@ -89,7 +89,7 @@ public: void existsInPacketBitsWritten(); /// Fix up tracking statistics in case where bitmasks were removed for some reason - void childBitsRemoved(bool includesExistsBits, bool includesColors); + void childBitsRemoved(bool includesExistsBits); /// Pack the details of the statistics into a buffer for sending as a network packet int packIntoPacket(); diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index 0b77683d4c..1fa18903cb 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -264,29 +264,6 @@ unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLev return newCode; } -unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode, - bool includeColorSpace) { - - int oldCodeLength = numberOfThreeBitSectionsInCode(originalOctalCode); - int newParentCodeLength = numberOfThreeBitSectionsInCode(newParentOctalCode); - int newCodeLength = newParentCodeLength + oldCodeLength; - int bufferLength = newCodeLength + (includeColorSpace ? SIZE_OF_COLOR_DATA : 0); - unsigned char* newCode = new unsigned char[bufferLength]; - *newCode = newCodeLength; // set the length byte - - // copy parent code section first - for (int sectionFromParent = 0; sectionFromParent < newParentCodeLength; sectionFromParent++) { - char sectionValue = getOctalCodeSectionValue(newParentOctalCode, sectionFromParent); - setOctalCodeSectionValue(newCode, sectionFromParent, sectionValue); - } - // copy original code section next - for (int sectionFromOriginal = 0; sectionFromOriginal < oldCodeLength; sectionFromOriginal++) { - char sectionValue = getOctalCodeSectionValue(originalOctalCode, sectionFromOriginal); - setOctalCodeSectionValue(newCode, sectionFromOriginal + newParentCodeLength, sectionValue); - } - return newCode; -} - bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* possibleDescendent, int descendentsChild) { if (!possibleAncestor || !possibleDescendent) { return false; diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index 9229157c3d..09766b685a 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -36,8 +36,6 @@ const int UNKNOWN_OCTCODE_LENGTH = -2; int numberOfThreeBitSectionsInCode(const unsigned char* octalCode, int maxBytes = UNKNOWN_OCTCODE_LENGTH); unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLevels); -unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode, - bool includeColorSpace = false); const int CHECK_NODE_ONLY = -1; bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* possibleDescendent, From 18e62290f3b7ea9a71afa8b65f1ff0f46d4fd365 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 4 Dec 2015 08:37:46 -0800 Subject: [PATCH 317/401] fix warnings --- libraries/octree/src/Octree.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 64a2eaccc4..aacb57f31d 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -1442,10 +1442,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, // final packet in standard order. So what we're going to do is keep track of how big each subtree was in bytes, // and then later reshuffle these sections of our output buffer back into normal order. This allows us to make // a single recursive pass in distance sorted order, but retain standard order in our encoded packet - int recursiveSliceSizes[NUMBER_OF_CHILDREN]; - const unsigned char* recursiveSliceStarts[NUMBER_OF_CHILDREN]; - int firstRecursiveSliceOffset = packetData->getUncompressedByteOffset(); - int allSlicesSize = 0; // for each child element in Distance sorted order..., check to see if they exist, are colored, and in view, and if so // add them to our distance ordered array of children @@ -1456,8 +1452,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, if (oneAtBit(childrenExistInPacketBits, originalIndex)) { int thisLevel = currentEncodeLevel; - // remember this for reshuffling - recursiveSliceStarts[originalIndex] = packetData->getUncompressedData() + packetData->getUncompressedSize(); int childTreeBytesOut = 0; @@ -1478,10 +1472,6 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element, } } - // remember this for reshuffling - recursiveSliceSizes[originalIndex] = childTreeBytesOut; - allSlicesSize += childTreeBytesOut; - // if the child wrote 0 bytes, it means that nothing below exists or was in view, or we ran out of space, // basically, the children below don't contain any info. From cd26422ca0a11d05ad467d667108817cacf4a229 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 3 Dec 2015 13:17:11 -0800 Subject: [PATCH 318/401] Fix warnings on OS X --- libraries/audio/src/AudioReverb.cpp | 74 ++++++++++++++--------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/libraries/audio/src/AudioReverb.cpp b/libraries/audio/src/AudioReverb.cpp index f06bbe76ed..ff286d780b 100644 --- a/libraries/audio/src/AudioReverb.cpp +++ b/libraries/audio/src/AudioReverb.cpp @@ -1324,64 +1324,64 @@ static int scaleDelay(float delay, float sampleRate) { // input clamped to [0.0f, 100.0f] // static const float earlyMix0Table[][2] = { - 0.0000f, 0.6000f, - 63.3333f, 0.0800f, - 83.3333f, 0.0200f, - 93.3333f, 0.0048f, - 100.0000f, 0.0048f, + {0.0000f, 0.6000f}, + {63.3333f, 0.0800f}, + {83.3333f, 0.0200f}, + {93.3333f, 0.0048f}, + {100.0000f, 0.0048f}, }; static const float earlyMix1Table[][2] = { - 0.0000f, 0.3360f, - 20.0000f, 0.6000f, - 100.0000f, 0.0240f, + {0.0000f, 0.3360f}, + {20.0000f, 0.6000f}, + {100.0000f, 0.0240f}, }; static const float earlyMix2Table[][2] = { - 0.0000f, 0.0480f, - 13.3333f, 0.0960f, - 53.3333f, 0.9600f, - 100.0000f, 0.1200f, + {0.0000f, 0.0480f}, + {13.3333f, 0.0960f}, + {53.3333f, 0.9600f}, + {100.0000f, 0.1200f}, }; static const float lateMix0Table[][2] = { - 0.0000f, 0.1250f, - 13.3333f, 0.1875f, - 66.6666f, 0.7500f, - 100.0000f, 0.8750f, + {0.0000f, 0.1250f}, + {13.3333f, 0.1875f}, + {66.6666f, 0.7500f}, + {100.0000f, 0.8750f}, }; static const float lateMix1Table[][2] = { - 0.0000f, 0.9990f, - 33.3333f, 0.5000f, - 66.6666f, 0.9990f, - 93.3333f, 0.6000f, - 100.0000f, 0.6000f, + {0.0000f, 0.9990f}, + {33.3333f, 0.5000f}, + {66.6666f, 0.9990f}, + {93.3333f, 0.6000f}, + {100.0000f, 0.6000f}, }; static const float lateMix2Table[][2] = { - 0.0000f, 0.9990f, - 33.3333f, 0.9990f, - 63.3333f, 0.4500f, - 100.0000f, 0.9990f, + {0.0000f, 0.9990f}, + {33.3333f, 0.9990f}, + {63.3333f, 0.4500f}, + {100.0000f, 0.9990f}, }; static const float diffusionCoefTable[][2] = { - 0.0000f, 0.0000f, - 20.0000f, 0.0470f, - 33.3333f, 0.0938f, - 46.6666f, 0.1563f, - 60.0000f, 0.2344f, - 73.3333f, 0.3125f, - 93.3333f, 0.5000f, - 100.0000f, PHI, + {0.0000f, 0.0000f}, + {20.0000f, 0.0470f}, + {33.3333f, 0.0938f}, + {46.6666f, 0.1563f}, + {60.0000f, 0.2344f}, + {73.3333f, 0.3125f}, + {93.3333f, 0.5000f}, + {100.0000f, PHI}, }; static const float roomSizeTable[][2] = { - 0.0000f, 0.1500f, - 25.0000f, 0.3000f, - 50.0000f, 0.5000f, - 100.0000f, 1.0000f, + {0.0000f, 0.1500f}, + {25.0000f, 0.3000f}, + {50.0000f, 0.5000f}, + {100.0000f, 1.0000f}, }; static float interpolateTable(const float table[][2], float x) { From cb758ca6b4256391a68b2d603b2a8e21854483e9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 4 Dec 2015 08:55:43 -0800 Subject: [PATCH 319/401] Fix override warnings on XCode 7 --- assignment-client/src/entities/EntityServer.h | 6 ++-- .../impl/endpoints/ActionEndpoint.h | 4 +-- .../impl/endpoints/InputEndpoint.h | 6 ++-- .../controllers/impl/filters/PulseFilter.h | 2 +- .../controllers/impl/filters/ScaleFilter.h | 2 +- .../src/RenderableModelEntityItem.h | 30 +++++++++---------- .../recording/src/recording/impl/ArrayClip.h | 4 +-- .../src/recording/impl/PointerClip.h | 2 +- 8 files changed, 28 insertions(+), 28 deletions(-) diff --git a/assignment-client/src/entities/EntityServer.h b/assignment-client/src/entities/EntityServer.h index 89b445c449..241c4c4d4f 100644 --- a/assignment-client/src/entities/EntityServer.h +++ b/assignment-client/src/entities/EntityServer.h @@ -50,10 +50,10 @@ public: virtual void entityCreated(const EntityItem& newEntity, const SharedNodePointer& senderNode) override; virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject) override; - virtual QString serverSubclassStats(); + virtual QString serverSubclassStats() override; - virtual void trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode); - virtual void trackViewerGone(const QUuid& viewerNode); + virtual void trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode) override; + virtual void trackViewerGone(const QUuid& viewerNode) override; public slots: void pruneDeletedEntities(); diff --git a/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.h index e07dc9e4c8..1073dc6593 100644 --- a/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.h +++ b/libraries/controllers/src/controllers/impl/endpoints/ActionEndpoint.h @@ -23,10 +23,10 @@ class ActionEndpoint : public Endpoint { public: ActionEndpoint(const Input& id = Input::INVALID_INPUT) : Endpoint(id) { } - virtual float peek() const { return _currentValue; } + virtual float peek() const override { return _currentValue; } virtual void apply(float newValue, const Pointer& source) override; - virtual Pose peekPose() const { return _currentPose; } + virtual Pose peekPose() const override { return _currentPose; } virtual void apply(const Pose& value, const Pointer& source) override; virtual void reset() override; diff --git a/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.h b/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.h index 663168bedc..7e4560dcf9 100644 --- a/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.h +++ b/libraries/controllers/src/controllers/impl/endpoints/InputEndpoint.h @@ -28,9 +28,9 @@ public: virtual Pose pose() override; virtual void apply(const Pose& value, const Pointer& source) override { } - virtual bool writeable() const { return false; } - virtual bool readable() const { return !_read; } - virtual void reset() { _read = false; } + virtual bool writeable() const override { return false; } + virtual bool readable() const override { return !_read; } + virtual void reset() override { _read = false; } private: bool _read { false }; diff --git a/libraries/controllers/src/controllers/impl/filters/PulseFilter.h b/libraries/controllers/src/controllers/impl/filters/PulseFilter.h index dbe2eba81b..271f4a04f6 100644 --- a/libraries/controllers/src/controllers/impl/filters/PulseFilter.h +++ b/libraries/controllers/src/controllers/impl/filters/PulseFilter.h @@ -23,7 +23,7 @@ public: virtual float apply(float value) const override; - virtual bool parseParameters(const QJsonValue& parameters); + virtual bool parseParameters(const QJsonValue& parameters) override; private: static const float DEFAULT_LAST_EMIT_TIME; diff --git a/libraries/controllers/src/controllers/impl/filters/ScaleFilter.h b/libraries/controllers/src/controllers/impl/filters/ScaleFilter.h index 39c5edd4e5..670da53fe8 100644 --- a/libraries/controllers/src/controllers/impl/filters/ScaleFilter.h +++ b/libraries/controllers/src/controllers/impl/filters/ScaleFilter.h @@ -23,7 +23,7 @@ public: virtual float apply(float value) const override { return value * _scale; } - virtual bool parseParameters(const QJsonValue& parameters); + virtual bool parseParameters(const QJsonValue& parameters) override; private: float _scale = 1.0f; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index c4e36c240a..b791373bde 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -30,42 +30,42 @@ public: virtual void setDimensions(const glm::vec3& value) override; - virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; - virtual bool setProperties(const EntityItemProperties& properties); + virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; + virtual bool setProperties(const EntityItemProperties& properties) override; virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData, - bool& somethingChanged); + bool& somethingChanged) override; - virtual void somethingChangedNotification() { + virtual void somethingChangedNotification() override { // FIX ME: this is overly aggressive. We only really need to simulate() if something about // the world space transform has changed and/or if some animation is occurring. _needsInitialSimulation = true; } virtual bool readyToAddToScene(RenderArgs* renderArgs = nullptr); - virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges); - virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges); + virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override; + virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override; - virtual void render(RenderArgs* args); - virtual bool supportsDetailedRayIntersection() const { return true; } + virtual void render(RenderArgs* args) override; + virtual bool supportsDetailedRayIntersection() const override { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, - void** intersectedObject, bool precisionPicking) const; + void** intersectedObject, bool precisionPicking) const override; Model* getModel(EntityTreeRenderer* renderer); - virtual bool needsToCallUpdate() const; - virtual void update(const quint64& now); + virtual bool needsToCallUpdate() const override; + virtual void update(const quint64& now) override; - virtual void setCompoundShapeURL(const QString& url); + virtual void setCompoundShapeURL(const QString& url) override; - bool isReadyToComputeShape(); - void computeShapeInfo(ShapeInfo& info); + virtual bool isReadyToComputeShape() override; + virtual void computeShapeInfo(ShapeInfo& info) override; - virtual bool contains(const glm::vec3& point) const; + virtual bool contains(const glm::vec3& point) const override; private: void remapTextures(); diff --git a/libraries/recording/src/recording/impl/ArrayClip.h b/libraries/recording/src/recording/impl/ArrayClip.h index 10b3580228..165842d24a 100644 --- a/libraries/recording/src/recording/impl/ArrayClip.h +++ b/libraries/recording/src/recording/impl/ArrayClip.h @@ -32,7 +32,7 @@ public: return _frames.size(); } - Clip::Pointer duplicate() const { + virtual Clip::Pointer duplicate() const override { auto result = newClip(); Locker lock(_mutex); for (size_t i = 0; i < _frames.size(); ++i) { @@ -41,7 +41,7 @@ public: return result; } - virtual void seekFrameTime(Frame::Time offset) { + virtual void seekFrameTime(Frame::Time offset) override { Locker lock(_mutex); auto itr = std::lower_bound(_frames.begin(), _frames.end(), offset, [](const T& a, Frame::Time b)->bool { diff --git a/libraries/recording/src/recording/impl/PointerClip.h b/libraries/recording/src/recording/impl/PointerClip.h index f5c0dd6bc4..48d4e4cbc8 100644 --- a/libraries/recording/src/recording/impl/PointerClip.h +++ b/libraries/recording/src/recording/impl/PointerClip.h @@ -45,7 +45,7 @@ public: // FIXME move to frame? static const qint64 MINIMUM_FRAME_SIZE = sizeof(FrameType) + sizeof(Frame::Time) + sizeof(FrameSize); protected: - void reset(); + void reset() override; virtual FrameConstPointer readFrame(size_t index) const override; QJsonDocument _header; uchar* _data { nullptr }; From a455cb880f0d0571f9590f2d4012884f6bd0e5a9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 4 Dec 2015 09:23:16 -0800 Subject: [PATCH 320/401] Fix typeid warning --- interface/src/ui/overlays/Overlays.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 96553843c8..f6e6851c38 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -533,15 +533,13 @@ bool Overlays::isLoaded(unsigned int id) { QSizeF Overlays::textSize(unsigned int id, const QString& text) const { Overlay::Pointer thisOverlay = _overlaysHUD[id]; if (thisOverlay) { - if (typeid(*thisOverlay) == typeid(TextOverlay)) { - return std::dynamic_pointer_cast(thisOverlay)->textSize(text); + if (auto textOverlay = std::dynamic_pointer_cast(thisOverlay)) { + return textOverlay->textSize(text); } } else { thisOverlay = _overlaysWorld[id]; - if (thisOverlay) { - if (typeid(*thisOverlay) == typeid(Text3DOverlay)) { - return std::dynamic_pointer_cast(thisOverlay)->textSize(text); - } + if (auto text3dOverlay = std::dynamic_pointer_cast(thisOverlay)) { + return text3dOverlay->textSize(text); } } return QSizeF(0.0f, 0.0f); From 07387ab8c0a7d4240f99f3b13ad7d99b3510ddb9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 4 Dec 2015 10:01:43 -0800 Subject: [PATCH 321/401] Fix most OpenGL warnings --- .../display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp | 1 - .../src/display-plugins/WindowOpenGLDisplayPlugin.cpp | 1 - libraries/gpu/src/gpu/GLBackendShared.h | 2 ++ libraries/render-utils/src/FboCache.h | 1 - plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp | 1 - 5 files changed, 2 insertions(+), 4 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 01cb0961e4..09f4ba9897 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -6,7 +6,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "OpenGLDisplayPlugin.h" -#include #include #include diff --git a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp index 6ddc791503..e6fb2be2f5 100644 --- a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp @@ -8,7 +8,6 @@ #include "WindowOpenGLDisplayPlugin.h" #include -#include #include "plugins/PluginContainer.h" diff --git a/libraries/gpu/src/gpu/GLBackendShared.h b/libraries/gpu/src/gpu/GLBackendShared.h index 21bd10a33a..59da9ab9e9 100644 --- a/libraries/gpu/src/gpu/GLBackendShared.h +++ b/libraries/gpu/src/gpu/GLBackendShared.h @@ -11,6 +11,8 @@ #ifndef hifi_gpu_GLBackend_Shared_h #define hifi_gpu_GLBackend_Shared_h +#include + #include #include "GPULogging.h" diff --git a/libraries/render-utils/src/FboCache.h b/libraries/render-utils/src/FboCache.h index 78c3194eb5..cedc4bff82 100644 --- a/libraries/render-utils/src/FboCache.h +++ b/libraries/render-utils/src/FboCache.h @@ -12,7 +12,6 @@ #ifndef hifi_FboCache_h #define hifi_FboCache_h -#include #include #include #include diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp index f0398158b4..8cfe061e37 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.cpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include From 786e241a29bbd0e86f34060e6c4fc3bb4d05c092 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 4 Dec 2015 10:14:40 -0800 Subject: [PATCH 322/401] blocks dont collide when held --- unpublishedScripts/hiddenEntityReset.js | 4 ++++ unpublishedScripts/masterReset.js | 3 +++ 2 files changed, 7 insertions(+) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index 48745715f9..259cdd066c 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -1366,7 +1366,11 @@ userData: JSON.stringify({ resetMe: { resetMe: true + }, + grabbableKey; { + invertSolidWhileHeld: true } + }) }); diff --git a/unpublishedScripts/masterReset.js b/unpublishedScripts/masterReset.js index 6a870f988f..2034bd9601 100644 --- a/unpublishedScripts/masterReset.js +++ b/unpublishedScripts/masterReset.js @@ -1346,6 +1346,9 @@ MasterReset = function() { userData: JSON.stringify({ resetMe: { resetMe: true + }, + grabbableKey: { + invertSolidWhileHeld: true } }) }); From b9ace94ff1fa8e0b86603c10afe3f20eb050d7ae Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 30 Nov 2015 09:35:18 -0800 Subject: [PATCH 323/401] Prototyping threaded present --- interface/resources/qml/Stats.qml | 7 +- interface/src/Application.cpp | 83 +++--- interface/src/Application.h | 6 + interface/src/GLCanvas.cpp | 21 -- interface/src/GLCanvas.h | 2 - interface/src/PluginContainerProxy.cpp | 87 ++++-- interface/src/PluginContainerProxy.h | 7 +- interface/src/avatar/AvatarUpdate.cpp | 3 +- interface/src/avatar/MyAvatar.cpp | 2 +- interface/src/ui/ApplicationCompositor.cpp | 2 +- interface/src/ui/Stats.cpp | 8 +- interface/src/ui/Stats.h | 6 +- .../Basic2DWindowOpenGLDisplayPlugin.cpp | 80 +++--- .../Basic2DWindowOpenGLDisplayPlugin.h | 9 +- .../src/display-plugins/DisplayPlugin.cpp | 30 +- .../src/display-plugins/NullDisplayPlugin.cpp | 13 +- .../src/display-plugins/NullDisplayPlugin.h | 6 +- .../display-plugins/OpenGLDisplayPlugin.cpp | 258 +++++++++++++++--- .../src/display-plugins/OpenGLDisplayPlugin.h | 66 +++-- .../WindowOpenGLDisplayPlugin.cpp | 28 +- .../WindowOpenGLDisplayPlugin.h | 12 +- .../openvr/OpenVrDisplayPlugin.cpp | 40 +-- .../openvr/OpenVrDisplayPlugin.h | 6 +- .../stereo/InterleavedStereoDisplayPlugin.cpp | 8 +- .../stereo/InterleavedStereoDisplayPlugin.h | 3 +- libraries/gl/src/gl/GLEscrow.h | 24 +- libraries/plugins/src/plugins/DisplayPlugin.h | 30 +- .../plugins/src/plugins/PluginContainer.h | 11 +- .../oculus/src/OculusBaseDisplayPlugin.cpp | 28 +- plugins/oculus/src/OculusBaseDisplayPlugin.h | 8 +- .../oculus/src/OculusDebugDisplayPlugin.cpp | 10 - plugins/oculus/src/OculusDebugDisplayPlugin.h | 3 - plugins/oculus/src/OculusDisplayPlugin.cpp | 60 ++-- plugins/oculus/src/OculusDisplayPlugin.h | 11 +- plugins/oculus/src/OculusHelpers.cpp | 1 - .../src/OculusLegacyDisplayPlugin.h | 1 - tests/controllers/src/main.cpp | 7 +- 37 files changed, 600 insertions(+), 387 deletions(-) diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index 84381cc754..56d4f9c14b 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -45,7 +45,12 @@ Item { Text { color: root.fontColor; font.pixelSize: root.fontSize - text: "Framerate: " + root.framerate + text: "Render Rate: " + root.renderrate + } + Text { + color: root.fontColor; + font.pixelSize: root.fontSize + text: "Present Rate: " + root.presentrate } Text { color: root.fontColor; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c552feb51b..581fdbec5a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -150,6 +150,8 @@ #include "InterfaceParentFinder.h" +#include +#include // ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. @@ -1089,6 +1091,7 @@ void Application::paintGL() { // update fps once a second if (now - _lastFramesPerSecondUpdate > USECS_PER_SECOND) { _fps = _framesPerSecond.getAverage(); + qDebug() << QString::number(_fps, 'g', 4); _lastFramesPerSecondUpdate = now; } @@ -1136,7 +1139,7 @@ void Application::paintGL() { _lastInstantaneousFps = instantaneousFps; auto displayPlugin = getActiveDisplayPlugin(); - displayPlugin->preRender(); + // FIXME not needed anymore? _offscreenContext->makeCurrent(); // update the avatar with a fresh HMD pose @@ -1304,6 +1307,13 @@ void Application::paintGL() { auto baseProjection = renderArgs._viewFrustum->getProjection(); auto hmdInterface = DependencyManager::get(); float IPDScale = hmdInterface->getIPDScale(); + + // Tell the plugin what pose we're using to render. In this case we're just using the + // unmodified head pose because the only plugin that cares (the Oculus plugin) uses it + // for rotational timewarp. If we move to support positonal timewarp, we need to + // ensure this contains the full pose composed with the eye offsets. + mat4 headPose = displayPlugin->getHeadPose(_frameCount); + // FIXME we probably don't need to set the projection matrix every frame, // only when the display plugin changes (or in non-HMD modes when the user // changes the FOV manually, which right now I don't think they can. @@ -1319,12 +1329,7 @@ void Application::paintGL() { mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * IPDScale); eyeOffsets[eye] = eyeOffsetTransform; - // Tell the plugin what pose we're using to render. In this case we're just using the - // unmodified head pose because the only plugin that cares (the Oculus plugin) uses it - // for rotational timewarp. If we move to support positonal timewarp, we need to - // ensure this contains the full pose composed with the eye offsets. - mat4 headPose = displayPlugin->getHeadPose(); - displayPlugin->setEyeRenderPose(eye, headPose); + displayPlugin->setEyeRenderPose(_frameCount, eye, headPose); eyeProjections[eye] = displayPlugin->getProjection(eye, baseProjection); }); @@ -1367,44 +1372,35 @@ void Application::paintGL() { { PROFILE_RANGE(__FUNCTION__ "/pluginOutput"); PerformanceTimer perfTimer("pluginOutput"); - auto primaryFbo = framebufferCache->getPrimaryFramebuffer(); - GLuint finalTexture = gpu::GLBackend::getTextureID(primaryFbo->getRenderBuffer(0)); - // Ensure the rendering context commands are completed when rendering - GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); - // Ensure the sync object is flushed to the driver thread before releasing the context - // CRITICAL for the mac driver apparently. - glFlush(); - _offscreenContext->doneCurrent(); - - // Switches to the display plugin context - displayPlugin->preDisplay(); - // Ensure all operations from the previous context are complete before we try to read the fbo - glWaitSync(sync, 0, GL_TIMEOUT_IGNORED); - glDeleteSync(sync); uint64_t displayStart = usecTimestampNow(); + auto primaryFramebuffer = framebufferCache->getPrimaryFramebuffer(); + auto scratchFramebuffer = framebufferCache->getFramebuffer(); + gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) { + gpu::Vec4i rect; + rect.z = size.width(); + rect.w = size.height(); + batch.setFramebuffer(scratchFramebuffer); + batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)); + batch.blit(primaryFramebuffer, rect, scratchFramebuffer, rect); + batch.setFramebuffer(nullptr); + }); + auto finalTexturePointer = scratchFramebuffer->getRenderBuffer(0); + GLuint finalTexture = gpu::GLBackend::getTextureID(finalTexturePointer); - { - PROFILE_RANGE(__FUNCTION__ "/pluginDisplay"); - PerformanceTimer perfTimer("pluginDisplay"); - displayPlugin->display(finalTexture, toGlm(size)); - } + Q_ASSERT(0 != finalTexture); + Q_ASSERT(!_lockedFramebufferMap.contains(finalTexture)); + _lockedFramebufferMap[finalTexture] = scratchFramebuffer; + Q_ASSERT(QOpenGLContext::currentContext() == _offscreenContext->getContext()); + displayPlugin->submitSceneTexture(_frameCount, finalTexture, toGlm(size)); + Q_ASSERT(QOpenGLContext::currentContext() == _offscreenContext->getContext()); - { - PROFILE_RANGE(__FUNCTION__ "/bufferSwap"); - PerformanceTimer perfTimer("bufferSwap"); - displayPlugin->finishFrame(); - } uint64_t displayEnd = usecTimestampNow(); const float displayPeriodUsec = (float)(displayEnd - displayStart); // usecs _lastPaintWait = displayPeriodUsec / (float)USECS_PER_SECOND; - } { - PerformanceTimer perfTimer("makeCurrent"); - _offscreenContext->makeCurrent(); Stats::getInstance()->setRenderDetails(renderArgs._details); - // Reset the gpu::Context Stages // Back to the default framebuffer; gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) { @@ -2612,7 +2608,7 @@ void Application::updateMyAvatarLookAtPosition() { lookAtPosition.x = -lookAtPosition.x; } if (isHMD) { - glm::mat4 headPose = getActiveDisplayPlugin()->getHeadPose(); + glm::mat4 headPose = getActiveDisplayPlugin()->getHeadPose(_frameCount); glm::quat hmdRotation = glm::quat_cast(headPose); lookAtSpot = _myCamera.getPosition() + myAvatar->getOrientation() * (hmdRotation * lookAtPosition); } else { @@ -4503,6 +4499,7 @@ void Application::toggleLogDialog() { } void Application::takeSnapshot() { +#if 0 QMediaPlayer* player = new QMediaPlayer(); QFileInfo inf = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav"); player->setMedia(QUrl::fromLocalFile(inf.absoluteFilePath())); @@ -4519,7 +4516,7 @@ void Application::takeSnapshot() { _snapshotShareDialog = new SnapshotShareDialog(fileName, _glWidget); } _snapshotShareDialog->show(); - +#endif } float Application::getRenderResolutionScale() const { @@ -4702,10 +4699,6 @@ const DisplayPlugin* Application::getActiveDisplayPlugin() const { return ((Application*)this)->getActiveDisplayPlugin(); } -bool _activatingDisplayPlugin{ false }; -QVector> _currentDisplayPluginActions; -QVector> _currentInputPluginActions; - static void addDisplayPluginToMenu(DisplayPluginPointer displayPlugin, bool active = false) { auto menu = Menu::getInstance(); QString name = displayPlugin->getName(); @@ -4735,9 +4728,9 @@ void Application::updateDisplayMode() { bool first = true; foreach(auto displayPlugin, displayPlugins) { addDisplayPluginToMenu(displayPlugin, first); - QObject::connect(displayPlugin.get(), &DisplayPlugin::requestRender, [this] { - paintGL(); - }); + QObject::connect(displayPlugin.get(), &DisplayPlugin::requestRender, + this, &Application::paintGL, Qt::QueuedConnection); + QObject::connect(displayPlugin.get(), &DisplayPlugin::recommendedFramebufferSizeChanged, [this](const QSize & size) { resizeGL(); }); @@ -4917,7 +4910,7 @@ mat4 Application::getEyeOffset(int eye) const { mat4 Application::getHMDSensorPose() const { if (isHMDMode()) { - return getActiveDisplayPlugin()->getHeadPose(); + return getActiveDisplayPlugin()->getHeadPose(_frameCount); } return mat4(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index e2445f7f22..1af252de95 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -158,6 +158,7 @@ public: bool isForeground() const { return _isForeground; } + uint32_t getFrameCount() { return _frameCount; } float getFps() const { return _fps; } float const HMD_TARGET_FRAME_RATE = 75.0f; float const DESKTOP_TARGET_FRAME_RATE = 60.0f; @@ -425,6 +426,11 @@ private: DisplayPluginPointer _displayPlugin; InputPluginList _activeInputPlugins; + bool _activatingDisplayPlugin { false }; + QVector> _currentDisplayPluginActions; + QVector> _currentInputPluginActions; + QMap _lockedFramebufferMap; + MainWindow* _window; ToolWindow* _toolWindow; diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index 0b4c6dde3d..ec96f7c5d4 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -13,27 +13,6 @@ #include "Application.h" #include "GLCanvas.h" -#include - -#include "MainWindow.h" -#include "Menu.h" - -void GLCanvas::paintGL() { - PROFILE_RANGE(__FUNCTION__); - - // FIXME - I'm not sure why this still remains, it appears as if this GLCanvas gets a single paintGL call near - // the beginning of the application starting up. I'm not sure if we really need to call Application::paintGL() - // in this case, since the display plugins eventually handle all the painting - bool isThrottleFPSEnabled = Menu::getInstance()->isOptionChecked(MenuOption::ThrottleFPSIfNotFocus); - if (!qApp->getWindow()->isMinimized() || !isThrottleFPSEnabled) { - qApp->paintGL(); - } -} - -void GLCanvas::resizeGL(int width, int height) { - qApp->resizeGL(); -} - bool GLCanvas::event(QEvent* event) { if (QEvent::Paint == event->type() && qApp->isAboutToQuit()) { return true; diff --git a/interface/src/GLCanvas.h b/interface/src/GLCanvas.h index 0442159eeb..f707046c7c 100644 --- a/interface/src/GLCanvas.h +++ b/interface/src/GLCanvas.h @@ -18,8 +18,6 @@ class GLCanvas : public GLWidget { Q_OBJECT protected: - virtual void paintGL() override; - virtual void resizeGL(int width, int height) override; virtual bool event(QEvent* event) override; }; diff --git a/interface/src/PluginContainerProxy.cpp b/interface/src/PluginContainerProxy.cpp index 2e5c883897..8774eecd77 100644 --- a/interface/src/PluginContainerProxy.cpp +++ b/interface/src/PluginContainerProxy.cpp @@ -1,17 +1,23 @@ #include "PluginContainerProxy.h" -#include -#include +#include +#include #include #include #include +#include +#include +#include #include "Application.h" #include "MainWindow.h" #include "GLCanvas.h" #include "ui/DialogsManager.h" +#include +#include + PluginContainerProxy::PluginContainerProxy() { } @@ -36,30 +42,31 @@ extern QVector> _currentInputPluginActions; std::map _exclusiveGroups; QAction* PluginContainerProxy::addMenuItem(const QString& path, const QString& name, std::function onClicked, bool checkable, bool checked, const QString& groupName) { - auto menu = Menu::getInstance(); - MenuWrapper* parentItem = menu->getMenu(path); - QAction* action = menu->addActionToQMenuAndActionHash(parentItem, name); - if (!groupName.isEmpty()) { - QActionGroup* group{ nullptr }; - if (!_exclusiveGroups.count(groupName)) { - group = _exclusiveGroups[groupName] = new QActionGroup(menu); - group->setExclusive(true); - } else { - group = _exclusiveGroups[groupName]; - } - group->addAction(action); - } - connect(action, &QAction::triggered, [=] { - onClicked(action->isChecked()); - }); - action->setCheckable(checkable); - action->setChecked(checked); - if (_activatingDisplayPlugin) { - _currentDisplayPluginActions.push_back({ path, name }); - } else { - _currentInputPluginActions.push_back({ path, name }); - } - return action; + //auto menu = Menu::getInstance(); + //MenuWrapper* parentItem = menu->getMenu(path); + //QAction* action = menu->addActionToQMenuAndActionHash(parentItem, name); + //if (!groupName.isEmpty()) { + // QActionGroup* group{ nullptr }; + // if (!_exclusiveGroups.count(groupName)) { + // group = _exclusiveGroups[groupName] = new QActionGroup(menu); + // group->setExclusive(true); + // } else { + // group = _exclusiveGroups[groupName]; + // } + // group->addAction(action); + //} + //connect(action, &QAction::triggered, [=] { + // onClicked(action->isChecked()); + //}); + //action->setCheckable(checkable); + //action->setChecked(checked); + //if (_activatingDisplayPlugin) { + // _currentDisplayPluginActions.push_back({ path, name }); + //} else { + // _currentInputPluginActions.push_back({ path, name }); + //} + //return action; + return nullptr; } void PluginContainerProxy::removeMenuItem(const QString& menuName, const QString& menuItem) { @@ -150,10 +157,36 @@ void PluginContainerProxy::showDisplayPluginsTools() { DependencyManager::get()->hmdTools(true); } -QGLWidget* PluginContainerProxy::getPrimarySurface() { +QGLWidget* PluginContainerProxy::getPrimaryWidget() { return qApp->_glWidget; } +QWindow* PluginContainerProxy::getPrimaryWindow() { + return qApp->_glWidget->windowHandle(); +} + +QOpenGLContext* PluginContainerProxy::getPrimaryContext() { + return qApp->_glWidget->context()->contextHandle(); +} + const DisplayPlugin* PluginContainerProxy::getActiveDisplayPlugin() const { return qApp->getActiveDisplayPlugin(); } + +bool PluginContainerProxy::makeRenderingContextCurrent() { + return qApp->_offscreenContext->makeCurrent(); +} + +void PluginContainerProxy::releaseSceneTexture(uint32_t texture) { + Q_ASSERT(QThread::currentThread() == qApp->thread()); + auto& framebufferMap = qApp->_lockedFramebufferMap; + Q_ASSERT(framebufferMap.contains(texture)); + auto framebufferPointer = framebufferMap[texture]; + framebufferMap.remove(texture); + auto framebufferCache = DependencyManager::get(); + framebufferCache->releaseFramebuffer(framebufferPointer); +} + +void PluginContainerProxy::releaseOverlayTexture(uint32_t texture) { + +} diff --git a/interface/src/PluginContainerProxy.h b/interface/src/PluginContainerProxy.h index 79f8287b66..5cc1cc8583 100644 --- a/interface/src/PluginContainerProxy.h +++ b/interface/src/PluginContainerProxy.h @@ -22,7 +22,12 @@ class PluginContainerProxy : public QObject, PluginContainer { virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) override; virtual void showDisplayPluginsTools() override; virtual void requestReset() override; - virtual QGLWidget* getPrimarySurface() override; + virtual bool makeRenderingContextCurrent() override; + virtual void releaseSceneTexture(uint32_t texture) override; + virtual void releaseOverlayTexture(uint32_t texture) override; + virtual QGLWidget* getPrimaryWidget() override; + virtual QWindow* getPrimaryWindow() override; + virtual QOpenGLContext* getPrimaryContext() override; virtual bool isForeground() override; virtual const DisplayPlugin* getActiveDisplayPlugin() const override; diff --git a/interface/src/avatar/AvatarUpdate.cpp b/interface/src/avatar/AvatarUpdate.cpp index 52fa568879..99e5d2acaa 100644 --- a/interface/src/avatar/AvatarUpdate.cpp +++ b/interface/src/avatar/AvatarUpdate.cpp @@ -30,7 +30,8 @@ void AvatarUpdate::synchronousProcess() { // Keep our own updated value, so that our asynchronous code can consult it. _isHMDMode = qApp->isHMDMode(); - _headPose = qApp->getActiveDisplayPlugin()->getHeadPose(); + auto frameCount = qApp->getFrameCount(); + _headPose = qApp->getActiveDisplayPlugin()->getHeadPose(frameCount); if (_updateBillboard) { DependencyManager::get()->getMyAvatar()->doUpdateBillboard(); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5f43b834ec..1a098ec5f6 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1200,7 +1200,7 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, fl if (qApp->isHMDMode()) { glm::vec3 cameraPosition = qApp->getCamera()->getPosition(); - glm::mat4 headPose = qApp->getActiveDisplayPlugin()->getHeadPose(); + glm::mat4 headPose = qApp->getActiveDisplayPlugin()->getHeadPose(qApp->getFrameCount()); glm::mat4 leftEyePose = qApp->getActiveDisplayPlugin()->getEyeToHeadTransform(Eye::Left); leftEyePose = leftEyePose * headPose; glm::vec3 leftEyePosition = extractTranslation(leftEyePose); diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index eb43b9d864..4cee190a47 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -287,7 +287,7 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int mat4 camMat; _cameraBaseTransform.getMatrix(camMat); auto displayPlugin = qApp->getActiveDisplayPlugin(); - auto headPose = displayPlugin->getHeadPose(); + auto headPose = displayPlugin->getHeadPose(qApp->getFrameCount()); auto eyeToHead = displayPlugin->getEyeToHeadTransform((Eye)eye); camMat = (headPose * eyeToHead) * camMat; batch.setViewportTransform(renderArgs->_viewport); diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 12692698e7..358dc49bdb 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "BandwidthRecorder.h" #include "Menu.h" @@ -118,7 +119,12 @@ void Stats::updateStats(bool force) { STAT_UPDATE(avatarRenderableCount, avatarManager->getNumberInRenderRange()); STAT_UPDATE(avatarRenderDistance, (int) round(avatarManager->getRenderDistance())); // deliberately truncating STAT_UPDATE(serverCount, nodeList->size()); - STAT_UPDATE(framerate, (int)qApp->getFps()); + STAT_UPDATE(renderrate, (int)qApp->getFps()); + if (qApp->getActiveDisplayPlugin()) { + STAT_UPDATE(presentrate, (int)qApp->getActiveDisplayPlugin()->presentRate()); + } else { + STAT_UPDATE(presentrate, -1); + } STAT_UPDATE(simrate, (int)qApp->getAverageSimsPerSecond()); STAT_UPDATE(avatarSimrate, (int)qApp->getAvatarSimrate()); diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index d1c0dd19d7..eb28883001 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -32,7 +32,8 @@ class Stats : public QQuickItem { Q_PROPERTY(float audioPacketlossDownstream READ getAudioPacketLossDownstream) STATS_PROPERTY(int, serverCount, 0) - STATS_PROPERTY(int, framerate, 0) + STATS_PROPERTY(int, renderrate, 0) + STATS_PROPERTY(int, presentrate, 0) STATS_PROPERTY(int, simrate, 0) STATS_PROPERTY(int, avatarSimrate, 0) STATS_PROPERTY(int, avatarCount, 0) @@ -115,7 +116,8 @@ signals: void expandedChanged(); void timingExpandedChanged(); void serverCountChanged(); - void framerateChanged(); + void renderrateChanged(); + void presentrateChanged(); void simrateChanged(); void avatarSimrateChanged(); void avatarCountChanged(); diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp index 9366ec4403..36216f8912 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp @@ -30,44 +30,41 @@ const QString& Basic2DWindowOpenGLDisplayPlugin::getName() const { return NAME; } -std::vector _framerateActions; -QAction* _vsyncAction{ nullptr }; - void Basic2DWindowOpenGLDisplayPlugin::activate() { - _framerateActions.clear(); - _container->addMenuItem(MENU_PATH(), FULLSCREEN, - [this](bool clicked) { - if (clicked) { - _container->setFullscreen(getFullscreenTarget()); - } else { - _container->unsetFullscreen(); - } - }, true, false); - _container->addMenu(FRAMERATE); - _framerateActions.push_back( - _container->addMenuItem(FRAMERATE, FRAMERATE_UNLIMITED, - [this](bool) { updateFramerate(); }, true, true, FRAMERATE)); - _framerateActions.push_back( - _container->addMenuItem(FRAMERATE, FRAMERATE_60, - [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); - _framerateActions.push_back( - _container->addMenuItem(FRAMERATE, FRAMERATE_50, - [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); - _framerateActions.push_back( - _container->addMenuItem(FRAMERATE, FRAMERATE_40, - [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); - _framerateActions.push_back( - _container->addMenuItem(FRAMERATE, FRAMERATE_30, - [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); + //_framerateActions.clear(); + //_container->addMenuItem(MENU_PATH(), FULLSCREEN, + // [this](bool clicked) { + // if (clicked) { + // _container->setFullscreen(getFullscreenTarget()); + // } else { + // _container->unsetFullscreen(); + // } + // }, true, false); + //_container->addMenu(FRAMERATE); + //_framerateActions.push_back( + // _container->addMenuItem(FRAMERATE, FRAMERATE_UNLIMITED, + // [this](bool) { updateFramerate(); }, true, true, FRAMERATE)); + //_framerateActions.push_back( + // _container->addMenuItem(FRAMERATE, FRAMERATE_60, + // [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); + //_framerateActions.push_back( + // _container->addMenuItem(FRAMERATE, FRAMERATE_50, + // [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); + //_framerateActions.push_back( + // _container->addMenuItem(FRAMERATE, FRAMERATE_40, + // [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); + //_framerateActions.push_back( + // _container->addMenuItem(FRAMERATE, FRAMERATE_30, + // [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); WindowOpenGLDisplayPlugin::activate(); - // Vsync detection happens in the parent class activate, so we need to check after that - if (_vsyncSupported) { - _vsyncAction = _container->addMenuItem(MENU_PATH(), VSYNC_ON, [this](bool) {}, true, true); - } else { - _vsyncAction = nullptr; - } + //// Vsync detection happens in the parent class activate, so we need to check after that + //if (_vsyncSupported) { + // _vsyncAction = _container->addMenuItem(MENU_PATH(), VSYNC_ON, [this](bool) {}, true, true); + //} else { + // _vsyncAction = nullptr; + //} updateFramerate(); } @@ -76,19 +73,18 @@ void Basic2DWindowOpenGLDisplayPlugin::deactivate() { WindowOpenGLDisplayPlugin::deactivate(); } -void Basic2DWindowOpenGLDisplayPlugin::display(GLuint sceneTexture, const glm::uvec2& sceneSize) { +void Basic2DWindowOpenGLDisplayPlugin::submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) { if (_vsyncAction) { - bool wantVsync = _vsyncAction->isChecked(); - bool vsyncEnabed = isVsyncEnabled(); - if (vsyncEnabed ^ wantVsync) { - enableVsync(wantVsync); - } + _wantVsync = _vsyncAction->isChecked(); + //bool vsyncEnabed = isVsyncEnabled(); + //if (vsyncEnabed ^ wantVsync) { + // enableVsync(wantVsync); + //} } - WindowOpenGLDisplayPlugin::display(sceneTexture, sceneSize); + WindowOpenGLDisplayPlugin::submitSceneTexture(frameIndex, sceneTexture, sceneSize); } - int Basic2DWindowOpenGLDisplayPlugin::getDesiredInterval() const { static const int THROTTLED_PAINT_TIMER_DELAY_MS = MSECS_PER_SECOND / 15; static const int ULIMIITED_PAINT_TIMER_DELAY_MS = 1; diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h index f4655ab79f..80aebf9efc 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h @@ -10,6 +10,8 @@ #include "WindowOpenGLDisplayPlugin.h" class QScreen; +class QAction; + class Basic2DWindowOpenGLDisplayPlugin : public WindowOpenGLDisplayPlugin { Q_OBJECT @@ -19,7 +21,7 @@ public: virtual void activate() override; virtual void deactivate() override; - virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize) override; + virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override; virtual bool isThrottled() const override; @@ -31,6 +33,9 @@ private: void updateFramerate(); static const QString NAME; QScreen* getFullscreenTarget(); - uint32_t _framerateTarget{ 0 }; + std::vector _framerateActions; + QAction* _vsyncAction { nullptr }; + uint32_t _framerateTarget { 0 }; int _fullscreenTarget{ -1 }; + bool _wantVsync { true }; }; diff --git a/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp index 8155d69826..85e832abdd 100644 --- a/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp @@ -25,22 +25,22 @@ const QString& DisplayPlugin::MENU_PATH() { DisplayPluginList getDisplayPlugins() { DisplayPlugin* PLUGIN_POOL[] = { new Basic2DWindowOpenGLDisplayPlugin(), -#ifdef DEBUG new NullDisplayPlugin(), -#endif - - // Stereo modes - - // SBS left/right - new SideBySideStereoDisplayPlugin(), - // Interleaved left/right - new InterleavedStereoDisplayPlugin(), - - // HMDs -#ifdef Q_OS_WIN - // SteamVR SDK - new OpenVrDisplayPlugin(), -#endif +//#ifdef DEBUG +//#endif +// +// // Stereo modes +// +// // SBS left/right +// new SideBySideStereoDisplayPlugin(), +// // Interleaved left/right +// new InterleavedStereoDisplayPlugin(), +// +// // HMDs +//#ifdef Q_OS_WIN +// // SteamVR SDK +// new OpenVrDisplayPlugin(), +//#endif nullptr }; diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp index ce512962ff..b0f02b1149 100644 --- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp @@ -9,6 +9,7 @@ // #include "NullDisplayPlugin.h" +#include const QString NullDisplayPlugin::NAME("NullDisplayPlugin"); const QString & NullDisplayPlugin::getName() const { @@ -23,8 +24,12 @@ bool NullDisplayPlugin::hasFocus() const { return false; } -void NullDisplayPlugin::preRender() {} -void NullDisplayPlugin::preDisplay() {} -void NullDisplayPlugin::display(uint32_t sceneTexture, const glm::uvec2& sceneSize) {} -void NullDisplayPlugin::finishFrame() {} +void NullDisplayPlugin::submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) { + _container->releaseSceneTexture(sceneTexture); +} + +void NullDisplayPlugin::submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) { + _container->releaseOverlayTexture(overlayTexture); +} + void NullDisplayPlugin::stop() {} diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h index 8cd5c2bc37..c4052f38dd 100644 --- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h @@ -19,10 +19,8 @@ public: virtual glm::uvec2 getRecommendedRenderSize() const override; virtual bool hasFocus() const override; - virtual void preRender() override; - virtual void preDisplay() override; - virtual void display(uint32_t sceneTexture, const glm::uvec2& sceneSize) override; - virtual void finishFrame() override; + virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override; + virtual void submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) override; private: static const QString NAME; diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 09f4ba9897..e18cc6c82f 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -6,71 +6,167 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "OpenGLDisplayPlugin.h" -#include +#include +#include +#include + +#include +#include + +#include +#include +#include #include +#include #include +class PresentThread : public QThread, public Dependency { + using Mutex = std::mutex; + using Lock = std::unique_lock; + friend class OpenGLDisplayPlugin; +public: + + ~PresentThread() { + _shutdown = true; + wait(); + } + + void setNewDisplayPlugin(OpenGLDisplayPlugin* plugin) { + Lock lock(_mutex); + _newPlugin = plugin; + } + + virtual void run() override { + Q_ASSERT(_context); + while (!_shutdown) { + // Check before lock + if (_newPlugin != nullptr) { + Lock lock(_mutex); + // Check if we have a new plugin to activate + if (_newPlugin != nullptr) { + // Deactivate the old plugin + if (_activePlugin != nullptr) { + _activePlugin->uncustomizeContext(); + } + + _newPlugin->customizeContext(); + _activePlugin = _newPlugin; + _newPlugin = nullptr; + _context->doneCurrent(); + } + lock.unlock(); + } + + // If there's no active plugin, just sleep + if (_activePlugin == nullptr) { + QThread::usleep(100); + continue; + } + + // take the latest texture and present it + _activePlugin->present(); + + } + _context->doneCurrent(); + _context->moveToThread(qApp->thread()); + } + + +private: + bool _shutdown { false }; + Mutex _mutex; + QThread* _mainThread { nullptr }; + OpenGLDisplayPlugin* _newPlugin { nullptr }; + OpenGLDisplayPlugin* _activePlugin { nullptr }; + QOpenGLContext* _context { nullptr }; +}; OpenGLDisplayPlugin::OpenGLDisplayPlugin() { + _sceneTextureEscrow.setRecycler([this](GLuint texture){ + cleanupForSceneTexture(texture); + _container->releaseSceneTexture(texture); + }); + + _overlayTextureEscrow.setRecycler([this](GLuint texture) { + _container->releaseOverlayTexture(texture); + }); + connect(&_timer, &QTimer::timeout, this, [&] { - if (_active) { + if (_active && _sceneTextureEscrow.depth() < 1) { emit requestRender(); } }); } -OpenGLDisplayPlugin::~OpenGLDisplayPlugin() { +void OpenGLDisplayPlugin::cleanupForSceneTexture(uint32_t sceneTexture) { + Lock lock(_mutex); + Q_ASSERT(_sceneTextureToFrameIndexMap.contains(sceneTexture)); + _sceneTextureToFrameIndexMap.remove(sceneTexture); } -void OpenGLDisplayPlugin::preDisplay() { - makeCurrent(); -}; - -void OpenGLDisplayPlugin::preRender() { - // NOOP -} - -void OpenGLDisplayPlugin::finishFrame() { - swapBuffers(); - doneCurrent(); -}; - -void OpenGLDisplayPlugin::customizeContext() { - using namespace oglplus; - // TODO: write the poper code for linux -#if defined(Q_OS_WIN) - _vsyncSupported = wglewGetExtension("WGL_EXT_swap_control"); -#endif - - Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha); - Context::Disable(Capability::Blend); - Context::Disable(Capability::DepthTest); - Context::Disable(Capability::CullFace); - - - _program = loadDefaultShader(); - _plane = loadPlane(_program); - - enableVsync(); -} void OpenGLDisplayPlugin::activate() { + _timer.start(2); + + // Start the present thread if necessary + auto presentThread = DependencyManager::get(); + if (!presentThread) { + DependencyManager::set(); + presentThread = DependencyManager::get(); + auto widget = _container->getPrimaryWidget(); + auto glContext = widget->context(); + auto context = glContext->contextHandle(); + glContext->moveToThread(presentThread.data()); + context->moveToThread(presentThread.data()); + + // Move the OpenGL context to the present thread + presentThread->_context = context; + + // Start execution + presentThread->start(); + } + presentThread->setNewDisplayPlugin(this); DisplayPlugin::activate(); - _timer.start(1); + emit requestRender(); } void OpenGLDisplayPlugin::stop() { - DisplayPlugin::activate(); _timer.stop(); } void OpenGLDisplayPlugin::deactivate() { - _active = false; _timer.stop(); + DisplayPlugin::deactivate(); +} +void OpenGLDisplayPlugin::customizeContext() { + auto presentThread = DependencyManager::get(); + Q_ASSERT(thread() == presentThread->thread()); + + bool makeCurrentResult = makeCurrent(); + Q_ASSERT(makeCurrentResult); + + // TODO: write the proper code for linux +#if defined(Q_OS_WIN) + _vsyncSupported = wglewGetExtension("WGL_EXT_swap_control"); +#endif + enableVsync(); + + using namespace oglplus; + Context::BlendFunc(BlendFunction::SrcAlpha, BlendFunction::OneMinusSrcAlpha); + Context::Disable(Capability::Blend); + Context::Disable(Capability::DepthTest); + Context::Disable(Capability::CullFace); + + _program = loadDefaultShader(); + _plane = loadPlane(_program); + + doneCurrent(); +} + +void OpenGLDisplayPlugin::uncustomizeContext() { makeCurrent(); - Q_ASSERT(0 == glGetError()); _program.reset(); _plane.reset(); doneCurrent(); @@ -118,13 +214,74 @@ bool OpenGLDisplayPlugin::eventFilter(QObject* receiver, QEvent* event) { return false; } -void OpenGLDisplayPlugin::display( - GLuint finalTexture, const glm::uvec2& sceneSize) { +void OpenGLDisplayPlugin::submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) { + { + Lock lock(_mutex); + _sceneTextureToFrameIndexMap[sceneTexture] = frameIndex; + } + + // Submit it to the presentation thread via escrow + _sceneTextureEscrow.submit(sceneTexture); +} + +void OpenGLDisplayPlugin::submitOverlayTexture(GLuint sceneTexture, const glm::uvec2& sceneSize) { + // Submit it to the presentation thread via escrow + _overlayTextureEscrow.submit(sceneTexture); +} + +void OpenGLDisplayPlugin::updateTextures() { + _currentSceneTexture = _sceneTextureEscrow.fetchAndRelease(_currentSceneTexture); + _currentOverlayTexture = _overlayTextureEscrow.fetchAndRelease(_currentOverlayTexture); +} + +void OpenGLDisplayPlugin::updateFramerate() { + uint64_t now = usecTimestampNow(); + static uint64_t lastSwapEnd { now }; + uint64_t diff = now - lastSwapEnd; + lastSwapEnd = now; + if (diff != 0) { + Lock lock(_mutex); + _usecsPerFrame.updateAverage(diff); + } +} + + +void OpenGLDisplayPlugin::internalPresent() { using namespace oglplus; - uvec2 size = getSurfaceSize(); + uvec2 size = getSurfacePixels(); Context::Viewport(size.x, size.y); - glBindTexture(GL_TEXTURE_2D, finalTexture); + Context::Clear().DepthBuffer(); + glBindTexture(GL_TEXTURE_2D, _currentSceneTexture); drawUnitQuad(); + swapBuffers(); + updateFramerate(); +} + +void OpenGLDisplayPlugin::present() { + auto makeCurrentResult = makeCurrent(); + Q_ASSERT(makeCurrentResult); + if (!makeCurrentResult) { + qDebug() << "Failed to make current"; + return; + } + + updateTextures(); + if (_currentSceneTexture) { + internalPresent(); + updateFramerate(); + } + doneCurrent(); +} + +float OpenGLDisplayPlugin::presentRate() { + float result { -1.0f }; + { + Lock lock(_mutex); + result = _usecsPerFrame.getAverage(); + result = 1.0f / result; + result *= USECS_PER_SECOND; + } + return result; } void OpenGLDisplayPlugin::drawUnitQuad() { @@ -151,3 +308,20 @@ bool OpenGLDisplayPlugin::isVsyncEnabled() { return true; #endif } +bool OpenGLDisplayPlugin::makeCurrent() { + static auto widget = _container->getPrimaryWidget(); + widget->makeCurrent(); + auto result = widget->context()->contextHandle() == QOpenGLContext::currentContext(); + Q_ASSERT(result); + return result; +} + +void OpenGLDisplayPlugin::doneCurrent() { + static auto widget = _container->getPrimaryWidget(); + widget->doneCurrent(); +} + +void OpenGLDisplayPlugin::swapBuffers() { + static auto widget = _container->getPrimaryWidget(); + widget->swapBuffers(); +} diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index 43d8e5af6b..4426bfd5ef 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -9,42 +9,74 @@ #include "DisplayPlugin.h" -#include -#include +#include -class GlWindow; -class QOpenGLContext; +#include +#include +#include +#include class OpenGLDisplayPlugin : public DisplayPlugin { +protected: + using Mutex = std::recursive_mutex; + using Lock = std::unique_lock; public: OpenGLDisplayPlugin(); - virtual ~OpenGLDisplayPlugin(); - virtual void preRender() override; - virtual void preDisplay() override; - virtual void finishFrame() override; - virtual void activate() override; virtual void deactivate() override; virtual void stop() override; virtual bool eventFilter(QObject* receiver, QEvent* event) override; - virtual void display(GLuint sceneTexture, const glm::uvec2& sceneSize) override; + virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override; + virtual void submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) override; + virtual float presentRate() override; + + virtual glm::uvec2 getRecommendedRenderSize() const { + return getSurfacePixels(); + } + + virtual glm::uvec2 getRecommendedUiSize() const { + return getSurfaceSize(); + } protected: - virtual void customizeContext(); - virtual void drawUnitQuad(); - virtual glm::uvec2 getSurfaceSize() const = 0; - virtual void makeCurrent() = 0; - virtual void doneCurrent() = 0; - virtual void swapBuffers() = 0; + friend class PresentThread; + virtual glm::uvec2 getSurfaceSize() const = 0; + virtual glm::uvec2 getSurfacePixels() const = 0; + + // FIXME make thread safe? virtual bool isVsyncEnabled(); virtual void enableVsync(bool enable = true); + // These functions must only be called on the presentation thread + virtual void customizeContext(); + virtual void uncustomizeContext(); + virtual void cleanupForSceneTexture(uint32_t sceneTexture); + void present(); + void updateTextures(); + void updateFramerate(); + void drawUnitQuad(); + bool makeCurrent(); + void doneCurrent(); + void swapBuffers(); + // Plugin specific functionality to composite the scene and overlay and present the result + virtual void internalPresent(); + mutable QTimer _timer; ProgramPtr _program; ShapeWrapperPtr _plane; - bool _vsyncSupported{ false }; + bool _vsyncSupported { false }; + + Mutex _mutex; + SimpleMovingAverage _usecsPerFrame { 10 }; + QMap _sceneTextureToFrameIndexMap; + + GLuint _currentSceneTexture { 0 }; + GLuint _currentOverlayTexture { 0 }; + + GLTextureEscrow _overlayTextureEscrow; + GLTextureEscrow _sceneTextureEscrow; }; diff --git a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp index e6fb2be2f5..b215b19b15 100644 --- a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp @@ -11,14 +11,7 @@ #include "plugins/PluginContainer.h" -WindowOpenGLDisplayPlugin::WindowOpenGLDisplayPlugin() { -} - -glm::uvec2 WindowOpenGLDisplayPlugin::getRecommendedRenderSize() const { - return getSurfaceSize(); -} - -glm::uvec2 WindowOpenGLDisplayPlugin::getSurfaceSize() const { +glm::uvec2 WindowOpenGLDisplayPlugin::getSurfacePixels() const { uvec2 result; if (_window) { result = toGlm(_window->geometry().size() * _window->devicePixelRatio()); @@ -26,8 +19,7 @@ glm::uvec2 WindowOpenGLDisplayPlugin::getSurfaceSize() const { return result; } - -glm::uvec2 WindowOpenGLDisplayPlugin::getRecommendedUiSize() const { +glm::uvec2 WindowOpenGLDisplayPlugin::getSurfaceSize() const { uvec2 result; if (_window) { result = toGlm(_window->geometry().size()); @@ -40,11 +32,8 @@ bool WindowOpenGLDisplayPlugin::hasFocus() const { } void WindowOpenGLDisplayPlugin::activate() { + _window = _container->getPrimaryWidget(); OpenGLDisplayPlugin::activate(); - _window = _container->getPrimarySurface(); - _window->makeCurrent(); - customizeContext(); - _window->doneCurrent(); } void WindowOpenGLDisplayPlugin::deactivate() { @@ -52,14 +41,3 @@ void WindowOpenGLDisplayPlugin::deactivate() { _window = nullptr; } -void WindowOpenGLDisplayPlugin::makeCurrent() { - _window->makeCurrent(); -} - -void WindowOpenGLDisplayPlugin::doneCurrent() { - _window->doneCurrent(); -} - -void WindowOpenGLDisplayPlugin::swapBuffers() { - _window->swapBuffers(); -} diff --git a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.h index fc7691fc56..51e5d32503 100644 --- a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.h @@ -9,21 +9,17 @@ #include "OpenGLDisplayPlugin.h" -class QGLWidget; +class QWidget; class WindowOpenGLDisplayPlugin : public OpenGLDisplayPlugin { public: - WindowOpenGLDisplayPlugin(); - virtual glm::uvec2 getRecommendedRenderSize() const override; - virtual glm::uvec2 getRecommendedUiSize() const override; virtual bool hasFocus() const override; virtual void activate() override; virtual void deactivate() override; protected: virtual glm::uvec2 getSurfaceSize() const override final; - virtual void makeCurrent() override; - virtual void doneCurrent() override; - virtual void swapBuffers() override; - QGLWidget* _window{ nullptr }; + virtual glm::uvec2 getSurfacePixels() const override final; + + QWidget* _window { nullptr }; }; diff --git a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp index 4278165e25..68a711a847 100644 --- a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.cpp @@ -152,7 +152,7 @@ glm::mat4 OpenVrDisplayPlugin::getEyeToHeadTransform(Eye eye) const { return _eyesData[eye]._eyeOffset; } -glm::mat4 OpenVrDisplayPlugin::getHeadPose() const { +glm::mat4 OpenVrDisplayPlugin::getHeadPose(uint32_t frameIndex) const { return _trackedDevicePoseMat4[0]; } @@ -160,26 +160,26 @@ void OpenVrDisplayPlugin::customizeContext() { WindowOpenGLDisplayPlugin::customizeContext(); } -void OpenVrDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSize) { - // Flip y-axis since GL UV coords are backwards. - static vr::Compositor_TextureBounds leftBounds{ 0, 1, 0.5f, 0 }; - static vr::Compositor_TextureBounds rightBounds{ 0.5f, 1, 1, 0 }; - _compositor->Submit(vr::Eye_Left, (void*)finalTexture, &leftBounds); - _compositor->Submit(vr::Eye_Right, (void*)finalTexture, &rightBounds); - glFinish(); -} +//void OpenVrDisplayPlugin::display(uint32_t frameIndex, uint32_t finalTexture, const glm::uvec2& sceneSize) { +// // Flip y-axis since GL UV coords are backwards. +// static vr::Compositor_TextureBounds leftBounds{ 0, 1, 0.5f, 0 }; +// static vr::Compositor_TextureBounds rightBounds{ 0.5f, 1, 1, 0 }; +// _compositor->Submit(vr::Eye_Left, (void*)finalTexture, &leftBounds); +// _compositor->Submit(vr::Eye_Right, (void*)finalTexture, &rightBounds); +// glFinish(); +//} -void OpenVrDisplayPlugin::finishFrame() { -// swapBuffers(); - doneCurrent(); - _compositor->WaitGetPoses(_trackedDevicePose, vr::k_unMaxTrackedDeviceCount); - for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { - _trackedDevicePoseMat4[i] = _sensorResetMat * toGlm(_trackedDevicePose[i].mDeviceToAbsoluteTracking); - } - openvr_for_each_eye([&](vr::Hmd_Eye eye) { - _eyesData[eye]._pose = _trackedDevicePoseMat4[0]; - }); -}; +//void OpenVrDisplayPlugin::finishFrame() { +//// swapBuffers(); +// doneCurrent(); +// _compositor->WaitGetPoses(_trackedDevicePose, vr::k_unMaxTrackedDeviceCount); +// for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { +// _trackedDevicePoseMat4[i] = _sensorResetMat * toGlm(_trackedDevicePose[i].mDeviceToAbsoluteTracking); +// } +// openvr_for_each_eye([&](vr::Hmd_Eye eye) { +// _eyesData[eye]._pose = _trackedDevicePoseMat4[0]; +// }); +//}; #endif diff --git a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.h index 15d37d9de8..c8887276b7 100644 --- a/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/openvr/OpenVrDisplayPlugin.h @@ -31,13 +31,11 @@ public: virtual void resetSensors() override; virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override; - virtual glm::mat4 getHeadPose() const override; + virtual glm::mat4 getHeadPose(uint32_t frameIndex) const override; protected: - virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override; +// virtual void display(uint32_t frameIndex, uint32_t finalTexture, const glm::uvec2& sceneSize) override; virtual void customizeContext() override; - // Do not perform swap in finish - virtual void finishFrame() override; private: vr::IVRSystem* _hmd { nullptr }; diff --git a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp index 72921b4f90..4332c53d81 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp @@ -66,10 +66,6 @@ glm::uvec2 InterleavedStereoDisplayPlugin::getRecommendedRenderSize() const { return result; } -void InterleavedStereoDisplayPlugin::display( - GLuint finalTexture, const glm::uvec2& sceneSize) { - using namespace oglplus; - _program->Bind(); - Uniform(*_program, "textureSize").SetValue(sceneSize); - WindowOpenGLDisplayPlugin::display(finalTexture, sceneSize); +void InterleavedStereoDisplayPlugin::internalPresent() { + // FIXME } diff --git a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h index 3044d91247..b9b3566349 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h @@ -19,7 +19,8 @@ public: virtual void customizeContext() override; virtual glm::uvec2 getRecommendedRenderSize() const override; - void display(GLuint finalTexture, const glm::uvec2& sceneSize) override; + + void internalPresent() override; private: static const QString NAME; diff --git a/libraries/gl/src/gl/GLEscrow.h b/libraries/gl/src/gl/GLEscrow.h index db9f033de8..d860f1239c 100644 --- a/libraries/gl/src/gl/GLEscrow.h +++ b/libraries/gl/src/gl/GLEscrow.h @@ -76,7 +76,7 @@ public: } }; - using Mutex = std::mutex; + using Mutex = std::recursive_mutex; using Lock = std::unique_lock; using Recycler = std::function; // deque gives us random access, double ended push & pop and size, all in constant time @@ -130,6 +130,21 @@ public: return result; } + // Returns the next available resource provided by the submitter, + // or if none is available (which could mean either the submission + // list is empty or that the first item on the list isn't yet signaled + // Also releases any previous texture held by the caller + T fetchAndRelease(T oldValue) { + T result = fetch(); + if (!result) { + return oldValue; + } + if (oldValue) { + release(oldValue); + } + return result; + } + // If fetch returns a non-zero value, it's the responsibility of the // client to release it at some point void release(T t, GLsync readSync = 0) { @@ -162,7 +177,12 @@ private: pop(_releases); } - trash.swap(_trash); + { + // FIXME I don't think this lock should be necessary, only the submitting thread + // touches the trash + Lock lock(_mutex); + trash.swap(_trash); + } } // FIXME maybe doing a timing on the deleters and warn if it's taking excessive time? diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h index 5b00391f09..928b72970b 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.h +++ b/libraries/plugins/src/plugins/DisplayPlugin.h @@ -65,29 +65,15 @@ public: // processing messages in the middle of submitFrame virtual void stop() = 0; - /** - * Called by the application before the frame rendering. Can be used for - * render timing related calls (for instance, the Oculus begin frame timing - * call) - */ - virtual void preRender() = 0; - /** - * Called by the application immediately before calling the display function. - * For OpenGL based plugins, this is the best place to put activate the output - * OpenGL context - */ - virtual void preDisplay() = 0; - /** * Sends the scene texture to the display plugin. */ - virtual void display(uint32_t sceneTexture, const glm::uvec2& sceneSize) = 0; + virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) = 0; /** - * Called by the application immeidately after display. For OpenGL based - * displays, this is the best place to put the buffer swap - */ - virtual void finishFrame() = 0; + * Sends the scene texture to the display plugin. + */ + virtual void submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) = 0; // Does the rendering surface have current focus? virtual bool hasFocus() const = 0; @@ -116,12 +102,12 @@ public: static const glm::mat4 transform; return transform; } - virtual glm::mat4 getHeadPose() const { + virtual glm::mat4 getHeadPose(uint32_t frameIndex) const { static const glm::mat4 pose; return pose; } // Needed for timewarp style features - virtual void setEyeRenderPose(Eye eye, const glm::mat4& pose) { + virtual void setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) { // NOOP } @@ -129,8 +115,8 @@ public: virtual void abandonCalibration() {} virtual void resetSensors() {} - virtual float devicePixelRatio() { return 1.0; } - + virtual float devicePixelRatio() { return 1.0f; } + virtual float presentRate() { return -1.0f; } static const QString& MENU_PATH(); signals: diff --git a/libraries/plugins/src/plugins/PluginContainer.h b/libraries/plugins/src/plugins/PluginContainer.h index f013bfe3bf..25c2bcb11f 100644 --- a/libraries/plugins/src/plugins/PluginContainer.h +++ b/libraries/plugins/src/plugins/PluginContainer.h @@ -8,11 +8,15 @@ #pragma once #include +#include #include class QAction; class QGLWidget; class QScreen; +class QOpenGLContext; +class QWindow; + class DisplayPlugin; class PluginContainer { @@ -30,7 +34,12 @@ public: virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) = 0; virtual void showDisplayPluginsTools() = 0; virtual void requestReset() = 0; - virtual QGLWidget* getPrimarySurface() = 0; + virtual bool makeRenderingContextCurrent() = 0; + virtual void releaseSceneTexture(uint32_t texture) = 0; + virtual void releaseOverlayTexture(uint32_t texture) = 0; + virtual QGLWidget* getPrimaryWidget() = 0; + virtual QWindow* getPrimaryWindow() = 0; + virtual QOpenGLContext* getPrimaryContext() = 0; virtual bool isForeground() = 0; virtual const DisplayPlugin* getActiveDisplayPlugin() const = 0; }; diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index 7fd956a08f..805ad75e95 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -15,13 +15,6 @@ uvec2 OculusBaseDisplayPlugin::getRecommendedRenderSize() const { return _desiredFramebufferSize; } -void OculusBaseDisplayPlugin::preRender() { -#if (OVR_MAJOR_VERSION >= 6) - ovrFrameTiming ftiming = ovr_GetFrameTiming(_hmd, _frameIndex); - _trackingState = ovr_GetTrackingState(_hmd, ftiming.DisplayMidpointSeconds); -#endif -} - glm::mat4 OculusBaseDisplayPlugin::getProjection(Eye eye, const glm::mat4& baseProjection) const { return _eyeProjections[eye]; } @@ -29,7 +22,6 @@ glm::mat4 OculusBaseDisplayPlugin::getProjection(Eye eye, const glm::mat4& baseP void OculusBaseDisplayPlugin::resetSensors() { #if (OVR_MAJOR_VERSION >= 6) ovr_RecenterPose(_hmd); - preRender(); #endif } @@ -37,15 +29,14 @@ glm::mat4 OculusBaseDisplayPlugin::getEyeToHeadTransform(Eye eye) const { return glm::translate(mat4(), toGlm(_eyeOffsets[eye])); } -glm::mat4 OculusBaseDisplayPlugin::getHeadPose() const { - return toGlm(_trackingState.HeadPose.ThePose); +glm::mat4 OculusBaseDisplayPlugin::getHeadPose(uint32_t frameIndex) const { +#if (OVR_MAJOR_VERSION >= 6) + auto frameTiming = ovr_GetFrameTiming(_hmd, frameIndex); + auto trackingState = ovr_GetTrackingState(_hmd, frameTiming.DisplayMidpointSeconds); + return toGlm(trackingState.HeadPose.ThePose); +#endif } -void OculusBaseDisplayPlugin::setEyeRenderPose(Eye eye, const glm::mat4& pose) { - _eyePoses[eye] = ovrPoseFromGlm(pose); -} - - bool OculusBaseDisplayPlugin::isSupported() const { #if (OVR_MAJOR_VERSION >= 6) if (!OVR_SUCCESS(ovr_Initialize(nullptr))) { @@ -64,9 +55,11 @@ bool OculusBaseDisplayPlugin::isSupported() const { // DLL based display plugins MUST initialize GLEW inside the DLL code. void OculusBaseDisplayPlugin::customizeContext() { + makeCurrent(); glewExperimental = true; GLenum err = glewInit(); glGetError(); + doneCurrent(); WindowOpenGLDisplayPlugin::customizeContext(); } @@ -123,8 +116,6 @@ void OculusBaseDisplayPlugin::activate() { eyeSizes[0].x + eyeSizes[1].x, std::max(eyeSizes[0].y, eyeSizes[1].y)); - _frameIndex = 0; - if (!OVR_SUCCESS(ovr_ConfigureTracking(_hmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, 0))) { qFatal("Could not attach to sensor device"); @@ -159,9 +150,6 @@ void OculusBaseDisplayPlugin::deactivate() { #endif } -void OculusBaseDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSize) { - ++_frameIndex; -} float OculusBaseDisplayPlugin::getIPD() const { float result = OVR_DEFAULT_IPD; diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.h b/plugins/oculus/src/OculusBaseDisplayPlugin.h index ba1924bfff..711be6aa5e 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.h +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.h @@ -30,24 +30,18 @@ public: virtual glm::uvec2 getRecommendedUiSize() const override final { return uvec2(1920, 1080); } virtual void resetSensors() override final; virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override final; - virtual glm::mat4 getHeadPose() const override final; - virtual void setEyeRenderPose(Eye eye, const glm::mat4& pose) override final; virtual float getIPD() const override final; + virtual glm::mat4 getHeadPose(uint32_t frameIndex) const override; protected: virtual void customizeContext() override; - virtual void preRender() override final; - virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override; protected: - ovrPosef _eyePoses[2]; ovrVector3f _eyeOffsets[2]; mat4 _eyeProjections[3]; mat4 _compositeEyeProjections[2]; uvec2 _desiredFramebufferSize; - ovrTrackingState _trackingState; - unsigned int _frameIndex{ 0 }; #if (OVR_MAJOR_VERSION >= 6) ovrHmd _hmd; diff --git a/plugins/oculus/src/OculusDebugDisplayPlugin.cpp b/plugins/oculus/src/OculusDebugDisplayPlugin.cpp index 7a8b355ddd..26bb3cf9b2 100644 --- a/plugins/oculus/src/OculusDebugDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDebugDisplayPlugin.cpp @@ -28,13 +28,3 @@ void OculusDebugDisplayPlugin::customizeContext() { OculusBaseDisplayPlugin::customizeContext(); enableVsync(false); } - -void OculusDebugDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSize) { - WindowOpenGLDisplayPlugin::display(finalTexture, sceneSize); - OculusBaseDisplayPlugin::display(finalTexture, sceneSize); -} - -void OculusDebugDisplayPlugin::finishFrame() { - swapBuffers(); - doneCurrent(); -}; diff --git a/plugins/oculus/src/OculusDebugDisplayPlugin.h b/plugins/oculus/src/OculusDebugDisplayPlugin.h index d23c6ba567..04b68704cc 100644 --- a/plugins/oculus/src/OculusDebugDisplayPlugin.h +++ b/plugins/oculus/src/OculusDebugDisplayPlugin.h @@ -15,10 +15,7 @@ public: virtual bool isSupported() const override; protected: - virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override; virtual void customizeContext() override; - // Do not perform swap in finish - virtual void finishFrame() override; private: static const QString NAME; diff --git a/plugins/oculus/src/OculusDisplayPlugin.cpp b/plugins/oculus/src/OculusDisplayPlugin.cpp index 923b8bde6e..bcb39f5100 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDisplayPlugin.cpp @@ -144,7 +144,6 @@ static const QString MONO_PREVIEW = "Mono Preview"; static const QString FRAMERATE = DisplayPlugin::MENU_PATH() + ">Framerate"; void OculusDisplayPlugin::activate() { - _container->addMenuItem(MENU_PATH(), MONO_PREVIEW, [this](bool clicked) { _monoPreview = clicked; @@ -155,6 +154,8 @@ void OculusDisplayPlugin::activate() { void OculusDisplayPlugin::customizeContext() { OculusBaseDisplayPlugin::customizeContext(); + bool makeCurrentResult = makeCurrent(); + Q_ASSERT(makeCurrentResult); #if (OVR_MAJOR_VERSION >= 6) _sceneFbo = SwapFboPtr(new SwapFramebufferWrapper(_hmd)); _sceneFbo->Init(getRecommendedRenderSize()); @@ -168,20 +169,24 @@ void OculusDisplayPlugin::customizeContext() { enableVsync(false); // Only enable mirroring if we know vsync is disabled _enablePreview = !isVsyncEnabled(); + doneCurrent(); } -void OculusDisplayPlugin::deactivate() { +void OculusDisplayPlugin::uncustomizeContext() { #if (OVR_MAJOR_VERSION >= 6) makeCurrent(); _sceneFbo.reset(); doneCurrent(); #endif - - OculusBaseDisplayPlugin::deactivate(); + OculusBaseDisplayPlugin::uncustomizeContext(); } -void OculusDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSize) { +void OculusDisplayPlugin::internalPresent() { #if (OVR_MAJOR_VERSION >= 6) + if (!_currentSceneTexture) { + return; + } + using namespace oglplus; // Need to make sure only the display plugin is responsible for // controlling vsync @@ -196,7 +201,7 @@ void OculusDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSi } else { Context::Viewport(windowSize.x, windowSize.y); } - glBindTexture(GL_TEXTURE_2D, finalTexture); + glBindTexture(GL_TEXTURE_2D, _currentSceneTexture); GLenum err = glGetError(); Q_ASSERT(0 == err); drawUnitQuad(); @@ -205,16 +210,24 @@ void OculusDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSi _sceneFbo->Bound([&] { auto size = _sceneFbo->size; Context::Viewport(size.x, size.y); - glBindTexture(GL_TEXTURE_2D, finalTexture); + glBindTexture(GL_TEXTURE_2D, _currentSceneTexture); GLenum err = glGetError(); drawUnitQuad(); }); - ovr_for_each_eye([&](ovrEyeType eye) { - _sceneLayer.RenderPose[eye] = _eyePoses[eye]; - }); + uint32_t frameIndex { 0 }; + EyePoses eyePoses; + { + Lock lock(_mutex); + Q_ASSERT(_sceneTextureToFrameIndexMap.contains(_currentSceneTexture)); + frameIndex = _sceneTextureToFrameIndexMap[_currentSceneTexture]; + Q_ASSERT(_frameEyePoses.contains(frameIndex)); + eyePoses = _frameEyePoses[frameIndex]; + } + + _sceneLayer.RenderPose[ovrEyeType::ovrEye_Left] = eyePoses.first; + _sceneLayer.RenderPose[ovrEyeType::ovrEye_Right] = eyePoses.second; - auto windowSize = toGlm(_window->size()); { ovrViewScaleDesc viewScaleDesc; viewScaleDesc.HmdSpaceToWorldScaleInMeters = 1.0f; @@ -228,19 +241,26 @@ void OculusDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSi } } _sceneFbo->Increment(); - - ++_frameIndex; #endif -} -/* + /* The swapbuffer call here is only required if we want to mirror the content to the screen. - However, it should only be done if we can reliably disable v-sync on the mirror surface, + However, it should only be done if we can reliably disable v-sync on the mirror surface, otherwise the swapbuffer delay will interefere with the framerate of the headset -*/ -void OculusDisplayPlugin::finishFrame() { + */ if (_enablePreview) { swapBuffers(); } - doneCurrent(); -}; +} + +void OculusDisplayPlugin::setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) { + auto ovrPose = ovrPoseFromGlm(pose); + { + Lock lock(_mutex); + if (eye == Eye::Left) { + _frameEyePoses[frameIndex].first = ovrPose; + } else { + _frameEyePoses[frameIndex].second = ovrPose; + } + } +} diff --git a/plugins/oculus/src/OculusDisplayPlugin.h b/plugins/oculus/src/OculusDisplayPlugin.h index c1224ecf3a..5509715b9f 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.h +++ b/plugins/oculus/src/OculusDisplayPlugin.h @@ -15,22 +15,21 @@ using SwapFboPtr = QSharedPointer; class OculusDisplayPlugin : public OculusBaseDisplayPlugin { public: virtual void activate() override; - virtual void deactivate() override; virtual const QString & getName() const override; + virtual void setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) override final; protected: - virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override; + virtual void internalPresent() override; virtual void customizeContext() override; - // Do not perform swap in finish - virtual void finishFrame() override; + virtual void uncustomizeContext() override; private: + using EyePoses = std::pair; static const QString NAME; bool _enablePreview { false }; bool _monoPreview { true }; + QMap _frameEyePoses; -#if (OVR_MAJOR_VERSION >= 6) SwapFboPtr _sceneFbo; -#endif }; diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index f93580e5a3..37c560e9ad 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -11,7 +11,6 @@ namespace Oculus { ovrHmd _hmd; - unsigned int _frameIndex{ 0 }; ovrEyeRenderDesc _eyeRenderDescs[2]; ovrPosef _eyePoses[2]; ovrVector3f _eyeOffsets[2]; diff --git a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h index 6e3f864aee..ccf1ffdb57 100644 --- a/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h +++ b/plugins/oculusLegacy/src/OculusLegacyDisplayPlugin.h @@ -46,7 +46,6 @@ private: static const QString NAME; ovrHmd _hmd; - unsigned int _frameIndex; ovrTrackingState _trackingState; ovrEyeRenderDesc _eyeRenderDescs[2]; ovrPosef _eyePoses[2]; diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp index 664a894e44..c5c038fde3 100644 --- a/tests/controllers/src/main.cpp +++ b/tests/controllers/src/main.cpp @@ -91,7 +91,12 @@ public: virtual void unsetFullscreen(const QScreen* avoidScreen = nullptr) override {} virtual void showDisplayPluginsTools() override {} virtual void requestReset() override {} - virtual QGLWidget* getPrimarySurface() override { return nullptr; } + virtual bool makeRenderingContextCurrent() override { return true; } + virtual void releaseSceneTexture(uint32_t texture) override {} + virtual void releaseOverlayTexture(uint32_t texture) override {} + virtual QGLWidget* getPrimaryWidget() override { return nullptr; } + virtual QWindow* getPrimaryWindow() override { return nullptr; } + virtual QOpenGLContext* getPrimaryContext() override { return nullptr; } virtual bool isForeground() override { return true; } virtual const DisplayPlugin* getActiveDisplayPlugin() const override { return nullptr; } }; From d8bb9f8d183fe8cfa2a064276e50feed05689ce4 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 3 Dec 2015 13:00:36 -0800 Subject: [PATCH 324/401] Fixing screenshot functionality --- interface/src/Application.cpp | 23 +++--- .../src/display-plugins/NullDisplayPlugin.cpp | 6 ++ .../src/display-plugins/NullDisplayPlugin.h | 2 +- .../display-plugins/OpenGLDisplayPlugin.cpp | 77 +++++++++++++++++-- .../src/display-plugins/OpenGLDisplayPlugin.h | 10 ++- libraries/plugins/src/plugins/DisplayPlugin.h | 4 + 6 files changed, 105 insertions(+), 17 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 581fdbec5a..2c58156d2a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -44,6 +44,9 @@ #include +#include +#include + #include #include #include @@ -150,8 +153,6 @@ #include "InterfaceParentFinder.h" -#include -#include // ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. @@ -1091,7 +1092,6 @@ void Application::paintGL() { // update fps once a second if (now - _lastFramesPerSecondUpdate > USECS_PER_SECOND) { _fps = _framesPerSecond.getAverage(); - qDebug() << QString::number(_fps, 'g', 4); _lastFramesPerSecondUpdate = now; } @@ -1344,6 +1344,7 @@ void Application::paintGL() { } // Overlay Composition, needs to occur after screen space effects have completed + // FIXME migrate composition into the display plugins { PROFILE_RANGE(__FUNCTION__ "/compositor"); PerformanceTimer perfTimer("compositor"); @@ -1372,7 +1373,6 @@ void Application::paintGL() { { PROFILE_RANGE(__FUNCTION__ "/pluginOutput"); PerformanceTimer perfTimer("pluginOutput"); - uint64_t displayStart = usecTimestampNow(); auto primaryFramebuffer = framebufferCache->getPrimaryFramebuffer(); auto scratchFramebuffer = framebufferCache->getFramebuffer(); gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) { @@ -1386,12 +1386,18 @@ void Application::paintGL() { }); auto finalTexturePointer = scratchFramebuffer->getRenderBuffer(0); GLuint finalTexture = gpu::GLBackend::getTextureID(finalTexturePointer); - Q_ASSERT(0 != finalTexture); + Q_ASSERT(!_lockedFramebufferMap.contains(finalTexture)); _lockedFramebufferMap[finalTexture] = scratchFramebuffer; + + uint64_t displayStart = usecTimestampNow(); Q_ASSERT(QOpenGLContext::currentContext() == _offscreenContext->getContext()); - displayPlugin->submitSceneTexture(_frameCount, finalTexture, toGlm(size)); + { + PROFILE_RANGE(__FUNCTION__ "/pluginSubmitScene"); + PerformanceTimer perfTimer("pluginSubmitScene"); + displayPlugin->submitSceneTexture(_frameCount, finalTexture, toGlm(size)); + } Q_ASSERT(QOpenGLContext::currentContext() == _offscreenContext->getContext()); uint64_t displayEnd = usecTimestampNow(); @@ -4499,13 +4505,12 @@ void Application::toggleLogDialog() { } void Application::takeSnapshot() { -#if 0 QMediaPlayer* player = new QMediaPlayer(); QFileInfo inf = QFileInfo(PathUtils::resourcesPath() + "sounds/snap.wav"); player->setMedia(QUrl::fromLocalFile(inf.absoluteFilePath())); player->play(); - QString fileName = Snapshot::saveSnapshot(_glWidget->grabFrameBuffer()); + QString fileName = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot()); AccountManager& accountManager = AccountManager::getInstance(); if (!accountManager.isLoggedIn()) { @@ -4516,7 +4521,6 @@ void Application::takeSnapshot() { _snapshotShareDialog = new SnapshotShareDialog(fileName, _glWidget); } _snapshotShareDialog->show(); -#endif } float Application::getRenderResolutionScale() const { @@ -4728,6 +4732,7 @@ void Application::updateDisplayMode() { bool first = true; foreach(auto displayPlugin, displayPlugins) { addDisplayPluginToMenu(displayPlugin, first); + // This must be a queued connection to avoid a deadlock QObject::connect(displayPlugin.get(), &DisplayPlugin::requestRender, this, &Application::paintGL, Qt::QueuedConnection); diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp index b0f02b1149..f780534bc9 100644 --- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.cpp @@ -9,7 +9,9 @@ // #include "NullDisplayPlugin.h" +#include #include + const QString NullDisplayPlugin::NAME("NullDisplayPlugin"); const QString & NullDisplayPlugin::getName() const { @@ -33,3 +35,7 @@ void NullDisplayPlugin::submitOverlayTexture(uint32_t overlayTexture, const glm: } void NullDisplayPlugin::stop() {} + +QImage NullDisplayPlugin::getScreenshot() const { + return QImage(); +} diff --git a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h index c4052f38dd..23e23e2c4e 100644 --- a/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/NullDisplayPlugin.h @@ -21,7 +21,7 @@ public: virtual bool hasFocus() const override; virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override; virtual void submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) override; - + virtual QImage getScreenshot() const override; private: static const QString NAME; }; diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index e18cc6c82f..22adeb8447 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -7,12 +7,15 @@ // #include "OpenGLDisplayPlugin.h" +#include + #include #include #include #include #include +#include #include #include @@ -23,7 +26,9 @@ class PresentThread : public QThread, public Dependency { using Mutex = std::mutex; + using Condition = std::condition_variable; using Lock = std::unique_lock; + friend class OpenGLDisplayPlugin; public: @@ -40,6 +45,25 @@ public: virtual void run() override { Q_ASSERT(_context); while (!_shutdown) { + if (_pendingMainThreadOperation) { + { + Lock lock(_mutex); + // Move the context to the main thread + _context->moveToThread(qApp->thread()); + _widgetContext->moveToThread(qApp->thread()); + _pendingMainThreadOperation = false; + // Release the main thread to do it's action + _condition.notify_one(); + } + + + { + // Main thread does it's thing while we wait on the lock to release + Lock lock(_mutex); + _condition.wait(lock, [&] { return _finishedMainThreadOperation; }); + } + } + // Check before lock if (_newPlugin != nullptr) { Lock lock(_mutex); @@ -69,17 +93,43 @@ public: } _context->doneCurrent(); + _widgetContext->moveToThread(qApp->thread()); _context->moveToThread(qApp->thread()); } + void withMainThreadContext(std::function f) { + // Signal to the thread that there is work to be done on the main thread + Lock lock(_mutex); + _pendingMainThreadOperation = true; + _finishedMainThreadOperation = false; + _condition.wait(lock, [&] { return !_pendingMainThreadOperation; }); + + _widgetContext->makeCurrent(); + f(); + _widgetContext->doneCurrent(); + + // restore control of the context to the presentation thread and signal + // the end of the operation + _widgetContext->moveToThread(this); + _context->moveToThread(this); + _finishedMainThreadOperation = true; + lock.unlock(); + _condition.notify_one(); + } + private: bool _shutdown { false }; Mutex _mutex; + // Used to allow the main thread to perform context operations + Condition _condition; + bool _pendingMainThreadOperation { false }; + bool _finishedMainThreadOperation { false }; QThread* _mainThread { nullptr }; OpenGLDisplayPlugin* _newPlugin { nullptr }; OpenGLDisplayPlugin* _activePlugin { nullptr }; QOpenGLContext* _context { nullptr }; + QGLContext* _widgetContext { nullptr }; }; OpenGLDisplayPlugin::OpenGLDisplayPlugin() { @@ -114,14 +164,16 @@ void OpenGLDisplayPlugin::activate() { if (!presentThread) { DependencyManager::set(); presentThread = DependencyManager::get(); + presentThread->setObjectName("Presentation Thread"); + auto widget = _container->getPrimaryWidget(); - auto glContext = widget->context(); - auto context = glContext->contextHandle(); - glContext->moveToThread(presentThread.data()); - context->moveToThread(presentThread.data()); // Move the OpenGL context to the present thread - presentThread->_context = context; + // Extra code because of the widget 'wrapper' context + presentThread->_widgetContext = widget->context(); + presentThread->_widgetContext->moveToThread(presentThread.data()); + presentThread->_context = presentThread->_widgetContext->contextHandle(); + presentThread->_context->moveToThread(presentThread.data()); // Start execution presentThread->start(); @@ -325,3 +377,18 @@ void OpenGLDisplayPlugin::swapBuffers() { static auto widget = _container->getPrimaryWidget(); widget->swapBuffers(); } + +void OpenGLDisplayPlugin::withMainThreadContext(std::function f) const { + static auto presentThread = DependencyManager::get(); + presentThread->withMainThreadContext(f); + _container->makeRenderingContextCurrent(); +} + +QImage OpenGLDisplayPlugin::getScreenshot() const { + QImage result; + withMainThreadContext([&] { + static auto widget = _container->getPrimaryWidget(); + result = widget->grabFrameBuffer(); + }); + return result; +} diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index 4426bfd5ef..edbe7db006 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -31,17 +31,20 @@ public: virtual void submitOverlayTexture(uint32_t overlayTexture, const glm::uvec2& overlaySize) override; virtual float presentRate() override; - virtual glm::uvec2 getRecommendedRenderSize() const { + virtual glm::uvec2 getRecommendedRenderSize() const override { return getSurfacePixels(); } - virtual glm::uvec2 getRecommendedUiSize() const { + virtual glm::uvec2 getRecommendedUiSize() const override { return getSurfaceSize(); } + virtual QImage getScreenshot() const override; + protected: friend class PresentThread; + virtual glm::uvec2 getSurfaceSize() const = 0; virtual glm::uvec2 getSurfacePixels() const = 0; @@ -53,6 +56,9 @@ protected: virtual void customizeContext(); virtual void uncustomizeContext(); virtual void cleanupForSceneTexture(uint32_t sceneTexture); + void withMainThreadContext(std::function f) const; + + void present(); void updateTextures(); void updateFramerate(); diff --git a/libraries/plugins/src/plugins/DisplayPlugin.h b/libraries/plugins/src/plugins/DisplayPlugin.h index 928b72970b..83afbc9402 100644 --- a/libraries/plugins/src/plugins/DisplayPlugin.h +++ b/libraries/plugins/src/plugins/DisplayPlugin.h @@ -14,6 +14,7 @@ #include #include +class QImage; #include #include @@ -96,6 +97,9 @@ public: return baseProjection; } + // Fetch the most recently displayed image as a QImage + virtual QImage getScreenshot() const = 0; + // HMD specific methods // TODO move these into another class? virtual glm::mat4 getEyeToHeadTransform(Eye eye) const { From 7262a10e62cf181e4d36d14d95349545b19c0d4b Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 3 Dec 2015 15:39:09 -0800 Subject: [PATCH 325/401] Refactoring present thread / GL base plugin for saner context management --- .../src/display-plugins/DisplayPlugin.cpp | 22 +++--- .../display-plugins/OpenGLDisplayPlugin.cpp | 74 +++++++------------ .../src/display-plugins/OpenGLDisplayPlugin.h | 2 - .../stereo/InterleavedStereoDisplayPlugin.cpp | 6 +- .../oculus/src/OculusBaseDisplayPlugin.cpp | 2 - plugins/oculus/src/OculusDisplayPlugin.cpp | 5 -- 6 files changed, 42 insertions(+), 69 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp index 85e832abdd..6c34612e8c 100644 --- a/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/DisplayPlugin.cpp @@ -26,17 +26,17 @@ DisplayPluginList getDisplayPlugins() { DisplayPlugin* PLUGIN_POOL[] = { new Basic2DWindowOpenGLDisplayPlugin(), new NullDisplayPlugin(), -//#ifdef DEBUG -//#endif -// -// // Stereo modes -// -// // SBS left/right -// new SideBySideStereoDisplayPlugin(), -// // Interleaved left/right -// new InterleavedStereoDisplayPlugin(), -// -// // HMDs +#ifdef DEBUG +#endif + + // Stereo modes + + // SBS left/right + new SideBySideStereoDisplayPlugin(), + // Interleaved left/right + new InterleavedStereoDisplayPlugin(), + + // HMDs //#ifdef Q_OS_WIN // // SteamVR SDK // new OpenVrDisplayPlugin(), diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 22adeb8447..45e6daef31 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -28,8 +28,6 @@ class PresentThread : public QThread, public Dependency { using Mutex = std::mutex; using Condition = std::condition_variable; using Lock = std::unique_lock; - - friend class OpenGLDisplayPlugin; public: ~PresentThread() { @@ -42,6 +40,14 @@ public: _newPlugin = plugin; } + void setContext(QGLContext * context) { + // Move the OpenGL context to the present thread + // Extra code because of the widget 'wrapper' context + _context = context; + _context->moveToThread(this); + _context->contextHandle()->moveToThread(this); + } + virtual void run() override { Q_ASSERT(_context); while (!_shutdown) { @@ -50,7 +56,7 @@ public: Lock lock(_mutex); // Move the context to the main thread _context->moveToThread(qApp->thread()); - _widgetContext->moveToThread(qApp->thread()); + _context->contextHandle()->moveToThread(qApp->thread()); _pendingMainThreadOperation = false; // Release the main thread to do it's action _condition.notify_one(); @@ -67,6 +73,7 @@ public: // Check before lock if (_newPlugin != nullptr) { Lock lock(_mutex); + _context->makeCurrent(); // Check if we have a new plugin to activate if (_newPlugin != nullptr) { // Deactivate the old plugin @@ -77,8 +84,8 @@ public: _newPlugin->customizeContext(); _activePlugin = _newPlugin; _newPlugin = nullptr; - _context->doneCurrent(); } + _context->doneCurrent(); lock.unlock(); } @@ -89,12 +96,14 @@ public: } // take the latest texture and present it + _context->makeCurrent(); _activePlugin->present(); - + _context->doneCurrent(); } + _context->doneCurrent(); - _widgetContext->moveToThread(qApp->thread()); _context->moveToThread(qApp->thread()); + _context->contextHandle()->moveToThread(qApp->thread()); } void withMainThreadContext(std::function f) { @@ -104,14 +113,16 @@ public: _finishedMainThreadOperation = false; _condition.wait(lock, [&] { return !_pendingMainThreadOperation; }); - _widgetContext->makeCurrent(); + _context->makeCurrent(); f(); - _widgetContext->doneCurrent(); + _context->doneCurrent(); + + // Move the context back to the presentation thread + _context->moveToThread(this); + _context->contextHandle()->moveToThread(this); // restore control of the context to the presentation thread and signal // the end of the operation - _widgetContext->moveToThread(this); - _context->moveToThread(this); _finishedMainThreadOperation = true; lock.unlock(); _condition.notify_one(); @@ -119,6 +130,9 @@ public: private: + void makeCurrent(); + void doneCurrent(); + bool _shutdown { false }; Mutex _mutex; // Used to allow the main thread to perform context operations @@ -128,8 +142,7 @@ private: QThread* _mainThread { nullptr }; OpenGLDisplayPlugin* _newPlugin { nullptr }; OpenGLDisplayPlugin* _activePlugin { nullptr }; - QOpenGLContext* _context { nullptr }; - QGLContext* _widgetContext { nullptr }; + QGLContext* _context { nullptr }; }; OpenGLDisplayPlugin::OpenGLDisplayPlugin() { @@ -165,16 +178,8 @@ void OpenGLDisplayPlugin::activate() { DependencyManager::set(); presentThread = DependencyManager::get(); presentThread->setObjectName("Presentation Thread"); - auto widget = _container->getPrimaryWidget(); - - // Move the OpenGL context to the present thread - // Extra code because of the widget 'wrapper' context - presentThread->_widgetContext = widget->context(); - presentThread->_widgetContext->moveToThread(presentThread.data()); - presentThread->_context = presentThread->_widgetContext->contextHandle(); - presentThread->_context->moveToThread(presentThread.data()); - + presentThread->setContext(widget->context()); // Start execution presentThread->start(); } @@ -196,9 +201,6 @@ void OpenGLDisplayPlugin::customizeContext() { auto presentThread = DependencyManager::get(); Q_ASSERT(thread() == presentThread->thread()); - bool makeCurrentResult = makeCurrent(); - Q_ASSERT(makeCurrentResult); - // TODO: write the proper code for linux #if defined(Q_OS_WIN) _vsyncSupported = wglewGetExtension("WGL_EXT_swap_control"); @@ -213,15 +215,11 @@ void OpenGLDisplayPlugin::customizeContext() { _program = loadDefaultShader(); _plane = loadPlane(_program); - - doneCurrent(); } void OpenGLDisplayPlugin::uncustomizeContext() { - makeCurrent(); _program.reset(); _plane.reset(); - doneCurrent(); } // Pressing Alt (and Meta) key alone activates the menubar because its style inherits the @@ -310,19 +308,11 @@ void OpenGLDisplayPlugin::internalPresent() { } void OpenGLDisplayPlugin::present() { - auto makeCurrentResult = makeCurrent(); - Q_ASSERT(makeCurrentResult); - if (!makeCurrentResult) { - qDebug() << "Failed to make current"; - return; - } - updateTextures(); if (_currentSceneTexture) { internalPresent(); updateFramerate(); } - doneCurrent(); } float OpenGLDisplayPlugin::presentRate() { @@ -360,18 +350,6 @@ bool OpenGLDisplayPlugin::isVsyncEnabled() { return true; #endif } -bool OpenGLDisplayPlugin::makeCurrent() { - static auto widget = _container->getPrimaryWidget(); - widget->makeCurrent(); - auto result = widget->context()->contextHandle() == QOpenGLContext::currentContext(); - Q_ASSERT(result); - return result; -} - -void OpenGLDisplayPlugin::doneCurrent() { - static auto widget = _container->getPrimaryWidget(); - widget->doneCurrent(); -} void OpenGLDisplayPlugin::swapBuffers() { static auto widget = _container->getPrimaryWidget(); diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index edbe7db006..809a52ef7f 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -63,8 +63,6 @@ protected: void updateTextures(); void updateFramerate(); void drawUnitQuad(); - bool makeCurrent(); - void doneCurrent(); void swapBuffers(); // Plugin specific functionality to composite the scene and overlay and present the result virtual void internalPresent(); diff --git a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp index 4332c53d81..ffaf005533 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.cpp @@ -67,5 +67,9 @@ glm::uvec2 InterleavedStereoDisplayPlugin::getRecommendedRenderSize() const { } void InterleavedStereoDisplayPlugin::internalPresent() { - // FIXME + using namespace oglplus; + _program->Bind(); + auto sceneSize = getRecommendedRenderSize(); + Uniform(*_program, "textureSize").SetValue(sceneSize); + WindowOpenGLDisplayPlugin::internalPresent(); } diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index 805ad75e95..b6690ea76e 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -55,11 +55,9 @@ bool OculusBaseDisplayPlugin::isSupported() const { // DLL based display plugins MUST initialize GLEW inside the DLL code. void OculusBaseDisplayPlugin::customizeContext() { - makeCurrent(); glewExperimental = true; GLenum err = glewInit(); glGetError(); - doneCurrent(); WindowOpenGLDisplayPlugin::customizeContext(); } diff --git a/plugins/oculus/src/OculusDisplayPlugin.cpp b/plugins/oculus/src/OculusDisplayPlugin.cpp index bcb39f5100..21c318677e 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDisplayPlugin.cpp @@ -154,8 +154,6 @@ void OculusDisplayPlugin::activate() { void OculusDisplayPlugin::customizeContext() { OculusBaseDisplayPlugin::customizeContext(); - bool makeCurrentResult = makeCurrent(); - Q_ASSERT(makeCurrentResult); #if (OVR_MAJOR_VERSION >= 6) _sceneFbo = SwapFboPtr(new SwapFramebufferWrapper(_hmd)); _sceneFbo->Init(getRecommendedRenderSize()); @@ -169,14 +167,11 @@ void OculusDisplayPlugin::customizeContext() { enableVsync(false); // Only enable mirroring if we know vsync is disabled _enablePreview = !isVsyncEnabled(); - doneCurrent(); } void OculusDisplayPlugin::uncustomizeContext() { #if (OVR_MAJOR_VERSION >= 6) - makeCurrent(); _sceneFbo.reset(); - doneCurrent(); #endif OculusBaseDisplayPlugin::uncustomizeContext(); } From 60aa93c38c6633b3d604f0e800cad33cd75f4048 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 3 Dec 2015 16:42:17 -0800 Subject: [PATCH 326/401] Fixing menu items in display plugins --- interface/src/Application.cpp | 9 +-- interface/src/Application.h | 2 - interface/src/PluginContainerProxy.cpp | 66 ++++++++-------- interface/src/PluginContainerProxy.h | 14 +++- .../Basic2DWindowOpenGLDisplayPlugin.cpp | 79 +++++++++---------- .../Basic2DWindowOpenGLDisplayPlugin.h | 3 +- .../display-plugins/OpenGLDisplayPlugin.cpp | 16 ++-- .../src/display-plugins/OpenGLDisplayPlugin.h | 3 +- .../stereo/InterleavedStereoDisplayPlugin.h | 1 - .../stereo/StereoDisplayPlugin.cpp | 2 +- .../src/input-plugins/SixenseManager.cpp | 2 +- .../input-plugins/ViveControllerManager.cpp | 2 +- libraries/plugins/src/plugins/Forward.h | 5 ++ .../plugins/src/plugins/PluginContainer.h | 8 +- .../oculus/src/OculusBaseDisplayPlugin.cpp | 3 +- plugins/oculus/src/OculusDisplayPlugin.cpp | 2 +- 16 files changed, 120 insertions(+), 97 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2c58156d2a..bbc36e8623 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4777,19 +4777,18 @@ void Application::updateDisplayMode() { return; } - if (!_currentDisplayPluginActions.isEmpty()) { + + if (!_pluginContainer->currentDisplayActions().isEmpty()) { auto menu = Menu::getInstance(); - foreach(auto itemInfo, _currentDisplayPluginActions) { + foreach(auto itemInfo, _pluginContainer->currentDisplayActions()) { menu->removeMenuItem(itemInfo.first, itemInfo.second); } - _currentDisplayPluginActions.clear(); + _pluginContainer->currentDisplayActions().clear(); } if (newDisplayPlugin) { _offscreenContext->makeCurrent(); - _activatingDisplayPlugin = true; newDisplayPlugin->activate(); - _activatingDisplayPlugin = false; _offscreenContext->makeCurrent(); offscreenUi->resize(fromGlm(newDisplayPlugin->getRecommendedUiSize())); _offscreenContext->makeCurrent(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 1af252de95..d12d29cde8 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -427,8 +427,6 @@ private: InputPluginList _activeInputPlugins; bool _activatingDisplayPlugin { false }; - QVector> _currentDisplayPluginActions; - QVector> _currentInputPluginActions; QMap _lockedFramebufferMap; MainWindow* _window; diff --git a/interface/src/PluginContainerProxy.cpp b/interface/src/PluginContainerProxy.cpp index 8774eecd77..abb52380d0 100644 --- a/interface/src/PluginContainerProxy.cpp +++ b/interface/src/PluginContainerProxy.cpp @@ -36,37 +36,31 @@ void PluginContainerProxy::removeMenu(const QString& menuName) { Menu::getInstance()->removeMenu(menuName); } -extern bool _activatingDisplayPlugin; -extern QVector> _currentDisplayPluginActions; -extern QVector> _currentInputPluginActions; -std::map _exclusiveGroups; - -QAction* PluginContainerProxy::addMenuItem(const QString& path, const QString& name, std::function onClicked, bool checkable, bool checked, const QString& groupName) { - //auto menu = Menu::getInstance(); - //MenuWrapper* parentItem = menu->getMenu(path); - //QAction* action = menu->addActionToQMenuAndActionHash(parentItem, name); - //if (!groupName.isEmpty()) { - // QActionGroup* group{ nullptr }; - // if (!_exclusiveGroups.count(groupName)) { - // group = _exclusiveGroups[groupName] = new QActionGroup(menu); - // group->setExclusive(true); - // } else { - // group = _exclusiveGroups[groupName]; - // } - // group->addAction(action); - //} - //connect(action, &QAction::triggered, [=] { - // onClicked(action->isChecked()); - //}); - //action->setCheckable(checkable); - //action->setChecked(checked); - //if (_activatingDisplayPlugin) { - // _currentDisplayPluginActions.push_back({ path, name }); - //} else { - // _currentInputPluginActions.push_back({ path, name }); - //} - //return action; - return nullptr; +QAction* PluginContainerProxy::addMenuItem(PluginType type, const QString& path, const QString& name, std::function onClicked, bool checkable, bool checked, const QString& groupName) { + auto menu = Menu::getInstance(); + MenuWrapper* parentItem = menu->getMenu(path); + QAction* action = menu->addActionToQMenuAndActionHash(parentItem, name); + if (!groupName.isEmpty()) { + QActionGroup* group{ nullptr }; + if (!_exclusiveGroups.count(groupName)) { + group = _exclusiveGroups[groupName] = new QActionGroup(menu); + group->setExclusive(true); + } else { + group = _exclusiveGroups[groupName]; + } + group->addAction(action); + } + connect(action, &QAction::triggered, [=] { + onClicked(action->isChecked()); + }); + action->setCheckable(checkable); + action->setChecked(checked); + if (type == PluginType::DISPLAY_PLUGIN) { + _currentDisplayPluginActions.push_back({ path, name }); + } else { + _currentInputPluginActions.push_back({ path, name }); + } + return action; } void PluginContainerProxy::removeMenuItem(const QString& menuName, const QString& menuItem) { @@ -188,5 +182,13 @@ void PluginContainerProxy::releaseSceneTexture(uint32_t texture) { } void PluginContainerProxy::releaseOverlayTexture(uint32_t texture) { - + // FIXME implement present thread compositing +} + +QVector>& PluginContainerProxy::currentDisplayActions() { + return _currentDisplayPluginActions; +} + +QVector>& PluginContainerProxy::currentInputActions() { + return _currentInputPluginActions; } diff --git a/interface/src/PluginContainerProxy.h b/interface/src/PluginContainerProxy.h index 5cc1cc8583..cd15510885 100644 --- a/interface/src/PluginContainerProxy.h +++ b/interface/src/PluginContainerProxy.h @@ -2,19 +2,23 @@ #ifndef hifi_PluginContainerProxy_h #define hifi_PluginContainerProxy_h -#include -#include +#include +#include #include #include +class QActionGroup; + class PluginContainerProxy : public QObject, PluginContainer { Q_OBJECT PluginContainerProxy(); virtual ~PluginContainerProxy(); + virtual QVector>& currentDisplayActions() override; + virtual QVector>& currentInputActions() override; virtual void addMenu(const QString& menuName) override; virtual void removeMenu(const QString& menuName) override; - virtual QAction* addMenuItem(const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override; + virtual QAction* addMenuItem(PluginType type, const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override; virtual void removeMenuItem(const QString& menuName, const QString& menuItem) override; virtual bool isOptionChecked(const QString& name) override; virtual void setIsOptionChecked(const QString& path, bool checked) override; @@ -32,8 +36,12 @@ class PluginContainerProxy : public QObject, PluginContainer { virtual const DisplayPlugin* getActiveDisplayPlugin() const override; QRect _savedGeometry{ 10, 120, 800, 600 }; + std::map _exclusiveGroups; + QVector> _currentDisplayPluginActions; + QVector> _currentInputPluginActions; friend class Application; + }; #endif \ No newline at end of file diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp index 36216f8912..6c450e0735 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.cpp @@ -31,60 +31,59 @@ const QString& Basic2DWindowOpenGLDisplayPlugin::getName() const { } void Basic2DWindowOpenGLDisplayPlugin::activate() { - //_framerateActions.clear(); - //_container->addMenuItem(MENU_PATH(), FULLSCREEN, - // [this](bool clicked) { - // if (clicked) { - // _container->setFullscreen(getFullscreenTarget()); - // } else { - // _container->unsetFullscreen(); - // } - // }, true, false); - //_container->addMenu(FRAMERATE); - //_framerateActions.push_back( - // _container->addMenuItem(FRAMERATE, FRAMERATE_UNLIMITED, - // [this](bool) { updateFramerate(); }, true, true, FRAMERATE)); - //_framerateActions.push_back( - // _container->addMenuItem(FRAMERATE, FRAMERATE_60, - // [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); - //_framerateActions.push_back( - // _container->addMenuItem(FRAMERATE, FRAMERATE_50, - // [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); - //_framerateActions.push_back( - // _container->addMenuItem(FRAMERATE, FRAMERATE_40, - // [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); - //_framerateActions.push_back( - // _container->addMenuItem(FRAMERATE, FRAMERATE_30, - // [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); - WindowOpenGLDisplayPlugin::activate(); - //// Vsync detection happens in the parent class activate, so we need to check after that - //if (_vsyncSupported) { - // _vsyncAction = _container->addMenuItem(MENU_PATH(), VSYNC_ON, [this](bool) {}, true, true); - //} else { - // _vsyncAction = nullptr; - //} + _framerateActions.clear(); + _container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), FULLSCREEN, + [this](bool clicked) { + if (clicked) { + _container->setFullscreen(getFullscreenTarget()); + } else { + _container->unsetFullscreen(); + } + }, true, false); + _container->addMenu(FRAMERATE); + _framerateActions.push_back( + _container->addMenuItem(PluginType::DISPLAY_PLUGIN, FRAMERATE, FRAMERATE_UNLIMITED, + [this](bool) { updateFramerate(); }, true, true, FRAMERATE)); + _framerateActions.push_back( + _container->addMenuItem(PluginType::DISPLAY_PLUGIN, FRAMERATE, FRAMERATE_60, + [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); + _framerateActions.push_back( + _container->addMenuItem(PluginType::DISPLAY_PLUGIN, FRAMERATE, FRAMERATE_50, + [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); + _framerateActions.push_back( + _container->addMenuItem(PluginType::DISPLAY_PLUGIN, FRAMERATE, FRAMERATE_40, + [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); + _framerateActions.push_back( + _container->addMenuItem(PluginType::DISPLAY_PLUGIN, FRAMERATE, FRAMERATE_30, + [this](bool) { updateFramerate(); }, true, false, FRAMERATE)); + + // Vsync detection happens in the parent class activate, so we need to check after that + if (_vsyncSupported) { + _vsyncAction = _container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), VSYNC_ON, [this](bool) {}, true, true); + } else { + _vsyncAction = nullptr; + } updateFramerate(); } -void Basic2DWindowOpenGLDisplayPlugin::deactivate() { - WindowOpenGLDisplayPlugin::deactivate(); -} - void Basic2DWindowOpenGLDisplayPlugin::submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) { if (_vsyncAction) { _wantVsync = _vsyncAction->isChecked(); - //bool vsyncEnabed = isVsyncEnabled(); - //if (vsyncEnabed ^ wantVsync) { - // enableVsync(wantVsync); - //} } WindowOpenGLDisplayPlugin::submitSceneTexture(frameIndex, sceneTexture, sceneSize); } +void Basic2DWindowOpenGLDisplayPlugin::internalPresent() { + if (_wantVsync != isVsyncEnabled()) { + enableVsync(_wantVsync); + } + WindowOpenGLDisplayPlugin::internalPresent(); +} + int Basic2DWindowOpenGLDisplayPlugin::getDesiredInterval() const { static const int THROTTLED_PAINT_TIMER_DELAY_MS = MSECS_PER_SECOND / 15; static const int ULIMIITED_PAINT_TIMER_DELAY_MS = 1; diff --git a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h index 80aebf9efc..36a1a73b94 100644 --- a/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/Basic2DWindowOpenGLDisplayPlugin.h @@ -19,10 +19,11 @@ public: virtual const QString & getName() const override; virtual void activate() override; - virtual void deactivate() override; virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override; + virtual void internalPresent() override; + virtual bool isThrottled() const override; protected: diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 45e6daef31..12aa37cd56 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -145,6 +145,8 @@ private: QGLContext* _context { nullptr }; }; +bool OpenGLDisplayPlugin::_vsyncSupported = false; + OpenGLDisplayPlugin::OpenGLDisplayPlugin() { _sceneTextureEscrow.setRecycler([this](GLuint texture){ cleanupForSceneTexture(texture); @@ -175,10 +177,18 @@ void OpenGLDisplayPlugin::activate() { // Start the present thread if necessary auto presentThread = DependencyManager::get(); if (!presentThread) { + auto widget = _container->getPrimaryWidget(); + + // TODO: write the proper code for linux +#if defined(Q_OS_WIN) + widget->makeCurrent(); + _vsyncSupported = wglewGetExtension("WGL_EXT_swap_control"); + widget->doneCurrent(); +#endif + DependencyManager::set(); presentThread = DependencyManager::get(); presentThread->setObjectName("Presentation Thread"); - auto widget = _container->getPrimaryWidget(); presentThread->setContext(widget->context()); // Start execution presentThread->start(); @@ -201,10 +211,6 @@ void OpenGLDisplayPlugin::customizeContext() { auto presentThread = DependencyManager::get(); Q_ASSERT(thread() == presentThread->thread()); - // TODO: write the proper code for linux -#if defined(Q_OS_WIN) - _vsyncSupported = wglewGetExtension("WGL_EXT_swap_control"); -#endif enableVsync(); using namespace oglplus; diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index 809a52ef7f..747d8b810b 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -70,7 +70,6 @@ protected: mutable QTimer _timer; ProgramPtr _program; ShapeWrapperPtr _plane; - bool _vsyncSupported { false }; Mutex _mutex; SimpleMovingAverage _usecsPerFrame { 10 }; @@ -81,6 +80,8 @@ protected: GLTextureEscrow _overlayTextureEscrow; GLTextureEscrow _sceneTextureEscrow; + + static bool _vsyncSupported; }; diff --git a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h index b9b3566349..7116363e44 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/stereo/InterleavedStereoDisplayPlugin.h @@ -19,7 +19,6 @@ public: virtual void customizeContext() override; virtual glm::uvec2 getRecommendedRenderSize() const override; - void internalPresent() override; private: diff --git a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp index f7e71313df..a691f375eb 100644 --- a/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/stereo/StereoDisplayPlugin.cpp @@ -74,7 +74,7 @@ void StereoDisplayPlugin::activate() { if (screen == qApp->primaryScreen()) { checked = true; } - auto action = _container->addMenuItem(MENU_PATH(), name, + auto action = _container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), name, [this](bool clicked) { updateScreen(); }, true, checked, "Screens"); _screenActions[i] = action; } diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp index 18fdc9ddad..5dd0248224 100644 --- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp +++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp @@ -68,7 +68,7 @@ void SixenseManager::activate() { #ifdef HAVE_SIXENSE _container->addMenu(MENU_PATH); - _container->addMenuItem(MENU_PATH, TOGGLE_SMOOTH, + _container->addMenuItem(PluginType::INPUT_PLUGIN, MENU_PATH, TOGGLE_SMOOTH, [this] (bool clicked) { setSixenseFilter(clicked); }, true, true); diff --git a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp index ec0c35cc96..b315a7a3d9 100644 --- a/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp +++ b/libraries/input-plugins/src/input-plugins/ViveControllerManager.cpp @@ -60,7 +60,7 @@ void ViveControllerManager::activate() { InputPlugin::activate(); #ifdef Q_OS_WIN _container->addMenu(MENU_PATH); - _container->addMenuItem(MENU_PATH, RENDER_CONTROLLERS, + _container->addMenuItem(PluginType::INPUT_PLUGIN, MENU_PATH, RENDER_CONTROLLERS, [this] (bool clicked) { this->setRenderControllers(clicked); }, true, true); diff --git a/libraries/plugins/src/plugins/Forward.h b/libraries/plugins/src/plugins/Forward.h index 8d8259ba4f..036b42f7d7 100644 --- a/libraries/plugins/src/plugins/Forward.h +++ b/libraries/plugins/src/plugins/Forward.h @@ -10,6 +10,11 @@ #include #include +enum class PluginType { + DISPLAY_PLUGIN, + INPUT_PLUGIN, +}; + class DisplayPlugin; class InputPlugin; class Plugin; diff --git a/libraries/plugins/src/plugins/PluginContainer.h b/libraries/plugins/src/plugins/PluginContainer.h index 25c2bcb11f..337ffd3c57 100644 --- a/libraries/plugins/src/plugins/PluginContainer.h +++ b/libraries/plugins/src/plugins/PluginContainer.h @@ -10,6 +10,10 @@ #include #include #include +#include +#include + +#include "Forward.h" class QAction; class QGLWidget; @@ -24,9 +28,11 @@ public: static PluginContainer& getInstance(); PluginContainer(); virtual ~PluginContainer(); + virtual QVector>& currentDisplayActions() = 0; + virtual QVector>& currentInputActions() = 0; virtual void addMenu(const QString& menuName) = 0; virtual void removeMenu(const QString& menuName) = 0; - virtual QAction* addMenuItem(const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") = 0; + virtual QAction* addMenuItem(PluginType pluginType, const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") = 0; virtual void removeMenuItem(const QString& menuName, const QString& menuItem) = 0; virtual bool isOptionChecked(const QString& name) = 0; virtual void setIsOptionChecked(const QString& path, bool checked) = 0; diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index b6690ea76e..7c057c7152 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -68,6 +68,7 @@ void OculusBaseDisplayPlugin::deinit() { } void OculusBaseDisplayPlugin::activate() { + WindowOpenGLDisplayPlugin::activate(); #if (OVR_MAJOR_VERSION >= 6) if (!OVR_SUCCESS(ovr_Initialize(nullptr))) { qFatal("Could not init OVR"); @@ -134,8 +135,6 @@ void OculusBaseDisplayPlugin::activate() { qFatal("Could not attach to sensor device"); } #endif - - WindowOpenGLDisplayPlugin::activate(); } void OculusBaseDisplayPlugin::deactivate() { diff --git a/plugins/oculus/src/OculusDisplayPlugin.cpp b/plugins/oculus/src/OculusDisplayPlugin.cpp index 21c318677e..8846b8a6a6 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDisplayPlugin.cpp @@ -144,7 +144,7 @@ static const QString MONO_PREVIEW = "Mono Preview"; static const QString FRAMERATE = DisplayPlugin::MENU_PATH() + ">Framerate"; void OculusDisplayPlugin::activate() { - _container->addMenuItem(MENU_PATH(), MONO_PREVIEW, + _container->addMenuItem(PluginType::DISPLAY_PLUGIN, MENU_PATH(), MONO_PREVIEW, [this](bool clicked) { _monoPreview = clicked; }, true, true); From c4514743d16440ee17565af885842ad83eb1f2d9 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 3 Dec 2015 17:07:04 -0800 Subject: [PATCH 327/401] Fixing tests, moving some plugin container stuff to base class --- interface/src/PluginContainerProxy.cpp | 7 ------- interface/src/PluginContainerProxy.h | 4 ---- libraries/plugins/src/plugins/PluginContainer.h | 15 +++++++++++++-- tests/controllers/src/main.cpp | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/interface/src/PluginContainerProxy.cpp b/interface/src/PluginContainerProxy.cpp index abb52380d0..aff36fb881 100644 --- a/interface/src/PluginContainerProxy.cpp +++ b/interface/src/PluginContainerProxy.cpp @@ -185,10 +185,3 @@ void PluginContainerProxy::releaseOverlayTexture(uint32_t texture) { // FIXME implement present thread compositing } -QVector>& PluginContainerProxy::currentDisplayActions() { - return _currentDisplayPluginActions; -} - -QVector>& PluginContainerProxy::currentInputActions() { - return _currentInputPluginActions; -} diff --git a/interface/src/PluginContainerProxy.h b/interface/src/PluginContainerProxy.h index cd15510885..5d974f0a0c 100644 --- a/interface/src/PluginContainerProxy.h +++ b/interface/src/PluginContainerProxy.h @@ -14,8 +14,6 @@ class PluginContainerProxy : public QObject, PluginContainer { Q_OBJECT PluginContainerProxy(); virtual ~PluginContainerProxy(); - virtual QVector>& currentDisplayActions() override; - virtual QVector>& currentInputActions() override; virtual void addMenu(const QString& menuName) override; virtual void removeMenu(const QString& menuName) override; virtual QAction* addMenuItem(PluginType type, const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override; @@ -37,8 +35,6 @@ class PluginContainerProxy : public QObject, PluginContainer { QRect _savedGeometry{ 10, 120, 800, 600 }; std::map _exclusiveGroups; - QVector> _currentDisplayPluginActions; - QVector> _currentInputPluginActions; friend class Application; diff --git a/libraries/plugins/src/plugins/PluginContainer.h b/libraries/plugins/src/plugins/PluginContainer.h index 337ffd3c57..6732bc02ba 100644 --- a/libraries/plugins/src/plugins/PluginContainer.h +++ b/libraries/plugins/src/plugins/PluginContainer.h @@ -28,8 +28,6 @@ public: static PluginContainer& getInstance(); PluginContainer(); virtual ~PluginContainer(); - virtual QVector>& currentDisplayActions() = 0; - virtual QVector>& currentInputActions() = 0; virtual void addMenu(const QString& menuName) = 0; virtual void removeMenu(const QString& menuName) = 0; virtual QAction* addMenuItem(PluginType pluginType, const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") = 0; @@ -48,4 +46,17 @@ public: virtual QOpenGLContext* getPrimaryContext() = 0; virtual bool isForeground() = 0; virtual const DisplayPlugin* getActiveDisplayPlugin() const = 0; + + QVector>& currentDisplayActions() { + return _currentDisplayPluginActions; + } + + QVector>& currentInputActions() { + return _currentInputPluginActions; + } + +protected: + QVector> _currentDisplayPluginActions; + QVector> _currentInputPluginActions; + }; diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp index c5c038fde3..8514d33d2e 100644 --- a/tests/controllers/src/main.cpp +++ b/tests/controllers/src/main.cpp @@ -83,7 +83,7 @@ public: virtual ~PluginContainerProxy() {} virtual void addMenu(const QString& menuName) override {} virtual void removeMenu(const QString& menuName) override {} - virtual QAction* addMenuItem(const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override { return nullptr; } + virtual QAction* addMenuItem(PluginType type, const QString& path, const QString& name, std::function onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override { return nullptr; } virtual void removeMenuItem(const QString& menuName, const QString& menuItem) override {} virtual bool isOptionChecked(const QString& name) override { return false; } virtual void setIsOptionChecked(const QString& path, bool checked) override {} From 90ef7c6bf763d77be56ced44f4325a22ef673a93 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 3 Dec 2015 23:29:56 -0800 Subject: [PATCH 328/401] Disabling 0.5 Oculus plugin (Mac / Linux) for now --- interface/src/PluginContainerProxy.cpp | 1 - plugins/oculusLegacy/CMakeLists.txt | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/PluginContainerProxy.cpp b/interface/src/PluginContainerProxy.cpp index aff36fb881..aae94162ad 100644 --- a/interface/src/PluginContainerProxy.cpp +++ b/interface/src/PluginContainerProxy.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include diff --git a/plugins/oculusLegacy/CMakeLists.txt b/plugins/oculusLegacy/CMakeLists.txt index bf9d22410d..44cee83a7d 100644 --- a/plugins/oculusLegacy/CMakeLists.txt +++ b/plugins/oculusLegacy/CMakeLists.txt @@ -6,7 +6,8 @@ # See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html # -if (NOT WIN32) +#if (NOT WIN32) +if (FALSE) set(TARGET_NAME oculusLegacy) setup_hifi_plugin() From 528a17422d4d32b29915191b71417375272d9e90 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 4 Dec 2015 10:33:10 -0800 Subject: [PATCH 329/401] Last of the OpenGL warnings on OS X --- .../src/QOpenGLContextWrapper.cpp | 40 +++++++++++++++++++ .../render-utils/src/QOpenGLContextWrapper.h | 33 +++++++++++++++ .../src/QOpenGLDebugLoggerWrapper.cpp | 24 +++++++++++ .../src/QOpenGLDebugLoggerWrapper.h | 19 +++++++++ tests/gpu-test/src/main.cpp | 24 ++++------- tests/render-utils/src/main.cpp | 25 ++++-------- tests/shaders/src/main.cpp | 25 +++++------- 7 files changed, 141 insertions(+), 49 deletions(-) create mode 100644 libraries/render-utils/src/QOpenGLContextWrapper.cpp create mode 100644 libraries/render-utils/src/QOpenGLContextWrapper.h create mode 100644 libraries/render-utils/src/QOpenGLDebugLoggerWrapper.cpp create mode 100644 libraries/render-utils/src/QOpenGLDebugLoggerWrapper.h diff --git a/libraries/render-utils/src/QOpenGLContextWrapper.cpp b/libraries/render-utils/src/QOpenGLContextWrapper.cpp new file mode 100644 index 0000000000..64233ea413 --- /dev/null +++ b/libraries/render-utils/src/QOpenGLContextWrapper.cpp @@ -0,0 +1,40 @@ +// +// QOpenGLContextWrapper.cpp +// +// +// Created by Clement on 12/4/15. +// 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 "QOpenGLContextWrapper.h" + +#include + + +QOpenGLContextWrapper::QOpenGLContextWrapper() : + _context(new QOpenGLContext) +{ +} + +void QOpenGLContextWrapper::setFormat(const QSurfaceFormat& format) { + _context->setFormat(format); +} + +bool QOpenGLContextWrapper::create() { + return _context->create(); +} + +void QOpenGLContextWrapper::swapBuffers(QSurface* surface) { + _context->swapBuffers(surface); +} + +bool QOpenGLContextWrapper::makeCurrent(QSurface* surface) { + return _context->makeCurrent(surface); +} + +void QOpenGLContextWrapper::doneCurrent() { + _context->doneCurrent(); +} \ No newline at end of file diff --git a/libraries/render-utils/src/QOpenGLContextWrapper.h b/libraries/render-utils/src/QOpenGLContextWrapper.h new file mode 100644 index 0000000000..6c50d5f438 --- /dev/null +++ b/libraries/render-utils/src/QOpenGLContextWrapper.h @@ -0,0 +1,33 @@ +// +// QOpenGLContextWrapper.h +// +// +// Created by Clement on 12/4/15. +// 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_QOpenGLContextWrapper_h +#define hifi_QOpenGLContextWrapper_h + +class QOpenGLContext; +class QSurface; +class QSurfaceFormat; + +class QOpenGLContextWrapper { +public: + QOpenGLContextWrapper(); + + void setFormat(const QSurfaceFormat& format); + bool create(); + void swapBuffers(QSurface* surface); + bool makeCurrent(QSurface* surface); + void doneCurrent(); + +private: + QOpenGLContext* _context { nullptr }; +}; + +#endif // hifi_QOpenGLContextWrapper_h \ No newline at end of file diff --git a/libraries/render-utils/src/QOpenGLDebugLoggerWrapper.cpp b/libraries/render-utils/src/QOpenGLDebugLoggerWrapper.cpp new file mode 100644 index 0000000000..bd185034f4 --- /dev/null +++ b/libraries/render-utils/src/QOpenGLDebugLoggerWrapper.cpp @@ -0,0 +1,24 @@ +// +// QOpenGLDebugLoggerWrapper.cpp +// +// +// Created by Clement on 12/4/15. +// 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 "QOpenGLDebugLoggerWrapper.h" + +#include +#include + +void setupDebugLogger(QObject* window) { + QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(window); + logger->initialize(); // initializes in the current context, i.e. ctx + logger->enableMessages(); + QObject::connect(logger, &QOpenGLDebugLogger::messageLogged, window, [&](const QOpenGLDebugMessage & debugMessage) { + qDebug() << debugMessage; + }); +} \ No newline at end of file diff --git a/libraries/render-utils/src/QOpenGLDebugLoggerWrapper.h b/libraries/render-utils/src/QOpenGLDebugLoggerWrapper.h new file mode 100644 index 0000000000..e2b1c5d9d4 --- /dev/null +++ b/libraries/render-utils/src/QOpenGLDebugLoggerWrapper.h @@ -0,0 +1,19 @@ +// +// QOpenGLDebugLoggerWrapper.h +// +// +// Created by Clement on 12/4/15. +// 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_QOpenGLDebugLoggerWrapper_h +#define hifi_QOpenGLDebugLoggerWrapper_h + +class QObject; + +void setupDebugLogger(QObject* window); + +#endif // hifi_QOpenGLDebugLoggerWrapper_h \ No newline at end of file diff --git a/tests/gpu-test/src/main.cpp b/tests/gpu-test/src/main.cpp index 80c2dbf8e9..fbfb49aace 100644 --- a/tests/gpu-test/src/main.cpp +++ b/tests/gpu-test/src/main.cpp @@ -33,9 +33,8 @@ #include #include -// Must come after GL headers -#include -#include +#include +#include #include #include @@ -118,7 +117,7 @@ gpu::Stream::FormatPointer& getInstancedSolidStreamFormat(); class QTestWindow : public QWindow { Q_OBJECT - QOpenGLContext* _qGlContext{ nullptr }; + QOpenGLContextWrapper _qGlContext; QSize _size; gpu::ContextPointer _context; @@ -151,19 +150,12 @@ public: setFormat(format); - _qGlContext = new QOpenGLContext; - _qGlContext->setFormat(format); - _qGlContext->create(); + _qGlContext.setFormat(format); + _qGlContext.create(); show(); makeCurrent(); - QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(this); - logger->initialize(); // initializes in the current context, i.e. ctx - connect(logger, &QOpenGLDebugLogger::messageLogged, [](const QOpenGLDebugMessage& message){ - qDebug() << message; - }); - logger->startLogging(QOpenGLDebugLogger::SynchronousLogging); - + setupDebugLogger(this); gpu::Context::init(); _context = std::make_shared(); @@ -371,7 +363,7 @@ public: geometryCache->renderWireCube(batch); _context->render(batch); - _qGlContext->swapBuffers(this); + _qGlContext.swapBuffers(this); fps.increment(); if (fps.elapsed() >= 0.5f) { @@ -381,7 +373,7 @@ public: } void makeCurrent() { - _qGlContext->makeCurrent(this); + _qGlContext.makeCurrent(this); } protected: diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index 0fa261db8d..43778c5c56 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -14,8 +14,8 @@ #include -#include -#include +#include +#include #include #include @@ -77,7 +77,7 @@ const QString& getQmlDir() { class QTestWindow : public QWindow { Q_OBJECT - QOpenGLContext* _context{ nullptr }; + QOpenGLContextWrapper _context; QSize _size; //TextRenderer* _textRenderer[4]; RateCounter fps; @@ -104,9 +104,8 @@ public: setFormat(format); - _context = new QOpenGLContext; - _context->setFormat(format); - _context->create(); + _context.setFormat(format); + _context.create(); show(); makeCurrent(); @@ -114,15 +113,7 @@ public: gpu::Context::init(); - { - QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(this); - logger->initialize(); // initializes in the current context, i.e. ctx - logger->enableMessages(); - connect(logger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage & debugMessage) { - qDebug() << debugMessage; - }); - // logger->startLogging(QOpenGLDebugLogger::SynchronousLogging); - } + setupDebugLogger(this); qDebug() << (const char*)glGetString(GL_VERSION); //_textRenderer[0] = TextRenderer::getInstance(SANS_FONT_FAMILY, 12, false); @@ -147,7 +138,7 @@ public: void draw(); void makeCurrent() { - _context->makeCurrent(this); + _context.makeCurrent(this); } protected: @@ -185,7 +176,7 @@ void QTestWindow::draw() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(0, 0, _size.width() * devicePixelRatio(), _size.height() * devicePixelRatio()); - _context->swapBuffers(this); + _context.swapBuffers(this); glFinish(); fps.increment(); diff --git a/tests/shaders/src/main.cpp b/tests/shaders/src/main.cpp index f65cd9b5aa..658bc9c236 100644 --- a/tests/shaders/src/main.cpp +++ b/tests/shaders/src/main.cpp @@ -10,8 +10,6 @@ #include -#include - #include #include #include @@ -22,6 +20,9 @@ #include +#include +#include + #include "../model/Skybox_vert.h" #include "../model/Skybox_frag.h" @@ -120,7 +121,7 @@ // Create a simple OpenGL window that renders text in various ways class QTestWindow : public QWindow { Q_OBJECT - QOpenGLContext* _context{ nullptr }; + QOpenGLContextWrapper _context; protected: void renderText(); @@ -130,22 +131,14 @@ public: setSurfaceType(QSurface::OpenGLSurface); QSurfaceFormat format = getDefaultOpenGLSurfaceFormat(); setFormat(format); - _context = new QOpenGLContext; - _context->setFormat(format); - _context->create(); + _context.setFormat(format); + _context.create(); show(); makeCurrent(); gpu::Context::init(); - { - QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(this); - logger->initialize(); // initializes in the current context, i.e. ctx - logger->enableMessages(); - connect(logger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage & debugMessage) { - qDebug() << debugMessage; - }); - } + setupDebugLogger(this); makeCurrent(); resize(QSize(800, 600)); } @@ -155,7 +148,7 @@ public: void draw(); void makeCurrent() { - _context->makeCurrent(this); + _context.makeCurrent(this); } }; @@ -248,7 +241,7 @@ void QTestWindow::draw() { testShaderBuild(polyvox_vert, polyvox_frag); }); - _context->swapBuffers(this); + _context.swapBuffers(this); } void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { From 42466728131c63fa6fee072f358466670264cb33 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 4 Dec 2015 10:38:24 -0800 Subject: [PATCH 330/401] enable head-moving of distance grabbing --- examples/controllers/handControllerGrab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index bcb76716d9..05de977bd8 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -37,7 +37,7 @@ var BUMPER_ON_VALUE = 0.5; var DISTANCE_HOLDING_RADIUS_FACTOR = 3.5; // multiplied by distance between hand and object var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did -var MOVE_WITH_HEAD = false; // experimental head-controll of distantly held objects +var MOVE_WITH_HEAD = true; // experimental head-controll of distantly held objects var NO_INTERSECT_COLOR = { red: 10, From cb67f05103d66eb2234c50a1d8b2d01f696cece5 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Fri, 4 Dec 2015 10:47:27 -0800 Subject: [PATCH 331/401] Remove unimplemented menu items Developer->Avatar->Show Skeleton/Head Collision Shapes. --- interface/src/Menu.cpp | 2 -- interface/src/Menu.h | 2 -- interface/src/avatar/Avatar.cpp | 10 ---------- 3 files changed, 14 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d0c8b502c5..d48511d990 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -433,8 +433,6 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AvatarReceiveStats, 0, false, avatarManager.data(), SLOT(setShouldShowReceiveStats(bool))); - addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderSkeletonCollisionShapes); - addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderHeadCollisionShapes); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderBoundingCollisionShapes); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtVectors, 0, false); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtTargets, 0, false); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 6b51987479..8041d2533f 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -239,10 +239,8 @@ namespace MenuOption { const QString ReloadContent = "Reload Content (Clears all caches)"; const QString RenderBoundingCollisionShapes = "Show Bounding Collision Shapes"; const QString RenderFocusIndicator = "Show Eye Focus"; - const QString RenderHeadCollisionShapes = "Show Head Collision Shapes"; const QString RenderLookAtTargets = "Show Look-at Targets"; const QString RenderLookAtVectors = "Show Look-at Vectors"; - const QString RenderSkeletonCollisionShapes = "Show Skeleton Collision Shapes"; const QString RenderResolution = "Scale Resolution"; const QString RenderResolutionOne = "1"; const QString RenderResolutionTwoThird = "2/3"; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index bf4ddadb62..cf812db383 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -463,16 +463,6 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { } } - /* - // TODO: re-implement these when we have more detailed avatar collision shapes - bool renderSkeleton = Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes); - if (renderSkeleton) { - } - bool renderHead = Menu::getInstance()->isOptionChecked(MenuOption::RenderHeadCollisionShapes); - if (renderHead && shouldRenderHead(renderArgs)) { - } - */ - bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes); if (renderBounding && shouldRenderHead(renderArgs) && _skeletonModel.isRenderable()) { PROFILE_RANGE_BATCH(batch, __FUNCTION__":skeletonBoundingCollisionShapes"); From ca84fcd7f414e5f8870df7079933e909f9a9cd77 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 4 Dec 2015 11:01:18 -0800 Subject: [PATCH 332/401] parent the keepalive timer to the NL thread --- libraries/networking/src/NodeList.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 925c64c77a..5a39f0312c 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -40,7 +40,8 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned _nodeTypesOfInterest(), _domainHandler(this), _numNoReplyDomainCheckIns(0), - _assignmentServerSocket() + _assignmentServerSocket(), + _keepAlivePingTimer(this) { setCustomDeleter([](Dependency* dependency){ static_cast(dependency)->deleteLater(); From ea65ef964fbd1672803ab729d5eaffda9916b02f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 4 Dec 2015 11:13:36 -0800 Subject: [PATCH 333/401] fix an AC race/crash --- libraries/shared/src/SpatiallyNestable.cpp | 51 +++++++++++++--------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index a0280943de..0d7d2a7652 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -62,6 +62,9 @@ SpatiallyNestablePointer SpatiallyNestable::getParentPointer() const { // we have a _parentID but no parent pointer, or our parent pointer was to the wrong thing QSharedPointer parentFinder = DependencyManager::get(); + if (!parentFinder) { + return nullptr; + } _parent = parentFinder->find(_parentID); parent = _parent.lock(); if (parent) { @@ -98,12 +101,14 @@ void SpatiallyNestable::setParentID(const QUuid parentID) { glm::vec3 SpatiallyNestable::worldToLocal(glm::vec3 position, QUuid parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); - auto parentWP = parentFinder->find(parentID); - auto parent = parentWP.lock(); Transform parentTransform; - if (parent) { - parentTransform = parent->getTransform(parentJointIndex); - parentTransform.setScale(1.0f); + if (parentFinder) { + auto parentWP = parentFinder->find(parentID); + auto parent = parentWP.lock(); + if (parent) { + parentTransform = parent->getTransform(parentJointIndex); + parentTransform.setScale(1.0f); + } } Transform positionTransform; @@ -119,12 +124,14 @@ glm::vec3 SpatiallyNestable::worldToLocal(glm::vec3 position, QUuid parentID, in glm::quat SpatiallyNestable::worldToLocal(glm::quat orientation, QUuid parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); - auto parentWP = parentFinder->find(parentID); - auto parent = parentWP.lock(); Transform parentTransform; - if (parent) { - parentTransform = parent->getTransform(parentJointIndex); - parentTransform.setScale(1.0f); + if (parentFinder) { + auto parentWP = parentFinder->find(parentID); + auto parent = parentWP.lock(); + if (parent) { + parentTransform = parent->getTransform(parentJointIndex); + parentTransform.setScale(1.0f); + } } Transform orientationTransform; @@ -139,12 +146,14 @@ glm::quat SpatiallyNestable::worldToLocal(glm::quat orientation, QUuid parentID, glm::vec3 SpatiallyNestable::localToWorld(glm::vec3 position, QUuid parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); - auto parentWP = parentFinder->find(parentID); - auto parent = parentWP.lock(); Transform parentTransform; - if (parent) { - parentTransform = parent->getTransform(parentJointIndex); - parentTransform.setScale(1.0f); + if (parentFinder) { + auto parentWP = parentFinder->find(parentID); + auto parent = parentWP.lock(); + if (parent) { + parentTransform = parent->getTransform(parentJointIndex); + parentTransform.setScale(1.0f); + } } Transform positionTransform; positionTransform.setTranslation(position); @@ -155,12 +164,14 @@ glm::vec3 SpatiallyNestable::localToWorld(glm::vec3 position, QUuid parentID, in glm::quat SpatiallyNestable::localToWorld(glm::quat orientation, QUuid parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); - auto parentWP = parentFinder->find(parentID); - auto parent = parentWP.lock(); Transform parentTransform; - if (parent) { - parentTransform = parent->getTransform(parentJointIndex); - parentTransform.setScale(1.0f); + if (parentFinder) { + auto parentWP = parentFinder->find(parentID); + auto parent = parentWP.lock(); + if (parent) { + parentTransform = parent->getTransform(parentJointIndex); + parentTransform.setScale(1.0f); + } } Transform orientationTransform; orientationTransform.setRotation(orientation); From 918342df5f1bd2e04d6e036d747f6d181f5e947d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 4 Dec 2015 11:18:46 -0800 Subject: [PATCH 334/401] make sure the NodeList is reset on its own thread --- libraries/networking/src/DomainHandler.cpp | 2 +- libraries/networking/src/NodeList.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/DomainHandler.cpp b/libraries/networking/src/DomainHandler.cpp index 681f971ef5..96a6c9c4a5 100644 --- a/libraries/networking/src/DomainHandler.cpp +++ b/libraries/networking/src/DomainHandler.cpp @@ -94,7 +94,7 @@ void DomainHandler::softReset() { clearSettings(); // cancel the failure timeout for any pending requests for settings - QMetaObject::invokeMethod(&_settingsTimer, "stop", Qt::AutoConnection); + QMetaObject::invokeMethod(&_settingsTimer, "stop"); } void DomainHandler::hardReset() { diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 925c64c77a..38c9d819e2 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -199,6 +199,11 @@ void NodeList::processICEPingPacket(QSharedPointer packet) { } void NodeList::reset() { + if (thread() != QThread::currentThread()) { + QMetaObject::invokeMethod(this, "reset"); + return; + } + LimitedNodeList::reset(); _numNoReplyDomainCheckIns = 0; From d5f79b84fca14cf41ead9471349ed0bc23e2a8ef Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 4 Dec 2015 11:20:46 -0800 Subject: [PATCH 335/401] make the NodeList reset a blocking queued connection --- libraries/networking/src/NodeList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 38c9d819e2..87899d59a8 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -200,7 +200,7 @@ void NodeList::processICEPingPacket(QSharedPointer packet) { void NodeList::reset() { if (thread() != QThread::currentThread()) { - QMetaObject::invokeMethod(this, "reset"); + QMetaObject::invokeMethod(this, "reset", Qt::BlockingQueuedConnection); return; } From 3bb1dedaf9990a71a55d052c12ad30e270f7a072 Mon Sep 17 00:00:00 2001 From: ericrius1 Date: Fri, 4 Dec 2015 11:41:23 -0800 Subject: [PATCH 336/401] fixed syntax error --- unpublishedScripts/hiddenEntityReset.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unpublishedScripts/hiddenEntityReset.js b/unpublishedScripts/hiddenEntityReset.js index 259cdd066c..ecbeec7a81 100644 --- a/unpublishedScripts/hiddenEntityReset.js +++ b/unpublishedScripts/hiddenEntityReset.js @@ -1367,7 +1367,7 @@ resetMe: { resetMe: true }, - grabbableKey; { + grabbableKey: { invertSolidWhileHeld: true } From 165db97cb22331e04d20ce42031003da6e6c311f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 4 Dec 2015 11:50:27 -0800 Subject: [PATCH 337/401] cleanup double reset debug on assignment-client restart --- libraries/networking/src/LimitedNodeList.cpp | 20 +++++++++++++------- libraries/networking/src/udt/Socket.cpp | 10 ++++++---- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index e717856ca2..6942ce1861 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -435,17 +435,23 @@ SharedNodePointer LimitedNodeList::nodeWithUUID(const QUuid& nodeUUID) { } void LimitedNodeList::eraseAllNodes() { - qCDebug(networking) << "Clearing the NodeList. Deleting all nodes in list."; - QSet killedNodes; - eachNode([&killedNodes](const SharedNodePointer& node){ - killedNodes.insert(node); - }); { - // iterate the current nodes, emit that they are dying and remove them from the hash + // iterate the current nodes - grab them so we can emit that they are dying + // and then remove them from the hash QWriteLocker writeLocker(&_nodeMutex); - _nodeHash.clear(); + + if (_nodeHash.size() > 0) { + qCDebug(networking) << "LimitedNodeList::eraseAllNodes() removing all nodes from NodeList."; + + auto it = _nodeHash.begin(); + + while (it != _nodeHash.end()) { + killedNodes.insert(it->second); + it = _nodeHash.unsafe_erase(it); + } + } } foreach(const SharedNodePointer& killedNode, killedNodes) { diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 6d4a834879..f1e336b431 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -194,10 +194,12 @@ void Socket::clearConnections() { QMetaObject::invokeMethod(this, "clearConnections", Qt::BlockingQueuedConnection); return; } - - // clear all of the current connections in the socket - qDebug() << "Clearing all remaining connections in Socket."; - _connectionsHash.clear(); + + if (_connectionsHash.size() > 0) { + // clear all of the current connections in the socket + qDebug() << "Clearing all remaining connections in Socket."; + _connectionsHash.clear(); + } } void Socket::cleanupConnection(HifiSockAddr sockAddr) { From 11917ca501226493a83e26257d82725b0c3dc086 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 4 Dec 2015 12:46:19 -0800 Subject: [PATCH 338/401] Fixing preview / vsync functionality --- interface/src/Application.cpp | 5 +++++ interface/src/PluginContainerProxy.cpp | 2 +- interface/src/PluginContainerProxy.h | 2 +- .../src/display-plugins/OpenGLDisplayPlugin.cpp | 13 +++---------- .../src/display-plugins/OpenGLDisplayPlugin.h | 2 +- .../display-plugins/WindowOpenGLDisplayPlugin.cpp | 2 +- libraries/gl/src/gl/GLWidget.cpp | 15 +++++++++++++++ libraries/gl/src/gl/GLWidget.h | 6 +++++- libraries/plugins/src/plugins/PluginContainer.h | 4 ++-- tests/controllers/src/main.cpp | 2 +- 10 files changed, 35 insertions(+), 18 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bbc36e8623..9e98b51442 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -620,6 +620,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : // enable mouse tracking; otherwise, we only get drag events _glWidget->setMouseTracking(true); + _glWidget->makeCurrent(); + _glWidget->initializeGL(); _offscreenContext = new OffscreenGLCanvas(); _offscreenContext->create(_glWidget->context()->contextHandle()); @@ -1194,6 +1196,9 @@ void Application::paintGL() { QSize size = getDeviceSize(); renderArgs._viewport = glm::ivec4(0, 0, size.width(), size.height()); _applicationOverlay.renderOverlay(&renderArgs); + gpu::FramebufferPointer overlayFramebuffer = _applicationOverlay.getOverlayFramebuffer(); + + } { diff --git a/interface/src/PluginContainerProxy.cpp b/interface/src/PluginContainerProxy.cpp index aae94162ad..048f079653 100644 --- a/interface/src/PluginContainerProxy.cpp +++ b/interface/src/PluginContainerProxy.cpp @@ -150,7 +150,7 @@ void PluginContainerProxy::showDisplayPluginsTools() { DependencyManager::get()->hmdTools(true); } -QGLWidget* PluginContainerProxy::getPrimaryWidget() { +GLWidget* PluginContainerProxy::getPrimaryWidget() { return qApp->_glWidget; } diff --git a/interface/src/PluginContainerProxy.h b/interface/src/PluginContainerProxy.h index 5d974f0a0c..3adc696ba9 100644 --- a/interface/src/PluginContainerProxy.h +++ b/interface/src/PluginContainerProxy.h @@ -27,7 +27,7 @@ class PluginContainerProxy : public QObject, PluginContainer { virtual bool makeRenderingContextCurrent() override; virtual void releaseSceneTexture(uint32_t texture) override; virtual void releaseOverlayTexture(uint32_t texture) override; - virtual QGLWidget* getPrimaryWidget() override; + virtual GLWidget* getPrimaryWidget() override; virtual QWindow* getPrimaryWindow() override; virtual QOpenGLContext* getPrimaryContext() override; virtual bool isForeground() override; diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 12aa37cd56..cec84c74d4 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -145,8 +146,6 @@ private: QGLContext* _context { nullptr }; }; -bool OpenGLDisplayPlugin::_vsyncSupported = false; - OpenGLDisplayPlugin::OpenGLDisplayPlugin() { _sceneTextureEscrow.setRecycler([this](GLuint texture){ cleanupForSceneTexture(texture); @@ -172,19 +171,14 @@ void OpenGLDisplayPlugin::cleanupForSceneTexture(uint32_t sceneTexture) { void OpenGLDisplayPlugin::activate() { - _timer.start(2); + _timer.start(1); + _vsyncSupported = _container->getPrimaryWidget()->isVsyncSupported(); // Start the present thread if necessary auto presentThread = DependencyManager::get(); if (!presentThread) { auto widget = _container->getPrimaryWidget(); - // TODO: write the proper code for linux -#if defined(Q_OS_WIN) - widget->makeCurrent(); - _vsyncSupported = wglewGetExtension("WGL_EXT_swap_control"); - widget->doneCurrent(); -#endif DependencyManager::set(); presentThread = DependencyManager::get(); @@ -195,7 +189,6 @@ void OpenGLDisplayPlugin::activate() { } presentThread->setNewDisplayPlugin(this); DisplayPlugin::activate(); - emit requestRender(); } void OpenGLDisplayPlugin::stop() { diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index 747d8b810b..ef78374994 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -81,7 +81,7 @@ protected: GLTextureEscrow _overlayTextureEscrow; GLTextureEscrow _sceneTextureEscrow; - static bool _vsyncSupported; + bool _vsyncSupported { false }; }; diff --git a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp index b215b19b15..c1922599a5 100644 --- a/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/WindowOpenGLDisplayPlugin.cpp @@ -7,7 +7,7 @@ // #include "WindowOpenGLDisplayPlugin.h" -#include +#include #include "plugins/PluginContainer.h" diff --git a/libraries/gl/src/gl/GLWidget.cpp b/libraries/gl/src/gl/GLWidget.cpp index 310675c01f..c67dec1e51 100644 --- a/libraries/gl/src/gl/GLWidget.cpp +++ b/libraries/gl/src/gl/GLWidget.cpp @@ -7,6 +7,7 @@ // 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 "GLWidget.h" @@ -16,11 +17,14 @@ #include #include +#include #include #include + #include "GLHelpers.h" + GLWidget::GLWidget() : QGLWidget(getDefaultGLFormat()) { #ifdef Q_OS_LINUX // Cause GLWidget::eventFilter to be called. @@ -42,6 +46,12 @@ void GLWidget::initializeGL() { setAcceptDrops(true); // Note, we *DO NOT* want Qt to automatically swap buffers for us. This results in the "ringing" bug mentioned in WL#19514 when we're throttling the framerate. setAutoBufferSwap(false); + + // TODO: write the proper code for linux + makeCurrent(); +#if defined(Q_OS_WIN) + _vsyncSupported = context()->contextHandle()->hasExtension("WGL_EXT_swap_control");; +#endif } void GLWidget::paintEvent(QPaintEvent* event) { @@ -112,3 +122,8 @@ bool GLWidget::eventFilter(QObject*, QEvent* event) { } return false; } + +bool GLWidget::isVsyncSupported() const { + return _vsyncSupported; +} + diff --git a/libraries/gl/src/gl/GLWidget.h b/libraries/gl/src/gl/GLWidget.h index df4a73ac50..5b391aa6cd 100644 --- a/libraries/gl/src/gl/GLWidget.h +++ b/libraries/gl/src/gl/GLWidget.h @@ -21,15 +21,19 @@ public: int getDeviceWidth() const; int getDeviceHeight() const; QSize getDeviceSize() const { return QSize(getDeviceWidth(), getDeviceHeight()); } + bool isVsyncSupported() const; + virtual void initializeGL() override; protected: - virtual void initializeGL() override; virtual bool event(QEvent* event) override; virtual void paintEvent(QPaintEvent* event) override; virtual void resizeEvent(QResizeEvent* event) override; private slots: virtual bool eventFilter(QObject*, QEvent* event) override; + +private: + bool _vsyncSupported { false }; }; diff --git a/libraries/plugins/src/plugins/PluginContainer.h b/libraries/plugins/src/plugins/PluginContainer.h index 6732bc02ba..19859fd98b 100644 --- a/libraries/plugins/src/plugins/PluginContainer.h +++ b/libraries/plugins/src/plugins/PluginContainer.h @@ -16,7 +16,7 @@ #include "Forward.h" class QAction; -class QGLWidget; +class GLWidget; class QScreen; class QOpenGLContext; class QWindow; @@ -41,7 +41,7 @@ public: virtual bool makeRenderingContextCurrent() = 0; virtual void releaseSceneTexture(uint32_t texture) = 0; virtual void releaseOverlayTexture(uint32_t texture) = 0; - virtual QGLWidget* getPrimaryWidget() = 0; + virtual GLWidget* getPrimaryWidget() = 0; virtual QWindow* getPrimaryWindow() = 0; virtual QOpenGLContext* getPrimaryContext() = 0; virtual bool isForeground() = 0; diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp index 8514d33d2e..fe49c2b385 100644 --- a/tests/controllers/src/main.cpp +++ b/tests/controllers/src/main.cpp @@ -94,7 +94,7 @@ public: virtual bool makeRenderingContextCurrent() override { return true; } virtual void releaseSceneTexture(uint32_t texture) override {} virtual void releaseOverlayTexture(uint32_t texture) override {} - virtual QGLWidget* getPrimaryWidget() override { return nullptr; } + virtual GLWidget* getPrimaryWidget() override { return nullptr; } virtual QWindow* getPrimaryWindow() override { return nullptr; } virtual QOpenGLContext* getPrimaryContext() override { return nullptr; } virtual bool isForeground() override { return true; } From 0d9d5375c7b2787d66820fb510a978be98a9261f Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 4 Dec 2015 13:29:18 -0800 Subject: [PATCH 339/401] remove optional WANT_COMPRESSION from OctreeQuery --- .../src/octree/OctreeQueryNode.cpp | 18 +++-------- .../src/octree/OctreeQueryNode.h | 8 ----- .../src/octree/OctreeSendThread.cpp | 32 +++++++------------ libraries/octree/src/OctreeHeadlessViewer.cpp | 1 - libraries/octree/src/OctreeQuery.cpp | 2 -- libraries/octree/src/OctreeQuery.h | 5 +-- 6 files changed, 18 insertions(+), 48 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 06e9834804..e8457c2bf1 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -33,8 +33,6 @@ OctreeQueryNode::OctreeQueryNode() : _lastTimeBagEmpty(0), _viewFrustumChanging(false), _viewFrustumJustStoppedChanging(true), - _currentPacketIsColor(true), - _currentPacketIsCompressed(false), _octreeSendThread(NULL), _lastClientBoundaryLevelAdjust(0), _lastClientOctreeSizeScale(DEFAULT_OCTREE_SIZE_SCALE), @@ -179,14 +177,9 @@ void OctreeQueryNode::resetOctreePacket() { // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. - _currentPacketIsCompressed = getWantCompression(); OCTREE_PACKET_FLAGS flags = 0; - if (_currentPacketIsColor) { - setAtBit(flags, PACKET_IS_COLOR_BIT); - } - if (_currentPacketIsCompressed) { - setAtBit(flags, PACKET_IS_COMPRESSED_BIT); - } + setAtBit(flags, PACKET_IS_COLOR_BIT); // always color + setAtBit(flags, PACKET_IS_COMPRESSED_BIT); // always compressed _octreePacket->reset(); @@ -211,10 +204,9 @@ void OctreeQueryNode::writeToPacket(const unsigned char* buffer, unsigned int by // compressed packets include lead bytes which contain compressed size, this allows packing of // multiple compressed portions together - if (_currentPacketIsCompressed) { - OCTREE_PACKET_INTERNAL_SECTION_SIZE sectionSize = bytes; - _octreePacket->writePrimitive(sectionSize); - } + OCTREE_PACKET_INTERNAL_SECTION_SIZE sectionSize = bytes; + _octreePacket->writePrimitive(sectionSize); + if (bytes <= _octreePacket->bytesAvailableForWrite()) { _octreePacket->write(reinterpret_cast(buffer), bytes); _octreePacketWaiting = true; diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 4140d42a5f..a5307b0e34 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -75,12 +75,6 @@ public: quint64 getLastTimeBagEmpty() const { return _lastTimeBagEmpty; } void setLastTimeBagEmpty() { _lastTimeBagEmpty = _sceneSendStartTime; } - bool getCurrentPacketIsColor() const { return _currentPacketIsColor; } - bool getCurrentPacketIsCompressed() const { return _currentPacketIsCompressed; } - bool getCurrentPacketFormatMatches() { - return (getCurrentPacketIsCompressed() == getWantCompression()); - } - bool hasLodChanged() const { return _lodChanged; } OctreeSceneStats stats; @@ -133,8 +127,6 @@ private: quint64 _lastTimeBagEmpty; bool _viewFrustumChanging; bool _viewFrustumJustStoppedChanging; - bool _currentPacketIsColor; - bool _currentPacketIsCompressed; OctreeSendThread* _octreeSendThread; diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index efc81d6a21..383de88d3d 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -321,22 +321,18 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // If we're starting a fresh packet, then... // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. - bool wantCompression = nodeData->getWantCompression(); // If we have a packet waiting, and our desired want color, doesn't match the current waiting packets color // then let's just send that waiting packet. - if (!nodeData->getCurrentPacketFormatMatches()) { - if (nodeData->isPacketWaiting()) { - packetsSentThisInterval += handlePacketSend(nodeData, trueBytesSent, truePacketsSent); - } else { - nodeData->resetOctreePacket(); - } - int targetSize = MAX_OCTREE_PACKET_DATA_SIZE; - if (wantCompression) { - targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); - } - _packetData.changeSettings(wantCompression, targetSize); + if (nodeData->isPacketWaiting()) { + packetsSentThisInterval += handlePacketSend(nodeData, trueBytesSent, truePacketsSent); + } else { + nodeData->resetOctreePacket(); } + int targetSize = MAX_OCTREE_PACKET_DATA_SIZE; + targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); + + _packetData.changeSettings(true, targetSize); // FIXME - eventually support only compressed packets const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL; @@ -522,8 +518,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // if for some reason the finalized size is greater than our available size, then probably the "compressed" // form actually inflated beyond our padding, and in this case we will send the current packet, then // write to out new packet... - unsigned int writtenSize = _packetData.getFinalizedSize() - + (nodeData->getCurrentPacketIsCompressed() ? sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE) : 0); + unsigned int writtenSize = _packetData.getFinalizedSize() + sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); if (writtenSize > nodeData->getAvailable()) { packetsSentThisInterval += handlePacketSend(nodeData, trueBytesSent, truePacketsSent); @@ -539,8 +534,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // the packet doesn't have enough space to bother attempting to pack more... bool sendNow = true; - if (nodeData->getCurrentPacketIsCompressed() && - nodeData->getAvailable() >= MINIMUM_ATTEMPT_MORE_PACKING && + if (nodeData->getAvailable() >= MINIMUM_ATTEMPT_MORE_PACKING && extraPackingAttempts <= REASONABLE_NUMBER_OF_PACKING_ATTEMPTS) { sendNow = false; // try to pack more } @@ -552,9 +546,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus quint64 packetSendingEnd = usecTimestampNow(); packetSendingElapsedUsec = (float)(packetSendingEnd - packetSendingStart); - if (wantCompression) { - targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); - } + targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); } else { // If we're in compressed mode, then we want to see if we have room for more in this wire packet. // but we've finalized the _packetData, so we want to start a new section, we will do that by @@ -564,7 +556,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // a larger compressed size then uncompressed size targetSize = nodeData->getAvailable() - sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE) - COMPRESS_PADDING; } - _packetData.changeSettings(nodeData->getWantCompression(), targetSize); // will do reset + _packetData.changeSettings(true, targetSize); // will do reset - NOTE: Always compressed } OctreeServer::trackTreeWaitTime(lockWaitElapsedUsec); diff --git a/libraries/octree/src/OctreeHeadlessViewer.cpp b/libraries/octree/src/OctreeHeadlessViewer.cpp index f1c2172d86..7b80d315f1 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.cpp +++ b/libraries/octree/src/OctreeHeadlessViewer.cpp @@ -52,7 +52,6 @@ void OctreeHeadlessViewer::queryOctree() { // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. _octreeQuery.setWantLowResMoving(true); _octreeQuery.setWantDelta(true); - _octreeQuery.setWantCompression(true); // TODO: should be on by default _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); _octreeQuery.setCameraOrientation(_viewFrustum.getOrientation()); diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index c431d66bf2..8449e3083a 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -42,7 +42,6 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { unsigned char bitItems = 0; if (_wantLowResMoving) { setAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); } if (_wantDelta) { setAtBit(bitItems, WANT_DELTA_AT_BIT); } - if (_wantCompression) { setAtBit(bitItems, WANT_COMPRESSION); } *destinationBuffer++ = bitItems; @@ -83,7 +82,6 @@ int OctreeQuery::parseData(NLPacket& packet) { bitItems = (unsigned char)*sourceBuffer++; _wantLowResMoving = oneAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); _wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT); - _wantCompression = oneAtBit(bitItems, WANT_COMPRESSION); // desired Max Octree PPS memcpy(&_maxQueryPPS, sourceBuffer, sizeof(_maxQueryPPS)); diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index 71c9361e68..fda1630519 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -38,7 +38,7 @@ const int WANT_LOW_RES_MOVING_BIT = 0; const int UNUSED_BIT_1 = 1; // unused... available for new feature const int WANT_DELTA_AT_BIT = 2; const int UNUSED_BIT_3 = 3; // unused... available for new feature -const int WANT_COMPRESSION = 4; // 5th bit +const int UNUSED_BIT_4 = 4; // 5th bit... unused... available for new feature class OctreeQuery : public NodeData { Q_OBJECT @@ -73,7 +73,6 @@ public: // related to Octree Sending strategies bool getWantDelta() const { return _wantDelta; } bool getWantLowResMoving() const { return _wantLowResMoving; } - bool getWantCompression() const { return _wantCompression; } int getMaxQueryPacketsPerSecond() const { return _maxQueryPPS; } float getOctreeSizeScale() const { return _octreeElementSizeScale; } int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } @@ -81,7 +80,6 @@ public: public slots: void setWantLowResMoving(bool wantLowResMoving) { _wantLowResMoving = wantLowResMoving; } void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; } - void setWantCompression(bool wantCompression) { _wantCompression = wantCompression; } void setMaxQueryPacketsPerSecond(int maxQueryPPS) { _maxQueryPPS = maxQueryPPS; } void setOctreeSizeScale(float octreeSizeScale) { _octreeElementSizeScale = octreeSizeScale; } void setBoundaryLevelAdjust(int boundaryLevelAdjust) { _boundaryLevelAdjust = boundaryLevelAdjust; } @@ -99,7 +97,6 @@ protected: // octree server sending items bool _wantDelta = true; bool _wantLowResMoving = true; - bool _wantCompression = false; int _maxQueryPPS = DEFAULT_MAX_OCTREE_PPS; float _octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE; /// used for LOD calculations int _boundaryLevelAdjust = 0; /// used for LOD calculations From f44a9daa21ca8b4980c2a3cdd961ba7db1b5a9b9 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 4 Dec 2015 13:56:39 -0800 Subject: [PATCH 340/401] remove WANT_DELTA from OctreeQuery --- assignment-client/src/octree/OctreeSendThread.cpp | 14 +++----------- interface/src/Application.cpp | 2 -- libraries/octree/src/OctreeHeadlessViewer.cpp | 1 - libraries/octree/src/OctreeQuery.cpp | 2 -- libraries/octree/src/OctreeQuery.h | 7 ------- 5 files changed, 3 insertions(+), 23 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 383de88d3d..8ba93c137e 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -309,14 +309,11 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus int truePacketsSent = 0; int trueBytesSent = 0; int packetsSentThisInterval = 0; - bool isFullScene = ((!viewFrustumChanged || !nodeData->getWantDelta()) && nodeData->getViewFrustumJustStoppedChanging()) + bool isFullScene = ((!viewFrustumChanged) && nodeData->getViewFrustumJustStoppedChanging()) || nodeData->hasLodChanged(); bool somethingToSend = true; // assume we have something - // FOR NOW... node tells us if it wants to receive only view frustum deltas - bool wantDelta = viewFrustumChanged && nodeData->getWantDelta(); - // If our packet already has content in it, then we must use the color choice of the waiting packet. // If we're starting a fresh packet, then... // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use @@ -334,7 +331,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus _packetData.changeSettings(true, targetSize); // FIXME - eventually support only compressed packets - const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL; + const ViewFrustum* lastViewFrustum = viewFrustumChanged ? &nodeData->getLastKnownViewFrustum() : NULL; // If the current view frustum has changed OR we have nothing to send, then search against // the current view frustum for things to send. @@ -347,11 +344,6 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus } } - if (!viewFrustumChanged && !nodeData->getWantDelta()) { - // only set our last sent time if we weren't resetting due to frustum change - nodeData->setLastTimeBagEmpty(); - } - // track completed scenes and send out the stats packet accordingly nodeData->stats.sceneCompleted(); nodeData->setLastRootTimestamp(_myServer->getOctree()->getRoot()->getLastChanged()); @@ -452,7 +444,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), - WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, + WANT_EXISTS_BITS, DONT_CHOP, viewFrustumChanged, lastViewFrustum, boundaryLevelAdjust, octreeSizeScale, nodeData->getLastTimeBagEmpty(), isFullScene, &nodeData->stats, _myServer->getJurisdiction(), diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c552feb51b..b6314148e9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3068,8 +3068,6 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. _octreeQuery.setWantLowResMoving(true); - _octreeQuery.setWantDelta(true); - _octreeQuery.setWantCompression(true); _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); _octreeQuery.setCameraOrientation(_viewFrustum.getOrientation()); diff --git a/libraries/octree/src/OctreeHeadlessViewer.cpp b/libraries/octree/src/OctreeHeadlessViewer.cpp index 7b80d315f1..adab2ad5f2 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.cpp +++ b/libraries/octree/src/OctreeHeadlessViewer.cpp @@ -51,7 +51,6 @@ void OctreeHeadlessViewer::queryOctree() { // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. _octreeQuery.setWantLowResMoving(true); - _octreeQuery.setWantDelta(true); _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); _octreeQuery.setCameraOrientation(_viewFrustum.getOrientation()); diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index 8449e3083a..a92818dab5 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -41,7 +41,6 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { // bitMask of less than byte wide items unsigned char bitItems = 0; if (_wantLowResMoving) { setAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); } - if (_wantDelta) { setAtBit(bitItems, WANT_DELTA_AT_BIT); } *destinationBuffer++ = bitItems; @@ -81,7 +80,6 @@ int OctreeQuery::parseData(NLPacket& packet) { unsigned char bitItems = 0; bitItems = (unsigned char)*sourceBuffer++; _wantLowResMoving = oneAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); - _wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT); // desired Max Octree PPS memcpy(&_maxQueryPPS, sourceBuffer, sizeof(_maxQueryPPS)); diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index fda1630519..38014aec01 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -35,10 +35,6 @@ typedef unsigned long long quint64; // First bitset const int WANT_LOW_RES_MOVING_BIT = 0; -const int UNUSED_BIT_1 = 1; // unused... available for new feature -const int WANT_DELTA_AT_BIT = 2; -const int UNUSED_BIT_3 = 3; // unused... available for new feature -const int UNUSED_BIT_4 = 4; // 5th bit... unused... available for new feature class OctreeQuery : public NodeData { Q_OBJECT @@ -71,7 +67,6 @@ public: void setCameraEyeOffsetPosition(const glm::vec3& eyeOffsetPosition) { _cameraEyeOffsetPosition = eyeOffsetPosition; } // related to Octree Sending strategies - bool getWantDelta() const { return _wantDelta; } bool getWantLowResMoving() const { return _wantLowResMoving; } int getMaxQueryPacketsPerSecond() const { return _maxQueryPPS; } float getOctreeSizeScale() const { return _octreeElementSizeScale; } @@ -79,7 +74,6 @@ public: public slots: void setWantLowResMoving(bool wantLowResMoving) { _wantLowResMoving = wantLowResMoving; } - void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; } void setMaxQueryPacketsPerSecond(int maxQueryPPS) { _maxQueryPPS = maxQueryPPS; } void setOctreeSizeScale(float octreeSizeScale) { _octreeElementSizeScale = octreeSizeScale; } void setBoundaryLevelAdjust(int boundaryLevelAdjust) { _boundaryLevelAdjust = boundaryLevelAdjust; } @@ -95,7 +89,6 @@ protected: glm::vec3 _cameraEyeOffsetPosition = glm::vec3(0.0f); // octree server sending items - bool _wantDelta = true; bool _wantLowResMoving = true; int _maxQueryPPS = DEFAULT_MAX_OCTREE_PPS; float _octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE; /// used for LOD calculations From ad4f818b21d41ef51e502853480739749afa9490 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 4 Dec 2015 14:12:41 -0800 Subject: [PATCH 341/401] only attempt to stop QTimer if active --- libraries/networking/src/NodeList.cpp | 8 +++++++- libraries/networking/src/NodeList.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 8748db50d7..253058ae89 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -94,7 +94,7 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned _keepAlivePingTimer.setInterval(KEEPALIVE_PING_INTERVAL_MS); connect(&_keepAlivePingTimer, &QTimer::timeout, this, &NodeList::sendKeepAlivePings); connect(&_domainHandler, SIGNAL(connectedToDomain(QString)), &_keepAlivePingTimer, SLOT(start())); - connect(&_domainHandler, &DomainHandler::disconnectedFromDomain, &_keepAlivePingTimer, &QTimer::stop); + connect(&_domainHandler, &DomainHandler::disconnectedFromDomain, this, &NodeList::stopKeepalivePingTimer); // we definitely want STUN to update our public socket, so call the LNL to kick that off startSTUNPublicSocketUpdate(); @@ -646,6 +646,12 @@ void NodeList::activateSocketFromNodeCommunication(QSharedPointer pack } } +void NodeList::stopKeepalivePingTimer() { + if (_keepAlivePingTimer.isActive()) { + _keepAlivePingTimer.stop(); + } +} + void NodeList::sendKeepAlivePings() { eachMatchingNode([this](const SharedNodePointer& node)->bool { return _nodeTypesOfInterest.contains(node->getType()); diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 02f49d2918..4d787bac6d 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -89,6 +89,7 @@ public slots: signals: void limitOfSilentDomainCheckInsReached(); private slots: + void stopKeepalivePingTimer(); void sendPendingDSPathQuery(); void handleICEConnectionToDomainServer(); From 46946212cf6c7195c8f57d7cec9bf9e6693ab8f8 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 4 Dec 2015 14:24:31 -0800 Subject: [PATCH 342/401] remove WANT_LOW_RES_MOVING_BIT from OctreeQuery always true --- assignment-client/src/octree/OctreeSendThread.cpp | 4 ++-- interface/src/Application.cpp | 3 --- libraries/octree/src/OctreeHeadlessViewer.cpp | 3 --- libraries/octree/src/OctreeQuery.cpp | 8 ++++++-- libraries/octree/src/OctreeQuery.h | 3 --- 5 files changed, 8 insertions(+), 13 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 8ba93c137e..9b664572c1 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -440,8 +440,8 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus float octreeSizeScale = nodeData->getOctreeSizeScale(); int boundaryLevelAdjustClient = nodeData->getBoundaryLevelAdjust(); - int boundaryLevelAdjust = boundaryLevelAdjustClient + (viewFrustumChanged && nodeData->getWantLowResMoving() - ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); + int boundaryLevelAdjust = boundaryLevelAdjustClient + + (viewFrustumChanged ? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST); EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), WANT_EXISTS_BITS, DONT_CHOP, viewFrustumChanged, lastViewFrustum, diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b6314148e9..ca95b8f36d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3066,9 +3066,6 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node //qCDebug(interfaceapp) << ">>> inside... queryOctree()... _viewFrustum.getFieldOfView()=" << _viewFrustum.getFieldOfView(); bool wantExtraDebugging = getLogger()->extraDebugging(); - // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. - _octreeQuery.setWantLowResMoving(true); - _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); _octreeQuery.setCameraOrientation(_viewFrustum.getOrientation()); _octreeQuery.setCameraFov(_viewFrustum.getFieldOfView()); diff --git a/libraries/octree/src/OctreeHeadlessViewer.cpp b/libraries/octree/src/OctreeHeadlessViewer.cpp index adab2ad5f2..1d00e88d9e 100644 --- a/libraries/octree/src/OctreeHeadlessViewer.cpp +++ b/libraries/octree/src/OctreeHeadlessViewer.cpp @@ -49,9 +49,6 @@ void OctreeHeadlessViewer::queryOctree() { qCDebug(octree) << "---------------"; } - // These will be the same for all servers, so we can set them up once and then reuse for each server we send to. - _octreeQuery.setWantLowResMoving(true); - _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); _octreeQuery.setCameraOrientation(_viewFrustum.getOrientation()); _octreeQuery.setCameraFov(_viewFrustum.getFieldOfView()); diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index a92818dab5..0288d19b80 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -40,7 +40,9 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { // bitMask of less than byte wide items unsigned char bitItems = 0; - if (_wantLowResMoving) { setAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); } + // NOTE: we used to use these bits to set feature request items + // if we need to extend the protocol with optional features + // do it here with... setAtBit(bitItems, WANT_FEATURE_BIT); *destinationBuffer++ = bitItems; @@ -79,7 +81,9 @@ int OctreeQuery::parseData(NLPacket& packet) { // voxel sending features... unsigned char bitItems = 0; bitItems = (unsigned char)*sourceBuffer++; - _wantLowResMoving = oneAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); + + // NOTE: we used to use these bits to set feature request items if we need to extend the protocol with optional features + // do it here with... wantFeature= oneAtBit(bitItems, WANT_FEATURE_BIT); // desired Max Octree PPS memcpy(&_maxQueryPPS, sourceBuffer, sizeof(_maxQueryPPS)); diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index 38014aec01..8c72983a7f 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -67,13 +67,11 @@ public: void setCameraEyeOffsetPosition(const glm::vec3& eyeOffsetPosition) { _cameraEyeOffsetPosition = eyeOffsetPosition; } // related to Octree Sending strategies - bool getWantLowResMoving() const { return _wantLowResMoving; } int getMaxQueryPacketsPerSecond() const { return _maxQueryPPS; } float getOctreeSizeScale() const { return _octreeElementSizeScale; } int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } public slots: - void setWantLowResMoving(bool wantLowResMoving) { _wantLowResMoving = wantLowResMoving; } void setMaxQueryPacketsPerSecond(int maxQueryPPS) { _maxQueryPPS = maxQueryPPS; } void setOctreeSizeScale(float octreeSizeScale) { _octreeElementSizeScale = octreeSizeScale; } void setBoundaryLevelAdjust(int boundaryLevelAdjust) { _boundaryLevelAdjust = boundaryLevelAdjust; } @@ -89,7 +87,6 @@ protected: glm::vec3 _cameraEyeOffsetPosition = glm::vec3(0.0f); // octree server sending items - bool _wantLowResMoving = true; int _maxQueryPPS = DEFAULT_MAX_OCTREE_PPS; float _octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE; /// used for LOD calculations int _boundaryLevelAdjust = 0; /// used for LOD calculations From 7faf9c2f22ff285163b9b1ab5fbf487fceb07e75 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 4 Dec 2015 14:33:45 -0800 Subject: [PATCH 343/401] bump protocol version --- libraries/networking/src/udt/PacketHeaders.cpp | 3 ++- libraries/networking/src/udt/PacketHeaders.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 93fbe7acdc..158cf15584 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -38,10 +38,11 @@ const QSet RELIABLE_PACKETS = QSet(); PacketVersion versionForPacketType(PacketType packetType) { switch (packetType) { + case PacketType::EntityQuery: case PacketType::EntityAdd: case PacketType::EntityEdit: case PacketType::EntityData: - return VERSION_ENTITIES_HAVE_PARENTS; + return VERSION_ENTITIES_DEFAULT_QUERY_BITS; case PacketType::AvatarData: case PacketType::BulkAvatarData: return 17; diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index cd7b9a113c..a9f89417c0 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -161,5 +161,6 @@ const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP_BIS = 48; const PacketVersion VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING = 49; const PacketVersion VERSION_ENTITIES_POLYLINE_TEXTURE = 50; const PacketVersion VERSION_ENTITIES_HAVE_PARENTS = 51; +const PacketVersion VERSION_ENTITIES_DEFAULT_QUERY_BITS = 52; #endif // hifi_PacketHeaders_h From be4bc7b2caf7ec35002ec4b20185194d83c8868e Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 4 Dec 2015 14:55:16 -0800 Subject: [PATCH 344/401] going a different way, same packet version, but always send feature requests to old servers --- libraries/networking/src/udt/PacketHeaders.cpp | 3 +-- libraries/networking/src/udt/PacketHeaders.h | 1 - libraries/octree/src/OctreeQuery.cpp | 12 +++++++++--- libraries/octree/src/OctreeQuery.h | 4 ++++ 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 158cf15584..93fbe7acdc 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -38,11 +38,10 @@ const QSet RELIABLE_PACKETS = QSet(); PacketVersion versionForPacketType(PacketType packetType) { switch (packetType) { - case PacketType::EntityQuery: case PacketType::EntityAdd: case PacketType::EntityEdit: case PacketType::EntityData: - return VERSION_ENTITIES_DEFAULT_QUERY_BITS; + return VERSION_ENTITIES_HAVE_PARENTS; case PacketType::AvatarData: case PacketType::BulkAvatarData: return 17; diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index a9f89417c0..cd7b9a113c 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -161,6 +161,5 @@ const PacketVersion VERSION_ENTITIES_KEYLIGHT_PROPERTIES_GROUP_BIS = 48; const PacketVersion VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING = 49; const PacketVersion VERSION_ENTITIES_POLYLINE_TEXTURE = 50; const PacketVersion VERSION_ENTITIES_HAVE_PARENTS = 51; -const PacketVersion VERSION_ENTITIES_DEFAULT_QUERY_BITS = 52; #endif // hifi_PacketHeaders_h diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index 0288d19b80..0a25b87d83 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -40,9 +40,15 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) { // bitMask of less than byte wide items unsigned char bitItems = 0; - // NOTE: we used to use these bits to set feature request items - // if we need to extend the protocol with optional features - // do it here with... setAtBit(bitItems, WANT_FEATURE_BIT); + + // NOTE: we need to keep these here for new clients to talk to old servers. After we know that the clients and + // servers and clients have all been updated we could remove these bits. New servers will always force these + // features on old clients even if they don't ask for them. (which old clients will properly handle). New clients + // will always ask for these so that old servers will use these features. + setAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); + setAtBit(bitItems, WANT_COLOR_AT_BIT); + setAtBit(bitItems, WANT_DELTA_AT_BIT); + setAtBit(bitItems, WANT_COMPRESSION); *destinationBuffer++ = bitItems; diff --git a/libraries/octree/src/OctreeQuery.h b/libraries/octree/src/OctreeQuery.h index 8c72983a7f..8362cff396 100644 --- a/libraries/octree/src/OctreeQuery.h +++ b/libraries/octree/src/OctreeQuery.h @@ -35,6 +35,10 @@ typedef unsigned long long quint64; // First bitset const int WANT_LOW_RES_MOVING_BIT = 0; +const int WANT_COLOR_AT_BIT = 1; +const int WANT_DELTA_AT_BIT = 2; +const int UNUSED_BIT_3 = 3; // unused... available for new feature +const int WANT_COMPRESSION = 4; // 5th bit class OctreeQuery : public NodeData { Q_OBJECT From 0a9b42ad3c588616bd4c3987c3ff13bb1248524f Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Fri, 4 Dec 2015 15:10:46 -0800 Subject: [PATCH 345/401] Fix present rate stats display, which was counting (roughly) twice for 2D display, and flickering. --- interface/src/ui/Stats.cpp | 2 +- .../display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 358dc49bdb..55751d8631 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -121,7 +121,7 @@ void Stats::updateStats(bool force) { STAT_UPDATE(serverCount, nodeList->size()); STAT_UPDATE(renderrate, (int)qApp->getFps()); if (qApp->getActiveDisplayPlugin()) { - STAT_UPDATE(presentrate, (int)qApp->getActiveDisplayPlugin()->presentRate()); + STAT_UPDATE(presentrate, (int)round(qApp->getActiveDisplayPlugin()->presentRate())); } else { STAT_UPDATE(presentrate, -1); } diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index cec84c74d4..8593da1573 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -303,7 +303,6 @@ void OpenGLDisplayPlugin::internalPresent() { glBindTexture(GL_TEXTURE_2D, _currentSceneTexture); drawUnitQuad(); swapBuffers(); - updateFramerate(); } void OpenGLDisplayPlugin::present() { From ba001ef4b0fc44faf1c5d328cf16c40eff050220 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 4 Dec 2015 15:15:18 -0800 Subject: [PATCH 346/401] Rig: split Poses into internal and external sets. In preparation for making some accessors thread safe. --- libraries/animation/src/Rig.cpp | 120 +++++++++++++++++--------------- libraries/animation/src/Rig.h | 21 ++++-- 2 files changed, 81 insertions(+), 60 deletions(-) diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index c0b399ee0f..5ad000a62c 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include @@ -158,10 +160,10 @@ void Rig::destroyAnimGraph() { _animSkeleton.reset(); _animLoader.reset(); _animNode.reset(); - _relativePoses.clear(); - _absolutePoses.clear(); - _overridePoses.clear(); - _overrideFlags.clear(); + _internalPoseSet._relativePoses.clear(); + _internalPoseSet._absolutePoses.clear(); + _internalPoseSet._overridePoses.clear(); + _internalPoseSet._overrideFlags.clear(); } void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOffset) { @@ -173,16 +175,16 @@ void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOff computeEyesInRootFrame(_animSkeleton->getRelativeDefaultPoses()); - _relativePoses.clear(); - _relativePoses = _animSkeleton->getRelativeDefaultPoses(); + _internalPoseSet._relativePoses.clear(); + _internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses(); - buildAbsoluteRigPoses(_relativePoses, _absolutePoses); + buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses); - _overridePoses.clear(); - _overridePoses = _animSkeleton->getRelativeDefaultPoses(); + _internalPoseSet._overridePoses.clear(); + _internalPoseSet._overridePoses = _animSkeleton->getRelativeDefaultPoses(); - _overrideFlags.clear(); - _overrideFlags.resize(_animSkeleton->getNumJoints(), false); + _internalPoseSet._overrideFlags.clear(); + _internalPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints(), false); buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses); @@ -201,16 +203,16 @@ void Rig::reset(const FBXGeometry& geometry) { computeEyesInRootFrame(_animSkeleton->getRelativeDefaultPoses()); - _relativePoses.clear(); - _relativePoses = _animSkeleton->getRelativeDefaultPoses(); + _internalPoseSet._relativePoses.clear(); + _internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses(); - buildAbsoluteRigPoses(_relativePoses, _absolutePoses); + buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses); - _overridePoses.clear(); - _overridePoses = _animSkeleton->getRelativeDefaultPoses(); + _internalPoseSet._overridePoses.clear(); + _internalPoseSet._overridePoses = _animSkeleton->getRelativeDefaultPoses(); - _overrideFlags.clear(); - _overrideFlags.resize(_animSkeleton->getNumJoints(), false); + _internalPoseSet._overrideFlags.clear(); + _internalPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints(), false); buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses); @@ -228,11 +230,11 @@ void Rig::reset(const FBXGeometry& geometry) { } bool Rig::jointStatesEmpty() { - return _relativePoses.empty(); + return _internalPoseSet._relativePoses.empty(); } int Rig::getJointStateCount() const { - return _relativePoses.size(); + return _internalPoseSet._relativePoses.size(); } int Rig::indexOfJoint(const QString& jointName) const { @@ -262,7 +264,7 @@ void Rig::setModelOffset(const glm::mat4& modelOffsetMat) { bool Rig::getJointStateRotation(int index, glm::quat& rotation) const { if (isIndexValid(index)) { - rotation = _relativePoses[index].rot; + rotation = _internalPoseSet._relativePoses[index].rot; return !isEqual(rotation, _animSkeleton->getRelativeDefaultPose(index).rot); } else { return false; @@ -271,7 +273,7 @@ bool Rig::getJointStateRotation(int index, glm::quat& rotation) const { bool Rig::getJointStateTranslation(int index, glm::vec3& translation) const { if (isIndexValid(index)) { - translation = _relativePoses[index].trans; + translation = _internalPoseSet._relativePoses[index].trans; return !isEqual(translation, _animSkeleton->getRelativeDefaultPose(index).trans); } else { return false; @@ -280,46 +282,46 @@ bool Rig::getJointStateTranslation(int index, glm::vec3& translation) const { void Rig::clearJointState(int index) { if (isIndexValid(index)) { - _overrideFlags[index] = false; + _internalPoseSet._overrideFlags[index] = false; } } void Rig::clearJointStates() { - _overrideFlags.clear(); - _overrideFlags.resize(_animSkeleton->getNumJoints()); + _internalPoseSet._overrideFlags.clear(); + _internalPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints()); } void Rig::clearJointAnimationPriority(int index) { if (isIndexValid(index)) { - _overrideFlags[index] = false; + _internalPoseSet._overrideFlags[index] = false; } } void Rig::setJointTranslation(int index, bool valid, const glm::vec3& translation, float priority) { if (isIndexValid(index)) { if (valid) { - assert(_overrideFlags.size() == _overridePoses.size()); - _overrideFlags[index] = true; - _overridePoses[index].trans = translation; + assert(_overrideFlags.size() == _internalPoseSet._overridePoses.size()); + _internalPoseSet._overrideFlags[index] = true; + _internalPoseSet._overridePoses[index].trans = translation; } } } void Rig::setJointState(int index, bool valid, const glm::quat& rotation, const glm::vec3& translation, float priority) { if (isIndexValid(index)) { - assert(_overrideFlags.size() == _overridePoses.size()); - _overrideFlags[index] = true; - _overridePoses[index].rot = rotation; - _overridePoses[index].trans = translation; + assert(_internalPoseSet._overrideFlags.size() == _internalPoseSet._overridePoses.size()); + _internalPoseSet._overrideFlags[index] = true; + _internalPoseSet._overridePoses[index].rot = rotation; + _internalPoseSet._overridePoses[index].trans = translation; } } void Rig::setJointRotation(int index, bool valid, const glm::quat& rotation, float priority) { if (isIndexValid(index)) { if (valid) { - ASSERT(_overrideFlags.size() == _overridePoses.size()); - _overrideFlags[index] = true; - _overridePoses[index].rot = rotation; + ASSERT(_internalPoseSet._overrideFlags.size() == _internalPoseSet._overridePoses.size()); + _internalPoseSet._overrideFlags[index] = true; + _internalPoseSet._overridePoses[index].rot = rotation; } } } @@ -336,7 +338,7 @@ void Rig::restoreJointTranslation(int index, float fraction, float priority) { bool Rig::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position, glm::vec3 translation, glm::quat rotation) const { if (isIndexValid(jointIndex)) { - position = (rotation * _absolutePoses[jointIndex].trans) + translation; + position = (rotation * _internalPoseSet._absolutePoses[jointIndex].trans) + translation; return true; } else { return false; @@ -345,7 +347,7 @@ bool Rig::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position, glm: bool Rig::getJointPosition(int jointIndex, glm::vec3& position) const { if (isIndexValid(jointIndex)) { - position = _absolutePoses[jointIndex].trans; + position = _internalPoseSet._absolutePoses[jointIndex].trans; return true; } else { return false; @@ -354,7 +356,7 @@ bool Rig::getJointPosition(int jointIndex, glm::vec3& position) const { bool Rig::getJointRotationInWorldFrame(int jointIndex, glm::quat& result, const glm::quat& rotation) const { if (isIndexValid(jointIndex)) { - result = rotation * _absolutePoses[jointIndex].rot; + result = rotation * _internalPoseSet._absolutePoses[jointIndex].rot; return true; } else { return false; @@ -363,7 +365,7 @@ bool Rig::getJointRotationInWorldFrame(int jointIndex, glm::quat& result, const bool Rig::getJointRotation(int jointIndex, glm::quat& rotation) const { if (isIndexValid(jointIndex)) { - rotation = _relativePoses[jointIndex].rot; + rotation = _internalPoseSet._relativePoses[jointIndex].rot; return true; } else { return false; @@ -372,7 +374,7 @@ bool Rig::getJointRotation(int jointIndex, glm::quat& rotation) const { bool Rig::getJointTranslation(int jointIndex, glm::vec3& translation) const { if (isIndexValid(jointIndex)) { - translation = _relativePoses[jointIndex].trans; + translation = _internalPoseSet._relativePoses[jointIndex].trans; return true; } else { return false; @@ -708,21 +710,27 @@ void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) { // evaluate the animation AnimNode::Triggers triggersOut; - _relativePoses = _animNode->evaluate(_animVars, deltaTime, triggersOut); - if ((int)_relativePoses.size() != _animSkeleton->getNumJoints()) { + _internalPoseSet._relativePoses = _animNode->evaluate(_animVars, deltaTime, triggersOut); + if ((int)_internalPoseSet._relativePoses.size() != _animSkeleton->getNumJoints()) { // animations haven't fully loaded yet. - _relativePoses = _animSkeleton->getRelativeDefaultPoses(); + _internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses(); } _animVars.clearTriggers(); for (auto& trigger : triggersOut) { _animVars.setTrigger(trigger); } - computeEyesInRootFrame(_relativePoses); + computeEyesInRootFrame(_internalPoseSet._relativePoses); } applyOverridePoses(); - buildAbsoluteRigPoses(_relativePoses, _absolutePoses); + buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses); + + // copy internal poses to external poses + { + QWriteLocker writeLock(&_externalPoseSetLock); + _externalPoseSet = _internalPoseSet; + } } void Rig::inverseKinematics(int endIndex, glm::vec3 targetPosition, const glm::quat& targetRotation, float priority, @@ -884,7 +892,7 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm if (isIndexValid(index)) { glm::mat4 rigToWorld = createMatFromQuatAndPos(modelRotation, modelTranslation); glm::mat4 worldToRig = glm::inverse(rigToWorld); - glm::vec3 zAxis = glm::normalize(_absolutePoses[index].trans - transformPoint(worldToRig, lookAtSpot)); + glm::vec3 zAxis = glm::normalize(_internalPoseSet._absolutePoses[index].trans - transformPoint(worldToRig, lookAtSpot)); glm::quat q = rotationBetween(IDENTITY_FRONT, zAxis); // limit rotation @@ -892,7 +900,7 @@ void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm q = glm::angleAxis(glm::clamp(glm::angle(q), -MAX_ANGLE, MAX_ANGLE), glm::axis(q)); // directly set absolutePose rotation - _absolutePoses[index].rot = q; + _internalPoseSet._absolutePoses[index].rot = q; } } @@ -989,13 +997,13 @@ void Rig::applyOverridePoses() { return; } - ASSERT(_animSkeleton->getNumJoints() == (int)_relativePoses.size()); - ASSERT(_animSkeleton->getNumJoints() == (int)_overrideFlags.size()); - ASSERT(_animSkeleton->getNumJoints() == (int)_overridePoses.size()); + ASSERT(_animSkeleton->getNumJoints() == (int)_internalPoseSet._relativePoses.size()); + ASSERT(_animSkeleton->getNumJoints() == (int)_internalPoseSet._overrideFlags.size()); + ASSERT(_animSkeleton->getNumJoints() == (int)_internalPoseSet._overridePoses.size()); - for (size_t i = 0; i < _overrideFlags.size(); i++) { - if (_overrideFlags[i]) { - _relativePoses[i] = _overridePoses[i]; + for (size_t i = 0; i < _internalPoseSet._overrideFlags.size(); i++) { + if (_internalPoseSet._overrideFlags[i]) { + _internalPoseSet._relativePoses[i] = _internalPoseSet._overridePoses[i]; } } } @@ -1020,14 +1028,14 @@ void Rig::buildAbsoluteRigPoses(const AnimPoseVec& relativePoses, AnimPoseVec& a // transform all absolute poses into rig space. AnimPose geometryToRigTransform(_geometryToRigTransform); - for (int i = 0; i < (int)_absolutePoses.size(); i++) { + for (int i = 0; i < (int)absolutePosesOut.size(); i++) { absolutePosesOut[i] = geometryToRigTransform * absolutePosesOut[i]; } } glm::mat4 Rig::getJointTransform(int jointIndex) const { if (isIndexValid(jointIndex)) { - return _absolutePoses[jointIndex]; + return _internalPoseSet._absolutePoses[jointIndex]; } else { return glm::mat4(); } diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 8d1d768c18..3d8b0f3bc7 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -19,6 +19,7 @@ #include #include #include +#include #include "AnimNode.h" #include "AnimNodeLoader.h" @@ -27,6 +28,9 @@ class Rig; typedef std::shared_ptr RigPointer; +// Rig instances are reentrant. +// However only specific methods thread-safe. Noted below. + class Rig : public QObject, public std::enable_shared_from_this { public: struct StateHandler { @@ -217,10 +221,19 @@ public: AnimPose _modelOffset; // model to rig space AnimPose _geometryOffset; // geometry to model space (includes unit offset & fst offsets) - AnimPoseVec _relativePoses; // geometry space relative to parent. - AnimPoseVec _absolutePoses; // rig space, not relative to parent. - AnimPoseVec _overridePoses; // geometry space relative to parent. - std::vector _overrideFlags; + struct PoseSet { + AnimPoseVec _relativePoses; // geometry space relative to parent. + AnimPoseVec _absolutePoses; // rig space, not relative to parent. + AnimPoseVec _overridePoses; // geometry space relative to parent. + std::vector _overrideFlags; + }; + + // Only accessed by the main thread + PoseSet _internalPoseSet; + + // Copy of the _poseSet for external threads. + PoseSet _externalPoseSet; + mutable QReadWriteLock _externalPoseSetLock; AnimPoseVec _absoluteDefaultPoses; // rig space, not relative to parent. From 1eb5b21e48b52324b6ca61b4e950ac09a0f48dc9 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Fri, 4 Dec 2015 15:17:16 -0800 Subject: [PATCH 347/401] fix warning --- libraries/octree/src/OctreeQuery.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/octree/src/OctreeQuery.cpp b/libraries/octree/src/OctreeQuery.cpp index 0a25b87d83..543e6ee2fd 100644 --- a/libraries/octree/src/OctreeQuery.cpp +++ b/libraries/octree/src/OctreeQuery.cpp @@ -84,12 +84,13 @@ int OctreeQuery::parseData(NLPacket& packet) { memcpy(&_cameraEyeOffsetPosition, sourceBuffer, sizeof(_cameraEyeOffsetPosition)); sourceBuffer += sizeof(_cameraEyeOffsetPosition); - // voxel sending features... + // optional feature flags unsigned char bitItems = 0; bitItems = (unsigned char)*sourceBuffer++; // NOTE: we used to use these bits to set feature request items if we need to extend the protocol with optional features // do it here with... wantFeature= oneAtBit(bitItems, WANT_FEATURE_BIT); + Q_UNUSED(bitItems); // desired Max Octree PPS memcpy(&_maxQueryPPS, sourceBuffer, sizeof(_maxQueryPPS)); From 817f0307a040567b82ec783559b719262658fbaf Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 4 Dec 2015 15:51:19 -0800 Subject: [PATCH 348/401] fix 3d line overlays --- interface/src/ui/overlays/Line3DOverlay.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/ui/overlays/Line3DOverlay.cpp b/interface/src/ui/overlays/Line3DOverlay.cpp index 0acd7ecc1e..9dc609af31 100644 --- a/interface/src/ui/overlays/Line3DOverlay.cpp +++ b/interface/src/ui/overlays/Line3DOverlay.cpp @@ -12,6 +12,7 @@ #include #include +#include QString const Line3DOverlay::TYPE = "line3d"; @@ -53,6 +54,7 @@ void Line3DOverlay::render(RenderArgs* args) { auto batch = args->_batch; if (batch) { batch->setModelTransform(_transform); + DependencyManager::get()->bindSimpleProgram(*batch); if (getIsDashedLine()) { // TODO: add support for color to renderDashedLine() From 7abfc93ff964cc57db629c1549c5971784b4adf4 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Fri, 4 Dec 2015 16:16:17 -0800 Subject: [PATCH 349/401] Avatar::getJointRotation and getJointTranslation is thread-safe It can be called from script with minimal blocking, because it inspects a copy of the joint values from the Rig, which is updated atomically. This copy occurs in Rig::updateAnimations() --- interface/src/avatar/Avatar.cpp | 6 ------ libraries/animation/src/Rig.cpp | 12 +++++++----- libraries/animation/src/Rig.h | 4 ++-- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 0fecb3a761..2c8d970336 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -857,18 +857,12 @@ QVector Avatar::getJointRotations() const { } glm::quat Avatar::getJointRotation(int index) const { - if (QThread::currentThread() != thread()) { - return AvatarData::getJointRotation(index); - } glm::quat rotation; _skeletonModel.getJointRotation(index, rotation); return rotation; } glm::vec3 Avatar::getJointTranslation(int index) const { - if (QThread::currentThread() != thread()) { - return AvatarData::getJointTranslation(index); - } glm::vec3 translation; _skeletonModel.getJointTranslation(index, translation); return translation; diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 5ad000a62c..8fb56ed699 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -300,7 +300,7 @@ void Rig::clearJointAnimationPriority(int index) { void Rig::setJointTranslation(int index, bool valid, const glm::vec3& translation, float priority) { if (isIndexValid(index)) { if (valid) { - assert(_overrideFlags.size() == _internalPoseSet._overridePoses.size()); + assert(_internalPoseSet._overrideFlags.size() == _internalPoseSet._overridePoses.size()); _internalPoseSet._overrideFlags[index] = true; _internalPoseSet._overridePoses[index].trans = translation; } @@ -364,8 +364,9 @@ bool Rig::getJointRotationInWorldFrame(int jointIndex, glm::quat& result, const } bool Rig::getJointRotation(int jointIndex, glm::quat& rotation) const { - if (isIndexValid(jointIndex)) { - rotation = _internalPoseSet._relativePoses[jointIndex].rot; + QReadLocker readLock(&_externalPoseSetLock); + if (jointIndex >= 0 && jointIndex < (int)_externalPoseSet._relativePoses.size()) { + rotation = _externalPoseSet._relativePoses[jointIndex].rot; return true; } else { return false; @@ -373,8 +374,9 @@ bool Rig::getJointRotation(int jointIndex, glm::quat& rotation) const { } bool Rig::getJointTranslation(int jointIndex, glm::vec3& translation) const { - if (isIndexValid(jointIndex)) { - translation = _internalPoseSet._relativePoses[jointIndex].trans; + QReadLocker readLock(&_externalPoseSetLock); + if (jointIndex >= 0 && jointIndex < (int)_externalPoseSet._relativePoses.size()) { + translation = _externalPoseSet._relativePoses[jointIndex].trans; return true; } else { return false; diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 3d8b0f3bc7..64ce8c52ef 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -127,10 +127,10 @@ public: // if rotation is identity, result will be in rig space bool getJointRotationInWorldFrame(int jointIndex, glm::quat& result, const glm::quat& rotation) const; - // geometry space + // geometry space (thread-safe) bool getJointRotation(int jointIndex, glm::quat& rotation) const; - // geometry space + // geometry space (thread-safe) bool getJointTranslation(int jointIndex, glm::vec3& translation) const; // legacy From 62b4eac875fa5e76487965ab828e32dec02dfb61 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 4 Dec 2015 16:41:56 -0800 Subject: [PATCH 350/401] fix avatar-mixer parents-related crash --- assignment-client/src/avatars/AvatarMixerClientData.cpp | 8 ++++---- assignment-client/src/avatars/AvatarMixerClientData.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixerClientData.cpp b/assignment-client/src/avatars/AvatarMixerClientData.cpp index 9d78d92463..96df98fdd0 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.cpp +++ b/assignment-client/src/avatars/AvatarMixerClientData.cpp @@ -18,7 +18,7 @@ int AvatarMixerClientData::parseData(NLPacket& packet) { packet.readPrimitive(&_lastReceivedSequenceNumber); // compute the offset to the data payload - return _avatar.parseDataFromBuffer(packet.readWithoutCopy(packet.bytesLeftToRead())); + return _avatar->parseDataFromBuffer(packet.readWithoutCopy(packet.bytesLeftToRead())); } bool AvatarMixerClientData::checkAndSetHasReceivedFirstPacketsFrom(const QUuid& uuid) { @@ -40,7 +40,7 @@ uint16_t AvatarMixerClientData::getLastBroadcastSequenceNumber(const QUuid& node } void AvatarMixerClientData::loadJSONStats(QJsonObject& jsonObject) const { - jsonObject["display_name"] = _avatar.getDisplayName(); + jsonObject["display_name"] = _avatar->getDisplayName(); jsonObject["full_rate_distance"] = _fullRateDistance; jsonObject["max_av_distance"] = _maxAvatarDistance; jsonObject["num_avs_sent_last_frame"] = _numAvatarsSentLastFrame; @@ -49,7 +49,7 @@ void AvatarMixerClientData::loadJSONStats(QJsonObject& jsonObject) const { jsonObject["total_num_out_of_order_sends"] = _numOutOfOrderSends; jsonObject[OUTBOUND_AVATAR_DATA_STATS_KEY] = getOutboundAvatarDataKbps(); - jsonObject[INBOUND_AVATAR_DATA_STATS_KEY] = _avatar.getAverageBytesReceivedPerSecond() / (float) BYTES_PER_KILOBIT; + jsonObject[INBOUND_AVATAR_DATA_STATS_KEY] = _avatar->getAverageBytesReceivedPerSecond() / (float) BYTES_PER_KILOBIT; - jsonObject["av_data_receive_rate"] = _avatar.getReceiveRate(); + jsonObject["av_data_receive_rate"] = _avatar->getReceiveRate(); } diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index 1f5e8fa77a..09100010e0 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -34,7 +34,7 @@ class AvatarMixerClientData : public NodeData { Q_OBJECT public: int parseData(NLPacket& packet); - AvatarData& getAvatar() { return _avatar; } + AvatarData& getAvatar() { return *_avatar; } bool checkAndSetHasReceivedFirstPacketsFrom(const QUuid& uuid); @@ -80,7 +80,7 @@ public: void loadJSONStats(QJsonObject& jsonObject) const; private: - AvatarData _avatar; + AvatarSharedPointer _avatar { new AvatarData() }; uint16_t _lastReceivedSequenceNumber { 0 }; std::unordered_map _lastBroadcastSequenceNumbers; From 560b9f012fecf6069e0e6c0e4392079881fd0bf0 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 5 Dec 2015 16:25:28 +1300 Subject: [PATCH 351/401] Get hand positioning and orientation working again --- examples/controllers/leap/leapHands.js | 49 ++++++++++++++++---------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/examples/controllers/leap/leapHands.js b/examples/controllers/leap/leapHands.js index bd8765e376..424ab81948 100644 --- a/examples/controllers/leap/leapHands.js +++ b/examples/controllers/leap/leapHands.js @@ -40,7 +40,13 @@ var leapHands = (function () { avatarScale, avatarFaceModelURL, avatarSkeletonModelURL, - settingsTimer; + settingsTimer, + HMD_CAMERA_TO_AVATAR_ROTATION = [ + Quat.angleAxis(180.0, { x: 0, y: 0, z: 1 }), + Quat.angleAxis(-180.0, { x: 0, y: 0, z: 1 }) + ], + DESKTOP_CAMERA_TO_AVATAR_ROTATION = + Quat.multiply(Quat.angleAxis(180.0, { x: 0, y: 1, z: 0 }), Quat.angleAxis(90.0, { x: 0, y: 0, z: 1 })); function printSkeletonJointNames() { var jointNames, @@ -394,37 +400,41 @@ var leapHands = (function () { // Hand offset in camera coordinates ... handOffset = { - x: hands[h].zeroPosition.x - handOffset.x, - y: hands[h].zeroPosition.y - handOffset.z, - z: hands[h].zeroPosition.z + handOffset.y + x: -handOffset.x, + y: -handOffset.z, + z: -handOffset.y - hands[h].zeroPosition.z }; - handOffset.z = -handOffset.z; // Hand offset in world coordinates ... cameraOrientation = Camera.getOrientation(); handOffset = Vec3.sum(Camera.getPosition(), Vec3.multiplyQbyV(cameraOrientation, handOffset)); - // Hand offset in avatar coordinates ... + // Hand offset in avatar coordinates ... inverseAvatarOrientation = Quat.inverse(MyAvatar.orientation); handOffset = Vec3.subtract(handOffset, MyAvatar.position); handOffset = Vec3.multiplyQbyV(inverseAvatarOrientation, handOffset); handOffset.z = -handOffset.z; handOffset.x = -handOffset.x; + // Hand rotation in camera coordinates ... handRotation = { - x: -handRotation.x, + x: -handRotation.y, y: -handRotation.z, - z: -handRotation.y, + z: -handRotation.x, w: handRotation.w }; // Hand rotation in avatar coordinates ... - handRotation = Quat.multiply(Quat.angleAxis(180.0, { x: 0, y: 1, z: 0 }), handRotation); - cameraOrientation.x = -cameraOrientation.x; - cameraOrientation.z = -cameraOrientation.z; - handRotation = Quat.multiply(cameraOrientation, handRotation); - handRotation = Quat.multiply(inverseAvatarOrientation, handRotation); + handRotation = Quat.multiply(HMD_CAMERA_TO_AVATAR_ROTATION[h], handRotation); + cameraOrientation = { + x: cameraOrientation.z, + y: cameraOrientation.y, + z: cameraOrientation.x, + w: cameraOrientation.w + }; + cameraOrientation = Quat.multiply(cameraOrientation, Quat.inverse(MyAvatar.orientation)); + handRotation = Quat.multiply(handRotation, cameraOrientation); // Works!!! } else { @@ -443,18 +453,19 @@ var leapHands = (function () { // Hand rotation in camera coordinates ... handRotation = { - x: -handRotation.x, - y: -handRotation.z, - z: -handRotation.y, + x: handRotation.z, + y: handRotation.y, + z: handRotation.x, w: handRotation.w }; // Hand rotation in avatar coordinates ... - handRotation = Quat.multiply(Quat.angleAxis(90.0, { x: 1, y: 0, z: 0 }), handRotation); + handRotation = Quat.multiply(DESKTOP_CAMERA_TO_AVATAR_ROTATION, handRotation); } - // Set hand position and orientation ... - MyAvatar.setJointModelPositionAndOrientation(hands[h].jointName, handOffset, handRotation, true); + // Set hand position and orientation for animation state handler ... + hands[h].position = handOffset; + hands[h].rotation = handRotation; // Set finger joints ... for (i = 0; i < NUM_FINGERS; i += 1) { From 404deba78d67689320487693f672504e8035a0cb Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 5 Dec 2015 16:26:21 +1300 Subject: [PATCH 352/401] Adjust avatar thumb root joint angle to look better --- examples/controllers/leap/leapHands.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/controllers/leap/leapHands.js b/examples/controllers/leap/leapHands.js index 424ab81948..a77fa44e1c 100644 --- a/examples/controllers/leap/leapHands.js +++ b/examples/controllers/leap/leapHands.js @@ -46,7 +46,8 @@ var leapHands = (function () { Quat.angleAxis(-180.0, { x: 0, y: 0, z: 1 }) ], DESKTOP_CAMERA_TO_AVATAR_ROTATION = - Quat.multiply(Quat.angleAxis(180.0, { x: 0, y: 1, z: 0 }), Quat.angleAxis(90.0, { x: 0, y: 0, z: 1 })); + Quat.multiply(Quat.angleAxis(180.0, { x: 0, y: 1, z: 0 }), Quat.angleAxis(90.0, { x: 0, y: 0, z: 1 })), + LEAP_THUMB_ROOT_ADJUST = [Quat.fromPitchYawRollDegrees(0, 0, 20), Quat.fromPitchYawRollDegrees(0, 0, -20)]; function printSkeletonJointNames() { var jointNames, @@ -479,6 +480,10 @@ var leapHands = (function () { z: side * -locRotation.x, w: locRotation.w }; + if (j === 0) { + // Adjust avatar thumb root joint rotation to make avatar hands look better + locRotation = Quat.multiply(LEAP_THUMB_ROOT_ADJUST[h], locRotation); + } } else { locRotation = { x: -locRotation.x, From 3b6cd4c2d10e50389278725d530b666dfc0fd8dc Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 5 Dec 2015 14:11:59 -0800 Subject: [PATCH 353/401] initial live earthqukes commit --- .../data_visualization/earthquakes_live.js | 173 +++ examples/data_visualization/testQuakes.json | 153 +++ examples/libraries/tinyColor.js | 1155 +++++++++++++++++ 3 files changed, 1481 insertions(+) create mode 100644 examples/data_visualization/earthquakes_live.js create mode 100644 examples/data_visualization/testQuakes.json create mode 100644 examples/libraries/tinyColor.js diff --git a/examples/data_visualization/earthquakes_live.js b/examples/data_visualization/earthquakes_live.js new file mode 100644 index 0000000000..76f0fad5b0 --- /dev/null +++ b/examples/data_visualization/earthquakes_live.js @@ -0,0 +1,173 @@ +//earthquakes_live.js +//created by james b. pollack @imgntn on 12/5/2015 +Script.include('../libraries/promise.js'); +var Promise = loadPromise(); + +Script.include('../libraries/tinyColor.js'); +var tinyColor = loadTinyColor(); + +var EARTH_SPHERE_RADIUS = 5; +var EARTH_CENTER_POSITION = Vec3.sum(MyAvatar.position, { + x: 5, + y: 0, + z: 0 +}); + +var EARTH_MODEL_URL='http://public.highfidelity.io/marketplace/hificontent/Scripts/planets/planets/earth.fbx'; +//USGS updates the data every five minutes +var CHECK_QUAKE_FREQUENCY = 300 * 1000; + +var QUAKE_MARKER_DIMENSIONS = { + x: 0.1, + y: 0.1, + z: 0.1 +}; + +function createEarth() { + var earthProperties = { + name: 'Earth', + type: 'Model', + modelURL:EARTH_MODEL_URL, + position: EARTH_CENTER_POSITION, + dimensions: { + x: EARTH_SPHERE_RADIUS, + y: EARTH_SPHERE_RADIUS, + z: EARTH_SPHERE_RADIUS + }, + // color: { + // red: 0, + // green: 100, + // blue: 150 + // }, + collisionsWillMove: false, + userData: JSON.stringify({ + grabbableKey: { + grabbable: false + } + }) + } + + return Entities.addEntity(earthProperties) +} + +function plotLatitudeLongitude(radiusOfSphere, latitude, longitude) { + var tx = radiusOfSphere * Math.cos(latitude) * Math.cos(longitude); + var ty = radiusOfSphere * -Math.sin(latitude); + var tz = radiusOfSphere * Math.cos(latitude) * Math.sin(longitude); + return { + x: tx, + y: ty, + z: tz + } +} + +function getQuakePosition(earthquake) { + var latitude = earthquake.geometry.coordinates[0]; + var longitude = earthquake.geometry.coordinates[1]; + var latlng = plotLatitudeLongitude(2.5, latitude, longitude); + + var position = EARTH_CENTER_POSITION; + var finalPosition = Vec3.sum(position, latlng); + + // print('finalpos::' + JSON.stringify(finalPosition)) + return finalPosition +} + +var QUAKE_URL = 'http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson' + +function get(url) { + print('getting' + url) + // Return a new promise. + return new Promise(function(resolve, reject) { + // Do the usual XHR stuff + var req = new XMLHttpRequest(); + req.open('GET', url); + req.onreadystatechange = function() { + print('req status:: ' + JSON.stringify(req.status)) + + if (req.readyState == 4 && req.status == 200) { + var myArr = JSON.parse(req.responseText); + resolve(myArr); + } + }; + + req.send(); + }); +} + +function showEarthquake(snapshot) { + var earthquake = snapshot.val(); + print("Mag " + earthquake.mag + " at " + earthquake.place); +} + +function createQuakeMarker(earthquake) { + var markerProperties = { + name: 'Marker', + type: 'Sphere', + dimensions: QUAKE_MARKER_DIMENSIONS, + position: getQuakePosition(earthquake), + lifetime: 6000, + color: getQuakeMarkerColor(earthquake) + } + + //print('marker properties::' + JSON.stringify(markerProperties)) + return Entities.addEntity(markerProperties); +} + +function getQuakeMarkerColor(earthquake) { + var color = {}; + var magnitude = earthquake.properties.mag; + //realistic but will never get full red coloring and will probably be pretty dull for most. must experiment + var sValue = scale(magnitude, 0, 10, 0, 100); + var HSL_string = "hsl(0, " + sValue + "%, 50%)" + var color = tinyColor(HSL_string); + var finalColor = { + red: color._r, + green: color._g, + blue: color._b + } + + return finalColor +} + +function scale(value, min1, max1, min2, max2) { + return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); +} + +function processQuakes(earthquakes) { + print('quakers length' + earthquakes.length) + earthquakes.forEach(function(quake) { + // print('PROCESSING A QUAKE') + var marker = createQuakeMarker(quake); + markers.push(marker); + }) + print('markers length:' + markers.length) +} + +var quakea; +var markers = []; + +var earth = createEarth(); + +get(QUAKE_URL).then(function(response) { + print('got it::' + response.features.length) + quakes = response.features; + processQuakes(quakes); + //print("Success!" + JSON.stringify(response)); +}, function(error) { + print('error getting quakes') +}); + +function cleanupMarkers() { + print('CLEANING UP MARKERS') + while (markers.length > 0) { + Entities.deleteEntity(markers.pop()); + } +} + +function cleanupEarth() { + Entities.deleteEntity(earth); +} + +Script.scriptEnding.connect(cleanupMarkers); +Script.scriptEnding.connect(cleanupEarth); \ No newline at end of file diff --git a/examples/data_visualization/testQuakes.json b/examples/data_visualization/testQuakes.json new file mode 100644 index 0000000000..a6429b79c8 --- /dev/null +++ b/examples/data_visualization/testQuakes.json @@ -0,0 +1,153 @@ +{ + "type": "FeatureCollection", + "metadata": { + "generated": 1449347736000, + "url": "http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_hour.geojson", + "title": "USGS All Earthquakes, Past Hour", + "status": 200, + "api": "1.1.0", + "count": 4 + }, + "features": [{ + "type": "Feature", + "properties": { + "mag": 1.39, + "place": "17km ESE of Julian, California", + "time": 1449345604050, + "updated": 1449345856673, + "tz": -480, + "url": "http://earthquake.usgs.gov/earthquakes/eventpage/ci37498832", + "detail": "http://earthquake.usgs.gov/earthquakes/feed/v1.0/detail/ci37498832.geojson", + "felt": null, + "cdi": null, + "mmi": null, + "alert": null, + "status": "automatic", + "tsunami": 0, + "sig": 30, + "net": "ci", + "code": "37498832", + "ids": ",ci37498832,", + "sources": ",ci,", + "types": ",general-link,geoserve,nearby-cities,origin,phase-data,", + "nst": 32, + "dmin": 0.1379, + "rms": 0.21, + "gap": 68, + "magType": "ml", + "type": "earthquake", + "title": "M 1.4 - 17km ESE of Julian, California" + }, + "geometry": { + "type": "Point", + "coordinates": [-116.4293333, 33.0301667, 7.84] + }, + "id": "ci37498832" + }, { + "type": "Feature", + "properties": { + "mag": 1.12, + "place": "3km ESE of The Geysers, California", + "time": 1449344686690, + "updated": 1449344783260, + "tz": -480, + "url": "http://earthquake.usgs.gov/earthquakes/eventpage/nc72564866", + "detail": "http://earthquake.usgs.gov/earthquakes/feed/v1.0/detail/nc72564866.geojson", + "felt": null, + "cdi": null, + "mmi": null, + "alert": null, + "status": "automatic", + "tsunami": 0, + "sig": 19, + "net": "nc", + "code": "72564866", + "ids": ",nc72564866,", + "sources": ",nc,", + "types": ",general-link,geoserve,nearby-cities,origin,phase-data,", + "nst": 11, + "dmin": 0.01342, + "rms": 0.03, + "gap": 154, + "magType": "md", + "type": "earthquake", + "title": "M 1.1 - 3km ESE of The Geysers, California" + }, + "geometry": { + "type": "Point", + "coordinates": [-122.7176666, 38.7598343, 1.48] + }, + "id": "nc72564866" + }, { + "type": "Feature", + "properties": { + "mag": 1.99, + "place": "3km SE of The Geysers, California", + "time": 1449344287500, + "updated": 1449344383210, + "tz": -480, + "url": "http://earthquake.usgs.gov/earthquakes/eventpage/nc72564856", + "detail": "http://earthquake.usgs.gov/earthquakes/feed/v1.0/detail/nc72564856.geojson", + "felt": null, + "cdi": null, + "mmi": null, + "alert": null, + "status": "automatic", + "tsunami": 0, + "sig": 61, + "net": "nc", + "code": "72564856", + "ids": ",nc72564856,", + "sources": ",nc,", + "types": ",general-link,geoserve,nearby-cities,origin,phase-data,", + "nst": 13, + "dmin": 0.01626, + "rms": 0.02, + "gap": 72, + "magType": "md", + "type": "earthquake", + "title": "M 2.0 - 3km SE of The Geysers, California" + }, + "geometry": { + "type": "Point", + "coordinates": [-122.7203369, 38.7571678, 0.3] + }, + "id": "nc72564856" + }, { + "type": "Feature", + "properties": { + "mag": 2.36, + "place": "3km ESE of The Geysers, California", + "time": 1449344196380, + "updated": 1449344459434, + "tz": -480, + "url": "http://earthquake.usgs.gov/earthquakes/eventpage/nc72564836", + "detail": "http://earthquake.usgs.gov/earthquakes/feed/v1.0/detail/nc72564836.geojson", + "felt": 0, + "cdi": 1, + "mmi": null, + "alert": null, + "status": "automatic", + "tsunami": 0, + "sig": 86, + "net": "nc", + "code": "72564836", + "ids": ",nc72564836,", + "sources": ",nc,", + "types": ",dyfi,focal-mechanism,general-link,geoserve,nearby-cities,origin,phase-data,scitech-link,", + "nst": 36, + "dmin": 0.01395, + "rms": 0.07, + "gap": 38, + "magType": "md", + "type": "earthquake", + "title": "M 2.4 - 3km ESE of The Geysers, California" + }, + "geometry": { + "type": "Point", + "coordinates": [-122.722168, 38.7598343, 1.21] + }, + "id": "nc72564836" + }], + "bbox": [-122.722168, 33.0301667, 0.3, -116.4293333, 38.7598343, 7.84] +} \ No newline at end of file diff --git a/examples/libraries/tinyColor.js b/examples/libraries/tinyColor.js new file mode 100644 index 0000000000..18aa462010 --- /dev/null +++ b/examples/libraries/tinyColor.js @@ -0,0 +1,1155 @@ +// TinyColor v1.3.0 +// https://github.com/bgrins/TinyColor +// Brian Grinstead, MIT License + + + +var trimLeft = /^\s+/, + trimRight = /\s+$/, + tinyCounter = 0, + math = Math, + mathRound = math.round, + mathMin = math.min, + mathMax = math.max, + mathRandom = math.random; + +function tinycolor (color, opts) { + + color = (color) ? color : ''; + opts = opts || { }; + + // If input is already a tinycolor, return itself + if (color instanceof tinycolor) { + return color; + } + // If we are called as a function, call using new instead + if (!(this instanceof tinycolor)) { + return new tinycolor(color, opts); + } + + var rgb = inputToRGB(color); + this._originalInput = color, + this._r = rgb.r, + this._g = rgb.g, + this._b = rgb.b, + this._a = rgb.a, + this._roundA = mathRound(100*this._a) / 100, + this._format = opts.format || rgb.format; + this._gradientType = opts.gradientType; + + // Don't let the range of [0,255] come back in [0,1]. + // Potentially lose a little bit of precision here, but will fix issues where + // .5 gets interpreted as half of the total, instead of half of 1 + // If it was supposed to be 128, this was already taken care of by `inputToRgb` + if (this._r < 1) { this._r = mathRound(this._r); } + if (this._g < 1) { this._g = mathRound(this._g); } + if (this._b < 1) { this._b = mathRound(this._b); } + + this._ok = rgb.ok; + this._tc_id = tinyCounter++; +} + +tinycolor.prototype = { + isDark: function() { + return this.getBrightness() < 128; + }, + isLight: function() { + return !this.isDark(); + }, + isValid: function() { + return this._ok; + }, + getOriginalInput: function() { + return this._originalInput; + }, + getFormat: function() { + return this._format; + }, + getAlpha: function() { + return this._a; + }, + getBrightness: function() { + //http://www.w3.org/TR/AERT#color-contrast + var rgb = this.toRgb(); + return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000; + }, + getLuminance: function() { + //http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef + var rgb = this.toRgb(); + var RsRGB, GsRGB, BsRGB, R, G, B; + RsRGB = rgb.r/255; + GsRGB = rgb.g/255; + BsRGB = rgb.b/255; + + if (RsRGB <= 0.03928) {R = RsRGB / 12.92;} else {R = Math.pow(((RsRGB + 0.055) / 1.055), 2.4);} + if (GsRGB <= 0.03928) {G = GsRGB / 12.92;} else {G = Math.pow(((GsRGB + 0.055) / 1.055), 2.4);} + if (BsRGB <= 0.03928) {B = BsRGB / 12.92;} else {B = Math.pow(((BsRGB + 0.055) / 1.055), 2.4);} + return (0.2126 * R) + (0.7152 * G) + (0.0722 * B); + }, + setAlpha: function(value) { + this._a = boundAlpha(value); + this._roundA = mathRound(100*this._a) / 100; + return this; + }, + toHsv: function() { + var hsv = rgbToHsv(this._r, this._g, this._b); + return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: this._a }; + }, + toHsvString: function() { + var hsv = rgbToHsv(this._r, this._g, this._b); + var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100); + return (this._a == 1) ? + "hsv(" + h + ", " + s + "%, " + v + "%)" : + "hsva(" + h + ", " + s + "%, " + v + "%, "+ this._roundA + ")"; + }, + toHsl: function() { + var hsl = rgbToHsl(this._r, this._g, this._b); + return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: this._a }; + }, + toHslString: function() { + var hsl = rgbToHsl(this._r, this._g, this._b); + var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100); + return (this._a == 1) ? + "hsl(" + h + ", " + s + "%, " + l + "%)" : + "hsla(" + h + ", " + s + "%, " + l + "%, "+ this._roundA + ")"; + }, + toHex: function(allow3Char) { + return rgbToHex(this._r, this._g, this._b, allow3Char); + }, + toHexString: function(allow3Char) { + return '#' + this.toHex(allow3Char); + }, + toHex8: function() { + return rgbaToHex(this._r, this._g, this._b, this._a); + }, + toHex8String: function() { + return '#' + this.toHex8(); + }, + toRgb: function() { + return { r: mathRound(this._r), g: mathRound(this._g), b: mathRound(this._b), a: this._a }; + }, + toRgbString: function() { + return (this._a == 1) ? + "rgb(" + mathRound(this._r) + ", " + mathRound(this._g) + ", " + mathRound(this._b) + ")" : + "rgba(" + mathRound(this._r) + ", " + mathRound(this._g) + ", " + mathRound(this._b) + ", " + this._roundA + ")"; + }, + toPercentageRgb: function() { + return { r: mathRound(bound01(this._r, 255) * 100) + "%", g: mathRound(bound01(this._g, 255) * 100) + "%", b: mathRound(bound01(this._b, 255) * 100) + "%", a: this._a }; + }, + toPercentageRgbString: function() { + return (this._a == 1) ? + "rgb(" + mathRound(bound01(this._r, 255) * 100) + "%, " + mathRound(bound01(this._g, 255) * 100) + "%, " + mathRound(bound01(this._b, 255) * 100) + "%)" : + "rgba(" + mathRound(bound01(this._r, 255) * 100) + "%, " + mathRound(bound01(this._g, 255) * 100) + "%, " + mathRound(bound01(this._b, 255) * 100) + "%, " + this._roundA + ")"; + }, + toName: function() { + if (this._a === 0) { + return "transparent"; + } + + if (this._a < 1) { + return false; + } + + return hexNames[rgbToHex(this._r, this._g, this._b, true)] || false; + }, + toFilter: function(secondColor) { + var hex8String = '#' + rgbaToHex(this._r, this._g, this._b, this._a); + var secondHex8String = hex8String; + var gradientType = this._gradientType ? "GradientType = 1, " : ""; + + if (secondColor) { + var s = tinycolor(secondColor); + secondHex8String = s.toHex8String(); + } + + return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr="+hex8String+",endColorstr="+secondHex8String+")"; + }, + toString: function(format) { + var formatSet = !!format; + format = format || this._format; + + var formattedString = false; + var hasAlpha = this._a < 1 && this._a >= 0; + var needsAlphaFormat = !formatSet && hasAlpha && (format === "hex" || format === "hex6" || format === "hex3" || format === "name"); + + if (needsAlphaFormat) { + // Special case for "transparent", all other non-alpha formats + // will return rgba when there is transparency. + if (format === "name" && this._a === 0) { + return this.toName(); + } + return this.toRgbString(); + } + if (format === "rgb") { + formattedString = this.toRgbString(); + } + if (format === "prgb") { + formattedString = this.toPercentageRgbString(); + } + if (format === "hex" || format === "hex6") { + formattedString = this.toHexString(); + } + if (format === "hex3") { + formattedString = this.toHexString(true); + } + if (format === "hex8") { + formattedString = this.toHex8String(); + } + if (format === "name") { + formattedString = this.toName(); + } + if (format === "hsl") { + formattedString = this.toHslString(); + } + if (format === "hsv") { + formattedString = this.toHsvString(); + } + + return formattedString || this.toHexString(); + }, + clone: function() { + return tinycolor(this.toString()); + }, + + _applyModification: function(fn, args) { + var color = fn.apply(null, [this].concat([].slice.call(args))); + this._r = color._r; + this._g = color._g; + this._b = color._b; + this.setAlpha(color._a); + return this; + }, + lighten: function() { + return this._applyModification(lighten, arguments); + }, + brighten: function() { + return this._applyModification(brighten, arguments); + }, + darken: function() { + return this._applyModification(darken, arguments); + }, + desaturate: function() { + return this._applyModification(desaturate, arguments); + }, + saturate: function() { + return this._applyModification(saturate, arguments); + }, + greyscale: function() { + return this._applyModification(greyscale, arguments); + }, + spin: function() { + return this._applyModification(spin, arguments); + }, + + _applyCombination: function(fn, args) { + return fn.apply(null, [this].concat([].slice.call(args))); + }, + analogous: function() { + return this._applyCombination(analogous, arguments); + }, + complement: function() { + return this._applyCombination(complement, arguments); + }, + monochromatic: function() { + return this._applyCombination(monochromatic, arguments); + }, + splitcomplement: function() { + return this._applyCombination(splitcomplement, arguments); + }, + triad: function() { + return this._applyCombination(triad, arguments); + }, + tetrad: function() { + return this._applyCombination(tetrad, arguments); + } +}; + +// If input is an object, force 1 into "1.0" to handle ratios properly +// String input requires "1.0" as input, so 1 will be treated as 1 +tinycolor.fromRatio = function(color, opts) { + if (typeof color == "object") { + var newColor = {}; + for (var i in color) { + if (color.hasOwnProperty(i)) { + if (i === "a") { + newColor[i] = color[i]; + } + else { + newColor[i] = convertToPercentage(color[i]); + } + } + } + color = newColor; + } + + return tinycolor(color, opts); +}; + +// Given a string or object, convert that input to RGB +// Possible string inputs: +// +// "red" +// "#f00" or "f00" +// "#ff0000" or "ff0000" +// "#ff000000" or "ff000000" +// "rgb 255 0 0" or "rgb (255, 0, 0)" +// "rgb 1.0 0 0" or "rgb (1, 0, 0)" +// "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1" +// "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1" +// "hsl(0, 100%, 50%)" or "hsl 0 100% 50%" +// "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1" +// "hsv(0, 100%, 100%)" or "hsv 0 100% 100%" +// +function inputToRGB(color) { + + var rgb = { r: 0, g: 0, b: 0 }; + var a = 1; + var ok = false; + var format = false; + + if (typeof color == "string") { + color = stringInputToObject(color); + } + + if (typeof color == "object") { + if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) { + rgb = rgbToRgb(color.r, color.g, color.b); + ok = true; + format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb"; + } + else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) { + color.s = convertToPercentage(color.s); + color.v = convertToPercentage(color.v); + rgb = hsvToRgb(color.h, color.s, color.v); + ok = true; + format = "hsv"; + } + else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) { + color.s = convertToPercentage(color.s); + color.l = convertToPercentage(color.l); + rgb = hslToRgb(color.h, color.s, color.l); + ok = true; + format = "hsl"; + } + + if (color.hasOwnProperty("a")) { + a = color.a; + } + } + + a = boundAlpha(a); + + return { + ok: ok, + format: color.format || format, + r: mathMin(255, mathMax(rgb.r, 0)), + g: mathMin(255, mathMax(rgb.g, 0)), + b: mathMin(255, mathMax(rgb.b, 0)), + a: a + }; +} + + +// Conversion Functions +// -------------------- + +// `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from: +// + +// `rgbToRgb` +// Handle bounds / percentage checking to conform to CSS color spec +// +// *Assumes:* r, g, b in [0, 255] or [0, 1] +// *Returns:* { r, g, b } in [0, 255] +function rgbToRgb(r, g, b){ + return { + r: bound01(r, 255) * 255, + g: bound01(g, 255) * 255, + b: bound01(b, 255) * 255 + }; +} + +// `rgbToHsl` +// Converts an RGB color value to HSL. +// *Assumes:* r, g, and b are contained in [0, 255] or [0, 1] +// *Returns:* { h, s, l } in [0,1] +function rgbToHsl(r, g, b) { + + r = bound01(r, 255); + g = bound01(g, 255); + b = bound01(b, 255); + + var max = mathMax(r, g, b), min = mathMin(r, g, b); + var h, s, l = (max + min) / 2; + + if(max == min) { + h = s = 0; // achromatic + } + else { + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch(max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + + h /= 6; + } + + return { h: h, s: s, l: l }; +} + +// `hslToRgb` +// Converts an HSL color value to RGB. +// *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100] +// *Returns:* { r, g, b } in the set [0, 255] +function hslToRgb(h, s, l) { + var r, g, b; + + h = bound01(h, 360); + s = bound01(s, 100); + l = bound01(l, 100); + + function hue2rgb(p, q, t) { + if(t < 0) t += 1; + if(t > 1) t -= 1; + if(t < 1/6) return p + (q - p) * 6 * t; + if(t < 1/2) return q; + if(t < 2/3) return p + (q - p) * (2/3 - t) * 6; + return p; + } + + if(s === 0) { + r = g = b = l; // achromatic + } + else { + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + r = hue2rgb(p, q, h + 1/3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1/3); + } + + return { r: r * 255, g: g * 255, b: b * 255 }; +} + +// `rgbToHsv` +// Converts an RGB color value to HSV +// *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1] +// *Returns:* { h, s, v } in [0,1] +function rgbToHsv(r, g, b) { + + r = bound01(r, 255); + g = bound01(g, 255); + b = bound01(b, 255); + + var max = mathMax(r, g, b), min = mathMin(r, g, b); + var h, s, v = max; + + var d = max - min; + s = max === 0 ? 0 : d / max; + + if(max == min) { + h = 0; // achromatic + } + else { + switch(max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + h /= 6; + } + return { h: h, s: s, v: v }; +} + +// `hsvToRgb` +// Converts an HSV color value to RGB. +// *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100] +// *Returns:* { r, g, b } in the set [0, 255] + function hsvToRgb(h, s, v) { + + h = bound01(h, 360) * 6; + s = bound01(s, 100); + v = bound01(v, 100); + + var i = math.floor(h), + f = h - i, + p = v * (1 - s), + q = v * (1 - f * s), + t = v * (1 - (1 - f) * s), + mod = i % 6, + r = [v, q, p, p, t, v][mod], + g = [t, v, v, q, p, p][mod], + b = [p, p, t, v, v, q][mod]; + + return { r: r * 255, g: g * 255, b: b * 255 }; +} + +// `rgbToHex` +// Converts an RGB color to hex +// Assumes r, g, and b are contained in the set [0, 255] +// Returns a 3 or 6 character hex +function rgbToHex(r, g, b, allow3Char) { + + var hex = [ + pad2(mathRound(r).toString(16)), + pad2(mathRound(g).toString(16)), + pad2(mathRound(b).toString(16)) + ]; + + // Return a 3 character hex if possible + if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) { + return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0); + } + + return hex.join(""); +} + +// `rgbaToHex` +// Converts an RGBA color plus alpha transparency to hex +// Assumes r, g, b and a are contained in the set [0, 255] +// Returns an 8 character hex +function rgbaToHex(r, g, b, a) { + + var hex = [ + pad2(convertDecimalToHex(a)), + pad2(mathRound(r).toString(16)), + pad2(mathRound(g).toString(16)), + pad2(mathRound(b).toString(16)) + ]; + + return hex.join(""); +} + +// `equals` +// Can be called with any tinycolor input +tinycolor.equals = function (color1, color2) { + if (!color1 || !color2) { return false; } + return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString(); +}; + +tinycolor.random = function() { + return tinycolor.fromRatio({ + r: mathRandom(), + g: mathRandom(), + b: mathRandom() + }); +}; + + +// Modification Functions +// ---------------------- +// Thanks to less.js for some of the basics here +// + +function desaturate(color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.s -= amount / 100; + hsl.s = clamp01(hsl.s); + return tinycolor(hsl); +} + +function saturate(color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.s += amount / 100; + hsl.s = clamp01(hsl.s); + return tinycolor(hsl); +} + +function greyscale(color) { + return tinycolor(color).desaturate(100); +} + +function lighten (color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.l += amount / 100; + hsl.l = clamp01(hsl.l); + return tinycolor(hsl); +} + +function brighten(color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var rgb = tinycolor(color).toRgb(); + rgb.r = mathMax(0, mathMin(255, rgb.r - mathRound(255 * - (amount / 100)))); + rgb.g = mathMax(0, mathMin(255, rgb.g - mathRound(255 * - (amount / 100)))); + rgb.b = mathMax(0, mathMin(255, rgb.b - mathRound(255 * - (amount / 100)))); + return tinycolor(rgb); +} + +function darken (color, amount) { + amount = (amount === 0) ? 0 : (amount || 10); + var hsl = tinycolor(color).toHsl(); + hsl.l -= amount / 100; + hsl.l = clamp01(hsl.l); + return tinycolor(hsl); +} + +// Spin takes a positive or negative amount within [-360, 360] indicating the change of hue. +// Values outside of this range will be wrapped into this range. +function spin(color, amount) { + var hsl = tinycolor(color).toHsl(); + var hue = (hsl.h + amount) % 360; + hsl.h = hue < 0 ? 360 + hue : hue; + return tinycolor(hsl); +} + +// Combination Functions +// --------------------- +// Thanks to jQuery xColor for some of the ideas behind these +// + +function complement(color) { + var hsl = tinycolor(color).toHsl(); + hsl.h = (hsl.h + 180) % 360; + return tinycolor(hsl); +} + +function triad(color) { + var hsl = tinycolor(color).toHsl(); + var h = hsl.h; + return [ + tinycolor(color), + tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }), + tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l }) + ]; +} + +function tetrad(color) { + var hsl = tinycolor(color).toHsl(); + var h = hsl.h; + return [ + tinycolor(color), + tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }), + tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }), + tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l }) + ]; +} + +function splitcomplement(color) { + var hsl = tinycolor(color).toHsl(); + var h = hsl.h; + return [ + tinycolor(color), + tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}), + tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l}) + ]; +} + +function analogous(color, results, slices) { + results = results || 6; + slices = slices || 30; + + var hsl = tinycolor(color).toHsl(); + var part = 360 / slices; + var ret = [tinycolor(color)]; + + for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) { + hsl.h = (hsl.h + part) % 360; + ret.push(tinycolor(hsl)); + } + return ret; +} + +function monochromatic(color, results) { + results = results || 6; + var hsv = tinycolor(color).toHsv(); + var h = hsv.h, s = hsv.s, v = hsv.v; + var ret = []; + var modification = 1 / results; + + while (results--) { + ret.push(tinycolor({ h: h, s: s, v: v})); + v = (v + modification) % 1; + } + + return ret; +} + +// Utility Functions +// --------------------- + +tinycolor.mix = function(color1, color2, amount) { + amount = (amount === 0) ? 0 : (amount || 50); + + var rgb1 = tinycolor(color1).toRgb(); + var rgb2 = tinycolor(color2).toRgb(); + + var p = amount / 100; + var w = p * 2 - 1; + var a = rgb2.a - rgb1.a; + + var w1; + + if (w * a == -1) { + w1 = w; + } else { + w1 = (w + a) / (1 + w * a); + } + + w1 = (w1 + 1) / 2; + + var w2 = 1 - w1; + + var rgba = { + r: rgb2.r * w1 + rgb1.r * w2, + g: rgb2.g * w1 + rgb1.g * w2, + b: rgb2.b * w1 + rgb1.b * w2, + a: rgb2.a * p + rgb1.a * (1 - p) + }; + + return tinycolor(rgba); +}; + + +// Readability Functions +// --------------------- +// false +// tinycolor.isReadable("#000", "#111",{level:"AA",size:"large"}) => false +tinycolor.isReadable = function(color1, color2, wcag2) { + var readability = tinycolor.readability(color1, color2); + var wcag2Parms, out; + + out = false; + + wcag2Parms = validateWCAG2Parms(wcag2); + switch (wcag2Parms.level + wcag2Parms.size) { + case "AAsmall": + case "AAAlarge": + out = readability >= 4.5; + break; + case "AAlarge": + out = readability >= 3; + break; + case "AAAsmall": + out = readability >= 7; + break; + } + return out; + +}; + +// `mostReadable` +// Given a base color and a list of possible foreground or background +// colors for that base, returns the most readable color. +// Optionally returns Black or White if the most readable color is unreadable. +// *Example* +// tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:false}).toHexString(); // "#112255" +// tinycolor.mostReadable(tinycolor.mostReadable("#123", ["#124", "#125"],{includeFallbackColors:true}).toHexString(); // "#ffffff" +// tinycolor.mostReadable("#a8015a", ["#faf3f3"],{includeFallbackColors:true,level:"AAA",size:"large"}).toHexString(); // "#faf3f3" +// tinycolor.mostReadable("#a8015a", ["#faf3f3"],{includeFallbackColors:true,level:"AAA",size:"small"}).toHexString(); // "#ffffff" +tinycolor.mostReadable = function(baseColor, colorList, args) { + var bestColor = null; + var bestScore = 0; + var readability; + var includeFallbackColors, level, size ; + args = args || {}; + includeFallbackColors = args.includeFallbackColors ; + level = args.level; + size = args.size; + + for (var i= 0; i < colorList.length ; i++) { + readability = tinycolor.readability(baseColor, colorList[i]); + if (readability > bestScore) { + bestScore = readability; + bestColor = tinycolor(colorList[i]); + } + } + + if (tinycolor.isReadable(baseColor, bestColor, {"level":level,"size":size}) || !includeFallbackColors) { + return bestColor; + } + else { + args.includeFallbackColors=false; + return tinycolor.mostReadable(baseColor,["#fff", "#000"],args); + } +}; + + +// Big List of Colors +// ------------------ +// +var names = tinycolor.names = { + aliceblue: "f0f8ff", + antiquewhite: "faebd7", + aqua: "0ff", + aquamarine: "7fffd4", + azure: "f0ffff", + beige: "f5f5dc", + bisque: "ffe4c4", + black: "000", + blanchedalmond: "ffebcd", + blue: "00f", + blueviolet: "8a2be2", + brown: "a52a2a", + burlywood: "deb887", + burntsienna: "ea7e5d", + cadetblue: "5f9ea0", + chartreuse: "7fff00", + chocolate: "d2691e", + coral: "ff7f50", + cornflowerblue: "6495ed", + cornsilk: "fff8dc", + crimson: "dc143c", + cyan: "0ff", + darkblue: "00008b", + darkcyan: "008b8b", + darkgoldenrod: "b8860b", + darkgray: "a9a9a9", + darkgreen: "006400", + darkgrey: "a9a9a9", + darkkhaki: "bdb76b", + darkmagenta: "8b008b", + darkolivegreen: "556b2f", + darkorange: "ff8c00", + darkorchid: "9932cc", + darkred: "8b0000", + darksalmon: "e9967a", + darkseagreen: "8fbc8f", + darkslateblue: "483d8b", + darkslategray: "2f4f4f", + darkslategrey: "2f4f4f", + darkturquoise: "00ced1", + darkviolet: "9400d3", + deeppink: "ff1493", + deepskyblue: "00bfff", + dimgray: "696969", + dimgrey: "696969", + dodgerblue: "1e90ff", + firebrick: "b22222", + floralwhite: "fffaf0", + forestgreen: "228b22", + fuchsia: "f0f", + gainsboro: "dcdcdc", + ghostwhite: "f8f8ff", + gold: "ffd700", + goldenrod: "daa520", + gray: "808080", + green: "008000", + greenyellow: "adff2f", + grey: "808080", + honeydew: "f0fff0", + hotpink: "ff69b4", + indianred: "cd5c5c", + indigo: "4b0082", + ivory: "fffff0", + khaki: "f0e68c", + lavender: "e6e6fa", + lavenderblush: "fff0f5", + lawngreen: "7cfc00", + lemonchiffon: "fffacd", + lightblue: "add8e6", + lightcoral: "f08080", + lightcyan: "e0ffff", + lightgoldenrodyellow: "fafad2", + lightgray: "d3d3d3", + lightgreen: "90ee90", + lightgrey: "d3d3d3", + lightpink: "ffb6c1", + lightsalmon: "ffa07a", + lightseagreen: "20b2aa", + lightskyblue: "87cefa", + lightslategray: "789", + lightslategrey: "789", + lightsteelblue: "b0c4de", + lightyellow: "ffffe0", + lime: "0f0", + limegreen: "32cd32", + linen: "faf0e6", + magenta: "f0f", + maroon: "800000", + mediumaquamarine: "66cdaa", + mediumblue: "0000cd", + mediumorchid: "ba55d3", + mediumpurple: "9370db", + mediumseagreen: "3cb371", + mediumslateblue: "7b68ee", + mediumspringgreen: "00fa9a", + mediumturquoise: "48d1cc", + mediumvioletred: "c71585", + midnightblue: "191970", + mintcream: "f5fffa", + mistyrose: "ffe4e1", + moccasin: "ffe4b5", + navajowhite: "ffdead", + navy: "000080", + oldlace: "fdf5e6", + olive: "808000", + olivedrab: "6b8e23", + orange: "ffa500", + orangered: "ff4500", + orchid: "da70d6", + palegoldenrod: "eee8aa", + palegreen: "98fb98", + paleturquoise: "afeeee", + palevioletred: "db7093", + papayawhip: "ffefd5", + peachpuff: "ffdab9", + peru: "cd853f", + pink: "ffc0cb", + plum: "dda0dd", + powderblue: "b0e0e6", + purple: "800080", + rebeccapurple: "663399", + red: "f00", + rosybrown: "bc8f8f", + royalblue: "4169e1", + saddlebrown: "8b4513", + salmon: "fa8072", + sandybrown: "f4a460", + seagreen: "2e8b57", + seashell: "fff5ee", + sienna: "a0522d", + silver: "c0c0c0", + skyblue: "87ceeb", + slateblue: "6a5acd", + slategray: "708090", + slategrey: "708090", + snow: "fffafa", + springgreen: "00ff7f", + steelblue: "4682b4", + tan: "d2b48c", + teal: "008080", + thistle: "d8bfd8", + tomato: "ff6347", + turquoise: "40e0d0", + violet: "ee82ee", + wheat: "f5deb3", + white: "fff", + whitesmoke: "f5f5f5", + yellow: "ff0", + yellowgreen: "9acd32" +}; + +// Make it easy to access colors via `hexNames[hex]` +var hexNames = tinycolor.hexNames = flip(names); + + +// Utilities +// --------- + +// `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }` +function flip(o) { + var flipped = { }; + for (var i in o) { + if (o.hasOwnProperty(i)) { + flipped[o[i]] = i; + } + } + return flipped; +} + +// Return a valid alpha value [0,1] with all invalid values being set to 1 +function boundAlpha(a) { + a = parseFloat(a); + + if (isNaN(a) || a < 0 || a > 1) { + a = 1; + } + + return a; +} + +// Take input from [0, n] and return it as [0, 1] +function bound01(n, max) { + if (isOnePointZero(n)) { n = "100%"; } + + var processPercent = isPercentage(n); + n = mathMin(max, mathMax(0, parseFloat(n))); + + // Automatically convert percentage into number + if (processPercent) { + n = parseInt(n * max, 10) / 100; + } + + // Handle floating point rounding errors + if ((math.abs(n - max) < 0.000001)) { + return 1; + } + + // Convert into [0, 1] range if it isn't already + return (n % max) / parseFloat(max); +} + +// Force a number between 0 and 1 +function clamp01(val) { + return mathMin(1, mathMax(0, val)); +} + +// Parse a base-16 hex value into a base-10 integer +function parseIntFromHex(val) { + return parseInt(val, 16); +} + +// Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1 +// +function isOnePointZero(n) { + return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1; +} + +// Check to see if string passed in is a percentage +function isPercentage(n) { + return typeof n === "string" && n.indexOf('%') != -1; +} + +// Force a hex value to have 2 characters +function pad2(c) { + return c.length == 1 ? '0' + c : '' + c; +} + +// Replace a decimal with it's percentage value +function convertToPercentage(n) { + if (n <= 1) { + n = (n * 100) + "%"; + } + + return n; +} + +// Converts a decimal to a hex value +function convertDecimalToHex(d) { + return Math.round(parseFloat(d) * 255).toString(16); +} +// Converts a hex value to a decimal +function convertHexToDecimal(h) { + return (parseIntFromHex(h) / 255); +} + +var matchers = (function() { + + // + var CSS_INTEGER = "[-\\+]?\\d+%?"; + + // + var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?"; + + // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome. + var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")"; + + // Actual matching. + // Parentheses and commas are optional, but not required. + // Whitespace can take the place of commas or opening paren + var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; + var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?"; + + return { + rgb: new RegExp("rgb" + PERMISSIVE_MATCH3), + rgba: new RegExp("rgba" + PERMISSIVE_MATCH4), + hsl: new RegExp("hsl" + PERMISSIVE_MATCH3), + hsla: new RegExp("hsla" + PERMISSIVE_MATCH4), + hsv: new RegExp("hsv" + PERMISSIVE_MATCH3), + hsva: new RegExp("hsva" + PERMISSIVE_MATCH4), + hex3: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/, + hex6: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/, + hex8: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/ + }; +})(); + +// `stringInputToObject` +// Permissive string parsing. Take in a number of formats, and output an object +// based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}` +function stringInputToObject(color) { + + color = color.replace(trimLeft,'').replace(trimRight, '').toLowerCase(); + var named = false; + if (names[color]) { + color = names[color]; + named = true; + } + else if (color == 'transparent') { + return { r: 0, g: 0, b: 0, a: 0, format: "name" }; + } + + // Try to match string input using regular expressions. + // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360] + // Just return an object and let the conversion functions handle that. + // This way the result will be the same whether the tinycolor is initialized with string or object. + var match; + if ((match = matchers.rgb.exec(color))) { + return { r: match[1], g: match[2], b: match[3] }; + } + if ((match = matchers.rgba.exec(color))) { + return { r: match[1], g: match[2], b: match[3], a: match[4] }; + } + if ((match = matchers.hsl.exec(color))) { + return { h: match[1], s: match[2], l: match[3] }; + } + if ((match = matchers.hsla.exec(color))) { + return { h: match[1], s: match[2], l: match[3], a: match[4] }; + } + if ((match = matchers.hsv.exec(color))) { + return { h: match[1], s: match[2], v: match[3] }; + } + if ((match = matchers.hsva.exec(color))) { + return { h: match[1], s: match[2], v: match[3], a: match[4] }; + } + if ((match = matchers.hex8.exec(color))) { + return { + a: convertHexToDecimal(match[1]), + r: parseIntFromHex(match[2]), + g: parseIntFromHex(match[3]), + b: parseIntFromHex(match[4]), + format: named ? "name" : "hex8" + }; + } + if ((match = matchers.hex6.exec(color))) { + return { + r: parseIntFromHex(match[1]), + g: parseIntFromHex(match[2]), + b: parseIntFromHex(match[3]), + format: named ? "name" : "hex" + }; + } + if ((match = matchers.hex3.exec(color))) { + return { + r: parseIntFromHex(match[1] + '' + match[1]), + g: parseIntFromHex(match[2] + '' + match[2]), + b: parseIntFromHex(match[3] + '' + match[3]), + format: named ? "name" : "hex" + }; + } + + return false; +} + +function validateWCAG2Parms(parms) { + // return valid WCAG2 parms for isReadable. + // If input parms are invalid, return {"level":"AA", "size":"small"} + var level, size; + parms = parms || {"level":"AA", "size":"small"}; + level = (parms.level || "AA").toUpperCase(); + size = (parms.size || "small").toLowerCase(); + if (level !== "AA" && level !== "AAA") { + level = "AA"; + } + if (size !== "small" && size !== "large") { + size = "small"; + } + return {"level":level, "size":size}; +} + +loadTinyColor = function(){ + return tinycolor +} \ No newline at end of file From 1f0150f65f4635d00d33d531be46108884ff920f Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 5 Dec 2015 15:12:44 -0800 Subject: [PATCH 354/401] add parentID and parentJointIndex to terse logging --- libraries/entities/src/EntityItemProperties.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 52f98be208..9ff5d73616 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -1780,6 +1780,12 @@ QList EntityItemProperties::listChangedProperties() { if (zPNeighborIDChanged()) { out += "zPNeighborID"; } + if (parentIDChanged()) { + out += "parentID"; + } + if (parentJointIndexChanged()) { + out += "parentJointIndex"; + } getAnimation().listChangedProperties(out); getKeyLight().listChangedProperties(out); From d518a4573e7965e7693fa0abbd683ff92878bca1 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 5 Dec 2015 15:15:33 -0800 Subject: [PATCH 355/401] if script sets parent or jointIndex, don't pop entity off to someplace --- .../entities/src/EntityScriptingInterface.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 2551b2727b..23fbac13cf 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -202,7 +202,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties script bool updatedEntity = false; _entityTree->withWriteLock([&] { if (scriptSideProperties.parentDependentPropertyChanged()) { - // if the script sets a location property but didn't include parent information, grab the needed + // if the script set a location property but didn't include parent information, grab the needed // properties from the entity. if (!scriptSideProperties.parentIDChanged() || !scriptSideProperties.parentJointIndexChanged()) { EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); @@ -214,6 +214,18 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties script } } } + if (scriptSideProperties.parentIDChanged() || scriptSideProperties.parentJointIndexChanged()) { + // if the script set parentID or parentJointIndex but didn't include position and rotation, grab + // the missing properties from the entity + if (!scriptSideProperties.localPositionChanged() && !scriptSideProperties.positionChanged()) { + EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); + properties.setPosition(entity->getPosition()); + } + if (!scriptSideProperties.localRotationChanged() && !scriptSideProperties.rotationChanged()) { + EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); + properties.setRotation(entity->getOrientation()); + } + } properties = convertLocationFromScriptSemantics(properties); updatedEntity = _entityTree->updateEntity(entityID, properties); }); From 1f2d7262111187e1888b6e3314ed6e921a80d687 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 5 Dec 2015 16:16:58 -0800 Subject: [PATCH 356/401] awesome stuff --- .../data_visualization/earthquakes_live.js | 110 +++++++++++------- 1 file changed, 65 insertions(+), 45 deletions(-) diff --git a/examples/data_visualization/earthquakes_live.js b/examples/data_visualization/earthquakes_live.js index 76f0fad5b0..fa464b9e13 100644 --- a/examples/data_visualization/earthquakes_live.js +++ b/examples/data_visualization/earthquakes_live.js @@ -1,44 +1,49 @@ -//earthquakes_live.js -//created by james b. pollack @imgntn on 12/5/2015 +// earthquakes_live.js +// exploratory implementation in prep for abstract latlong to earth graphing tool for VR +// shows all of the quakes in the past 24 hours reported by the USGS +// created by james b. pollack @imgntn on 12/5/2015 +// working notes: maybe try doing markers as boxes,rotated to the sphere normal, and with the height representing some value + Script.include('../libraries/promise.js'); var Promise = loadPromise(); Script.include('../libraries/tinyColor.js'); var tinyColor = loadTinyColor(); -var EARTH_SPHERE_RADIUS = 5; +//you could make it the size of the actual earth. +var EARTH_SPHERE_RADIUS = 6371; +var EARTH_SPHERE_RADIUS = 2; + var EARTH_CENTER_POSITION = Vec3.sum(MyAvatar.position, { - x: 5, + x: 0, y: 0, z: 0 }); -var EARTH_MODEL_URL='http://public.highfidelity.io/marketplace/hificontent/Scripts/planets/planets/earth.fbx'; +var EARTH_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/earthquakes_live/models/earth-noclouds.fbx'; + +var POLL_FOR_CHANGES = false; //USGS updates the data every five minutes -var CHECK_QUAKE_FREQUENCY = 300 * 1000; +var CHECK_QUAKE_FREQUENCY = 5 * 60 * 1000; var QUAKE_MARKER_DIMENSIONS = { - x: 0.1, - y: 0.1, - z: 0.1 + x: 0.01, + y: 0.01, + z: 0.01 }; function createEarth() { var earthProperties = { name: 'Earth', type: 'Model', - modelURL:EARTH_MODEL_URL, + modelURL: EARTH_MODEL_URL, position: EARTH_CENTER_POSITION, dimensions: { x: EARTH_SPHERE_RADIUS, y: EARTH_SPHERE_RADIUS, z: EARTH_SPHERE_RADIUS }, - // color: { - // red: 0, - // green: 100, - // blue: 150 - // }, + rotation: Quat.fromPitchYawRollDegrees(0, 90, 0), collisionsWillMove: false, userData: JSON.stringify({ grabbableKey: { @@ -50,26 +55,32 @@ function createEarth() { return Entities.addEntity(earthProperties) } -function plotLatitudeLongitude(radiusOfSphere, latitude, longitude) { - var tx = radiusOfSphere * Math.cos(latitude) * Math.cos(longitude); - var ty = radiusOfSphere * -Math.sin(latitude); - var tz = radiusOfSphere * Math.cos(latitude) * Math.sin(longitude); +function latLongToVector3(lat, lon, radius, height) { + var phi = (lat) * Math.PI / 180; + var theta = (lon - 180) * Math.PI / 180; + + var x = -(radius + height) * Math.cos(phi) * Math.cos(theta); + var y = (radius + height) * Math.sin(phi); + var z = (radius + height) * Math.cos(phi) * Math.sin(theta); + return { - x: tx, - y: ty, - z: tz - } + x: x, + y: y, + z: z + }; } function getQuakePosition(earthquake) { - var latitude = earthquake.geometry.coordinates[0]; - var longitude = earthquake.geometry.coordinates[1]; - var latlng = plotLatitudeLongitude(2.5, latitude, longitude); + var longitude = earthquake.geometry.coordinates[0]; + var latitude = earthquake.geometry.coordinates[1]; + var depth = earthquake.geometry.coordinates[2]; + + var latlng = latLongToVector3(latitude, longitude, EARTH_SPHERE_RADIUS / 2, 0); var position = EARTH_CENTER_POSITION; var finalPosition = Vec3.sum(position, latlng); - // print('finalpos::' + JSON.stringify(finalPosition)) + print('finalpos::' + JSON.stringify(finalPosition)) return finalPosition } @@ -95,14 +106,9 @@ function get(url) { }); } -function showEarthquake(snapshot) { - var earthquake = snapshot.val(); - print("Mag " + earthquake.mag + " at " + earthquake.place); -} - function createQuakeMarker(earthquake) { var markerProperties = { - name: 'Marker', + name: earthquake.properties.place, type: 'Sphere', dimensions: QUAKE_MARKER_DIMENSIONS, position: getQuakePosition(earthquake), @@ -110,7 +116,7 @@ function createQuakeMarker(earthquake) { color: getQuakeMarkerColor(earthquake) } - //print('marker properties::' + JSON.stringify(markerProperties)) + print('marker properties::' + JSON.stringify(markerProperties)) return Entities.addEntity(markerProperties); } @@ -137,7 +143,7 @@ function scale(value, min1, max1, min2, max2) { function processQuakes(earthquakes) { print('quakers length' + earthquakes.length) earthquakes.forEach(function(quake) { - // print('PROCESSING A QUAKE') + // print('PROCESSING A QUAKE') var marker = createQuakeMarker(quake); markers.push(marker); }) @@ -147,16 +153,18 @@ function processQuakes(earthquakes) { var quakea; var markers = []; -var earth = createEarth(); +var earth = createEarth(); -get(QUAKE_URL).then(function(response) { - print('got it::' + response.features.length) - quakes = response.features; - processQuakes(quakes); - //print("Success!" + JSON.stringify(response)); -}, function(error) { - print('error getting quakes') -}); +function getThenProcessQuakes() { + get(QUAKE_URL).then(function(response) { + print('got it::' + response.features.length) + quakes = response.features; + processQuakes(quakes); + //print("Success!" + JSON.stringify(response)); + }, function(error) { + print('error getting quakes') + }); +} function cleanupMarkers() { print('CLEANING UP MARKERS') @@ -170,4 +178,16 @@ function cleanupEarth() { } Script.scriptEnding.connect(cleanupMarkers); -Script.scriptEnding.connect(cleanupEarth); \ No newline at end of file +Script.scriptEnding.connect(cleanupEarth); + +//first draw +getThenProcessQuakes(); + + +var pollingInterval; +if (POLL_FOR_CHANGES === true) { + pollingInterval = Script.setInterval(function() { + cleanupMarkers(); + getThenProcessQuakes() + }, CHECK_QUAKE_FREQUENCY) +} \ No newline at end of file From f33f4cbcaefb08ae885baabf20f59d555189d58f Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 5 Dec 2015 16:22:17 -0800 Subject: [PATCH 357/401] cleanup --- examples/data_visualization/testQuakes.json | 153 -------------------- 1 file changed, 153 deletions(-) delete mode 100644 examples/data_visualization/testQuakes.json diff --git a/examples/data_visualization/testQuakes.json b/examples/data_visualization/testQuakes.json deleted file mode 100644 index a6429b79c8..0000000000 --- a/examples/data_visualization/testQuakes.json +++ /dev/null @@ -1,153 +0,0 @@ -{ - "type": "FeatureCollection", - "metadata": { - "generated": 1449347736000, - "url": "http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_hour.geojson", - "title": "USGS All Earthquakes, Past Hour", - "status": 200, - "api": "1.1.0", - "count": 4 - }, - "features": [{ - "type": "Feature", - "properties": { - "mag": 1.39, - "place": "17km ESE of Julian, California", - "time": 1449345604050, - "updated": 1449345856673, - "tz": -480, - "url": "http://earthquake.usgs.gov/earthquakes/eventpage/ci37498832", - "detail": "http://earthquake.usgs.gov/earthquakes/feed/v1.0/detail/ci37498832.geojson", - "felt": null, - "cdi": null, - "mmi": null, - "alert": null, - "status": "automatic", - "tsunami": 0, - "sig": 30, - "net": "ci", - "code": "37498832", - "ids": ",ci37498832,", - "sources": ",ci,", - "types": ",general-link,geoserve,nearby-cities,origin,phase-data,", - "nst": 32, - "dmin": 0.1379, - "rms": 0.21, - "gap": 68, - "magType": "ml", - "type": "earthquake", - "title": "M 1.4 - 17km ESE of Julian, California" - }, - "geometry": { - "type": "Point", - "coordinates": [-116.4293333, 33.0301667, 7.84] - }, - "id": "ci37498832" - }, { - "type": "Feature", - "properties": { - "mag": 1.12, - "place": "3km ESE of The Geysers, California", - "time": 1449344686690, - "updated": 1449344783260, - "tz": -480, - "url": "http://earthquake.usgs.gov/earthquakes/eventpage/nc72564866", - "detail": "http://earthquake.usgs.gov/earthquakes/feed/v1.0/detail/nc72564866.geojson", - "felt": null, - "cdi": null, - "mmi": null, - "alert": null, - "status": "automatic", - "tsunami": 0, - "sig": 19, - "net": "nc", - "code": "72564866", - "ids": ",nc72564866,", - "sources": ",nc,", - "types": ",general-link,geoserve,nearby-cities,origin,phase-data,", - "nst": 11, - "dmin": 0.01342, - "rms": 0.03, - "gap": 154, - "magType": "md", - "type": "earthquake", - "title": "M 1.1 - 3km ESE of The Geysers, California" - }, - "geometry": { - "type": "Point", - "coordinates": [-122.7176666, 38.7598343, 1.48] - }, - "id": "nc72564866" - }, { - "type": "Feature", - "properties": { - "mag": 1.99, - "place": "3km SE of The Geysers, California", - "time": 1449344287500, - "updated": 1449344383210, - "tz": -480, - "url": "http://earthquake.usgs.gov/earthquakes/eventpage/nc72564856", - "detail": "http://earthquake.usgs.gov/earthquakes/feed/v1.0/detail/nc72564856.geojson", - "felt": null, - "cdi": null, - "mmi": null, - "alert": null, - "status": "automatic", - "tsunami": 0, - "sig": 61, - "net": "nc", - "code": "72564856", - "ids": ",nc72564856,", - "sources": ",nc,", - "types": ",general-link,geoserve,nearby-cities,origin,phase-data,", - "nst": 13, - "dmin": 0.01626, - "rms": 0.02, - "gap": 72, - "magType": "md", - "type": "earthquake", - "title": "M 2.0 - 3km SE of The Geysers, California" - }, - "geometry": { - "type": "Point", - "coordinates": [-122.7203369, 38.7571678, 0.3] - }, - "id": "nc72564856" - }, { - "type": "Feature", - "properties": { - "mag": 2.36, - "place": "3km ESE of The Geysers, California", - "time": 1449344196380, - "updated": 1449344459434, - "tz": -480, - "url": "http://earthquake.usgs.gov/earthquakes/eventpage/nc72564836", - "detail": "http://earthquake.usgs.gov/earthquakes/feed/v1.0/detail/nc72564836.geojson", - "felt": 0, - "cdi": 1, - "mmi": null, - "alert": null, - "status": "automatic", - "tsunami": 0, - "sig": 86, - "net": "nc", - "code": "72564836", - "ids": ",nc72564836,", - "sources": ",nc,", - "types": ",dyfi,focal-mechanism,general-link,geoserve,nearby-cities,origin,phase-data,scitech-link,", - "nst": 36, - "dmin": 0.01395, - "rms": 0.07, - "gap": 38, - "magType": "md", - "type": "earthquake", - "title": "M 2.4 - 3km ESE of The Geysers, California" - }, - "geometry": { - "type": "Point", - "coordinates": [-122.722168, 38.7598343, 1.21] - }, - "id": "nc72564836" - }], - "bbox": [-122.722168, 33.0301667, 0.3, -116.4293333, 38.7598343, 7.84] -} \ No newline at end of file From 4999b34327822655d2063d2ec1bac96949997ead Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 5 Dec 2015 16:54:55 -0800 Subject: [PATCH 358/401] cleanup interval --- examples/data_visualization/earthquakes_live.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/examples/data_visualization/earthquakes_live.js b/examples/data_visualization/earthquakes_live.js index fa464b9e13..cb88ec33dc 100644 --- a/examples/data_visualization/earthquakes_live.js +++ b/examples/data_visualization/earthquakes_live.js @@ -80,7 +80,7 @@ function getQuakePosition(earthquake) { var position = EARTH_CENTER_POSITION; var finalPosition = Vec3.sum(position, latlng); - print('finalpos::' + JSON.stringify(finalPosition)) + //print('finalpos::' + JSON.stringify(finalPosition)) return finalPosition } @@ -116,7 +116,7 @@ function createQuakeMarker(earthquake) { color: getQuakeMarkerColor(earthquake) } - print('marker properties::' + JSON.stringify(markerProperties)) + // print('marker properties::' + JSON.stringify(markerProperties)) return Entities.addEntity(markerProperties); } @@ -177,14 +177,20 @@ function cleanupEarth() { Entities.deleteEntity(earth); } +function cleanupInterval() { + if (pollingInterval !== null) { + Script.clearInterval(pollingInterval) + } +} + Script.scriptEnding.connect(cleanupMarkers); Script.scriptEnding.connect(cleanupEarth); - +Script.scriptEnding.connect(cleanupInterval); //first draw getThenProcessQuakes(); +var pollingInterval = null; -var pollingInterval; if (POLL_FOR_CHANGES === true) { pollingInterval = Script.setInterval(function() { cleanupMarkers(); From 4a5b9bd523391320a08aa203091c24b74779c2fa Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 5 Dec 2015 16:57:09 -0800 Subject: [PATCH 359/401] start position --- examples/data_visualization/earthquakes_live.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/examples/data_visualization/earthquakes_live.js b/examples/data_visualization/earthquakes_live.js index cb88ec33dc..eae1333089 100644 --- a/examples/data_visualization/earthquakes_live.js +++ b/examples/data_visualization/earthquakes_live.js @@ -14,11 +14,17 @@ var tinyColor = loadTinyColor(); var EARTH_SPHERE_RADIUS = 6371; var EARTH_SPHERE_RADIUS = 2; -var EARTH_CENTER_POSITION = Vec3.sum(MyAvatar.position, { +var EARTH_CENTER_POSITION = Vec3.sum(Vec3.sum(MyAvatar.position, { x: 0, - y: 0, + y: 0.5, z: 0 -}); +}), Vec3.multiply(EARTH_SPHERE_RADIUS, Quat.getFront(Camera.getOrientation()))); + +// var EARTH_CENTER_POSITION = Vec3.sum(MyAvatar.position, { +// x: 0, +// y: 0, +// z: 0 +// }); var EARTH_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/earthquakes_live/models/earth-noclouds.fbx'; From 7fc3d0f34edebde14f630bfea9c608fa3e382142 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 5 Dec 2015 16:58:50 -0800 Subject: [PATCH 360/401] header --- examples/data_visualization/earthquakes_live.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/data_visualization/earthquakes_live.js b/examples/data_visualization/earthquakes_live.js index eae1333089..3090b00e44 100644 --- a/examples/data_visualization/earthquakes_live.js +++ b/examples/data_visualization/earthquakes_live.js @@ -1,7 +1,13 @@ // earthquakes_live.js +// // exploratory implementation in prep for abstract latlong to earth graphing tool for VR // shows all of the quakes in the past 24 hours reported by the USGS +// // created by james b. pollack @imgntn on 12/5/2015 +// 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 +// // working notes: maybe try doing markers as boxes,rotated to the sphere normal, and with the height representing some value Script.include('../libraries/promise.js'); From d518def97477cd11e45fecdc842e47c220b68f39 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 5 Dec 2015 17:01:54 -0800 Subject: [PATCH 361/401] poll by default --- examples/data_visualization/earthquakes_live.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/data_visualization/earthquakes_live.js b/examples/data_visualization/earthquakes_live.js index 3090b00e44..2457a0646a 100644 --- a/examples/data_visualization/earthquakes_live.js +++ b/examples/data_visualization/earthquakes_live.js @@ -34,7 +34,7 @@ var EARTH_CENTER_POSITION = Vec3.sum(Vec3.sum(MyAvatar.position, { var EARTH_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/earthquakes_live/models/earth-noclouds.fbx'; -var POLL_FOR_CHANGES = false; +var POLL_FOR_CHANGES = true; //USGS updates the data every five minutes var CHECK_QUAKE_FREQUENCY = 5 * 60 * 1000; From 945b5bd00f5c9d0a1caf2c5bf90347ac125411fe Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 5 Dec 2015 17:11:27 -0800 Subject: [PATCH 362/401] cleanup --- examples/data_visualization/earthquakes_live.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/examples/data_visualization/earthquakes_live.js b/examples/data_visualization/earthquakes_live.js index 2457a0646a..826c833243 100644 --- a/examples/data_visualization/earthquakes_live.js +++ b/examples/data_visualization/earthquakes_live.js @@ -26,12 +26,6 @@ var EARTH_CENTER_POSITION = Vec3.sum(Vec3.sum(MyAvatar.position, { z: 0 }), Vec3.multiply(EARTH_SPHERE_RADIUS, Quat.getFront(Camera.getOrientation()))); -// var EARTH_CENTER_POSITION = Vec3.sum(MyAvatar.position, { -// x: 0, -// y: 0, -// z: 0 -// }); - var EARTH_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/earthquakes_live/models/earth-noclouds.fbx'; var POLL_FOR_CHANGES = true; From a899fe0e1b3eacca35d79c2cd0b4ce889d0dae5f Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 5 Dec 2015 17:26:11 -0800 Subject: [PATCH 363/401] fix typo --- examples/data_visualization/earthquakes_live.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/data_visualization/earthquakes_live.js b/examples/data_visualization/earthquakes_live.js index 826c833243..272c933696 100644 --- a/examples/data_visualization/earthquakes_live.js +++ b/examples/data_visualization/earthquakes_live.js @@ -44,6 +44,7 @@ function createEarth() { type: 'Model', modelURL: EARTH_MODEL_URL, position: EARTH_CENTER_POSITION, + collisionsWillMove:true, dimensions: { x: EARTH_SPHERE_RADIUS, y: EARTH_SPHERE_RADIUS, @@ -116,6 +117,7 @@ function createQuakeMarker(earthquake) { var markerProperties = { name: earthquake.properties.place, type: 'Sphere', + parentID:earth, dimensions: QUAKE_MARKER_DIMENSIONS, position: getQuakePosition(earthquake), lifetime: 6000, @@ -156,7 +158,7 @@ function processQuakes(earthquakes) { print('markers length:' + markers.length) } -var quakea; +var quakes; var markers = []; var earth = createEarth(); From ade32cbf6137fada8eb5661c846779ccd88bc015 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 5 Dec 2015 17:30:38 -0800 Subject: [PATCH 364/401] remove collisions and add parenting --- examples/data_visualization/earthquakes_live.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/data_visualization/earthquakes_live.js b/examples/data_visualization/earthquakes_live.js index 272c933696..69d639238c 100644 --- a/examples/data_visualization/earthquakes_live.js +++ b/examples/data_visualization/earthquakes_live.js @@ -44,7 +44,6 @@ function createEarth() { type: 'Model', modelURL: EARTH_MODEL_URL, position: EARTH_CENTER_POSITION, - collisionsWillMove:true, dimensions: { x: EARTH_SPHERE_RADIUS, y: EARTH_SPHERE_RADIUS, From 30b32765b915f7e4f5947883fdfc601e4bae9f86 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 5 Dec 2015 17:32:02 -0800 Subject: [PATCH 365/401] make earth grabbable to show parenting --- examples/data_visualization/earthquakes_live.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/data_visualization/earthquakes_live.js b/examples/data_visualization/earthquakes_live.js index 69d639238c..579c981b2d 100644 --- a/examples/data_visualization/earthquakes_live.js +++ b/examples/data_visualization/earthquakes_live.js @@ -51,11 +51,11 @@ function createEarth() { }, rotation: Quat.fromPitchYawRollDegrees(0, 90, 0), collisionsWillMove: false, - userData: JSON.stringify({ - grabbableKey: { - grabbable: false - } - }) + // userData: JSON.stringify({ + // grabbableKey: { + // grabbable: false + // } + // }) } return Entities.addEntity(earthProperties) From 188c477f7e32885b716caa99b6a56fbf380f53f3 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Sat, 5 Dec 2015 17:32:32 -0800 Subject: [PATCH 366/401] Fix render rate. Depending on how the threads get assigned, the actual render rate (not just the stats) could be as little as a third of what is targetted. That's because the code was insisting on an empty texture escrow before our update/render cycle could begin, and otherwise just waits for the next whole cycle. On my MacbookPro, this was regularly giving a render average of 20fps instead of 60. --- .../display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 8593da1573..d306c23dc0 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -157,7 +157,7 @@ OpenGLDisplayPlugin::OpenGLDisplayPlugin() { }); connect(&_timer, &QTimer::timeout, this, [&] { - if (_active && _sceneTextureEscrow.depth() < 1) { + if (_active && _sceneTextureEscrow.depth() <= 1) { emit requestRender(); } }); From 906540272ec77dfa1cb96ae46cff1d6de8004242 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 5 Dec 2015 17:39:43 -0800 Subject: [PATCH 367/401] disable collisions for now because of shapetype --- examples/data_visualization/earthquakes_live.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/data_visualization/earthquakes_live.js b/examples/data_visualization/earthquakes_live.js index 579c981b2d..3498885ff6 100644 --- a/examples/data_visualization/earthquakes_live.js +++ b/examples/data_visualization/earthquakes_live.js @@ -50,7 +50,9 @@ function createEarth() { z: EARTH_SPHERE_RADIUS }, rotation: Quat.fromPitchYawRollDegrees(0, 90, 0), - collisionsWillMove: false, + // collisionsWillMove: true, + //if you have a shapetype it blocks the smaller markers + // shapeType:'sphere' // userData: JSON.stringify({ // grabbableKey: { // grabbable: false @@ -119,6 +121,7 @@ function createQuakeMarker(earthquake) { parentID:earth, dimensions: QUAKE_MARKER_DIMENSIONS, position: getQuakePosition(earthquake), + ignoreForCollisions:true, lifetime: 6000, color: getQuakeMarkerColor(earthquake) } From 7859241ad31d1ad467eb22e1b4512f6178f57e10 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 5 Dec 2015 17:43:13 -0800 Subject: [PATCH 368/401] spin the earth for fun --- .../data_visualization/earthquakes_live.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/examples/data_visualization/earthquakes_live.js b/examples/data_visualization/earthquakes_live.js index 3498885ff6..f625f9afb0 100644 --- a/examples/data_visualization/earthquakes_live.js +++ b/examples/data_visualization/earthquakes_live.js @@ -185,6 +185,7 @@ function cleanupMarkers() { function cleanupEarth() { Entities.deleteEntity(earth); + Script.update.disconnect(spinEarth); } function cleanupInterval() { @@ -196,7 +197,7 @@ function cleanupInterval() { Script.scriptEnding.connect(cleanupMarkers); Script.scriptEnding.connect(cleanupEarth); Script.scriptEnding.connect(cleanupInterval); -//first draw + getThenProcessQuakes(); var pollingInterval = null; @@ -206,4 +207,17 @@ if (POLL_FOR_CHANGES === true) { cleanupMarkers(); getThenProcessQuakes() }, CHECK_QUAKE_FREQUENCY) -} \ No newline at end of file +} + + +function spinEarth(){ +Entities.editEntity(earth,{ + angularVelocity:{ + x:0, + y:0.5, + z:0 + } +}) +} + +Script.update.connect(spinEarth) \ No newline at end of file From 378b71d7011a097262f5f31764981c99551606fa Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Sat, 5 Dec 2015 17:51:55 -0800 Subject: [PATCH 369/401] dont spin by default --- examples/data_visualization/earthquakes_live.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/data_visualization/earthquakes_live.js b/examples/data_visualization/earthquakes_live.js index f625f9afb0..8594f827a0 100644 --- a/examples/data_visualization/earthquakes_live.js +++ b/examples/data_visualization/earthquakes_live.js @@ -28,6 +28,7 @@ var EARTH_CENTER_POSITION = Vec3.sum(Vec3.sum(MyAvatar.position, { var EARTH_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/earthquakes_live/models/earth-noclouds.fbx'; +var SHOULD_SPIN=false; var POLL_FOR_CHANGES = true; //USGS updates the data every five minutes var CHECK_QUAKE_FREQUENCY = 5 * 60 * 1000; @@ -214,10 +215,12 @@ function spinEarth(){ Entities.editEntity(earth,{ angularVelocity:{ x:0, - y:0.5, + y:0.25, z:0 } }) } -Script.update.connect(spinEarth) \ No newline at end of file +if(SHOULD_SPIN===true){ + Script.update.connect(spinEarth); +} From 138125faab4ea4a43ad960243702edc12f6ff61a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 6 Dec 2015 05:42:51 -0800 Subject: [PATCH 370/401] fix-up parentJointIndex in terse logging --- libraries/entities/src/EntityTree.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 2752473b07..892b186a25 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -740,6 +740,14 @@ void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList= 0) { + quint16 value = properties.getParentJointIndex(); + changedProperties[index] = QString("parentJointIndex:") + QString::number((int)value); + } + } } int EntityTree::processEditPacketData(NLPacket& packet, const unsigned char* editData, int maxLength, From 9a80c4d681005bfb805410ff0d95de35b67ea196 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 6 Dec 2015 05:43:23 -0800 Subject: [PATCH 371/401] call locationChanged on children of joints when joints change --- interface/src/avatar/Avatar.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 2c8d970336..7d407046d6 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -201,6 +201,7 @@ void Avatar::simulate(float deltaTime) { _skeletonModel.getRig()->copyJointsFromJointData(_jointData); _skeletonModel.simulate(deltaTime, _hasNewJointRotations || _hasNewJointTranslations); simulateAttachments(deltaTime); + locationChanged(); // joints changed, so if there are any children, update them. _hasNewJointRotations = false; _hasNewJointTranslations = false; } From edc312199ddaac0efea77f3912e94d0111b7bffc Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 6 Dec 2015 06:16:47 -0800 Subject: [PATCH 372/401] rename a method to match convention in https://docs.google.com/document/d/1LFCmkK26JMVs8Ci33L4Yrle6lL7UU7oxthsWfddzZXQ/edit# --- libraries/shared/src/SpatiallyNestable.cpp | 4 ++-- libraries/shared/src/SpatiallyNestable.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 0d7d2a7652..0a2310e43e 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -232,7 +232,7 @@ const Transform SpatiallyNestable::getTransform(int jointIndex) const { // this returns the world-space transform for this object. It finds its parent's transform (which may // cause this object's parent to query its parent, etc) and multiplies this object's local transform onto it. Transform worldTransform = getTransform(); - Transform jointInObjectFrame = getJointTransformInObjectFrame(jointIndex); + Transform jointInObjectFrame = getJointTransformInModelFrame(jointIndex); Transform jointInWorldFrame; Transform::mult(jointInWorldFrame, worldTransform, jointInObjectFrame); return jointInWorldFrame; @@ -339,7 +339,7 @@ QList SpatiallyNestable::getChildren() const { return children; } -const Transform SpatiallyNestable::getJointTransformInObjectFrame(int jointIndex) const { +const Transform SpatiallyNestable::getJointTransformInModelFrame(int jointIndex) const { Transform jointInObjectFrame; glm::vec3 position = getJointTranslation(jointIndex); glm::quat orientation = getJointRotation(jointIndex); diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index f3056d9a4f..da7aff6b52 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -91,7 +91,7 @@ public: NestableTypes::NestableType getNestableType() const { return _nestableType; } // this object's frame - virtual const Transform getJointTransformInObjectFrame(int jointIndex) const; + virtual const Transform getJointTransformInModelFrame(int jointIndex) const; virtual glm::quat getJointRotation(int index) const { assert(false); return glm::quat(); } virtual glm::vec3 getJointTranslation(int index) const { assert(false); return glm::vec3(); } From a948ae5f1943f7a4e8d51244f80a6ef7348f0e26 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 6 Dec 2015 10:48:00 -0800 Subject: [PATCH 373/401] children of avatar joints might be right, now --- interface/src/avatar/Avatar.cpp | 11 ++++++++++ interface/src/avatar/Avatar.h | 3 +++ libraries/animation/src/Rig.cpp | 20 +++++++++++++++++++ libraries/animation/src/Rig.h | 6 ++++-- .../src/RenderableModelEntityItem.cpp | 8 ++++---- .../src/RenderableModelEntityItem.h | 6 +++--- libraries/entities/src/EntityItem.h | 6 +++--- libraries/render-utils/src/Model.cpp | 8 ++++++++ libraries/render-utils/src/Model.h | 4 ++++ libraries/shared/src/SpatiallyNestable.cpp | 12 +++++------ libraries/shared/src/SpatiallyNestable.h | 4 ++-- 11 files changed, 68 insertions(+), 20 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 7d407046d6..29423f4d79 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -869,6 +869,17 @@ glm::vec3 Avatar::getJointTranslation(int index) const { return translation; } +glm::quat Avatar::getJointRotationInModelFrame(int index) const { + glm::quat rotation; + _skeletonModel.getJointRotationInModelFrame(index, rotation); + return Quaternions::Y_180 * rotation; +} + +glm::vec3 Avatar::getJointTranslationInModelFrame(int index) const { + glm::vec3 translation; + _skeletonModel.getJointTranslationInModelFrame(index, translation); + return Quaternions::Y_180 * translation; +} int Avatar::getJointIndex(const QString& name) const { if (QThread::currentThread() != thread()) { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index dc5014a7ea..3f8b955b6c 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -108,6 +108,9 @@ public: virtual int getJointIndex(const QString& name) const; virtual QStringList getJointNames() const; + virtual glm::quat getJointRotationInModelFrame(int index) const; + virtual glm::vec3 getJointTranslationInModelFrame(int index) const; + virtual void setFaceModelURL(const QUrl& faceModelURL); virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); virtual void setAttachmentData(const QVector& attachmentData); diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 8fb56ed699..04c9ba173f 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -373,6 +373,16 @@ bool Rig::getJointRotation(int jointIndex, glm::quat& rotation) const { } } +bool Rig::getJointRotationInModelFrame(int jointIndex, glm::quat& rotation) const { + QReadLocker readLock(&_externalPoseSetLock); + if (jointIndex >= 0 && jointIndex < (int)_externalPoseSet._absolutePoses.size()) { + rotation = _externalPoseSet._absolutePoses[jointIndex].rot; + return true; + } else { + return false; + } +} + bool Rig::getJointTranslation(int jointIndex, glm::vec3& translation) const { QReadLocker readLock(&_externalPoseSetLock); if (jointIndex >= 0 && jointIndex < (int)_externalPoseSet._relativePoses.size()) { @@ -383,6 +393,16 @@ bool Rig::getJointTranslation(int jointIndex, glm::vec3& translation) const { } } +bool Rig::getJointTranslationInModelFrame(int jointIndex, glm::vec3& translation) const { + QReadLocker readLock(&_externalPoseSetLock); + if (jointIndex >= 0 && jointIndex < (int)_externalPoseSet._absolutePoses.size()) { + translation = _externalPoseSet._absolutePoses[jointIndex].trans; + return true; + } else { + return false; + } +} + bool Rig::getJointCombinedRotation(int jointIndex, glm::quat& result, const glm::quat& rotation) const { // AJT: TODO: used by attachments ASSERT(false); diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 64ce8c52ef..956a07c543 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -129,10 +129,12 @@ public: // geometry space (thread-safe) bool getJointRotation(int jointIndex, glm::quat& rotation) const; - - // geometry space (thread-safe) bool getJointTranslation(int jointIndex, glm::vec3& translation) const; + // model space (thread-safe) + bool getJointRotationInModelFrame(int jointIndex, glm::quat& rotation) const; + bool getJointTranslationInModelFrame(int jointIndex, glm::vec3& translation) const; + // legacy bool getJointCombinedRotation(int jointIndex, glm::quat& result, const glm::quat& rotation) const; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 393c0dc0dc..8f2b54b35a 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -565,20 +565,20 @@ bool RenderableModelEntityItem::contains(const glm::vec3& point) const { return false; } -glm::quat RenderableModelEntityItem::getJointRotation(int index) const { +glm::quat RenderableModelEntityItem::getJointRotationInModelFrame(int index) const { if (_model) { glm::quat result; - if (_model->getJointRotation(index, result)) { + if (_model->getJointRotationInModelFrame(index, result)) { return result; } } return glm::quat(); } -glm::vec3 RenderableModelEntityItem::getJointTranslation(int index) const { +glm::vec3 RenderableModelEntityItem::getJointTranslationInModelFrame(int index) const { if (_model) { glm::vec3 result; - if (_model->getJointTranslation(index, result)) { + if (_model->getJointTranslationInModelFrame(index, result)) { return result; } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 2ee4aeb73e..e73289174c 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -67,9 +67,9 @@ public: virtual bool contains(const glm::vec3& point) const override; - // these are in the frame of this object - virtual glm::quat getJointRotation(int index) const; - virtual glm::vec3 getJointTranslation(int index) const; + // these are in the frame of this object (model space) + virtual glm::quat getJointRotationInModelFrame(int index) const; + virtual glm::vec3 getJointTranslationInModelFrame(int index) const; private: void remapTextures(); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 761208cb06..bfc178f2c3 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -378,9 +378,9 @@ public: QList getActionsOfType(EntityActionType typeToGet); - // these are in the frame of this object - virtual glm::quat getJointRotation(int index) const { return glm::quat(); } - virtual glm::vec3 getJointTranslation(int index) const { return glm::vec3(0.0f); } + // these are in the frame of this object (model space) + virtual glm::quat getJointRotationInModelFrame(int index) const { return glm::quat(); } + virtual glm::vec3 getJointTranslationInModelFrame(int index) const { return glm::vec3(0.0f); } protected: diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index f566d0879d..82b3228f0b 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -765,6 +765,14 @@ bool Model::getJointTranslation(int jointIndex, glm::vec3& translation) const { return _rig->getJointTranslation(jointIndex, translation); } +bool Model::getJointRotationInModelFrame(int jointIndex, glm::quat& rotation) const { + return _rig->getJointRotationInModelFrame(jointIndex, rotation); +} + +bool Model::getJointTranslationInModelFrame(int jointIndex, glm::vec3& translation) const { + return _rig->getJointTranslationInModelFrame(jointIndex, translation); +} + bool Model::getJointCombinedRotation(int jointIndex, glm::quat& rotation) const { return _rig->getJointCombinedRotation(jointIndex, rotation, _rotation); } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index e8e9f93986..287e0046f0 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -166,6 +166,10 @@ public: bool getJointRotation(int jointIndex, glm::quat& rotation) const; bool getJointTranslation(int jointIndex, glm::vec3& translation) const; + // model frame + bool getJointRotationInModelFrame(int jointIndex, glm::quat& rotation) const; + bool getJointTranslationInModelFrame(int jointIndex, glm::vec3& translation) const; + /// Returns the index of the parent of the indexed joint, or -1 if not found. int getParentJointIndex(int jointIndex) const; diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 0a2310e43e..7d61442ad1 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -340,12 +340,12 @@ QList SpatiallyNestable::getChildren() const { } const Transform SpatiallyNestable::getJointTransformInModelFrame(int jointIndex) const { - Transform jointInObjectFrame; - glm::vec3 position = getJointTranslation(jointIndex); - glm::quat orientation = getJointRotation(jointIndex); - jointInObjectFrame.setRotation(orientation); - jointInObjectFrame.setTranslation(position); - return jointInObjectFrame; + Transform jointTransformInObjectFrame; + glm::vec3 position = getJointTranslationInModelFrame(jointIndex); + glm::quat orientation = getJointRotationInModelFrame(jointIndex); + jointTransformInObjectFrame.setRotation(orientation); + jointTransformInObjectFrame.setTranslation(position); + return jointTransformInObjectFrame; } SpatiallyNestablePointer SpatiallyNestable::getThisPointer() const { diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index da7aff6b52..0d3b00e0eb 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -92,8 +92,8 @@ public: // this object's frame virtual const Transform getJointTransformInModelFrame(int jointIndex) const; - virtual glm::quat getJointRotation(int index) const { assert(false); return glm::quat(); } - virtual glm::vec3 getJointTranslation(int index) const { assert(false); return glm::vec3(); } + virtual glm::quat getJointRotationInModelFrame(int index) const { assert(false); return glm::quat(); } + virtual glm::vec3 getJointTranslationInModelFrame(int index) const { assert(false); return glm::vec3(); } SpatiallyNestablePointer getThisPointer() const; From fff4e3e831ef29114a97b62a3c38c55e4e5b3001 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 6 Dec 2015 12:01:30 -0800 Subject: [PATCH 374/401] make SpatiallyNestable setters take values by reference --- interface/src/avatar/Avatar.cpp | 4 ++-- interface/src/avatar/Avatar.h | 4 ++-- libraries/avatars/src/AvatarData.cpp | 4 ++-- libraries/avatars/src/AvatarData.h | 4 ++-- libraries/shared/src/SpatiallyNestable.cpp | 18 +++++++++--------- libraries/shared/src/SpatiallyNestable.h | 18 +++++++++--------- 6 files changed, 26 insertions(+), 26 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 29423f4d79..62ec4de1b2 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -1157,12 +1157,12 @@ glm::quat Avatar::getRightPalmRotation() { return rightRotation; } -void Avatar::setPosition(const glm::vec3 position) { +void Avatar::setPosition(const glm::vec3& position) { AvatarData::setPosition(position); updateAttitude(); } -void Avatar::setOrientation(const glm::quat orientation) { +void Avatar::setOrientation(const glm::quat& orientation) { AvatarData::setOrientation(orientation); updateAttitude(); } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 3f8b955b6c..e2eeab2c3d 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -158,8 +158,8 @@ public: void setMotionState(AvatarMotionState* motionState) { _motionState = motionState; } AvatarMotionState* getMotionState() { return _motionState; } - virtual void setPosition(glm::vec3 position); - virtual void setOrientation(glm::quat orientation); + virtual void setPosition(const glm::vec3& position); + virtual void setOrientation(const glm::quat& orientation); public slots: diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 76575909aa..fe03fb09cd 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -1626,10 +1626,10 @@ void AvatarData::setBodyRoll(float bodyRoll) { setOrientation(glm::quat(glm::radians(eulerAngles))); } -void AvatarData::setPosition(const glm::vec3 position) { +void AvatarData::setPosition(const glm::vec3& position) { SpatiallyNestable::setPosition(position); } -void AvatarData::setOrientation(const glm::quat orientation) { +void AvatarData::setOrientation(const glm::quat& orientation) { SpatiallyNestable::setOrientation(orientation); } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 8419ce2154..0db259ceda 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -201,8 +201,8 @@ public: float getBodyRoll() const; void setBodyRoll(float bodyRoll); - virtual void setPosition(glm::vec3 position); - virtual void setOrientation(glm::quat orientation); + virtual void setPosition(const glm::vec3& position); + virtual void setOrientation(const glm::quat& orientation); void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time. void startCapture(); // start/end of the period in which the latest values are about to be captured for camera, etc. diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 7d61442ad1..77b5f57bfb 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -91,7 +91,7 @@ void SpatiallyNestable::forgetChild(SpatiallyNestablePointer newChild) const { }); } -void SpatiallyNestable::setParentID(const QUuid parentID) { +void SpatiallyNestable::setParentID(const QUuid& parentID) { if (_parentID != parentID) { _parentID = parentID; _parentKnowsMe = false; @@ -188,7 +188,7 @@ glm::vec3 SpatiallyNestable::getPosition(int jointIndex) const { return getTransform(jointIndex).getTranslation(); } -void SpatiallyNestable::setPosition(glm::vec3 position) { +void SpatiallyNestable::setPosition(const glm::vec3& position) { Transform parentTransform = getParentTransform(); Transform myWorldTransform; _transformLock.withWriteLock([&] { @@ -207,7 +207,7 @@ glm::quat SpatiallyNestable::getOrientation(int jointIndex) const { return getTransform(jointIndex).getRotation(); } -void SpatiallyNestable::setOrientation(glm::quat orientation) { +void SpatiallyNestable::setOrientation(const glm::quat& orientation) { Transform parentTransform = getParentTransform(); Transform myWorldTransform; _transformLock.withWriteLock([&] { @@ -238,7 +238,7 @@ const Transform SpatiallyNestable::getTransform(int jointIndex) const { return jointInWorldFrame; } -void SpatiallyNestable::setTransform(const Transform transform) { +void SpatiallyNestable::setTransform(const Transform& transform) { Transform parentTransform = getParentTransform(); _transformLock.withWriteLock([&] { Transform::inverseMult(_transform, parentTransform, transform); @@ -259,7 +259,7 @@ glm::vec3 SpatiallyNestable::getScale(int jointIndex) const { return getScale(); } -void SpatiallyNestable::setScale(glm::vec3 scale) { +void SpatiallyNestable::setScale(const glm::vec3& scale) { _transformLock.withWriteLock([&] { _transform.setScale(scale); }); @@ -274,7 +274,7 @@ const Transform SpatiallyNestable::getLocalTransform() const { return result; } -void SpatiallyNestable::setLocalTransform(const Transform transform) { +void SpatiallyNestable::setLocalTransform(const Transform& transform) { _transformLock.withWriteLock([&] { _transform = transform; }); @@ -289,7 +289,7 @@ glm::vec3 SpatiallyNestable::getLocalPosition() const { return result; } -void SpatiallyNestable::setLocalPosition(glm::vec3 position) { +void SpatiallyNestable::setLocalPosition(const glm::vec3& position) { _transformLock.withWriteLock([&] { _transform.setTranslation(position); }); @@ -304,7 +304,7 @@ glm::quat SpatiallyNestable::getLocalOrientation() const { return result; } -void SpatiallyNestable::setLocalOrientation(glm::quat orientation) { +void SpatiallyNestable::setLocalOrientation(const glm::quat& orientation) { _transformLock.withWriteLock([&] { _transform.setRotation(orientation); }); @@ -319,7 +319,7 @@ glm::vec3 SpatiallyNestable::getLocalScale() const { return result; } -void SpatiallyNestable::setLocalScale(glm::vec3 scale) { +void SpatiallyNestable::setLocalScale(const glm::vec3& scale) { _transformLock.withWriteLock([&] { _transform.setScale(scale); }); diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 0d3b00e0eb..dc1be54219 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -42,7 +42,7 @@ public: virtual void setID(const QUuid& id) { _id = id; } virtual const QUuid getParentID() const { return _parentID; } - virtual void setParentID(const QUuid parentID); + virtual void setParentID(const QUuid& parentID); virtual quint16 getParentJointIndex() const { return _parentJointIndex; } virtual void setParentJointIndex(quint16 parentJointIndex) { _parentJointIndex = parentJointIndex; } @@ -55,19 +55,19 @@ public: // world frame virtual const Transform getTransform() const; - virtual void setTransform(const Transform transform); + virtual void setTransform(const Transform& transform); virtual Transform getParentTransform() const; virtual glm::vec3 getPosition() const; - virtual void setPosition(glm::vec3 position); + virtual void setPosition(const glm::vec3& position); virtual glm::quat getOrientation() const; virtual glm::quat getOrientation(int jointIndex) const; - virtual void setOrientation(glm::quat orientation); + virtual void setOrientation(const glm::quat& orientation); virtual glm::vec3 getScale() const; - virtual void setScale(glm::vec3 scale); + virtual void setScale(const glm::vec3& scale); // get world-frame values for a specific joint virtual const Transform getTransform(int jointIndex) const; @@ -76,16 +76,16 @@ public: // object's parent's frame virtual const Transform getLocalTransform() const; - virtual void setLocalTransform(const Transform transform); + virtual void setLocalTransform(const Transform& transform); virtual glm::vec3 getLocalPosition() const; - virtual void setLocalPosition(glm::vec3 position); + virtual void setLocalPosition(const glm::vec3& position); virtual glm::quat getLocalOrientation() const; - virtual void setLocalOrientation(glm::quat orientation); + virtual void setLocalOrientation(const glm::quat& orientation); virtual glm::vec3 getLocalScale() const; - virtual void setLocalScale(glm::vec3 scale); + virtual void setLocalScale(const glm::vec3& scale); QList getChildren() const; NestableTypes::NestableType getNestableType() const { return _nestableType; } From f0fb9966ada9f89ec58ba5612cfae35adb1e9156 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 6 Dec 2015 12:34:41 -0800 Subject: [PATCH 375/401] expose parent-joint-index to edit.js --- examples/html/entityProperties.html | 9 +++++++ .../entities/src/EntityScriptingInterface.cpp | 27 +++++++------------ 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index bef5c825c2..186b2ee828 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -226,6 +226,7 @@ var elRescaleDimensionsButton = document.getElementById("dimension-rescale-button"); var elParentID = document.getElementById("property-parent-id"); + var elParentJointIndex = document.getElementById("property-parent-joint-index"); var elRegistrationX = document.getElementById("property-reg-x"); var elRegistrationY = document.getElementById("property-reg-y"); @@ -456,6 +457,7 @@ elDimensionsZ.value = properties.dimensions.z.toFixed(2); elParentID.value = properties.parentID; + elParentJointIndex.value = properties.parentJointIndex; elRegistrationX.value = properties.registrationPoint.x.toFixed(2); elRegistrationY.value = properties.registrationPoint.y.toFixed(2); @@ -671,6 +673,7 @@ elDimensionsZ.addEventListener('change', dimensionsChangeFunction); elParentID.addEventListener('change', createEmitTextPropertyUpdateFunction('parentID')); + elParentJointIndex.addEventListener('change', createEmitNumberPropertyUpdateFunction('parentJointIndex')); var registrationChangeFunction = createEmitVec3PropertyUpdateFunction( 'registrationPoint', elRegistrationX, elRegistrationY, elRegistrationZ); @@ -1067,6 +1070,12 @@
+
+ ParentJointIndex +
+ +
+
Registration
diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 23fbac13cf..2488470bfa 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -201,28 +201,21 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties script bool updatedEntity = false; _entityTree->withWriteLock([&] { - if (scriptSideProperties.parentDependentPropertyChanged()) { - // if the script set a location property but didn't include parent information, grab the needed - // properties from the entity. - if (!scriptSideProperties.parentIDChanged() || !scriptSideProperties.parentJointIndexChanged()) { - EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); - if (entity && !scriptSideProperties.parentIDChanged()) { - properties.setParentID(entity->getParentID()); - } - if (entity && !scriptSideProperties.parentJointIndexChanged()) { - properties.setParentJointIndex(entity->getParentJointIndex()); - } + if (scriptSideProperties.parentDependentPropertyChanged() || + scriptSideProperties.parentIDChanged() || scriptSideProperties.parentJointIndexChanged()) { + // All of parentID, parentJointIndex, position, rotation are needed to make sense of any of them. + // If any of these changed, pull any missing properties from the entity. + EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); + if (entity && !scriptSideProperties.parentIDChanged()) { + properties.setParentID(entity->getParentID()); + } + if (entity && !scriptSideProperties.parentJointIndexChanged()) { + properties.setParentJointIndex(entity->getParentJointIndex()); } - } - if (scriptSideProperties.parentIDChanged() || scriptSideProperties.parentJointIndexChanged()) { - // if the script set parentID or parentJointIndex but didn't include position and rotation, grab - // the missing properties from the entity if (!scriptSideProperties.localPositionChanged() && !scriptSideProperties.positionChanged()) { - EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); properties.setPosition(entity->getPosition()); } if (!scriptSideProperties.localRotationChanged() && !scriptSideProperties.rotationChanged()) { - EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); properties.setRotation(entity->getOrientation()); } } From 3cc423ca03800da8c3317de05f186f474cfeb632 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 6 Dec 2015 17:55:48 -0800 Subject: [PATCH 376/401] remap IDs when importing entities --- interface/src/Application.cpp | 1 + libraries/entities/src/EntityTree.cpp | 6 ++++ libraries/entities/src/EntityTree.h | 2 ++ libraries/entities/src/RemapIDOperator.cpp | 33 ++++++++++++++++++++++ libraries/entities/src/RemapIDOperator.h | 30 ++++++++++++++++++++ 5 files changed, 72 insertions(+) create mode 100644 libraries/entities/src/RemapIDOperator.cpp create mode 100644 libraries/entities/src/RemapIDOperator.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9e98b51442..6ef440843f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2480,6 +2480,7 @@ bool Application::importEntities(const QString& urlOrFilename) { bool success = _entityClipboard->readFromURL(url.toString()); if (success) { + _entityClipboard->remapIDs(); _entityClipboard->reaverageOctreeElements(); } return success; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 892b186a25..c0ef3e0fe3 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -24,6 +24,7 @@ #include "EntitiesLogging.h" #include "RecurseOctreeToMapOperator.h" #include "LogHandler.h" +#include "RemapIDOperator.h" static const quint64 DELETED_ENTITIES_EXTRA_USECS_TO_CONSIDER = USECS_PER_MSEC * 50; @@ -1194,6 +1195,11 @@ bool EntityTree::sendEntitiesOperation(OctreeElementPointer element, void* extra return true; } +void EntityTree::remapIDs() { + RemapIDOperator theOperator; + recurseTreeWithOperator(&theOperator); +} + bool EntityTree::writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues) { if (! entityDescription.contains("Entities")) { entityDescription["Entities"] = QVariantList(); diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index d1e0462f64..97a23124bb 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -196,6 +196,8 @@ public: bool wantTerseEditLogging() const { return _wantTerseEditLogging; } void setWantTerseEditLogging(bool value) { _wantTerseEditLogging = value; } + void remapIDs(); + bool writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues); bool readFromMap(QVariantMap& entityDescription); diff --git a/libraries/entities/src/RemapIDOperator.cpp b/libraries/entities/src/RemapIDOperator.cpp new file mode 100644 index 0000000000..eee6e49a1c --- /dev/null +++ b/libraries/entities/src/RemapIDOperator.cpp @@ -0,0 +1,33 @@ +// +// RemapIDOperator.cpp +// libraries/entities/src +// +// Created by Seth Alves on 2015-12-6. +// 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 "EntityTree.h" +#include "RemapIDOperator.h" + +QUuid RemapIDOperator::remap(const QUuid& oldID) { + if (oldID.isNull()) { + return oldID; + } + if (!_oldToNew.contains(oldID)) { + _oldToNew[oldID] = QUuid::createUuid(); + } + return _oldToNew[oldID]; +} + +bool RemapIDOperator::postRecursion(OctreeElementPointer element) { + EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); + entityTreeElement->forEachEntity([&](EntityItemPointer entityItem) { + entityItem->setID(remap(entityItem->getID())); + entityItem->setParentID(remap(entityItem->getParentID())); + }); + return true; +} diff --git a/libraries/entities/src/RemapIDOperator.h b/libraries/entities/src/RemapIDOperator.h new file mode 100644 index 0000000000..439aec28fc --- /dev/null +++ b/libraries/entities/src/RemapIDOperator.h @@ -0,0 +1,30 @@ +// +// RemapIDOperator.h +// libraries/entities/src +// +// Created by Seth Alves on 2015-12-6. +// 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_RemapIDOperator_h +#define hifi_RemapIDOperator_h + +#include "Octree.h" + +// this will change all the IDs in an EntityTree. Parent/Child relationships are maintained. + +class RemapIDOperator : public RecurseOctreeOperator { +public: + RemapIDOperator() : RecurseOctreeOperator() {} + ~RemapIDOperator() {} + virtual bool preRecursion(OctreeElementPointer element) { return true; } + virtual bool postRecursion(OctreeElementPointer element); +private: + QUuid remap(const QUuid& oldID); + QHash _oldToNew; +}; + +#endif // hifi_RemapIDOperator_h From 22bdc1ae840c56fc4adb0762376a3ef1654fbf42 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Mon, 7 Dec 2015 13:49:49 +0100 Subject: [PATCH 377/401] Make it possible to use the focus-right-click-drag-camera in the edit.js script again. Still keep right-clicking ignore Toolbar and entity selection events. --- examples/edit.js | 9 +++++---- examples/libraries/entitySelectionTool.js | 5 +++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 9b83079198..5d5d642f47 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -392,6 +392,11 @@ var toolBar = (function() { url, file; + if (!event.isLeftButton) { + // if another mouse button than left is pressed ignore it + return false; + } + clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y @@ -738,10 +743,6 @@ var mousePressStartPosition = { var mouseDown = false; function mousePressEvent(event) { - if (!event.isLeftButton) { - // If another mouse button than left is pressed ignore it - return false; - } mouseDown = true; mousePressStartPosition = { x: event.x, diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index 61aa5b0394..6edbe6844b 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -2340,6 +2340,11 @@ SelectionDisplay = (function () { that.mousePressEvent = function(event) { + if (!event.isLeftButton) { + // if another mouse button than left is pressed ignore it + return false; + } + var somethingClicked = false; var pickRay = Camera.computePickRay(event.x, event.y); From 96e9580473b597f6bb83c3d684d121a6265bf785 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 7 Dec 2015 05:30:19 -0800 Subject: [PATCH 378/401] change some more parameters back to being pass-by-reference, where it's safe --- .../entities-renderer/src/RenderableModelEntityItem.cpp | 5 +++-- .../entities-renderer/src/RenderableModelEntityItem.h | 2 +- libraries/entities/src/EntityItem.cpp | 2 +- libraries/entities/src/EntityItem.h | 2 +- libraries/entities/src/EntityItemProperties.cpp | 2 +- libraries/entities/src/EntityItemProperties.h | 2 +- libraries/entities/src/EntityScriptingInterface.cpp | 6 +++--- libraries/entities/src/EntityScriptingInterface.h | 2 +- libraries/entities/src/LightEntityItem.cpp | 2 +- libraries/entities/src/LightEntityItem.h | 2 +- libraries/entities/src/TextEntityItem.cpp | 2 +- libraries/entities/src/TextEntityItem.h | 2 +- libraries/entities/src/WebEntityItem.cpp | 2 +- libraries/entities/src/WebEntityItem.h | 2 +- libraries/shared/src/SpatiallyNestable.cpp | 8 ++++---- libraries/shared/src/SpatiallyNestable.h | 8 ++++---- 16 files changed, 26 insertions(+), 25 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 8f2b54b35a..95ce59b6a3 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -33,7 +33,8 @@ EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityI RenderableModelEntityItem::RenderableModelEntityItem(const EntityItemID& entityItemID, bool dimensionsInitialized) : ModelEntityItem(entityItemID), - _dimensionsInitialized(dimensionsInitialized) { + _dimensionsInitialized(dimensionsInitialized) +{ } RenderableModelEntityItem::~RenderableModelEntityItem() { @@ -44,7 +45,7 @@ RenderableModelEntityItem::~RenderableModelEntityItem() { } } -void RenderableModelEntityItem::setDimensions(const glm::vec3 value) { +void RenderableModelEntityItem::setDimensions(const glm::vec3& value) { _dimensionsInitialized = true; ModelEntityItem::setDimensions(value); } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index e73289174c..7dba6ac5f0 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -28,7 +28,7 @@ public: virtual ~RenderableModelEntityItem(); - virtual void setDimensions(const glm::vec3 value) override; + virtual void setDimensions(const glm::vec3& value) override; virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const override; virtual bool setProperties(const EntityItemProperties& properties) override; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 51ade5b46e..9b31c2aa59 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1192,7 +1192,7 @@ const Transform EntityItem::getTransformToCenter() const { return result; } -void EntityItem::setDimensions(const glm::vec3 value) { +void EntityItem::setDimensions(const glm::vec3& value) { if (value.x <= 0.0f || value.y <= 0.0f || value.z <= 0.0f) { return; } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index bfc178f2c3..4fc4ee2afb 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -178,7 +178,7 @@ public: /// Dimensions in meters (0.0 - TREE_SCALE) inline const glm::vec3 getDimensions() const { return getScale(); } - virtual void setDimensions(const glm::vec3 value); + virtual void setDimensions(const glm::vec3& value); float getGlowLevel() const { return _glowLevel; } void setGlowLevel(float glowLevel) { _glowLevel = glowLevel; } diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 9ff5d73616..d040f785da 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -1796,6 +1796,6 @@ QList EntityItemProperties::listChangedProperties() { return out; } -bool EntityItemProperties::parentDependentPropertyChanged() { +bool EntityItemProperties::parentDependentPropertyChanged() const { return localPositionChanged() || positionChanged() || localRotationChanged() || rotationChanged(); } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 11d29c5d57..c13519996a 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -83,7 +83,7 @@ public: { return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; } EntityPropertyFlags getChangedProperties() const; - bool parentDependentPropertyChanged(); // was there a changed in a property that requires parent info to interpret? + bool parentDependentPropertyChanged() const; // was there a changed in a property that requires parent info to interpret? AACube getMaximumAACube() const; AABox getAABox() const; diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 2488470bfa..4cb815f365 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -64,7 +64,7 @@ void EntityScriptingInterface::setEntityTree(EntityTreePointer elementTree) { } } -EntityItemProperties convertLocationToScriptSemantics(EntityItemProperties entitySideProperties) { +EntityItemProperties convertLocationToScriptSemantics(const EntityItemProperties& entitySideProperties) { // In EntityTree code, properties.position and properties.rotation are relative to the parent. In javascript, // they are in world-space. The local versions are put into localPosition and localRotation and position and // rotation are converted from local to world space. @@ -85,7 +85,7 @@ EntityItemProperties convertLocationToScriptSemantics(EntityItemProperties entit } -EntityItemProperties convertLocationFromScriptSemantics(EntityItemProperties scriptSideProperties) { +EntityItemProperties convertLocationFromScriptSemantics(const EntityItemProperties& scriptSideProperties) { // convert position and rotation properties from world-space to local, unless localPosition and localRotation // are set. If they are set, they overwrite position and rotation. EntityItemProperties entitySideProperties = scriptSideProperties; @@ -190,7 +190,7 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit return convertLocationToScriptSemantics(results); } -QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties scriptSideProperties) { +QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& scriptSideProperties) { EntityItemProperties properties = scriptSideProperties; EntityItemID entityID(id); // If we have a local entity tree set, then also update it. diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 84688ab24a..591dee6a85 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -86,7 +86,7 @@ public slots: /// edits a model updating only the included properties, will return the identified EntityItemID in case of /// successful edit, if the input entityID is for an unknown model this function will have no effect - Q_INVOKABLE QUuid editEntity(QUuid entityID, EntityItemProperties properties); + Q_INVOKABLE QUuid editEntity(QUuid entityID, const EntityItemProperties& properties); /// deletes a model Q_INVOKABLE void deleteEntity(QUuid entityID); diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index af3110c000..ac56fc9c1f 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -40,7 +40,7 @@ LightEntityItem::LightEntityItem(const EntityItemID& entityItemID) : EntityItem( _cutoff = PI; } -void LightEntityItem::setDimensions(const glm::vec3 value) { +void LightEntityItem::setDimensions(const glm::vec3& value) { if (_isSpotlight) { // If we are a spotlight, treat the z value as our radius or length, and // recalculate the x/y dimensions to properly encapsulate the spotlight. diff --git a/libraries/entities/src/LightEntityItem.h b/libraries/entities/src/LightEntityItem.h index edb2ca7b3c..103c462809 100644 --- a/libraries/entities/src/LightEntityItem.h +++ b/libraries/entities/src/LightEntityItem.h @@ -23,7 +23,7 @@ public: ALLOW_INSTANTIATION // This class can be instantiated /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately - virtual void setDimensions(const glm::vec3 value); + virtual void setDimensions(const glm::vec3& value); // methods for getting/setting all properties of an entity virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index 7d1cfb5c6b..893329d1ce 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -41,7 +41,7 @@ TextEntityItem::TextEntityItem(const EntityItemID& entityItemID) : EntityItem(en const float TEXT_ENTITY_ITEM_FIXED_DEPTH = 0.01f; -void TextEntityItem::setDimensions(const glm::vec3 value) { +void TextEntityItem::setDimensions(const glm::vec3& value) { // NOTE: Text Entities always have a "depth" of 1cm. EntityItem::setDimensions(glm::vec3(value.x, value.y, TEXT_ENTITY_ITEM_FIXED_DEPTH)); } diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index 2080912d92..1caceee085 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -23,7 +23,7 @@ public: ALLOW_INSTANTIATION // This class can be instantiated /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately - virtual void setDimensions(const glm::vec3 value); + virtual void setDimensions(const glm::vec3& value); virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; } // methods for getting/setting all properties of an entity diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp index 35189074bb..5f113f1de4 100644 --- a/libraries/entities/src/WebEntityItem.cpp +++ b/libraries/entities/src/WebEntityItem.cpp @@ -34,7 +34,7 @@ WebEntityItem::WebEntityItem(const EntityItemID& entityItemID) : EntityItem(enti const float WEB_ENTITY_ITEM_FIXED_DEPTH = 0.01f; -void WebEntityItem::setDimensions(const glm::vec3 value) { +void WebEntityItem::setDimensions(const glm::vec3& value) { // NOTE: Web Entities always have a "depth" of 1cm. EntityItem::setDimensions(glm::vec3(value.x, value.y, WEB_ENTITY_ITEM_FIXED_DEPTH)); } diff --git a/libraries/entities/src/WebEntityItem.h b/libraries/entities/src/WebEntityItem.h index 49ab009bb2..8e9d924cde 100644 --- a/libraries/entities/src/WebEntityItem.h +++ b/libraries/entities/src/WebEntityItem.h @@ -22,7 +22,7 @@ public: ALLOW_INSTANTIATION // This class can be instantiated /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately - virtual void setDimensions(const glm::vec3 value); + virtual void setDimensions(const glm::vec3& value); virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; } // methods for getting/setting all properties of an entity diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 77b5f57bfb..3d697edd92 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -99,7 +99,7 @@ void SpatiallyNestable::setParentID(const QUuid& parentID) { parentChanged(); } -glm::vec3 SpatiallyNestable::worldToLocal(glm::vec3 position, QUuid parentID, int parentJointIndex) { +glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position, const QUuid& parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); Transform parentTransform; if (parentFinder) { @@ -122,7 +122,7 @@ glm::vec3 SpatiallyNestable::worldToLocal(glm::vec3 position, QUuid parentID, in return result.getTranslation(); } -glm::quat SpatiallyNestable::worldToLocal(glm::quat orientation, QUuid parentID, int parentJointIndex) { +glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); Transform parentTransform; if (parentFinder) { @@ -144,7 +144,7 @@ glm::quat SpatiallyNestable::worldToLocal(glm::quat orientation, QUuid parentID, return result.getRotation(); } -glm::vec3 SpatiallyNestable::localToWorld(glm::vec3 position, QUuid parentID, int parentJointIndex) { +glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3& position, const QUuid& parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); Transform parentTransform; if (parentFinder) { @@ -162,7 +162,7 @@ glm::vec3 SpatiallyNestable::localToWorld(glm::vec3 position, QUuid parentID, in return result.getTranslation(); } -glm::quat SpatiallyNestable::localToWorld(glm::quat orientation, QUuid parentID, int parentJointIndex) { +glm::quat SpatiallyNestable::localToWorld(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex) { QSharedPointer parentFinder = DependencyManager::get(); Transform parentTransform; if (parentFinder) { diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index dc1be54219..4fdb051e84 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -47,11 +47,11 @@ public: virtual quint16 getParentJointIndex() const { return _parentJointIndex; } virtual void setParentJointIndex(quint16 parentJointIndex) { _parentJointIndex = parentJointIndex; } - static glm::vec3 worldToLocal(glm::vec3 position, QUuid parentID, int parentJointIndex); - static glm::quat worldToLocal(glm::quat orientation, QUuid parentID, int parentJointIndex); + static glm::vec3 worldToLocal(const glm::vec3& position, const QUuid& parentID, int parentJointIndex); + static glm::quat worldToLocal(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex); - static glm::vec3 localToWorld(glm::vec3 position, QUuid parentID, int parentJointIndex); - static glm::quat localToWorld(glm::quat orientation, QUuid parentID, int parentJointIndex); + static glm::vec3 localToWorld(const glm::vec3& position, const QUuid& parentID, int parentJointIndex); + static glm::quat localToWorld(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex); // world frame virtual const Transform getTransform() const; From f53571ac81c50a92f43d32868bd9beb6e576cbc9 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 7 Dec 2015 05:41:34 -0800 Subject: [PATCH 379/401] remap IDs on export, also --- interface/src/Application.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6ef440843f..094f04df29 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2414,6 +2414,9 @@ bool Application::exportEntities(const QString& filename, const QVectoraddEntity(entityItem->getEntityItemID(), properties); } + // remap IDs on export so that we aren't publishing the IDs of entities in our domain + exportTree->remapIDs(); + exportTree->writeToJSONFile(filename.toLocal8Bit().constData()); // restore the main window's active state From f6b1ef85b30f06ca82eaeed2a1e1c378d20a128a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 7 Dec 2015 06:03:47 -0800 Subject: [PATCH 380/401] remap entity IDs on export also --- interface/src/Application.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 094f04df29..4a5811826b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2439,6 +2439,10 @@ bool Application::exportEntities(const QString& filename, float x, float y, floa properties.setPosition(properties.getPosition() - root); exportTree->addEntity(id, properties); } + + // remap IDs on export so that we aren't publishing the IDs of entities in our domain + exportTree->remapIDs(); + exportTree->writeToSVOFile(filename.toLocal8Bit().constData()); } else { qCDebug(interfaceapp) << "No models were selected"; From 60b8e65520cc93c70d1e040fa700b341578d6555 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 7 Dec 2015 06:03:58 -0800 Subject: [PATCH 381/401] get file dialog working on Linux --- interface/src/scripting/WindowScriptingInterface.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index a2886c8b77..0bf94f02a9 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -622,7 +622,8 @@ QScriptValue WindowScriptingInterface::showBrowse(const QString& title, const QS fileDialog.setAcceptMode(acceptMode); QUrl fileUrl(directory); if (acceptMode == QFileDialog::AcceptSave) { - fileDialog.setFileMode(QFileDialog::Directory); + // TODO -- Setting this breaks the dialog on Linux. Does it help something on other platforms? + // fileDialog.setFileMode(QFileDialog::Directory); fileDialog.selectFile(fileUrl.fileName()); } if (fileDialog.exec()) { From 18198cb6fbb55a52741510f07c0a98bc2f7b8cdb Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Dec 2015 08:36:49 -0800 Subject: [PATCH 382/401] Fix missing override --- libraries/entities-renderer/src/RenderableModelEntityItem.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 2ee4aeb73e..f54f97a5a9 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -68,8 +68,8 @@ public: virtual bool contains(const glm::vec3& point) const override; // these are in the frame of this object - virtual glm::quat getJointRotation(int index) const; - virtual glm::vec3 getJointTranslation(int index) const; + virtual glm::quat getJointRotation(int index) const override; + virtual glm::vec3 getJointTranslation(int index) const override; private: void remapTextures(); From f8ee377f017261d11a9d76b4be6f51354e6beab8 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Dec 2015 08:37:07 -0800 Subject: [PATCH 383/401] Fix QOpenGL warning --- interface/src/Application.cpp | 6 +++--- libraries/render-utils/src/QOpenGLContextWrapper.cpp | 4 ++++ libraries/render-utils/src/QOpenGLContextWrapper.h | 2 ++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9e98b51442..65ed624f5e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -45,7 +45,7 @@ #include #include -#include +#include #include #include @@ -1397,13 +1397,13 @@ void Application::paintGL() { _lockedFramebufferMap[finalTexture] = scratchFramebuffer; uint64_t displayStart = usecTimestampNow(); - Q_ASSERT(QOpenGLContext::currentContext() == _offscreenContext->getContext()); + Q_ASSERT(isCurrentContext(_offscreenContext->getContext())); { PROFILE_RANGE(__FUNCTION__ "/pluginSubmitScene"); PerformanceTimer perfTimer("pluginSubmitScene"); displayPlugin->submitSceneTexture(_frameCount, finalTexture, toGlm(size)); } - Q_ASSERT(QOpenGLContext::currentContext() == _offscreenContext->getContext()); + Q_ASSERT(isCurrentContext(_offscreenContext->getContext())); uint64_t displayEnd = usecTimestampNow(); const float displayPeriodUsec = (float)(displayEnd - displayStart); // usecs diff --git a/libraries/render-utils/src/QOpenGLContextWrapper.cpp b/libraries/render-utils/src/QOpenGLContextWrapper.cpp index 64233ea413..3e879df7af 100644 --- a/libraries/render-utils/src/QOpenGLContextWrapper.cpp +++ b/libraries/render-utils/src/QOpenGLContextWrapper.cpp @@ -37,4 +37,8 @@ bool QOpenGLContextWrapper::makeCurrent(QSurface* surface) { void QOpenGLContextWrapper::doneCurrent() { _context->doneCurrent(); +} + +bool isCurrentContext(QOpenGLContext* context) { + return QOpenGLContext::currentContext() == context; } \ No newline at end of file diff --git a/libraries/render-utils/src/QOpenGLContextWrapper.h b/libraries/render-utils/src/QOpenGLContextWrapper.h index 6c50d5f438..832119162c 100644 --- a/libraries/render-utils/src/QOpenGLContextWrapper.h +++ b/libraries/render-utils/src/QOpenGLContextWrapper.h @@ -30,4 +30,6 @@ private: QOpenGLContext* _context { nullptr }; }; +bool isCurrentContext(QOpenGLContext* context); + #endif // hifi_QOpenGLContextWrapper_h \ No newline at end of file From c2049e530873dce4ffbdc94573e8ab9c671c13a1 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 4 Dec 2015 16:25:22 -0800 Subject: [PATCH 384/401] Fix udt-test to work with ReceivedMessage updates --- tools/udt-test/src/UDTTest.cpp | 42 +++++++++++++++++++++++++++------- tools/udt-test/src/UDTTest.h | 11 ++++++++- 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 3d0d03b8d2..d4054527f9 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -176,10 +176,36 @@ UDTTest::UDTTest(int& argc, char** argv) : } else { // this is a receiver - in case there are ordered packets (messages) being sent to us make sure that we handle them // so that they can be verified - // TODO Fix support for message testing - //_socket.setMessageHandler( - //[this](std::unique_ptr packetList) { handlePacketList(std::move(packetList)); }); + _socket.setMessageHandler( + [this](std::unique_ptr packet) { + auto messageNumber = packet->getMessageNumber(); + auto it = _pendingMessages.find(messageNumber); + + if (it == _pendingMessages.end()) { + auto message = std::unique_ptr(new Message { messageNumber, packet->readAll() }); + message->data.reserve(_messageSize); + if (packet->getPacketPosition() == udt::Packet::ONLY) { + handleMessage(std::move(message)); + } else { + _pendingMessages[messageNumber] = std::move(message); + } + } else { + auto& message = it->second; + message->data.append(packet->readAll()); + + if (packet->getPacketPosition() == udt::Packet::LAST) { + handleMessage(std::move(message)); + _pendingMessages.erase(it); + } + } + + }); } + _socket.setMessageFailureHandler( + [this](HifiSockAddr from, udt::Packet::MessageNumber messageNumber) { + _pendingMessages.erase(messageNumber); + } + ); // the sender reports stats every 100 milliseconds, unless passed a custom value @@ -309,11 +335,11 @@ void UDTTest::sendPacket() { } -void UDTTest::handlePacketList(std::unique_ptr packetList) { +void UDTTest::handleMessage(std::unique_ptr message) { // generate the byte array that should match this message - using the same seed the sender did int packetSize = udt::Packet::maxPayloadSize(true); - int messageSize = packetList->getMessageSize(); + int messageSize = message->data.size(); QByteArray messageData(messageSize, 0); @@ -324,13 +350,13 @@ void UDTTest::handlePacketList(std::unique_ptr packetList) { messageData.replace(i, sizeof(randomInt), reinterpret_cast(&randomInt), sizeof(randomInt)); } - bool dataMatch = messageData == packetList->getMessage(); + bool dataMatch = messageData == message->data; - Q_ASSERT_X(dataMatch, "UDTTest::handlePacketList", + Q_ASSERT_X(dataMatch, "UDTTest::handleMessage", "received message did not match expected message (from seeded random number generation)."); if (!dataMatch) { - qCritical() << "UDTTest::handlePacketList" << "received message did not match expected message" + qCritical() << "UDTTest::handleMessage" << "received message did not match expected message" << "(from seeded random number generation)."; } } diff --git a/tools/udt-test/src/UDTTest.h b/tools/udt-test/src/UDTTest.h index fda57cc183..3a4b1b897d 100644 --- a/tools/udt-test/src/UDTTest.h +++ b/tools/udt-test/src/UDTTest.h @@ -23,6 +23,13 @@ #include #include +#include + +struct Message { + udt::MessageNumber messageNumber; + QByteArray data; +}; + class UDTTest : public QCoreApplication { Q_OBJECT public: @@ -34,7 +41,7 @@ public slots: private: void parseArguments(); - void handlePacketList(std::unique_ptr packetList); + void handleMessage(std::unique_ptr message); void sendInitialPackets(); // fills the queue with packets to start void sendPacket(); // constructs and sends a packet according to the test parameters @@ -53,6 +60,8 @@ private: bool _sendOrdered { false }; // whether to send ordered packets int _messageSize { 10000000 }; // number of bytes per message while sending ordered + + std::unordered_map> _pendingMessages; std::random_device _randomDevice; std::mt19937 _generator { _randomDevice() }; // random number generator for ordered data testing From fd4ed29405c01639a88fbf697d65bbee958bf054 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Mon, 7 Dec 2015 09:03:40 -0800 Subject: [PATCH 385/401] MyAvatar.clearJointData bug fix MyAvatar.setJointRotation() now works properly after MyAvatar.clearJointData() --- interface/src/avatar/MyAvatar.cpp | 2 -- libraries/animation/src/Rig.cpp | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5c4b51fefd..b75835dc96 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -967,8 +967,6 @@ void MyAvatar::clearJointData(int index) { QMetaObject::invokeMethod(this, "clearJointData", Q_ARG(int, index)); return; } - // HACK: ATM only JS scripts call clearJointData() on MyAvatar so we hardcode the priority - _rig->setJointState(index, false, glm::quat(), glm::vec3(), 0.0f); _rig->clearJointAnimationPriority(index); } diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 8fb56ed699..98b347c660 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -294,6 +294,7 @@ void Rig::clearJointStates() { void Rig::clearJointAnimationPriority(int index) { if (isIndexValid(index)) { _internalPoseSet._overrideFlags[index] = false; + _internalPoseSet._overridePoses[index] = _animSkeleton->getRelativeDefaultPose(index); } } From cdf621e8d008a76090786422beb6a520a872d078 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Dec 2015 09:11:41 -0800 Subject: [PATCH 386/401] Remove unnecessary moveToThread to remove warning --- .../src/display-plugins/OpenGLDisplayPlugin.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 8593da1573..332bbe63ed 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -14,7 +14,6 @@ #include #include -#include #include #include @@ -46,7 +45,6 @@ public: // Extra code because of the widget 'wrapper' context _context = context; _context->moveToThread(this); - _context->contextHandle()->moveToThread(this); } virtual void run() override { @@ -57,7 +55,6 @@ public: Lock lock(_mutex); // Move the context to the main thread _context->moveToThread(qApp->thread()); - _context->contextHandle()->moveToThread(qApp->thread()); _pendingMainThreadOperation = false; // Release the main thread to do it's action _condition.notify_one(); @@ -104,7 +101,6 @@ public: _context->doneCurrent(); _context->moveToThread(qApp->thread()); - _context->contextHandle()->moveToThread(qApp->thread()); } void withMainThreadContext(std::function f) { @@ -120,7 +116,6 @@ public: // Move the context back to the presentation thread _context->moveToThread(this); - _context->contextHandle()->moveToThread(this); // restore control of the context to the presentation thread and signal // the end of the operation From dd6c8cbe335a4aaa511bc8add3ad9d1dd9cc10ae Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 7 Dec 2015 09:42:04 -0800 Subject: [PATCH 387/401] Remove verbose piggyback logging --- interface/src/octree/OctreePacketProcessor.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/octree/OctreePacketProcessor.cpp b/interface/src/octree/OctreePacketProcessor.cpp index f93011a2f4..5e1a7213b5 100644 --- a/interface/src/octree/OctreePacketProcessor.cpp +++ b/interface/src/octree/OctreePacketProcessor.cpp @@ -54,7 +54,6 @@ void OctreePacketProcessor::processPacket(QSharedPointer messag // construct a new packet from the piggybacked one auto buffer = std::unique_ptr(new char[piggybackBytes]); memcpy(buffer.get(), message->getRawMessage() + statsMessageLength, piggybackBytes); - qDebug() << "Got piggyback, read " << piggybackBytes << " bytes"; auto newPacket = NLPacket::fromReceivedPacket(std::move(buffer), piggybackBytes, message->getSenderSockAddr()); message = QSharedPointer::create(*newPacket.release()); From 72ce46af5916b79cd940f3c5132d7fb2ddd42a4c Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Mon, 7 Dec 2015 11:46:36 -0800 Subject: [PATCH 388/401] Mac-only. --- .../src/display-plugins/OpenGLDisplayPlugin.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 29bd9301e3..8e02077600 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -152,7 +152,14 @@ OpenGLDisplayPlugin::OpenGLDisplayPlugin() { }); connect(&_timer, &QTimer::timeout, this, [&] { +#ifdef Q_OS_MAC + // On Mac, QT thread timing is such that we can miss one or even two cycles quite often, giving a render rate (including update/simulate) + // far lower than what we want. This hack keeps that rate more natural, at the expense of some wasted rendering. + // This is likely to be mooted by further planned changes. if (_active && _sceneTextureEscrow.depth() <= 1) { +#else + if (_active && _sceneTextureEscrow.depth() < 1) { +#endif emit requestRender(); } }); From 84bc947854fe4d998a2b06c0bdf35bb250d03077 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Dec 2015 14:00:06 -0800 Subject: [PATCH 389/401] Typo --- examples/baseball/assets.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/baseball/assets.json b/examples/baseball/assets.json index aa0626edfc..00edcbe703 100644 --- a/examples/baseball/assets.json +++ b/examples/baseball/assets.json @@ -84,22 +84,22 @@ "fire1.wav": { "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire1.wav", "atp_url": "atp:ee6afe565576c4546c6d6cd89c1af532484c9b60ab30574d6b40c2df022f7260.wav", - "attribution": "CC BY 3.0 - Credirt: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" + "attribution": "CC BY 3.0 - Credir: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" }, "fire2.wav": { "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire2.wav", "atp_url": "atp:91ef19ba1c78be82d3fd06530cd05ceb90d1e75f4204c66819c208c55da049ef.wav", - "attribution": "CC BY 3.0 - Credirt: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" + "attribution": "CC BY 3.0 - Credit: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" }, "fire3.wav": { "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire3.wav", "atp_url": "atp:ee56993daf775012cf49293bfd5971eec7e5c396642f8bfbea902ba8f47b56cd.wav", - "attribution": "CC BY 3.0 - Credirt: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" + "attribution": "CC BY 3.0 - Credit: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" }, "fire4.wav": { "s3_url": "http://hifi-public.s3.amazonaws.com/birarda/baseball/fireworks/fire4.wav", "atp_url": "atp:37775d267f00f82242a7e7f61f3f3d7bf64a54c5a3799e7f2540fa5f6b79bd02.wav", - "attribution": "CC BY 3.0 - Credirt: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" + "attribution": "CC BY 3.0 - Credit: dcsimon - https://www.freesound.org/people/dcsimon/sounds/160720/" } } } From 0bf276efa59fcae851979aa3e1295f546fe2964a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 7 Dec 2015 14:37:35 -0800 Subject: [PATCH 390/401] adjust method names to fit convention --- interface/src/avatar/Avatar.h | 4 ++-- libraries/avatars/src/AvatarData.h | 4 ++-- libraries/entities/src/EntityScriptingInterface.cpp | 8 ++++---- libraries/entities/src/EntityScriptingInterface.h | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index d26a02d815..99a4fc52a9 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -158,8 +158,8 @@ public: void setMotionState(AvatarMotionState* motionState) { _motionState = motionState; } AvatarMotionState* getMotionState() { return _motionState; } - virtual void setPosition(const glm::vec3& position); - virtual void setOrientation(const glm::quat& orientation); + virtual void setPosition(const glm::vec3& position) override; + virtual void setOrientation(const glm::quat& orientation) override; public slots: diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 67cf6624d4..1fa33ff606 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -201,8 +201,8 @@ public: float getBodyRoll() const; void setBodyRoll(float bodyRoll); - virtual void setPosition(const glm::vec3& position); - virtual void setOrientation(const glm::quat& orientation); + virtual void setPosition(const glm::vec3& position) override; + virtual void setOrientation(const glm::quat& orientation) override; void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time. void startCapture(); // start/end of the period in which the latest values are about to be captured for camera, etc. diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index a417e094a0..f97e904423 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -806,19 +806,19 @@ glm::vec3 EntityScriptingInterface::localCoordsToVoxelCoords(const QUuid& entity } } -glm::vec3 EntityScriptingInterface::getJointTranslation(const QUuid& entityID, int jointIndex) { +glm::vec3 EntityScriptingInterface::getAbsoluteJointTranslationInObjectFrame(const QUuid& entityID, int jointIndex) { if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::Model)) { auto modelEntity = std::dynamic_pointer_cast(entity); - return modelEntity->getJointTranslation(jointIndex); + return modelEntity->getAbsoluteJointTranslationInObjectFrame(jointIndex); } else { return glm::vec3(0.0f); } } -glm::quat EntityScriptingInterface::getJointRotation(const QUuid& entityID, int jointIndex) { +glm::quat EntityScriptingInterface::getAbsoluteJointRotationInObjectFrame(const QUuid& entityID, int jointIndex) { if (auto entity = checkForTreeEntityAndTypeMatch(entityID, EntityTypes::Model)) { auto modelEntity = std::dynamic_pointer_cast(entity); - return modelEntity->getJointRotation(jointIndex); + return modelEntity->getAbsoluteJointRotationInObjectFrame(jointIndex); } else { return glm::quat(); } diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 5e1d81583e..f745b6b644 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -148,9 +148,9 @@ public slots: Q_INVOKABLE glm::vec3 worldCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 worldCoords); Q_INVOKABLE glm::vec3 voxelCoordsToLocalCoords(const QUuid& entityID, glm::vec3 voxelCoords); Q_INVOKABLE glm::vec3 localCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 localCoords); - - Q_INVOKABLE glm::vec3 getJointTranslation(const QUuid& entityID, int jointIndex); - Q_INVOKABLE glm::quat getJointRotation(const QUuid& entityID, int jointIndex); + + Q_INVOKABLE glm::vec3 getAbsoluteJointTranslationInObjectFrame(const QUuid& entityID, int jointIndex); + Q_INVOKABLE glm::quat getAbsoluteJointRotationInObjectFrame(const QUuid& entityID, int jointIndex); signals: void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); From 0fee004bdde72d2d7961e4af0f33bf5919f21b13 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Dec 2015 15:13:14 -0800 Subject: [PATCH 391/401] use case insensitive check for extensions --- interface/src/Application.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9e98b51442..136ca88ac5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4079,7 +4079,7 @@ bool Application::canAcceptURL(const QString& urlString) { QString lowerPath = url.path().toLower(); while (i.hasNext()) { i.next(); - if (lowerPath.endsWith(i.key())) { + if (lowerPath.endsWith(i.key(), Qt::CaseInsensitive)) { return true; } } @@ -4099,7 +4099,7 @@ bool Application::acceptURL(const QString& urlString, bool defaultUpload) { QString lowerPath = url.path().toLower(); while (i.hasNext()) { i.next(); - if (lowerPath.endsWith(i.key())) { + if (lowerPath.endsWith(i.key(), Qt::CaseInsensitive)) { AcceptURLMethod method = i.value(); return (this->*method)(urlString); } @@ -4199,7 +4199,7 @@ bool Application::askToUploadAsset(const QString& filename) { messageBox.setDefaultButton(QMessageBox::Ok); // Option to drop model in world for models - if (filename.endsWith(FBX_EXTENSION) || filename.endsWith(OBJ_EXTENSION)) { + if (filename.endsWith(FBX_EXTENSION, Qt::CaseInsensitive) || filename.endsWith(OBJ_EXTENSION, Qt::CaseInsensitive)) { auto checkBox = new QCheckBox(&messageBox); checkBox->setText("Add to scene"); messageBox.setCheckBox(checkBox); @@ -4234,7 +4234,7 @@ void Application::modelUploadFinished(AssetUpload* upload, const QString& hash) auto filename = QFileInfo(upload->getFilename()).fileName(); if ((upload->getError() == AssetUpload::NoError) && - (filename.endsWith(FBX_EXTENSION) || filename.endsWith(OBJ_EXTENSION))) { + (filename.endsWith(FBX_EXTENSION, Qt::CaseInsensitive) || filename.endsWith(OBJ_EXTENSION, Qt::CaseInsensitive))) { auto entities = DependencyManager::get(); From 7beaf5e235bbc2c82eb509a7c638b1d70aa8b872 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Dec 2015 15:18:32 -0800 Subject: [PATCH 392/401] force asset upload to use a lowercase extension --- interface/src/Application.cpp | 3 ++- libraries/networking/src/AssetUpload.cpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 136ca88ac5..51d398ace9 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4234,7 +4234,8 @@ void Application::modelUploadFinished(AssetUpload* upload, const QString& hash) auto filename = QFileInfo(upload->getFilename()).fileName(); if ((upload->getError() == AssetUpload::NoError) && - (filename.endsWith(FBX_EXTENSION, Qt::CaseInsensitive) || filename.endsWith(OBJ_EXTENSION, Qt::CaseInsensitive))) { + (upload->getExtension().endsWith(FBX_EXTENSION, Qt::CaseInsensitive) || + upload->getExtension().endsWith(OBJ_EXTENSION, Qt::CaseInsensitive))) { auto entities = DependencyManager::get(); diff --git a/libraries/networking/src/AssetUpload.cpp b/libraries/networking/src/AssetUpload.cpp index e6f467e717..2d6f0c0e97 100644 --- a/libraries/networking/src/AssetUpload.cpp +++ b/libraries/networking/src/AssetUpload.cpp @@ -63,6 +63,7 @@ void AssetUpload::start() { // file opened, read the data and grab the extension _extension = QFileInfo(_filename).suffix(); + _extension = _extension.toLower(); _data = file.readAll(); } else { From 4a0c6eebd888c4be43cd088866134fe3c88e4ff3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Dec 2015 16:17:59 -0800 Subject: [PATCH 393/401] change avatar URL when typing completed or accepted --- interface/src/ui/PreferencesDialog.cpp | 23 +++++++++++++++++------ interface/src/ui/PreferencesDialog.h | 1 + 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 89c82a1c97..a25f868172 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -33,8 +33,8 @@ const int PREFERENCES_HEIGHT_PADDING = 20; PreferencesDialog::PreferencesDialog(QWidget* parent) : - QDialog(parent) { - + QDialog(parent) +{ setAttribute(Qt::WA_DeleteOnClose); ui.setupUi(this); @@ -48,10 +48,8 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) : connect(ui.buttonReloadDefaultScripts, &QPushButton::clicked, qApp, &Application::loadDefaultScripts); connect(ui.buttonChangeAppearance, &QPushButton::clicked, this, &PreferencesDialog::openFullAvatarModelBrowser); - connect(ui.appearanceDescription, &QLineEdit::textChanged, this, [this](const QString& url) { - DependencyManager::get()->getMyAvatar()->useFullAvatarURL(url, ""); - this->fullAvatarURLChanged(url, ""); - }); + connect(ui.appearanceDescription, &QLineEdit::editingFinished, this, &PreferencesDialog::changeFullAvatarURL); + connect(qApp, &Application::fullAvatarURLChanged, this, &PreferencesDialog::fullAvatarURLChanged); // move dialog to left side @@ -61,6 +59,11 @@ PreferencesDialog::PreferencesDialog(QWidget* parent) : UIUtil::scaleWidgetFontSizes(this); } +void PreferencesDialog::changeFullAvatarURL() { + DependencyManager::get()->getMyAvatar()->useFullAvatarURL(ui.appearanceDescription->text(), ""); + this->fullAvatarURLChanged(ui.appearanceDescription->text(), ""); +} + void PreferencesDialog::fullAvatarURLChanged(const QString& newValue, const QString& modelName) { ui.appearanceDescription->setText(newValue); const QString APPEARANCE_LABEL_TEXT("Appearance: "); @@ -69,9 +72,17 @@ void PreferencesDialog::fullAvatarURLChanged(const QString& newValue, const QStr void PreferencesDialog::accept() { MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); + + // if there is an attempted change to the full avatar URL, apply it now + if (QUrl(ui.appearanceDescription->text()) != myAvatar->getFullAvatarURLFromPreferences()) { + changeFullAvatarURL(); + } + _lastGoodAvatarURL = myAvatar->getFullAvatarURLFromPreferences(); _lastGoodAvatarName = myAvatar->getFullAvatarModelName(); + savePreferences(); + close(); delete _marketplaceWindow; _marketplaceWindow = NULL; diff --git a/interface/src/ui/PreferencesDialog.h b/interface/src/ui/PreferencesDialog.h index 6d7a87b97c..1536eca3ee 100644 --- a/interface/src/ui/PreferencesDialog.h +++ b/interface/src/ui/PreferencesDialog.h @@ -49,6 +49,7 @@ private slots: void openFullAvatarModelBrowser(); void openSnapshotLocationBrowser(); void openScriptsLocationBrowser(); + void changeFullAvatarURL(); void fullAvatarURLChanged(const QString& newValue, const QString& modelName); }; From 6dbff93bbda38fd7e2eea4403d0259f04d0ba4b5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 7 Dec 2015 16:24:26 -0800 Subject: [PATCH 394/401] fix assert on model URL change from _renderItemsSet --- libraries/render-utils/src/Model.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index f566d0879d..193f3c04b5 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -544,6 +544,7 @@ void Model::removeFromScene(std::shared_ptr scene, render::Pendin pendingChanges.removeItem(item); } _renderItems.clear(); + _renderItemsSet.clear(); _readyWhenAdded = false; } From fc77d6cd404384a6c898c6c2d309fdbecb940752 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 7 Dec 2015 17:08:36 -0800 Subject: [PATCH 395/401] Fix grab behavior --- interface/src/avatar/AvatarActionHold.cpp | 15 ++++++++------- interface/src/avatar/AvatarActionHold.h | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index e0ea226a53..fab838aa68 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -65,11 +65,6 @@ std::shared_ptr AvatarActionHold::getTarget(glm::quat& rotation, glm::ve } } - if (!isRightHand) { - static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); - palmRotation *= yFlip; // Match right hand frame of reference - } - rotation = palmRotation * _relativeRotation; position = palmPosition + rotation * _relativePosition; }); @@ -218,14 +213,20 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) { ok = true; kinematic = EntityActionInterface::extractBooleanArgument("hold", arguments, "kinematic", ok, false); if (!ok) { - _kinematic = false; + kinematic = _kinematic; } ok = true; kinematicSetVelocity = EntityActionInterface::extractBooleanArgument("hold", arguments, "kinematicSetVelocity", ok, false); if (!ok) { - _kinematicSetVelocity = false; + kinematicSetVelocity = _kinematicSetVelocity; + } + + ok = true; + ignoreIK = EntityActionInterface::extractBooleanArgument("hold", arguments, "ignoreIK", ok, false); + if (!ok) { + ignoreIK = _ignoreIK; } if (somethingChanged || diff --git a/interface/src/avatar/AvatarActionHold.h b/interface/src/avatar/AvatarActionHold.h index 8a6948dde2..63f30a75d9 100644 --- a/interface/src/avatar/AvatarActionHold.h +++ b/interface/src/avatar/AvatarActionHold.h @@ -50,7 +50,7 @@ private: bool _kinematic { false }; bool _kinematicSetVelocity { false }; bool _previousSet { false }; - bool _ignoreIK { true }; + bool _ignoreIK { false }; glm::vec3 _previousPositionalTarget; glm::quat _previousRotationalTarget; From b7aeb34a8cb39e69e2b4c9940eb55c4a85a8f8d3 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Mon, 7 Dec 2015 17:46:03 -0800 Subject: [PATCH 396/401] Fix crashes on exit due to poor cleanup --- interface/src/Application.cpp | 5 +++++ .../src/display-plugins/OpenGLDisplayPlugin.cpp | 10 ++++++++++ libraries/gl/src/gl/OffscreenQmlSurface.cpp | 3 +++ 3 files changed, 18 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d4136571ad..5488574188 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1077,6 +1077,11 @@ void Application::initializeUi() { } void Application::paintGL() { + // paintGL uses a queued connection, so we can get messages from the queue even after we've quit + // and the plugins have shutdown + if (_aboutToQuit) { + return; + } _frameCount++; // update fps moving average diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 332bbe63ed..7986eb7c67 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -30,6 +30,12 @@ class PresentThread : public QThread, public Dependency { using Lock = std::unique_lock; public: + PresentThread() { + connect(qApp, &QCoreApplication::aboutToQuit, [this]{ + _shutdown = true; + }); + } + ~PresentThread() { _shutdown = true; wait(); @@ -99,6 +105,10 @@ public: _context->doneCurrent(); } + _context->makeCurrent(); + if (_activePlugin) { + _activePlugin->uncustomizeContext(); + } _context->doneCurrent(); _context->moveToThread(qApp->thread()); } diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index f2eb112dc7..482eb1b36f 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -337,6 +337,9 @@ void OffscreenQmlSurface::create(QOpenGLContext* shareContext) { // a timer with a small interval is used to get better performance. _updateTimer.setInterval(MIN_TIMER_MS); connect(&_updateTimer, &QTimer::timeout, this, &OffscreenQmlSurface::updateQuick); + QObject::connect(qApp, &QCoreApplication::aboutToQuit, [this]{ + disconnect(&_updateTimer, &QTimer::timeout, this, &OffscreenQmlSurface::updateQuick); + }); _updateTimer.start(); _qmlComponent = new QQmlComponent(_qmlEngine); From 44d740ef571148912ce233c63bb1e8d7c76d5f73 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Dec 2015 09:22:02 -0800 Subject: [PATCH 397/401] Remove unused variable 'addr' --- libraries/networking/src/PacketReceiver.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 7e91a42a64..a162ba72c8 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -297,7 +297,6 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer recei emit dataReceived(matchingNode->getType(), receivedMessage->getSize()); matchingNode->recordBytesReceived(receivedMessage->getSize()); Node* n = matchingNode.data(); - auto addr = n->getActiveSocket(); QMetaMethod metaMethod = listener.method; From 71c266bc00e6e997eae0eba898efd65d99abc222 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Dec 2015 09:22:17 -0800 Subject: [PATCH 398/401] Fix order of initializion in ReceivedMessage --- libraries/networking/src/ReceivedMessage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/networking/src/ReceivedMessage.cpp b/libraries/networking/src/ReceivedMessage.cpp index f383257520..651b856923 100644 --- a/libraries/networking/src/ReceivedMessage.cpp +++ b/libraries/networking/src/ReceivedMessage.cpp @@ -22,8 +22,8 @@ static const int HEAD_DATA_SIZE = 512; ReceivedMessage::ReceivedMessage(const NLPacketList& packetList) : _data(packetList.getMessage()), _headData(_data.mid(0, HEAD_DATA_SIZE)), - _sourceID(packetList.getSourceID()), _numPackets(packetList.getNumPackets()), + _sourceID(packetList.getSourceID()), _packetType(packetList.getType()), _packetVersion(packetList.getVersion()), _senderSockAddr(packetList.getSenderSockAddr()), @@ -34,8 +34,8 @@ ReceivedMessage::ReceivedMessage(const NLPacketList& packetList) ReceivedMessage::ReceivedMessage(NLPacket& packet) : _data(packet.readAll()), _headData(_data.mid(0, HEAD_DATA_SIZE)), - _sourceID(packet.getSourceID()), _numPackets(1), + _sourceID(packet.getSourceID()), _packetType(packet.getType()), _packetVersion(packet.getVersion()), _senderSockAddr(packet.getSenderSockAddr()), From 0759462df714c865e897da07a42e99b9c65c008e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Tue, 8 Dec 2015 09:38:23 -0800 Subject: [PATCH 399/401] Remove unused variable in PacketReceiver --- libraries/networking/src/PacketReceiver.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index a162ba72c8..530efc5fb3 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -296,7 +296,6 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer recei if (matchingNode) { emit dataReceived(matchingNode->getType(), receivedMessage->getSize()); matchingNode->recordBytesReceived(receivedMessage->getSize()); - Node* n = matchingNode.data(); QMetaMethod metaMethod = listener.method; From ec9f1e0754c165bcc06d375b88b12e09c330856c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 8 Dec 2015 09:44:43 -0800 Subject: [PATCH 400/401] possible fix for crash when grabbing bubblewand --- libraries/entities/src/EntityScriptingInterface.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index f97e904423..a0a6719521 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -206,10 +206,13 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& // All of parentID, parentJointIndex, position, rotation are needed to make sense of any of them. // If any of these changed, pull any missing properties from the entity. EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); - if (entity && !scriptSideProperties.parentIDChanged()) { + if (!entity) { + return; + } + if (!scriptSideProperties.parentIDChanged()) { properties.setParentID(entity->getParentID()); } - if (entity && !scriptSideProperties.parentJointIndexChanged()) { + if (!scriptSideProperties.parentJointIndexChanged()) { properties.setParentJointIndex(entity->getParentJointIndex()); } if (!scriptSideProperties.localPositionChanged() && !scriptSideProperties.positionChanged()) { From 011a43d5f214243e00b3feee613d6028299f977e Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Tue, 8 Dec 2015 11:08:22 -0800 Subject: [PATCH 401/401] Add sphere and cube triangle counts to displayed stats --- .../src/RenderableBoxEntityItem.cpp | 5 ++++- .../src/RenderableSphereEntityItem.cpp | 4 +++- libraries/render-utils/src/GeometryCache.cpp | 14 ++++++++++++++ libraries/render-utils/src/GeometryCache.h | 3 +++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp b/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp index 588f17d959..54fe491c46 100644 --- a/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableBoxEntityItem.cpp @@ -41,6 +41,7 @@ void RenderableBoxEntityItem::render(RenderArgs* args) { Q_ASSERT(getType() == EntityTypes::Box); Q_ASSERT(args->_batch); + if (!_procedural) { _procedural.reset(new Procedural(this->getUserData())); _procedural->_vertexSource = simple_vert; @@ -64,4 +65,6 @@ void RenderableBoxEntityItem::render(RenderArgs* args) { } else { DependencyManager::get()->renderSolidCubeInstance(batch, getTransformToCenter(), cubeColor); } -}; + static const auto triCount = DependencyManager::get()->getCubeTriangleCount(); + args->_details._trianglesRendered += triCount; +} diff --git a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp index 2bdcfc19ad..8768e41a07 100644 --- a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp @@ -71,4 +71,6 @@ void RenderableSphereEntityItem::render(RenderArgs* args) { batch.setModelTransform(Transform()); DependencyManager::get()->renderSolidSphereInstance(batch, modelTransform, sphereColor); } -}; + static const auto triCount = DependencyManager::get()->getSphereTriangleCount(); + args->_details._trianglesRendered += triCount; +} diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 75b3b91c10..b9fdcd95a4 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -214,6 +214,19 @@ VertexVector tesselate(const VertexVector& startingTriangles, int count) { return triangles; } +size_t GeometryCache::getShapeTriangleCount(Shape shape) { + return _shapes[shape]._indexCount / VERTICES_PER_TRIANGLE; +} + +size_t GeometryCache::getSphereTriangleCount() { + return getShapeTriangleCount(Sphere); +} + +size_t GeometryCache::getCubeTriangleCount() { + return getShapeTriangleCount(Cube); +} + + // FIXME solids need per-face vertices, but smooth shaded // components do not. Find a way to support using draw elements // or draw arrays as appropriate @@ -1727,3 +1740,4 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { batch.setPipeline(_standardDrawPipeline); } } + diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index aa1593db78..c408115011 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -151,16 +151,19 @@ public: void renderWireShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& transformBuffer, gpu::BufferPointer& colorBuffer); void renderShape(gpu::Batch& batch, Shape shape); void renderWireShape(gpu::Batch& batch, Shape shape); + size_t getShapeTriangleCount(Shape shape); void renderCubeInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer transformBuffer, gpu::BufferPointer colorBuffer); void renderWireCubeInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer transformBuffer, gpu::BufferPointer colorBuffer); void renderCube(gpu::Batch& batch); void renderWireCube(gpu::Batch& batch); + size_t getCubeTriangleCount(); void renderSphereInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer transformBuffer, gpu::BufferPointer colorBuffer); void renderWireSphereInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer transformBuffer, gpu::BufferPointer colorBuffer); void renderSphere(gpu::Batch& batch); void renderWireSphere(gpu::Batch& batch); + size_t getSphereTriangleCount(); void renderGrid(gpu::Batch& batch, int xDivisions, int yDivisions, const glm::vec4& color); void renderGrid(gpu::Batch& batch, int x, int y, int width, int height, int rows, int cols, const glm::vec4& color, int id = UNKNOWN_ID);