mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 04:57:58 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into baseball
This commit is contained in:
commit
5154fbc8c5
76 changed files with 1332 additions and 610 deletions
|
@ -63,7 +63,9 @@ AvatarMixer::~AvatarMixer() {
|
||||||
_broadcastThread.wait();
|
_broadcastThread.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
const float BILLBOARD_AND_IDENTITY_SEND_PROBABILITY = 1.0f / 300.0f;
|
// An 80% chance of sending a identity packet within a 5 second interval.
|
||||||
|
// assuming 60 htz update rate.
|
||||||
|
const float BILLBOARD_AND_IDENTITY_SEND_PROBABILITY = 1.0f / 187.0f;
|
||||||
|
|
||||||
// NOTE: some additional optimizations to consider.
|
// NOTE: some additional optimizations to consider.
|
||||||
// 1) use the view frustum to cull those avatars that are out of view. Since avatar data doesn't need to be present
|
// 1) use the view frustum to cull those avatars that are out of view. Since avatar data doesn't need to be present
|
||||||
|
@ -243,6 +245,46 @@ void AvatarMixer::broadcastAvatarData() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make sure we send out identity and billboard packets to and from new arrivals.
|
||||||
|
bool forceSend = !otherNodeData->checkAndSetHasReceivedFirstPacketsFrom(node->getUUID());
|
||||||
|
|
||||||
|
// we will also force a send of billboard or identity packet
|
||||||
|
// if either has changed in the last frame
|
||||||
|
if (otherNodeData->getBillboardChangeTimestamp() > 0
|
||||||
|
&& (forceSend
|
||||||
|
|| otherNodeData->getBillboardChangeTimestamp() > _lastFrameTimestamp
|
||||||
|
|| distribution(generator) < BILLBOARD_AND_IDENTITY_SEND_PROBABILITY)) {
|
||||||
|
|
||||||
|
QByteArray rfcUUID = otherNode->getUUID().toRfc4122();
|
||||||
|
QByteArray billboard = otherNodeData->getAvatar().getBillboard();
|
||||||
|
|
||||||
|
auto billboardPacket = NLPacket::create(PacketType::AvatarBillboard, rfcUUID.size() + billboard.size());
|
||||||
|
billboardPacket->write(rfcUUID);
|
||||||
|
billboardPacket->write(billboard);
|
||||||
|
|
||||||
|
nodeList->sendPacket(std::move(billboardPacket), *node);
|
||||||
|
|
||||||
|
++_sumBillboardPackets;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (otherNodeData->getIdentityChangeTimestamp() > 0
|
||||||
|
&& (forceSend
|
||||||
|
|| otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp
|
||||||
|
|| distribution(generator) < BILLBOARD_AND_IDENTITY_SEND_PROBABILITY)) {
|
||||||
|
|
||||||
|
QByteArray individualData = otherNodeData->getAvatar().identityByteArray();
|
||||||
|
|
||||||
|
auto identityPacket = NLPacket::create(PacketType::AvatarIdentity, individualData.size());
|
||||||
|
|
||||||
|
individualData.replace(0, NUM_BYTES_RFC4122_UUID, otherNode->getUUID().toRfc4122());
|
||||||
|
|
||||||
|
identityPacket->write(individualData);
|
||||||
|
|
||||||
|
nodeList->sendPacket(std::move(identityPacket), *node);
|
||||||
|
|
||||||
|
++_sumIdentityPackets;
|
||||||
|
}
|
||||||
|
|
||||||
AvatarData& otherAvatar = otherNodeData->getAvatar();
|
AvatarData& otherAvatar = otherNodeData->getAvatar();
|
||||||
// Decide whether to send this avatar's data based on it's distance from us
|
// Decide whether to send this avatar's data based on it's distance from us
|
||||||
|
|
||||||
|
@ -254,10 +296,10 @@ void AvatarMixer::broadcastAvatarData() {
|
||||||
// potentially update the max full rate distance for this frame
|
// potentially update the max full rate distance for this frame
|
||||||
maxAvatarDistanceThisFrame = std::max(maxAvatarDistanceThisFrame, distanceToAvatar);
|
maxAvatarDistanceThisFrame = std::max(maxAvatarDistanceThisFrame, distanceToAvatar);
|
||||||
|
|
||||||
if (distanceToAvatar != 0.0f
|
if (distanceToAvatar != 0.0f
|
||||||
&& distribution(generator) > (nodeData->getFullRateDistance() / distanceToAvatar)) {
|
&& distribution(generator) > (nodeData->getFullRateDistance() / distanceToAvatar)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AvatarDataSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(otherNode->getUUID());
|
AvatarDataSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(otherNode->getUUID());
|
||||||
AvatarDataSequenceNumber lastSeqFromSender = otherNodeData->getLastReceivedSequenceNumber();
|
AvatarDataSequenceNumber lastSeqFromSender = otherNodeData->getLastReceivedSequenceNumber();
|
||||||
|
@ -291,53 +333,11 @@ void AvatarMixer::broadcastAvatarData() {
|
||||||
|
|
||||||
numAvatarDataBytes += avatarPacketList->write(otherNode->getUUID().toRfc4122());
|
numAvatarDataBytes += avatarPacketList->write(otherNode->getUUID().toRfc4122());
|
||||||
numAvatarDataBytes +=
|
numAvatarDataBytes +=
|
||||||
avatarPacketList->write(otherAvatar.toByteArray(false, randFloat() < AVATAR_SEND_FULL_UPDATE_RATIO));
|
avatarPacketList->write(otherAvatar.toByteArray(false, distribution(generator) < AVATAR_SEND_FULL_UPDATE_RATIO));
|
||||||
|
|
||||||
avatarPacketList->endSegment();
|
avatarPacketList->endSegment();
|
||||||
|
|
||||||
// if the receiving avatar has just connected make sure we send out the mesh and billboard
|
|
||||||
// for this avatar (assuming they exist)
|
|
||||||
bool forceSend = !nodeData->checkAndSetHasReceivedFirstPackets();
|
|
||||||
|
|
||||||
// we will also force a send of billboard or identity packet
|
|
||||||
// if either has changed in the last frame
|
|
||||||
|
|
||||||
if (otherNodeData->getBillboardChangeTimestamp() > 0
|
|
||||||
&& (forceSend
|
|
||||||
|| otherNodeData->getBillboardChangeTimestamp() > _lastFrameTimestamp
|
|
||||||
|| randFloat() < BILLBOARD_AND_IDENTITY_SEND_PROBABILITY)) {
|
|
||||||
|
|
||||||
QByteArray rfcUUID = otherNode->getUUID().toRfc4122();
|
|
||||||
QByteArray billboard = otherNodeData->getAvatar().getBillboard();
|
|
||||||
|
|
||||||
auto billboardPacket = NLPacket::create(PacketType::AvatarBillboard, rfcUUID.size() + billboard.size());
|
|
||||||
billboardPacket->write(rfcUUID);
|
|
||||||
billboardPacket->write(billboard);
|
|
||||||
|
|
||||||
nodeList->sendPacket(std::move(billboardPacket), *node);
|
|
||||||
|
|
||||||
++_sumBillboardPackets;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (otherNodeData->getIdentityChangeTimestamp() > 0
|
|
||||||
&& (forceSend
|
|
||||||
|| otherNodeData->getIdentityChangeTimestamp() > _lastFrameTimestamp
|
|
||||||
|| randFloat() < BILLBOARD_AND_IDENTITY_SEND_PROBABILITY)) {
|
|
||||||
|
|
||||||
QByteArray individualData = otherNodeData->getAvatar().identityByteArray();
|
|
||||||
|
|
||||||
auto identityPacket = NLPacket::create(PacketType::AvatarIdentity, individualData.size());
|
|
||||||
|
|
||||||
individualData.replace(0, NUM_BYTES_RFC4122_UUID, otherNode->getUUID().toRfc4122());
|
|
||||||
|
|
||||||
identityPacket->write(individualData);
|
|
||||||
|
|
||||||
nodeList->sendPacket(std::move(identityPacket), *node);
|
|
||||||
|
|
||||||
++_sumIdentityPackets;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// close the current packet so that we're always sending something
|
// close the current packet so that we're always sending something
|
||||||
avatarPacketList->closeCurrentPacket(true);
|
avatarPacketList->closeCurrentPacket(true);
|
||||||
|
|
||||||
|
@ -484,7 +484,7 @@ void AvatarMixer::sendStatsPacket() {
|
||||||
|
|
||||||
// add the key to ask the domain-server for a username replacement, if it has it
|
// add the key to ask the domain-server for a username replacement, if it has it
|
||||||
avatarStats[USERNAME_UUID_REPLACEMENT_STATS_KEY] = uuidStringWithoutCurlyBraces(node->getUUID());
|
avatarStats[USERNAME_UUID_REPLACEMENT_STATS_KEY] = uuidStringWithoutCurlyBraces(node->getUUID());
|
||||||
|
|
||||||
avatarStats[NODE_OUTBOUND_KBPS_STAT_KEY] = node->getOutboundBandwidth();
|
avatarStats[NODE_OUTBOUND_KBPS_STAT_KEY] = node->getOutboundBandwidth();
|
||||||
avatarStats[NODE_INBOUND_KBPS_STAT_KEY] = node->getInboundBandwidth();
|
avatarStats[NODE_INBOUND_KBPS_STAT_KEY] = node->getInboundBandwidth();
|
||||||
|
|
||||||
|
@ -537,7 +537,7 @@ void AvatarMixer::run() {
|
||||||
qDebug() << "Waiting for domain settings from domain-server.";
|
qDebug() << "Waiting for domain settings from domain-server.";
|
||||||
|
|
||||||
// block until we get the settingsRequestComplete signal
|
// block until we get the settingsRequestComplete signal
|
||||||
|
|
||||||
QEventLoop loop;
|
QEventLoop loop;
|
||||||
connect(&domainHandler, &DomainHandler::settingsReceived, &loop, &QEventLoop::quit);
|
connect(&domainHandler, &DomainHandler::settingsReceived, &loop, &QEventLoop::quit);
|
||||||
connect(&domainHandler, &DomainHandler::settingsReceiveFail, &loop, &QEventLoop::quit);
|
connect(&domainHandler, &DomainHandler::settingsReceiveFail, &loop, &QEventLoop::quit);
|
||||||
|
|
|
@ -16,15 +16,17 @@
|
||||||
int AvatarMixerClientData::parseData(NLPacket& packet) {
|
int AvatarMixerClientData::parseData(NLPacket& packet) {
|
||||||
// pull the sequence number from the data first
|
// pull the sequence number from the data first
|
||||||
packet.readPrimitive(&_lastReceivedSequenceNumber);
|
packet.readPrimitive(&_lastReceivedSequenceNumber);
|
||||||
|
|
||||||
// compute the offset to the data payload
|
// compute the offset to the data payload
|
||||||
return _avatar.parseDataFromBuffer(packet.readWithoutCopy(packet.bytesLeftToRead()));
|
return _avatar.parseDataFromBuffer(packet.readWithoutCopy(packet.bytesLeftToRead()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AvatarMixerClientData::checkAndSetHasReceivedFirstPackets() {
|
bool AvatarMixerClientData::checkAndSetHasReceivedFirstPacketsFrom(const QUuid& uuid) {
|
||||||
bool oldValue = _hasReceivedFirstPackets;
|
if (_hasReceivedFirstPacketsFrom.find(uuid) == _hasReceivedFirstPacketsFrom.end()) {
|
||||||
_hasReceivedFirstPackets = true;
|
_hasReceivedFirstPacketsFrom.insert(uuid);
|
||||||
return oldValue;
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t AvatarMixerClientData::getLastBroadcastSequenceNumber(const QUuid& nodeUUID) const {
|
uint16_t AvatarMixerClientData::getLastBroadcastSequenceNumber(const QUuid& nodeUUID) const {
|
||||||
|
@ -45,9 +47,9 @@ void AvatarMixerClientData::loadJSONStats(QJsonObject& jsonObject) const {
|
||||||
jsonObject["avg_other_av_starves_per_second"] = getAvgNumOtherAvatarStarvesPerSecond();
|
jsonObject["avg_other_av_starves_per_second"] = getAvgNumOtherAvatarStarvesPerSecond();
|
||||||
jsonObject["avg_other_av_skips_per_second"] = getAvgNumOtherAvatarSkipsPerSecond();
|
jsonObject["avg_other_av_skips_per_second"] = getAvgNumOtherAvatarSkipsPerSecond();
|
||||||
jsonObject["total_num_out_of_order_sends"] = _numOutOfOrderSends;
|
jsonObject["total_num_out_of_order_sends"] = _numOutOfOrderSends;
|
||||||
|
|
||||||
jsonObject[OUTBOUND_AVATAR_DATA_STATS_KEY] = getOutboundAvatarDataKbps();
|
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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cfloat>
|
#include <cfloat>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include <QtCore/QJsonObject>
|
#include <QtCore/QJsonObject>
|
||||||
#include <QtCore/QUrl>
|
#include <QtCore/QUrl>
|
||||||
|
@ -34,25 +35,25 @@ class AvatarMixerClientData : public NodeData {
|
||||||
public:
|
public:
|
||||||
int parseData(NLPacket& packet);
|
int parseData(NLPacket& packet);
|
||||||
AvatarData& getAvatar() { return _avatar; }
|
AvatarData& getAvatar() { return _avatar; }
|
||||||
|
|
||||||
bool checkAndSetHasReceivedFirstPackets();
|
bool checkAndSetHasReceivedFirstPacketsFrom(const QUuid& uuid);
|
||||||
|
|
||||||
uint16_t getLastBroadcastSequenceNumber(const QUuid& nodeUUID) const;
|
uint16_t getLastBroadcastSequenceNumber(const QUuid& nodeUUID) const;
|
||||||
void setLastBroadcastSequenceNumber(const QUuid& nodeUUID, uint16_t sequenceNumber)
|
void setLastBroadcastSequenceNumber(const QUuid& nodeUUID, uint16_t sequenceNumber)
|
||||||
{ _lastBroadcastSequenceNumbers[nodeUUID] = sequenceNumber; }
|
{ _lastBroadcastSequenceNumbers[nodeUUID] = sequenceNumber; }
|
||||||
Q_INVOKABLE void removeLastBroadcastSequenceNumber(const QUuid& nodeUUID) { _lastBroadcastSequenceNumbers.erase(nodeUUID); }
|
Q_INVOKABLE void removeLastBroadcastSequenceNumber(const QUuid& nodeUUID) { _lastBroadcastSequenceNumbers.erase(nodeUUID); }
|
||||||
|
|
||||||
uint16_t getLastReceivedSequenceNumber() const { return _lastReceivedSequenceNumber; }
|
uint16_t getLastReceivedSequenceNumber() const { return _lastReceivedSequenceNumber; }
|
||||||
|
|
||||||
quint64 getBillboardChangeTimestamp() const { return _billboardChangeTimestamp; }
|
quint64 getBillboardChangeTimestamp() const { return _billboardChangeTimestamp; }
|
||||||
void setBillboardChangeTimestamp(quint64 billboardChangeTimestamp) { _billboardChangeTimestamp = billboardChangeTimestamp; }
|
void setBillboardChangeTimestamp(quint64 billboardChangeTimestamp) { _billboardChangeTimestamp = billboardChangeTimestamp; }
|
||||||
|
|
||||||
quint64 getIdentityChangeTimestamp() const { return _identityChangeTimestamp; }
|
quint64 getIdentityChangeTimestamp() const { return _identityChangeTimestamp; }
|
||||||
void setIdentityChangeTimestamp(quint64 identityChangeTimestamp) { _identityChangeTimestamp = identityChangeTimestamp; }
|
void setIdentityChangeTimestamp(quint64 identityChangeTimestamp) { _identityChangeTimestamp = identityChangeTimestamp; }
|
||||||
|
|
||||||
void setFullRateDistance(float fullRateDistance) { _fullRateDistance = fullRateDistance; }
|
void setFullRateDistance(float fullRateDistance) { _fullRateDistance = fullRateDistance; }
|
||||||
float getFullRateDistance() const { return _fullRateDistance; }
|
float getFullRateDistance() const { return _fullRateDistance; }
|
||||||
|
|
||||||
void setMaxAvatarDistance(float maxAvatarDistance) { _maxAvatarDistance = maxAvatarDistance; }
|
void setMaxAvatarDistance(float maxAvatarDistance) { _maxAvatarDistance = maxAvatarDistance; }
|
||||||
float getMaxAvatarDistance() const { return _maxAvatarDistance; }
|
float getMaxAvatarDistance() const { return _maxAvatarDistance; }
|
||||||
|
|
||||||
|
@ -73,31 +74,31 @@ public:
|
||||||
void resetNumFramesSinceFRDAdjustment() { _numFramesSinceAdjustment = 0; }
|
void resetNumFramesSinceFRDAdjustment() { _numFramesSinceAdjustment = 0; }
|
||||||
|
|
||||||
void recordSentAvatarData(int numBytes) { _avgOtherAvatarDataRate.updateAverage((float) numBytes); }
|
void recordSentAvatarData(int numBytes) { _avgOtherAvatarDataRate.updateAverage((float) numBytes); }
|
||||||
|
|
||||||
float getOutboundAvatarDataKbps() const
|
float getOutboundAvatarDataKbps() const
|
||||||
{ return _avgOtherAvatarDataRate.getAverageSampleValuePerSecond() / (float) BYTES_PER_KILOBIT; }
|
{ return _avgOtherAvatarDataRate.getAverageSampleValuePerSecond() / (float) BYTES_PER_KILOBIT; }
|
||||||
|
|
||||||
void loadJSONStats(QJsonObject& jsonObject) const;
|
void loadJSONStats(QJsonObject& jsonObject) const;
|
||||||
private:
|
private:
|
||||||
AvatarData _avatar;
|
AvatarData _avatar;
|
||||||
|
|
||||||
uint16_t _lastReceivedSequenceNumber { 0 };
|
uint16_t _lastReceivedSequenceNumber { 0 };
|
||||||
std::unordered_map<QUuid, uint16_t> _lastBroadcastSequenceNumbers;
|
std::unordered_map<QUuid, uint16_t> _lastBroadcastSequenceNumbers;
|
||||||
|
std::unordered_set<QUuid> _hasReceivedFirstPacketsFrom;
|
||||||
|
|
||||||
bool _hasReceivedFirstPackets = false;
|
|
||||||
quint64 _billboardChangeTimestamp = 0;
|
quint64 _billboardChangeTimestamp = 0;
|
||||||
quint64 _identityChangeTimestamp = 0;
|
quint64 _identityChangeTimestamp = 0;
|
||||||
|
|
||||||
float _fullRateDistance = FLT_MAX;
|
float _fullRateDistance = FLT_MAX;
|
||||||
float _maxAvatarDistance = FLT_MAX;
|
float _maxAvatarDistance = FLT_MAX;
|
||||||
|
|
||||||
int _numAvatarsSentLastFrame = 0;
|
int _numAvatarsSentLastFrame = 0;
|
||||||
int _numFramesSinceAdjustment = 0;
|
int _numFramesSinceAdjustment = 0;
|
||||||
|
|
||||||
SimpleMovingAverage _otherAvatarStarves;
|
SimpleMovingAverage _otherAvatarStarves;
|
||||||
SimpleMovingAverage _otherAvatarSkips;
|
SimpleMovingAverage _otherAvatarSkips;
|
||||||
int _numOutOfOrderSends = 0;
|
int _numOutOfOrderSends = 0;
|
||||||
|
|
||||||
SimpleMovingAverage _avgOtherAvatarDataRate;
|
SimpleMovingAverage _avgOtherAvatarDataRate;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "OctreeSendThread.h"
|
#include "OctreeSendThread.h"
|
||||||
#include "OctreeServer.h"
|
#include "OctreeServer.h"
|
||||||
#include "OctreeServerConsts.h"
|
#include "OctreeServerConsts.h"
|
||||||
|
#include "OctreeLogging.h"
|
||||||
|
|
||||||
quint64 startSceneSleepTime = 0;
|
quint64 startSceneSleepTime = 0;
|
||||||
quint64 endSceneSleepTime = 0;
|
quint64 endSceneSleepTime = 0;
|
||||||
|
@ -572,14 +573,12 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus
|
||||||
OctreeServer::trackInsideTime((float)elapsedInsideUsecs);
|
OctreeServer::trackInsideTime((float)elapsedInsideUsecs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (somethingToSend && _myServer->wantsVerboseDebug()) {
|
if (somethingToSend && _myServer->wantsVerboseDebug()) {
|
||||||
qDebug() << "Hit PPS Limit, packetsSentThisInterval =" << packetsSentThisInterval
|
qCDebug(octree) << "Hit PPS Limit, packetsSentThisInterval =" << packetsSentThisInterval
|
||||||
<< " maxPacketsPerInterval = " << maxPacketsPerInterval
|
<< " maxPacketsPerInterval = " << maxPacketsPerInterval
|
||||||
<< " clientMaxPacketsPerInterval = " << clientMaxPacketsPerInterval;
|
<< " clientMaxPacketsPerInterval = " << clientMaxPacketsPerInterval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Here's where we can/should allow the server to send other data...
|
// Here's where we can/should allow the server to send other data...
|
||||||
// send the environment packet
|
// send the environment packet
|
||||||
// TODO: should we turn this into a while loop to better handle sending multiple special packets
|
// TODO: should we turn this into a while loop to better handle sending multiple special packets
|
||||||
|
|
|
@ -272,6 +272,7 @@ void DomainServer::setupNodeListAndAssignments(const QUuid& sessionUUID) {
|
||||||
packetReceiver.registerListener(PacketType::DomainListRequest, this, "processListRequestPacket");
|
packetReceiver.registerListener(PacketType::DomainListRequest, this, "processListRequestPacket");
|
||||||
packetReceiver.registerListener(PacketType::DomainServerPathQuery, this, "processPathQueryPacket");
|
packetReceiver.registerListener(PacketType::DomainServerPathQuery, this, "processPathQueryPacket");
|
||||||
packetReceiver.registerMessageListener(PacketType::NodeJsonStats, this, "processNodeJSONStatsPacket");
|
packetReceiver.registerMessageListener(PacketType::NodeJsonStats, this, "processNodeJSONStatsPacket");
|
||||||
|
packetReceiver.registerListener(PacketType::DomainDisconnectRequest, this, "processNodeDisconnectRequestPacket");
|
||||||
|
|
||||||
// NodeList won't be available to the settings manager when it is created, so call registerListener here
|
// NodeList won't be available to the settings manager when it is created, so call registerListener here
|
||||||
packetReceiver.registerListener(PacketType::DomainSettingsRequest, &_settingsManager, "processSettingsRequestPacket");
|
packetReceiver.registerListener(PacketType::DomainSettingsRequest, &_settingsManager, "processSettingsRequestPacket");
|
||||||
|
@ -1826,3 +1827,24 @@ void DomainServer::processPathQueryPacket(QSharedPointer<NLPacket> packet) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DomainServer::processNodeDisconnectRequestPacket(QSharedPointer<NLPacket> packet) {
|
||||||
|
// This packet has been matched to a source node and they're asking not to be in the domain anymore
|
||||||
|
auto limitedNodeList = DependencyManager::get<LimitedNodeList>();
|
||||||
|
|
||||||
|
const QUuid& nodeUUID = packet->getSourceID();
|
||||||
|
|
||||||
|
qDebug() << "Received a disconnect request from node with UUID" << nodeUUID;
|
||||||
|
|
||||||
|
if (limitedNodeList->killNodeWithUUID(nodeUUID)) {
|
||||||
|
static auto removedNodePacket = NLPacket::create(PacketType::DomainServerRemovedNode, NUM_BYTES_RFC4122_UUID);
|
||||||
|
|
||||||
|
removedNodePacket->reset();
|
||||||
|
removedNodePacket->write(nodeUUID.toRfc4122());
|
||||||
|
|
||||||
|
// broadcast out the DomainServerRemovedNode message
|
||||||
|
limitedNodeList->eachNode([&limitedNodeList](const SharedNodePointer& otherNode){
|
||||||
|
limitedNodeList->sendUnreliablePacket(*removedNodePacket, *otherNode);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -60,7 +60,8 @@ public slots:
|
||||||
void processListRequestPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
void processListRequestPacket(QSharedPointer<NLPacket> packet, SharedNodePointer sendingNode);
|
||||||
void processNodeJSONStatsPacket(QSharedPointer<NLPacketList> packetList, SharedNodePointer sendingNode);
|
void processNodeJSONStatsPacket(QSharedPointer<NLPacketList> packetList, SharedNodePointer sendingNode);
|
||||||
void processPathQueryPacket(QSharedPointer<NLPacket> packet);
|
void processPathQueryPacket(QSharedPointer<NLPacket> packet);
|
||||||
|
void processNodeDisconnectRequestPacket(QSharedPointer<NLPacket> packet);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void aboutToQuit();
|
void aboutToQuit();
|
||||||
|
|
||||||
|
|
|
@ -33,15 +33,6 @@ var SHOW = 4;
|
||||||
var HIDE = 5;
|
var HIDE = 5;
|
||||||
var LOAD = 6;
|
var LOAD = 6;
|
||||||
|
|
||||||
var COLORS = [];
|
|
||||||
COLORS[PLAY] = { red: PLAY, green: 0, blue: 0 };
|
|
||||||
COLORS[PLAY_LOOP] = { red: PLAY_LOOP, green: 0, blue: 0 };
|
|
||||||
COLORS[STOP] = { red: STOP, green: 0, blue: 0 };
|
|
||||||
COLORS[SHOW] = { red: SHOW, green: 0, blue: 0 };
|
|
||||||
COLORS[HIDE] = { red: HIDE, green: 0, blue: 0 };
|
|
||||||
COLORS[LOAD] = { red: LOAD, green: 0, blue: 0 };
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var windowDimensions = Controller.getViewportDimensions();
|
var windowDimensions = Controller.getViewportDimensions();
|
||||||
var TOOL_ICON_URL = HIFI_PUBLIC_BUCKET + "images/tools/";
|
var TOOL_ICON_URL = HIFI_PUBLIC_BUCKET + "images/tools/";
|
||||||
|
@ -138,6 +129,7 @@ function setupToolBars() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendCommand(id, action) {
|
function sendCommand(id, action) {
|
||||||
|
|
||||||
if (action === SHOW) {
|
if (action === SHOW) {
|
||||||
toolBars[id].selectTool(onOffIcon[id], false);
|
toolBars[id].selectTool(onOffIcon[id], false);
|
||||||
toolBars[id].setAlpha(ALPHA_ON, playIcon[id]);
|
toolBars[id].setAlpha(ALPHA_ON, playIcon[id]);
|
||||||
|
@ -154,24 +146,29 @@ function sendCommand(id, action) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id === (toolBars.length - 1)) {
|
if (id === (toolBars.length - 1))
|
||||||
for (i = 0; i < NUM_AC; i++) {
|
id = -1;
|
||||||
sendCommand(i, action);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var position = { x: controlEntityPosition.x + id * controlEntitySize,
|
var controlEntity = Entities.addEntity({
|
||||||
y: controlEntityPosition.y, z: controlEntityPosition.z };
|
name: 'New Actor Controller',
|
||||||
Entities.addEntity({
|
|
||||||
name: "Actor Controller",
|
|
||||||
userData: clip_url,
|
|
||||||
type: "Box",
|
type: "Box",
|
||||||
position: position,
|
color: { red: 0, green: 0, blue: 0 },
|
||||||
dimensions: { x: controlEntitySize, y: controlEntitySize, z: controlEntitySize },
|
position: controlEntityPosition,
|
||||||
color: COLORS[action],
|
dimensions: { x: controlEntitySize, y: controlEntitySize, z: controlEntitySize },
|
||||||
lifetime: 5
|
visible: false,
|
||||||
});
|
lifetime: 10,
|
||||||
|
userData: JSON.stringify({
|
||||||
|
idKey: {
|
||||||
|
uD_id: id
|
||||||
|
},
|
||||||
|
actionKey: {
|
||||||
|
uD_action: action
|
||||||
|
},
|
||||||
|
clipKey: {
|
||||||
|
uD_url: clip_url
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function mousePressEvent(event) {
|
function mousePressEvent(event) {
|
||||||
|
@ -191,8 +188,12 @@ function mousePressEvent(event) {
|
||||||
sendCommand(i, PLAY_LOOP);
|
sendCommand(i, PLAY_LOOP);
|
||||||
} else if (stopIcon[i] === toolBars[i].clicked(clickedOverlay, false)) {
|
} else if (stopIcon[i] === toolBars[i].clicked(clickedOverlay, false)) {
|
||||||
sendCommand(i, STOP);
|
sendCommand(i, STOP);
|
||||||
} else if (loadIcon[i] === toolBars[i].clicked(clickedOverlay, false)) {
|
} else if (loadIcon[i] === toolBars[i].clicked(clickedOverlay, false)) {
|
||||||
sendCommand(i, LOAD);
|
input_text = Window.prompt("Insert the url of the clip: ","");
|
||||||
|
if (!(input_text === "" || input_text === null)) {
|
||||||
|
clip_url = input_text;
|
||||||
|
sendCommand(i, LOAD);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Check individual controls
|
// Check individual controls
|
||||||
for (i = 0; i < NUM_AC; i++) {
|
for (i = 0; i < NUM_AC; i++) {
|
||||||
|
@ -210,7 +211,7 @@ function mousePressEvent(event) {
|
||||||
sendCommand(i, STOP);
|
sendCommand(i, STOP);
|
||||||
} else if (loadIcon[i] === toolBars[i].clicked(clickedOverlay, false)) {
|
} else if (loadIcon[i] === toolBars[i].clicked(clickedOverlay, false)) {
|
||||||
input_text = Window.prompt("Insert the url of the clip: ","");
|
input_text = Window.prompt("Insert the url of the clip: ","");
|
||||||
if(!(input_text === "" || input_text === null)){
|
if (!(input_text === "" || input_text === null)) {
|
||||||
clip_url = input_text;
|
clip_url = input_text;
|
||||||
sendCommand(i, LOAD);
|
sendCommand(i, LOAD);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,18 +38,6 @@ var SHOW = 4;
|
||||||
var HIDE = 5;
|
var HIDE = 5;
|
||||||
var LOAD = 6;
|
var LOAD = 6;
|
||||||
|
|
||||||
var COLORS = [];
|
|
||||||
COLORS[PLAY] = { red: PLAY, green: 0, blue: 0 };
|
|
||||||
COLORS[PLAY_LOOP] = { red: PLAY_LOOP, green: 0, blue: 0 };
|
|
||||||
COLORS[STOP] = { red: STOP, green: 0, blue: 0 };
|
|
||||||
COLORS[SHOW] = { red: SHOW, green: 0, blue: 0 };
|
|
||||||
COLORS[HIDE] = { red: HIDE, green: 0, blue: 0 };
|
|
||||||
COLORS[LOAD] = { red: LOAD, green: 0, blue: 0 };
|
|
||||||
|
|
||||||
controlEntityPosition.x += id * controlEntitySize;
|
|
||||||
|
|
||||||
Avatar.loadRecording(clip_url);
|
|
||||||
|
|
||||||
Avatar.setPlayFromCurrentLocation(playFromCurrentLocation);
|
Avatar.setPlayFromCurrentLocation(playFromCurrentLocation);
|
||||||
Avatar.setPlayerUseDisplayName(useDisplayName);
|
Avatar.setPlayerUseDisplayName(useDisplayName);
|
||||||
Avatar.setPlayerUseAttachments(useAttachments);
|
Avatar.setPlayerUseAttachments(useAttachments);
|
||||||
|
@ -67,27 +55,27 @@ function setupEntityViewer() {
|
||||||
EntityViewer.queryOctree();
|
EntityViewer.queryOctree();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAction(controlEntity) {
|
function getAction(controlEntity) {
|
||||||
clip_url = controlEntity.userData;
|
if (controlEntity === null) {
|
||||||
|
return DO_NOTHING;
|
||||||
|
}
|
||||||
|
|
||||||
|
var userData = JSON.parse(Entities.getEntityProperties(controlEntity, ["userData"]).userData);
|
||||||
|
|
||||||
if (controlEntity === null ||
|
var uD_id = userData.idKey.uD_id;
|
||||||
controlEntity.position.x !== controlEntityPosition.x ||
|
var uD_action = userData.actionKey.uD_action;
|
||||||
controlEntity.position.y !== controlEntityPosition.y ||
|
var uD_url = userData.clipKey.uD_url;
|
||||||
controlEntity.position.z !== controlEntityPosition.z ||
|
|
||||||
controlEntity.dimensions.x !== controlEntitySize) {
|
Entities.deleteEntity((Entities.getEntityProperties(controlEntity)).id);
|
||||||
|
|
||||||
|
if (uD_id === id || uD_id === -1) {
|
||||||
|
if (uD_action === 6)
|
||||||
|
clip_url = uD_url;
|
||||||
|
|
||||||
|
return uD_action;
|
||||||
|
} else {
|
||||||
return DO_NOTHING;
|
return DO_NOTHING;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i in COLORS) {
|
|
||||||
if (controlEntity.color.red === COLORS[i].red &&
|
|
||||||
controlEntity.color.green === COLORS[i].green &&
|
|
||||||
controlEntity.color.blue === COLORS[i].blue) {
|
|
||||||
Entities.deleteEntity(controlEntity.id);
|
|
||||||
return parseInt(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return DO_NOTHING;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
count = 100; // This is necessary to wait for the audio mixer to connect
|
count = 100; // This is necessary to wait for the audio mixer to connect
|
||||||
|
@ -100,7 +88,7 @@ function update(event) {
|
||||||
|
|
||||||
|
|
||||||
var controlEntity = Entities.findClosestEntity(controlEntityPosition, controlEntitySize);
|
var controlEntity = Entities.findClosestEntity(controlEntityPosition, controlEntitySize);
|
||||||
var action = getAction(Entities.getEntityProperties(controlEntity));
|
var action = getAction(controlEntity);
|
||||||
|
|
||||||
switch(action) {
|
switch(action) {
|
||||||
case PLAY:
|
case PLAY:
|
||||||
|
|
|
@ -506,6 +506,7 @@ Grabber.prototype.activateEntity = function(entityID, grabbedProperties) {
|
||||||
if (data["refCount"] == 1) {
|
if (data["refCount"] == 1) {
|
||||||
data["gravity"] = grabbedProperties.gravity;
|
data["gravity"] = grabbedProperties.gravity;
|
||||||
data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions;
|
data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions;
|
||||||
|
data["collisionsWillMove"] = grabbedProperties.collisionsWillMove;
|
||||||
var whileHeldProperties = {gravity: {x:0, y:0, z:0}};
|
var whileHeldProperties = {gravity: {x:0, y:0, z:0}};
|
||||||
if (invertSolidWhileHeld) {
|
if (invertSolidWhileHeld) {
|
||||||
whileHeldProperties["ignoreForCollisions"] = ! grabbedProperties.ignoreForCollisions;
|
whileHeldProperties["ignoreForCollisions"] = ! grabbedProperties.ignoreForCollisions;
|
||||||
|
@ -522,7 +523,8 @@ Grabber.prototype.deactivateEntity = function(entityID) {
|
||||||
if (data["refCount"] < 1) {
|
if (data["refCount"] < 1) {
|
||||||
Entities.editEntity(entityID, {
|
Entities.editEntity(entityID, {
|
||||||
gravity: data["gravity"],
|
gravity: data["gravity"],
|
||||||
ignoreForCollisions: data["ignoreForCollisions"]
|
ignoreForCollisions: data["ignoreForCollisions"],
|
||||||
|
collisionsWillMove: data["collisionsWillMove"]
|
||||||
});
|
});
|
||||||
data = null;
|
data = null;
|
||||||
}
|
}
|
||||||
|
|
137
examples/grabInspector.js
Normal file
137
examples/grabInspector.js
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
//
|
||||||
|
// grabInspector.js
|
||||||
|
// examples
|
||||||
|
//
|
||||||
|
// Created by Seth Alves on 2015-9-30.
|
||||||
|
// 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("libraries/utils.js");
|
||||||
|
|
||||||
|
var INSPECT_RADIUS = 10;
|
||||||
|
var overlays = {};
|
||||||
|
|
||||||
|
var toType = function(obj) {
|
||||||
|
return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
function grabDataToString(grabData) {
|
||||||
|
var result = "";
|
||||||
|
|
||||||
|
for (var argumentName in grabData) {
|
||||||
|
if (grabData.hasOwnProperty(argumentName)) {
|
||||||
|
if (argumentName == "type") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var arg = grabData[argumentName];
|
||||||
|
var argType = toType(arg);
|
||||||
|
var argString = arg;
|
||||||
|
if (argType == "object") {
|
||||||
|
if (Object.keys(arg).length == 3) {
|
||||||
|
argString = vec3toStr(arg, 1);
|
||||||
|
}
|
||||||
|
} else if (argType == "number") {
|
||||||
|
argString = arg.toFixed(2);
|
||||||
|
}
|
||||||
|
result += argumentName + ": "
|
||||||
|
// + toType(arg) + " -- "
|
||||||
|
+ argString + "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function updateOverlay(entityID, grabText) {
|
||||||
|
var properties = Entities.getEntityProperties(entityID, ["position", "dimensions"]);
|
||||||
|
var position = Vec3.sum(properties.position, {x:0, y:properties.dimensions.y, z:0});
|
||||||
|
if (entityID in overlays) {
|
||||||
|
var overlay = overlays[entityID];
|
||||||
|
Overlays.editOverlay(overlay, {
|
||||||
|
text: grabText,
|
||||||
|
position: position
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
var lines = grabText.split(/\r\n|\r|\n/);
|
||||||
|
|
||||||
|
var maxLineLength = lines[0].length;
|
||||||
|
for (var i = 1; i < lines.length; i++) {
|
||||||
|
if (lines[i].length > maxLineLength) {
|
||||||
|
maxLineLength = lines[i].length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var textWidth = maxLineLength * 0.034; // XXX how to know this?
|
||||||
|
var textHeight = .5;
|
||||||
|
var numberOfLines = lines.length;
|
||||||
|
var textMargin = 0.05;
|
||||||
|
var lineHeight = (textHeight - (2 * textMargin)) / numberOfLines;
|
||||||
|
|
||||||
|
overlays[entityID] = Overlays.addOverlay("text3d", {
|
||||||
|
position: position,
|
||||||
|
dimensions: { x: textWidth, y: textHeight },
|
||||||
|
backgroundColor: { red: 0, green: 0, blue: 0},
|
||||||
|
color: { red: 255, green: 255, blue: 255},
|
||||||
|
topMargin: textMargin,
|
||||||
|
leftMargin: textMargin,
|
||||||
|
bottomMargin: textMargin,
|
||||||
|
rightMargin: textMargin,
|
||||||
|
text: grabText,
|
||||||
|
lineHeight: lineHeight,
|
||||||
|
alpha: 0.9,
|
||||||
|
backgroundAlpha: 0.9,
|
||||||
|
ignoreRayIntersection: true,
|
||||||
|
visible: true,
|
||||||
|
isFacingAvatar: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function cleanup() {
|
||||||
|
for (var entityID in overlays) {
|
||||||
|
Overlays.deleteOverlay(overlays[entityID]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Script.setInterval(function() {
|
||||||
|
var nearbyEntities = Entities.findEntities(MyAvatar.position, INSPECT_RADIUS);
|
||||||
|
for (var entityIndex = 0; entityIndex < nearbyEntities.length; entityIndex++) {
|
||||||
|
var entityID = nearbyEntities[entityIndex];
|
||||||
|
var userData = getEntityUserData(entityID);
|
||||||
|
var grabData = userData["grabKey"]
|
||||||
|
|
||||||
|
// {"grabbableKey":{"invertSolidWhileHeld":true},
|
||||||
|
// "grabKey":{"activated":true,"avatarId":"{6ea8b092-10e0-4058-888b-6facc40d0fe9}","refCount":1,"gravity":{"x":0,"y":0,"z":0},"ignoreForCollisions":0,"collisionsWillMove":1}
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (typeof grabData != 'undefined') {
|
||||||
|
var grabText = grabDataToString(grabData);
|
||||||
|
updateOverlay(entityID, grabText);
|
||||||
|
} else {
|
||||||
|
if (entityID in overlays) {
|
||||||
|
Overlays.deleteOverlay(overlays[entityID]);
|
||||||
|
delete overlays[entityID];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if an entity is too far away, remove its overlay
|
||||||
|
for (var entityID in overlays) {
|
||||||
|
var position = Entities.getEntityProperties(entityID, ["position"]).position;
|
||||||
|
if (Vec3.distance(position, MyAvatar.position) > INSPECT_RADIUS) {
|
||||||
|
Overlays.deleteOverlay(overlays[entityID]);
|
||||||
|
delete overlays[entityID];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(cleanup);
|
|
@ -176,14 +176,13 @@ function formatTime(time) {
|
||||||
var SEC_PER_MIN = 60;
|
var SEC_PER_MIN = 60;
|
||||||
var MSEC_PER_SEC = 1000;
|
var MSEC_PER_SEC = 1000;
|
||||||
|
|
||||||
var hours = Math.floor(time / (MSEC_PER_SEC * SEC_PER_MIN * MIN_PER_HOUR));
|
var hours = Math.floor(time / (SEC_PER_MIN * MIN_PER_HOUR));
|
||||||
time -= hours * (MSEC_PER_SEC * SEC_PER_MIN * MIN_PER_HOUR);
|
time -= hours * (SEC_PER_MIN * MIN_PER_HOUR);
|
||||||
|
|
||||||
var minutes = Math.floor(time / (MSEC_PER_SEC * SEC_PER_MIN));
|
var minutes = Math.floor(time / (SEC_PER_MIN));
|
||||||
time -= minutes * (MSEC_PER_SEC * SEC_PER_MIN);
|
time -= minutes * (SEC_PER_MIN);
|
||||||
|
|
||||||
var seconds = Math.floor(time / MSEC_PER_SEC);
|
var seconds = time;
|
||||||
seconds = time / MSEC_PER_SEC;
|
|
||||||
|
|
||||||
var text = "";
|
var text = "";
|
||||||
text += (hours > 0) ? hours + ":" :
|
text += (hours > 0) ? hours + ":" :
|
||||||
|
|
|
@ -62,10 +62,24 @@ var overlaysCounter = new CounterWidget(panel, "Overlays",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
panel.newCheckbox("Display status",
|
// see libraries/render/src/render/Engine.h
|
||||||
function(value) { Scene.setEngineDisplayItemStatus(value); },
|
var showDisplayStatusFlag = 1;
|
||||||
function() { return Scene.doEngineDisplayItemStatus(); },
|
var showNetworkStatusFlag = 2;
|
||||||
function(value) { return (value); }
|
|
||||||
|
panel.newCheckbox("Display status",
|
||||||
|
function(value) { Scene.setEngineDisplayItemStatus(value ?
|
||||||
|
Scene.doEngineDisplayItemStatus() | showDisplayStatusFlag :
|
||||||
|
Scene.doEngineDisplayItemStatus() & ~showDisplayStatusFlag); },
|
||||||
|
function() { return (Scene.doEngineDisplayItemStatus() & showDisplayStatusFlag) > 0; },
|
||||||
|
function(value) { return (value & showDisplayStatusFlag) > 0; }
|
||||||
|
);
|
||||||
|
|
||||||
|
panel.newCheckbox("Network/Physics status",
|
||||||
|
function(value) { Scene.setEngineDisplayItemStatus(value ?
|
||||||
|
Scene.doEngineDisplayItemStatus() | showNetworkStatusFlag :
|
||||||
|
Scene.doEngineDisplayItemStatus() & ~showNetworkStatusFlag); },
|
||||||
|
function() { return (Scene.doEngineDisplayItemStatus() & showNetworkStatusFlag) > 0; },
|
||||||
|
function(value) { return (value & showNetworkStatusFlag) > 0; }
|
||||||
);
|
);
|
||||||
|
|
||||||
var tickTackPeriod = 500;
|
var tickTackPeriod = 500;
|
||||||
|
|
|
@ -55,8 +55,7 @@ bool IceServer::packetVersionMatch(const udt::Packet& packet) {
|
||||||
if (headerVersion == versionForPacketType(headerType)) {
|
if (headerVersion == versionForPacketType(headerType)) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Packet version mismatch for packet" << headerType
|
qDebug() << "Packet version mismatch for packet" << headerType << " from" << packet.getSenderSockAddr();
|
||||||
<< "(" << nameForPacketType(headerType) << ") from" << packet.getSenderSockAddr();
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
31
interface/resources/icons/statusIconAtlas.svg
Normal file
31
interface/resources/icons/statusIconAtlas.svg
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" baseProfile="tiny" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
x="0px" y="0px" width="1600px" height="100px" viewBox="0 0 1600 100" xml:space="preserve">
|
||||||
|
<path fill="#FFFFFF" d="M92.8,69.3c-0.8-1.5-1.9-2.7-3.1-3.8c4.4-11.4,3.7-24.6-2.6-35.8c-9.2-16.3-28.3-24.4-46.3-20l-3.1,0.7
|
||||||
|
l4.9,8.7l1.7-0.3c13.7-2.7,27.6,3.6,34.5,15.7c4.9,8.7,5.5,18.9,1.9,27.9c-2.1,0.1-4.3,0.6-6.2,1.8c-6.5,3.7-8.8,12-5.1,18.5
|
||||||
|
c3.7,6.5,12,8.8,18.5,5.1C94.2,84.1,96.5,75.8,92.8,69.3z"/>
|
||||||
|
<path fill="#FFFFFF" d="M54.2,82.6l-1.5,0.1c-12.3,0.8-24.2-5.6-30.2-16.3c-3.8-6.6-4.9-14.2-3.7-21.3c2.8,0.4,5.9-0.1,8.6-1.6
|
||||||
|
c6.5-3.7,8.8-12,5.1-18.5s-12-8.8-18.5-5.1C7.7,23.7,5.4,32,9,38.5c0.3,0.6,0.7,1.2,1.2,1.7c-2.6,10.3-1.4,21.5,4.1,31.1
|
||||||
|
c7.5,13.2,21.5,21.2,36.5,21.2c1.8,0,3.5-0.1,5.2-0.3l3.6-0.4L54.2,82.6z"/>
|
||||||
|
<path fill="#FFFFFF" d="M67.2,63.4H33.8c-1,0-2.1-0.5-2.6-1.5c-0.5-0.9-0.5-2.1,0-3L47.8,30c0.5-0.9,1.6-1.5,2.6-1.5
|
||||||
|
s2.1,0.5,2.6,1.5l16.7,28.9c0.5,0.9,0.5,2.1,0,3C69.3,62.9,68.3,63.4,67.2,63.4z M39,57.4h23L50.4,37.5L39,57.4z"/>
|
||||||
|
<polygon fill="#FFFFFF" points="175.4,30.6 149.9,8 123.9,30.7 139,30.7 139.2,59.6 161,59.3 160.8,30.7 "/>
|
||||||
|
<polygon fill="#FFFFFF" points="225.6,39.8 251.1,62.5 277.1,39.8 261.9,39.8 261.7,8.9 240,9.2 240.2,39.8 "/>
|
||||||
|
<path fill="#FFFFFF" d="M174.3,42.8c1.8,3.7,2.8,7.8,2.8,12.1c0,15.2-12.3,27.5-27.5,27.5c-15.2,0-27.5-12.3-27.5-27.5
|
||||||
|
c0-4.4,1-8.5,2.9-12.1h-7.9c-1.4,3.8-2.2,7.8-2.2,12.1c0,19.2,15.6,34.7,34.7,34.7c19.2,0,34.7-15.6,34.7-34.7
|
||||||
|
c0-4.3-0.8-8.3-2.2-12.1H174.3z"/>
|
||||||
|
<path fill="#FFFFFF" d="M278.8,53c0.1,0.7,0.1,1.5,0.1,2.2c0,15.2-12.4,27.6-27.6,27.6c-15.2,0-27.6-12.4-27.6-27.6
|
||||||
|
c0-1.1,0.1-2.1,0.2-3.1c-2.1-2.1-4.1-4.1-6.2-6.2c-0.8,3-1.3,6.1-1.3,9.3c0,19.2,15.6,34.9,34.9,34.9s34.9-15.6,34.9-34.9
|
||||||
|
c0-2.9-0.4-5.8-1.1-8.5L278.8,53z"/>
|
||||||
|
<circle fill="none" stroke="#000000" stroke-width="7" stroke-miterlimit="10" stroke-dasharray="7.7202,7.7202" cx="-174" cy="-5.8" r="14.7"/>
|
||||||
|
<path d="M-174-10.6c2.6,0,4.7,2.1,4.7,4.7s-2.1,4.7-4.7,4.7s-4.7-2.1-4.7-4.7S-176.6-10.6-174-10.6 M-174-17.6
|
||||||
|
c-6.5,0-11.7,5.3-11.7,11.7s5.3,11.7,11.7,11.7s11.7-5.3,11.7-11.7S-167.5-17.6-174-17.6L-174-17.6z"/>
|
||||||
|
<path fill="#FFFFFF" d="M353.3,91.2c-0.3,0-0.7,0-1,0c-1.8-0.2-3.5-0.4-5.3-0.7c-21.3-3.6-35.2-22.8-32-44.2
|
||||||
|
c2.7-18.2,17.7-31.4,36.8-32.5c17.2-0.9,33.8,11.4,38.2,28.5c0.8,3.1,1.1,6.3,1.6,9.5c0,0.3,0,0.7,0,1c-0.2,0.9-0.4,1.8-0.5,2.7
|
||||||
|
c-1.3,16.3-12.9,30.1-28.8,34C359.3,90.4,356.3,90.7,353.3,91.2z M353.7,83.9c8.3,0,16.1-3.4,22.6-9.9c2.2-2.2,2-3.1-0.7-4.5
|
||||||
|
c-3.9-1.9-7.8-3.7-11.7-5.6c-4-2-4.6-8.1-1.1-10.8c2-1.5,2.4-3.7,2.1-5.9c-0.2-1.8-1-3.5-1.2-5.3c-0.6-6-5.2-10.2-11.1-10.1
|
||||||
|
c-5.9,0.1-10.4,4.8-10.6,10.9c-0.1,1.4-0.4,2.8-0.9,4.1c-0.6,1.9,0.1,4.9,1.7,6.3c3.8,3.1,3.1,9-1.4,11.2c-3.6,1.7-7.2,3.4-10.8,5.2
|
||||||
|
c-3.4,1.6-3.6,2.5-0.8,5.1C336.2,80.6,343.8,83.9,353.7,83.9z"/>
|
||||||
|
<polygon fill="#FFFFFF" points="445.3,14.1 484.6,14.1 461.5,38.2 485.6,41.4 422.2,86.9 441.2,53.4 425.6,49.3 "/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3 KiB |
|
@ -804,8 +804,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||||
|
|
||||||
void Application::aboutToQuit() {
|
void Application::aboutToQuit() {
|
||||||
emit beforeAboutToQuit();
|
emit beforeAboutToQuit();
|
||||||
|
|
||||||
getActiveDisplayPlugin()->deactivate();
|
getActiveDisplayPlugin()->deactivate();
|
||||||
|
|
||||||
_aboutToQuit = true;
|
_aboutToQuit = true;
|
||||||
|
|
||||||
cleanupBeforeQuit();
|
cleanupBeforeQuit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -831,8 +834,14 @@ void Application::cleanupBeforeQuit() {
|
||||||
|
|
||||||
_entities.clear(); // this will allow entity scripts to properly shutdown
|
_entities.clear(); // this will allow entity scripts to properly shutdown
|
||||||
|
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
|
// send the domain a disconnect packet, force stoppage of domain-server check-ins
|
||||||
|
nodeList->getDomainHandler().disconnect();
|
||||||
|
nodeList->setIsShuttingDown(true);
|
||||||
|
|
||||||
// tell the packet receiver we're shutting down, so it can drop packets
|
// tell the packet receiver we're shutting down, so it can drop packets
|
||||||
DependencyManager::get<NodeList>()->getPacketReceiver().setShouldDropPackets(true);
|
nodeList->getPacketReceiver().setShouldDropPackets(true);
|
||||||
|
|
||||||
_entities.shutdown(); // tell the entities system we're shutting down, so it will stop running scripts
|
_entities.shutdown(); // tell the entities system we're shutting down, so it will stop running scripts
|
||||||
ScriptEngine::stopAllScripts(this); // stop all currently running global scripts
|
ScriptEngine::stopAllScripts(this); // stop all currently running global scripts
|
||||||
|
@ -852,9 +861,6 @@ void Application::cleanupBeforeQuit() {
|
||||||
saveSettings();
|
saveSettings();
|
||||||
_window->saveGeometry();
|
_window->saveGeometry();
|
||||||
|
|
||||||
// let the avatar mixer know we're out
|
|
||||||
MyAvatar::sendKillAvatar();
|
|
||||||
|
|
||||||
// stop the AudioClient
|
// stop the AudioClient
|
||||||
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(),
|
QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(),
|
||||||
"stop", Qt::BlockingQueuedConnection);
|
"stop", Qt::BlockingQueuedConnection);
|
||||||
|
@ -3499,10 +3505,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls)) {
|
||||||
renderDebugFlags = (RenderArgs::DebugFlags) (renderDebugFlags | (int)RenderArgs::RENDER_DEBUG_HULLS);
|
renderDebugFlags = (RenderArgs::DebugFlags) (renderDebugFlags | (int)RenderArgs::RENDER_DEBUG_HULLS);
|
||||||
}
|
}
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowOwned)) {
|
|
||||||
renderDebugFlags =
|
|
||||||
(RenderArgs::DebugFlags) (renderDebugFlags | (int)RenderArgs::RENDER_DEBUG_SIMULATION_OWNERSHIP);
|
|
||||||
}
|
|
||||||
renderArgs->_debugFlags = renderDebugFlags;
|
renderArgs->_debugFlags = renderDebugFlags;
|
||||||
//ViveControllerManager::getInstance().updateRendering(renderArgs, _main3DScene, pendingChanges);
|
//ViveControllerManager::getInstance().updateRendering(renderArgs, _main3DScene, pendingChanges);
|
||||||
}
|
}
|
||||||
|
@ -3562,6 +3564,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
|
||||||
renderContext._maxDrawnOverlay3DItems = sceneInterface->getEngineMaxDrawnOverlay3DItems();
|
renderContext._maxDrawnOverlay3DItems = sceneInterface->getEngineMaxDrawnOverlay3DItems();
|
||||||
|
|
||||||
renderContext._drawItemStatus = sceneInterface->doEngineDisplayItemStatus();
|
renderContext._drawItemStatus = sceneInterface->doEngineDisplayItemStatus();
|
||||||
|
if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowOwned)) {
|
||||||
|
renderContext._drawItemStatus |= render::showNetworkStatusFlag;
|
||||||
|
}
|
||||||
renderContext._drawHitEffect = sceneInterface->doEngineDisplayHitEffect();
|
renderContext._drawHitEffect = sceneInterface->doEngineDisplayHitEffect();
|
||||||
|
|
||||||
renderContext._occlusionStatus = Menu::getInstance()->isOptionChecked(MenuOption::DebugAmbientOcclusion);
|
renderContext._occlusionStatus = Menu::getInstance()->isOptionChecked(MenuOption::DebugAmbientOcclusion);
|
||||||
|
|
|
@ -271,6 +271,7 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) {
|
||||||
auto ownerEntity = _ownerEntity.lock();
|
auto ownerEntity = _ownerEntity.lock();
|
||||||
if (ownerEntity) {
|
if (ownerEntity) {
|
||||||
ownerEntity->setActionDataDirty(true);
|
ownerEntity->setActionDataDirty(true);
|
||||||
|
ownerEntity->setActionDataNeedsTransmit(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
activateBody();
|
activateBody();
|
||||||
|
|
|
@ -608,7 +608,7 @@ float MyAvatar::recorderElapsed() {
|
||||||
if (!_recorder) {
|
if (!_recorder) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return (float)_recorder->position() / MSECS_PER_SECOND;
|
return (float)_recorder->position() / (float) MSECS_PER_SECOND;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMetaObject::Connection _audioClientRecorderConnection;
|
QMetaObject::Connection _audioClientRecorderConnection;
|
||||||
|
@ -1024,11 +1024,6 @@ int MyAvatar::parseDataFromBuffer(const QByteArray& buffer) {
|
||||||
return buffer.size();
|
return buffer.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::sendKillAvatar() {
|
|
||||||
auto killPacket = NLPacket::create(PacketType::KillAvatar, 0);
|
|
||||||
DependencyManager::get<NodeList>()->broadcastToNodes(std::move(killPacket), NodeSet() << NodeType::AvatarMixer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyAvatar::updateLookAtTargetAvatar() {
|
void MyAvatar::updateLookAtTargetAvatar() {
|
||||||
//
|
//
|
||||||
// Look at the avatar whose eyes are closest to the ray in direction of my avatar's head
|
// Look at the avatar whose eyes are closest to the ray in direction of my avatar's head
|
||||||
|
|
|
@ -162,8 +162,6 @@ public:
|
||||||
|
|
||||||
eyeContactTarget getEyeContactTarget();
|
eyeContactTarget getEyeContactTarget();
|
||||||
|
|
||||||
static void sendKillAvatar();
|
|
||||||
|
|
||||||
Q_INVOKABLE glm::vec3 getTrackedHeadPosition() const { return _trackedHeadPosition; }
|
Q_INVOKABLE glm::vec3 getTrackedHeadPosition() const { return _trackedHeadPosition; }
|
||||||
Q_INVOKABLE glm::vec3 getHeadPosition() const { return getHead()->getPosition(); }
|
Q_INVOKABLE glm::vec3 getHeadPosition() const { return getHead()->getPosition(); }
|
||||||
Q_INVOKABLE float getHeadFinalYaw() const { return getHead()->getFinalYaw(); }
|
Q_INVOKABLE float getHeadFinalYaw() const { return getHead()->getFinalYaw(); }
|
||||||
|
|
|
@ -804,12 +804,12 @@ float AvatarData::playerElapsed() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
qint64 result;
|
float result;
|
||||||
QMetaObject::invokeMethod(this, "playerElapsed", Qt::BlockingQueuedConnection,
|
QMetaObject::invokeMethod(this, "playerElapsed", Qt::BlockingQueuedConnection,
|
||||||
Q_RETURN_ARG(qint64, result));
|
Q_RETURN_ARG(float, result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return (float)_player->position() / MSECS_PER_SECOND;
|
return (float)_player->position() / (float) MSECS_PER_SECOND;
|
||||||
}
|
}
|
||||||
|
|
||||||
float AvatarData::playerLength() {
|
float AvatarData::playerLength() {
|
||||||
|
@ -817,12 +817,12 @@ float AvatarData::playerLength() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
qint64 result;
|
float result;
|
||||||
QMetaObject::invokeMethod(this, "playerLength", Qt::BlockingQueuedConnection,
|
QMetaObject::invokeMethod(this, "playerLength", Qt::BlockingQueuedConnection,
|
||||||
Q_RETURN_ARG(qint64, result));
|
Q_RETURN_ARG(float, result));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
return _player->length() / MSECS_PER_SECOND;
|
return (float)_player->length() / (float) MSECS_PER_SECOND;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarData::loadRecording(const QString& filename) {
|
void AvatarData::loadRecording(const QString& filename) {
|
||||||
|
@ -1513,7 +1513,8 @@ void AvatarData::setRecordingBasis(std::shared_ptr<Transform> recordingBasis) {
|
||||||
recordingBasis = std::make_shared<Transform>();
|
recordingBasis = std::make_shared<Transform>();
|
||||||
recordingBasis->setRotation(getOrientation());
|
recordingBasis->setRotation(getOrientation());
|
||||||
recordingBasis->setTranslation(getPosition());
|
recordingBasis->setTranslation(getPosition());
|
||||||
recordingBasis->setScale(getTargetScale());
|
// TODO: find a different way to record/playback the Scale of the avatar
|
||||||
|
//recordingBasis->setScale(getTargetScale());
|
||||||
}
|
}
|
||||||
_recordingBasis = recordingBasis;
|
_recordingBasis = recordingBasis;
|
||||||
}
|
}
|
||||||
|
@ -1532,7 +1533,7 @@ Transform AvatarData::getTransform() const {
|
||||||
|
|
||||||
static const QString JSON_AVATAR_BASIS = QStringLiteral("basisTransform");
|
static const QString JSON_AVATAR_BASIS = QStringLiteral("basisTransform");
|
||||||
static const QString JSON_AVATAR_RELATIVE = QStringLiteral("relativeTransform");
|
static const QString JSON_AVATAR_RELATIVE = QStringLiteral("relativeTransform");
|
||||||
static const QString JSON_AVATAR_JOINT_ROTATIONS = QStringLiteral("jointRotations");
|
static const QString JSON_AVATAR_JOINT_ARRAY = QStringLiteral("jointArray");
|
||||||
static const QString JSON_AVATAR_HEAD = QStringLiteral("head");
|
static const QString JSON_AVATAR_HEAD = QStringLiteral("head");
|
||||||
static const QString JSON_AVATAR_HEAD_ROTATION = QStringLiteral("rotation");
|
static const QString JSON_AVATAR_HEAD_ROTATION = QStringLiteral("rotation");
|
||||||
static const QString JSON_AVATAR_HEAD_BLENDSHAPE_COEFFICIENTS = QStringLiteral("blendShapes");
|
static const QString JSON_AVATAR_HEAD_BLENDSHAPE_COEFFICIENTS = QStringLiteral("blendShapes");
|
||||||
|
@ -1544,6 +1545,24 @@ static const QString JSON_AVATAR_BODY_MODEL = QStringLiteral("bodyModel");
|
||||||
static const QString JSON_AVATAR_DISPLAY_NAME = QStringLiteral("displayName");
|
static const QString JSON_AVATAR_DISPLAY_NAME = QStringLiteral("displayName");
|
||||||
static const QString JSON_AVATAR_ATTACHEMENTS = QStringLiteral("attachments");
|
static const QString JSON_AVATAR_ATTACHEMENTS = QStringLiteral("attachments");
|
||||||
|
|
||||||
|
QJsonValue toJsonValue(const JointData& joint) {
|
||||||
|
QJsonArray result;
|
||||||
|
result.push_back(toJsonValue(joint.rotation));
|
||||||
|
result.push_back(toJsonValue(joint.translation));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
JointData jointDataFromJsonValue(const QJsonValue& json) {
|
||||||
|
JointData result;
|
||||||
|
if (json.isArray()) {
|
||||||
|
QJsonArray array = json.toArray();
|
||||||
|
result.rotation = quatFromJsonValue(array[0]);
|
||||||
|
result.rotationSet = true;
|
||||||
|
result.translation = vec3FromJsonValue(array[1]);
|
||||||
|
result.translationSet = false;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Every frame will store both a basis for the recording and a relative transform
|
// Every frame will store both a basis for the recording and a relative transform
|
||||||
// This allows the application to decide whether playback should be relative to an avatar's
|
// This allows the application to decide whether playback should be relative to an avatar's
|
||||||
|
@ -1575,13 +1594,16 @@ QByteArray avatarStateToFrame(const AvatarData* _avatar) {
|
||||||
root[JSON_AVATAR_RELATIVE] = Transform::toJson(relativeTransform);
|
root[JSON_AVATAR_RELATIVE] = Transform::toJson(relativeTransform);
|
||||||
root[JSON_AVATAR_BASIS] = Transform::toJson(*recordingBasis);
|
root[JSON_AVATAR_BASIS] = Transform::toJson(*recordingBasis);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
root[JSON_AVATAR_RELATIVE] = Transform::toJson(_avatar->getTransform());
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonArray jointRotations;
|
// Skeleton pose
|
||||||
for (const auto& jointRotation : _avatar->getJointRotations()) {
|
QJsonArray jointArray;
|
||||||
jointRotations.push_back(toJsonValue(jointRotation));
|
for (const auto& joint : _avatar->getRawJointData()) {
|
||||||
|
jointArray.push_back(toJsonValue(joint));
|
||||||
}
|
}
|
||||||
root[JSON_AVATAR_JOINT_ROTATIONS] = jointRotations;
|
root[JSON_AVATAR_JOINT_ARRAY] = jointArray;
|
||||||
|
|
||||||
const HeadData* head = _avatar->getHeadData();
|
const HeadData* head = _avatar->getHeadData();
|
||||||
if (head) {
|
if (head) {
|
||||||
|
@ -1643,24 +1665,34 @@ void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar) {
|
||||||
auto worldTransform = currentBasis->worldTransform(relativeTransform);
|
auto worldTransform = currentBasis->worldTransform(relativeTransform);
|
||||||
_avatar->setPosition(worldTransform.getTranslation());
|
_avatar->setPosition(worldTransform.getTranslation());
|
||||||
_avatar->setOrientation(worldTransform.getRotation());
|
_avatar->setOrientation(worldTransform.getRotation());
|
||||||
_avatar->setTargetScale(worldTransform.getScale().x);
|
|
||||||
|
// TODO: find a way to record/playback the Scale of the avatar
|
||||||
|
//_avatar->setTargetScale(worldTransform.getScale().x);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
if (root.contains(JSON_AVATAR_ATTACHEMENTS)) {
|
if (root.contains(JSON_AVATAR_ATTACHEMENTS)) {
|
||||||
// FIXME de-serialize attachment data
|
// FIXME de-serialize attachment data
|
||||||
}
|
}
|
||||||
|
|
||||||
// Joint rotations are relative to the avatar, so they require no basis correction
|
// Joint rotations are relative to the avatar, so they require no basis correction
|
||||||
if (root.contains(JSON_AVATAR_JOINT_ROTATIONS)) {
|
if (root.contains(JSON_AVATAR_JOINT_ARRAY)) {
|
||||||
QVector<quat> jointRotations;
|
QVector<JointData> jointArray;
|
||||||
QJsonArray jointRotationsJson = root[JSON_AVATAR_JOINT_ROTATIONS].toArray();
|
QJsonArray jointArrayJson = root[JSON_AVATAR_JOINT_ARRAY].toArray();
|
||||||
jointRotations.reserve(jointRotationsJson.size());
|
jointArray.reserve(jointArrayJson.size());
|
||||||
for (const auto& jointRotationJson : jointRotationsJson) {
|
for (const auto& jointJson : jointArrayJson) {
|
||||||
jointRotations.push_back(quatFromJsonValue(jointRotationJson));
|
jointArray.push_back(jointDataFromJsonValue(jointJson));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVector<glm::quat> jointRotations;
|
||||||
|
jointRotations.reserve(jointArray.size());
|
||||||
|
for (const auto& joint : jointArray) {
|
||||||
|
jointRotations.push_back(joint.rotation);
|
||||||
|
}
|
||||||
|
_avatar->setJointRotations(jointRotations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
// Most head data is relative to the avatar, and needs no basis correction,
|
// Most head data is relative to the avatar, and needs no basis correction,
|
||||||
// but the lookat vector does need correction
|
// but the lookat vector does need correction
|
||||||
HeadData* head = _avatar->_headData;
|
HeadData* head = _avatar->_headData;
|
||||||
|
|
|
@ -457,6 +457,9 @@ public:
|
||||||
bool translationSet = false;
|
bool translationSet = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
QJsonValue toJsonValue(const JointData& joint);
|
||||||
|
JointData jointDataFromJsonValue(const QJsonValue& q);
|
||||||
|
|
||||||
class AttachmentData {
|
class AttachmentData {
|
||||||
public:
|
public:
|
||||||
QUrl modelURL;
|
QUrl modelURL;
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include <ObjectMotionState.h>
|
#include <ObjectMotionState.h>
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
|
|
||||||
#include "RenderableDebugableEntityItem.h"
|
|
||||||
#include "../render-utils/simple_vert.h"
|
#include "../render-utils/simple_vert.h"
|
||||||
#include "../render-utils/simple_frag.h"
|
#include "../render-utils/simple_frag.h"
|
||||||
|
|
||||||
|
@ -63,6 +62,4 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
|
||||||
} else {
|
} else {
|
||||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidCubeInstance(batch, getTransformToCenter(), cubeColor);
|
DependencyManager::get<DeferredLightingEffect>()->renderSolidCubeInstance(batch, getTransformToCenter(), cubeColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderableDebugableEntityItem::render(this, args);
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
//
|
|
||||||
// RenderableDebugableEntityItem.cpp
|
|
||||||
// libraries/entities-renderer/src/
|
|
||||||
//
|
|
||||||
// Created by Seth Alves on 5/1/15.
|
|
||||||
// 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 "RenderableDebugableEntityItem.h"
|
|
||||||
|
|
||||||
#include <glm/gtx/quaternion.hpp>
|
|
||||||
|
|
||||||
#include <gpu/Batch.h>
|
|
||||||
#include <DeferredLightingEffect.h>
|
|
||||||
#include <ObjectMotionState.h>
|
|
||||||
|
|
||||||
|
|
||||||
void RenderableDebugableEntityItem::renderBoundingBox(EntityItem* entity, RenderArgs* args,
|
|
||||||
float puffedOut, glm::vec4& color) {
|
|
||||||
Q_ASSERT(args->_batch);
|
|
||||||
gpu::Batch& batch = *args->_batch;
|
|
||||||
|
|
||||||
auto shapeTransform = entity->getTransformToCenter();
|
|
||||||
if (puffedOut != 0.0f) {
|
|
||||||
shapeTransform.postScale(1.0f + puffedOut);
|
|
||||||
}
|
|
||||||
batch.setModelTransform(Transform()); // we want to include the scale as well
|
|
||||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCubeInstance(batch, shapeTransform, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderableDebugableEntityItem::render(EntityItem* entity, RenderArgs* args) {
|
|
||||||
if (args->_debugFlags & RenderArgs::RENDER_DEBUG_SIMULATION_OWNERSHIP) {
|
|
||||||
Q_ASSERT(args->_batch);
|
|
||||||
gpu::Batch& batch = *args->_batch;
|
|
||||||
|
|
||||||
batch.setModelTransform(entity->getTransformToCenter()); // we want to include the scale as well
|
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
|
||||||
const QUuid& myNodeID = nodeList->getSessionUUID();
|
|
||||||
bool highlightSimulationOwnership = (entity->getSimulatorID() == myNodeID);
|
|
||||||
if (highlightSimulationOwnership) {
|
|
||||||
glm::vec4 greenColor(0.0f, 1.0f, 0.2f, 1.0f);
|
|
||||||
renderBoundingBox(entity, args, 0.08f, greenColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
quint64 now = usecTimestampNow();
|
|
||||||
if (now - entity->getLastEditedFromRemote() < 0.1f * USECS_PER_SECOND) {
|
|
||||||
glm::vec4 redColor(1.0f, 0.0f, 0.0f, 1.0f);
|
|
||||||
renderBoundingBox(entity, args, 0.16f, redColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (now - entity->getLastBroadcast() < 0.2f * USECS_PER_SECOND) {
|
|
||||||
glm::vec4 yellowColor(1.0f, 1.0f, 0.2f, 1.0f);
|
|
||||||
renderBoundingBox(entity, args, 0.24f, yellowColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(entity->getPhysicsInfo());
|
|
||||||
if (motionState && motionState->isActive()) {
|
|
||||||
glm::vec4 blueColor(0.0f, 0.0f, 1.0f, 1.0f);
|
|
||||||
renderBoundingBox(entity, args, 0.32f, blueColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
//
|
|
||||||
// RenderableDebugableEntityItem.h
|
|
||||||
// libraries/entities-renderer/src/
|
|
||||||
//
|
|
||||||
// Created by Seth Alves on 5/1/15.
|
|
||||||
// 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_RenderableDebugableEntityItem_h
|
|
||||||
#define hifi_RenderableDebugableEntityItem_h
|
|
||||||
|
|
||||||
#include <EntityItem.h>
|
|
||||||
|
|
||||||
class RenderableDebugableEntityItem {
|
|
||||||
public:
|
|
||||||
static void renderBoundingBox(EntityItem* entity, RenderArgs* args, float puffedOut, glm::vec4& color);
|
|
||||||
static void render(EntityItem* entity, RenderArgs* args);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // hifi_RenderableDebugableEntityItem_h
|
|
|
@ -10,6 +10,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#include <ObjectMotionState.h>
|
||||||
#include "RenderableEntityItem.h"
|
#include "RenderableEntityItem.h"
|
||||||
|
|
||||||
namespace render {
|
namespace render {
|
||||||
|
@ -40,5 +41,60 @@ namespace render {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void makeEntityItemStatusGetters(EntityItemPointer entity, render::Item::Status::Getters& statusGetters) {
|
||||||
|
statusGetters.push_back([entity] () -> render::Item::Status::Value {
|
||||||
|
quint64 delta = usecTimestampNow() - entity->getLastEditedFromRemote();
|
||||||
|
const float WAIT_THRESHOLD_INV = 1.0f / (0.2f * USECS_PER_SECOND);
|
||||||
|
float normalizedDelta = delta * WAIT_THRESHOLD_INV;
|
||||||
|
// Status icon will scale from 1.0f down to 0.0f after WAIT_THRESHOLD
|
||||||
|
// Color is red if last update is after WAIT_THRESHOLD, green otherwise (120 deg is green)
|
||||||
|
return render::Item::Status::Value(1.0f - normalizedDelta, (normalizedDelta > 1.0f ?
|
||||||
|
render::Item::Status::Value::GREEN :
|
||||||
|
render::Item::Status::Value::RED),
|
||||||
|
(unsigned char) RenderItemStatusIcon::PACKET_RECEIVED);
|
||||||
|
});
|
||||||
|
|
||||||
|
statusGetters.push_back([entity] () -> render::Item::Status::Value {
|
||||||
|
quint64 delta = usecTimestampNow() - entity->getLastBroadcast();
|
||||||
|
const float WAIT_THRESHOLD_INV = 1.0f / (0.4f * USECS_PER_SECOND);
|
||||||
|
float normalizedDelta = delta * WAIT_THRESHOLD_INV;
|
||||||
|
// Status icon will scale from 1.0f down to 0.0f after WAIT_THRESHOLD
|
||||||
|
// Color is Magenta if last update is after WAIT_THRESHOLD, cyan otherwise (180 deg is green)
|
||||||
|
return render::Item::Status::Value(1.0f - normalizedDelta, (normalizedDelta > 1.0f ?
|
||||||
|
render::Item::Status::Value::MAGENTA :
|
||||||
|
render::Item::Status::Value::CYAN),
|
||||||
|
(unsigned char)RenderItemStatusIcon::PACKET_SENT);
|
||||||
|
});
|
||||||
|
|
||||||
|
statusGetters.push_back([entity] () -> render::Item::Status::Value {
|
||||||
|
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(entity->getPhysicsInfo());
|
||||||
|
if (motionState && motionState->isActive()) {
|
||||||
|
return render::Item::Status::Value(1.0f, render::Item::Status::Value::BLUE,
|
||||||
|
(unsigned char)RenderItemStatusIcon::ACTIVE_IN_BULLET);
|
||||||
|
}
|
||||||
|
return render::Item::Status::Value(0.0f, render::Item::Status::Value::BLUE,
|
||||||
|
(unsigned char)RenderItemStatusIcon::ACTIVE_IN_BULLET);
|
||||||
|
});
|
||||||
|
|
||||||
|
statusGetters.push_back([entity] () -> render::Item::Status::Value {
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
const QUuid& myNodeID = nodeList->getSessionUUID();
|
||||||
|
bool weOwnSimulation = entity->getSimulationOwner().matchesValidID(myNodeID);
|
||||||
|
|
||||||
|
if (weOwnSimulation) {
|
||||||
|
return render::Item::Status::Value(1.0f, render::Item::Status::Value::BLUE,
|
||||||
|
(unsigned char)RenderItemStatusIcon::SIMULATION_OWNER);
|
||||||
|
}
|
||||||
|
return render::Item::Status::Value(0.0f, render::Item::Status::Value::BLUE,
|
||||||
|
(unsigned char)RenderItemStatusIcon::SIMULATION_OWNER);
|
||||||
|
});
|
||||||
|
|
||||||
|
statusGetters.push_back([entity] () -> render::Item::Status::Value {
|
||||||
|
if (entity->hasActions()) {
|
||||||
|
return render::Item::Status::Value(1.0f, render::Item::Status::Value::GREEN,
|
||||||
|
(unsigned char)RenderItemStatusIcon::HAS_ACTIONS);
|
||||||
|
}
|
||||||
|
return render::Item::Status::Value(0.0f, render::Item::Status::Value::GREEN,
|
||||||
|
(unsigned char)RenderItemStatusIcon::HAS_ACTIONS);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -15,13 +15,26 @@
|
||||||
#include <render/Scene.h>
|
#include <render/Scene.h>
|
||||||
#include <EntityItem.h>
|
#include <EntityItem.h>
|
||||||
|
|
||||||
|
// These or the icon "name" used by the render item status value, they correspond to the atlas texture used by the DrawItemStatus
|
||||||
|
// job in the current rendering pipeline defined as of now (11/2015) in render-utils/RenderDeferredTask.cpp.
|
||||||
|
enum class RenderItemStatusIcon {
|
||||||
|
ACTIVE_IN_BULLET = 0,
|
||||||
|
PACKET_SENT = 1,
|
||||||
|
PACKET_RECEIVED = 2,
|
||||||
|
SIMULATION_OWNER = 3,
|
||||||
|
HAS_ACTIONS = 4,
|
||||||
|
NONE = 255
|
||||||
|
};
|
||||||
|
|
||||||
|
void makeEntityItemStatusGetters(EntityItemPointer entity, render::Item::Status::Getters& statusGetters);
|
||||||
|
|
||||||
|
|
||||||
class RenderableEntityItemProxy {
|
class RenderableEntityItemProxy {
|
||||||
public:
|
public:
|
||||||
RenderableEntityItemProxy(EntityItemPointer entity) : entity(entity) { }
|
RenderableEntityItemProxy(EntityItemPointer entity) : entity(entity) { }
|
||||||
typedef render::Payload<RenderableEntityItemProxy> Payload;
|
typedef render::Payload<RenderableEntityItemProxy> Payload;
|
||||||
typedef Payload::DataPointer Pointer;
|
typedef Payload::DataPointer Pointer;
|
||||||
|
|
||||||
EntityItemPointer entity;
|
EntityItemPointer entity;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,19 +49,23 @@ class SimpleRenderableEntityItem {
|
||||||
public:
|
public:
|
||||||
bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
|
bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
|
||||||
_myItem = scene->allocateID();
|
_myItem = scene->allocateID();
|
||||||
|
|
||||||
auto renderData = std::make_shared<RenderableEntityItemProxy>(self);
|
auto renderData = std::make_shared<RenderableEntityItemProxy>(self);
|
||||||
auto renderPayload = std::make_shared<RenderableEntityItemProxy::Payload>(renderData);
|
auto renderPayload = std::make_shared<RenderableEntityItemProxy::Payload>(renderData);
|
||||||
|
|
||||||
|
render::Item::Status::Getters statusGetters;
|
||||||
|
makeEntityItemStatusGetters(self, statusGetters);
|
||||||
|
renderPayload->addStatusGetters(statusGetters);
|
||||||
|
|
||||||
pendingChanges.resetItem(_myItem, renderPayload);
|
pendingChanges.resetItem(_myItem, renderPayload);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
|
void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
|
||||||
pendingChanges.removeItem(_myItem);
|
pendingChanges.removeItem(_myItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
render::ItemID _myItem;
|
render::ItemID _myItem;
|
||||||
};
|
};
|
||||||
|
@ -62,5 +79,4 @@ private: \
|
||||||
SimpleRenderableEntityItem _renderHelper;
|
SimpleRenderableEntityItem _renderHelper;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // hifi_RenderableEntityItem_h
|
#endif // hifi_RenderableEntityItem_h
|
||||||
|
|
|
@ -54,6 +54,4 @@ void RenderableLineEntityItem::render(RenderArgs* args) {
|
||||||
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch);
|
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch);
|
||||||
DependencyManager::get<GeometryCache>()->renderVertices(batch, gpu::LINE_STRIP, _lineVerticesID);
|
DependencyManager::get<GeometryCache>()->renderVertices(batch, gpu::LINE_STRIP, _lineVerticesID);
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderableDebugableEntityItem::render(this, args);
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
#define hifi_RenderableLineEntityItem_h
|
#define hifi_RenderableLineEntityItem_h
|
||||||
|
|
||||||
#include <LineEntityItem.h>
|
#include <LineEntityItem.h>
|
||||||
#include "RenderableDebugableEntityItem.h"
|
|
||||||
#include "RenderableEntityItem.h"
|
#include "RenderableEntityItem.h"
|
||||||
#include <GeometryCache.h>
|
#include <GeometryCache.h>
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,9 @@
|
||||||
|
|
||||||
#include "EntityTreeRenderer.h"
|
#include "EntityTreeRenderer.h"
|
||||||
#include "EntitiesRendererLogging.h"
|
#include "EntitiesRendererLogging.h"
|
||||||
|
#include "RenderableEntityItem.h"
|
||||||
#include "RenderableModelEntityItem.h"
|
#include "RenderableModelEntityItem.h"
|
||||||
|
#include "RenderableEntityItem.h"
|
||||||
|
|
||||||
EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||||
return std::make_shared<RenderableModelEntityItem>(entityID, properties);
|
return std::make_shared<RenderableModelEntityItem>(entityID, properties);
|
||||||
|
@ -179,25 +181,6 @@ namespace render {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void makeEntityItemStatusGetters(RenderableModelEntityItem* entity, render::Item::Status::Getters& statusGetters) {
|
|
||||||
statusGetters.push_back([entity] () -> render::Item::Status::Value {
|
|
||||||
quint64 delta = usecTimestampNow() - entity->getLastEditedFromRemote();
|
|
||||||
const float WAIT_THRESHOLD_INV = 1.0f / (0.2f * USECS_PER_SECOND);
|
|
||||||
float normalizedDelta = delta * WAIT_THRESHOLD_INV;
|
|
||||||
// Status icon will scale from 1.0f down to 0.0f after WAIT_THRESHOLD
|
|
||||||
// Color is red if last update is after WAIT_THRESHOLD, green otherwise (120 deg is green)
|
|
||||||
return render::Item::Status::Value(1.0f - normalizedDelta, (normalizedDelta > 1.0f ? render::Item::Status::Value::GREEN : render::Item::Status::Value::RED));
|
|
||||||
});
|
|
||||||
statusGetters.push_back([entity] () -> render::Item::Status::Value {
|
|
||||||
quint64 delta = usecTimestampNow() - entity->getLastBroadcast();
|
|
||||||
const float WAIT_THRESHOLD_INV = 1.0f / (0.4f * USECS_PER_SECOND);
|
|
||||||
float normalizedDelta = delta * WAIT_THRESHOLD_INV;
|
|
||||||
// Status icon will scale from 1.0f down to 0.0f after WAIT_THRESHOLD
|
|
||||||
// Color is Magenta if last update is after WAIT_THRESHOLD, cyan otherwise (180 deg is green)
|
|
||||||
return render::Item::Status::Value(1.0f - normalizedDelta, (normalizedDelta > 1.0f ? render::Item::Status::Value::MAGENTA : render::Item::Status::Value::CYAN));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
|
bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
|
||||||
render::PendingChanges& pendingChanges) {
|
render::PendingChanges& pendingChanges) {
|
||||||
_myMetaItem = scene->allocateID();
|
_myMetaItem = scene->allocateID();
|
||||||
|
@ -209,11 +192,11 @@ bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_p
|
||||||
|
|
||||||
if (_model) {
|
if (_model) {
|
||||||
render::Item::Status::Getters statusGetters;
|
render::Item::Status::Getters statusGetters;
|
||||||
makeEntityItemStatusGetters(this, statusGetters);
|
makeEntityItemStatusGetters(shared_from_this(), statusGetters);
|
||||||
|
|
||||||
// note: we don't care if the model fails to add items, we always added our meta item and therefore we return
|
// 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!
|
// true so that the system knows our meta item is in the scene!
|
||||||
_model->addToScene(scene, pendingChanges, statusGetters);
|
_model->addToScene(scene, pendingChanges, statusGetters, _showCollisionHull);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -245,14 +228,16 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
||||||
|
|
||||||
// check to see if when we added our models to the scene they were ready, if they were not ready, then
|
// check to see if when we added our models to the scene they were ready, if they were not ready, then
|
||||||
// fix them up in the scene
|
// fix them up in the scene
|
||||||
if (_model->needsFixupInScene()) {
|
bool shouldShowCollisionHull = (args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS) > 0;
|
||||||
|
if (_model->needsFixupInScene() || _showCollisionHull != shouldShowCollisionHull) {
|
||||||
|
_showCollisionHull = shouldShowCollisionHull;
|
||||||
render::PendingChanges pendingChanges;
|
render::PendingChanges pendingChanges;
|
||||||
|
|
||||||
_model->removeFromScene(scene, pendingChanges);
|
_model->removeFromScene(scene, pendingChanges);
|
||||||
|
|
||||||
render::Item::Status::Getters statusGetters;
|
render::Item::Status::Getters statusGetters;
|
||||||
makeEntityItemStatusGetters(this, statusGetters);
|
makeEntityItemStatusGetters(shared_from_this(), statusGetters);
|
||||||
_model->addToScene(scene, pendingChanges, statusGetters);
|
_model->addToScene(scene, pendingChanges, statusGetters, _showCollisionHull);
|
||||||
|
|
||||||
scene->enqueuePendingChanges(pendingChanges);
|
scene->enqueuePendingChanges(pendingChanges);
|
||||||
}
|
}
|
||||||
|
@ -274,7 +259,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
||||||
EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(args->_renderer);
|
EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(args->_renderer);
|
||||||
getModel(renderer);
|
getModel(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_model) {
|
if (_model) {
|
||||||
// handle animations..
|
// handle animations..
|
||||||
if (hasAnimation()) {
|
if (hasAnimation()) {
|
||||||
|
@ -320,11 +305,12 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f);
|
static glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f);
|
||||||
RenderableDebugableEntityItem::renderBoundingBox(this, args, 0.0f, greenColor);
|
gpu::Batch& batch = *args->_batch;
|
||||||
|
auto shapeTransform = getTransformToCenter();
|
||||||
|
batch.setModelTransform(Transform()); // we want to include the scale as well
|
||||||
|
DependencyManager::get<DeferredLightingEffect>()->renderWireCubeInstance(batch, shapeTransform, greenColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderableDebugableEntityItem::render(this, args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) {
|
Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) {
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
#include <ModelEntityItem.h>
|
#include <ModelEntityItem.h>
|
||||||
#include "RenderableDebugableEntityItem.h"
|
|
||||||
|
|
||||||
class Model;
|
class Model;
|
||||||
class EntityTreeRenderer;
|
class EntityTreeRenderer;
|
||||||
|
@ -85,6 +84,8 @@ private:
|
||||||
bool _dimensionsInitialized = true;
|
bool _dimensionsInitialized = true;
|
||||||
|
|
||||||
render::ItemID _myMetaItem;
|
render::ItemID _myMetaItem;
|
||||||
|
|
||||||
|
bool _showCollisionHull = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_RenderableModelEntityItem_h
|
#endif // hifi_RenderableModelEntityItem_h
|
||||||
|
|
|
@ -139,6 +139,9 @@ bool RenderableParticleEffectEntityItem::addToScene(EntityItemPointer self,
|
||||||
_renderItemId = scene->allocateID();
|
_renderItemId = scene->allocateID();
|
||||||
auto renderData = ParticlePayload::Pointer(particlePayload);
|
auto renderData = ParticlePayload::Pointer(particlePayload);
|
||||||
auto renderPayload = render::PayloadPointer(new ParticlePayload::Payload(renderData));
|
auto renderPayload = render::PayloadPointer(new ParticlePayload::Payload(renderData));
|
||||||
|
render::Item::Status::Getters statusGetters;
|
||||||
|
makeEntityItemStatusGetters(shared_from_this(), statusGetters);
|
||||||
|
renderPayload->addStatusGetters(statusGetters);
|
||||||
pendingChanges.resetItem(_renderItemId, renderPayload);
|
pendingChanges.resetItem(_renderItemId, renderPayload);
|
||||||
_scene = scene;
|
_scene = scene;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -153,6 +153,4 @@ void RenderablePolyLineEntityItem::render(RenderArgs* args) {
|
||||||
batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride);
|
batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride);
|
||||||
|
|
||||||
batch.draw(gpu::TRIANGLE_STRIP, _numVertices, 0);
|
batch.draw(gpu::TRIANGLE_STRIP, _numVertices, 0);
|
||||||
|
|
||||||
RenderableDebugableEntityItem::render(this, args);
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
#include <gpu/Batch.h>
|
#include <gpu/Batch.h>
|
||||||
#include <PolyLineEntityItem.h>
|
#include <PolyLineEntityItem.h>
|
||||||
#include "RenderableDebugableEntityItem.h"
|
|
||||||
#include "RenderableEntityItem.h"
|
#include "RenderableEntityItem.h"
|
||||||
#include <GeometryCache.h>
|
#include <GeometryCache.h>
|
||||||
#include <QReadWriteLock>
|
#include <QReadWriteLock>
|
||||||
|
|
|
@ -538,8 +538,6 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
|
||||||
batch._glUniform3f(voxelVolumeSizeLocation, _voxelVolumeSize.x, _voxelVolumeSize.y, _voxelVolumeSize.z);
|
batch._glUniform3f(voxelVolumeSizeLocation, _voxelVolumeSize.x, _voxelVolumeSize.y, _voxelVolumeSize.z);
|
||||||
|
|
||||||
batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0);
|
batch.drawIndexed(gpu::TRIANGLES, mesh->getNumIndices(), 0);
|
||||||
|
|
||||||
RenderableDebugableEntityItem::render(this, args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenderablePolyVoxEntityItem::addToScene(EntityItemPointer self,
|
bool RenderablePolyVoxEntityItem::addToScene(EntityItemPointer self,
|
||||||
|
@ -551,6 +549,10 @@ bool RenderablePolyVoxEntityItem::addToScene(EntityItemPointer self,
|
||||||
auto renderData = PolyVoxPayload::Pointer(renderItem);
|
auto renderData = PolyVoxPayload::Pointer(renderItem);
|
||||||
auto renderPayload = std::make_shared<PolyVoxPayload::Payload>(renderData);
|
auto renderPayload = std::make_shared<PolyVoxPayload::Payload>(renderData);
|
||||||
|
|
||||||
|
render::Item::Status::Getters statusGetters;
|
||||||
|
makeEntityItemStatusGetters(shared_from_this(), statusGetters);
|
||||||
|
renderPayload->addStatusGetters(statusGetters);
|
||||||
|
|
||||||
pendingChanges.resetItem(_myItem, renderPayload);
|
pendingChanges.resetItem(_myItem, renderPayload);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
#include <TextureCache.h>
|
#include <TextureCache.h>
|
||||||
|
|
||||||
#include "PolyVoxEntityItem.h"
|
#include "PolyVoxEntityItem.h"
|
||||||
#include "RenderableDebugableEntityItem.h"
|
|
||||||
#include "RenderableEntityItem.h"
|
#include "RenderableEntityItem.h"
|
||||||
#include "gpu/Context.h"
|
#include "gpu/Context.h"
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include <GeometryCache.h>
|
#include <GeometryCache.h>
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
|
|
||||||
#include "RenderableDebugableEntityItem.h"
|
|
||||||
#include "../render-utils/simple_vert.h"
|
#include "../render-utils/simple_vert.h"
|
||||||
#include "../render-utils/simple_frag.h"
|
#include "../render-utils/simple_frag.h"
|
||||||
|
|
||||||
|
@ -70,7 +69,4 @@ void RenderableSphereEntityItem::render(RenderArgs* args) {
|
||||||
batch.setModelTransform(Transform());
|
batch.setModelTransform(Transform());
|
||||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphereInstance(batch, modelTransform, sphereColor);
|
DependencyManager::get<DeferredLightingEffect>()->renderSolidSphereInstance(batch, modelTransform, sphereColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RenderableDebugableEntityItem::render(this, args);
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#include <GeometryCache.h>
|
#include <GeometryCache.h>
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
|
|
||||||
|
#include "RenderableEntityItem.h"
|
||||||
|
|
||||||
// Sphere entities should fit inside a cube entity of the same size, so a sphere that has dimensions 1x1x1
|
// Sphere entities should fit inside a cube entity of the same size, so a sphere that has dimensions 1x1x1
|
||||||
// is a half unit sphere. However, the geometry cache renders a UNIT sphere, so we need to scale down.
|
// is a half unit sphere. However, the geometry cache renders a UNIT sphere, so we need to scale down.
|
||||||
static const float SPHERE_ENTITY_SCALE = 0.5f;
|
static const float SPHERE_ENTITY_SCALE = 0.5f;
|
||||||
|
@ -112,7 +114,9 @@ void RenderableZoneEntityItem::render(RenderArgs* args) {
|
||||||
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||||
render::PendingChanges pendingChanges;
|
render::PendingChanges pendingChanges;
|
||||||
_model->removeFromScene(scene, pendingChanges);
|
_model->removeFromScene(scene, pendingChanges);
|
||||||
_model->addToScene(scene, pendingChanges);
|
render::Item::Status::Getters statusGetters;
|
||||||
|
makeEntityItemStatusGetters(shared_from_this(), statusGetters);
|
||||||
|
_model->addToScene(scene, pendingChanges, false);
|
||||||
|
|
||||||
scene->enqueuePendingChanges(pendingChanges);
|
scene->enqueuePendingChanges(pendingChanges);
|
||||||
|
|
||||||
|
@ -203,7 +207,11 @@ bool RenderableZoneEntityItem::addToScene(EntityItemPointer self, std::shared_pt
|
||||||
|
|
||||||
auto renderData = std::make_shared<RenderableZoneEntityItemMeta>(self);
|
auto renderData = std::make_shared<RenderableZoneEntityItemMeta>(self);
|
||||||
auto renderPayload = std::make_shared<RenderableZoneEntityItemMeta::Payload>(renderData);
|
auto renderPayload = std::make_shared<RenderableZoneEntityItemMeta::Payload>(renderData);
|
||||||
|
|
||||||
|
render::Item::Status::Getters statusGetters;
|
||||||
|
makeEntityItemStatusGetters(shared_from_this(), statusGetters);
|
||||||
|
renderPayload->addStatusGetters(statusGetters);
|
||||||
|
|
||||||
pendingChanges.resetItem(_myMetaItem, renderPayload);
|
pendingChanges.resetItem(_myMetaItem, renderPayload);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -304,3 +304,24 @@ QDataStream& operator>>(QDataStream& stream, EntityActionType& entityActionType)
|
||||||
entityActionType = (EntityActionType)actionTypeAsInt;
|
entityActionType = (EntityActionType)actionTypeAsInt;
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString serializedActionsToDebugString(QByteArray data) {
|
||||||
|
if (data.size() == 0) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
QVector<QByteArray> serializedActions;
|
||||||
|
QDataStream serializedActionsStream(data);
|
||||||
|
serializedActionsStream >> serializedActions;
|
||||||
|
|
||||||
|
QString result;
|
||||||
|
foreach(QByteArray serializedAction, serializedActions) {
|
||||||
|
QDataStream serializedActionStream(serializedAction);
|
||||||
|
EntityActionType actionType;
|
||||||
|
QUuid actionID;
|
||||||
|
serializedActionStream >> actionType;
|
||||||
|
serializedActionStream >> actionID;
|
||||||
|
result += EntityActionInterface::actionTypeToString(actionType) + "-" + actionID.toString() + " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -89,4 +89,6 @@ typedef std::shared_ptr<EntityActionInterface> EntityActionPointer;
|
||||||
QDataStream& operator<<(QDataStream& stream, const EntityActionType& entityActionType);
|
QDataStream& operator<<(QDataStream& stream, const EntityActionType& entityActionType);
|
||||||
QDataStream& operator>>(QDataStream& stream, EntityActionType& entityActionType);
|
QDataStream& operator>>(QDataStream& stream, EntityActionType& entityActionType);
|
||||||
|
|
||||||
|
QString serializedActionsToDebugString(QByteArray data);
|
||||||
|
|
||||||
#endif // hifi_EntityActionInterface_h
|
#endif // hifi_EntityActionInterface_h
|
||||||
|
|
|
@ -630,6 +630,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
dataAt += bytes;
|
dataAt += bytes;
|
||||||
bytesRead += bytes;
|
bytesRead += bytes;
|
||||||
|
|
||||||
|
if (wantTerseEditLogging() && _simulationOwner != newSimOwner) {
|
||||||
|
qCDebug(entities) << "sim ownership for" << getDebugName() << "is now" << newSimOwner;
|
||||||
|
}
|
||||||
if (_simulationOwner.set(newSimOwner)) {
|
if (_simulationOwner.set(newSimOwner)) {
|
||||||
_dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID;
|
_dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID;
|
||||||
}
|
}
|
||||||
|
@ -704,17 +707,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
READ_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
|
READ_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
|
||||||
READ_ENTITY_PROPERTY(PROP_HREF, QString, setHref);
|
READ_ENTITY_PROPERTY(PROP_HREF, QString, setHref);
|
||||||
READ_ENTITY_PROPERTY(PROP_DESCRIPTION, QString, setDescription);
|
READ_ENTITY_PROPERTY(PROP_DESCRIPTION, QString, setDescription);
|
||||||
|
READ_ENTITY_PROPERTY(PROP_ACTION_DATA, QByteArray, setActionData);
|
||||||
{ // When we own the simulation we don't accept updates to the entity's actions
|
|
||||||
// but since we're using macros below we have to temporarily modify overwriteLocalData.
|
|
||||||
// NOTE: this prevents userB from adding an action to an object1 when UserA
|
|
||||||
// has simulation ownership of it.
|
|
||||||
// TODO: figure out how to allow multiple users to update actions simultaneously
|
|
||||||
bool oldOverwrite = overwriteLocalData;
|
|
||||||
overwriteLocalData = overwriteLocalData && !weOwnSimulation;
|
|
||||||
READ_ENTITY_PROPERTY(PROP_ACTION_DATA, QByteArray, setActionData);
|
|
||||||
overwriteLocalData = oldOverwrite;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
|
bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
|
||||||
propertyFlags, overwriteLocalData, somethingChanged);
|
propertyFlags, overwriteLocalData, somethingChanged);
|
||||||
|
@ -737,7 +730,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
// this "new" data is actually slightly out of date. We calculate the time we need to skip forward and
|
// this "new" data is actually slightly out of date. We calculate the time we need to skip forward and
|
||||||
// use our simulation helper routine to get a best estimate of where the entity should be.
|
// use our simulation helper routine to get a best estimate of where the entity should be.
|
||||||
float skipTimeForward = (float)(now - lastSimulatedFromBufferAdjusted) / (float)(USECS_PER_SECOND);
|
float skipTimeForward = (float)(now - lastSimulatedFromBufferAdjusted) / (float)(USECS_PER_SECOND);
|
||||||
|
|
||||||
// we want to extrapolate the motion forward to compensate for packet travel time, but
|
// we want to extrapolate the motion forward to compensate for packet travel time, but
|
||||||
// we don't want the side effect of flag setting.
|
// we don't want the side effect of flag setting.
|
||||||
simulateKinematicMotion(skipTimeForward, false);
|
simulateKinematicMotion(skipTimeForward, false);
|
||||||
|
@ -745,7 +738,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
|
|
||||||
if (overwriteLocalData) {
|
if (overwriteLocalData) {
|
||||||
if (!_simulationOwner.matchesValidID(myNodeID)) {
|
if (!_simulationOwner.matchesValidID(myNodeID)) {
|
||||||
|
|
||||||
_lastSimulated = now;
|
_lastSimulated = now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -996,6 +988,11 @@ EntityTreePointer EntityItem::getTree() const {
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EntityItem::wantTerseEditLogging() {
|
||||||
|
EntityTreePointer tree = getTree();
|
||||||
|
return tree ? tree->wantTerseEditLogging() : false;
|
||||||
|
}
|
||||||
|
|
||||||
glm::mat4 EntityItem::getEntityToWorldMatrix() const {
|
glm::mat4 EntityItem::getEntityToWorldMatrix() const {
|
||||||
glm::mat4 translation = glm::translate(getPosition());
|
glm::mat4 translation = glm::translate(getPosition());
|
||||||
glm::mat4 rotation = glm::mat4_cast(getRotation());
|
glm::mat4 rotation = glm::mat4_cast(getRotation());
|
||||||
|
@ -1492,20 +1489,35 @@ void EntityItem::updateCreated(uint64_t value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::setSimulationOwner(const QUuid& id, quint8 priority) {
|
void EntityItem::setSimulationOwner(const QUuid& id, quint8 priority) {
|
||||||
|
if (wantTerseEditLogging() && (id != _simulationOwner.getID() || priority != _simulationOwner.getPriority())) {
|
||||||
|
qCDebug(entities) << "sim ownership for" << getDebugName() << "is now" << id << priority;
|
||||||
|
}
|
||||||
_simulationOwner.set(id, priority);
|
_simulationOwner.set(id, priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::setSimulationOwner(const SimulationOwner& owner) {
|
void EntityItem::setSimulationOwner(const SimulationOwner& owner) {
|
||||||
|
if (wantTerseEditLogging() && _simulationOwner != owner) {
|
||||||
|
qCDebug(entities) << "sim ownership for" << getDebugName() << "is now" << owner;
|
||||||
|
}
|
||||||
|
|
||||||
_simulationOwner.set(owner);
|
_simulationOwner.set(owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::updateSimulatorID(const QUuid& value) {
|
void EntityItem::updateSimulatorID(const QUuid& value) {
|
||||||
|
if (wantTerseEditLogging() && _simulationOwner.getID() != value) {
|
||||||
|
qCDebug(entities) << "sim ownership for" << getDebugName() << "is now" << value;
|
||||||
|
}
|
||||||
|
|
||||||
if (_simulationOwner.setID(value)) {
|
if (_simulationOwner.setID(value)) {
|
||||||
_dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID;
|
_dirtyFlags |= Simulation::DIRTY_SIMULATOR_ID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::clearSimulationOwnership() {
|
void EntityItem::clearSimulationOwnership() {
|
||||||
|
if (wantTerseEditLogging() && !_simulationOwner.isNull()) {
|
||||||
|
qCDebug(entities) << "sim ownership for" << getDebugName() << "is now null";
|
||||||
|
}
|
||||||
|
|
||||||
_simulationOwner.clear();
|
_simulationOwner.clear();
|
||||||
// don't bother setting the DIRTY_SIMULATOR_ID flag because clearSimulationOwnership()
|
// don't bother setting the DIRTY_SIMULATOR_ID flag because clearSimulationOwnership()
|
||||||
// is only ever called entity-server-side and the flags are only used client-side
|
// is only ever called entity-server-side and the flags are only used client-side
|
||||||
|
@ -1607,6 +1619,7 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulation* s
|
||||||
bool success = true;
|
bool success = true;
|
||||||
serializeActions(success, _allActionsDataCache);
|
serializeActions(success, _allActionsDataCache);
|
||||||
_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
|
_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
|
||||||
|
setActionDataNeedsTransmit(true);
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -1649,7 +1662,7 @@ void EntityItem::deserializeActionsInternal() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityTreePointer entityTree = _element ? _element->getTree() : nullptr;
|
EntityTreePointer entityTree = getTree();
|
||||||
assert(entityTree);
|
assert(entityTree);
|
||||||
EntitySimulation* simulation = entityTree ? entityTree->getSimulation() : nullptr;
|
EntitySimulation* simulation = entityTree ? entityTree->getSimulation() : nullptr;
|
||||||
assert(simulation);
|
assert(simulation);
|
||||||
|
@ -1770,6 +1783,7 @@ void EntityItem::serializeActions(bool& success, QByteArray& result) const {
|
||||||
serializedActionsStream << serializedActions;
|
serializedActionsStream << serializedActions;
|
||||||
|
|
||||||
if (result.size() >= _maxActionsDataSize) {
|
if (result.size() >= _maxActionsDataSize) {
|
||||||
|
qDebug() << "EntityItem::serializeActions size is too large -- " << result.size() << ">=" << _maxActionsDataSize;
|
||||||
success = false;
|
success = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -307,6 +307,7 @@ public:
|
||||||
|
|
||||||
QString getName() const { return _name; }
|
QString getName() const { return _name; }
|
||||||
void setName(const QString& value) { _name = value; }
|
void setName(const QString& value) { _name = value; }
|
||||||
|
QString getDebugName() { return _name != "" ? _name : getID().toString(); }
|
||||||
|
|
||||||
bool getVisible() const { return _visible; }
|
bool getVisible() const { return _visible; }
|
||||||
void setVisible(bool value) { _visible = value; }
|
void setVisible(bool value) { _visible = value; }
|
||||||
|
@ -381,6 +382,7 @@ public:
|
||||||
void setPhysicsInfo(void* data) { _physicsInfo = data; }
|
void setPhysicsInfo(void* data) { _physicsInfo = data; }
|
||||||
EntityTreeElementPointer getElement() const { return _element; }
|
EntityTreeElementPointer getElement() const { return _element; }
|
||||||
EntityTreePointer getTree() const;
|
EntityTreePointer getTree() const;
|
||||||
|
bool wantTerseEditLogging();
|
||||||
|
|
||||||
static void setSendPhysicsUpdates(bool value) { _sendPhysicsUpdates = value; }
|
static void setSendPhysicsUpdates(bool value) { _sendPhysicsUpdates = value; }
|
||||||
static bool getSendPhysicsUpdates() { return _sendPhysicsUpdates; }
|
static bool getSendPhysicsUpdates() { return _sendPhysicsUpdates; }
|
||||||
|
@ -406,7 +408,13 @@ public:
|
||||||
QList<QUuid> getActionIDs() { return _objectActions.keys(); }
|
QList<QUuid> getActionIDs() { return _objectActions.keys(); }
|
||||||
QVariantMap getActionArguments(const QUuid& actionID) const;
|
QVariantMap getActionArguments(const QUuid& actionID) const;
|
||||||
void deserializeActions();
|
void deserializeActions();
|
||||||
|
|
||||||
void setActionDataDirty(bool value) const { _actionDataDirty = value; }
|
void setActionDataDirty(bool value) const { _actionDataDirty = value; }
|
||||||
|
bool actionDataDirty() const { return _actionDataDirty; }
|
||||||
|
|
||||||
|
void setActionDataNeedsTransmit(bool value) const { _actionDataNeedsTransmit = value; }
|
||||||
|
bool actionDataNeedsTransmit() const { return _actionDataNeedsTransmit; }
|
||||||
|
|
||||||
bool shouldSuppressLocationEdits() const;
|
bool shouldSuppressLocationEdits() const;
|
||||||
|
|
||||||
void setSourceUUID(const QUuid& sourceUUID) { _sourceUUID = sourceUUID; }
|
void setSourceUUID(const QUuid& sourceUUID) { _sourceUUID = sourceUUID; }
|
||||||
|
@ -439,7 +447,7 @@ protected:
|
||||||
mutable bool _recalcAABox = true;
|
mutable bool _recalcAABox = true;
|
||||||
mutable bool _recalcMinAACube = true;
|
mutable bool _recalcMinAACube = true;
|
||||||
mutable bool _recalcMaxAACube = true;
|
mutable bool _recalcMaxAACube = true;
|
||||||
|
|
||||||
float _glowLevel;
|
float _glowLevel;
|
||||||
float _localRenderAlpha;
|
float _localRenderAlpha;
|
||||||
float _density = ENTITY_ITEM_DEFAULT_DENSITY; // kg/m^3
|
float _density = ENTITY_ITEM_DEFAULT_DENSITY; // kg/m^3
|
||||||
|
@ -510,6 +518,7 @@ protected:
|
||||||
void checkWaitingToRemove(EntitySimulation* simulation = nullptr);
|
void checkWaitingToRemove(EntitySimulation* simulation = nullptr);
|
||||||
mutable QSet<QUuid> _actionsToRemove;
|
mutable QSet<QUuid> _actionsToRemove;
|
||||||
mutable bool _actionDataDirty = false;
|
mutable bool _actionDataDirty = false;
|
||||||
|
mutable bool _actionDataNeedsTransmit = false;
|
||||||
// _previouslyDeletedActions is used to avoid an action being re-added due to server round-trip lag
|
// _previouslyDeletedActions is used to avoid an action being re-added due to server round-trip lag
|
||||||
static quint64 _rememberDeletedActionTime;
|
static quint64 _rememberDeletedActionTime;
|
||||||
mutable QHash<QUuid, quint64> _previouslyDeletedActions;
|
mutable QHash<QUuid, quint64> _previouslyDeletedActions;
|
||||||
|
|
|
@ -611,7 +611,8 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString,
|
||||||
const QVariantMap& arguments) {
|
const QVariantMap& arguments) {
|
||||||
QUuid actionID = QUuid::createUuid();
|
QUuid actionID = QUuid::createUuid();
|
||||||
auto actionFactory = DependencyManager::get<EntityActionFactoryInterface>();
|
auto actionFactory = DependencyManager::get<EntityActionFactoryInterface>();
|
||||||
bool success = actionWorker(entityID, [&](EntitySimulation* simulation, EntityItemPointer entity) {
|
bool success = false;
|
||||||
|
actionWorker(entityID, [&](EntitySimulation* simulation, EntityItemPointer entity) {
|
||||||
// create this action even if the entity doesn't have physics info. it will often be the
|
// create this action even if the entity doesn't have physics info. it will often be the
|
||||||
// case that a script adds an action immediately after an object is created, and the physicsInfo
|
// case that a script adds an action immediately after an object is created, and the physicsInfo
|
||||||
// is computed asynchronously.
|
// is computed asynchronously.
|
||||||
|
@ -623,16 +624,16 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
EntityActionPointer action = actionFactory->factory(actionType, actionID, entity, arguments);
|
EntityActionPointer action = actionFactory->factory(actionType, actionID, entity, arguments);
|
||||||
if (action) {
|
if (!action) {
|
||||||
entity->addAction(simulation, action);
|
return false;
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
|
||||||
const QUuid myNodeID = nodeList->getSessionUUID();
|
|
||||||
if (entity->getSimulatorID() != myNodeID) {
|
|
||||||
entity->flagForOwnership();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
success = entity->addAction(simulation, action);
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
const QUuid myNodeID = nodeList->getSessionUUID();
|
||||||
|
if (entity->getSimulatorID() != myNodeID) {
|
||||||
|
entity->flagForOwnership();
|
||||||
|
}
|
||||||
|
return false; // Physics will cause a packet to be sent, so don't send from here.
|
||||||
});
|
});
|
||||||
if (success) {
|
if (success) {
|
||||||
return actionID;
|
return actionID;
|
||||||
|
@ -656,9 +657,12 @@ bool EntityScriptingInterface::updateAction(const QUuid& entityID, const QUuid&
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityScriptingInterface::deleteAction(const QUuid& entityID, const QUuid& actionID) {
|
bool EntityScriptingInterface::deleteAction(const QUuid& entityID, const QUuid& actionID) {
|
||||||
return actionWorker(entityID, [&](EntitySimulation* simulation, EntityItemPointer entity) {
|
bool success = false;
|
||||||
return entity->removeAction(simulation, actionID);
|
actionWorker(entityID, [&](EntitySimulation* simulation, EntityItemPointer entity) {
|
||||||
|
success = entity->removeAction(simulation, actionID);
|
||||||
|
return false; // Physics will cause a packet to be sent, so don't send from here.
|
||||||
});
|
});
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<QUuid> EntityScriptingInterface::getActionIDs(const QUuid& entityID) {
|
QVector<QUuid> EntityScriptingInterface::getActionIDs(const QUuid& entityID) {
|
||||||
|
|
|
@ -198,6 +198,10 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
|
||||||
properties.setVelocityChanged(false);
|
properties.setVelocityChanged(false);
|
||||||
properties.setAngularVelocityChanged(false);
|
properties.setAngularVelocityChanged(false);
|
||||||
properties.setAccelerationChanged(false);
|
properties.setAccelerationChanged(false);
|
||||||
|
|
||||||
|
if (wantTerseEditLogging()) {
|
||||||
|
qCDebug(entities) << senderNode->getUUID() << "physical edits suppressed";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// else client accepts what the server says
|
// else client accepts what the server says
|
||||||
|
@ -612,6 +616,14 @@ EntityItemPointer EntityTree::findEntityByEntityItemID(const EntityItemID& entit
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList<QString>& changedProperties) {
|
void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList<QString>& changedProperties) {
|
||||||
|
static quint64 lastTerseLog = 0;
|
||||||
|
quint64 now = usecTimestampNow();
|
||||||
|
|
||||||
|
if (now - lastTerseLog > USECS_PER_SECOND) {
|
||||||
|
qCDebug(entities) << "-------------------------";
|
||||||
|
}
|
||||||
|
lastTerseLog = now;
|
||||||
|
|
||||||
if (properties.simulationOwnerChanged()) {
|
if (properties.simulationOwnerChanged()) {
|
||||||
int simIndex = changedProperties.indexOf("simulationOwner");
|
int simIndex = changedProperties.indexOf("simulationOwner");
|
||||||
if (simIndex >= 0) {
|
if (simIndex >= 0) {
|
||||||
|
@ -619,6 +631,79 @@ void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList<Q
|
||||||
changedProperties[simIndex] = QString("simulationOwner:") + QString::number((int)simOwner.getPriority());
|
changedProperties[simIndex] = QString("simulationOwner:") + QString::number((int)simOwner.getPriority());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (properties.velocityChanged()) {
|
||||||
|
int index = changedProperties.indexOf("velocity");
|
||||||
|
if (index >= 0) {
|
||||||
|
glm::vec3 value = properties.getVelocity();
|
||||||
|
QString changeHint = "0";
|
||||||
|
if (value.x + value.y + value.z > 0) {
|
||||||
|
changeHint = "+";
|
||||||
|
} else if (value.x + value.y + value.z < 0) {
|
||||||
|
changeHint = "-";
|
||||||
|
}
|
||||||
|
changedProperties[index] = QString("velocity:") + changeHint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (properties.gravityChanged()) {
|
||||||
|
int index = changedProperties.indexOf("gravity");
|
||||||
|
if (index >= 0) {
|
||||||
|
glm::vec3 value = properties.getGravity();
|
||||||
|
QString changeHint = "0";
|
||||||
|
if (value.x + value.y + value.z > 0) {
|
||||||
|
changeHint = "+";
|
||||||
|
} else if (value.x + value.y + value.z < 0) {
|
||||||
|
changeHint = "-";
|
||||||
|
}
|
||||||
|
changedProperties[index] = QString("gravity:") + changeHint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (properties.actionDataChanged()) {
|
||||||
|
int index = changedProperties.indexOf("actionData");
|
||||||
|
if (index >= 0) {
|
||||||
|
QByteArray value = properties.getActionData();
|
||||||
|
QString changeHint = serializedActionsToDebugString(value);
|
||||||
|
changedProperties[index] = QString("actionData:") + changeHint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (properties.ignoreForCollisionsChanged()) {
|
||||||
|
int index = changedProperties.indexOf("ignoreForCollisions");
|
||||||
|
if (index >= 0) {
|
||||||
|
bool value = properties.getIgnoreForCollisions();
|
||||||
|
QString changeHint = "0";
|
||||||
|
if (value) {
|
||||||
|
changeHint = "1";
|
||||||
|
}
|
||||||
|
changedProperties[index] = QString("ignoreForCollisions:") + changeHint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (properties.collisionsWillMoveChanged()) {
|
||||||
|
int index = changedProperties.indexOf("collisionsWillMove");
|
||||||
|
if (index >= 0) {
|
||||||
|
bool value = properties.getCollisionsWillMove();
|
||||||
|
QString changeHint = "0";
|
||||||
|
if (value) {
|
||||||
|
changeHint = "1";
|
||||||
|
}
|
||||||
|
changedProperties[index] = QString("collisionsWillMove:") + changeHint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (properties.lockedChanged()) {
|
||||||
|
int index = changedProperties.indexOf("locked");
|
||||||
|
if (index >= 0) {
|
||||||
|
bool value = properties.getLocked();
|
||||||
|
QString changeHint = "0";
|
||||||
|
if (value) {
|
||||||
|
changeHint = "1";
|
||||||
|
}
|
||||||
|
changedProperties[index] = QString("locked:") + changeHint;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int EntityTree::processEditPacketData(NLPacket& packet, const unsigned char* editData, int maxLength,
|
int EntityTree::processEditPacketData(NLPacket& packet, const unsigned char* editData, int maxLength,
|
||||||
|
@ -673,7 +758,8 @@ int EntityTree::processEditPacketData(NLPacket& packet, const unsigned char* edi
|
||||||
if (wantTerseEditLogging()) {
|
if (wantTerseEditLogging()) {
|
||||||
QList<QString> changedProperties = properties.listChangedProperties();
|
QList<QString> changedProperties = properties.listChangedProperties();
|
||||||
fixupTerseEditLogging(properties, changedProperties);
|
fixupTerseEditLogging(properties, changedProperties);
|
||||||
qCDebug(entities) << "edit" << entityItemID.toString() << changedProperties;
|
qCDebug(entities) << senderNode->getUUID() << "edit" <<
|
||||||
|
existingEntity->getDebugName() << changedProperties;
|
||||||
}
|
}
|
||||||
endLogging = usecTimestampNow();
|
endLogging = usecTimestampNow();
|
||||||
|
|
||||||
|
@ -703,7 +789,7 @@ int EntityTree::processEditPacketData(NLPacket& packet, const unsigned char* edi
|
||||||
if (wantTerseEditLogging()) {
|
if (wantTerseEditLogging()) {
|
||||||
QList<QString> changedProperties = properties.listChangedProperties();
|
QList<QString> changedProperties = properties.listChangedProperties();
|
||||||
fixupTerseEditLogging(properties, changedProperties);
|
fixupTerseEditLogging(properties, changedProperties);
|
||||||
qCDebug(entities) << "add" << entityItemID.toString() << changedProperties;
|
qCDebug(entities) << senderNode->getUUID() << "add" << entityItemID << changedProperties;
|
||||||
}
|
}
|
||||||
endLogging = usecTimestampNow();
|
endLogging = usecTimestampNow();
|
||||||
|
|
||||||
|
|
|
@ -157,7 +157,7 @@ void SimulationOwner::test() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SimulationOwner::operator!=(const SimulationOwner& other) {
|
bool SimulationOwner::operator!=(const SimulationOwner& other) {
|
||||||
return (_id != other._id && _priority != other._priority);
|
return (_id != other._id || _priority != other._priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
SimulationOwner& SimulationOwner::operator=(const SimulationOwner& other) {
|
SimulationOwner& SimulationOwner::operator=(const SimulationOwner& other) {
|
||||||
|
|
|
@ -331,7 +331,7 @@ public:
|
||||||
|
|
||||||
template <typename T> Iterator<T> begin() { return Iterator<T>(&edit<T>(0), _stride); }
|
template <typename T> Iterator<T> begin() { return Iterator<T>(&edit<T>(0), _stride); }
|
||||||
template <typename T> Iterator<T> end() { return Iterator<T>(&edit<T>(getNum<T>()), _stride); }
|
template <typename T> Iterator<T> end() { return Iterator<T>(&edit<T>(getNum<T>()), _stride); }
|
||||||
template <typename T> Iterator<const T> cbegin() const { return Iterator<const T>(&get<T>(0), _stride); }
|
template <typename T> Iterator<const T> cbegin() const { return Iterator<const T>(&get<T>(), _stride); }
|
||||||
template <typename T> Iterator<const T> cend() const { return Iterator<const T>(&get<T>(getNum<T>()), _stride); }
|
template <typename T> Iterator<const T> cend() const { return Iterator<const T>(&get<T>(getNum<T>()), _stride); }
|
||||||
|
|
||||||
// the number of elements of the specified type fitting in the view size
|
// the number of elements of the specified type fitting in the view size
|
||||||
|
|
|
@ -46,7 +46,13 @@ DomainHandler::DomainHandler(QObject* parent) :
|
||||||
connect(this, &DomainHandler::completedSocketDiscovery, &_icePeer, &NetworkPeer::stopPingTimer);
|
connect(this, &DomainHandler::completedSocketDiscovery, &_icePeer, &NetworkPeer::stopPingTimer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainHandler::clearConnectionInfo() {
|
void DomainHandler::disconnect() {
|
||||||
|
// if we're currently connected to a domain, send a disconnect packet on our way out
|
||||||
|
if (_isConnected) {
|
||||||
|
sendDisconnectPacket();
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear member variables that hold the connection state to a domain
|
||||||
_uuid = QUuid();
|
_uuid = QUuid();
|
||||||
_connectionToken = QUuid();
|
_connectionToken = QUuid();
|
||||||
|
|
||||||
|
@ -60,6 +66,18 @@ void DomainHandler::clearConnectionInfo() {
|
||||||
setIsConnected(false);
|
setIsConnected(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DomainHandler::sendDisconnectPacket() {
|
||||||
|
// The DomainDisconnect packet is not verified - we're relying on the eventual addition of DTLS to the
|
||||||
|
// domain-server connection to stop greifing here
|
||||||
|
|
||||||
|
// construct the disconnect packet once (an empty packet but sourced with our current session UUID)
|
||||||
|
static auto disconnectPacket = NLPacket::create(PacketType::DomainDisconnectRequest, 0);
|
||||||
|
|
||||||
|
// send the disconnect packet to the current domain server
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
nodeList->sendUnreliablePacket(*disconnectPacket, _sockAddr);
|
||||||
|
}
|
||||||
|
|
||||||
void DomainHandler::clearSettings() {
|
void DomainHandler::clearSettings() {
|
||||||
_settingsObject = QJsonObject();
|
_settingsObject = QJsonObject();
|
||||||
_failedSettingsRequests = 0;
|
_failedSettingsRequests = 0;
|
||||||
|
@ -67,7 +85,7 @@ void DomainHandler::clearSettings() {
|
||||||
|
|
||||||
void DomainHandler::softReset() {
|
void DomainHandler::softReset() {
|
||||||
qCDebug(networking) << "Resetting current domain connection information.";
|
qCDebug(networking) << "Resetting current domain connection information.";
|
||||||
clearConnectionInfo();
|
disconnect();
|
||||||
clearSettings();
|
clearSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ class DomainHandler : public QObject {
|
||||||
public:
|
public:
|
||||||
DomainHandler(QObject* parent = 0);
|
DomainHandler(QObject* parent = 0);
|
||||||
|
|
||||||
void clearConnectionInfo();
|
void disconnect();
|
||||||
void clearSettings();
|
void clearSettings();
|
||||||
|
|
||||||
const QUuid& getUUID() const { return _uuid; }
|
const QUuid& getUUID() const { return _uuid; }
|
||||||
|
@ -113,6 +113,7 @@ signals:
|
||||||
void settingsReceiveFail();
|
void settingsReceiveFail();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void sendDisconnectPacket();
|
||||||
void hardReset();
|
void hardReset();
|
||||||
|
|
||||||
QUuid _uuid;
|
QUuid _uuid;
|
||||||
|
|
|
@ -441,7 +441,7 @@ void LimitedNodeList::reset() {
|
||||||
_nodeSocket.clearConnections();
|
_nodeSocket.clearConnections();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID) {
|
bool LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID) {
|
||||||
QReadLocker readLocker(&_nodeMutex);
|
QReadLocker readLocker(&_nodeMutex);
|
||||||
|
|
||||||
NodeHash::iterator it = _nodeHash.find(nodeUUID);
|
NodeHash::iterator it = _nodeHash.find(nodeUUID);
|
||||||
|
@ -456,7 +456,10 @@ void LimitedNodeList::killNodeWithUUID(const QUuid& nodeUUID) {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleNodeKill(matchingNode);
|
handleNodeKill(matchingNode);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LimitedNodeList::processKillNode(NLPacket& packet) {
|
void LimitedNodeList::processKillNode(NLPacket& packet) {
|
||||||
|
|
|
@ -230,7 +230,7 @@ public slots:
|
||||||
virtual void sendSTUNRequest();
|
virtual void sendSTUNRequest();
|
||||||
void sendPingPackets();
|
void sendPingPackets();
|
||||||
|
|
||||||
void killNodeWithUUID(const QUuid& nodeUUID);
|
bool killNodeWithUUID(const QUuid& nodeUUID);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void dataSent(quint8 channelType, int bytes);
|
void dataSent(quint8 channelType, int bytes);
|
||||||
|
|
|
@ -103,6 +103,7 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned
|
||||||
packetReceiver.registerListener(PacketType::DomainServerRequireDTLS, &_domainHandler, "processDTLSRequirementPacket");
|
packetReceiver.registerListener(PacketType::DomainServerRequireDTLS, &_domainHandler, "processDTLSRequirementPacket");
|
||||||
packetReceiver.registerListener(PacketType::ICEPingReply, &_domainHandler, "processICEPingReplyPacket");
|
packetReceiver.registerListener(PacketType::ICEPingReply, &_domainHandler, "processICEPingReplyPacket");
|
||||||
packetReceiver.registerListener(PacketType::DomainServerPathResponse, this, "processDomainServerPathResponse");
|
packetReceiver.registerListener(PacketType::DomainServerPathResponse, this, "processDomainServerPathResponse");
|
||||||
|
packetReceiver.registerListener(PacketType::DomainServerRemovedNode, this, "processDomainServerRemovedNode");
|
||||||
}
|
}
|
||||||
|
|
||||||
qint64 NodeList::sendStats(const QJsonObject& statsObject, const HifiSockAddr& destination) {
|
qint64 NodeList::sendStats(const QJsonObject& statsObject, const HifiSockAddr& destination) {
|
||||||
|
@ -218,6 +219,10 @@ void NodeList::addSetOfNodeTypesToNodeInterestSet(const NodeSet& setOfNodeTypes)
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeList::sendDomainServerCheckIn() {
|
void NodeList::sendDomainServerCheckIn() {
|
||||||
|
if (_isShuttingDown) {
|
||||||
|
qCDebug(networking) << "Refusing to send a domain-server check in while shutting down.";
|
||||||
|
}
|
||||||
|
|
||||||
if (_publicSockAddr.isNull()) {
|
if (_publicSockAddr.isNull()) {
|
||||||
// we don't know our public socket and we need to send it to the domain server
|
// we don't know our public socket and we need to send it to the domain server
|
||||||
qCDebug(networking) << "Waiting for inital public socket from STUN. Will not send domain-server check in.";
|
qCDebug(networking) << "Waiting for inital public socket from STUN. Will not send domain-server check in.";
|
||||||
|
@ -513,6 +518,13 @@ void NodeList::processDomainServerAddedNode(QSharedPointer<NLPacket> packet) {
|
||||||
parseNodeFromPacketStream(packetStream);
|
parseNodeFromPacketStream(packetStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NodeList::processDomainServerRemovedNode(QSharedPointer<NLPacket> packet) {
|
||||||
|
// read the UUID from the packet, remove it if it exists
|
||||||
|
QUuid nodeUUID = QUuid::fromRfc4122(packet->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
|
||||||
|
qDebug() << "Received packet from domain-server to remove node with UUID" << uuidStringWithoutCurlyBraces(nodeUUID);
|
||||||
|
killNodeWithUUID(nodeUUID);
|
||||||
|
}
|
||||||
|
|
||||||
void NodeList::parseNodeFromPacketStream(QDataStream& packetStream) {
|
void NodeList::parseNodeFromPacketStream(QDataStream& packetStream) {
|
||||||
// setup variables to read into from QDataStream
|
// setup variables to read into from QDataStream
|
||||||
qint8 nodeType;
|
qint8 nodeType;
|
||||||
|
|
|
@ -66,6 +66,8 @@ public:
|
||||||
|
|
||||||
void setAssignmentServerSocket(const HifiSockAddr& serverSocket) { _assignmentServerSocket = serverSocket; }
|
void setAssignmentServerSocket(const HifiSockAddr& serverSocket) { _assignmentServerSocket = serverSocket; }
|
||||||
void sendAssignment(Assignment& assignment);
|
void sendAssignment(Assignment& assignment);
|
||||||
|
|
||||||
|
void setIsShuttingDown(bool isShuttingDown) { _isShuttingDown = isShuttingDown; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void reset();
|
void reset();
|
||||||
|
@ -74,6 +76,7 @@ public slots:
|
||||||
|
|
||||||
void processDomainServerList(QSharedPointer<NLPacket> packet);
|
void processDomainServerList(QSharedPointer<NLPacket> packet);
|
||||||
void processDomainServerAddedNode(QSharedPointer<NLPacket> packet);
|
void processDomainServerAddedNode(QSharedPointer<NLPacket> packet);
|
||||||
|
void processDomainServerRemovedNode(QSharedPointer<NLPacket> packet);
|
||||||
void processDomainServerPathResponse(QSharedPointer<NLPacket> packet);
|
void processDomainServerPathResponse(QSharedPointer<NLPacket> packet);
|
||||||
|
|
||||||
void processDomainServerConnectionTokenPacket(QSharedPointer<NLPacket> packet);
|
void processDomainServerConnectionTokenPacket(QSharedPointer<NLPacket> packet);
|
||||||
|
@ -114,6 +117,7 @@ private:
|
||||||
DomainHandler _domainHandler;
|
DomainHandler _domainHandler;
|
||||||
int _numNoReplyDomainCheckIns;
|
int _numNoReplyDomainCheckIns;
|
||||||
HifiSockAddr _assignmentServerSocket;
|
HifiSockAddr _assignmentServerSocket;
|
||||||
|
bool _isShuttingDown { false };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_NodeList_h
|
#endif // hifi_NodeList_h
|
||||||
|
|
|
@ -33,14 +33,19 @@ void ThreadedAssignment::setFinished(bool isFinished) {
|
||||||
if (_isFinished) {
|
if (_isFinished) {
|
||||||
|
|
||||||
qDebug() << "ThreadedAssignment::setFinished(true) called - finishing up.";
|
qDebug() << "ThreadedAssignment::setFinished(true) called - finishing up.";
|
||||||
|
|
||||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
|
auto& packetReceiver = nodeList->getPacketReceiver();
|
||||||
|
|
||||||
// we should de-register immediately for any of our packets
|
// we should de-register immediately for any of our packets
|
||||||
packetReceiver.unregisterListener(this);
|
packetReceiver.unregisterListener(this);
|
||||||
|
|
||||||
// we should also tell the packet receiver to drop packets while we're cleaning up
|
// we should also tell the packet receiver to drop packets while we're cleaning up
|
||||||
packetReceiver.setShouldDropPackets(true);
|
packetReceiver.setShouldDropPackets(true);
|
||||||
|
|
||||||
|
// send a disconnect packet to the domain
|
||||||
|
nodeList->getDomainHandler().disconnect();
|
||||||
|
|
||||||
if (_domainServerTimer) {
|
if (_domainServerTimer) {
|
||||||
// stop the domain-server check in timer by calling deleteLater so it gets cleaned up on NL thread
|
// stop the domain-server check in timer by calling deleteLater so it gets cleaned up on NL thread
|
||||||
|
|
|
@ -14,11 +14,13 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
|
#include <QtCore/QMetaEnum>
|
||||||
|
|
||||||
const QSet<PacketType> NON_VERIFIED_PACKETS = QSet<PacketType>()
|
const QSet<PacketType> NON_VERIFIED_PACKETS = QSet<PacketType>()
|
||||||
<< PacketType::NodeJsonStats << PacketType::EntityQuery
|
<< PacketType::NodeJsonStats << PacketType::EntityQuery
|
||||||
<< PacketType::OctreeDataNack << PacketType::EntityEditNack
|
<< PacketType::OctreeDataNack << PacketType::EntityEditNack
|
||||||
<< PacketType::DomainListRequest << PacketType::StopNode;
|
<< PacketType::DomainListRequest << PacketType::StopNode
|
||||||
|
<< PacketType::DomainDisconnectRequest;
|
||||||
|
|
||||||
const QSet<PacketType> NON_SOURCED_PACKETS = QSet<PacketType>()
|
const QSet<PacketType> NON_SOURCED_PACKETS = QSet<PacketType>()
|
||||||
<< PacketType::StunResponse << PacketType::CreateAssignment << PacketType::RequestAssignment
|
<< PacketType::StunResponse << PacketType::CreateAssignment << PacketType::RequestAssignment
|
||||||
|
@ -29,7 +31,8 @@ const QSet<PacketType> NON_SOURCED_PACKETS = QSet<PacketType>()
|
||||||
<< PacketType::DomainSettingsRequest << PacketType::DomainSettings
|
<< PacketType::DomainSettingsRequest << PacketType::DomainSettings
|
||||||
<< PacketType::ICEServerPeerInformation << PacketType::ICEServerQuery << PacketType::ICEServerHeartbeat
|
<< PacketType::ICEServerPeerInformation << PacketType::ICEServerQuery << PacketType::ICEServerHeartbeat
|
||||||
<< PacketType::ICEPing << PacketType::ICEPingReply
|
<< PacketType::ICEPing << PacketType::ICEPingReply
|
||||||
<< PacketType::AssignmentClientStatus << PacketType::StopNode;
|
<< PacketType::AssignmentClientStatus << PacketType::StopNode
|
||||||
|
<< PacketType::DomainServerRemovedNode;
|
||||||
|
|
||||||
const QSet<PacketType> RELIABLE_PACKETS = QSet<PacketType>();
|
const QSet<PacketType> RELIABLE_PACKETS = QSet<PacketType>();
|
||||||
|
|
||||||
|
@ -46,66 +49,17 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PACKET_TYPE_NAME_LOOKUP(x) case x: return QString(#x);
|
|
||||||
|
|
||||||
QString nameForPacketType(PacketType packetType) {
|
|
||||||
switch (packetType) {
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::Unknown);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::StunResponse);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::DomainList);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::Ping);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::PingReply);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::KillAvatar);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::AvatarData);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::InjectAudio);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::MixedAudio);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::MicrophoneAudioNoEcho);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::MicrophoneAudioWithEcho);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::BulkAvatarData);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::SilentAudioFrame);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::DomainListRequest);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::RequestAssignment);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::CreateAssignment);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::DomainConnectionDenied);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::MuteEnvironment);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::AudioStreamStats);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::OctreeStats);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::Jurisdiction);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::JurisdictionRequest);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::AvatarIdentity);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::AvatarBillboard);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::DomainConnectRequest);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::DomainServerRequireDTLS);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::NodeJsonStats);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::EntityQuery);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::EntityData);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::EntityErase);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::OctreeDataNack);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::StopNode);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::AudioEnvironment);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::EntityEditNack);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::ICEServerHeartbeat);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::DomainServerAddedNode);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::ICEServerQuery);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::ICEServerPeerInformation);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::ICEPing);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::ICEPingReply);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::EntityAdd);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::EntityEdit);
|
|
||||||
PACKET_TYPE_NAME_LOOKUP(PacketType::DomainServerConnectionToken);
|
|
||||||
default:
|
|
||||||
return QString("Type: ") + QString::number((int)packetType);
|
|
||||||
}
|
|
||||||
return QString("unexpected");
|
|
||||||
}
|
|
||||||
|
|
||||||
uint qHash(const PacketType& key, uint seed) {
|
uint qHash(const PacketType& key, uint seed) {
|
||||||
// seems odd that Qt couldn't figure out this cast itself, but this fixes a compile error after switch to
|
// seems odd that Qt couldn't figure out this cast itself, but this fixes a compile error after switch
|
||||||
// strongly typed enum for PacketType
|
// to strongly typed enum for PacketType
|
||||||
return qHash((quint8) key, seed);
|
return qHash((quint8) key, seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
QDebug operator<<(QDebug debug, const PacketType& type) {
|
QDebug operator<<(QDebug debug, const PacketType& type) {
|
||||||
debug.nospace() << (uint8_t) type << " (" << qPrintable(nameForPacketType(type)) << ")";
|
QMetaObject metaObject = PacketTypeEnum::staticMetaObject;
|
||||||
|
QMetaEnum metaEnum = metaObject.enumerator(metaObject.enumeratorOffset());
|
||||||
|
QString typeName = metaEnum.valueToKey((int) type);
|
||||||
|
|
||||||
|
debug.nospace().noquote() << (uint8_t) type << " (" << typeName << ")";
|
||||||
return debug.space();
|
return debug.space();
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,70 +18,81 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include <QtCore/QCryptographicHash>
|
#include <QtCore/QCryptographicHash>
|
||||||
|
#include <QtCore/QObject>
|
||||||
#include <QtCore/QSet>
|
#include <QtCore/QSet>
|
||||||
#include <QtCore/QUuid>
|
#include <QtCore/QUuid>
|
||||||
|
|
||||||
// If adding a new packet packetType, you can replace one marked usable or add at the end.
|
// The enums are inside this PacketTypeEnum for run-time conversion of enum value to string via
|
||||||
// If you want the name of the packet packetType to be available for debugging or logging, update nameForPacketType() as well
|
// Q_ENUMS, without requiring a macro that is called for each enum value.
|
||||||
// This enum must hold 256 or fewer packet types (so the value is <= 255) since it is statically typed as a uint8_t
|
class PacketTypeEnum {
|
||||||
enum class PacketType : uint8_t {
|
Q_GADGET
|
||||||
Unknown,
|
Q_ENUMS(Value)
|
||||||
StunResponse,
|
public:
|
||||||
DomainList,
|
// If adding a new packet packetType, you can replace one marked usable or add at the end.
|
||||||
Ping,
|
// This enum must hold 256 or fewer packet types (so the value is <= 255) since it is statically typed as a uint8_t
|
||||||
PingReply,
|
enum class Value : uint8_t {
|
||||||
KillAvatar,
|
Unknown,
|
||||||
AvatarData,
|
StunResponse,
|
||||||
InjectAudio,
|
DomainList,
|
||||||
MixedAudio,
|
Ping,
|
||||||
MicrophoneAudioNoEcho,
|
PingReply,
|
||||||
MicrophoneAudioWithEcho,
|
KillAvatar,
|
||||||
BulkAvatarData,
|
AvatarData,
|
||||||
SilentAudioFrame,
|
InjectAudio,
|
||||||
DomainListRequest,
|
MixedAudio,
|
||||||
RequestAssignment,
|
MicrophoneAudioNoEcho,
|
||||||
CreateAssignment,
|
MicrophoneAudioWithEcho,
|
||||||
DomainConnectionDenied,
|
BulkAvatarData,
|
||||||
MuteEnvironment,
|
SilentAudioFrame,
|
||||||
AudioStreamStats,
|
DomainListRequest,
|
||||||
DomainServerPathQuery,
|
RequestAssignment,
|
||||||
DomainServerPathResponse,
|
CreateAssignment,
|
||||||
DomainServerAddedNode,
|
DomainConnectionDenied,
|
||||||
ICEServerPeerInformation,
|
MuteEnvironment,
|
||||||
ICEServerQuery,
|
AudioStreamStats,
|
||||||
OctreeStats,
|
DomainServerPathQuery,
|
||||||
Jurisdiction,
|
DomainServerPathResponse,
|
||||||
JurisdictionRequest,
|
DomainServerAddedNode,
|
||||||
AssignmentClientStatus,
|
ICEServerPeerInformation,
|
||||||
NoisyMute,
|
ICEServerQuery,
|
||||||
AvatarIdentity,
|
OctreeStats,
|
||||||
AvatarBillboard,
|
Jurisdiction,
|
||||||
DomainConnectRequest,
|
JurisdictionRequest,
|
||||||
DomainServerRequireDTLS,
|
AssignmentClientStatus,
|
||||||
NodeJsonStats,
|
NoisyMute,
|
||||||
OctreeDataNack,
|
AvatarIdentity,
|
||||||
StopNode,
|
AvatarBillboard,
|
||||||
AudioEnvironment,
|
DomainConnectRequest,
|
||||||
EntityEditNack,
|
DomainServerRequireDTLS,
|
||||||
ICEServerHeartbeat,
|
NodeJsonStats,
|
||||||
ICEPing,
|
OctreeDataNack,
|
||||||
ICEPingReply,
|
StopNode,
|
||||||
EntityData,
|
AudioEnvironment,
|
||||||
EntityQuery,
|
EntityEditNack,
|
||||||
EntityAdd,
|
ICEServerHeartbeat,
|
||||||
EntityErase,
|
ICEPing,
|
||||||
EntityEdit,
|
ICEPingReply,
|
||||||
DomainServerConnectionToken,
|
EntityData,
|
||||||
DomainSettingsRequest,
|
EntityQuery,
|
||||||
DomainSettings,
|
EntityAdd,
|
||||||
AssetGet,
|
EntityErase,
|
||||||
AssetGetReply,
|
EntityEdit,
|
||||||
AssetUpload,
|
DomainServerConnectionToken,
|
||||||
AssetUploadReply,
|
DomainSettingsRequest,
|
||||||
AssetGetInfo,
|
DomainSettings,
|
||||||
AssetGetInfoReply
|
AssetGet,
|
||||||
|
AssetGetReply,
|
||||||
|
AssetUpload,
|
||||||
|
AssetUploadReply,
|
||||||
|
AssetGetInfo,
|
||||||
|
AssetGetInfoReply,
|
||||||
|
DomainDisconnectRequest,
|
||||||
|
DomainServerRemovedNode
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using PacketType = PacketTypeEnum::Value;
|
||||||
|
|
||||||
const int NUM_BYTES_MD5_HASH = 16;
|
const int NUM_BYTES_MD5_HASH = 16;
|
||||||
|
|
||||||
typedef char PacketVersion;
|
typedef char PacketVersion;
|
||||||
|
@ -90,7 +101,6 @@ extern const QSet<PacketType> NON_VERIFIED_PACKETS;
|
||||||
extern const QSet<PacketType> NON_SOURCED_PACKETS;
|
extern const QSet<PacketType> NON_SOURCED_PACKETS;
|
||||||
extern const QSet<PacketType> RELIABLE_PACKETS;
|
extern const QSet<PacketType> RELIABLE_PACKETS;
|
||||||
|
|
||||||
QString nameForPacketType(PacketType packetType);
|
|
||||||
PacketVersion versionForPacketType(PacketType packetType);
|
PacketVersion versionForPacketType(PacketType packetType);
|
||||||
|
|
||||||
uint qHash(const PacketType& key, uint seed);
|
uint qHash(const PacketType& key, uint seed);
|
||||||
|
|
|
@ -1890,8 +1890,8 @@ bool Octree::readSVOFromStream(unsigned long streamLength, QDataStream& inputStr
|
||||||
versionForPacketType(expectedDataPacketType()), gotVersion);
|
versionForPacketType(expectedDataPacketType()), gotVersion);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qCDebug(octree) << "SVO file type mismatch. Expected: " << nameForPacketType(expectedType)
|
qCDebug(octree) << "SVO file type mismatch. Expected: " << expectedType
|
||||||
<< " Got: " << nameForPacketType(gotType);
|
<< " Got: " << gotType;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -112,8 +112,8 @@ bool EntityMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine)
|
||||||
_outgoingPriority = NO_PRORITY;
|
_outgoingPriority = NO_PRORITY;
|
||||||
} else {
|
} else {
|
||||||
_nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS;
|
_nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS;
|
||||||
if (engine->getSessionID() == _entity->getSimulatorID() || _entity->getSimulationPriority() > _outgoingPriority) {
|
if (engine->getSessionID() == _entity->getSimulatorID() || _entity->getSimulationPriority() >= _outgoingPriority) {
|
||||||
// we own the simulation or our priority looses to remote
|
// we own the simulation or our priority looses to (or ties with) remote
|
||||||
_outgoingPriority = NO_PRORITY;
|
_outgoingPriority = NO_PRORITY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -244,7 +244,7 @@ bool EntityMotionState::isCandidateForOwnership(const QUuid& sessionID) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
assert(entityTreeIsLocked());
|
assert(entityTreeIsLocked());
|
||||||
return _outgoingPriority != NO_PRORITY || sessionID == _entity->getSimulatorID();
|
return _outgoingPriority != NO_PRORITY || sessionID == _entity->getSimulatorID() || _entity->actionDataNeedsTransmit();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
|
bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
|
||||||
|
@ -292,7 +292,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
|
||||||
_serverPosition += dt * _serverVelocity;
|
_serverPosition += dt * _serverVelocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_serverActionData != _entity->getActionData()) {
|
if (_entity->actionDataNeedsTransmit()) {
|
||||||
setOutgoingPriority(SCRIPT_EDIT_SIMULATION_PRIORITY);
|
setOutgoingPriority(SCRIPT_EDIT_SIMULATION_PRIORITY);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -370,11 +370,15 @@ bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep, const QUuid& s
|
||||||
assert(_body);
|
assert(_body);
|
||||||
assert(entityTreeIsLocked());
|
assert(entityTreeIsLocked());
|
||||||
|
|
||||||
|
if (_entity->actionDataNeedsTransmit()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (_entity->getSimulatorID() != sessionID) {
|
if (_entity->getSimulatorID() != sessionID) {
|
||||||
// we don't own the simulation, but maybe we should...
|
// we don't own the simulation, but maybe we should...
|
||||||
if (_outgoingPriority != NO_PRORITY) {
|
if (_outgoingPriority != NO_PRORITY) {
|
||||||
if (_outgoingPriority < _entity->getSimulationPriority()) {
|
if (_outgoingPriority < _entity->getSimulationPriority()) {
|
||||||
// our priority looses to remote, so we don't bother to bid
|
// our priority loses to remote, so we don't bother to bid
|
||||||
_outgoingPriority = NO_PRORITY;
|
_outgoingPriority = NO_PRORITY;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -456,7 +460,10 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q
|
||||||
properties.setVelocity(_serverVelocity);
|
properties.setVelocity(_serverVelocity);
|
||||||
properties.setAcceleration(_serverAcceleration);
|
properties.setAcceleration(_serverAcceleration);
|
||||||
properties.setAngularVelocity(_serverAngularVelocity);
|
properties.setAngularVelocity(_serverAngularVelocity);
|
||||||
properties.setActionData(_serverActionData);
|
if (_entity->actionDataNeedsTransmit()) {
|
||||||
|
_entity->setActionDataNeedsTransmit(false);
|
||||||
|
properties.setActionData(_serverActionData);
|
||||||
|
}
|
||||||
|
|
||||||
// set the LastEdited of the properties but NOT the entity itself
|
// set the LastEdited of the properties but NOT the entity itself
|
||||||
quint64 now = usecTimestampNow();
|
quint64 now = usecTimestampNow();
|
||||||
|
@ -526,7 +533,7 @@ void EntityMotionState::clearIncomingDirtyFlags() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
quint8 EntityMotionState::getSimulationPriority() const {
|
quint8 EntityMotionState::getSimulationPriority() const {
|
||||||
if (_entity) {
|
if (_entity) {
|
||||||
return _entity->getSimulationPriority();
|
return _entity->getSimulationPriority();
|
||||||
|
|
|
@ -130,6 +130,7 @@ bool ObjectActionOffset::updateArguments(QVariantMap arguments) {
|
||||||
auto ownerEntity = _ownerEntity.lock();
|
auto ownerEntity = _ownerEntity.lock();
|
||||||
if (ownerEntity) {
|
if (ownerEntity) {
|
||||||
ownerEntity->setActionDataDirty(true);
|
ownerEntity->setActionDataDirty(true);
|
||||||
|
ownerEntity->setActionDataNeedsTransmit(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
activateBody();
|
activateBody();
|
||||||
|
|
|
@ -163,6 +163,7 @@ bool ObjectActionSpring::updateArguments(QVariantMap arguments) {
|
||||||
auto ownerEntity = _ownerEntity.lock();
|
auto ownerEntity = _ownerEntity.lock();
|
||||||
if (ownerEntity) {
|
if (ownerEntity) {
|
||||||
ownerEntity->setActionDataDirty(true);
|
ownerEntity->setActionDataDirty(true);
|
||||||
|
ownerEntity->setActionDataNeedsTransmit(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
activateBody();
|
activateBody();
|
||||||
|
|
|
@ -25,6 +25,8 @@ void Deck::queueClip(ClipPointer clip, Time timeOffset) {
|
||||||
|
|
||||||
// FIXME if the time offset is not zero, wrap the clip in a OffsetClip wrapper
|
// FIXME if the time offset is not zero, wrap the clip in a OffsetClip wrapper
|
||||||
_clips.push_back(clip);
|
_clips.push_back(clip);
|
||||||
|
|
||||||
|
_length = std::max(_length, clip->duration());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Deck::play() {
|
void Deck::play() {
|
||||||
|
|
|
@ -27,7 +27,7 @@ public:
|
||||||
static const FrameType TYPE_INVALID = 0xFFFF;
|
static const FrameType TYPE_INVALID = 0xFFFF;
|
||||||
static const FrameType TYPE_HEADER = 0x0;
|
static const FrameType TYPE_HEADER = 0x0;
|
||||||
FrameType type { TYPE_INVALID };
|
FrameType type { TYPE_INVALID };
|
||||||
Time timeOffset { 0 };
|
Time timeOffset { 0 }; // milliseconds
|
||||||
QByteArray data;
|
QByteArray data;
|
||||||
|
|
||||||
Frame() {}
|
Frame() {}
|
||||||
|
|
|
@ -501,8 +501,10 @@ void Model::setVisibleInScene(bool newValue, std::shared_ptr<render::Scene> scen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Model::addToScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
|
bool Model::addToScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges, bool showCollisionHull) {
|
||||||
if (!_meshGroupsKnown && isLoaded()) {
|
|
||||||
|
if ((!_meshGroupsKnown || showCollisionHull != _showCollisionHull) && isLoaded()) {
|
||||||
|
_showCollisionHull = showCollisionHull;
|
||||||
segregateMeshGroups();
|
segregateMeshGroups();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,8 +527,12 @@ bool Model::addToScene(std::shared_ptr<render::Scene> scene, render::PendingChan
|
||||||
return somethingAdded;
|
return somethingAdded;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Model::addToScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges, render::Item::Status::Getters& statusGetters) {
|
bool Model::addToScene(std::shared_ptr<render::Scene> scene,
|
||||||
if (!_meshGroupsKnown && isLoaded()) {
|
render::PendingChanges& pendingChanges,
|
||||||
|
render::Item::Status::Getters& statusGetters,
|
||||||
|
bool showCollisionHull) {
|
||||||
|
if ((!_meshGroupsKnown || showCollisionHull != _showCollisionHull) && isLoaded()) {
|
||||||
|
_showCollisionHull = showCollisionHull;
|
||||||
segregateMeshGroups();
|
segregateMeshGroups();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1139,8 +1145,14 @@ AABox Model::getPartBounds(int meshIndex, int partIndex) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::segregateMeshGroups() {
|
void Model::segregateMeshGroups() {
|
||||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
QSharedPointer<NetworkGeometry> networkGeometry;
|
||||||
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = _geometry->getMeshes();
|
if (_showCollisionHull && _collisionGeometry && _collisionGeometry->isLoaded()) {
|
||||||
|
networkGeometry = _collisionGeometry;
|
||||||
|
} else {
|
||||||
|
networkGeometry = _geometry;
|
||||||
|
}
|
||||||
|
const FBXGeometry& geometry = networkGeometry->getFBXGeometry();
|
||||||
|
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = networkGeometry->getMeshes();
|
||||||
|
|
||||||
_rig->makeAnimSkeleton(geometry);
|
_rig->makeAnimSkeleton(geometry);
|
||||||
|
|
||||||
|
|
|
@ -76,10 +76,13 @@ public:
|
||||||
return !_needsReload && isRenderable() && isActive() && isLoaded();
|
return !_needsReload && isRenderable() && isActive() && isLoaded();
|
||||||
}
|
}
|
||||||
bool initWhenReady(render::ScenePointer scene);
|
bool initWhenReady(render::ScenePointer scene);
|
||||||
bool addToScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
|
||||||
bool addToScene(std::shared_ptr<render::Scene> scene,
|
bool addToScene(std::shared_ptr<render::Scene> scene,
|
||||||
render::PendingChanges& pendingChanges,
|
render::PendingChanges& pendingChanges,
|
||||||
render::Item::Status::Getters& statusGetters);
|
bool showCollisionHull = false);
|
||||||
|
bool addToScene(std::shared_ptr<render::Scene> scene,
|
||||||
|
render::PendingChanges& pendingChanges,
|
||||||
|
render::Item::Status::Getters& statusGetters,
|
||||||
|
bool showCollisionHull = false);
|
||||||
void removeFromScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
void removeFromScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||||
void renderSetup(RenderArgs* args);
|
void renderSetup(RenderArgs* args);
|
||||||
bool isRenderable() const { return !_meshStates.isEmpty() || (isActive() && _geometry->getMeshes().empty()); }
|
bool isRenderable() const { return !_meshStates.isEmpty() || (isActive() && _geometry->getMeshes().empty()); }
|
||||||
|
@ -368,6 +371,7 @@ private:
|
||||||
bool _readyWhenAdded = false;
|
bool _readyWhenAdded = false;
|
||||||
bool _needsReload = true;
|
bool _needsReload = true;
|
||||||
bool _needsUpdateClusterMatrices = true;
|
bool _needsUpdateClusterMatrices = true;
|
||||||
|
bool _showCollisionHull = false;
|
||||||
|
|
||||||
friend class MeshPartPayload;
|
friend class MeshPartPayload;
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "RenderDeferredTask.h"
|
#include "RenderDeferredTask.h"
|
||||||
|
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
|
#include <PathUtils.h>
|
||||||
#include <RenderArgs.h>
|
#include <RenderArgs.h>
|
||||||
#include <ViewFrustum.h>
|
#include <ViewFrustum.h>
|
||||||
#include <gpu/Context.h>
|
#include <gpu/Context.h>
|
||||||
|
@ -111,8 +112,11 @@ RenderDeferredTask::RenderDeferredTask() : Task() {
|
||||||
_jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortTransparent", _jobs.back().getOutput(), DepthSortItems(false))));
|
_jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortTransparent", _jobs.back().getOutput(), DepthSortItems(false))));
|
||||||
_jobs.push_back(Job(new DrawTransparentDeferred::JobModel("TransparentDeferred", _jobs.back().getOutput())));
|
_jobs.push_back(Job(new DrawTransparentDeferred::JobModel("TransparentDeferred", _jobs.back().getOutput())));
|
||||||
|
|
||||||
_jobs.push_back(Job(new render::DrawStatus::JobModel("DrawStatus", renderedOpaques)));
|
// Grab a texture map representing the different status icons and assign that to the drawStatsuJob
|
||||||
|
auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg";
|
||||||
|
|
||||||
|
auto statusIconMap = DependencyManager::get<TextureCache>()->getImageTexture(iconMapPath);
|
||||||
|
_jobs.push_back(Job(new render::DrawStatus::JobModel("DrawStatus", renderedOpaques, DrawStatus(statusIconMap))));
|
||||||
|
|
||||||
_jobs.back().setEnabled(false);
|
_jobs.back().setEnabled(false);
|
||||||
_drawStatusJobIndex = _jobs.size() - 1;
|
_drawStatusJobIndex = _jobs.size() - 1;
|
||||||
|
@ -387,4 +391,4 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const
|
||||||
|
|
||||||
});
|
});
|
||||||
args->_batch = nullptr;
|
args->_batch = nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,12 @@ public:
|
||||||
int _drawStatusJobIndex = -1;
|
int _drawStatusJobIndex = -1;
|
||||||
int _drawHitEffectJobIndex = -1;
|
int _drawHitEffectJobIndex = -1;
|
||||||
|
|
||||||
void setDrawItemStatus(bool draw) { if (_drawStatusJobIndex >= 0) { _jobs[_drawStatusJobIndex].setEnabled(draw); } }
|
void setDrawItemStatus(int draw) {
|
||||||
|
if (_drawStatusJobIndex >= 0) {
|
||||||
|
_jobs[_drawStatusJobIndex].setEnabled(draw > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool doDrawItemStatus() const { if (_drawStatusJobIndex >= 0) { return _jobs[_drawStatusJobIndex].isEnabled(); } else { return false; } }
|
bool doDrawItemStatus() const { if (_drawStatusJobIndex >= 0) { return _jobs[_drawStatusJobIndex].isEnabled(); } else { return false; } }
|
||||||
|
|
||||||
void setDrawHitEffect(bool draw) { if (_drawHitEffectJobIndex >= 0) { _jobs[_drawHitEffectJobIndex].setEnabled(draw); } }
|
void setDrawHitEffect(bool draw) { if (_drawHitEffectJobIndex >= 0) { _jobs[_drawHitEffectJobIndex].setEnabled(draw); } }
|
||||||
|
|
|
@ -29,7 +29,7 @@ using namespace render;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const gpu::PipelinePointer& DrawStatus::getDrawItemBoundsPipeline() {
|
const gpu::PipelinePointer DrawStatus::getDrawItemBoundsPipeline() {
|
||||||
if (!_drawItemBoundsPipeline) {
|
if (!_drawItemBoundsPipeline) {
|
||||||
auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(drawItemBounds_vert)));
|
auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(drawItemBounds_vert)));
|
||||||
auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(drawItemBounds_frag)));
|
auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(drawItemBounds_frag)));
|
||||||
|
@ -56,18 +56,20 @@ const gpu::PipelinePointer& DrawStatus::getDrawItemBoundsPipeline() {
|
||||||
return _drawItemBoundsPipeline;
|
return _drawItemBoundsPipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
const gpu::PipelinePointer& DrawStatus::getDrawItemStatusPipeline() {
|
const gpu::PipelinePointer DrawStatus::getDrawItemStatusPipeline() {
|
||||||
if (!_drawItemStatusPipeline) {
|
if (!_drawItemStatusPipeline) {
|
||||||
auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(drawItemStatus_vert)));
|
auto vs = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(drawItemStatus_vert)));
|
||||||
auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(drawItemStatus_frag)));
|
auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(drawItemStatus_frag)));
|
||||||
gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps));
|
gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps));
|
||||||
|
|
||||||
gpu::Shader::BindingSet slotBindings;
|
gpu::Shader::BindingSet slotBindings;
|
||||||
|
slotBindings.insert(gpu::Shader::Binding(std::string("iconStatusMap"), 0));
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
gpu::Shader::makeProgram(*program, slotBindings);
|
||||||
|
|
||||||
_drawItemStatusPosLoc = program->getUniforms().findLocation("inBoundPos");
|
_drawItemStatusPosLoc = program->getUniforms().findLocation("inBoundPos");
|
||||||
_drawItemStatusDimLoc = program->getUniforms().findLocation("inBoundDim");
|
_drawItemStatusDimLoc = program->getUniforms().findLocation("inBoundDim");
|
||||||
_drawItemStatusValueLoc = program->getUniforms().findLocation("inStatus");
|
_drawItemStatusValue0Loc = program->getUniforms().findLocation("inStatus0");
|
||||||
|
_drawItemStatusValue1Loc = program->getUniforms().findLocation("inStatus1");
|
||||||
|
|
||||||
auto state = std::make_shared<gpu::State>();
|
auto state = std::make_shared<gpu::State>();
|
||||||
|
|
||||||
|
@ -84,11 +86,23 @@ const gpu::PipelinePointer& DrawStatus::getDrawItemStatusPipeline() {
|
||||||
return _drawItemStatusPipeline;
|
return _drawItemStatusPipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawStatus::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) {
|
void DrawStatus::setStatusIconMap(const gpu::TexturePointer& map) {
|
||||||
|
_statusIconMap = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gpu::TexturePointer DrawStatus::getStatusIconMap() const {
|
||||||
|
return _statusIconMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawStatus::run(const SceneContextPointer& sceneContext,
|
||||||
|
const RenderContextPointer& renderContext,
|
||||||
|
const ItemIDsBounds& inItems) {
|
||||||
assert(renderContext->args);
|
assert(renderContext->args);
|
||||||
assert(renderContext->args->_viewFrustum);
|
assert(renderContext->args->_viewFrustum);
|
||||||
RenderArgs* args = renderContext->args;
|
RenderArgs* args = renderContext->args;
|
||||||
auto& scene = sceneContext->_scene;
|
auto& scene = sceneContext->_scene;
|
||||||
|
const int NUM_STATUS_VEC4_PER_ITEM = 2;
|
||||||
|
const int VEC4_LENGTH = 4;
|
||||||
|
|
||||||
// FIrst thing, we collect the bound and the status for all the items we want to render
|
// FIrst thing, we collect the bound and the status for all the items we want to render
|
||||||
int nbItems = 0;
|
int nbItems = 0;
|
||||||
|
@ -101,7 +115,7 @@ void DrawStatus::run(const SceneContextPointer& sceneContext, const RenderContex
|
||||||
}
|
}
|
||||||
|
|
||||||
_itemBounds->resize((inItems.size() * sizeof(AABox)));
|
_itemBounds->resize((inItems.size() * sizeof(AABox)));
|
||||||
_itemStatus->resize((inItems.size() * sizeof(glm::vec4)));
|
_itemStatus->resize((inItems.size() * NUM_STATUS_VEC4_PER_ITEM * sizeof(glm::vec4)));
|
||||||
AABox* itemAABox = reinterpret_cast<AABox*> (_itemBounds->editData());
|
AABox* itemAABox = reinterpret_cast<AABox*> (_itemBounds->editData());
|
||||||
glm::ivec4* itemStatus = reinterpret_cast<glm::ivec4*> (_itemStatus->editData());
|
glm::ivec4* itemStatus = reinterpret_cast<glm::ivec4*> (_itemStatus->editData());
|
||||||
for (auto& item : inItems) {
|
for (auto& item : inItems) {
|
||||||
|
@ -112,11 +126,31 @@ void DrawStatus::run(const SceneContextPointer& sceneContext, const RenderContex
|
||||||
(*itemAABox).setBox(item.bounds.getCorner(), 0.1f);
|
(*itemAABox).setBox(item.bounds.getCorner(), 0.1f);
|
||||||
}
|
}
|
||||||
auto& itemScene = scene->getItem(item.id);
|
auto& itemScene = scene->getItem(item.id);
|
||||||
(*itemStatus) = itemScene.getStatusPackedValues();
|
|
||||||
|
auto itemStatusPointer = itemScene.getStatus();
|
||||||
|
if (itemStatusPointer) {
|
||||||
|
// Query the current status values, this is where the statusGetter lambda get called
|
||||||
|
auto&& currentStatusValues = itemStatusPointer->getCurrentValues();
|
||||||
|
int valueNum = 0;
|
||||||
|
for (int vec4Num = 0; vec4Num < NUM_STATUS_VEC4_PER_ITEM; vec4Num++) {
|
||||||
|
(*itemStatus) = glm::ivec4(Item::Status::Value::INVALID.getPackedData());
|
||||||
|
for (int component = 0; component < VEC4_LENGTH; component++) {
|
||||||
|
valueNum = vec4Num * VEC4_LENGTH + component;
|
||||||
|
if (valueNum < (int)currentStatusValues.size()) {
|
||||||
|
(*itemStatus)[component] = currentStatusValues[valueNum].getPackedData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
itemStatus++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(*itemStatus) = glm::ivec4(Item::Status::Value::INVALID.getPackedData());
|
||||||
|
itemStatus++;
|
||||||
|
(*itemStatus) = glm::ivec4(Item::Status::Value::INVALID.getPackedData());
|
||||||
|
itemStatus++;
|
||||||
|
}
|
||||||
|
|
||||||
nbItems++;
|
nbItems++;
|
||||||
itemAABox++;
|
itemAABox++;
|
||||||
itemStatus++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,6 +165,7 @@ void DrawStatus::run(const SceneContextPointer& sceneContext, const RenderContex
|
||||||
Transform viewMat;
|
Transform viewMat;
|
||||||
args->_viewFrustum->evalProjectionMatrix(projMat);
|
args->_viewFrustum->evalProjectionMatrix(projMat);
|
||||||
args->_viewFrustum->evalViewTransform(viewMat);
|
args->_viewFrustum->evalViewTransform(viewMat);
|
||||||
|
batch.setViewportTransform(args->_viewport);
|
||||||
|
|
||||||
batch.setProjectionTransform(projMat);
|
batch.setProjectionTransform(projMat);
|
||||||
batch.setViewTransform(viewMat);
|
batch.setViewTransform(viewMat);
|
||||||
|
@ -144,20 +179,28 @@ void DrawStatus::run(const SceneContextPointer& sceneContext, const RenderContex
|
||||||
|
|
||||||
const unsigned int VEC3_ADRESS_OFFSET = 3;
|
const unsigned int VEC3_ADRESS_OFFSET = 3;
|
||||||
|
|
||||||
for (int i = 0; i < nbItems; i++) {
|
if ((renderContext->_drawItemStatus & showDisplayStatusFlag) > 0) {
|
||||||
batch._glUniform3fv(_drawItemBoundPosLoc, 1, (const float*) (itemAABox + i));
|
for (int i = 0; i < nbItems; i++) {
|
||||||
batch._glUniform3fv(_drawItemBoundDimLoc, 1, ((const float*) (itemAABox + i)) + VEC3_ADRESS_OFFSET);
|
batch._glUniform3fv(_drawItemBoundPosLoc, 1, (const float*) (itemAABox + i));
|
||||||
|
batch._glUniform3fv(_drawItemBoundDimLoc, 1, ((const float*) (itemAABox + i)) + VEC3_ADRESS_OFFSET);
|
||||||
|
|
||||||
batch.draw(gpu::LINES, 24, 0);
|
batch.draw(gpu::LINES, 24, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
batch.setResourceTexture(0, gpu::TextureView(getStatusIconMap(), 0));
|
||||||
|
|
||||||
batch.setPipeline(getDrawItemStatusPipeline());
|
batch.setPipeline(getDrawItemStatusPipeline());
|
||||||
for (int i = 0; i < nbItems; i++) {
|
|
||||||
batch._glUniform3fv(_drawItemStatusPosLoc, 1, (const float*) (itemAABox + i));
|
|
||||||
batch._glUniform3fv(_drawItemStatusDimLoc, 1, ((const float*) (itemAABox + i)) + VEC3_ADRESS_OFFSET);
|
|
||||||
batch._glUniform4iv(_drawItemStatusValueLoc, 1, (const int*) (itemStatus + i));
|
|
||||||
|
|
||||||
batch.draw(gpu::TRIANGLES, 24, 0);
|
if ((renderContext->_drawItemStatus & showNetworkStatusFlag) > 0) {
|
||||||
|
for (int i = 0; i < nbItems; i++) {
|
||||||
|
batch._glUniform3fv(_drawItemStatusPosLoc, 1, (const float*) (itemAABox + i));
|
||||||
|
batch._glUniform3fv(_drawItemStatusDimLoc, 1, ((const float*) (itemAABox + i)) + VEC3_ADRESS_OFFSET);
|
||||||
|
batch._glUniform4iv(_drawItemStatusValue0Loc, 1, (const int*)(itemStatus + NUM_STATUS_VEC4_PER_ITEM * i));
|
||||||
|
batch._glUniform4iv(_drawItemStatusValue1Loc, 1, (const int*)(itemStatus + NUM_STATUS_VEC4_PER_ITEM * i + 1));
|
||||||
|
batch.draw(gpu::TRIANGLES, 24 * NUM_STATUS_VEC4_PER_ITEM, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
batch.setResourceTexture(0, 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,22 +21,30 @@ namespace render {
|
||||||
int _drawItemBoundDimLoc = -1;
|
int _drawItemBoundDimLoc = -1;
|
||||||
int _drawItemStatusPosLoc = -1;
|
int _drawItemStatusPosLoc = -1;
|
||||||
int _drawItemStatusDimLoc = -1;
|
int _drawItemStatusDimLoc = -1;
|
||||||
int _drawItemStatusValueLoc = -1;
|
int _drawItemStatusValue0Loc = -1;
|
||||||
|
int _drawItemStatusValue1Loc = -1;
|
||||||
|
|
||||||
gpu::Stream::FormatPointer _drawItemFormat;
|
gpu::Stream::FormatPointer _drawItemFormat;
|
||||||
gpu::PipelinePointer _drawItemBoundsPipeline;
|
gpu::PipelinePointer _drawItemBoundsPipeline;
|
||||||
gpu::PipelinePointer _drawItemStatusPipeline;
|
gpu::PipelinePointer _drawItemStatusPipeline;
|
||||||
gpu::BufferPointer _itemBounds;
|
gpu::BufferPointer _itemBounds;
|
||||||
gpu::BufferPointer _itemStatus;
|
gpu::BufferPointer _itemStatus;
|
||||||
|
gpu::TexturePointer _statusIconMap;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
DrawStatus() {}
|
||||||
|
DrawStatus(const gpu::TexturePointer statusIconMap) { setStatusIconMap(statusIconMap); }
|
||||||
|
|
||||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems);
|
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems);
|
||||||
|
|
||||||
typedef Job::ModelI<DrawStatus, ItemIDsBounds> JobModel;
|
typedef Job::ModelI<DrawStatus, ItemIDsBounds> JobModel;
|
||||||
|
|
||||||
const gpu::PipelinePointer& getDrawItemBoundsPipeline();
|
const gpu::PipelinePointer getDrawItemBoundsPipeline();
|
||||||
const gpu::PipelinePointer& getDrawItemStatusPipeline();
|
const gpu::PipelinePointer getDrawItemStatusPipeline();
|
||||||
|
|
||||||
|
void setStatusIconMap(const gpu::TexturePointer& map);
|
||||||
|
const gpu::TexturePointer getStatusIconMap() const;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,7 @@ public:
|
||||||
|
|
||||||
const Varying getInput() const { return _input; }
|
const Varying getInput() const { return _input; }
|
||||||
|
|
||||||
ModelI(const std::string& name, const Varying& input): Concept(name), _input(input) {}
|
ModelI(const std::string& name, const Varying& input, Data data = Data()) : Concept(name), _data(data), _input(input) {}
|
||||||
ModelI(const std::string& name, Data data): Concept(name), _data(data) {}
|
ModelI(const std::string& name, Data data): Concept(name), _data(data) {}
|
||||||
|
|
||||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||||
|
|
|
@ -25,6 +25,10 @@ public:
|
||||||
};
|
};
|
||||||
typedef std::shared_ptr<SceneContext> SceneContextPointer;
|
typedef std::shared_ptr<SceneContext> SceneContextPointer;
|
||||||
|
|
||||||
|
// see examples/utilities/tools/renderEngineDebug.js
|
||||||
|
const int showDisplayStatusFlag = 1;
|
||||||
|
const int showNetworkStatusFlag = 2;
|
||||||
|
|
||||||
|
|
||||||
class RenderContext {
|
class RenderContext {
|
||||||
public:
|
public:
|
||||||
|
@ -49,7 +53,7 @@ public:
|
||||||
int _numDrawnOverlay3DItems = 0;
|
int _numDrawnOverlay3DItems = 0;
|
||||||
int _maxDrawnOverlay3DItems = -1;
|
int _maxDrawnOverlay3DItems = -1;
|
||||||
|
|
||||||
bool _drawItemStatus = false;
|
int _drawItemStatus = 0;
|
||||||
bool _drawHitEffect = false;
|
bool _drawHitEffect = false;
|
||||||
|
|
||||||
bool _occlusionStatus = false;
|
bool _occlusionStatus = false;
|
||||||
|
|
|
@ -72,17 +72,20 @@ void Item::Status::Value::setScale(float scale) {
|
||||||
void Item::Status::Value::setColor(float hue) {
|
void Item::Status::Value::setColor(float hue) {
|
||||||
// Convert the HUe from range [0, 360] to signed normalized value
|
// Convert the HUe from range [0, 360] to signed normalized value
|
||||||
const float HUE_MAX = 360.0f;
|
const float HUE_MAX = 360.0f;
|
||||||
_color = (std::numeric_limits<unsigned short>::max() - 1) * 0.5f * (1.0f + std::max(std::min(hue, HUE_MAX), 0.0f) / HUE_MAX);
|
_color = (std::numeric_limits<unsigned char>::max()) * (std::max(std::min(hue, HUE_MAX), 0.0f) / HUE_MAX);
|
||||||
|
}
|
||||||
|
void Item::Status::Value::setIcon(unsigned char icon) {
|
||||||
|
_icon = icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Item::Status::getPackedValues(glm::ivec4& values) const {
|
Item::Status::Values Item::Status::getCurrentValues() const {
|
||||||
for (unsigned int i = 0; i < (unsigned int)values.length(); i++) {
|
Values currentValues(_values.size());
|
||||||
if (i < _values.size()) {
|
auto currentValue = currentValues.begin();
|
||||||
values[i] = _values[i]().getPackedData();
|
for (auto& getter : _values) {
|
||||||
} else {
|
(*currentValue) = getter();
|
||||||
values[i] = Value::INVALID.getPackedData();
|
currentValue++;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return currentValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Item::PayloadInterface::addStatusGetter(const Status::Getter& getter) {
|
void Item::PayloadInterface::addStatusGetter(const Status::Getter& getter) {
|
||||||
|
@ -110,15 +113,6 @@ void Item::resetPayload(const PayloadPointer& payload) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::ivec4 Item::getStatusPackedValues() const {
|
|
||||||
glm::ivec4 values(Status::Value::INVALID.getPackedData());
|
|
||||||
auto& status = getStatus();
|
|
||||||
if (status) {
|
|
||||||
status->getPackedValues(values);
|
|
||||||
};
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PendingChanges::resetItem(ItemID id, const PayloadPointer& payload) {
|
void PendingChanges::resetItem(ItemID id, const PayloadPointer& payload) {
|
||||||
_resetItems.push_back(id);
|
_resetItems.push_back(id);
|
||||||
_resetPayloads.push_back(payload);
|
_resetPayloads.push_back(payload);
|
||||||
|
|
|
@ -206,17 +206,21 @@ public:
|
||||||
// It can be scaled in the range [0, 1] and the color hue in the range [0, 360] representing the color wheel hue
|
// It can be scaled in the range [0, 1] and the color hue in the range [0, 360] representing the color wheel hue
|
||||||
class Value {
|
class Value {
|
||||||
unsigned short _scale = 0xFFFF;
|
unsigned short _scale = 0xFFFF;
|
||||||
unsigned short _color = 0xFFFF;
|
unsigned char _color = 0xFF;
|
||||||
|
unsigned char _icon = 0xFF;
|
||||||
public:
|
public:
|
||||||
const static Value INVALID; // Invalid value meanss the status won't show
|
const static Value INVALID; // Invalid value meanss the status won't show
|
||||||
|
|
||||||
Value() {}
|
Value() {}
|
||||||
Value(float scale, float hue) { setScale(scale); setColor(hue); }
|
Value(float scale, float hue, unsigned char icon = 0xFF) { setScale(scale); setColor(hue); setIcon(icon); }
|
||||||
|
|
||||||
// It can be scaled in the range [0, 1]
|
// It can be scaled in the range [0, 1]
|
||||||
void setScale(float scale);
|
void setScale(float scale);
|
||||||
// the color hue in the range [0, 360] representing the color wheel hue
|
// the color hue in the range [0, 360] representing the color wheel hue
|
||||||
void setColor(float hue);
|
void setColor(float hue);
|
||||||
|
// the icon to display in the range [0, 255], where 0 means no icon, just filled quad and anything else would
|
||||||
|
// hopefully have an icon available to display (see DrawStatusJob)
|
||||||
|
void setIcon(unsigned char icon);
|
||||||
|
|
||||||
// Standard color Hue
|
// Standard color Hue
|
||||||
static const float RED; // 0.0f;
|
static const float RED; // 0.0f;
|
||||||
|
@ -237,7 +241,10 @@ public:
|
||||||
|
|
||||||
void addGetter(const Getter& getter) { _values.push_back(getter); }
|
void addGetter(const Getter& getter) { _values.push_back(getter); }
|
||||||
|
|
||||||
void getPackedValues(glm::ivec4& values) const;
|
size_t getNumValues() const { return _values.size(); }
|
||||||
|
|
||||||
|
using Values = std::vector <Value>;
|
||||||
|
Values getCurrentValues() const;
|
||||||
};
|
};
|
||||||
typedef std::shared_ptr<Status> StatusPointer;
|
typedef std::shared_ptr<Status> StatusPointer;
|
||||||
|
|
||||||
|
@ -301,7 +308,6 @@ public:
|
||||||
|
|
||||||
// Access the status
|
// Access the status
|
||||||
const StatusPointer& getStatus() const { return _payload->getStatus(); }
|
const StatusPointer& getStatus() const { return _payload->getStatus(); }
|
||||||
glm::ivec4 getStatusPackedValues() const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
PayloadPointer _payload;
|
PayloadPointer _payload;
|
||||||
|
|
|
@ -12,9 +12,20 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
in vec4 varColor;
|
in vec4 varColor;
|
||||||
|
in vec3 varTexcoord;
|
||||||
out vec4 outFragColor;
|
out vec4 outFragColor;
|
||||||
|
|
||||||
|
uniform sampler2D _icons;
|
||||||
|
vec2 getIconTexcoord(float icon, vec2 uv) {
|
||||||
|
const vec2 ICON_COORD_SIZE = vec2(0.0625, 1.0);
|
||||||
|
return vec2((uv.x + icon) * ICON_COORD_SIZE.x, uv.y * ICON_COORD_SIZE.y);
|
||||||
|
}
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
outFragColor = varColor;
|
if (varTexcoord.z < 254.5) {
|
||||||
|
outFragColor = texture(_icons, getIconTexcoord(varTexcoord.z, varTexcoord.xy)) * varColor;
|
||||||
|
} else {
|
||||||
|
vec2 centerDir = varTexcoord.xy * 2.0f - 1.0f;
|
||||||
|
outFragColor = vec4(varColor.xyz, 1.0 - step(1.0f, dot(centerDir.xy, centerDir.xy)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,12 @@
|
||||||
<$declareStandardTransform()$>
|
<$declareStandardTransform()$>
|
||||||
|
|
||||||
out vec4 varColor;
|
out vec4 varColor;
|
||||||
|
out vec3 varTexcoord;
|
||||||
|
|
||||||
uniform vec3 inBoundPos;
|
uniform vec3 inBoundPos;
|
||||||
uniform vec3 inBoundDim;
|
uniform vec3 inBoundDim;
|
||||||
uniform ivec4 inStatus;
|
uniform ivec4 inStatus0;
|
||||||
|
uniform ivec4 inStatus1;
|
||||||
|
|
||||||
vec3 paintRainbow(float normalizedHue) {
|
vec3 paintRainbow(float normalizedHue) {
|
||||||
float v = normalizedHue * 6.f;
|
float v = normalizedHue * 6.f;
|
||||||
|
@ -43,16 +45,28 @@ vec3 paintRainbow(float normalizedHue) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vec2 unpackStatus(int v) {
|
const int INVALID_STATUS = int(0xFFFFFFFF);
|
||||||
return vec2(clamp(float(int((v >> 0) & 0xFFFF) - 32727) / 32727.0, -1.0, 1.0),
|
const int MAX_NUM_ICONS = 8;
|
||||||
clamp(float(int((v >> 16) & 0xFFFF) - 32727) / 32727.0, -1.0, 1.0));
|
const int ICONS_PER_ROW = 4;
|
||||||
|
|
||||||
|
int getIconStatus(int icon) {
|
||||||
|
if (icon < ICONS_PER_ROW) {
|
||||||
|
return inStatus0[icon];
|
||||||
|
} else if (icon < MAX_NUM_ICONS) {
|
||||||
|
return inStatus1[icon - ICONS_PER_ROW];
|
||||||
|
}
|
||||||
|
return INVALID_STATUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 unpackStatus(int v) {
|
||||||
|
return vec3(clamp(float(int((v >> 0) & 0xFFFF) - 32727) / 32727.0, -1.0, 1.0),
|
||||||
|
clamp(float(uint((v >> 16) & 0xFF)) / 255.0, 0.0, 1.0),
|
||||||
|
clamp(float(int((v >> 24) & 0xFF)), 0.0, 255.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
const vec2 ICON_PIXEL_SIZE = vec2(10, 10);
|
const int NUM_VERTICES_PER_ICON = 6;
|
||||||
const vec2 MARGIN_PIXEL_SIZE = vec2(2, 2);
|
const vec4 UNIT_QUAD[NUM_VERTICES_PER_ICON] = vec4[NUM_VERTICES_PER_ICON](
|
||||||
const int NUM_VERTICES = 6;
|
|
||||||
const vec4 UNIT_QUAD[NUM_VERTICES] = vec4[NUM_VERTICES](
|
|
||||||
vec4(-1.0, -1.0, 0.0, 1.0),
|
vec4(-1.0, -1.0, 0.0, 1.0),
|
||||||
vec4(1.0, -1.0, 0.0, 1.0),
|
vec4(1.0, -1.0, 0.0, 1.0),
|
||||||
vec4(-1.0, 1.0, 0.0, 1.0),
|
vec4(-1.0, 1.0, 0.0, 1.0),
|
||||||
|
@ -61,6 +75,17 @@ void main(void) {
|
||||||
vec4(1.0, 1.0, 0.0, 1.0)
|
vec4(1.0, 1.0, 0.0, 1.0)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const vec2 ICON_PIXEL_SIZE = vec2(20, 20);
|
||||||
|
const vec2 MARGIN_PIXEL_SIZE = vec2(2, 2);
|
||||||
|
const vec2 ICON_GRID_SLOTS[MAX_NUM_ICONS] = vec2[MAX_NUM_ICONS](vec2(-1.5, 0.5),
|
||||||
|
vec2(-0.5, 0.5),
|
||||||
|
vec2(0.5, 0.5),
|
||||||
|
vec2(1.5, 0.5),
|
||||||
|
vec2(-1.5,-0.5),
|
||||||
|
vec2(-0.5,-0.5),
|
||||||
|
vec2(0.5, -0.5),
|
||||||
|
vec2(1.5, -0.5));
|
||||||
|
|
||||||
// anchor point in clip space
|
// anchor point in clip space
|
||||||
vec4 anchorPoint = vec4(inBoundPos, 1.0) + vec4(inBoundDim, 0.0) * vec4(0.5, 0.5, 0.5, 0.0);
|
vec4 anchorPoint = vec4(inBoundPos, 1.0) + vec4(inBoundDim, 0.0) * vec4(0.5, 0.5, 0.5, 0.0);
|
||||||
TransformCamera cam = getTransformCamera();
|
TransformCamera cam = getTransformCamera();
|
||||||
|
@ -68,36 +93,43 @@ void main(void) {
|
||||||
<$transformModelToClipPos(cam, obj, anchorPoint, anchorPoint)$>
|
<$transformModelToClipPos(cam, obj, anchorPoint, anchorPoint)$>
|
||||||
|
|
||||||
// Which icon are we dealing with ?
|
// Which icon are we dealing with ?
|
||||||
int iconNum = gl_VertexID / NUM_VERTICES;
|
int iconNum = gl_VertexID / NUM_VERTICES_PER_ICON;
|
||||||
|
int packedIconStatus = getIconStatus(iconNum);
|
||||||
|
|
||||||
// if invalid, just kill
|
// if invalid, just kill
|
||||||
if (inStatus[iconNum] == 0xFFFFFFFF) {
|
if (packedIconStatus == INVALID_STATUS) {
|
||||||
gl_Position = anchorPoint;
|
gl_Position = anchorPoint;
|
||||||
varColor = vec4(1.0);
|
varColor = vec4(1.0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Which quad vertex pos?
|
||||||
|
int twoTriID = gl_VertexID - iconNum * NUM_VERTICES_PER_ICON;
|
||||||
|
vec4 quadPos = UNIT_QUAD[twoTriID];
|
||||||
|
|
||||||
// unpack to get x and y satus
|
// unpack to get x and y satus
|
||||||
vec2 iconStatus = unpackStatus(inStatus[iconNum]);
|
vec3 iconStatus = unpackStatus(packedIconStatus);
|
||||||
|
|
||||||
// Use the status for showing a color
|
// Use the status for showing a color
|
||||||
varColor = vec4(paintRainbow(abs(iconStatus.y)), 1.0);
|
varColor = vec4(paintRainbow(abs(iconStatus.y)), 1.0);
|
||||||
|
|
||||||
|
// Pass the texcoord and the z texcoord is representing the texture icon
|
||||||
|
varTexcoord = vec3((quadPos.xy + 1.0) * 0.5, iconStatus.z);
|
||||||
|
|
||||||
// Also changes the size of the notification
|
// Also changes the size of the notification
|
||||||
vec2 iconScale = ICON_PIXEL_SIZE;
|
vec2 iconScale = ICON_PIXEL_SIZE;
|
||||||
iconScale = max(vec2(1, 1), (iconScale * iconStatus.x));
|
iconScale = max(vec2(0, 0), (iconScale * iconStatus.x));
|
||||||
|
|
||||||
//Offset icon to the right based on the iconNum
|
//Offset icon to the right based on the iconNum
|
||||||
vec2 offset = vec2(iconNum * (ICON_PIXEL_SIZE.x + MARGIN_PIXEL_SIZE.x), 0);
|
vec2 gridOffset = ICON_GRID_SLOTS[iconNum];
|
||||||
|
vec2 offset = gridOffset * (ICON_PIXEL_SIZE + MARGIN_PIXEL_SIZE);
|
||||||
|
|
||||||
// Final position in pixel space
|
// Final position in pixel space
|
||||||
int twoTriID = gl_VertexID - iconNum * NUM_VERTICES;
|
vec2 quadPixelPos = offset.xy + quadPos.xy * 0.5 * iconScale;
|
||||||
vec4 pos = UNIT_QUAD[twoTriID];
|
|
||||||
vec2 quadPixelPos = offset.xy + pos.xy * 0.5 * iconScale;
|
|
||||||
|
|
||||||
vec4 viewport;
|
vec4 viewport;
|
||||||
<$transformCameraViewport(cam, viewport)$>;
|
<$transformCameraViewport(cam, viewport)$>;
|
||||||
vec2 pixelToClip = vec2(2.0 / viewport.z, 2.0 / viewport.w);
|
vec2 pixelToClip = vec2(2.0 / viewport.z, 2.0 / viewport.w);
|
||||||
gl_Position = anchorPoint + (anchorPoint.w * vec4(quadPixelPos * pixelToClip, 0.0, 0.0));
|
gl_Position = anchorPoint + (anchorPoint.w * vec4(quadPixelPos * pixelToClip, 0.0, 0.0));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,8 +107,8 @@ public:
|
||||||
Q_INVOKABLE void setEngineMaxDrawnOverlay3DItems(int count) { _maxDrawnOverlay3DItems = count; }
|
Q_INVOKABLE void setEngineMaxDrawnOverlay3DItems(int count) { _maxDrawnOverlay3DItems = count; }
|
||||||
Q_INVOKABLE int getEngineMaxDrawnOverlay3DItems() { return _maxDrawnOverlay3DItems; }
|
Q_INVOKABLE int getEngineMaxDrawnOverlay3DItems() { return _maxDrawnOverlay3DItems; }
|
||||||
|
|
||||||
Q_INVOKABLE void setEngineDisplayItemStatus(bool display) { _drawItemStatus = display; }
|
Q_INVOKABLE void setEngineDisplayItemStatus(int display) { _drawItemStatus = display; }
|
||||||
Q_INVOKABLE bool doEngineDisplayItemStatus() { return _drawItemStatus; }
|
Q_INVOKABLE int doEngineDisplayItemStatus() { return _drawItemStatus; }
|
||||||
|
|
||||||
Q_INVOKABLE void setEngineDisplayHitEffect(bool display) { _drawHitEffect = display; }
|
Q_INVOKABLE void setEngineDisplayHitEffect(bool display) { _drawHitEffect = display; }
|
||||||
Q_INVOKABLE bool doEngineDisplayHitEffect() { return _drawHitEffect; }
|
Q_INVOKABLE bool doEngineDisplayHitEffect() { return _drawHitEffect; }
|
||||||
|
@ -143,7 +143,7 @@ protected:
|
||||||
int _maxDrawnTransparentItems = -1;
|
int _maxDrawnTransparentItems = -1;
|
||||||
int _maxDrawnOverlay3DItems = -1;
|
int _maxDrawnOverlay3DItems = -1;
|
||||||
|
|
||||||
bool _drawItemStatus = false;
|
int _drawItemStatus = 0;
|
||||||
|
|
||||||
bool _drawHitEffect = false;
|
bool _drawHitEffect = false;
|
||||||
|
|
||||||
|
|
|
@ -68,17 +68,16 @@ public:
|
||||||
class RenderArgs {
|
class RenderArgs {
|
||||||
public:
|
public:
|
||||||
typedef std::function<bool(const RenderArgs* args, const AABox& bounds)> ShoudRenderFunctor;
|
typedef std::function<bool(const RenderArgs* args, const AABox& bounds)> ShoudRenderFunctor;
|
||||||
|
|
||||||
enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE };
|
enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE };
|
||||||
|
|
||||||
enum RenderSide { MONO, STEREO_LEFT, STEREO_RIGHT };
|
enum RenderSide { MONO, STEREO_LEFT, STEREO_RIGHT };
|
||||||
|
|
||||||
enum DebugFlags {
|
enum DebugFlags {
|
||||||
RENDER_DEBUG_NONE = 0,
|
RENDER_DEBUG_NONE = 0,
|
||||||
RENDER_DEBUG_HULLS = 1,
|
RENDER_DEBUG_HULLS = 1
|
||||||
RENDER_DEBUG_SIMULATION_OWNERSHIP = 2,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
RenderArgs(std::shared_ptr<gpu::Context> context = nullptr,
|
RenderArgs(std::shared_ptr<gpu::Context> context = nullptr,
|
||||||
OctreeRenderer* renderer = nullptr,
|
OctreeRenderer* renderer = nullptr,
|
||||||
ViewFrustum* viewFrustum = nullptr,
|
ViewFrustum* viewFrustum = nullptr,
|
||||||
|
|
92
libraries/shared/src/shared/QTryReadLocker.h
Normal file
92
libraries/shared/src/shared/QTryReadLocker.h
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
//
|
||||||
|
// QTryReadLocker.h
|
||||||
|
// shared/src/shared/QTryReadLocker.h
|
||||||
|
//
|
||||||
|
// Created by Clément Brisset on 10/29/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_QTryReadLocker_h
|
||||||
|
#define hifi_QTryReadLocker_h
|
||||||
|
|
||||||
|
#include <QtCore/QReadWriteLock>
|
||||||
|
|
||||||
|
class QTryReadLocker {
|
||||||
|
public:
|
||||||
|
QTryReadLocker(QReadWriteLock* readWriteLock);
|
||||||
|
QTryReadLocker(QReadWriteLock* readWriteLock, int timeout);
|
||||||
|
~QTryReadLocker();
|
||||||
|
|
||||||
|
bool isLocked() const;
|
||||||
|
|
||||||
|
void unlock();
|
||||||
|
bool tryRelock();
|
||||||
|
bool tryRelock(int timeout);
|
||||||
|
|
||||||
|
QReadWriteLock* readWriteLock() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Q_DISABLE_COPY(QTryReadLocker)
|
||||||
|
quintptr _val;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Implementation
|
||||||
|
inline QTryReadLocker::QTryReadLocker(QReadWriteLock* areadWriteLock) :
|
||||||
|
_val(reinterpret_cast<quintptr>(areadWriteLock))
|
||||||
|
{
|
||||||
|
Q_ASSERT_X((_val & quintptr(1u)) == quintptr(0),
|
||||||
|
"QTryReadLocker", "QTryReadLocker pointer is misaligned");
|
||||||
|
tryRelock();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QTryReadLocker::QTryReadLocker(QReadWriteLock* areadWriteLock, int timeout) :
|
||||||
|
_val(reinterpret_cast<quintptr>(areadWriteLock))
|
||||||
|
{
|
||||||
|
Q_ASSERT_X((_val & quintptr(1u)) == quintptr(0),
|
||||||
|
"QTryReadLocker", "QTryReadLocker pointer is misaligned");
|
||||||
|
tryRelock(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QTryReadLocker::~QTryReadLocker() {
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool QTryReadLocker::isLocked() const {
|
||||||
|
return (_val & quintptr(1u)) == quintptr(1u);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void QTryReadLocker::unlock() {
|
||||||
|
if (_val && isLocked()) {
|
||||||
|
_val &= ~quintptr(1u);
|
||||||
|
readWriteLock()->unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool QTryReadLocker::tryRelock() {
|
||||||
|
if (_val && !isLocked()) {
|
||||||
|
if (readWriteLock()->tryLockForRead()) {
|
||||||
|
_val |= quintptr(1u);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool QTryReadLocker::tryRelock(int timeout) {
|
||||||
|
if (_val && !isLocked()) {
|
||||||
|
if (readWriteLock()->tryLockForRead(timeout)) {
|
||||||
|
_val |= quintptr(1u);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QReadWriteLock* QTryReadLocker::readWriteLock() const {
|
||||||
|
return reinterpret_cast<QReadWriteLock*>(_val & ~quintptr(1u));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // hifi_QTryReadLocker_h
|
92
libraries/shared/src/shared/QTryWriteLocker.h
Normal file
92
libraries/shared/src/shared/QTryWriteLocker.h
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
//
|
||||||
|
// QTryWriteLocker.h
|
||||||
|
// shared/src/shared/QTryWriteLocker.h
|
||||||
|
//
|
||||||
|
// Created by Clément Brisset on 10/29/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_QTryWriteLocker_h
|
||||||
|
#define hifi_QTryWriteLocker_h
|
||||||
|
|
||||||
|
#include <QtCore/QReadWriteLock>
|
||||||
|
|
||||||
|
class QTryWriteLocker {
|
||||||
|
public:
|
||||||
|
QTryWriteLocker(QReadWriteLock* readWriteLock);
|
||||||
|
QTryWriteLocker(QReadWriteLock* readWriteLock, int timeout);
|
||||||
|
~QTryWriteLocker();
|
||||||
|
|
||||||
|
bool isLocked() const;
|
||||||
|
|
||||||
|
void unlock();
|
||||||
|
bool tryRelock();
|
||||||
|
bool tryRelock(int timeout);
|
||||||
|
|
||||||
|
QReadWriteLock* readWriteLock() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Q_DISABLE_COPY(QTryWriteLocker)
|
||||||
|
quintptr _val;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Implementation
|
||||||
|
inline QTryWriteLocker::QTryWriteLocker(QReadWriteLock* readWriteLock) :
|
||||||
|
_val(reinterpret_cast<quintptr>(readWriteLock))
|
||||||
|
{
|
||||||
|
Q_ASSERT_X((_val & quintptr(1u)) == quintptr(0),
|
||||||
|
"QTryWriteLocker", "QTryWriteLocker pointer is misaligned");
|
||||||
|
tryRelock();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QTryWriteLocker::QTryWriteLocker(QReadWriteLock* readWriteLock, int timeout) :
|
||||||
|
_val(reinterpret_cast<quintptr>(readWriteLock))
|
||||||
|
{
|
||||||
|
Q_ASSERT_X((_val & quintptr(1u)) == quintptr(0),
|
||||||
|
"QTryWriteLocker", "QTryWriteLocker pointer is misaligned");
|
||||||
|
tryRelock(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QTryWriteLocker::~QTryWriteLocker() {
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool QTryWriteLocker::isLocked() const {
|
||||||
|
return (_val & quintptr(1u)) == quintptr(1u);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void QTryWriteLocker::unlock() {
|
||||||
|
if (_val && isLocked()) {
|
||||||
|
_val &= ~quintptr(1u);
|
||||||
|
readWriteLock()->unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool QTryWriteLocker::tryRelock() {
|
||||||
|
if (_val && !isLocked()) {
|
||||||
|
if (readWriteLock()->tryLockForWrite()) {
|
||||||
|
_val |= quintptr(1u);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool QTryWriteLocker::tryRelock(int timeout) {
|
||||||
|
if (_val && !isLocked()) {
|
||||||
|
if (readWriteLock()->tryLockForWrite(timeout)) {
|
||||||
|
_val |= quintptr(1u);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QReadWriteLock* QTryWriteLocker::readWriteLock() const {
|
||||||
|
return reinterpret_cast<QReadWriteLock*>(_val & ~quintptr(1u));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // hifi_QTryWriteLocker_h
|
|
@ -9,54 +9,118 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#ifndef hifi_ReadWriteLockable_h
|
#ifndef hifi_ReadWriteLockable_h
|
||||||
#define hifi_ReadWriteLockable_h
|
#define hifi_ReadWriteLockable_h
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <QtCore/QReadWriteLock>
|
#include <QtCore/QReadWriteLock>
|
||||||
|
|
||||||
|
#include "QTryReadLocker.h"
|
||||||
|
#include "QTryWriteLocker.h"
|
||||||
|
|
||||||
class ReadWriteLockable {
|
class ReadWriteLockable {
|
||||||
public:
|
public:
|
||||||
|
// Write locks
|
||||||
template <typename F>
|
template <typename F>
|
||||||
bool withWriteLock(F f, bool require = true) const {
|
void withWriteLock(F&& f) const;
|
||||||
if (!require) {
|
|
||||||
bool result = _lock.tryLockForWrite();
|
template <typename F>
|
||||||
if (result) {
|
bool withWriteLock(F&& f, bool require) const;
|
||||||
f();
|
|
||||||
_lock.unlock();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
QWriteLocker locker(&_lock);
|
|
||||||
f();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
bool withTryWriteLock(F f) const {
|
bool withTryWriteLock(F&& f) const;
|
||||||
return withWriteLock(f, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
bool withReadLock(F f, bool require = true) const {
|
bool withTryWriteLock(F&& f, int timeout) const;
|
||||||
if (!require) {
|
|
||||||
bool result = _lock.tryLockForRead();
|
// Read locks
|
||||||
if (result) {
|
|
||||||
f();
|
|
||||||
_lock.unlock();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
QReadLocker locker(&_lock);
|
|
||||||
f();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename F>
|
template <typename F>
|
||||||
bool withTryReadLock(F f) const {
|
void withReadLock(F&& f) const;
|
||||||
return withReadLock(f, false);
|
|
||||||
}
|
template <typename F>
|
||||||
|
bool withReadLock(F&& f, bool require) const;
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
bool withTryReadLock(F&& f) const;
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
bool withTryReadLock(F&& f, int timeout) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable QReadWriteLock _lock{ QReadWriteLock::Recursive };
|
mutable QReadWriteLock _lock { QReadWriteLock::Recursive };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ReadWriteLockable
|
||||||
|
template <typename F>
|
||||||
|
inline void ReadWriteLockable::withWriteLock(F&& f) const {
|
||||||
|
QWriteLocker locker(&_lock);
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
inline bool ReadWriteLockable::withWriteLock(F&& f, bool require) const {
|
||||||
|
if (require) {
|
||||||
|
withWriteLock(std::forward<F>(f));
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return withTryReadLock(std::forward<F>(f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
inline bool ReadWriteLockable::withTryWriteLock(F&& f) const {
|
||||||
|
QTryWriteLocker locker(&_lock);
|
||||||
|
if (locker.isLocked()) {
|
||||||
|
f();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
inline bool ReadWriteLockable::withTryWriteLock(F&& f, int timeout) const {
|
||||||
|
QTryWriteLocker locker(&_lock, timeout);
|
||||||
|
if (locker.isLocked()) {
|
||||||
|
f();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
inline void ReadWriteLockable::withReadLock(F&& f) const {
|
||||||
|
QReadLocker locker(&_lock);
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
inline bool ReadWriteLockable::withReadLock(F&& f, bool require) const {
|
||||||
|
if (require) {
|
||||||
|
withReadLock(std::forward<F>(f));
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return withTryReadLock(std::forward<F>(f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
inline bool ReadWriteLockable::withTryReadLock(F&& f) const {
|
||||||
|
QTryReadLocker locker(&_lock);
|
||||||
|
if (locker.isLocked()) {
|
||||||
|
f();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
inline bool ReadWriteLockable::withTryReadLock(F&& f, int timeout) const {
|
||||||
|
QTryReadLocker locker(&_lock, timeout);
|
||||||
|
if (locker.isLocked()) {
|
||||||
|
f();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue