mirror of
https://github.com/lubosz/overte.git
synced 2025-04-26 22:35:27 +02:00
Merge remote-tracking branch 'upstream/master' into rotateFilterChange
This commit is contained in:
commit
dd8a00983c
71 changed files with 1549 additions and 720 deletions
assignment-client/src
interface
resources/qml
src
libraries
avatars-renderer/src/avatars-renderer
avatars/src
entities-renderer/src
entities/src
BloomPropertyGroup.cppBloomPropertyGroup.hEntityItemProperties.cppEntityItemProperties.hEntityPropertyFlags.hZoneEntityItem.cppZoneEntityItem.h
graphics/src/graphics
networking/src/udt
physics/src
render-utils/src
BloomEffect.cppBloomEffect.hBloomStage.cppBloomStage.hHazeStage.hRenderDeferredTask.cppUpdateSceneTask.cppZoneRenderer.cpp
render/src/render
script-engine/src
shared/src
scripts
developer/utilities/render
system
|
@ -53,6 +53,7 @@
|
|||
#include <EntityScriptingInterface.h> // TODO: consider moving to scriptengine.h
|
||||
|
||||
#include "entities/AssignmentParentFinder.h"
|
||||
#include "AssignmentDynamicFactory.h"
|
||||
#include "RecordingScriptingInterface.h"
|
||||
#include "AbstractAudioInterface.h"
|
||||
#include "AgentScriptingInterface.h"
|
||||
|
@ -67,6 +68,9 @@ Agent::Agent(ReceivedMessage& message) :
|
|||
{
|
||||
DependencyManager::set<ScriptableAvatar>();
|
||||
|
||||
DependencyManager::registerInheritance<EntityDynamicFactoryInterface, AssignmentDynamicFactory>();
|
||||
DependencyManager::set<AssignmentDynamicFactory>();
|
||||
|
||||
DependencyManager::set<AnimationCache>();
|
||||
DependencyManager::set<AnimationCacheScriptingInterface>();
|
||||
DependencyManager::set<EntityScriptingInterface>(false);
|
||||
|
@ -860,6 +864,8 @@ void Agent::aboutToFinish() {
|
|||
DependencyManager::destroy<recording::ClipCache>();
|
||||
DependencyManager::destroy<ScriptEngine>();
|
||||
|
||||
DependencyManager::destroy<AssignmentDynamicFactory>();
|
||||
|
||||
DependencyManager::destroy<ScriptableAvatar>();
|
||||
|
||||
QMetaObject::invokeMethod(&_avatarAudioTimer, "stop");
|
||||
|
|
|
@ -541,7 +541,8 @@ void AvatarMixer::handleRequestsDomainListDataPacket(QSharedPointer<ReceivedMess
|
|||
// ...For those nodes, reset the lastBroadcastTime to 0
|
||||
// so that the AvatarMixer will send Identity data to us
|
||||
[&](const SharedNodePointer& node) {
|
||||
nodeData->setLastBroadcastTime(node->getUUID(), 0);
|
||||
nodeData->setLastBroadcastTime(node->getUUID(), 0);
|
||||
nodeData->resetSentTraitData(node->getLocalID());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -588,10 +589,10 @@ void AvatarMixer::handleAvatarIdentityRequestPacket(QSharedPointer<ReceivedMessa
|
|||
QUuid avatarID(QUuid::fromRfc4122(message->getMessage()) );
|
||||
if (!avatarID.isNull()) {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
auto node = nodeList->nodeWithUUID(avatarID);
|
||||
if (node) {
|
||||
QMutexLocker lock(&node->getMutex());
|
||||
AvatarMixerClientData* avatarClientData = dynamic_cast<AvatarMixerClientData*>(node->getLinkedData());
|
||||
auto requestedNode = nodeList->nodeWithUUID(avatarID);
|
||||
|
||||
if (requestedNode) {
|
||||
AvatarMixerClientData* avatarClientData = static_cast<AvatarMixerClientData*>(requestedNode->getLinkedData());
|
||||
if (avatarClientData) {
|
||||
const AvatarData& avatarData = avatarClientData->getAvatar();
|
||||
QByteArray serializedAvatar = avatarData.identityByteArray();
|
||||
|
@ -600,6 +601,11 @@ void AvatarMixer::handleAvatarIdentityRequestPacket(QSharedPointer<ReceivedMessa
|
|||
nodeList->sendPacketList(std::move(identityPackets), *senderNode);
|
||||
++_sumIdentityPackets;
|
||||
}
|
||||
|
||||
AvatarMixerClientData* senderData = static_cast<AvatarMixerClientData*>(senderNode->getLinkedData());
|
||||
if (senderData) {
|
||||
senderData->resetSentTraitData(requestedNode->getLocalID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -625,23 +631,24 @@ void AvatarMixer::handleNodeIgnoreRequestPacket(QSharedPointer<ReceivedMessage>
|
|||
while (message->getBytesLeftToRead()) {
|
||||
// parse out the UUID being ignored from the packet
|
||||
QUuid ignoredUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID));
|
||||
|
||||
if (nodeList->nodeWithUUID(ignoredUUID)) {
|
||||
auto ignoredNode = nodeList->nodeWithUUID(ignoredUUID);
|
||||
if (ignoredNode) {
|
||||
if (nodeData) {
|
||||
// Reset the lastBroadcastTime for the ignored avatar to 0
|
||||
// so the AvatarMixer knows it'll have to send identity data about the ignored avatar
|
||||
// to the ignorer if the ignorer unignores.
|
||||
nodeData->setLastBroadcastTime(ignoredUUID, 0);
|
||||
nodeData->resetSentTraitData(ignoredNode->getLocalID());
|
||||
}
|
||||
|
||||
|
||||
// Reset the lastBroadcastTime for the ignorer (FROM THE PERSPECTIVE OF THE IGNORED) to 0
|
||||
// so the AvatarMixer knows it'll have to send identity data about the ignorer
|
||||
// to the ignored if the ignorer unignores.
|
||||
auto ignoredNode = nodeList->nodeWithUUID(ignoredUUID);
|
||||
AvatarMixerClientData* ignoredNodeData = reinterpret_cast<AvatarMixerClientData*>(ignoredNode->getLinkedData());
|
||||
if (ignoredNodeData) {
|
||||
ignoredNodeData->setLastBroadcastTime(senderNode->getUUID(), 0);
|
||||
ignoredNodeData->resetSentTraitData(senderNode->getLocalID());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -228,6 +228,9 @@ void AvatarMixerClientData::ignoreOther(SharedNodePointer self, SharedNodePointe
|
|||
killPacket->writePrimitive(KillAvatarReason::YourAvatarEnteredTheirBubble);
|
||||
}
|
||||
setLastBroadcastTime(other->getUUID(), 0);
|
||||
|
||||
resetSentTraitData(other->getLocalID());
|
||||
|
||||
DependencyManager::get<NodeList>()->sendPacket(std::move(killPacket), *self);
|
||||
}
|
||||
}
|
||||
|
@ -238,6 +241,11 @@ void AvatarMixerClientData::removeFromRadiusIgnoringSet(SharedNodePointer self,
|
|||
}
|
||||
}
|
||||
|
||||
void AvatarMixerClientData::resetSentTraitData(Node::LocalID nodeLocalID) {
|
||||
_lastSentTraitsTimestamps[nodeLocalID] = TraitsCheckTimestamp();
|
||||
_sentTraitVersions[nodeLocalID].reset();
|
||||
}
|
||||
|
||||
void AvatarMixerClientData::readViewFrustumPacket(const QByteArray& message) {
|
||||
_currentViewFrustums.clear();
|
||||
|
||||
|
|
|
@ -135,6 +135,8 @@ public:
|
|||
|
||||
AvatarTraits::TraitVersions& getLastSentTraitVersions(Node::LocalID otherAvatar) { return _sentTraitVersions[otherAvatar]; }
|
||||
|
||||
void resetSentTraitData(Node::LocalID nodeID);
|
||||
|
||||
private:
|
||||
struct PacketQueue : public std::queue<QSharedPointer<ReceivedMessage>> {
|
||||
QWeakPointer<Node> node;
|
||||
|
|
|
@ -164,7 +164,7 @@ bool EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O
|
|||
// Send EntityQueryInitialResultsComplete reliable packet ...
|
||||
auto initialCompletion = NLPacket::create(PacketType::EntityQueryInitialResultsComplete,
|
||||
sizeof(OCTREE_PACKET_SEQUENCE), true);
|
||||
initialCompletion->writePrimitive(OCTREE_PACKET_SEQUENCE(nodeData->getSequenceNumber() - 1U));
|
||||
initialCompletion->writePrimitive(OCTREE_PACKET_SEQUENCE(nodeData->getSequenceNumber()));
|
||||
DependencyManager::get<NodeList>()->sendPacket(std::move(initialCompletion), *node);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <plugins/CodecPlugin.h>
|
||||
#include <plugins/PluginManager.h>
|
||||
#include <ResourceManager.h>
|
||||
#include <ResourceScriptingInterface.h>
|
||||
#include <ScriptCache.h>
|
||||
#include <ScriptEngines.h>
|
||||
#include <SoundCacheScriptingInterface.h>
|
||||
|
@ -32,6 +33,7 @@
|
|||
|
||||
#include <EntityScriptClient.h> // for EntityScriptServerServices
|
||||
|
||||
#include "../AssignmentDynamicFactory.h"
|
||||
#include "EntityScriptServerLogging.h"
|
||||
#include "../entities/AssignmentParentFinder.h"
|
||||
|
||||
|
@ -55,7 +57,11 @@ int EntityScriptServer::_entitiesScriptEngineCount = 0;
|
|||
EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssignment(message) {
|
||||
qInstallMessageHandler(messageHandler);
|
||||
|
||||
DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
|
||||
DependencyManager::registerInheritance<EntityDynamicFactoryInterface, AssignmentDynamicFactory>();
|
||||
DependencyManager::set<AssignmentDynamicFactory>();
|
||||
|
||||
DependencyManager::set<EntityScriptingInterface>(false)->setPacketSender(&_entityEditSender);
|
||||
DependencyManager::set<ResourceScriptingInterface>();
|
||||
|
||||
DependencyManager::set<ResourceManager>();
|
||||
DependencyManager::set<PluginManager>();
|
||||
|
@ -455,8 +461,11 @@ void EntityScriptServer::resetEntitiesScriptEngine() {
|
|||
auto newEngineSP = qSharedPointerCast<EntitiesScriptEngineProvider>(newEngine);
|
||||
DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(newEngineSP);
|
||||
|
||||
disconnect(_entitiesScriptEngine.data(), &ScriptEngine::entityScriptDetailsUpdated,
|
||||
this, &EntityScriptServer::updateEntityPPS);
|
||||
if (_entitiesScriptEngine) {
|
||||
disconnect(_entitiesScriptEngine.data(), &ScriptEngine::entityScriptDetailsUpdated,
|
||||
this, &EntityScriptServer::updateEntityPPS);
|
||||
}
|
||||
|
||||
_entitiesScriptEngine.swap(newEngine);
|
||||
connect(_entitiesScriptEngine.data(), &ScriptEngine::entityScriptDetailsUpdated,
|
||||
this, &EntityScriptServer::updateEntityPPS);
|
||||
|
@ -487,6 +496,21 @@ void EntityScriptServer::shutdownScriptEngine() {
|
|||
_shuttingDown = true;
|
||||
|
||||
clear(); // always clear() on shutdown
|
||||
|
||||
auto scriptEngines = DependencyManager::get<ScriptEngines>();
|
||||
scriptEngines->shutdownScripting();
|
||||
|
||||
_entitiesScriptEngine.clear();
|
||||
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
// our entity tree is going to go away so tell that to the EntityScriptingInterface
|
||||
entityScriptingInterface->setEntityTree(nullptr);
|
||||
|
||||
// Should always be true as they are singletons.
|
||||
if (entityScriptingInterface->getPacketSender() == &_entityEditSender) {
|
||||
// The packet sender is about to go away.
|
||||
entityScriptingInterface->setPacketSender(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void EntityScriptServer::addingEntity(const EntityItemID& entityID) {
|
||||
|
@ -559,24 +583,19 @@ void EntityScriptServer::handleOctreePacket(QSharedPointer<ReceivedMessage> mess
|
|||
void EntityScriptServer::aboutToFinish() {
|
||||
shutdownScriptEngine();
|
||||
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
// our entity tree is going to go away so tell that to the EntityScriptingInterface
|
||||
entityScriptingInterface->setEntityTree(nullptr);
|
||||
|
||||
// Should always be true as they are singletons.
|
||||
if (entityScriptingInterface->getPacketSender() == &_entityEditSender) {
|
||||
// The packet sender is about to go away.
|
||||
entityScriptingInterface->setPacketSender(nullptr);
|
||||
}
|
||||
|
||||
DependencyManager::destroy<AssignmentDynamicFactory>();
|
||||
DependencyManager::destroy<AssignmentParentFinder>();
|
||||
|
||||
DependencyManager::get<ResourceManager>()->cleanup();
|
||||
|
||||
DependencyManager::destroy<PluginManager>();
|
||||
|
||||
DependencyManager::destroy<ResourceScriptingInterface>();
|
||||
DependencyManager::destroy<EntityScriptingInterface>();
|
||||
|
||||
// cleanup the AudioInjectorManager (and any still running injectors)
|
||||
DependencyManager::destroy<AudioInjectorManager>();
|
||||
|
||||
DependencyManager::destroy<ScriptEngines>();
|
||||
DependencyManager::destroy<EntityScriptServerServices>();
|
||||
|
||||
|
|
|
@ -120,6 +120,7 @@ Item {
|
|||
|
||||
TextField {
|
||||
id: usernameField
|
||||
text: Settings.getValue("wallet/savedUsername", "");
|
||||
width: parent.width
|
||||
focus: true
|
||||
label: "Username or Email"
|
||||
|
|
|
@ -60,6 +60,9 @@ Item {
|
|||
StatText {
|
||||
text: "Game Rate: " + root.gameLoopRate
|
||||
}
|
||||
StatText {
|
||||
text: "Physics Object Count: " + root.physicsObjectCount
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded
|
||||
text: root.gameUpdateStats
|
||||
|
|
|
@ -63,47 +63,6 @@ Item {
|
|||
question: "How can I get HFC?";
|
||||
answer: "High Fidelity commerce is in open beta right now. Want more HFC? \
|
||||
Get it by going to <br><br><b><font color='#0093C5'><a href='#bank'>BankOfHighFidelity.</a></font></b> and meeting with the banker!";
|
||||
}
|
||||
ListElement {
|
||||
isExpanded: false;
|
||||
question: "What are private keys and where are they stored?";
|
||||
answer:
|
||||
"A private key is a secret piece of text that is used to prove ownership, unlock confidential information, and sign transactions. \
|
||||
In High Fidelity, your private key is used to securely access the contents of your Wallet and Purchases. \
|
||||
After wallet setup, a hifikey file is stored on your computer in High Fidelity Interface's AppData directory. \
|
||||
Your hifikey file contains your private key and is protected by your wallet passphrase. \
|
||||
<br><br>It is very important to back up your hifikey file! \
|
||||
<b><font color='#0093C5'><a href='#privateKeyPath'>Tap here to open the folder where your HifiKeys are stored on your main display.</a></font></b>"
|
||||
}
|
||||
ListElement {
|
||||
isExpanded: false;
|
||||
question: "How do I back up my private keys?";
|
||||
answer: "You can back up your hifikey file (which contains your private key and is encrypted using your wallet passphrase) by copying it to a USB flash drive, or to a service like Dropbox or Google Drive. \
|
||||
Restore your hifikey file by replacing the file in Interface's AppData directory with your backup copy. \
|
||||
Others with access to your back up should not be able to spend your HFC without your passphrase. \
|
||||
<b><font color='#0093C5'><a href='#privateKeyPath'>Tap here to open the folder where your HifiKeys are stored on your main display.</a></font></b>";
|
||||
}
|
||||
ListElement {
|
||||
isExpanded: false;
|
||||
question: "What happens if I lose my private keys?";
|
||||
answer: "We cannot stress enough that you should keep a backup! For security reasons, High Fidelity does not keep a copy, and cannot restore it for you. \
|
||||
If you lose your private key, you will no longer have access to the contents of your Wallet or My Purchases. \
|
||||
Here are some things to try:<ul>\
|
||||
<li>If you have backed up your hifikey file before, search your backup location</li>\
|
||||
<li>Search your AppData directory in the last machine you used to set up the Wallet</li>\
|
||||
<li>If you are a developer and have installed multiple builds of High Fidelity, your hifikey file might be in another folder</li>\
|
||||
</ul><br><br>As a last resort, you can set up your Wallet again and generate a new hifikey file. \
|
||||
Unfortunately, this means you will start with 0 HFC and your purchased items will not be transferred over.";
|
||||
}
|
||||
ListElement {
|
||||
isExpanded: false;
|
||||
question: "What if I forget my wallet passphrase?";
|
||||
answer: "Your wallet passphrase is used to encrypt your private keys. Please write it down and store it securely! \
|
||||
<br><br>If you forget your passphrase, you will no longer be able to decrypt the hifikey file that the passphrase protects. \
|
||||
You will also no longer have access to the contents of your Wallet or My Purchases. \
|
||||
For security reasons, High Fidelity does not keep a copy of your passphrase, and can't restore it for you. \
|
||||
<br><br>If you still cannot remember your wallet passphrase, you can set up your Wallet again and generate a new hifikey file. \
|
||||
Unfortunately, this means you will start with 0 HFC and your purchased items will not be transferred over.";
|
||||
}
|
||||
ListElement {
|
||||
isExpanded: false;
|
||||
|
@ -114,11 +73,9 @@ In your Wallet's Send Money tab, choose from your list of connections, or choose
|
|||
ListElement {
|
||||
isExpanded: false;
|
||||
question: "What is a Security Pic?"
|
||||
answer: "Your Security Pic is an encrypted image that you select during Wallet Setup. \
|
||||
It acts as an extra layer of Wallet security. \
|
||||
When you see your Security Pic, you know that your actions and data are securely making use of your private keys.\
|
||||
<br><br>Don't enter your passphrase anywhere that doesn't display your Security Pic! \
|
||||
If you don't see your Security Pic on a page that requests your Wallet passphrase, someone untrustworthy may be trying to access your Wallet.";
|
||||
answer: "Your Security Pic acts as an extra layer of Wallet security. \
|
||||
When you see your Security Pic, you know that your actions and data are securely making use of your account. \
|
||||
<br><br><b><font color='#0093C5'><a href='#securitypic'>Tap here to change your Security Pic.</a></font></b>";
|
||||
}
|
||||
ListElement {
|
||||
isExpanded: false;
|
||||
|
@ -260,6 +217,8 @@ At the moment, there is currently no way to convert HFC to other currencies. Sta
|
|||
}
|
||||
} else if (link === "#support") {
|
||||
Qt.openUrlExternally("mailto:support@highfidelity.com");
|
||||
} else if (link === "#securitypic") {
|
||||
sendSignalToWallet({method: 'walletSecurity_changeSecurityImage'});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,76 +88,9 @@ Item {
|
|||
color: hifi.colors.faintGray;
|
||||
}
|
||||
|
||||
Item {
|
||||
id: changePassphraseContainer;
|
||||
anchors.top: securityTextSeparator.bottom;
|
||||
anchors.topMargin: 8;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 40;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 55;
|
||||
height: 75;
|
||||
|
||||
HiFiGlyphs {
|
||||
id: changePassphraseImage;
|
||||
text: hifi.glyphs.passphrase;
|
||||
// Size
|
||||
size: 80;
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.left: parent.left;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
text: "Passphrase";
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.left: changePassphraseImage.right;
|
||||
anchors.leftMargin: 30;
|
||||
width: 50;
|
||||
// Text size
|
||||
size: 18;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
}
|
||||
|
||||
// "Change Passphrase" button
|
||||
HifiControlsUit.Button {
|
||||
id: changePassphraseButton;
|
||||
color: hifi.buttons.blue;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.right: parent.right;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
width: 140;
|
||||
height: 40;
|
||||
text: "Change";
|
||||
onClicked: {
|
||||
sendSignalToWallet({method: 'walletSecurity_changePassphrase'});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: changePassphraseSeparator;
|
||||
// Size
|
||||
width: parent.width;
|
||||
height: 1;
|
||||
// Anchors
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
anchors.top: changePassphraseContainer.bottom;
|
||||
anchors.topMargin: 8;
|
||||
// Style
|
||||
color: hifi.colors.faintGray;
|
||||
}
|
||||
|
||||
Item {
|
||||
id: changeSecurityImageContainer;
|
||||
anchors.top: changePassphraseSeparator.bottom;
|
||||
anchors.top: securityTextSeparator.bottom;
|
||||
anchors.topMargin: 8;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 40;
|
||||
|
@ -208,139 +141,77 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: privateKeysSeparator;
|
||||
// Size
|
||||
width: parent.width;
|
||||
height: 1;
|
||||
// Anchors
|
||||
anchors.left: parent.left;
|
||||
anchors.right: parent.right;
|
||||
Item {
|
||||
id: autoLogoutContainer;
|
||||
anchors.top: changeSecurityImageContainer.bottom;
|
||||
anchors.topMargin: 8;
|
||||
// Style
|
||||
color: hifi.colors.faintGray;
|
||||
}
|
||||
|
||||
Item {
|
||||
id: yourPrivateKeysContainer;
|
||||
anchors.top: privateKeysSeparator.bottom;
|
||||
anchors.left: parent.left;
|
||||
anchors.leftMargin: 40;
|
||||
anchors.right: parent.right;
|
||||
anchors.rightMargin: 55;
|
||||
anchors.bottom: parent.bottom;
|
||||
height: 75;
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
Commerce.getKeyFilePathIfExists();
|
||||
}
|
||||
HiFiGlyphs {
|
||||
id: autoLogoutImage;
|
||||
text: hifi.glyphs.walletKey;
|
||||
// Size
|
||||
size: 80;
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: 20;
|
||||
anchors.left: parent.left;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
}
|
||||
|
||||
HiFiGlyphs {
|
||||
id: yourPrivateKeysImage;
|
||||
text: hifi.glyphs.walletKey;
|
||||
// Size
|
||||
size: 80;
|
||||
HifiControlsUit.CheckBox {
|
||||
id: autoLogoutCheckbox;
|
||||
checked: Settings.getValue("wallet/autoLogout", false);
|
||||
text: "Automatically Log Out when Exiting Interface"
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: 20;
|
||||
anchors.left: parent.left;
|
||||
// Style
|
||||
anchors.verticalCenter: autoLogoutImage.verticalCenter;
|
||||
anchors.left: autoLogoutImage.right;
|
||||
anchors.leftMargin: 20;
|
||||
anchors.right: autoLogoutHelp.left;
|
||||
anchors.rightMargin: 12;
|
||||
boxSize: 28;
|
||||
labelFontSize: 18;
|
||||
color: hifi.colors.white;
|
||||
onCheckedChanged: {
|
||||
Settings.setValue("wallet/autoLogout", checked);
|
||||
if (checked) {
|
||||
Settings.setValue("wallet/savedUsername", Account.username);
|
||||
} else {
|
||||
Settings.setValue("wallet/savedUsername", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RalewaySemiBold {
|
||||
id: yourPrivateKeysText;
|
||||
text: "Private Keys";
|
||||
size: 18;
|
||||
id: autoLogoutHelp;
|
||||
text: '[?]';
|
||||
// Anchors
|
||||
anchors.top: parent.top;
|
||||
anchors.topMargin: 32;
|
||||
anchors.left: yourPrivateKeysImage.right;
|
||||
anchors.leftMargin: 30;
|
||||
anchors.verticalCenter: autoLogoutImage.verticalCenter;
|
||||
anchors.right: parent.right;
|
||||
width: 30;
|
||||
height: 30;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
}
|
||||
|
||||
// Text below "private keys"
|
||||
RalewayRegular {
|
||||
id: explanitoryText;
|
||||
text: "Your money and purchases are secured with private keys that only you have access to.";
|
||||
// Text size
|
||||
size: 18;
|
||||
// Anchors
|
||||
anchors.top: yourPrivateKeysText.bottom;
|
||||
anchors.topMargin: 10;
|
||||
anchors.left: yourPrivateKeysText.left;
|
||||
anchors.right: yourPrivateKeysText.right;
|
||||
height: paintedHeight;
|
||||
// Style
|
||||
color: hifi.colors.white;
|
||||
wrapMode: Text.WordWrap;
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignLeft;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
}
|
||||
color: hifi.colors.blueHighlight;
|
||||
|
||||
Rectangle {
|
||||
id: removeHmdContainer;
|
||||
z: 998;
|
||||
visible: false;
|
||||
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: 0.2;
|
||||
color: hifi.colors.baseGrayHighlight;
|
||||
}
|
||||
GradientStop {
|
||||
position: 1.0;
|
||||
color: hifi.colors.baseGrayShadow;
|
||||
}
|
||||
}
|
||||
anchors.fill: backupInstructionsButton;
|
||||
radius: 5;
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
propagateComposedEvents: false;
|
||||
hoverEnabled: true;
|
||||
}
|
||||
|
||||
RalewayBold {
|
||||
anchors.fill: parent;
|
||||
text: "INSTRUCTIONS OPEN ON DESKTOP";
|
||||
size: 15;
|
||||
color: hifi.colors.white;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
horizontalAlignment: Text.AlignHCenter;
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: removeHmdContainerTimer;
|
||||
interval: 5000;
|
||||
onTriggered: removeHmdContainer.visible = false
|
||||
onEntered: {
|
||||
parent.color = hifi.colors.blueAccent;
|
||||
}
|
||||
onExited: {
|
||||
parent.color = hifi.colors.blueHighlight;
|
||||
}
|
||||
onClicked: {
|
||||
sendSignalToWallet({method: 'walletSecurity_autoLogoutHelp'});
|
||||
}
|
||||
}
|
||||
|
||||
HifiControlsUit.Button {
|
||||
id: backupInstructionsButton;
|
||||
text: "View Backup Instructions";
|
||||
color: hifi.buttons.blue;
|
||||
colorScheme: hifi.colorSchemes.dark;
|
||||
anchors.left: explanitoryText.left;
|
||||
anchors.right: explanitoryText.right;
|
||||
anchors.top: explanitoryText.bottom;
|
||||
anchors.topMargin: 16;
|
||||
height: 40;
|
||||
|
||||
onClicked: {
|
||||
var keyPath = "file:///" + root.keyFilePath.substring(0, root.keyFilePath.lastIndexOf('/'));
|
||||
Qt.openUrlExternally(keyPath + "/backup_instructions.html");
|
||||
Qt.openUrlExternally(keyPath);
|
||||
removeHmdContainer.visible = true;
|
||||
removeHmdContainerTimer.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -382,6 +382,17 @@ Rectangle {
|
|||
} else if (msg.method === 'walletSecurity_changeSecurityImage') {
|
||||
securityImageChange.initModel();
|
||||
root.activeView = "securityImageChange";
|
||||
} else if (msg.method === 'walletSecurity_autoLogoutHelp') {
|
||||
lightboxPopup.titleText = "Automatically Log Out";
|
||||
lightboxPopup.bodyText = "By default, after you log in to High Fidelity, you will stay logged in to your High Fidelity " +
|
||||
"account even after you close and re-open Interface. This means anyone who opens Interface on your computer " +
|
||||
"could make purchases with your Wallet.\n\n" +
|
||||
"If you do not want to stay logged in across Interface sessions, check this box.";
|
||||
lightboxPopup.button1text = "CLOSE";
|
||||
lightboxPopup.button1method = function() {
|
||||
lightboxPopup.visible = false;
|
||||
}
|
||||
lightboxPopup.visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -399,6 +410,9 @@ Rectangle {
|
|||
onSendSignalToWallet: {
|
||||
if (msg.method === 'walletReset' || msg.method === 'passphraseReset') {
|
||||
sendToScript(msg);
|
||||
} else if (msg.method === 'walletSecurity_changeSecurityImage') {
|
||||
securityImageChange.initModel();
|
||||
root.activeView = "securityImageChange";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -803,12 +817,24 @@ Rectangle {
|
|||
}
|
||||
|
||||
function walletResetSetup() {
|
||||
/* Bypass all this and do it automatically
|
||||
root.activeView = "walletSetup";
|
||||
var timestamp = new Date();
|
||||
walletSetup.startingTimestamp = timestamp;
|
||||
walletSetup.setupAttemptID = generateUUID();
|
||||
UserActivityLogger.commerceWalletSetupStarted(timestamp, walletSetup.setupAttemptID, walletSetup.setupFlowVersion, walletSetup.referrer ? walletSetup.referrer : "wallet app",
|
||||
(AddressManager.placename || AddressManager.hostname || '') + (AddressManager.pathname ? AddressManager.pathname.match(/\/[^\/]+/)[0] : ''));
|
||||
*/
|
||||
|
||||
var randomNumber = Math.floor(Math.random() * 34) + 1;
|
||||
var securityImagePath = "images/" + addLeadingZero(randomNumber) + ".jpg";
|
||||
Commerce.getWalletAuthenticatedStatus(); // before writing security image, ensures that salt/account password is set.
|
||||
Commerce.chooseSecurityImage(securityImagePath);
|
||||
Commerce.generateKeyPair();
|
||||
}
|
||||
|
||||
function addLeadingZero(n) {
|
||||
return n < 10 ? '0' + n : '' + n;
|
||||
}
|
||||
|
||||
function followReferrer(msg) {
|
||||
|
|
|
@ -375,6 +375,7 @@ static const int INTERVAL_TO_CHECK_HMD_WORN_STATUS = 500; // milliseconds
|
|||
static const QString DESKTOP_DISPLAY_PLUGIN_NAME = "Desktop";
|
||||
static const QString ACTIVE_DISPLAY_PLUGIN_SETTING_NAME = "activeDisplayPlugin";
|
||||
static const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system";
|
||||
static const QString AUTO_LOGOUT_SETTING_NAME = "wallet/autoLogout";
|
||||
|
||||
const std::vector<std::pair<QString, Application::AcceptURLMethod>> Application::_acceptedExtensions {
|
||||
{ SVO_EXTENSION, &Application::importSVOFromURL },
|
||||
|
@ -1094,6 +1095,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
// Set File Logger Session UUID
|
||||
auto avatarManager = DependencyManager::get<AvatarManager>();
|
||||
auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr;
|
||||
if (avatarManager) {
|
||||
workload::SpacePointer space = getEntities()->getWorkloadSpace();
|
||||
avatarManager->setSpace(space);
|
||||
}
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
||||
_logger->setSessionID(accountManager->getSessionID());
|
||||
|
@ -1730,6 +1735,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
QTimer* settingsTimer = new QTimer();
|
||||
moveToNewNamedThread(settingsTimer, "Settings Thread", [this, settingsTimer]{
|
||||
connect(qApp, &Application::beforeAboutToQuit, [this, settingsTimer]{
|
||||
bool autoLogout = Setting::Handle<bool>(AUTO_LOGOUT_SETTING_NAME, false).get();
|
||||
if (autoLogout) {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
accountManager->logout();
|
||||
}
|
||||
// Disconnect the signal from the save settings
|
||||
QObject::disconnect(settingsTimer, &QTimer::timeout, this, &Application::saveSettings);
|
||||
// Stop the settings timer
|
||||
|
@ -2536,11 +2546,15 @@ void Application::cleanupBeforeQuit() {
|
|||
|
||||
Application::~Application() {
|
||||
// remove avatars from physics engine
|
||||
DependencyManager::get<AvatarManager>()->clearOtherAvatars();
|
||||
VectorOfMotionStates motionStates;
|
||||
DependencyManager::get<AvatarManager>()->getObjectsToRemoveFromPhysics(motionStates);
|
||||
_physicsEngine->removeObjects(motionStates);
|
||||
DependencyManager::get<AvatarManager>()->deleteAllAvatars();
|
||||
auto avatarManager = DependencyManager::get<AvatarManager>();
|
||||
avatarManager->clearOtherAvatars();
|
||||
|
||||
PhysicsEngine::Transaction transaction;
|
||||
avatarManager->buildPhysicsTransaction(transaction);
|
||||
_physicsEngine->processTransaction(transaction);
|
||||
avatarManager->handleProcessedPhysicsTransaction(transaction);
|
||||
|
||||
avatarManager->deleteAllAvatars();
|
||||
|
||||
_physicsEngine->setCharacterController(nullptr);
|
||||
|
||||
|
@ -5702,12 +5716,10 @@ void Application::update(float deltaTime) {
|
|||
|
||||
t1 = std::chrono::high_resolution_clock::now();
|
||||
|
||||
avatarManager->getObjectsToRemoveFromPhysics(motionStates);
|
||||
_physicsEngine->removeObjects(motionStates);
|
||||
avatarManager->getObjectsToAddToPhysics(motionStates);
|
||||
_physicsEngine->addObjects(motionStates);
|
||||
avatarManager->getObjectsToChange(motionStates);
|
||||
_physicsEngine->changeObjects(motionStates);
|
||||
PhysicsEngine::Transaction transaction;
|
||||
avatarManager->buildPhysicsTransaction(transaction);
|
||||
_physicsEngine->processTransaction(transaction);
|
||||
avatarManager->handleProcessedPhysicsTransaction(transaction);
|
||||
|
||||
myAvatar->prepareForPhysicsSimulation();
|
||||
_physicsEngine->forEachDynamic([&](EntityDynamicPointer dynamic) {
|
||||
|
@ -6178,6 +6190,10 @@ bool Application::isHMDMode() const {
|
|||
return getActiveDisplayPlugin()->isHmd();
|
||||
}
|
||||
|
||||
float Application::getNumCollisionObjects() const {
|
||||
return _physicsEngine ? _physicsEngine->getNumCollisionObjects() : 0;
|
||||
}
|
||||
|
||||
float Application::getTargetRenderFrameRate() const { return getActiveDisplayPlugin()->getTargetFrameRate(); }
|
||||
|
||||
QRect Application::getDesirableApplicationGeometry() const {
|
||||
|
|
|
@ -207,6 +207,7 @@ public:
|
|||
|
||||
size_t getRenderFrameCount() const { return _renderFrameCount; }
|
||||
float getRenderLoopRate() const { return _renderLoopCounter.rate(); }
|
||||
float getNumCollisionObjects() const;
|
||||
float getTargetRenderFrameRate() const; // frames/second
|
||||
|
||||
float getFieldOfView() { return _fieldOfView.get(); }
|
||||
|
|
|
@ -44,7 +44,6 @@
|
|||
#include "InterfaceLogging.h"
|
||||
#include "Menu.h"
|
||||
#include "MyAvatar.h"
|
||||
#include "OtherAvatar.h"
|
||||
#include "SceneScriptingInterface.h"
|
||||
|
||||
// 50 times per second - target is 45hz, but this helps account for any small deviations
|
||||
|
@ -81,8 +80,25 @@ AvatarManager::AvatarManager(QObject* parent) :
|
|||
});
|
||||
}
|
||||
|
||||
AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) {
|
||||
AvatarSharedPointer avatar = AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer);
|
||||
|
||||
const auto otherAvatar = std::static_pointer_cast<OtherAvatar>(avatar);
|
||||
if (otherAvatar && _space) {
|
||||
std::unique_lock<std::mutex> lock(_spaceLock);
|
||||
auto spaceIndex = _space->allocateID();
|
||||
otherAvatar->setSpaceIndex(spaceIndex);
|
||||
workload::Sphere sphere(otherAvatar->getWorldPosition(), otherAvatar->getBoundingRadius());
|
||||
workload::Transaction transaction;
|
||||
SpatiallyNestablePointer nestable = std::static_pointer_cast<SpatiallyNestable>(otherAvatar);
|
||||
transaction.reset(spaceIndex, sphere, workload::Owner(nestable));
|
||||
_space->enqueueTransaction(transaction);
|
||||
}
|
||||
return avatar;
|
||||
}
|
||||
|
||||
AvatarManager::~AvatarManager() {
|
||||
assert(_motionStates.empty());
|
||||
assert(_avatarsToChangeInPhysics.empty());
|
||||
}
|
||||
|
||||
void AvatarManager::init() {
|
||||
|
@ -104,6 +120,11 @@ void AvatarManager::init() {
|
|||
}
|
||||
}
|
||||
|
||||
void AvatarManager::setSpace(workload::SpacePointer& space ) {
|
||||
assert(!_space);
|
||||
_space = space;
|
||||
}
|
||||
|
||||
void AvatarManager::updateMyAvatar(float deltaTime) {
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "AvatarManager::updateMyAvatar()");
|
||||
|
@ -192,20 +213,20 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
|||
uint64_t updateExpiry = startTime + UPDATE_BUDGET;
|
||||
int numAvatarsUpdated = 0;
|
||||
int numAVatarsNotUpdated = 0;
|
||||
bool physicsEnabled = qApp->isPhysicsEnabled();
|
||||
|
||||
render::Transaction transaction;
|
||||
render::Transaction renderTransaction;
|
||||
workload::Transaction workloadTransaction;
|
||||
while (!sortedAvatars.empty()) {
|
||||
const SortableAvatar& sortData = sortedAvatars.top();
|
||||
const auto avatar = std::static_pointer_cast<Avatar>(sortData.getAvatar());
|
||||
const auto otherAvatar = std::static_pointer_cast<OtherAvatar>(sortData.getAvatar());
|
||||
const auto avatar = std::static_pointer_cast<OtherAvatar>(sortData.getAvatar());
|
||||
|
||||
// TODO: to help us scale to more avatars it would be nice to not have to poll orb state here
|
||||
// if the geometry is loaded then turn off the orb
|
||||
if (avatar->getSkeletonModel()->isLoaded()) {
|
||||
// remove the orb if it is there
|
||||
otherAvatar->removeOrb();
|
||||
avatar->removeOrb();
|
||||
} else {
|
||||
otherAvatar->updateOrbPosition();
|
||||
avatar->updateOrbPosition();
|
||||
}
|
||||
|
||||
bool ignoring = DependencyManager::get<NodeList>()->isPersonalMutingNode(avatar->getID());
|
||||
|
@ -218,18 +239,6 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
|||
if (_shouldRender) {
|
||||
avatar->ensureInScene(avatar, qApp->getMain3DScene());
|
||||
}
|
||||
if (physicsEnabled && !avatar->isInPhysicsSimulation()) {
|
||||
ShapeInfo shapeInfo;
|
||||
avatar->computeShapeInfo(shapeInfo);
|
||||
btCollisionShape* shape = const_cast<btCollisionShape*>(ObjectMotionState::getShapeManager()->getShape(shapeInfo));
|
||||
if (shape) {
|
||||
AvatarMotionState* motionState = new AvatarMotionState(avatar, shape);
|
||||
motionState->setMass(avatar->computeMass());
|
||||
avatar->setPhysicsCallback([=] (uint32_t flags) { motionState->addDirtyFlags(flags); });
|
||||
_motionStates.insert(avatar.get(), motionState);
|
||||
_motionStatesToAddToPhysics.insert(motionState);
|
||||
}
|
||||
}
|
||||
avatar->animateScaleChanges(deltaTime);
|
||||
|
||||
const float OUT_OF_VIEW_THRESHOLD = 0.5f * AvatarData::OUT_OF_VIEW_PENALTY;
|
||||
|
@ -241,15 +250,16 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
|||
numAvatarsUpdated++;
|
||||
}
|
||||
avatar->simulate(deltaTime, inView);
|
||||
avatar->updateRenderItem(transaction);
|
||||
avatar->updateRenderItem(renderTransaction);
|
||||
avatar->updateSpaceProxy(workloadTransaction);
|
||||
avatar->setLastRenderUpdateTime(startTime);
|
||||
} else {
|
||||
// we've spent our full time budget --> bail on the rest of the avatar updates
|
||||
// --> more avatars may freeze until their priority trickles up
|
||||
// --> some scale or fade animations may glitch
|
||||
// --> some scale animations may glitch
|
||||
// --> some avatar velocity measurements may be a little off
|
||||
|
||||
// no time simulate, but we take the time to count how many were tragically missed
|
||||
// no time to simulate, but we take the time to count how many were tragically missed
|
||||
bool inView = sortData.getPriority() > OUT_OF_VIEW_THRESHOLD;
|
||||
if (!inView) {
|
||||
break;
|
||||
|
@ -273,8 +283,16 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
|||
}
|
||||
|
||||
if (_shouldRender) {
|
||||
qApp->getMain3DScene()->enqueueTransaction(transaction);
|
||||
qApp->getMain3DScene()->enqueueTransaction(renderTransaction);
|
||||
}
|
||||
|
||||
if (!_spaceProxiesToDelete.empty() && _space) {
|
||||
std::unique_lock<std::mutex> lock(_spaceLock);
|
||||
workloadTransaction.remove(_spaceProxiesToDelete);
|
||||
_spaceProxiesToDelete.clear();
|
||||
}
|
||||
_space->enqueueTransaction(workloadTransaction);
|
||||
|
||||
_numAvatarsUpdated = numAvatarsUpdated;
|
||||
_numAvatarsNotUpdated = numAVatarsNotUpdated;
|
||||
|
||||
|
@ -362,19 +380,64 @@ AvatarSharedPointer AvatarManager::newSharedAvatar() {
|
|||
return AvatarSharedPointer(new OtherAvatar(qApp->thread()), [](OtherAvatar* ptr) { ptr->deleteLater(); });
|
||||
}
|
||||
|
||||
void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) {
|
||||
AvatarHashMap::handleRemovedAvatar(removedAvatar, removalReason);
|
||||
void AvatarManager::queuePhysicsChange(const OtherAvatarPointer& avatar) {
|
||||
_avatarsToChangeInPhysics.insert(avatar);
|
||||
}
|
||||
|
||||
// remove from physics
|
||||
auto avatar = std::static_pointer_cast<Avatar>(removedAvatar);
|
||||
avatar->setPhysicsCallback(nullptr);
|
||||
AvatarMotionStateMap::iterator itr = _motionStates.find(avatar.get());
|
||||
if (itr != _motionStates.end()) {
|
||||
AvatarMotionState* motionState = *itr;
|
||||
_motionStatesToAddToPhysics.remove(motionState);
|
||||
_motionStatesToRemoveFromPhysics.push_back(motionState);
|
||||
_motionStates.erase(itr);
|
||||
void AvatarManager::buildPhysicsTransaction(PhysicsEngine::Transaction& transaction) {
|
||||
SetOfOtherAvatars failedShapeBuilds;
|
||||
for (auto avatar : _avatarsToChangeInPhysics) {
|
||||
bool isInPhysics = avatar->isInPhysicsSimulation();
|
||||
if (isInPhysics != avatar->shouldBeInPhysicsSimulation()) {
|
||||
if (isInPhysics) {
|
||||
transaction.objectsToRemove.push_back(avatar->_motionState);
|
||||
avatar->_motionState = nullptr;
|
||||
} else {
|
||||
ShapeInfo shapeInfo;
|
||||
avatar->computeShapeInfo(shapeInfo);
|
||||
btCollisionShape* shape = const_cast<btCollisionShape*>(ObjectMotionState::getShapeManager()->getShape(shapeInfo));
|
||||
if (shape) {
|
||||
AvatarMotionState* motionState = new AvatarMotionState(avatar, shape);
|
||||
motionState->setMass(avatar->computeMass());
|
||||
avatar->_motionState = motionState;
|
||||
transaction.objectsToAdd.push_back(motionState);
|
||||
} else {
|
||||
failedShapeBuilds.insert(avatar);
|
||||
}
|
||||
}
|
||||
} else if (isInPhysics) {
|
||||
transaction.objectsToChange.push_back(avatar->_motionState);
|
||||
}
|
||||
}
|
||||
_avatarsToChangeInPhysics.swap(failedShapeBuilds);
|
||||
}
|
||||
|
||||
void AvatarManager::handleProcessedPhysicsTransaction(PhysicsEngine::Transaction& transaction) {
|
||||
// things on objectsToChange correspond to failed changes
|
||||
// so we push them back onto _avatarsToChangeInPhysics
|
||||
for (auto object : transaction.objectsToChange) {
|
||||
AvatarMotionState* motionState = static_cast<AvatarMotionState*>(object);
|
||||
assert(motionState);
|
||||
assert(motionState->_avatar);
|
||||
_avatarsToChangeInPhysics.insert(motionState->_avatar);
|
||||
}
|
||||
// things on objectsToRemove are ready for delete
|
||||
for (auto object : transaction.objectsToRemove) {
|
||||
delete object;
|
||||
}
|
||||
transaction.clear();
|
||||
}
|
||||
|
||||
void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) {
|
||||
auto avatar = std::static_pointer_cast<OtherAvatar>(removedAvatar);
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_spaceLock);
|
||||
_spaceProxiesToDelete.push_back(avatar->getSpaceIndex());
|
||||
}
|
||||
AvatarHashMap::handleRemovedAvatar(avatar, removalReason);
|
||||
|
||||
avatar->die();
|
||||
queuePhysicsChange(avatar);
|
||||
|
||||
if (removalReason == KillAvatarReason::TheirAvatarEnteredYourBubble) {
|
||||
emit DependencyManager::get<UsersScriptingInterface>()->enteredIgnoreRadius();
|
||||
|
@ -410,48 +473,15 @@ void AvatarManager::clearOtherAvatars() {
|
|||
}
|
||||
|
||||
void AvatarManager::deleteAllAvatars() {
|
||||
assert(_motionStates.empty()); // should have called clearOtherAvatars() before getting here
|
||||
deleteMotionStates();
|
||||
assert(_avatarsToChangeInPhysics.empty());
|
||||
|
||||
QReadLocker locker(&_hashLock);
|
||||
AvatarHash::iterator avatarIterator = _avatarHash.begin();
|
||||
while (avatarIterator != _avatarHash.end()) {
|
||||
auto avatar = std::static_pointer_cast<Avatar>(avatarIterator.value());
|
||||
auto avatar = std::static_pointer_cast<OtherAvatar>(avatarIterator.value());
|
||||
avatarIterator = _avatarHash.erase(avatarIterator);
|
||||
avatar->die();
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarManager::deleteMotionStates() {
|
||||
// delete motionstates that were removed from physics last frame
|
||||
for (auto state : _motionStatesToDelete) {
|
||||
delete state;
|
||||
}
|
||||
_motionStatesToDelete.clear();
|
||||
}
|
||||
|
||||
void AvatarManager::getObjectsToRemoveFromPhysics(VectorOfMotionStates& result) {
|
||||
deleteMotionStates();
|
||||
result = _motionStatesToRemoveFromPhysics;
|
||||
_motionStatesToDelete.swap(_motionStatesToRemoveFromPhysics);
|
||||
}
|
||||
|
||||
void AvatarManager::getObjectsToAddToPhysics(VectorOfMotionStates& result) {
|
||||
result.clear();
|
||||
for (auto motionState : _motionStatesToAddToPhysics) {
|
||||
result.push_back(motionState);
|
||||
}
|
||||
_motionStatesToAddToPhysics.clear();
|
||||
}
|
||||
|
||||
void AvatarManager::getObjectsToChange(VectorOfMotionStates& result) {
|
||||
result.clear();
|
||||
AvatarMotionStateMap::iterator motionStateItr = _motionStates.begin();
|
||||
while (motionStateItr != _motionStates.end()) {
|
||||
if ((*motionStateItr)->getIncomingDirtyFlags() != 0) {
|
||||
result.push_back(*motionStateItr);
|
||||
}
|
||||
++motionStateItr;
|
||||
assert(!avatar->_motionState);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#ifndef hifi_AvatarManager_h
|
||||
#define hifi_AvatarManager_h
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QSharedPointer>
|
||||
|
@ -23,9 +25,11 @@
|
|||
#include <shared/RateCounter.h>
|
||||
#include <avatars-renderer/ScriptAvatar.h>
|
||||
#include <AudioInjector.h>
|
||||
#include <workload/Space.h>
|
||||
|
||||
#include "AvatarMotionState.h"
|
||||
#include "MyAvatar.h"
|
||||
#include "OtherAvatar.h"
|
||||
|
||||
/**jsdoc
|
||||
* The AvatarManager API has properties and methods which manage Avatars within the same domain.
|
||||
|
@ -62,6 +66,7 @@ public:
|
|||
virtual ~AvatarManager();
|
||||
|
||||
void init();
|
||||
void setSpace(workload::SpacePointer& space );
|
||||
|
||||
std::shared_ptr<MyAvatar> getMyAvatar() { return _myAvatar; }
|
||||
glm::vec3 getMyAvatarPosition() const { return _myAvatar->getWorldPosition(); }
|
||||
|
@ -92,6 +97,7 @@ public:
|
|||
void getObjectsToRemoveFromPhysics(VectorOfMotionStates& motionStates);
|
||||
void getObjectsToAddToPhysics(VectorOfMotionStates& motionStates);
|
||||
void getObjectsToChange(VectorOfMotionStates& motionStates);
|
||||
|
||||
void handleChangedMotionStates(const VectorOfMotionStates& motionStates);
|
||||
void handleCollisionEvents(const CollisionEvents& collisionEvents);
|
||||
|
||||
|
@ -102,23 +108,21 @@ public:
|
|||
* @returns {number}
|
||||
*/
|
||||
Q_INVOKABLE float getAvatarDataRate(const QUuid& sessionID, const QString& rateName = QString("")) const;
|
||||
|
||||
|
||||
/**jsdoc
|
||||
* @function AvatarManager.getAvatarUpdateRate
|
||||
* @param {Uuid} sessionID
|
||||
* @param {string} [rateName=""]
|
||||
* @returns {number}
|
||||
*/
|
||||
|
||||
Q_INVOKABLE float getAvatarUpdateRate(const QUuid& sessionID, const QString& rateName = QString("")) const;
|
||||
|
||||
|
||||
/**jsdoc
|
||||
* @function AvatarManager.getAvatarSimulationRate
|
||||
* @param {Uuid} sessionID
|
||||
* @param {string} [rateName=""]
|
||||
* @returns {number}
|
||||
*/
|
||||
|
||||
Q_INVOKABLE float getAvatarSimulationRate(const QUuid& sessionID, const QString& rateName = QString("")) const;
|
||||
|
||||
/**jsdoc
|
||||
|
@ -153,7 +157,7 @@ public:
|
|||
*/
|
||||
// TODO: remove this HACK once we settle on optimal default sort coefficients
|
||||
Q_INVOKABLE float getAvatarSortCoefficient(const QString& name);
|
||||
|
||||
|
||||
/**jsdoc
|
||||
* @function AvatarManager.setAvatarSortCoefficient
|
||||
* @param {string} name
|
||||
|
@ -175,14 +179,20 @@ public:
|
|||
float getMyAvatarSendRate() const { return _myAvatarSendRate.rate(); }
|
||||
int getIdentityRequestsSent() const { return _identityRequestsSent; }
|
||||
|
||||
public slots:
|
||||
void queuePhysicsChange(const OtherAvatarPointer& avatar);
|
||||
void buildPhysicsTransaction(PhysicsEngine::Transaction& transaction);
|
||||
void handleProcessedPhysicsTransaction(PhysicsEngine::Transaction& transaction);
|
||||
|
||||
public slots:
|
||||
/**jsdoc
|
||||
* @function AvatarManager.updateAvatarRenderStatus
|
||||
* @param {boolean} shouldRenderAvatars
|
||||
*/
|
||||
void updateAvatarRenderStatus(bool shouldRenderAvatars);
|
||||
|
||||
protected:
|
||||
AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) override;
|
||||
|
||||
private:
|
||||
explicit AvatarManager(QObject* parent = 0);
|
||||
explicit AvatarManager(const AvatarManager& other);
|
||||
|
@ -190,16 +200,12 @@ private:
|
|||
void simulateAvatarFades(float deltaTime);
|
||||
|
||||
AvatarSharedPointer newSharedAvatar() override;
|
||||
void deleteMotionStates();
|
||||
void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason) override;
|
||||
|
||||
QVector<AvatarSharedPointer> _avatarsToFade;
|
||||
|
||||
using AvatarMotionStateMap = QMap<Avatar*, AvatarMotionState*>;
|
||||
AvatarMotionStateMap _motionStates;
|
||||
VectorOfMotionStates _motionStatesToRemoveFromPhysics;
|
||||
VectorOfMotionStates _motionStatesToDelete;
|
||||
SetOfMotionStates _motionStatesToAddToPhysics;
|
||||
using SetOfOtherAvatars = std::set<OtherAvatarPointer>;
|
||||
SetOfOtherAvatars _avatarsToChangeInPhysics;
|
||||
|
||||
std::shared_ptr<MyAvatar> _myAvatar;
|
||||
quint64 _lastSendAvatarDataTime = 0; // Controls MyAvatar send data rate.
|
||||
|
@ -212,6 +218,10 @@ private:
|
|||
float _avatarSimulationTime { 0.0f };
|
||||
bool _shouldRender { true };
|
||||
mutable int _identityRequestsSent { 0 };
|
||||
|
||||
mutable std::mutex _spaceLock;
|
||||
workload::SpacePointer _space;
|
||||
std::vector<int32_t> _spaceProxiesToDelete;
|
||||
};
|
||||
|
||||
#endif // hifi_AvatarManager_h
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include <PhysicsHelpers.h>
|
||||
|
||||
|
||||
AvatarMotionState::AvatarMotionState(AvatarSharedPointer avatar, const btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) {
|
||||
AvatarMotionState::AvatarMotionState(OtherAvatarPointer avatar, const btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) {
|
||||
assert(_avatar);
|
||||
_type = MOTIONSTATE_TYPE_AVATAR;
|
||||
cacheShapeDiameter();
|
||||
|
@ -57,7 +57,7 @@ PhysicsMotionType AvatarMotionState::computePhysicsMotionType() const {
|
|||
// virtual and protected
|
||||
const btCollisionShape* AvatarMotionState::computeNewShape() {
|
||||
ShapeInfo shapeInfo;
|
||||
std::static_pointer_cast<Avatar>(_avatar)->computeShapeInfo(shapeInfo);
|
||||
_avatar->computeShapeInfo(shapeInfo);
|
||||
return getShapeManager()->getShape(shapeInfo);
|
||||
}
|
||||
|
||||
|
@ -151,7 +151,7 @@ glm::vec3 AvatarMotionState::getObjectAngularVelocity() const {
|
|||
|
||||
// virtual
|
||||
glm::vec3 AvatarMotionState::getObjectGravity() const {
|
||||
return std::static_pointer_cast<Avatar>(_avatar)->getAcceleration();
|
||||
return _avatar->getAcceleration();
|
||||
}
|
||||
|
||||
// virtual
|
||||
|
@ -176,7 +176,7 @@ void AvatarMotionState::computeCollisionGroupAndMask(int32_t& group, int32_t& ma
|
|||
|
||||
// virtual
|
||||
float AvatarMotionState::getMass() const {
|
||||
return std::static_pointer_cast<Avatar>(_avatar)->computeMass();
|
||||
return _avatar->computeMass();
|
||||
}
|
||||
|
||||
void AvatarMotionState::cacheShapeDiameter() {
|
||||
|
|
|
@ -14,14 +14,14 @@
|
|||
|
||||
#include <QSet>
|
||||
|
||||
#include <avatars-renderer/Avatar.h>
|
||||
#include <ObjectMotionState.h>
|
||||
#include <BulletUtil.h>
|
||||
|
||||
#include "OtherAvatar.h"
|
||||
|
||||
class AvatarMotionState : public ObjectMotionState {
|
||||
public:
|
||||
AvatarMotionState(AvatarSharedPointer avatar, const btCollisionShape* shape);
|
||||
AvatarMotionState(OtherAvatarPointer avatar, const btCollisionShape* shape);
|
||||
|
||||
virtual void handleEasyChanges(uint32_t& flags) override;
|
||||
virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) override;
|
||||
|
@ -85,7 +85,7 @@ protected:
|
|||
virtual bool isReadyToComputeShape() const override { return true; }
|
||||
virtual const btCollisionShape* computeNewShape() override;
|
||||
|
||||
AvatarSharedPointer _avatar;
|
||||
OtherAvatarPointer _avatar;
|
||||
float _diameter { 0.0f };
|
||||
|
||||
uint32_t _dirtyFlags;
|
||||
|
|
|
@ -105,7 +105,7 @@ MyAvatar::MyAvatar(QThread* thread) :
|
|||
_eyeContactTarget(LEFT_EYE),
|
||||
_realWorldFieldOfView("realWorldFieldOfView",
|
||||
DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES),
|
||||
_useAdvancedMovementControls("advancedMovementForHandControllersIsChecked", false),
|
||||
_useAdvancedMovementControls("advancedMovementForHandControllersIsChecked", true),
|
||||
_smoothOrientationTimer(std::numeric_limits<float>::max()),
|
||||
_smoothOrientationInitial(),
|
||||
_smoothOrientationTarget(),
|
||||
|
@ -203,6 +203,7 @@ MyAvatar::MyAvatar(QThread* thread) :
|
|||
|
||||
connect(recorder.data(), &Recorder::recordingStateChanged, [=] {
|
||||
if (recorder->isRecording()) {
|
||||
createRecordingIDs();
|
||||
setRecordingBasis();
|
||||
} else {
|
||||
clearRecordingBasis();
|
||||
|
@ -444,7 +445,6 @@ void MyAvatar::reset(bool andRecenter, bool andReload, bool andHead) {
|
|||
}
|
||||
|
||||
void MyAvatar::update(float deltaTime) {
|
||||
|
||||
// update moving average of HMD facing in xz plane.
|
||||
const float HMD_FACING_TIMESCALE = getRotationRecenterFilterLength();
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include "OtherAvatar.h"
|
||||
#include "Application.h"
|
||||
|
||||
#include "AvatarMotionState.h"
|
||||
|
||||
OtherAvatar::OtherAvatar(QThread* thread) : Avatar(thread) {
|
||||
// give the pointer to our head to inherited _headData variable from AvatarData
|
||||
_headData = new Head(this);
|
||||
|
@ -58,3 +60,38 @@ void OtherAvatar::createOrb() {
|
|||
_otherAvatarOrbMeshPlaceholder->setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
void OtherAvatar::setSpaceIndex(int32_t index) {
|
||||
assert(_spaceIndex == -1);
|
||||
_spaceIndex = index;
|
||||
}
|
||||
|
||||
void OtherAvatar::updateSpaceProxy(workload::Transaction& transaction) const {
|
||||
if (_spaceIndex > -1) {
|
||||
float approximateBoundingRadius = glm::length(getTargetScale());
|
||||
workload::Sphere sphere(getWorldPosition(), approximateBoundingRadius);
|
||||
transaction.update(_spaceIndex, sphere);
|
||||
}
|
||||
}
|
||||
|
||||
int OtherAvatar::parseDataFromBuffer(const QByteArray& buffer) {
|
||||
int32_t bytesRead = Avatar::parseDataFromBuffer(buffer);
|
||||
if (_moving && _motionState) {
|
||||
_motionState->addDirtyFlags(Simulation::DIRTY_POSITION);
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
void OtherAvatar::setWorkloadRegion(uint8_t region) {
|
||||
_workloadRegion = region;
|
||||
}
|
||||
|
||||
bool OtherAvatar::shouldBeInPhysicsSimulation() const {
|
||||
return (_workloadRegion < workload::Region::R3 && !isDead());
|
||||
}
|
||||
|
||||
void OtherAvatar::rebuildCollisionShape() {
|
||||
if (_motionState) {
|
||||
_motionState->addDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2017/04/27
|
||||
// Copyright 2013-2017 High Fidelity, Inc.
|
||||
// Created by amantly 2018.06.26
|
||||
// Copyright 2018 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
|
||||
|
@ -9,10 +9,17 @@
|
|||
#ifndef hifi_OtherAvatar_h
|
||||
#define hifi_OtherAvatar_h
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <avatars-renderer/Avatar.h>
|
||||
#include <workload/Space.h>
|
||||
|
||||
#include "InterfaceLogging.h"
|
||||
#include "ui/overlays/Overlays.h"
|
||||
#include "ui/overlays/Sphere3DOverlay.h"
|
||||
#include "InterfaceLogging.h"
|
||||
|
||||
class AvatarManager;
|
||||
class AvatarMotionState;
|
||||
|
||||
class OtherAvatar : public Avatar {
|
||||
public:
|
||||
|
@ -24,9 +31,28 @@ public:
|
|||
void updateOrbPosition();
|
||||
void removeOrb();
|
||||
|
||||
void setSpaceIndex(int32_t index);
|
||||
int32_t getSpaceIndex() const { return _spaceIndex; }
|
||||
void updateSpaceProxy(workload::Transaction& transaction) const;
|
||||
|
||||
int parseDataFromBuffer(const QByteArray& buffer) override;
|
||||
|
||||
bool isInPhysicsSimulation() const { return _motionState != nullptr; }
|
||||
void rebuildCollisionShape() override;
|
||||
|
||||
void setWorkloadRegion(uint8_t region);
|
||||
bool shouldBeInPhysicsSimulation() const;
|
||||
|
||||
friend AvatarManager;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Sphere3DOverlay> _otherAvatarOrbMeshPlaceholder { nullptr };
|
||||
OverlayID _otherAvatarOrbMeshPlaceholderID { UNKNOWN_OVERLAY_ID };
|
||||
AvatarMotionState* _motionState { nullptr };
|
||||
int32_t _spaceIndex { -1 };
|
||||
uint8_t _workloadRegion { workload::Region::INVALID };
|
||||
};
|
||||
|
||||
using OtherAvatarPointer = std::shared_ptr<OtherAvatar>;
|
||||
|
||||
#endif // hifi_OtherAvatar_h
|
||||
|
|
|
@ -31,7 +31,9 @@
|
|||
QJsonObject Ledger::apiResponse(const QString& label, QNetworkReply* reply) {
|
||||
QByteArray response = reply->readAll();
|
||||
QJsonObject data = QJsonDocument::fromJson(response).object();
|
||||
#if defined(DEV_BUILD) // Don't expose user's personal data in the wild. But during development this can be handy.
|
||||
qInfo(commerce) << label << "response" << QJsonDocument(data).toJson(QJsonDocument::Compact);
|
||||
#endif
|
||||
return data;
|
||||
}
|
||||
// Non-200 responses are not json:
|
||||
|
@ -69,7 +71,9 @@ void Ledger::send(const QString& endpoint, const QString& success, const QString
|
|||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
const QString URL = "/api/v1/commerce/";
|
||||
JSONCallbackParameters callbackParams(this, success, fail);
|
||||
#if defined(DEV_BUILD) // Don't expose user's personal data in the wild. But during development this can be handy.
|
||||
qCInfo(commerce) << "Sending" << endpoint << QJsonDocument(request).toJson(QJsonDocument::Compact);
|
||||
#endif
|
||||
accountManager->sendRequest(URL + endpoint,
|
||||
authType,
|
||||
method,
|
||||
|
@ -117,7 +121,7 @@ void Ledger::buy(const QString& hfc_key, int cost, const QString& asset_id, cons
|
|||
signedSend("transaction", transactionString, hfc_key, "buy", "buySuccess", "buyFailure", controlled_failure);
|
||||
}
|
||||
|
||||
bool Ledger::receiveAt(const QString& hfc_key, const QString& signing_key) {
|
||||
bool Ledger::receiveAt(const QString& hfc_key, const QString& signing_key, const QByteArray& locker) {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
if (!accountManager->isLoggedIn()) {
|
||||
qCWarning(commerce) << "Cannot set receiveAt when not logged in.";
|
||||
|
@ -125,11 +129,25 @@ bool Ledger::receiveAt(const QString& hfc_key, const QString& signing_key) {
|
|||
emit receiveAtResult(result);
|
||||
return false; // We know right away that we will fail, so tell the caller.
|
||||
}
|
||||
|
||||
signedSend("public_key", hfc_key.toUtf8(), signing_key, "receive_at", "receiveAtSuccess", "receiveAtFailure");
|
||||
QJsonObject transaction;
|
||||
transaction["public_key"] = hfc_key;
|
||||
transaction["locker"] = QString::fromUtf8(locker);
|
||||
QJsonDocument transactionDoc{ transaction };
|
||||
auto transactionString = transactionDoc.toJson(QJsonDocument::Compact);
|
||||
signedSend("text", transactionString, signing_key, "receive_at", "receiveAtSuccess", "receiveAtFailure");
|
||||
return true; // Note that there may still be an asynchronous signal of failure that callers might be interested in.
|
||||
}
|
||||
|
||||
bool Ledger::receiveAt() {
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
auto keys = wallet->listPublicKeys();
|
||||
if (keys.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
auto key = keys.first();
|
||||
return receiveAt(key, key, wallet->getWallet());
|
||||
}
|
||||
|
||||
void Ledger::balance(const QStringList& keys) {
|
||||
keysQuery("balance", "balanceSuccess", "balanceFailure");
|
||||
}
|
||||
|
@ -283,24 +301,30 @@ void Ledger::accountSuccess(QNetworkReply* reply) {
|
|||
auto iv = QByteArray::fromBase64(data["iv"].toString().toUtf8());
|
||||
auto ckey = QByteArray::fromBase64(data["ckey"].toString().toUtf8());
|
||||
QString remotePublicKey = data["public_key"].toString();
|
||||
const QByteArray locker = data["locker"].toString().toUtf8();
|
||||
bool isOverride = wallet->wasSoftReset();
|
||||
|
||||
wallet->setSalt(salt);
|
||||
wallet->setIv(iv);
|
||||
wallet->setCKey(ckey);
|
||||
if (!locker.isEmpty()) {
|
||||
wallet->setWallet(locker);
|
||||
wallet->setPassphrase("ACCOUNT"); // We only locker wallets that have been converted to account-based auth.
|
||||
}
|
||||
|
||||
QString keyStatus = "ok";
|
||||
QStringList localPublicKeys = wallet->listPublicKeys();
|
||||
if (remotePublicKey.isEmpty() || isOverride) {
|
||||
if (!localPublicKeys.isEmpty()) {
|
||||
QString key = localPublicKeys.first();
|
||||
receiveAt(key, key);
|
||||
if (!localPublicKeys.isEmpty()) { // Let the metaverse know about a local wallet.
|
||||
receiveAt();
|
||||
}
|
||||
} else {
|
||||
if (localPublicKeys.isEmpty()) {
|
||||
keyStatus = "preexisting";
|
||||
} else if (localPublicKeys.first() != remotePublicKey) {
|
||||
keyStatus = "conflicting";
|
||||
} else if (locker.isEmpty()) { // Matches metaverse data, but we haven't lockered it yet.
|
||||
receiveAt();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,8 @@ class Ledger : public QObject, public Dependency {
|
|||
|
||||
public:
|
||||
void buy(const QString& hfc_key, int cost, const QString& asset_id, const QString& inventory_key, const bool controlled_failure = false);
|
||||
bool receiveAt(const QString& hfc_key, const QString& signing_key);
|
||||
bool receiveAt(const QString& hfc_key, const QString& signing_key, const QByteArray& locker);
|
||||
bool receiveAt();
|
||||
void balance(const QStringList& keys);
|
||||
void inventory(const QString& editionFilter, const QString& typeFilter, const QString& titleFilter, const int& page, const int& perPage);
|
||||
void history(const QStringList& keys, const int& pageNumber, const int& itemsPerPage);
|
||||
|
|
|
@ -131,7 +131,7 @@ bool Wallet::writeBackupInstructions() {
|
|||
QFile outputFile(outputFilename);
|
||||
bool retval = false;
|
||||
|
||||
if (getKeyFilePath() == "")
|
||||
if (getKeyFilePath().isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -190,6 +190,30 @@ bool writeKeys(const char* filename, EC_KEY* keys) {
|
|||
return retval;
|
||||
}
|
||||
|
||||
bool Wallet::setWallet(const QByteArray& wallet) {
|
||||
QFile file(keyFilePath());
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
qCCritical(commerce) << "Unable to open wallet for write in" << keyFilePath();
|
||||
return false;
|
||||
}
|
||||
if (file.write(wallet) != wallet.count()) {
|
||||
qCCritical(commerce) << "Unable to write wallet in" << keyFilePath();
|
||||
return false;
|
||||
}
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
QByteArray Wallet::getWallet() {
|
||||
QFile file(keyFilePath());
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
qCInfo(commerce) << "No existing wallet in" << keyFilePath();
|
||||
return QByteArray();
|
||||
}
|
||||
QByteArray wallet = file.readAll();
|
||||
file.close();
|
||||
return wallet;
|
||||
}
|
||||
|
||||
QPair<QByteArray*, QByteArray*> generateECKeypair() {
|
||||
|
||||
EC_KEY* keyPair = EC_KEY_new_by_curve_name(NID_secp256k1);
|
||||
|
@ -334,7 +358,7 @@ Wallet::Wallet() {
|
|||
uint status;
|
||||
QString keyStatus = result.contains("data") ? result["data"].toObject()["keyStatus"].toString() : "";
|
||||
|
||||
if (wallet->getKeyFilePath() == "" || !wallet->getSecurityImage()) {
|
||||
if (wallet->getKeyFilePath().isEmpty() || !wallet->getSecurityImage()) {
|
||||
if (keyStatus == "preexisting") {
|
||||
status = (uint) WalletStatus::WALLET_STATUS_PREEXISTING;
|
||||
} else{
|
||||
|
@ -524,15 +548,23 @@ bool Wallet::walletIsAuthenticatedWithPassphrase() {
|
|||
|
||||
// FIXME: initialize OpenSSL elsewhere soon
|
||||
initialize();
|
||||
qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: checking" << (!_passphrase || !_passphrase->isEmpty());
|
||||
|
||||
// this should always be false if we don't have a passphrase
|
||||
// cached yet
|
||||
if (!_passphrase || _passphrase->isEmpty()) {
|
||||
return false;
|
||||
if (!getKeyFilePath().isEmpty()) { // If file exists, then it is an old school file that has not been lockered. Must get user's passphrase.
|
||||
qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: No passphrase, but there is an existing wallet.";
|
||||
return false;
|
||||
} else {
|
||||
qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: New setup.";
|
||||
setPassphrase("ACCOUNT"); // Going forward, consider this an account-based client.
|
||||
}
|
||||
}
|
||||
if (_publicKeys.count() > 0) {
|
||||
// we _must_ be authenticated if the publicKeys are there
|
||||
DependencyManager::get<WalletScriptingInterface>()->setWalletStatus((uint)WalletStatus::WALLET_STATUS_READY);
|
||||
qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: wallet was ready";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -545,10 +577,15 @@ bool Wallet::walletIsAuthenticatedWithPassphrase() {
|
|||
|
||||
// be sure to add the public key so we don't do this over and over
|
||||
_publicKeys.push_back(publicKey.toBase64());
|
||||
|
||||
if (*_passphrase != "ACCOUNT") {
|
||||
changePassphrase("ACCOUNT"); // Rewrites with salt and constant, and will be lockered that way.
|
||||
}
|
||||
qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: wallet now ready";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
qCDebug(commerce) << "walletIsAuthenticatedWithPassphrase: wallet not ready";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -559,6 +596,7 @@ bool Wallet::generateKeyPair() {
|
|||
qCInfo(commerce) << "Generating keypair.";
|
||||
auto keyPair = generateECKeypair();
|
||||
if (!keyPair.first) {
|
||||
qCWarning(commerce) << "Empty keypair";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -576,7 +614,7 @@ bool Wallet::generateKeyPair() {
|
|||
// 2. It is maximally private, and we can step back from that later if desired.
|
||||
// 3. It maximally exercises all the machinery, so we are most likely to surface issues now.
|
||||
auto ledger = DependencyManager::get<Ledger>();
|
||||
return ledger->receiveAt(key, key);
|
||||
return ledger->receiveAt(key, key, getWallet());
|
||||
}
|
||||
|
||||
QStringList Wallet::listPublicKeys() {
|
||||
|
@ -666,11 +704,13 @@ void Wallet::chooseSecurityImage(const QString& filename) {
|
|||
// there _is_ a keyfile, we need to update it (similar to changing the
|
||||
// passphrase, we need to do so into a temp file and move it).
|
||||
if (!QFile(keyFilePath()).exists()) {
|
||||
qCDebug(commerce) << "initial security pic set for empty wallet";
|
||||
emit securityImageResult(true);
|
||||
return;
|
||||
}
|
||||
|
||||
bool success = writeWallet();
|
||||
qCDebug(commerce) << "updated security pic" << success;
|
||||
emit securityImageResult(success);
|
||||
}
|
||||
|
||||
|
@ -715,6 +755,11 @@ QString Wallet::getKeyFilePath() {
|
|||
|
||||
bool Wallet::writeWallet(const QString& newPassphrase) {
|
||||
EC_KEY* keys = readKeys(keyFilePath().toStdString().c_str());
|
||||
auto ledger = DependencyManager::get<Ledger>();
|
||||
// Remove any existing locker, because it will be out of date.
|
||||
if (!_publicKeys.isEmpty() && !ledger->receiveAt(_publicKeys.first(), _publicKeys.first(), QByteArray())) {
|
||||
return false; // FIXME: receiveAt could fail asynchronously.
|
||||
}
|
||||
if (keys) {
|
||||
// we read successfully, so now write to a new temp file
|
||||
QString tempFileName = QString("%1.%2").arg(keyFilePath(), QString("temp"));
|
||||
|
@ -722,6 +767,7 @@ bool Wallet::writeWallet(const QString& newPassphrase) {
|
|||
if (!newPassphrase.isEmpty()) {
|
||||
setPassphrase(newPassphrase);
|
||||
}
|
||||
|
||||
if (writeKeys(tempFileName.toStdString().c_str(), keys)) {
|
||||
if (writeSecurityImage(_securityImage, tempFileName)) {
|
||||
// ok, now move the temp file to the correct spot
|
||||
|
@ -729,6 +775,11 @@ bool Wallet::writeWallet(const QString& newPassphrase) {
|
|||
QFile(tempFileName).rename(QString(keyFilePath()));
|
||||
qCDebug(commerce) << "wallet written successfully";
|
||||
emit keyFilePathIfExistsResult(getKeyFilePath());
|
||||
if (!walletIsAuthenticatedWithPassphrase() || !ledger->receiveAt()) {
|
||||
// FIXME: Should we fail the whole operation?
|
||||
// Tricky, because we'll need the the key and file from the TEMP location...
|
||||
qCWarning(commerce) << "Failed to update locker";
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
qCDebug(commerce) << "couldn't write security image to temp wallet";
|
||||
|
|
|
@ -73,6 +73,7 @@ private slots:
|
|||
void handleChallengeOwnershipPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode);
|
||||
|
||||
private:
|
||||
friend class Ledger;
|
||||
QStringList _publicKeys{};
|
||||
QPixmap* _securityImage { nullptr };
|
||||
QByteArray _salt;
|
||||
|
@ -87,6 +88,9 @@ private:
|
|||
bool readSecurityImage(const QString& inputFilePath, unsigned char** outputBufferPtr, int* outputBufferLen);
|
||||
bool writeBackupInstructions();
|
||||
|
||||
bool setWallet(const QByteArray& wallet);
|
||||
QByteArray getWallet();
|
||||
|
||||
void account();
|
||||
};
|
||||
|
||||
|
|
|
@ -122,11 +122,11 @@ bool SafeLanding::isSequenceNumbersComplete() {
|
|||
int sequenceSize = _initialStart <= _initialEnd ? _initialEnd - _initialStart:
|
||||
_initialEnd + SEQUENCE_MODULO - _initialStart;
|
||||
auto startIter = _sequenceNumbers.find(_initialStart);
|
||||
auto endIter = _sequenceNumbers.find(_initialEnd);
|
||||
auto endIter = _sequenceNumbers.find(_initialEnd - 1);
|
||||
if (sequenceSize == 0 ||
|
||||
(startIter != _sequenceNumbers.end()
|
||||
&& endIter != _sequenceNumbers.end()
|
||||
&& distance(startIter, endIter) == sequenceSize) ) {
|
||||
&& distance(startIter, endIter) == sequenceSize - 1) ) {
|
||||
_trackingEntities = false; // Don't track anything else that comes in.
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ class SafeLanding : public QObject {
|
|||
public:
|
||||
void startEntitySequence(QSharedPointer<EntityTreeRenderer> entityTreeRenderer);
|
||||
void stopEntitySequence();
|
||||
void setCompletionSequenceNumbers(int first, int last);
|
||||
void setCompletionSequenceNumbers(int first, int last); // 'last' exclusive.
|
||||
void noteReceivedsequenceNumber(int sequenceNumber);
|
||||
bool isLoadSequenceComplete();
|
||||
|
||||
|
|
|
@ -272,7 +272,7 @@ void setupPreferences() {
|
|||
auto getter = [myAvatar]()->bool { return myAvatar->useAdvancedMovementControls(); };
|
||||
auto setter = [myAvatar](bool value) { myAvatar->setUseAdvancedMovementControls(value); };
|
||||
preferences->addPreference(new CheckPreference(VR_MOVEMENT,
|
||||
QStringLiteral("Advanced movement for hand controllers"),
|
||||
QStringLiteral("Advanced movement in VR (Teleport movement when unchecked)"),
|
||||
getter, setter));
|
||||
}
|
||||
{
|
||||
|
|
|
@ -121,6 +121,7 @@ void Stats::updateStats(bool force) {
|
|||
auto avatarManager = DependencyManager::get<AvatarManager>();
|
||||
// we need to take one avatar out so we don't include ourselves
|
||||
STAT_UPDATE(avatarCount, avatarManager->size() - 1);
|
||||
STAT_UPDATE(physicsObjectCount, qApp->getNumCollisionObjects());
|
||||
STAT_UPDATE(updatedAvatarCount, avatarManager->getNumAvatarsUpdated());
|
||||
STAT_UPDATE(notUpdatedAvatarCount, avatarManager->getNumAvatarsNotUpdated());
|
||||
STAT_UPDATE(serverCount, (int)nodeList->size());
|
||||
|
|
|
@ -49,6 +49,7 @@ private: \
|
|||
* @property {number} presentdroprate - <em>Read-only.</em>
|
||||
* @property {number} gameLoopRate - <em>Read-only.</em>
|
||||
* @property {number} avatarCount - <em>Read-only.</em>
|
||||
* @property {number} physicsObjectCount - <em>Read-only.</em>
|
||||
* @property {number} updatedAvatarCount - <em>Read-only.</em>
|
||||
* @property {number} notUpdatedAvatarCount - <em>Read-only.</em>
|
||||
* @property {number} packetInCount - <em>Read-only.</em>
|
||||
|
@ -195,6 +196,7 @@ class Stats : public QQuickItem {
|
|||
STATS_PROPERTY(float, presentdroprate, 0)
|
||||
STATS_PROPERTY(int, gameLoopRate, 0)
|
||||
STATS_PROPERTY(int, avatarCount, 0)
|
||||
STATS_PROPERTY(int, physicsObjectCount, 0)
|
||||
STATS_PROPERTY(int, updatedAvatarCount, 0)
|
||||
STATS_PROPERTY(int, notUpdatedAvatarCount, 0)
|
||||
STATS_PROPERTY(int, packetInCount, 0)
|
||||
|
@ -406,6 +408,13 @@ signals:
|
|||
*/
|
||||
void gameLoopRateChanged();
|
||||
|
||||
/**jsdoc
|
||||
* Trigered when
|
||||
* @function Stats.numPhysicsBodiesChanged
|
||||
* @returns {Signal}
|
||||
*/
|
||||
void physicsObjectCountChanged();
|
||||
|
||||
/**jsdoc
|
||||
* Triggered when the value of the <code>avatarCount</code> property changes.
|
||||
* @function Stats.avatarCountChanged
|
||||
|
|
|
@ -10,9 +10,13 @@
|
|||
|
||||
#include "PhysicsBoundary.h"
|
||||
|
||||
#include <EntityItem.h>
|
||||
#include <PhysicalEntitySimulation.h>
|
||||
#include <PhysicsLogging.h>
|
||||
#include <workload/Space.h>
|
||||
|
||||
#include "avatar/AvatarManager.h"
|
||||
#include "avatar/OtherAvatar.h"
|
||||
#include "workload/GameWorkload.h"
|
||||
|
||||
void PhysicsBoundary::run(const workload::WorkloadContextPointer& context, const Inputs& inputs) {
|
||||
|
@ -21,13 +25,27 @@ void PhysicsBoundary::run(const workload::WorkloadContextPointer& context, const
|
|||
return;
|
||||
}
|
||||
GameWorkloadContext* gameContext = static_cast<GameWorkloadContext*>(context.get());
|
||||
PhysicalEntitySimulationPointer simulation = gameContext->_simulation;
|
||||
const auto& regionChanges = inputs.get0();
|
||||
for (uint32_t i = 0; i < (uint32_t)regionChanges.size(); ++i) {
|
||||
const workload::Space::Change& change = regionChanges[i];
|
||||
auto entity = space->getOwner(change.proxyId).get<EntityItemPointer>();
|
||||
if (entity) {
|
||||
simulation->changeEntity(entity);
|
||||
auto nestable = space->getOwner(change.proxyId).get<SpatiallyNestablePointer>();
|
||||
if (nestable) {
|
||||
switch (nestable->getNestableType()) {
|
||||
case NestableType::Entity: {
|
||||
gameContext->_simulation->changeEntity(std::static_pointer_cast<EntityItem>(nestable));
|
||||
}
|
||||
break;
|
||||
case NestableType::Avatar: {
|
||||
auto avatar = std::static_pointer_cast<OtherAvatar>(nestable);
|
||||
avatar->setWorkloadRegion(change.region);
|
||||
if (avatar->isInPhysicsSimulation() != avatar->shouldBeInPhysicsSimulation()) {
|
||||
DependencyManager::get<AvatarManager>()->queuePhysicsChange(avatar);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,25 +7,22 @@
|
|||
// 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_PhysicsGatekeeper_h
|
||||
#define hifi_PhysicsGatekeeper_h
|
||||
#ifndef hifi_PhysicsBoundary_h
|
||||
#define hifi_PhysicsBoundary_h
|
||||
|
||||
#include <EntityItem.h>
|
||||
#include <workload/Engine.h>
|
||||
#include <workload/RegionTracker.h>
|
||||
|
||||
#include "PhysicalEntitySimulation.h"
|
||||
|
||||
class PhysicsBoundary {
|
||||
public:
|
||||
using Config = workload::Job::Config;
|
||||
using Inputs = workload::RegionTracker::Outputs;
|
||||
using Outputs = bool;
|
||||
using JobModel = workload::Job::ModelI<PhysicsBoundary, Inputs, Config>; // this doesn't work
|
||||
using JobModel = workload::Job::ModelI<PhysicsBoundary, Inputs, Config>;
|
||||
|
||||
PhysicsBoundary() {}
|
||||
void configure(const Config& config) { }
|
||||
void run(const workload::WorkloadContextPointer& context, const Inputs& inputs);
|
||||
};
|
||||
|
||||
#endif // hifi_PhysicsGatekeeper_h
|
||||
#endif // hifi_PhysicsBoundary_h
|
||||
|
|
|
@ -376,6 +376,9 @@ void Avatar::updateAvatarEntities() {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (avatarEntities.size() != _avatarEntityForRecording.size()) {
|
||||
createRecordingIDs();
|
||||
}
|
||||
});
|
||||
|
||||
setAvatarEntityDataChanged(false);
|
||||
|
@ -1480,9 +1483,6 @@ int Avatar::parseDataFromBuffer(const QByteArray& buffer) {
|
|||
|
||||
const float MOVE_DISTANCE_THRESHOLD = 0.001f;
|
||||
_moving = glm::distance(oldPosition, getWorldPosition()) > MOVE_DISTANCE_THRESHOLD;
|
||||
if (_moving) {
|
||||
addPhysicsFlags(Simulation::DIRTY_POSITION);
|
||||
}
|
||||
if (_moving || _hasNewJointData) {
|
||||
locationChanged();
|
||||
}
|
||||
|
@ -1624,20 +1624,6 @@ float Avatar::computeMass() {
|
|||
return _density * TWO_PI * radius * radius * (glm::length(end - start) + 2.0f * radius / 3.0f);
|
||||
}
|
||||
|
||||
void Avatar::rebuildCollisionShape() {
|
||||
addPhysicsFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
|
||||
}
|
||||
|
||||
void Avatar::setPhysicsCallback(AvatarPhysicsCallback cb) {
|
||||
_physicsCallback = cb;
|
||||
}
|
||||
|
||||
void Avatar::addPhysicsFlags(uint32_t flags) {
|
||||
if (_physicsCallback) {
|
||||
_physicsCallback(flags);
|
||||
}
|
||||
}
|
||||
|
||||
// thread-safe
|
||||
glm::vec3 Avatar::getLeftPalmPosition() const {
|
||||
return _leftPalmPositionCache.get();
|
||||
|
|
|
@ -50,8 +50,6 @@ enum ScreenTintLayer {
|
|||
|
||||
class Texture;
|
||||
|
||||
using AvatarPhysicsCallback = std::function<void(uint32_t)>;
|
||||
|
||||
class Avatar : public AvatarData, public scriptable::ModelProvider {
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -244,7 +242,7 @@ public:
|
|||
// (otherwise floating point error will cause problems at large positions).
|
||||
void applyPositionDelta(const glm::vec3& delta);
|
||||
|
||||
virtual void rebuildCollisionShape();
|
||||
virtual void rebuildCollisionShape() = 0;
|
||||
|
||||
virtual void computeShapeInfo(ShapeInfo& shapeInfo);
|
||||
void getCapsule(glm::vec3& start, glm::vec3& end, float& radius);
|
||||
|
@ -332,10 +330,6 @@ public:
|
|||
render::ItemID getRenderItemID() { return _renderItemID; }
|
||||
bool isMoving() const { return _moving; }
|
||||
|
||||
void setPhysicsCallback(AvatarPhysicsCallback cb);
|
||||
void addPhysicsFlags(uint32_t flags);
|
||||
bool isInPhysicsSimulation() const { return _physicsCallback != nullptr; }
|
||||
|
||||
void fadeIn(render::ScenePointer scene);
|
||||
void fadeOut(render::ScenePointer scene, KillAvatarReason reason);
|
||||
bool isFading() const { return _isFading; }
|
||||
|
@ -530,8 +524,6 @@ protected:
|
|||
|
||||
int _voiceSphereID;
|
||||
|
||||
AvatarPhysicsCallback _physicsCallback { nullptr };
|
||||
|
||||
float _displayNameTargetAlpha { 1.0f };
|
||||
float _displayNameAlpha { 1.0f };
|
||||
|
||||
|
|
|
@ -2308,6 +2308,15 @@ void AvatarData::setRecordingBasis(std::shared_ptr<Transform> recordingBasis) {
|
|||
_recordingBasis = recordingBasis;
|
||||
}
|
||||
|
||||
void AvatarData::createRecordingIDs() {
|
||||
_avatarEntitiesLock.withReadLock([&] {
|
||||
_avatarEntityForRecording.clear();
|
||||
for (int i = 0; i < _avatarEntityData.size(); i++) {
|
||||
_avatarEntityForRecording.insert(QUuid::createUuid());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void AvatarData::clearRecordingBasis() {
|
||||
_recordingBasis.reset();
|
||||
}
|
||||
|
@ -2368,21 +2377,15 @@ QJsonObject AvatarData::toJson() const {
|
|||
if (!getDisplayName().isEmpty()) {
|
||||
root[JSON_AVATAR_DISPLAY_NAME] = getDisplayName();
|
||||
}
|
||||
if (!getAttachmentData().isEmpty()) {
|
||||
QJsonArray attachmentsJson;
|
||||
for (auto attachment : getAttachmentData()) {
|
||||
attachmentsJson.push_back(attachment.toJson());
|
||||
}
|
||||
root[JSON_AVATAR_ATTACHMENTS] = attachmentsJson;
|
||||
}
|
||||
|
||||
_avatarEntitiesLock.withReadLock([&] {
|
||||
if (!_avatarEntityData.empty()) {
|
||||
QJsonArray avatarEntityJson;
|
||||
int entityCount = 0;
|
||||
for (auto entityID : _avatarEntityData.keys()) {
|
||||
QVariantMap entityData;
|
||||
entityData.insert("id", entityID);
|
||||
entityData.insert("properties", _avatarEntityData.value(entityID));
|
||||
QUuid newId = _avatarEntityForRecording.size() == _avatarEntityData.size() ? _avatarEntityForRecording.values()[entityCount++] : entityID;
|
||||
entityData.insert("id", newId);
|
||||
entityData.insert("properties", _avatarEntityData.value(entityID).toBase64());
|
||||
avatarEntityJson.push_back(QVariant(entityData).toJsonObject());
|
||||
}
|
||||
root[JSON_AVATAR_ENTITIES] = avatarEntityJson;
|
||||
|
@ -2504,12 +2507,17 @@ void AvatarData::fromJson(const QJsonObject& json, bool useFrameSkeleton) {
|
|||
setAttachmentData(attachments);
|
||||
}
|
||||
|
||||
// if (json.contains(JSON_AVATAR_ENTITIES) && json[JSON_AVATAR_ENTITIES].isArray()) {
|
||||
// QJsonArray attachmentsJson = json[JSON_AVATAR_ATTACHMENTS].toArray();
|
||||
// for (auto attachmentJson : attachmentsJson) {
|
||||
// // TODO -- something
|
||||
// }
|
||||
// }
|
||||
if (json.contains(JSON_AVATAR_ENTITIES) && json[JSON_AVATAR_ENTITIES].isArray()) {
|
||||
QJsonArray attachmentsJson = json[JSON_AVATAR_ENTITIES].toArray();
|
||||
for (auto attachmentJson : attachmentsJson) {
|
||||
if (attachmentJson.isObject()) {
|
||||
QVariantMap entityData = attachmentJson.toObject().toVariantMap();
|
||||
QUuid entityID = entityData.value("id").toUuid();
|
||||
QByteArray properties = QByteArray::fromBase64(entityData.value("properties").toByteArray());
|
||||
updateAvatarEntity(entityID, properties);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (json.contains(JSON_AVATAR_JOINT_ARRAY)) {
|
||||
if (version == (int)JsonAvatarFrameVersion::JointRotationsInRelativeFrame) {
|
||||
|
|
|
@ -1089,6 +1089,7 @@ public:
|
|||
void clearRecordingBasis();
|
||||
TransformPointer getRecordingBasis() const;
|
||||
void setRecordingBasis(TransformPointer recordingBasis = TransformPointer());
|
||||
void createRecordingIDs();
|
||||
QJsonObject toJson() const;
|
||||
void fromJson(const QJsonObject& json, bool useFrameSkeleton = true);
|
||||
|
||||
|
@ -1421,6 +1422,7 @@ protected:
|
|||
|
||||
mutable ReadWriteLockable _avatarEntitiesLock;
|
||||
AvatarEntityIDs _avatarEntityDetached; // recently detached from this avatar
|
||||
AvatarEntityIDs _avatarEntityForRecording; // create new entities id for avatar recording
|
||||
AvatarEntityMap _avatarEntityData;
|
||||
bool _avatarEntityDataChanged { false };
|
||||
|
||||
|
|
|
@ -295,7 +295,8 @@ void EntityTreeRenderer::addPendingEntities(const render::ScenePointer& scene, r
|
|||
auto spaceIndex = _space->allocateID();
|
||||
workload::Sphere sphere(entity->getWorldPosition(), entity->getBoundingRadius());
|
||||
workload::Transaction transaction;
|
||||
transaction.reset(spaceIndex, sphere, workload::Owner(entity));
|
||||
SpatiallyNestablePointer nestable = std::static_pointer_cast<SpatiallyNestable>(entity);
|
||||
transaction.reset(spaceIndex, sphere, workload::Owner(nestable));
|
||||
_space->enqueueTransaction(transaction);
|
||||
entity->setSpaceIndex(spaceIndex);
|
||||
connect(entity.get(), &EntityItem::spaceUpdate, this, &EntityTreeRenderer::handleSpaceUpdate, Qt::QueuedConnection);
|
||||
|
|
|
@ -64,6 +64,13 @@ void ZoneEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entity
|
|||
_hazeIndex = INVALID_INDEX;
|
||||
}
|
||||
}
|
||||
|
||||
if (_bloomStage) {
|
||||
if (!BloomStage::isIndexInvalid(_bloomIndex)) {
|
||||
_bloomStage->removeBloom(_bloomIndex);
|
||||
_bloomIndex = INVALID_INDEX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ZoneEntityRenderer::doRender(RenderArgs* args) {
|
||||
|
@ -112,6 +119,11 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) {
|
|||
assert(_hazeStage);
|
||||
}
|
||||
|
||||
if (!_bloomStage) {
|
||||
_bloomStage = args->_scene->getStage<BloomStage>();
|
||||
assert(_bloomStage);
|
||||
}
|
||||
|
||||
{ // Sun
|
||||
// Need an update ?
|
||||
if (_needSunUpdate) {
|
||||
|
@ -161,6 +173,15 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) {
|
|||
}
|
||||
}
|
||||
|
||||
{
|
||||
if (_needBloomUpdate) {
|
||||
if (BloomStage::isIndexInvalid(_bloomIndex)) {
|
||||
_bloomIndex = _bloomStage->addBloom(_bloom);
|
||||
}
|
||||
_needBloomUpdate = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (_visible) {
|
||||
// Finally, push the lights visible in the frame
|
||||
//
|
||||
|
@ -190,6 +211,12 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) {
|
|||
if (_hazeMode != COMPONENT_MODE_INHERIT) {
|
||||
_hazeStage->_currentFrame.pushHaze(_hazeIndex);
|
||||
}
|
||||
|
||||
if (_bloomMode == COMPONENT_MODE_DISABLED) {
|
||||
_bloomStage->_currentFrame.pushBloom(INVALID_INDEX);
|
||||
} else if (_bloomMode == COMPONENT_MODE_ENABLED) {
|
||||
_bloomStage->_currentFrame.pushBloom(_bloomIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,6 +238,7 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
|
|||
bool ambientLightChanged = entity->ambientLightPropertiesChanged();
|
||||
bool skyboxChanged = entity->skyboxPropertiesChanged();
|
||||
bool hazeChanged = entity->hazePropertiesChanged();
|
||||
bool bloomChanged = entity->bloomPropertiesChanged();
|
||||
|
||||
entity->resetRenderingPropertiesChanged();
|
||||
_lastPosition = entity->getWorldPosition();
|
||||
|
@ -221,6 +249,7 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
|
|||
_ambientLightProperties = entity->getAmbientLightProperties();
|
||||
_skyboxProperties = entity->getSkyboxProperties();
|
||||
_hazeProperties = entity->getHazeProperties();
|
||||
_bloomProperties = entity->getBloomProperties();
|
||||
|
||||
#if 0
|
||||
if (_lastShapeURL != _typedEntity->getCompoundShapeURL()) {
|
||||
|
@ -258,6 +287,10 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
|
|||
if (hazeChanged) {
|
||||
updateHazeFromEntity(entity);
|
||||
}
|
||||
|
||||
if (bloomChanged) {
|
||||
updateBloomFromEntity(entity);
|
||||
}
|
||||
}
|
||||
|
||||
void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
|
||||
|
@ -276,6 +309,7 @@ bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint
|
|||
if (entity->keyLightPropertiesChanged() ||
|
||||
entity->ambientLightPropertiesChanged() ||
|
||||
entity->hazePropertiesChanged() ||
|
||||
entity->bloomPropertiesChanged() ||
|
||||
entity->skyboxPropertiesChanged()) {
|
||||
|
||||
return true;
|
||||
|
@ -388,6 +422,16 @@ void ZoneEntityRenderer::updateHazeFromEntity(const TypedEntityPointer& entity)
|
|||
haze->setTransform(entity->getTransform().getMatrix());
|
||||
}
|
||||
|
||||
void ZoneEntityRenderer::updateBloomFromEntity(const TypedEntityPointer& entity) {
|
||||
setBloomMode((ComponentMode)entity->getBloomMode());
|
||||
|
||||
const auto& bloom = editBloom();
|
||||
|
||||
bloom->setBloomIntensity(_bloomProperties.getBloomIntensity());
|
||||
bloom->setBloomThreshold(_bloomProperties.getBloomThreshold());
|
||||
bloom->setBloomSize(_bloomProperties.getBloomSize());
|
||||
}
|
||||
|
||||
void ZoneEntityRenderer::updateKeyBackgroundFromEntity(const TypedEntityPointer& entity) {
|
||||
setSkyboxMode((ComponentMode)entity->getSkyboxMode());
|
||||
|
||||
|
@ -510,6 +554,10 @@ void ZoneEntityRenderer::setSkyboxMode(ComponentMode mode) {
|
|||
_skyboxMode = mode;
|
||||
}
|
||||
|
||||
void ZoneEntityRenderer::setBloomMode(ComponentMode mode) {
|
||||
_bloomMode = mode;
|
||||
}
|
||||
|
||||
void ZoneEntityRenderer::setSkyboxColor(const glm::vec3& color) {
|
||||
editSkybox()->setColor(color);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
//
|
||||
// RenderableZoneEntityItem.h
|
||||
//
|
||||
//
|
||||
// Created by Clement on 4/22/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
|
@ -15,10 +14,12 @@
|
|||
#include <ZoneEntityItem.h>
|
||||
#include <graphics/Skybox.h>
|
||||
#include <graphics/Haze.h>
|
||||
#include <graphics/Bloom.h>
|
||||
#include <graphics/Stage.h>
|
||||
#include <LightStage.h>
|
||||
#include <BackgroundStage.h>
|
||||
#include <HazeStage.h>
|
||||
#include <BloomStage.h>
|
||||
#include <TextureCache.h>
|
||||
#include "RenderableEntityItem.h"
|
||||
#include <ComponentMode.h>
|
||||
|
@ -50,6 +51,7 @@ private:
|
|||
void updateAmbientLightFromEntity(const TypedEntityPointer& entity);
|
||||
void updateHazeFromEntity(const TypedEntityPointer& entity);
|
||||
void updateKeyBackgroundFromEntity(const TypedEntityPointer& entity);
|
||||
void updateBloomFromEntity(const TypedEntityPointer& entity);
|
||||
void updateAmbientMap();
|
||||
void updateSkyboxMap();
|
||||
void setAmbientURL(const QString& ambientUrl);
|
||||
|
@ -59,6 +61,7 @@ private:
|
|||
void setKeyLightMode(ComponentMode mode);
|
||||
void setAmbientLightMode(ComponentMode mode);
|
||||
void setSkyboxMode(ComponentMode mode);
|
||||
void setBloomMode(ComponentMode mode);
|
||||
|
||||
void setSkyboxColor(const glm::vec3& color);
|
||||
void setProceduralUserData(const QString& userData);
|
||||
|
@ -68,6 +71,7 @@ private:
|
|||
graphics::SunSkyStagePointer editBackground() { _needBackgroundUpdate = true; return _background; }
|
||||
graphics::SkyboxPointer editSkybox() { return editBackground()->getSkybox(); }
|
||||
graphics::HazePointer editHaze() { _needHazeUpdate = true; return _haze; }
|
||||
graphics::BloomPointer editBloom() { _needBloomUpdate = true; return _bloom; }
|
||||
|
||||
glm::vec3 _lastPosition;
|
||||
glm::vec3 _lastDimensions;
|
||||
|
@ -82,36 +86,43 @@ private:
|
|||
#endif
|
||||
|
||||
LightStagePointer _stage;
|
||||
const graphics::LightPointer _sunLight{ std::make_shared<graphics::Light>() };
|
||||
const graphics::LightPointer _ambientLight{ std::make_shared<graphics::Light>() };
|
||||
const graphics::SunSkyStagePointer _background{ std::make_shared<graphics::SunSkyStage>() };
|
||||
const graphics::HazePointer _haze{ std::make_shared<graphics::Haze>() };
|
||||
const graphics::LightPointer _sunLight { std::make_shared<graphics::Light>() };
|
||||
const graphics::LightPointer _ambientLight { std::make_shared<graphics::Light>() };
|
||||
const graphics::SunSkyStagePointer _background { std::make_shared<graphics::SunSkyStage>() };
|
||||
const graphics::HazePointer _haze { std::make_shared<graphics::Haze>() };
|
||||
const graphics::BloomPointer _bloom { std::make_shared<graphics::Bloom>() };
|
||||
|
||||
ComponentMode _keyLightMode { COMPONENT_MODE_INHERIT };
|
||||
ComponentMode _ambientLightMode { COMPONENT_MODE_INHERIT };
|
||||
ComponentMode _skyboxMode { COMPONENT_MODE_INHERIT };
|
||||
ComponentMode _hazeMode { COMPONENT_MODE_INHERIT };
|
||||
ComponentMode _bloomMode { COMPONENT_MODE_INHERIT };
|
||||
|
||||
indexed_container::Index _sunIndex{ LightStage::INVALID_INDEX };
|
||||
indexed_container::Index _shadowIndex{ LightStage::INVALID_INDEX };
|
||||
indexed_container::Index _ambientIndex{ LightStage::INVALID_INDEX };
|
||||
indexed_container::Index _sunIndex { LightStage::INVALID_INDEX };
|
||||
indexed_container::Index _shadowIndex { LightStage::INVALID_INDEX };
|
||||
indexed_container::Index _ambientIndex { LightStage::INVALID_INDEX };
|
||||
|
||||
BackgroundStagePointer _backgroundStage;
|
||||
BackgroundStage::Index _backgroundIndex{ BackgroundStage::INVALID_INDEX };
|
||||
BackgroundStage::Index _backgroundIndex { BackgroundStage::INVALID_INDEX };
|
||||
|
||||
HazeStagePointer _hazeStage;
|
||||
HazeStage::Index _hazeIndex{ HazeStage::INVALID_INDEX };
|
||||
HazeStage::Index _hazeIndex { HazeStage::INVALID_INDEX };
|
||||
|
||||
BloomStagePointer _bloomStage;
|
||||
BloomStage::Index _bloomIndex { BloomStage::INVALID_INDEX };
|
||||
|
||||
bool _needUpdate{ true };
|
||||
bool _needSunUpdate{ true };
|
||||
bool _needAmbientUpdate{ true };
|
||||
bool _needBackgroundUpdate{ true };
|
||||
bool _needHazeUpdate{ true };
|
||||
bool _needBloomUpdate { true };
|
||||
|
||||
KeyLightPropertyGroup _keyLightProperties;
|
||||
AmbientLightPropertyGroup _ambientLightProperties;
|
||||
HazePropertyGroup _hazeProperties;
|
||||
SkyboxPropertyGroup _skyboxProperties;
|
||||
BloomPropertyGroup _bloomProperties;
|
||||
|
||||
// More attributes used for rendering:
|
||||
QString _ambientTextureURL;
|
||||
|
|
159
libraries/entities/src/BloomPropertyGroup.cpp
Normal file
159
libraries/entities/src/BloomPropertyGroup.cpp
Normal file
|
@ -0,0 +1,159 @@
|
|||
//
|
||||
// BloomPropertyGroup.cpp
|
||||
// libraries/entities/src
|
||||
//
|
||||
// Created by Sam Gondelman on 8/7/2018
|
||||
// Copyright 2018 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 "BloomPropertyGroup.h"
|
||||
|
||||
#include <OctreePacketData.h>
|
||||
|
||||
#include "EntityItemProperties.h"
|
||||
#include "EntityItemPropertiesMacros.h"
|
||||
|
||||
void BloomPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const {
|
||||
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_BLOOM_INTENSITY, Bloom, bloom, BloomIntensity, bloomIntensity);
|
||||
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_BLOOM_THRESHOLD, Bloom, bloom, BloomThreshold, bloomThreshold);
|
||||
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_BLOOM_SIZE, Bloom, bloom, BloomSize, bloomSize);
|
||||
}
|
||||
|
||||
void BloomPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) {
|
||||
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(bloom, bloomIntensity, float, setBloomIntensity);
|
||||
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(bloom, bloomThreshold, float, setBloomThreshold);
|
||||
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(bloom, bloomSize, float, setBloomSize);
|
||||
}
|
||||
|
||||
void BloomPropertyGroup::merge(const BloomPropertyGroup& other) {
|
||||
COPY_PROPERTY_IF_CHANGED(bloomIntensity);
|
||||
COPY_PROPERTY_IF_CHANGED(bloomThreshold);
|
||||
COPY_PROPERTY_IF_CHANGED(bloomSize);
|
||||
}
|
||||
|
||||
void BloomPropertyGroup::debugDump() const {
|
||||
qCDebug(entities) << " BloomPropertyGroup: ---------------------------------------------";
|
||||
qCDebug(entities) << " _bloomIntensity:" << _bloomIntensity;
|
||||
qCDebug(entities) << " _bloomThreshold:" << _bloomThreshold;
|
||||
qCDebug(entities) << " _bloomSize:" << _bloomSize;
|
||||
}
|
||||
|
||||
void BloomPropertyGroup::listChangedProperties(QList<QString>& out) {
|
||||
if (bloomIntensityChanged()) {
|
||||
out << "bloom-bloomIntensity";
|
||||
}
|
||||
if (bloomThresholdChanged()) {
|
||||
out << "bloom-bloomThreshold";
|
||||
}
|
||||
if (bloomSizeChanged()) {
|
||||
out << "bloom-bloomSize";
|
||||
}
|
||||
}
|
||||
|
||||
bool BloomPropertyGroup::appendToEditPacket(OctreePacketData* packetData,
|
||||
EntityPropertyFlags& requestedProperties,
|
||||
EntityPropertyFlags& propertyFlags,
|
||||
EntityPropertyFlags& propertiesDidntFit,
|
||||
int& propertyCount,
|
||||
OctreeElement::AppendState& appendState) const {
|
||||
bool successPropertyFits = true;
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, getBloomIntensity());
|
||||
APPEND_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, getBloomThreshold());
|
||||
APPEND_ENTITY_PROPERTY(PROP_BLOOM_SIZE, getBloomSize());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BloomPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) {
|
||||
int bytesRead = 0;
|
||||
bool overwriteLocalData = true;
|
||||
bool somethingChanged = false;
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, float, setBloomIntensity);
|
||||
READ_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, float, setBloomThreshold);
|
||||
READ_ENTITY_PROPERTY(PROP_BLOOM_SIZE, float, setBloomSize);
|
||||
|
||||
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_BLOOM_INTENSITY, BloomIntensity);
|
||||
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_BLOOM_THRESHOLD, BloomThreshold);
|
||||
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_BLOOM_SIZE, BloomSize);
|
||||
|
||||
processedBytes += bytesRead;
|
||||
|
||||
Q_UNUSED(somethingChanged);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BloomPropertyGroup::markAllChanged() {
|
||||
_bloomIntensityChanged = true;
|
||||
_bloomThresholdChanged = true;
|
||||
_bloomSizeChanged = true;
|
||||
}
|
||||
|
||||
EntityPropertyFlags BloomPropertyGroup::getChangedProperties() const {
|
||||
EntityPropertyFlags changedProperties;
|
||||
|
||||
CHECK_PROPERTY_CHANGE(PROP_BLOOM_INTENSITY, bloomIntensity);
|
||||
CHECK_PROPERTY_CHANGE(PROP_BLOOM_THRESHOLD, bloomThreshold);
|
||||
CHECK_PROPERTY_CHANGE(PROP_BLOOM_SIZE, bloomSize);
|
||||
|
||||
return changedProperties;
|
||||
}
|
||||
|
||||
void BloomPropertyGroup::getProperties(EntityItemProperties& properties) const {
|
||||
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Bloom, BloomIntensity, getBloomIntensity);
|
||||
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Bloom, BloomThreshold, getBloomThreshold);
|
||||
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Bloom, BloomSize, getBloomSize);
|
||||
}
|
||||
|
||||
bool BloomPropertyGroup::setProperties(const EntityItemProperties& properties) {
|
||||
bool somethingChanged = false;
|
||||
|
||||
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Bloom, BloomIntensity, bloomIntensity, setBloomIntensity);
|
||||
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Bloom, BloomThreshold, bloomThreshold, setBloomThreshold);
|
||||
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Bloom, BloomSize, bloomSize, setBloomSize);
|
||||
|
||||
return somethingChanged;
|
||||
}
|
||||
|
||||
EntityPropertyFlags BloomPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const {
|
||||
EntityPropertyFlags requestedProperties;
|
||||
|
||||
requestedProperties += PROP_BLOOM_INTENSITY;
|
||||
requestedProperties += PROP_BLOOM_THRESHOLD;
|
||||
requestedProperties += PROP_BLOOM_SIZE;
|
||||
|
||||
return requestedProperties;
|
||||
}
|
||||
|
||||
void BloomPropertyGroup::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
|
||||
EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData,
|
||||
EntityPropertyFlags& requestedProperties,
|
||||
EntityPropertyFlags& propertyFlags,
|
||||
EntityPropertyFlags& propertiesDidntFit,
|
||||
int& propertyCount,
|
||||
OctreeElement::AppendState& appendState) const {
|
||||
bool successPropertyFits = true;
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, getBloomIntensity());
|
||||
APPEND_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, getBloomThreshold());
|
||||
APPEND_ENTITY_PROPERTY(PROP_BLOOM_SIZE, getBloomSize());
|
||||
}
|
||||
|
||||
int BloomPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||
ReadBitstreamToTreeParams& args,
|
||||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
|
||||
bool& somethingChanged) {
|
||||
int bytesRead = 0;
|
||||
const unsigned char* dataAt = data;
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, float, setBloomIntensity);
|
||||
READ_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, float, setBloomThreshold);
|
||||
READ_ENTITY_PROPERTY(PROP_BLOOM_SIZE, float, setBloomSize);
|
||||
|
||||
return bytesRead;
|
||||
}
|
94
libraries/entities/src/BloomPropertyGroup.h
Normal file
94
libraries/entities/src/BloomPropertyGroup.h
Normal file
|
@ -0,0 +1,94 @@
|
|||
//
|
||||
// BloomPropertyGroup.h
|
||||
// libraries/entities/src
|
||||
//
|
||||
// Created by Sam Gondelman on 8/7/2018
|
||||
// Copyright 2018 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_BloomPropertyGroup_h
|
||||
#define hifi_BloomPropertyGroup_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <QtScript/QScriptEngine>
|
||||
|
||||
#include "PropertyGroup.h"
|
||||
#include "EntityItemPropertiesMacros.h"
|
||||
|
||||
class EntityItemProperties;
|
||||
class EncodeBitstreamParams;
|
||||
class OctreePacketData;
|
||||
class EntityTreeElementExtraEncodeData;
|
||||
class ReadBitstreamToTreeParams;
|
||||
|
||||
static const float INITIAL_BLOOM_INTENSITY { 0.25f };
|
||||
static const float INITIAL_BLOOM_THRESHOLD { 0.7f };
|
||||
static const float INITIAL_BLOOM_SIZE { 0.9f };
|
||||
|
||||
/**jsdoc
|
||||
* Bloom is defined by the following properties.
|
||||
* @typedef {object} Entities.Bloom
|
||||
*
|
||||
* @property {number} bloomIntensity=0.25 - The intensity of the bloom effect.
|
||||
* @property {number} bloomThreshold=0.7 - The threshold for the bloom effect.
|
||||
* @property {number} bloomSize=0.9 - The size of the bloom effect.
|
||||
*/
|
||||
class BloomPropertyGroup : public PropertyGroup {
|
||||
public:
|
||||
// EntityItemProperty related helpers
|
||||
virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties,
|
||||
QScriptEngine* engine, bool skipDefaults,
|
||||
EntityItemProperties& defaultEntityProperties) const override;
|
||||
virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) override;
|
||||
|
||||
void merge(const BloomPropertyGroup& other);
|
||||
|
||||
virtual void debugDump() const override;
|
||||
virtual void listChangedProperties(QList<QString>& out) override;
|
||||
|
||||
virtual bool appendToEditPacket(OctreePacketData* packetData,
|
||||
EntityPropertyFlags& requestedProperties,
|
||||
EntityPropertyFlags& propertyFlags,
|
||||
EntityPropertyFlags& propertiesDidntFit,
|
||||
int& propertyCount,
|
||||
OctreeElement::AppendState& appendState) const override;
|
||||
|
||||
virtual bool decodeFromEditPacket(EntityPropertyFlags& propertyFlags,
|
||||
const unsigned char*& dataAt, int& processedBytes) override;
|
||||
virtual void markAllChanged() override;
|
||||
virtual EntityPropertyFlags getChangedProperties() const override;
|
||||
|
||||
// EntityItem related helpers
|
||||
// methods for getting/setting all properties of an entity
|
||||
virtual void getProperties(EntityItemProperties& propertiesOut) const override;
|
||||
|
||||
/// returns true if something changed
|
||||
virtual bool setProperties(const EntityItemProperties& properties) override;
|
||||
|
||||
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override;
|
||||
|
||||
virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
|
||||
EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData,
|
||||
EntityPropertyFlags& requestedProperties,
|
||||
EntityPropertyFlags& propertyFlags,
|
||||
EntityPropertyFlags& propertiesDidntFit,
|
||||
int& propertyCount,
|
||||
OctreeElement::AppendState& appendState) const override;
|
||||
|
||||
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||
ReadBitstreamToTreeParams& args,
|
||||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
|
||||
bool& somethingChanged) override;
|
||||
|
||||
DEFINE_PROPERTY(PROP_BLOOM_INTENSITY, BloomIntensity, bloomIntensity, float, INITIAL_BLOOM_INTENSITY);
|
||||
DEFINE_PROPERTY(PROP_BLOOM_THRESHOLD, BloomThreshold, bloomThreshold, float, INITIAL_BLOOM_THRESHOLD);
|
||||
DEFINE_PROPERTY(PROP_BLOOM_SIZE, BloomSize, bloomSize, float, INITIAL_BLOOM_SIZE);
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_BloomPropertyGroup_h
|
|
@ -37,6 +37,7 @@
|
|||
AnimationPropertyGroup EntityItemProperties::_staticAnimation;
|
||||
SkyboxPropertyGroup EntityItemProperties::_staticSkybox;
|
||||
HazePropertyGroup EntityItemProperties::_staticHaze;
|
||||
BloomPropertyGroup EntityItemProperties::_staticBloom;
|
||||
KeyLightPropertyGroup EntityItemProperties::_staticKeyLight;
|
||||
AmbientLightPropertyGroup EntityItemProperties::_staticAmbientLight;
|
||||
|
||||
|
@ -84,6 +85,7 @@ void EntityItemProperties::debugDump() const {
|
|||
getHaze().debugDump();
|
||||
getKeyLight().debugDump();
|
||||
getAmbientLight().debugDump();
|
||||
getBloom().debugDump();
|
||||
|
||||
qCDebug(entities) << " changed properties...";
|
||||
EntityPropertyFlags props = getChangedProperties();
|
||||
|
@ -211,6 +213,10 @@ QString EntityItemProperties::getHazeModeAsString() const {
|
|||
return getComponentModeAsString(_hazeMode);
|
||||
}
|
||||
|
||||
QString EntityItemProperties::getBloomModeAsString() const {
|
||||
return getComponentModeAsString(_bloomMode);
|
||||
}
|
||||
|
||||
QString EntityItemProperties::getComponentModeString(uint32_t mode) {
|
||||
// return "inherit" if mode is not valid
|
||||
if (mode < COMPONENT_MODE_ITEM_COUNT) {
|
||||
|
@ -235,6 +241,15 @@ void EntityItemProperties::setHazeModeFromString(const QString& hazeMode) {
|
|||
}
|
||||
}
|
||||
|
||||
void EntityItemProperties::setBloomModeFromString(const QString& bloomMode) {
|
||||
auto result = findComponent(bloomMode);
|
||||
|
||||
if (result != COMPONENT_MODES.end()) {
|
||||
_bloomMode = result->first;
|
||||
_bloomModeChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
QString EntityItemProperties::getKeyLightModeAsString() const {
|
||||
return getComponentModeAsString(_keyLightMode);
|
||||
}
|
||||
|
@ -394,6 +409,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
CHECK_PROPERTY_CHANGE(PROP_KEY_LIGHT_MODE, keyLightMode);
|
||||
CHECK_PROPERTY_CHANGE(PROP_AMBIENT_LIGHT_MODE, ambientLightMode);
|
||||
CHECK_PROPERTY_CHANGE(PROP_SKYBOX_MODE, skyboxMode);
|
||||
CHECK_PROPERTY_CHANGE(PROP_BLOOM_MODE, bloomMode);
|
||||
|
||||
CHECK_PROPERTY_CHANGE(PROP_SOURCE_URL, sourceUrl);
|
||||
CHECK_PROPERTY_CHANGE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize);
|
||||
|
@ -454,6 +470,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
changedProperties += _ambientLight.getChangedProperties();
|
||||
changedProperties += _skybox.getChangedProperties();
|
||||
changedProperties += _haze.getChangedProperties();
|
||||
changedProperties += _bloom.getChangedProperties();
|
||||
|
||||
return changedProperties;
|
||||
}
|
||||
|
@ -1164,6 +1181,12 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* <code>"enabled"</code>: The haze properties of this zone are enabled, overriding the haze from any enclosing zone.
|
||||
* @property {Entities.Haze} haze - The haze properties of the zone.
|
||||
*
|
||||
* @property {string} bloomMode="inherit" - Configures the bloom in the zone. Possible values:<br />
|
||||
* <code>"inherit"</code>: The bloom from any enclosing zone continues into this zone.<br />
|
||||
* <code>"disabled"</code>: The bloom from any enclosing zone and the bloom of this zone are disabled in this zone.<br />
|
||||
* <code>"enabled"</code>: The bloom properties of this zone are enabled, overriding the bloom from any enclosing zone.
|
||||
* @property {Entities.Bloom} bloom - The bloom properties of the zone.
|
||||
*
|
||||
* @property {boolean} flyingAllowed=true - If <code>true</code> then visitors can fly in the zone; otherwise they cannot.
|
||||
* @property {boolean} ghostingAllowed=true - If <code>true</code> then visitors with avatar collisions turned off will not
|
||||
* collide with content in the zone; otherwise visitors will always collide with content in the zone.
|
||||
|
@ -1382,6 +1405,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_HAZE_MODE, hazeMode, getHazeModeAsString());
|
||||
_haze.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
|
||||
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BLOOM_MODE, bloomMode, getBloomModeAsString());
|
||||
_bloom.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
|
||||
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_KEY_LIGHT_MODE, keyLightMode, getKeyLightModeAsString());
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_AMBIENT_LIGHT_MODE, ambientLightMode, getAmbientLightModeAsString());
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SKYBOX_MODE, skyboxMode, getSkyboxModeAsString());
|
||||
|
@ -1630,6 +1656,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(keyLightMode, KeyLightMode);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(ambientLightMode, AmbientLightMode);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(skyboxMode, SkyboxMode);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(bloomMode, BloomMode);
|
||||
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(sourceUrl, QString, setSourceUrl);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelVolumeSize, vec3, setVoxelVolumeSize);
|
||||
|
@ -1662,6 +1689,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
_ambientLight.copyFromScriptValue(object, _defaultSettings);
|
||||
_skybox.copyFromScriptValue(object, _defaultSettings);
|
||||
_haze.copyFromScriptValue(object, _defaultSettings);
|
||||
_bloom.copyFromScriptValue(object, _defaultSettings);
|
||||
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(xTextureURL, QString, setXTextureURL);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(yTextureURL, QString, setYTextureURL);
|
||||
|
@ -1803,6 +1831,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
|
|||
COPY_PROPERTY_IF_CHANGED(keyLightMode);
|
||||
COPY_PROPERTY_IF_CHANGED(ambientLightMode);
|
||||
COPY_PROPERTY_IF_CHANGED(skyboxMode);
|
||||
COPY_PROPERTY_IF_CHANGED(bloomMode);
|
||||
|
||||
COPY_PROPERTY_IF_CHANGED(sourceUrl);
|
||||
COPY_PROPERTY_IF_CHANGED(voxelVolumeSize);
|
||||
|
@ -1825,6 +1854,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
|
|||
_ambientLight.merge(other._ambientLight);
|
||||
_skybox.merge(other._skybox);
|
||||
_haze.merge(other._haze);
|
||||
_bloom.merge(other._bloom);
|
||||
|
||||
COPY_PROPERTY_IF_CHANGED(xTextureURL);
|
||||
COPY_PROPERTY_IF_CHANGED(yTextureURL);
|
||||
|
@ -2096,6 +2126,11 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
|
|||
ADD_GROUP_PROPERTY_TO_MAP(PROP_HAZE_KEYLIGHT_RANGE, Haze, haze, HazeKeyLightRange, hazeKeyLightRange);
|
||||
ADD_GROUP_PROPERTY_TO_MAP(PROP_HAZE_KEYLIGHT_ALTITUDE, Haze, haze, HazeKeyLightAltitude, hazeKeyLightAltitude);
|
||||
|
||||
ADD_PROPERTY_TO_MAP(PROP_BLOOM_MODE, BloomMode, bloomMode, uint32_t);
|
||||
ADD_GROUP_PROPERTY_TO_MAP(PROP_BLOOM_INTENSITY, Bloom, bloom, BloomIntensity, bloomIntensity);
|
||||
ADD_GROUP_PROPERTY_TO_MAP(PROP_BLOOM_THRESHOLD, Bloom, bloom, BloomThreshold, bloomThreshold);
|
||||
ADD_GROUP_PROPERTY_TO_MAP(PROP_BLOOM_SIZE, Bloom, bloom, BloomSize, bloomSize);
|
||||
|
||||
ADD_PROPERTY_TO_MAP(PROP_KEY_LIGHT_MODE, KeyLightMode, keyLightMode, uint32_t);
|
||||
ADD_PROPERTY_TO_MAP(PROP_AMBIENT_LIGHT_MODE, AmbientLightMode, ambientLightMode, uint32_t);
|
||||
ADD_PROPERTY_TO_MAP(PROP_SKYBOX_MODE, SkyboxMode, skyboxMode, uint32_t);
|
||||
|
@ -2357,6 +2392,10 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
|
|||
_staticHaze.setProperties(properties);
|
||||
_staticHaze.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState);
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_BLOOM_MODE, (uint32_t)properties.getBloomMode());
|
||||
_staticBloom.setProperties(properties);
|
||||
_staticBloom.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState);
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, (uint32_t)properties.getKeyLightMode());
|
||||
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, (uint32_t)properties.getAmbientLightMode());
|
||||
APPEND_ENTITY_PROPERTY(PROP_SKYBOX_MODE, (uint32_t)properties.getSkyboxMode());
|
||||
|
@ -2731,6 +2770,9 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_HAZE_MODE, uint32_t, setHazeMode);
|
||||
properties.getHaze().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
|
||||
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BLOOM_MODE, uint32_t, setBloomMode);
|
||||
properties.getBloom().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
|
||||
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEY_LIGHT_MODE, uint32_t, setKeyLightMode);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_AMBIENT_LIGHT_MODE, uint32_t, setAmbientLightMode);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SKYBOX_MODE, uint32_t, setSkyboxMode);
|
||||
|
@ -3044,10 +3086,12 @@ void EntityItemProperties::markAllChanged() {
|
|||
_skyboxModeChanged = true;
|
||||
_ambientLightModeChanged = true;
|
||||
_hazeModeChanged = true;
|
||||
_bloomModeChanged = true;
|
||||
|
||||
_animation.markAllChanged();
|
||||
_skybox.markAllChanged();
|
||||
_haze.markAllChanged();
|
||||
_bloom.markAllChanged();
|
||||
|
||||
_sourceUrlChanged = true;
|
||||
_voxelVolumeSizeChanged = true;
|
||||
|
@ -3442,15 +3486,15 @@ QList<QString> EntityItemProperties::listChangedProperties() {
|
|||
if (hazeModeChanged()) {
|
||||
out += "hazeMode";
|
||||
}
|
||||
|
||||
if (bloomModeChanged()) {
|
||||
out += "bloomMode";
|
||||
}
|
||||
if (keyLightModeChanged()) {
|
||||
out += "keyLightMode";
|
||||
}
|
||||
|
||||
if (ambientLightModeChanged()) {
|
||||
out += "ambientLightMode";
|
||||
}
|
||||
|
||||
if (skyboxModeChanged()) {
|
||||
out += "skyboxMode";
|
||||
}
|
||||
|
@ -3581,6 +3625,7 @@ QList<QString> EntityItemProperties::listChangedProperties() {
|
|||
getAmbientLight().listChangedProperties(out);
|
||||
getSkybox().listChangedProperties(out);
|
||||
getHaze().listChangedProperties(out);
|
||||
getBloom().listChangedProperties(out);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "SimulationOwner.h"
|
||||
#include "SkyboxPropertyGroup.h"
|
||||
#include "HazePropertyGroup.h"
|
||||
#include "BloomPropertyGroup.h"
|
||||
#include "TextEntityItem.h"
|
||||
#include "ZoneEntityItem.h"
|
||||
|
||||
|
@ -195,9 +196,11 @@ public:
|
|||
DEFINE_PROPERTY_REF_ENUM(PROP_SKYBOX_MODE, SkyboxMode, skyboxMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT);
|
||||
DEFINE_PROPERTY_REF_ENUM(PROP_AMBIENT_LIGHT_MODE, AmbientLightMode, ambientLightMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT);
|
||||
DEFINE_PROPERTY_REF_ENUM(PROP_HAZE_MODE, HazeMode, hazeMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT);
|
||||
DEFINE_PROPERTY_REF_ENUM(PROP_BLOOM_MODE, BloomMode, bloomMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT);
|
||||
|
||||
DEFINE_PROPERTY_GROUP(Skybox, skybox, SkyboxPropertyGroup);
|
||||
DEFINE_PROPERTY_GROUP(Haze, haze, HazePropertyGroup);
|
||||
DEFINE_PROPERTY_GROUP(Bloom, bloom, BloomPropertyGroup);
|
||||
DEFINE_PROPERTY_GROUP(Animation, animation, AnimationPropertyGroup);
|
||||
DEFINE_PROPERTY_REF(PROP_SOURCE_URL, SourceUrl, sourceUrl, QString, "");
|
||||
DEFINE_PROPERTY(PROP_LINE_WIDTH, LineWidth, lineWidth, float, LineEntityItem::DEFAULT_LINE_WIDTH);
|
||||
|
@ -533,6 +536,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
|
|||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, KeyLightMode, keyLightMode, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AmbientLightMode, ambientLightMode, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, SkyboxMode, skyboxMode, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, BloomMode, bloomMode, "");
|
||||
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Cloneable, cloneable, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, CloneLifetime, cloneLifetime, "");
|
||||
|
|
|
@ -257,6 +257,11 @@ enum EntityPropertyList {
|
|||
PROP_SPIN_SPREAD,
|
||||
PROP_PARTICLE_ROTATE_WITH_ENTITY,
|
||||
|
||||
PROP_BLOOM_MODE,
|
||||
PROP_BLOOM_INTENSITY,
|
||||
PROP_BLOOM_THRESHOLD,
|
||||
PROP_BLOOM_SIZE,
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ATTENTION: add new properties to end of list just ABOVE this line
|
||||
PROP_AFTER_LAST_ITEM,
|
||||
|
|
|
@ -47,33 +47,27 @@ ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID) : EntityItem(en
|
|||
EntityItemProperties ZoneEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
|
||||
EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
|
||||
|
||||
// Contains a QString property, must be synchronized
|
||||
// Contain QString properties, must be synchronized
|
||||
withReadLock([&] {
|
||||
_keyLightProperties.getProperties(properties);
|
||||
});
|
||||
|
||||
withReadLock([&] {
|
||||
_ambientLightProperties.getProperties(properties);
|
||||
_skyboxProperties.getProperties(properties);
|
||||
});
|
||||
_hazeProperties.getProperties(properties);
|
||||
_bloomProperties.getProperties(properties);
|
||||
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(compoundShapeURL, getCompoundShapeURL);
|
||||
|
||||
// Contains a QString property, must be synchronized
|
||||
withReadLock([&] {
|
||||
_skyboxProperties.getProperties(properties);
|
||||
});
|
||||
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(flyingAllowed, getFlyingAllowed);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(ghostingAllowed, getGhostingAllowed);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(filterURL, getFilterURL);
|
||||
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(hazeMode, getHazeMode);
|
||||
_hazeProperties.getProperties(properties);
|
||||
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(keyLightMode, getKeyLightMode);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(ambientLightMode, getAmbientLightMode);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(skyboxMode, getSkyboxMode);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(bloomMode, getBloomMode);
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
@ -102,32 +96,27 @@ bool ZoneEntityItem::setSubClassProperties(const EntityItemProperties& propertie
|
|||
// Contains a QString property, must be synchronized
|
||||
withWriteLock([&] {
|
||||
_keyLightPropertiesChanged = _keyLightProperties.setProperties(properties);
|
||||
});
|
||||
withWriteLock([&] {
|
||||
_ambientLightPropertiesChanged = _ambientLightProperties.setProperties(properties);
|
||||
_skyboxPropertiesChanged = _skyboxProperties.setProperties(properties);
|
||||
});
|
||||
_hazePropertiesChanged = _hazeProperties.setProperties(properties);
|
||||
_bloomPropertiesChanged = _bloomProperties.setProperties(properties);
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, setShapeType);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL);
|
||||
|
||||
// Contains a QString property, must be synchronized
|
||||
withWriteLock([&] {
|
||||
_skyboxPropertiesChanged = _skyboxProperties.setProperties(properties);
|
||||
});
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(flyingAllowed, setFlyingAllowed);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(ghostingAllowed, setGhostingAllowed);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(filterURL, setFilterURL);
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(hazeMode, setHazeMode);
|
||||
_hazePropertiesChanged = _hazeProperties.setProperties(properties);
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(keyLightMode, setKeyLightMode);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(ambientLightMode, setAmbientLightMode);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(skyboxMode, setSkyboxMode);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(bloomMode, setBloomMode);
|
||||
|
||||
somethingChanged = somethingChanged || _keyLightPropertiesChanged || _ambientLightPropertiesChanged ||
|
||||
_stagePropertiesChanged || _skyboxPropertiesChanged || _hazePropertiesChanged;
|
||||
_stagePropertiesChanged || _skyboxPropertiesChanged || _hazePropertiesChanged || _bloomPropertiesChanged;
|
||||
|
||||
return somethingChanged;
|
||||
}
|
||||
|
@ -139,54 +128,67 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
|
|||
int bytesRead = 0;
|
||||
const unsigned char* dataAt = data;
|
||||
|
||||
int bytesFromKeylight;
|
||||
withWriteLock([&] {
|
||||
bytesFromKeylight = _keyLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
|
||||
propertyFlags, overwriteLocalData, _keyLightPropertiesChanged);
|
||||
});
|
||||
{
|
||||
int bytesFromKeylight;
|
||||
withWriteLock([&] {
|
||||
bytesFromKeylight = _keyLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
|
||||
propertyFlags, overwriteLocalData, _keyLightPropertiesChanged);
|
||||
});
|
||||
somethingChanged = somethingChanged || _keyLightPropertiesChanged;
|
||||
bytesRead += bytesFromKeylight;
|
||||
dataAt += bytesFromKeylight;
|
||||
}
|
||||
|
||||
somethingChanged = somethingChanged || _keyLightPropertiesChanged;
|
||||
bytesRead += bytesFromKeylight;
|
||||
dataAt += bytesFromKeylight;
|
||||
{
|
||||
int bytesFromAmbientlight;
|
||||
withWriteLock([&] {
|
||||
bytesFromAmbientlight = _ambientLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
|
||||
propertyFlags, overwriteLocalData, _ambientLightPropertiesChanged);
|
||||
});
|
||||
somethingChanged = somethingChanged || _ambientLightPropertiesChanged;
|
||||
bytesRead += bytesFromAmbientlight;
|
||||
dataAt += bytesFromAmbientlight;
|
||||
}
|
||||
|
||||
int bytesFromAmbientlight;
|
||||
withWriteLock([&] {
|
||||
bytesFromAmbientlight = _ambientLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
|
||||
propertyFlags, overwriteLocalData, _ambientLightPropertiesChanged);
|
||||
});
|
||||
{
|
||||
int bytesFromSkybox;
|
||||
withWriteLock([&] {
|
||||
bytesFromSkybox = _skyboxProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
|
||||
propertyFlags, overwriteLocalData, _skyboxPropertiesChanged);
|
||||
});
|
||||
somethingChanged = somethingChanged || _skyboxPropertiesChanged;
|
||||
bytesRead += bytesFromSkybox;
|
||||
dataAt += bytesFromSkybox;
|
||||
}
|
||||
|
||||
somethingChanged = somethingChanged || _ambientLightPropertiesChanged;
|
||||
bytesRead += bytesFromAmbientlight;
|
||||
dataAt += bytesFromAmbientlight;
|
||||
{
|
||||
int bytesFromHaze = _hazeProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
|
||||
propertyFlags, overwriteLocalData, _hazePropertiesChanged);
|
||||
somethingChanged = somethingChanged || _hazePropertiesChanged;
|
||||
bytesRead += bytesFromHaze;
|
||||
dataAt += bytesFromHaze;
|
||||
}
|
||||
|
||||
{
|
||||
int bytesFromBloom = _bloomProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
|
||||
propertyFlags, overwriteLocalData, _bloomPropertiesChanged);
|
||||
somethingChanged = somethingChanged || _bloomPropertiesChanged;
|
||||
bytesRead += bytesFromBloom;
|
||||
dataAt += bytesFromBloom;
|
||||
}
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType);
|
||||
READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL);
|
||||
|
||||
int bytesFromSkybox;
|
||||
withWriteLock([&] {
|
||||
bytesFromSkybox = _skyboxProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
|
||||
propertyFlags, overwriteLocalData, _skyboxPropertiesChanged);
|
||||
});
|
||||
somethingChanged = somethingChanged || _skyboxPropertiesChanged;
|
||||
bytesRead += bytesFromSkybox;
|
||||
dataAt += bytesFromSkybox;
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, bool, setFlyingAllowed);
|
||||
READ_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, bool, setGhostingAllowed);
|
||||
READ_ENTITY_PROPERTY(PROP_FILTER_URL, QString, setFilterURL);
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_HAZE_MODE, uint32_t, setHazeMode);
|
||||
|
||||
int bytesFromHaze = _hazeProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
|
||||
propertyFlags, overwriteLocalData, _hazePropertiesChanged);
|
||||
|
||||
somethingChanged = somethingChanged || _hazePropertiesChanged;
|
||||
bytesRead += bytesFromHaze;
|
||||
dataAt += bytesFromHaze;
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, uint32_t, setKeyLightMode);
|
||||
READ_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, uint32_t, setAmbientLightMode);
|
||||
READ_ENTITY_PROPERTY(PROP_SKYBOX_MODE, uint32_t, setSkyboxMode);
|
||||
READ_ENTITY_PROPERTY(PROP_BLOOM_MODE, uint32_t, setBloomMode);
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
@ -196,29 +198,24 @@ EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& p
|
|||
|
||||
withReadLock([&] {
|
||||
requestedProperties += _keyLightProperties.getEntityProperties(params);
|
||||
});
|
||||
|
||||
withReadLock([&] {
|
||||
requestedProperties += _ambientLightProperties.getEntityProperties(params);
|
||||
requestedProperties += _skyboxProperties.getEntityProperties(params);
|
||||
});
|
||||
requestedProperties += _hazeProperties.getEntityProperties(params);
|
||||
requestedProperties += _bloomProperties.getEntityProperties(params);
|
||||
|
||||
requestedProperties += PROP_SHAPE_TYPE;
|
||||
requestedProperties += PROP_COMPOUND_SHAPE_URL;
|
||||
|
||||
withReadLock([&] {
|
||||
requestedProperties += _skyboxProperties.getEntityProperties(params);
|
||||
});
|
||||
|
||||
requestedProperties += PROP_FLYING_ALLOWED;
|
||||
requestedProperties += PROP_GHOSTING_ALLOWED;
|
||||
requestedProperties += PROP_FILTER_URL;
|
||||
|
||||
requestedProperties += PROP_HAZE_MODE;
|
||||
requestedProperties += _hazeProperties.getEntityProperties(params);
|
||||
|
||||
requestedProperties += PROP_KEY_LIGHT_MODE;
|
||||
requestedProperties += PROP_AMBIENT_LIGHT_MODE;
|
||||
requestedProperties += PROP_SKYBOX_MODE;
|
||||
requestedProperties += PROP_BLOOM_MODE;
|
||||
|
||||
return requestedProperties;
|
||||
}
|
||||
|
@ -235,44 +232,46 @@ void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
|
|||
|
||||
_keyLightProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
|
||||
propertyFlags, propertiesDidntFit, propertyCount, appendState);
|
||||
|
||||
_ambientLightProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
|
||||
propertyFlags, propertiesDidntFit, propertyCount, appendState);
|
||||
_skyboxProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
|
||||
propertyFlags, propertiesDidntFit, propertyCount, appendState);
|
||||
_hazeProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
|
||||
propertyFlags, propertiesDidntFit, propertyCount, appendState);
|
||||
_bloomProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
|
||||
propertyFlags, propertiesDidntFit, propertyCount, appendState);
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, getCompoundShapeURL());
|
||||
|
||||
_skyboxProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
|
||||
propertyFlags, propertiesDidntFit, propertyCount, appendState);
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, getFlyingAllowed());
|
||||
APPEND_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, getGhostingAllowed());
|
||||
APPEND_ENTITY_PROPERTY(PROP_FILTER_URL, getFilterURL());
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_HAZE_MODE, (uint32_t)getHazeMode());
|
||||
_hazeProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
|
||||
propertyFlags, propertiesDidntFit, propertyCount, appendState);
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, (uint32_t)getKeyLightMode());
|
||||
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, (uint32_t)getAmbientLightMode());
|
||||
APPEND_ENTITY_PROPERTY(PROP_SKYBOX_MODE, (uint32_t)getSkyboxMode());
|
||||
APPEND_ENTITY_PROPERTY(PROP_BLOOM_MODE, (uint32_t)getBloomMode());
|
||||
}
|
||||
|
||||
void ZoneEntityItem::debugDump() const {
|
||||
quint64 now = usecTimestampNow();
|
||||
qCDebug(entities) << " ZoneEntityItem id:" << getEntityItemID() << "---------------------------------------------";
|
||||
qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition());
|
||||
qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions());
|
||||
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
|
||||
qCDebug(entities) << " _hazeMode:" << EntityItemProperties::getComponentModeString(_hazeMode);
|
||||
qCDebug(entities) << " _keyLightMode:" << EntityItemProperties::getComponentModeString(_keyLightMode);
|
||||
qCDebug(entities) << " _ambientLightMode:" << EntityItemProperties::getComponentModeString(_ambientLightMode);
|
||||
qCDebug(entities) << " _skyboxMode:" << EntityItemProperties::getComponentModeString(_skyboxMode);
|
||||
qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition());
|
||||
qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions());
|
||||
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
|
||||
qCDebug(entities) << " _hazeMode:" << EntityItemProperties::getComponentModeString(_hazeMode);
|
||||
qCDebug(entities) << " _keyLightMode:" << EntityItemProperties::getComponentModeString(_keyLightMode);
|
||||
qCDebug(entities) << " _ambientLightMode:" << EntityItemProperties::getComponentModeString(_ambientLightMode);
|
||||
qCDebug(entities) << " _skyboxMode:" << EntityItemProperties::getComponentModeString(_skyboxMode);
|
||||
qCDebug(entities) << " _bloomMode:" << EntityItemProperties::getComponentModeString(_bloomMode);
|
||||
|
||||
_keyLightProperties.debugDump();
|
||||
_ambientLightProperties.debugDump();
|
||||
_skyboxProperties.debugDump();
|
||||
_hazeProperties.debugDump();
|
||||
_bloomProperties.debugDump();
|
||||
}
|
||||
|
||||
ShapeType ZoneEntityItem::getShapeType() const {
|
||||
|
@ -344,6 +343,7 @@ void ZoneEntityItem::resetRenderingPropertiesChanged() {
|
|||
_ambientLightPropertiesChanged = false;
|
||||
_skyboxPropertiesChanged = false;
|
||||
_hazePropertiesChanged = false;
|
||||
_bloomPropertiesChanged = false;
|
||||
_stagePropertiesChanged = false;
|
||||
});
|
||||
}
|
||||
|
@ -359,6 +359,17 @@ uint32_t ZoneEntityItem::getHazeMode() const {
|
|||
return _hazeMode;
|
||||
}
|
||||
|
||||
void ZoneEntityItem::setBloomMode(const uint32_t value) {
|
||||
if (value < COMPONENT_MODE_ITEM_COUNT && value != _bloomMode) {
|
||||
_bloomMode = value;
|
||||
_bloomPropertiesChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ZoneEntityItem::getBloomMode() const {
|
||||
return _bloomMode;
|
||||
}
|
||||
|
||||
void ZoneEntityItem::setKeyLightMode(const uint32_t value) {
|
||||
if (value < COMPONENT_MODE_ITEM_COUNT && value != _keyLightMode) {
|
||||
_keyLightMode = value;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "EntityTree.h"
|
||||
#include "SkyboxPropertyGroup.h"
|
||||
#include "HazePropertyGroup.h"
|
||||
#include "BloomPropertyGroup.h"
|
||||
#include <ComponentMode.h>
|
||||
|
||||
class ZoneEntityItem : public EntityItem {
|
||||
|
@ -79,9 +80,13 @@ public:
|
|||
void setSkyboxMode(uint32_t value);
|
||||
uint32_t getSkyboxMode() const;
|
||||
|
||||
void setBloomMode(const uint32_t value);
|
||||
uint32_t getBloomMode() const;
|
||||
|
||||
SkyboxPropertyGroup getSkyboxProperties() const { return resultWithReadLock<SkyboxPropertyGroup>([&] { return _skyboxProperties; }); }
|
||||
|
||||
const HazePropertyGroup& getHazeProperties() const { return _hazeProperties; }
|
||||
const BloomPropertyGroup& getBloomProperties() const { return _bloomProperties; }
|
||||
|
||||
bool getFlyingAllowed() const { return _flyingAllowed; }
|
||||
void setFlyingAllowed(bool value) { _flyingAllowed = value; }
|
||||
|
@ -93,10 +98,8 @@ public:
|
|||
bool keyLightPropertiesChanged() const { return _keyLightPropertiesChanged; }
|
||||
bool ambientLightPropertiesChanged() const { return _ambientLightPropertiesChanged; }
|
||||
bool skyboxPropertiesChanged() const { return _skyboxPropertiesChanged; }
|
||||
|
||||
bool hazePropertiesChanged() const {
|
||||
return _hazePropertiesChanged;
|
||||
}
|
||||
bool hazePropertiesChanged() const { return _hazePropertiesChanged; }
|
||||
bool bloomPropertiesChanged() const { return _bloomPropertiesChanged; }
|
||||
|
||||
bool stagePropertiesChanged() const { return _stagePropertiesChanged; }
|
||||
|
||||
|
@ -133,9 +136,11 @@ protected:
|
|||
uint32_t _ambientLightMode { COMPONENT_MODE_INHERIT };
|
||||
|
||||
uint32_t _hazeMode { COMPONENT_MODE_INHERIT };
|
||||
uint32_t _bloomMode { COMPONENT_MODE_INHERIT };
|
||||
|
||||
SkyboxPropertyGroup _skyboxProperties;
|
||||
HazePropertyGroup _hazeProperties;
|
||||
BloomPropertyGroup _bloomProperties;
|
||||
|
||||
bool _flyingAllowed { DEFAULT_FLYING_ALLOWED };
|
||||
bool _ghostingAllowed { DEFAULT_GHOSTING_ALLOWED };
|
||||
|
@ -146,6 +151,7 @@ protected:
|
|||
bool _ambientLightPropertiesChanged { false };
|
||||
bool _skyboxPropertiesChanged { false };
|
||||
bool _hazePropertiesChanged{ false };
|
||||
bool _bloomPropertiesChanged { false };
|
||||
bool _stagePropertiesChanged { false };
|
||||
|
||||
static bool _drawZoneBoundaries;
|
||||
|
|
18
libraries/graphics/src/graphics/Bloom.cpp
Normal file
18
libraries/graphics/src/graphics/Bloom.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// Bloom.cpp
|
||||
// libraries/graphics/src/graphics
|
||||
//
|
||||
// Created by Sam Gondelman on 8/7/2018
|
||||
// Copyright 2018 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 "Bloom.h"
|
||||
|
||||
using namespace graphics;
|
||||
|
||||
const float Bloom::INITIAL_BLOOM_INTENSITY { 0.25f };
|
||||
const float Bloom::INITIAL_BLOOM_THRESHOLD { 0.7f };
|
||||
const float Bloom::INITIAL_BLOOM_SIZE { 0.9f };
|
41
libraries/graphics/src/graphics/Bloom.h
Normal file
41
libraries/graphics/src/graphics/Bloom.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// Bloom.h
|
||||
// libraries/graphics/src/graphics
|
||||
//
|
||||
// Created by Sam Gondelman on 8/7/2018
|
||||
// Copyright 2018 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_model_Bloom_h
|
||||
#define hifi_model_Bloom_h
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace graphics {
|
||||
class Bloom {
|
||||
public:
|
||||
// Initial values
|
||||
static const float INITIAL_BLOOM_INTENSITY;
|
||||
static const float INITIAL_BLOOM_THRESHOLD;
|
||||
static const float INITIAL_BLOOM_SIZE;
|
||||
|
||||
Bloom() {}
|
||||
|
||||
void setBloomIntensity(const float bloomIntensity) { _bloomIntensity = bloomIntensity; }
|
||||
void setBloomThreshold(const float bloomThreshold) { _bloomThreshold = bloomThreshold; }
|
||||
void setBloomSize(const float bloomSize) { _bloomSize = bloomSize; }
|
||||
|
||||
float getBloomIntensity() { return _bloomIntensity; }
|
||||
float getBloomThreshold() { return _bloomThreshold; }
|
||||
float getBloomSize() { return _bloomSize; }
|
||||
|
||||
private:
|
||||
float _bloomIntensity { INITIAL_BLOOM_INTENSITY };
|
||||
float _bloomThreshold {INITIAL_BLOOM_THRESHOLD };
|
||||
float _bloomSize { INITIAL_BLOOM_SIZE };
|
||||
};
|
||||
using BloomPointer = std::shared_ptr<Bloom>;
|
||||
}
|
||||
#endif // hifi_model_Bloom_h
|
|
@ -33,7 +33,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
|||
case PacketType::EntityEdit:
|
||||
case PacketType::EntityData:
|
||||
case PacketType::EntityPhysics:
|
||||
return static_cast<PacketVersion>(EntityVersion::ParticleSpin);
|
||||
return static_cast<PacketVersion>(EntityVersion::BloomEffect);
|
||||
case PacketType::EntityQuery:
|
||||
return static_cast<PacketVersion>(EntityQueryPacketVersion::ConicalFrustums);
|
||||
case PacketType::AvatarIdentity:
|
||||
|
@ -94,6 +94,8 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
|||
return static_cast<PacketVersion>(AvatarQueryVersion::ConicalFrustums);
|
||||
case PacketType::AvatarIdentityRequest:
|
||||
return 22;
|
||||
case PacketType::EntityQueryInitialResultsComplete:
|
||||
return static_cast<PacketVersion>(EntityVersion::ParticleSpin);
|
||||
default:
|
||||
return 22;
|
||||
}
|
||||
|
|
|
@ -241,7 +241,8 @@ enum class EntityVersion : PacketVersion {
|
|||
CollisionMask16Bytes,
|
||||
YieldSimulationOwnership,
|
||||
ParticleEntityFix,
|
||||
ParticleSpin
|
||||
ParticleSpin,
|
||||
BloomEffect
|
||||
};
|
||||
|
||||
enum class EntityScriptCallMethodVersion : PacketVersion {
|
||||
|
|
|
@ -77,6 +77,10 @@ uint32_t PhysicsEngine::getNumSubsteps() const {
|
|||
return _dynamicsWorld->getNumSubsteps();
|
||||
}
|
||||
|
||||
int32_t PhysicsEngine::getNumCollisionObjects() const {
|
||||
return _dynamicsWorld ? _dynamicsWorld->getNumCollisionObjects() : 0;
|
||||
}
|
||||
|
||||
// private
|
||||
void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) {
|
||||
assert(motionState);
|
||||
|
@ -279,6 +283,57 @@ void PhysicsEngine::reinsertObject(ObjectMotionState* object) {
|
|||
}
|
||||
}
|
||||
|
||||
void PhysicsEngine::processTransaction(PhysicsEngine::Transaction& transaction) {
|
||||
// removes
|
||||
for (auto object : transaction.objectsToRemove) {
|
||||
btRigidBody* body = object->getRigidBody();
|
||||
if (body) {
|
||||
removeDynamicsForBody(body);
|
||||
_dynamicsWorld->removeRigidBody(body);
|
||||
|
||||
// NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it.
|
||||
object->setRigidBody(nullptr);
|
||||
body->setMotionState(nullptr);
|
||||
delete body;
|
||||
}
|
||||
object->clearIncomingDirtyFlags();
|
||||
}
|
||||
|
||||
// adds
|
||||
for (auto object : transaction.objectsToAdd) {
|
||||
addObjectToDynamicsWorld(object);
|
||||
}
|
||||
|
||||
// changes
|
||||
std::vector<ObjectMotionState*> failedChanges;
|
||||
for (auto object : transaction.objectsToChange) {
|
||||
uint32_t flags = object->getIncomingDirtyFlags() & DIRTY_PHYSICS_FLAGS;
|
||||
if (flags & HARD_DIRTY_PHYSICS_FLAGS) {
|
||||
if (object->handleHardAndEasyChanges(flags, this)) {
|
||||
object->clearIncomingDirtyFlags();
|
||||
} else {
|
||||
failedChanges.push_back(object);
|
||||
}
|
||||
} else if (flags & EASY_DIRTY_PHYSICS_FLAGS) {
|
||||
object->handleEasyChanges(flags);
|
||||
object->clearIncomingDirtyFlags();
|
||||
}
|
||||
if (object->getMotionType() == MOTION_TYPE_STATIC && object->isActive()) {
|
||||
_activeStaticBodies.insert(object->getRigidBody());
|
||||
}
|
||||
}
|
||||
// activeStaticBodies have changed (in an Easy way) and need their Aabbs updated
|
||||
// but we've configured Bullet to NOT update them automatically (for improved performance)
|
||||
// so we must do it ourselves
|
||||
std::set<btRigidBody*>::const_iterator itr = _activeStaticBodies.begin();
|
||||
while (itr != _activeStaticBodies.end()) {
|
||||
_dynamicsWorld->updateSingleAabb(*itr);
|
||||
++itr;
|
||||
}
|
||||
// we replace objectsToChange with any that failed
|
||||
transaction.objectsToChange.swap(failedChanges);
|
||||
}
|
||||
|
||||
void PhysicsEngine::removeContacts(ObjectMotionState* motionState) {
|
||||
// trigger events for new/existing/old contacts
|
||||
ContactMap::iterator contactItr = _contactMap.begin();
|
||||
|
|
|
@ -70,11 +70,24 @@ using CollisionEvents = std::vector<Collision>;
|
|||
|
||||
class PhysicsEngine {
|
||||
public:
|
||||
class Transaction {
|
||||
public:
|
||||
void clear() {
|
||||
objectsToRemove.clear();
|
||||
objectsToAdd.clear();
|
||||
objectsToChange.clear();
|
||||
}
|
||||
std::vector<ObjectMotionState*> objectsToRemove;
|
||||
std::vector<ObjectMotionState*> objectsToAdd;
|
||||
std::vector<ObjectMotionState*> objectsToChange;
|
||||
};
|
||||
|
||||
PhysicsEngine(const glm::vec3& offset);
|
||||
~PhysicsEngine();
|
||||
void init();
|
||||
|
||||
uint32_t getNumSubsteps() const;
|
||||
int32_t getNumCollisionObjects() const;
|
||||
|
||||
void removeObjects(const VectorOfMotionStates& objects);
|
||||
void removeSetOfObjects(const SetOfMotionStates& objects); // only called during teardown
|
||||
|
@ -83,6 +96,8 @@ public:
|
|||
VectorOfMotionStates changeObjects(const VectorOfMotionStates& objects);
|
||||
void reinsertObject(ObjectMotionState* object);
|
||||
|
||||
void processTransaction(Transaction& transaction);
|
||||
|
||||
void stepSimulation();
|
||||
void harvestPerformanceStats();
|
||||
void printPerformanceStatsToFile(const QString& filename);
|
||||
|
@ -160,7 +175,7 @@ private:
|
|||
|
||||
CharacterController* _myAvatarController;
|
||||
|
||||
uint32_t _numContactFrames = 0;
|
||||
uint32_t _numContactFrames { 0 };
|
||||
|
||||
bool _dumpNextStats { false };
|
||||
bool _saveNextStats { false };
|
||||
|
|
|
@ -25,11 +25,7 @@ BloomThreshold::BloomThreshold(unsigned int downsamplingFactor) {
|
|||
_parameters.edit()._sampleCount = downsamplingFactor;
|
||||
}
|
||||
|
||||
void BloomThreshold::configure(const Config& config) {
|
||||
if (_parameters.get()._threshold != config.threshold) {
|
||||
_parameters.edit()._threshold = config.threshold;
|
||||
}
|
||||
}
|
||||
void BloomThreshold::configure(const Config& config) {}
|
||||
|
||||
void BloomThreshold::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) {
|
||||
assert(renderContext->args);
|
||||
|
@ -39,6 +35,7 @@ void BloomThreshold::run(const render::RenderContextPointer& renderContext, cons
|
|||
|
||||
const auto frameTransform = inputs.get0();
|
||||
const auto inputFrameBuffer = inputs.get1();
|
||||
const auto bloom = inputs.get2();
|
||||
|
||||
assert(inputFrameBuffer->hasColor());
|
||||
|
||||
|
@ -68,6 +65,13 @@ void BloomThreshold::run(const render::RenderContextPointer& renderContext, cons
|
|||
|
||||
glm::ivec4 viewport{ 0, 0, bufferSize.x, bufferSize.y };
|
||||
|
||||
if (!bloom) {
|
||||
renderContext->taskFlow.abortTask();
|
||||
return;
|
||||
}
|
||||
|
||||
_parameters.edit()._threshold = bloom->getBloomThreshold();
|
||||
|
||||
gpu::doInBatch("BloomThreshold::run", args->_context, [&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
|
||||
|
@ -83,23 +87,15 @@ void BloomThreshold::run(const render::RenderContextPointer& renderContext, cons
|
|||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
|
||||
outputs = _outputBuffer;
|
||||
outputs.edit0() = _outputBuffer;
|
||||
outputs.edit1() = 0.5f + bloom->getBloomSize() * 3.5f;
|
||||
}
|
||||
|
||||
BloomApply::BloomApply() {
|
||||
|
||||
}
|
||||
|
||||
void BloomApply::configure(const Config& config) {
|
||||
const auto newIntensity = config.intensity / 3.0f;
|
||||
|
||||
if (_parameters.get()._intensities.x != newIntensity) {
|
||||
auto& parameters = _parameters.edit();
|
||||
parameters._intensities.x = newIntensity;
|
||||
parameters._intensities.y = newIntensity;
|
||||
parameters._intensities.z = newIntensity;
|
||||
}
|
||||
}
|
||||
void BloomApply::configure(const Config& config) {}
|
||||
|
||||
void BloomApply::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) {
|
||||
assert(renderContext->args);
|
||||
|
@ -109,7 +105,6 @@ void BloomApply::run(const render::RenderContextPointer& renderContext, const In
|
|||
static const auto BLUR0_SLOT = 0;
|
||||
static const auto BLUR1_SLOT = 1;
|
||||
static const auto BLUR2_SLOT = 2;
|
||||
static const auto PARAMETERS_SLOT = 0;
|
||||
|
||||
if (!_pipeline) {
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::bloomApply);
|
||||
|
@ -123,8 +118,15 @@ void BloomApply::run(const render::RenderContextPointer& renderContext, const In
|
|||
const auto blur0FB = inputs.get1();
|
||||
const auto blur1FB = inputs.get2();
|
||||
const auto blur2FB = inputs.get3();
|
||||
const auto bloom = inputs.get4();
|
||||
const glm::ivec4 viewport{ 0, 0, framebufferSize.x, framebufferSize.y };
|
||||
|
||||
const auto newIntensity = bloom->getBloomIntensity() / 3.0f;
|
||||
auto& parameters = _parameters.edit();
|
||||
parameters._intensities.x = newIntensity;
|
||||
parameters._intensities.y = newIntensity;
|
||||
parameters._intensities.z = newIntensity;
|
||||
|
||||
gpu::doInBatch("BloomApply::run", args->_context, [&](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
|
||||
|
@ -139,7 +141,7 @@ void BloomApply::run(const render::RenderContextPointer& renderContext, const In
|
|||
batch.setResourceTexture(BLUR0_SLOT, blur0FB->getRenderBuffer(0));
|
||||
batch.setResourceTexture(BLUR1_SLOT, blur1FB->getRenderBuffer(0));
|
||||
batch.setResourceTexture(BLUR2_SLOT, blur2FB->getRenderBuffer(0));
|
||||
batch.setUniformBuffer(PARAMETERS_SLOT, _parameters);
|
||||
batch.setUniformBuffer(render_utils::slot::buffer::BloomParams, _parameters);
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
});
|
||||
}
|
||||
|
@ -206,8 +208,6 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In
|
|||
level2FB->getRenderBuffer(0)
|
||||
};
|
||||
|
||||
static auto TEXCOORD_RECT_SLOT = 1;
|
||||
|
||||
if (!_pipeline) {
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::gpu::program::drawTextureOpaqueTexcoordRect);
|
||||
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
|
||||
|
@ -227,7 +227,7 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In
|
|||
|
||||
Transform modelTransform;
|
||||
if (_mode == DebugBloomConfig::MODE_ALL_LEVELS) {
|
||||
batch._glUniform4f(TEXCOORD_RECT_SLOT, 0.0f, 0.0f, 1.f, 1.f);
|
||||
batch._glUniform4f(gpu::slot::uniform::TexCoordRect, 0.0f, 0.0f, 1.f, 1.f);
|
||||
|
||||
modelTransform = gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport / 2);
|
||||
modelTransform.postTranslate(glm::vec3(-1.0f, 1.0f, 0.0f));
|
||||
|
@ -255,7 +255,7 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In
|
|||
|
||||
viewport.z /= 2;
|
||||
|
||||
batch._glUniform4f(TEXCOORD_RECT_SLOT, 0.5f, 0.0f, 0.5f, 1.f);
|
||||
batch._glUniform4f(gpu::slot::uniform::TexCoordRect, 0.5f, 0.0f, 0.5f, 1.f);
|
||||
|
||||
modelTransform = gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, viewport);
|
||||
modelTransform.postTranslate(glm::vec3(-1.0f, 0.0f, 0.0f));
|
||||
|
@ -266,44 +266,10 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In
|
|||
});
|
||||
}
|
||||
|
||||
void BloomConfig::setIntensity(float value) {
|
||||
auto task = static_cast<render::Task::TaskConcept*>(_task);
|
||||
auto blurJobIt = task->editJob("BloomApply");
|
||||
assert(blurJobIt != task->_jobs.end());
|
||||
blurJobIt->getConfiguration()->setProperty("intensity", value);
|
||||
}
|
||||
BloomEffect::BloomEffect() {}
|
||||
|
||||
float BloomConfig::getIntensity() const {
|
||||
auto task = static_cast<render::Task::TaskConcept*>(_task);
|
||||
auto blurJobIt = task->getJob("BloomApply");
|
||||
assert(blurJobIt != task->_jobs.end());
|
||||
return blurJobIt->getConfiguration()->property("intensity").toFloat();
|
||||
}
|
||||
|
||||
void BloomConfig::setSize(float value) {
|
||||
std::string blurName{ "BloomBlurN" };
|
||||
auto sigma = 0.5f+value*3.5f;
|
||||
auto task = static_cast<render::Task::TaskConcept*>(_task);
|
||||
|
||||
for (auto i = 0; i < BLOOM_BLUR_LEVEL_COUNT; i++) {
|
||||
blurName.back() = '0' + i;
|
||||
auto blurJobIt = task->editJob(blurName);
|
||||
assert(blurJobIt != task->_jobs.end());
|
||||
auto& gaussianBlur = blurJobIt->edit<render::BlurGaussian>();
|
||||
auto gaussianBlurParams = gaussianBlur.getParameters();
|
||||
gaussianBlurParams->setFilterGaussianTaps(9, sigma);
|
||||
}
|
||||
auto blurJobIt = task->getJob("BloomApply");
|
||||
assert(blurJobIt != task->_jobs.end());
|
||||
blurJobIt->getConfiguration()->setProperty("sigma", sigma);
|
||||
}
|
||||
|
||||
Bloom::Bloom() {
|
||||
|
||||
}
|
||||
|
||||
void Bloom::configure(const Config& config) {
|
||||
std::string blurName{ "BloomBlurN" };
|
||||
void BloomEffect::configure(const Config& config) {
|
||||
std::string blurName { "BloomBlurN" };
|
||||
|
||||
for (auto i = 0; i < BLOOM_BLUR_LEVEL_COUNT; i++) {
|
||||
blurName.back() = '0' + i;
|
||||
|
@ -312,25 +278,30 @@ void Bloom::configure(const Config& config) {
|
|||
}
|
||||
}
|
||||
|
||||
void Bloom::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) {
|
||||
void BloomEffect::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) {
|
||||
// Start by computing threshold of color buffer input at quarter resolution
|
||||
const auto bloomInputBuffer = task.addJob<BloomThreshold>("BloomThreshold", inputs, 4U);
|
||||
const auto bloomOutputs = task.addJob<BloomThreshold>("BloomThreshold", inputs, 4U);
|
||||
|
||||
// Multi-scale blur, each new blur is half resolution of the previous pass
|
||||
const auto blurFB0 = task.addJob<render::BlurGaussian>("BloomBlur0", bloomInputBuffer, true);
|
||||
const auto blurFB1 = task.addJob<render::BlurGaussian>("BloomBlur1", blurFB0, true, 2U);
|
||||
const auto blurFB2 = task.addJob<render::BlurGaussian>("BloomBlur2", blurFB1, true, 2U);
|
||||
const auto blurInputBuffer = bloomOutputs.getN<BloomThreshold::Outputs>(0);
|
||||
const auto sigma = bloomOutputs.getN<BloomThreshold::Outputs>(1);
|
||||
const auto blurInput0 = render::BlurGaussian::Inputs(blurInputBuffer, true, 1U, 9, sigma).asVarying();
|
||||
const auto blurFB0 = task.addJob<render::BlurGaussian>("BloomBlur0", blurInput0);
|
||||
const auto blurInput1 = render::BlurGaussian::Inputs(blurFB0, true, 2U, 9, sigma).asVarying();
|
||||
const auto blurFB1 = task.addJob<render::BlurGaussian>("BloomBlur1", blurInput1);
|
||||
const auto blurInput2 = render::BlurGaussian::Inputs(blurFB1, true, 2U, 9, sigma).asVarying();
|
||||
const auto blurFB2 = task.addJob<render::BlurGaussian>("BloomBlur2", blurInput2);
|
||||
|
||||
const auto& input = inputs.get<Inputs>();
|
||||
const auto& frameBuffer = input[1];
|
||||
const auto& frameBuffer = inputs.getN<Inputs>(1);
|
||||
const auto& bloom = inputs.getN<Inputs>(2);
|
||||
|
||||
// Mix all blur levels at quarter resolution
|
||||
const auto applyInput = BloomApply::Inputs(bloomInputBuffer, blurFB0, blurFB1, blurFB2).asVarying();
|
||||
const auto applyInput = BloomApply::Inputs(blurInputBuffer, blurFB0, blurFB1, blurFB2, bloom).asVarying();
|
||||
task.addJob<BloomApply>("BloomApply", applyInput);
|
||||
// And then blend result in additive manner on top of final color buffer
|
||||
const auto drawInput = BloomDraw::Inputs(frameBuffer, bloomInputBuffer).asVarying();
|
||||
const auto drawInput = BloomDraw::Inputs(frameBuffer, blurInputBuffer).asVarying();
|
||||
task.addJob<BloomDraw>("BloomDraw", drawInput);
|
||||
|
||||
const auto debugInput = DebugBloom::Inputs(frameBuffer, blurFB0, blurFB1, blurFB2, bloomInputBuffer).asVarying();
|
||||
const auto debugInput = DebugBloom::Inputs(frameBuffer, blurFB0, blurFB1, blurFB2, blurInputBuffer).asVarying();
|
||||
task.addJob<DebugBloom>("DebugBloom", debugInput);
|
||||
}
|
||||
|
|
|
@ -14,43 +14,22 @@
|
|||
|
||||
#include <render/Engine.h>
|
||||
|
||||
#include "graphics/Bloom.h"
|
||||
|
||||
#include "DeferredFrameTransform.h"
|
||||
|
||||
class BloomConfig : public render::Task::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(float intensity READ getIntensity WRITE setIntensity NOTIFY dirty)
|
||||
Q_PROPERTY(float size MEMBER size WRITE setSize NOTIFY dirty)
|
||||
|
||||
public:
|
||||
|
||||
BloomConfig() : render::Task::Config(false) {}
|
||||
|
||||
float size{ 0.7f };
|
||||
|
||||
void setIntensity(float value);
|
||||
float getIntensity() const;
|
||||
void setSize(float value);
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
};
|
||||
|
||||
class BloomThresholdConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(float threshold MEMBER threshold NOTIFY dirty)
|
||||
|
||||
public:
|
||||
|
||||
float threshold{ 0.9f };
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
};
|
||||
|
||||
class BloomThreshold {
|
||||
public:
|
||||
using Inputs = render::VaryingSet2<DeferredFrameTransformPointer, gpu::FramebufferPointer>;
|
||||
using Outputs = gpu::FramebufferPointer;
|
||||
using Inputs = render::VaryingSet3<DeferredFrameTransformPointer, gpu::FramebufferPointer, graphics::BloomPointer>;
|
||||
using Outputs = render::VaryingSet2<gpu::FramebufferPointer, float>;
|
||||
using Config = BloomThresholdConfig;
|
||||
using JobModel = render::Job::ModelIO<BloomThreshold, Inputs, Outputs, Config>;
|
||||
|
||||
|
@ -71,21 +50,11 @@ private:
|
|||
|
||||
class BloomApplyConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(float intensity MEMBER intensity NOTIFY dirty)
|
||||
Q_PROPERTY(float sigma MEMBER sigma NOTIFY dirty)
|
||||
|
||||
public:
|
||||
|
||||
float intensity{ 0.25f };
|
||||
float sigma{ 1.0f };
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
};
|
||||
|
||||
class BloomApply {
|
||||
public:
|
||||
using Inputs = render::VaryingSet4<gpu::FramebufferPointer, gpu::FramebufferPointer, gpu::FramebufferPointer, gpu::FramebufferPointer>;
|
||||
using Inputs = render::VaryingSet5<gpu::FramebufferPointer, gpu::FramebufferPointer, gpu::FramebufferPointer, gpu::FramebufferPointer, graphics::BloomPointer>;
|
||||
using Config = BloomApplyConfig;
|
||||
using JobModel = render::Job::ModelI<BloomApply, Inputs, Config>;
|
||||
|
||||
|
@ -118,7 +87,7 @@ private:
|
|||
|
||||
class DebugBloomConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int mode MEMBER mode NOTIFY dirty)
|
||||
Q_PROPERTY(int mode MEMBER mode NOTIFY dirty)
|
||||
|
||||
public:
|
||||
|
||||
|
@ -155,13 +124,13 @@ private:
|
|||
DebugBloomConfig::Mode _mode;
|
||||
};
|
||||
|
||||
class Bloom {
|
||||
class BloomEffect {
|
||||
public:
|
||||
using Inputs = render::VaryingSet2<DeferredFrameTransformPointer, gpu::FramebufferPointer>;
|
||||
using Inputs = render::VaryingSet3<DeferredFrameTransformPointer, gpu::FramebufferPointer, graphics::BloomPointer>;
|
||||
using Config = BloomConfig;
|
||||
using JobModel = render::Task::ModelI<Bloom, Inputs, Config>;
|
||||
using JobModel = render::Task::ModelI<BloomEffect, Inputs, Config>;
|
||||
|
||||
Bloom();
|
||||
BloomEffect();
|
||||
|
||||
void configure(const Config& config);
|
||||
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs);
|
||||
|
|
79
libraries/render-utils/src/BloomStage.cpp
Normal file
79
libraries/render-utils/src/BloomStage.cpp
Normal file
|
@ -0,0 +1,79 @@
|
|||
//
|
||||
// BloomStage.cpp
|
||||
//
|
||||
// Created by Sam Gondelman on 8/7/2018
|
||||
// Copyright 2018 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 "BloomStage.h"
|
||||
|
||||
#include "DeferredLightingEffect.h"
|
||||
|
||||
#include <gpu/Context.h>
|
||||
|
||||
std::string BloomStage::_stageName { "BLOOM_STAGE"};
|
||||
const BloomStage::Index BloomStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX };
|
||||
|
||||
FetchBloomStage::FetchBloomStage() {
|
||||
_bloom = std::make_shared<graphics::Bloom>();
|
||||
}
|
||||
|
||||
void FetchBloomStage::configure(const Config& config) {
|
||||
_bloom->setBloomIntensity(config.bloomIntensity);
|
||||
_bloom->setBloomThreshold(config.bloomThreshold);
|
||||
_bloom->setBloomSize(config.bloomSize);
|
||||
}
|
||||
|
||||
BloomStage::Index BloomStage::findBloom(const BloomPointer& bloom) const {
|
||||
auto found = _bloomMap.find(bloom);
|
||||
if (found != _bloomMap.end()) {
|
||||
return INVALID_INDEX;
|
||||
} else {
|
||||
return (*found).second;
|
||||
}
|
||||
}
|
||||
|
||||
BloomStage::Index BloomStage::addBloom(const BloomPointer& bloom) {
|
||||
auto found = _bloomMap.find(bloom);
|
||||
if (found == _bloomMap.end()) {
|
||||
auto bloomId = _blooms.newElement(bloom);
|
||||
// Avoid failing to allocate a bloom, just pass
|
||||
if (bloomId != INVALID_INDEX) {
|
||||
// Insert the bloom and its index in the reverse map
|
||||
_bloomMap.insert(BloomMap::value_type(bloom, bloomId));
|
||||
}
|
||||
return bloomId;
|
||||
} else {
|
||||
return (*found).second;
|
||||
}
|
||||
}
|
||||
|
||||
BloomStage::BloomPointer BloomStage::removeBloom(Index index) {
|
||||
BloomPointer removed = _blooms.freeElement(index);
|
||||
if (removed) {
|
||||
_bloomMap.erase(removed);
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
BloomStageSetup::BloomStageSetup() {}
|
||||
|
||||
void BloomStageSetup::run(const render::RenderContextPointer& renderContext) {
|
||||
auto stage = renderContext->_scene->getStage(BloomStage::getName());
|
||||
if (!stage) {
|
||||
renderContext->_scene->resetStage(BloomStage::getName(), std::make_shared<BloomStage>());
|
||||
}
|
||||
}
|
||||
|
||||
void FetchBloomStage::run(const render::RenderContextPointer& renderContext, graphics::BloomPointer& bloom) {
|
||||
auto bloomStage = renderContext->_scene->getStage<BloomStage>();
|
||||
assert(bloomStage);
|
||||
|
||||
bloom = nullptr;
|
||||
if (bloomStage->_currentFrame._blooms.size() != 0) {
|
||||
auto bloomId = bloomStage->_currentFrame._blooms.front();
|
||||
bloom = bloomStage->getBloom(bloomId);
|
||||
}
|
||||
}
|
118
libraries/render-utils/src/BloomStage.h
Normal file
118
libraries/render-utils/src/BloomStage.h
Normal file
|
@ -0,0 +1,118 @@
|
|||
//
|
||||
// BloomStage.h
|
||||
|
||||
// Created by Sam Gondelman on 8/7/2018
|
||||
// Copyright 2018 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_render_utils_BloomStage_h
|
||||
#define hifi_render_utils_BloomStage_h
|
||||
|
||||
#include <graphics/Stage.h>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <render/IndexedContainer.h>
|
||||
#include <render/Stage.h>
|
||||
|
||||
#include <render/Forward.h>
|
||||
#include <render/DrawTask.h>
|
||||
#include <graphics/Bloom.h>
|
||||
|
||||
// Bloom stage to set up bloom-related rendering tasks
|
||||
class BloomStage : public render::Stage {
|
||||
public:
|
||||
static std::string _stageName;
|
||||
static const std::string& getName() { return _stageName; }
|
||||
|
||||
using Index = render::indexed_container::Index;
|
||||
static const Index INVALID_INDEX;
|
||||
static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; }
|
||||
|
||||
using BloomPointer = graphics::BloomPointer;
|
||||
using Blooms = render::indexed_container::IndexedPointerVector<graphics::Bloom>;
|
||||
using BloomMap = std::unordered_map<BloomPointer, Index>;
|
||||
|
||||
using BloomIndices = std::vector<Index>;
|
||||
|
||||
Index findBloom(const BloomPointer& bloom) const;
|
||||
Index addBloom(const BloomPointer& bloom);
|
||||
|
||||
BloomPointer removeBloom(Index index);
|
||||
|
||||
bool checkBloomId(Index index) const { return _blooms.checkIndex(index); }
|
||||
|
||||
Index getNumBlooms() const { return _blooms.getNumElements(); }
|
||||
Index getNumFreeBlooms() const { return _blooms.getNumFreeIndices(); }
|
||||
Index getNumAllocatedBlooms() const { return _blooms.getNumAllocatedIndices(); }
|
||||
|
||||
BloomPointer getBloom(Index bloomId) const {
|
||||
return _blooms.get(bloomId);
|
||||
}
|
||||
|
||||
Blooms _blooms;
|
||||
BloomMap _bloomMap;
|
||||
|
||||
class Frame {
|
||||
public:
|
||||
Frame() {}
|
||||
|
||||
void clear() { _blooms.clear(); }
|
||||
|
||||
void pushBloom(BloomStage::Index index) { _blooms.emplace_back(index); }
|
||||
|
||||
BloomStage::BloomIndices _blooms;
|
||||
};
|
||||
|
||||
Frame _currentFrame;
|
||||
};
|
||||
using BloomStagePointer = std::shared_ptr<BloomStage>;
|
||||
|
||||
class BloomStageSetup {
|
||||
public:
|
||||
using JobModel = render::Job::Model<BloomStageSetup>;
|
||||
|
||||
BloomStageSetup();
|
||||
void run(const render::RenderContextPointer& renderContext);
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
class FetchBloomConfig : public render::Job::Config {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(float bloomIntensity MEMBER bloomIntensity WRITE setBloomIntensity NOTIFY dirty);
|
||||
Q_PROPERTY(float bloomThreshold MEMBER bloomThreshold WRITE setBloomThreshold NOTIFY dirty);
|
||||
Q_PROPERTY(float bloomSize MEMBER bloomSize WRITE setBloomSize NOTIFY dirty);
|
||||
|
||||
public:
|
||||
FetchBloomConfig() : render::Job::Config() {}
|
||||
|
||||
float bloomIntensity { graphics::Bloom::INITIAL_BLOOM_INTENSITY };
|
||||
float bloomThreshold { graphics::Bloom::INITIAL_BLOOM_THRESHOLD };
|
||||
float bloomSize { graphics::Bloom::INITIAL_BLOOM_SIZE };
|
||||
|
||||
public slots:
|
||||
void setBloomIntensity(const float value) { bloomIntensity = value; emit dirty(); }
|
||||
void setBloomThreshold(const float value) { bloomThreshold = value; emit dirty(); }
|
||||
void setBloomSize(const float value) { bloomSize = value; emit dirty(); }
|
||||
|
||||
signals:
|
||||
void dirty();
|
||||
};
|
||||
|
||||
class FetchBloomStage {
|
||||
public:
|
||||
using Config = FetchBloomConfig;
|
||||
using JobModel = render::Job::ModelO<FetchBloomStage, graphics::BloomPointer, Config>;
|
||||
|
||||
FetchBloomStage();
|
||||
|
||||
void configure(const Config& config);
|
||||
void run(const render::RenderContextPointer& renderContext, graphics::BloomPointer& bloom);
|
||||
|
||||
private:
|
||||
graphics::BloomPointer _bloom;
|
||||
};
|
||||
#endif
|
|
@ -163,6 +163,5 @@ public:
|
|||
|
||||
private:
|
||||
graphics::HazePointer _haze;
|
||||
gpu::PipelinePointer _hazePipeline;
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "TextureCache.h"
|
||||
#include "ZoneRenderer.h"
|
||||
#include "FadeEffect.h"
|
||||
#include "BloomStage.h"
|
||||
#include "RenderUtilsLogging.h"
|
||||
|
||||
#include "AmbientOcclusionEffect.h"
|
||||
|
@ -173,7 +174,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
|||
const auto velocityBufferOutputs = task.addJob<VelocityBufferPass>("VelocityBuffer", velocityBufferInputs);
|
||||
const auto velocityBuffer = velocityBufferOutputs.getN<VelocityBufferPass::Outputs>(0);
|
||||
|
||||
// Clear Light, Haze and Skybox Stages and render zones from the general metas bucket
|
||||
// Clear Light, Haze, Bloom, and Skybox Stages and render zones from the general metas bucket
|
||||
const auto zones = task.addJob<ZoneRendererTask>("ZoneRenderer", metas);
|
||||
|
||||
// Draw Lights just add the lights to the current list of lights to deal with. NOt really gpu job for now.
|
||||
|
@ -245,8 +246,9 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
|
|||
task.addJob<Antialiasing>("Antialiasing", antialiasingInputs);
|
||||
|
||||
// Add bloom
|
||||
const auto bloomInputs = Bloom::Inputs(deferredFrameTransform, lightingFramebuffer).asVarying();
|
||||
task.addJob<Bloom>("Bloom", bloomInputs);
|
||||
const auto bloomModel = task.addJob<FetchBloomStage>("BloomModel");
|
||||
const auto bloomInputs = BloomEffect::Inputs(deferredFrameTransform, lightingFramebuffer, bloomModel).asVarying();
|
||||
task.addJob<BloomEffect>("Bloom", bloomInputs);
|
||||
|
||||
// Lighting Buffer ready for tone mapping
|
||||
const auto toneMappingInputs = ToneMappingDeferred::Inputs(lightingFramebuffer, scaledPrimaryFramebuffer).asVarying();
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "LightStage.h"
|
||||
#include "BackgroundStage.h"
|
||||
#include "HazeStage.h"
|
||||
#include "BloomStage.h"
|
||||
#include <render/TransitionStage.h>
|
||||
#include <render/HighlightStage.h>
|
||||
#include "DeferredLightingEffect.h"
|
||||
|
@ -22,6 +23,7 @@ void UpdateSceneTask::build(JobModel& task, const render::Varying& input, render
|
|||
task.addJob<LightStageSetup>("LightStageSetup");
|
||||
task.addJob<BackgroundStageSetup>("BackgroundStageSetup");
|
||||
task.addJob<HazeStageSetup>("HazeStageSetup");
|
||||
task.addJob<BloomStageSetup>("BloomStageSetup");
|
||||
task.addJob<render::TransitionStageSetup>("TransitionStageSetup");
|
||||
task.addJob<render::HighlightStageSetup>("HighlightStageSetup");
|
||||
|
||||
|
|
|
@ -21,11 +21,12 @@
|
|||
#include "StencilMaskPass.h"
|
||||
#include "DeferredLightingEffect.h"
|
||||
|
||||
|
||||
#include "render-utils/ShaderConstants.h"
|
||||
#include "StencilMaskPass.h"
|
||||
#include "DeferredLightingEffect.h"
|
||||
|
||||
#include "BloomStage.h"
|
||||
|
||||
namespace ru {
|
||||
using render_utils::slot::texture::Texture;
|
||||
using render_utils::slot::buffer::Buffer;
|
||||
|
@ -63,7 +64,7 @@ void ZoneRendererTask::build(JobModel& task, const Varying& input, Varying& oupu
|
|||
}
|
||||
|
||||
void SetupZones::run(const RenderContextPointer& context, const Inputs& inputs) {
|
||||
// Grab light, background and haze stages and clear them
|
||||
// Grab light, background, haze, and bloom stages and clear them
|
||||
auto lightStage = context->_scene->getStage<LightStage>();
|
||||
assert(lightStage);
|
||||
lightStage->_currentFrame.clear();
|
||||
|
@ -76,6 +77,10 @@ void SetupZones::run(const RenderContextPointer& context, const Inputs& inputs)
|
|||
assert(hazeStage);
|
||||
hazeStage->_currentFrame.clear();
|
||||
|
||||
auto bloomStage = context->_scene->getStage<BloomStage>();
|
||||
assert(bloomStage);
|
||||
bloomStage->_currentFrame.clear();
|
||||
|
||||
// call render over the zones to grab their components in the correct order first...
|
||||
render::renderItems(context, inputs);
|
||||
|
||||
|
@ -84,6 +89,7 @@ void SetupZones::run(const RenderContextPointer& context, const Inputs& inputs)
|
|||
lightStage->_currentFrame.pushAmbientLight(lightStage->getDefaultLight());
|
||||
backgroundStage->_currentFrame.pushBackground(0);
|
||||
hazeStage->_currentFrame.pushHaze(0);
|
||||
bloomStage->_currentFrame.pushBloom(INVALID_INDEX);
|
||||
}
|
||||
|
||||
const gpu::PipelinePointer& DebugZoneLighting::getKeyLightPipeline() {
|
||||
|
|
|
@ -195,9 +195,7 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra
|
|||
return true;
|
||||
}
|
||||
|
||||
BlurGaussian::BlurGaussian(bool generateOutputFramebuffer, unsigned int downsampleFactor) :
|
||||
_inOutResources(generateOutputFramebuffer, downsampleFactor)
|
||||
{
|
||||
BlurGaussian::BlurGaussian() {
|
||||
_parameters = std::make_shared<BlurParams>();
|
||||
}
|
||||
|
||||
|
@ -243,12 +241,17 @@ void BlurGaussian::configure(const Config& config) {
|
|||
}
|
||||
|
||||
|
||||
void BlurGaussian::run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& sourceFramebuffer, gpu::FramebufferPointer& blurredFramebuffer) {
|
||||
void BlurGaussian::run(const RenderContextPointer& renderContext, const Inputs& inputs, gpu::FramebufferPointer& blurredFramebuffer) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->hasViewFrustum());
|
||||
|
||||
RenderArgs* args = renderContext->args;
|
||||
|
||||
const auto sourceFramebuffer = inputs.get0();
|
||||
_inOutResources._generateOutputFramebuffer = inputs.get1();
|
||||
_inOutResources._downsampleFactor = inputs.get2();
|
||||
_parameters->setFilterGaussianTaps(inputs.get3(), inputs.get4());
|
||||
|
||||
BlurInOutResource::Resources blurringResources;
|
||||
if (!_inOutResources.updateResources(sourceFramebuffer, blurringResources)) {
|
||||
// early exit if no valid blurring resources
|
||||
|
|
|
@ -72,6 +72,7 @@ using BlurParamsPointer = std::shared_ptr<BlurParams>;
|
|||
|
||||
class BlurInOutResource {
|
||||
public:
|
||||
BlurInOutResource() {}
|
||||
BlurInOutResource(bool generateOutputFramebuffer, unsigned int downsampleFactor);
|
||||
|
||||
struct Resources {
|
||||
|
@ -113,13 +114,14 @@ protected:
|
|||
|
||||
class BlurGaussian {
|
||||
public:
|
||||
using Inputs = VaryingSet5<gpu::FramebufferPointer, bool, unsigned int, int, float>;
|
||||
using Config = BlurGaussianConfig;
|
||||
using JobModel = Job::ModelIO<BlurGaussian, gpu::FramebufferPointer, gpu::FramebufferPointer, Config>;
|
||||
using JobModel = Job::ModelIO<BlurGaussian, Inputs, gpu::FramebufferPointer, Config>;
|
||||
|
||||
BlurGaussian(bool generateOutputFramebuffer = false, unsigned int downsampleFactor = 1U);
|
||||
BlurGaussian();
|
||||
|
||||
void configure(const Config& config);
|
||||
void run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& sourceFramebuffer, gpu::FramebufferPointer& blurredFramebuffer);
|
||||
void run(const RenderContextPointer& renderContext, const Inputs& inputs, gpu::FramebufferPointer& blurredFramebuffer);
|
||||
|
||||
BlurParamsPointer getParameters() const { return _parameters; }
|
||||
|
||||
|
|
|
@ -176,9 +176,7 @@ ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const
|
|||
_timerFunctionMap(),
|
||||
_fileNameString(fileNameString),
|
||||
_arrayBufferClass(new ArrayBufferClass(this)),
|
||||
_assetScriptingInterface(new AssetScriptingInterface(this)),
|
||||
// don't delete `ScriptEngines` until all `ScriptEngine`s are gone
|
||||
_scriptEngines(DependencyManager::get<ScriptEngines>())
|
||||
_assetScriptingInterface(new AssetScriptingInterface(this))
|
||||
{
|
||||
switch (_context) {
|
||||
case Context::CLIENT_SCRIPT:
|
||||
|
|
|
@ -806,8 +806,6 @@ protected:
|
|||
static const QString _SETTINGS_ENABLE_EXTENDED_EXCEPTIONS;
|
||||
|
||||
Setting::Handle<bool> _enableExtendedJSExceptions { _SETTINGS_ENABLE_EXTENDED_EXCEPTIONS, true };
|
||||
|
||||
QSharedPointer<ScriptEngines> _scriptEngines;
|
||||
};
|
||||
|
||||
ScriptEnginePointer scriptEngineFactory(ScriptEngine::Context context,
|
||||
|
|
|
@ -22,8 +22,8 @@ const float defaultAACubeSize = 1.0f;
|
|||
const int MAX_PARENTING_CHAIN_SIZE = 30;
|
||||
|
||||
SpatiallyNestable::SpatiallyNestable(NestableType nestableType, QUuid id) :
|
||||
_nestableType(nestableType),
|
||||
_id(id),
|
||||
_nestableType(nestableType),
|
||||
_transform() {
|
||||
// set flags in _transform
|
||||
_transform.setTranslation(glm::vec3(0.0f));
|
||||
|
|
|
@ -212,7 +212,6 @@ public:
|
|||
virtual void parentDeleted() { } // called on children of a deleted parent
|
||||
|
||||
protected:
|
||||
const NestableType _nestableType; // EntityItem or an AvatarData
|
||||
QUuid _id;
|
||||
mutable SpatiallyNestableWeakPointer _parent;
|
||||
|
||||
|
@ -232,6 +231,8 @@ protected:
|
|||
quint64 _rotationChanged { 0 };
|
||||
|
||||
private:
|
||||
SpatiallyNestable() = delete;
|
||||
const NestableType _nestableType; // EntityItem or an AvatarData
|
||||
QUuid _parentID; // what is this thing's transform relative to?
|
||||
quint16 _parentJointIndex { INVALID_JOINT_INDEX }; // which joint of the parent is this relative to?
|
||||
|
||||
|
|
|
@ -14,20 +14,11 @@ import "configSlider"
|
|||
|
||||
Item {
|
||||
id: root
|
||||
property var config: Render.getConfig("RenderMainView.Bloom")
|
||||
property var configThreshold: Render.getConfig("RenderMainView.BloomThreshold")
|
||||
property var configDebug: Render.getConfig("RenderMainView.DebugBloom")
|
||||
|
||||
Column {
|
||||
spacing: 8
|
||||
|
||||
CheckBox {
|
||||
text: "Enable"
|
||||
checked: root.config["enabled"]
|
||||
onCheckedChanged: {
|
||||
root.config["enabled"] = checked;
|
||||
}
|
||||
}
|
||||
GroupBox {
|
||||
title: "Debug"
|
||||
Row {
|
||||
|
@ -88,35 +79,5 @@ Item {
|
|||
}
|
||||
}
|
||||
}
|
||||
ConfigSlider {
|
||||
label: "Intensity"
|
||||
integral: false
|
||||
config: root.config
|
||||
property: "intensity"
|
||||
max: 1.0
|
||||
min: 0.0
|
||||
width: 280
|
||||
height:38
|
||||
}
|
||||
ConfigSlider {
|
||||
label: "Size"
|
||||
integral: false
|
||||
config: root.config
|
||||
property: "size"
|
||||
max: 1.0
|
||||
min: 0.0
|
||||
width: 280
|
||||
height:38
|
||||
}
|
||||
ConfigSlider {
|
||||
label: "Threshold"
|
||||
integral: false
|
||||
config: root.configThreshold
|
||||
property: "threshold"
|
||||
max: 2.0
|
||||
min: 0.0
|
||||
width: 280
|
||||
height:38
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,6 @@ var window = new OverlayWindow({
|
|||
title: 'Bloom',
|
||||
source: qml,
|
||||
width: 285,
|
||||
height: 210,
|
||||
height: 40,
|
||||
});
|
||||
window.closed.connect(function() { Script.stop(); });
|
|
@ -406,6 +406,11 @@
|
|||
sendMoneyRecipient = null;
|
||||
}
|
||||
|
||||
function onUsernameChanged() {
|
||||
Settings.setValue("wallet/autoLogout", false);
|
||||
Settings.setValue("wallet/savedUsername", "");
|
||||
}
|
||||
|
||||
// Function Name: fromQml()
|
||||
//
|
||||
// Description:
|
||||
|
@ -581,6 +586,7 @@
|
|||
var tablet = null;
|
||||
var walletEnabled = Settings.getValue("commerce", true);
|
||||
function startup() {
|
||||
GlobalServices.myUsernameChanged.connect(onUsernameChanged);
|
||||
if (walletEnabled) {
|
||||
tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
button = tablet.addButton({
|
||||
|
@ -612,6 +618,7 @@
|
|||
removeOverlays();
|
||||
}
|
||||
function shutdown() {
|
||||
GlobalServices.myUsernameChanged.disconnect(onUsernameChanged);
|
||||
button.clicked.disconnect(onButtonClicked);
|
||||
tablet.removeButton(button);
|
||||
deleteSendMoneyParticleEffect();
|
||||
|
|
|
@ -678,6 +678,52 @@
|
|||
</div>
|
||||
</fieldset-->
|
||||
</fieldset>
|
||||
<fieldset class="minor">
|
||||
<legend class="sub-section-header zone-group zone-section">
|
||||
Bloom
|
||||
</legend>
|
||||
<form>
|
||||
<input type="radio" name="bloomMode" value="inherit" id="property-zone-bloom-mode-inherit" checked> Inherit
|
||||
<input type="radio" name="bloomMode" value="disabled" id="property-zone-bloom-mode-disabled"> Off
|
||||
<input type="radio" name="bloomMode" value="enabled" id="property-zone-bloom-mode-enabled"> On
|
||||
</form>
|
||||
<fieldset class="zone-group zone-section bloom-section property gen fstuple">
|
||||
<div class="tuple">
|
||||
<div>
|
||||
<br>
|
||||
<table>
|
||||
<td><label>Bloom Intensity 0</label></td>
|
||||
<td><input type="range" class="slider" id="property-zone-bloom-intensity" min="0" max="1" step="0.01"></td>
|
||||
<td><label>1</label>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="zone-group zone-section bloom-section property gen fstuple">
|
||||
<div class="tuple">
|
||||
<div>
|
||||
<br>
|
||||
<table>
|
||||
<td><label>Bloom Threshold 0</label></td>
|
||||
<td><input type="range" class="slider" id="property-zone-bloom-threshold" min="0" max="1" step="0.01"></td>
|
||||
<td><label>1</label>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset class="zone-group zone-section bloom-section property gen fstuple">
|
||||
<div class="tuple">
|
||||
<div>
|
||||
<br>
|
||||
<table>
|
||||
<td><label>Bloom Size 0</label></td>
|
||||
<td><input type="range" class="slider" id="property-zone-bloom-size" min="0" max="2" step="0.01"></td>
|
||||
<td><label>2</label>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</fieldset>
|
||||
</fieldset>
|
||||
<fieldset id="text" class="major">
|
||||
<legend class="section-header text-group text-section">
|
||||
|
|
|
@ -841,7 +841,7 @@ function loaded() {
|
|||
var elZoneHazeModeInherit = document.getElementById("property-zone-haze-mode-inherit");
|
||||
var elZoneHazeModeDisabled = document.getElementById("property-zone-haze-mode-disabled");
|
||||
var elZoneHazeModeEnabled = document.getElementById("property-zone-haze-mode-enabled");
|
||||
|
||||
|
||||
var elZoneHazeRange = document.getElementById("property-zone-haze-range");
|
||||
var elZoneHazeColor = document.getElementById("property-zone-haze-color");
|
||||
var elZoneHazeColorRed = document.getElementById("property-zone-haze-color-red");
|
||||
|
@ -860,6 +860,15 @@ function loaded() {
|
|||
|
||||
var elZoneHazeBackgroundBlend = document.getElementById("property-zone-haze-background-blend");
|
||||
|
||||
// Bloom
|
||||
var elZoneBloomModeInherit = document.getElementById("property-zone-bloom-mode-inherit");
|
||||
var elZoneBloomModeDisabled = document.getElementById("property-zone-bloom-mode-disabled");
|
||||
var elZoneBloomModeEnabled = document.getElementById("property-zone-bloom-mode-enabled");
|
||||
|
||||
var elZoneBloomIntensity = document.getElementById("property-zone-bloom-intensity");
|
||||
var elZoneBloomThreshold = document.getElementById("property-zone-bloom-threshold");
|
||||
var elZoneBloomSize = document.getElementById("property-zone-bloom-size");
|
||||
|
||||
var elZoneSkyboxColor = document.getElementById("property-zone-skybox-color");
|
||||
var elZoneSkyboxColorRed = document.getElementById("property-zone-skybox-color-red");
|
||||
var elZoneSkyboxColorGreen = document.getElementById("property-zone-skybox-color-green");
|
||||
|
@ -916,19 +925,19 @@ function loaded() {
|
|||
deleteJSONMaterialEditor();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
elTypeIcon.style.display = "none";
|
||||
elType.innerHTML = "<i>No selection</i>";
|
||||
elPropertiesList.className = '';
|
||||
|
||||
|
||||
elID.value = "";
|
||||
elName.value = "";
|
||||
elLocked.checked = false;
|
||||
elVisible.checked = false;
|
||||
|
||||
|
||||
elParentID.value = "";
|
||||
elParentJointIndex.value = "";
|
||||
|
||||
|
||||
elColorRed.value = "";
|
||||
elColorGreen.value = "";
|
||||
elColorBlue.value = "";
|
||||
|
@ -937,15 +946,15 @@ function loaded() {
|
|||
elPositionX.value = "";
|
||||
elPositionY.value = "";
|
||||
elPositionZ.value = "";
|
||||
|
||||
|
||||
elRotationX.value = "";
|
||||
elRotationY.value = "";
|
||||
elRotationZ.value = "";
|
||||
|
||||
|
||||
elDimensionsX.value = "";
|
||||
elDimensionsY.value = "";
|
||||
elDimensionsZ.value = "";
|
||||
|
||||
|
||||
elRegistrationX.value = "";
|
||||
elRegistrationY.value = "";
|
||||
elRegistrationZ.value = "";
|
||||
|
@ -967,14 +976,14 @@ function loaded() {
|
|||
elAccelerationX.value = "";
|
||||
elAccelerationY.value = "";
|
||||
elAccelerationZ.value = "";
|
||||
|
||||
|
||||
elRestitution.value = "";
|
||||
elFriction.value = "";
|
||||
elDensity.value = "";
|
||||
|
||||
|
||||
elCollisionless.checked = false;
|
||||
elDynamic.checked = false;
|
||||
|
||||
|
||||
elCollideStatic.checked = false;
|
||||
elCollideKinematic.checked = false;
|
||||
elCollideDynamic.checked = false;
|
||||
|
@ -991,27 +1000,27 @@ function loaded() {
|
|||
elCloneableGroup.style.display = "none";
|
||||
elCloneableLimit.value = "";
|
||||
elCloneableLifetime.value = "";
|
||||
|
||||
showElements(document.getElementsByClassName('can-cast-shadow-section'), true);
|
||||
|
||||
showElements(document.getElementsByClassName('can-cast-shadow-section'), true);
|
||||
elCanCastShadow.checked = false;
|
||||
|
||||
|
||||
elCollisionSoundURL.value = "";
|
||||
elLifetime.value = "";
|
||||
elScriptURL.value = "";
|
||||
elServerScripts.value = "";
|
||||
elHyperlinkHref.value = "";
|
||||
elDescription.value = "";
|
||||
|
||||
|
||||
deleteJSONEditor();
|
||||
elUserData.value = "";
|
||||
showUserDataTextArea();
|
||||
showSaveUserDataButton();
|
||||
showNewJSONEditorButton();
|
||||
|
||||
|
||||
// Shape Properties
|
||||
elShape.value = "Cube";
|
||||
setDropdownText(elShape);
|
||||
|
||||
|
||||
// Light Properties
|
||||
elLightSpotLight.checked = false;
|
||||
elLightColor.style.backgroundColor = "rgb(" + 0 + "," + 0 + "," + 0 + ")";
|
||||
|
@ -1022,7 +1031,7 @@ function loaded() {
|
|||
elLightFalloffRadius.value = "";
|
||||
elLightExponent.value = "";
|
||||
elLightCutoff.value = "";
|
||||
|
||||
|
||||
// Model Properties
|
||||
elModelURL.value = "";
|
||||
elCompoundShapeURL.value = "";
|
||||
|
@ -1039,7 +1048,7 @@ function loaded() {
|
|||
elModelAnimationAllowTranslation.checked = false;
|
||||
elModelTextures.value = "";
|
||||
elModelOriginalTextures.value = "";
|
||||
|
||||
|
||||
// Zone Properties
|
||||
elZoneFlyingAllowed.checked = false;
|
||||
elZoneGhostingAllowed.checked = false;
|
||||
|
@ -1069,6 +1078,9 @@ function loaded() {
|
|||
elZoneHazeAltitudeEffect.checked = false;
|
||||
elZoneHazeBaseRef.value = "";
|
||||
elZoneHazeCeiling.value = "";
|
||||
elZoneBloomIntensity.value = "";
|
||||
elZoneBloomThreshold.value = "";
|
||||
elZoneBloomSize.value = "";
|
||||
elZoneSkyboxColor.style.backgroundColor = "rgb(" + 0 + "," + 0 + "," + 0 + ")";
|
||||
elZoneSkyboxColorRed.value = "";
|
||||
elZoneSkyboxColorGreen.value = "";
|
||||
|
@ -1078,7 +1090,8 @@ function loaded() {
|
|||
showElements(document.getElementsByClassName('skybox-section'), true);
|
||||
showElements(document.getElementsByClassName('ambient-section'), true);
|
||||
showElements(document.getElementsByClassName('haze-section'), true);
|
||||
|
||||
showElements(document.getElementsByClassName('bloom-section'), true);
|
||||
|
||||
// Text Properties
|
||||
elTextText.value = "";
|
||||
elTextLineHeight.value = "";
|
||||
|
@ -1091,14 +1104,14 @@ function loaded() {
|
|||
elTextBackgroundColorRed.value = "";
|
||||
elTextBackgroundColorGreen.value = "";
|
||||
elTextBackgroundColorBlue.value = "";
|
||||
|
||||
|
||||
// Image Properties
|
||||
elImageURL.value = "";
|
||||
|
||||
|
||||
// Web Properties
|
||||
elWebSourceURL.value = "";
|
||||
elWebDPI.value = "";
|
||||
|
||||
|
||||
// Material Properties
|
||||
elMaterialURL.value = "";
|
||||
elParentMaterialNameNumber.value = "";
|
||||
|
@ -1109,13 +1122,13 @@ function loaded() {
|
|||
elMaterialMappingScaleX.value = "";
|
||||
elMaterialMappingScaleY.value = "";
|
||||
elMaterialMappingRot.value = "";
|
||||
|
||||
|
||||
deleteJSONMaterialEditor();
|
||||
elMaterialData.value = "";
|
||||
showMaterialDataTextArea();
|
||||
showSaveMaterialDataButton();
|
||||
showNewJSONMaterialEditorButton();
|
||||
|
||||
|
||||
disableProperties();
|
||||
} else if (data.selections.length > 1) {
|
||||
deleteJSONEditor();
|
||||
|
@ -1252,7 +1265,7 @@ function loaded() {
|
|||
elCloneableGroup.style.display = elCloneable.checked ? "block": "none";
|
||||
elCloneableLimit.value = properties.cloneLimit;
|
||||
elCloneableLifetime.value = properties.cloneLifetime;
|
||||
|
||||
|
||||
var grabbablesSet = false;
|
||||
var parsedUserData = {};
|
||||
try {
|
||||
|
@ -1478,6 +1491,14 @@ function loaded() {
|
|||
elZoneHazeBaseRef.value = properties.haze.hazeBaseRef.toFixed(0);
|
||||
elZoneHazeCeiling.value = properties.haze.hazeCeiling.toFixed(0);
|
||||
|
||||
elZoneBloomModeInherit.checked = (properties.bloomMode === 'inherit');
|
||||
elZoneBloomModeDisabled.checked = (properties.bloomMode === 'disabled');
|
||||
elZoneBloomModeEnabled.checked = (properties.bloomMode === 'enabled');
|
||||
|
||||
elZoneBloomIntensity.value = properties.bloom.bloomIntensity.toFixed(2);
|
||||
elZoneBloomThreshold.value = properties.bloom.bloomThreshold.toFixed(2);
|
||||
elZoneBloomSize.value = properties.bloom.bloomSize.toFixed(2);
|
||||
|
||||
elShapeType.value = properties.shapeType;
|
||||
elCompoundShapeURL.value = properties.compoundShapeURL;
|
||||
|
||||
|
@ -1504,6 +1525,9 @@ function loaded() {
|
|||
|
||||
showElements(document.getElementsByClassName('haze-section'),
|
||||
elZoneHazeModeEnabled.checked);
|
||||
|
||||
showElements(document.getElementsByClassName('bloom-section'),
|
||||
elZoneBloomModeEnabled.checked);
|
||||
} else if (properties.type === "PolyVox") {
|
||||
elVoxelVolumeSizeX.value = properties.voxelVolumeSize.x.toFixed(2);
|
||||
elVoxelVolumeSizeY.value = properties.voxelVolumeSize.y.toFixed(2);
|
||||
|
@ -2069,6 +2093,18 @@ function loaded() {
|
|||
elZoneHazeBackgroundBlend.addEventListener('change',
|
||||
createEmitGroupNumberPropertyUpdateFunction('haze', 'hazeBackgroundBlend'));
|
||||
|
||||
// Bloom
|
||||
var bloomModeChanged = createZoneComponentModeChangedFunction('bloomMode',
|
||||
elZoneBloomModeInherit, elZoneBloomModeDisabled, elZoneBloomModeEnabled);
|
||||
|
||||
elZoneBloomModeInherit.addEventListener('change', bloomModeChanged);
|
||||
elZoneBloomModeDisabled.addEventListener('change', bloomModeChanged);
|
||||
elZoneBloomModeEnabled.addEventListener('change', bloomModeChanged);
|
||||
|
||||
elZoneBloomIntensity.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('bloom', 'bloomIntensity'));
|
||||
elZoneBloomThreshold.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('bloom', 'bloomThreshold'));
|
||||
elZoneBloomSize.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('bloom', 'bloomSize'));
|
||||
|
||||
var zoneSkyboxColorChangeFunction = createEmitGroupColorPropertyUpdateFunction('skybox', 'color',
|
||||
elZoneSkyboxColorRed, elZoneSkyboxColorGreen, elZoneSkyboxColorBlue);
|
||||
elZoneSkyboxColorRed.addEventListener('change', zoneSkyboxColorChangeFunction);
|
||||
|
|
|
@ -352,7 +352,7 @@ function fillImageDataFromPrevious() {
|
|||
containsGif: previousAnimatedSnapPath !== "",
|
||||
processingGif: false,
|
||||
shouldUpload: false,
|
||||
canBlast: location.domainID === Settings.getValue("previousSnapshotDomainID"),
|
||||
canBlast: snapshotDomainID === Settings.getValue("previousSnapshotDomainID"),
|
||||
isLoggedIn: isLoggedIn
|
||||
};
|
||||
imageData = [];
|
||||
|
@ -427,7 +427,7 @@ function snapshotUploaded(isError, reply) {
|
|||
}
|
||||
isUploadingPrintableStill = false;
|
||||
}
|
||||
var href, domainID;
|
||||
var href, snapshotDomainID;
|
||||
function takeSnapshot() {
|
||||
tablet.emitScriptEvent(JSON.stringify({
|
||||
type: "snapshot",
|
||||
|
@ -452,8 +452,8 @@ function takeSnapshot() {
|
|||
// Even the domainID could change (e.g., if the user falls into a teleporter while recording).
|
||||
href = location.href;
|
||||
Settings.setValue("previousSnapshotHref", href);
|
||||
domainID = location.domainID;
|
||||
Settings.setValue("previousSnapshotDomainID", domainID);
|
||||
snapshotDomainID = location.domainID;
|
||||
Settings.setValue("previousSnapshotDomainID", snapshotDomainID);
|
||||
|
||||
maybeDeleteSnapshotStories();
|
||||
|
||||
|
@ -551,7 +551,7 @@ function stillSnapshotTaken(pathStillSnapshot, notify) {
|
|||
|
||||
HMD.openTablet();
|
||||
|
||||
isDomainOpen(domainID, function (canShare) {
|
||||
isDomainOpen(snapshotDomainID, function (canShare) {
|
||||
snapshotOptions = {
|
||||
containsGif: false,
|
||||
processingGif: false,
|
||||
|
@ -594,7 +594,7 @@ function processingGifStarted(pathStillSnapshot) {
|
|||
|
||||
HMD.openTablet();
|
||||
|
||||
isDomainOpen(domainID, function (canShare) {
|
||||
isDomainOpen(snapshotDomainID, function (canShare) {
|
||||
snapshotOptions = {
|
||||
containsGif: true,
|
||||
processingGif: true,
|
||||
|
@ -622,7 +622,7 @@ function processingGifCompleted(pathAnimatedSnapshot) {
|
|||
|
||||
Settings.setValue("previousAnimatedSnapPath", pathAnimatedSnapshot);
|
||||
|
||||
isDomainOpen(domainID, function (canShare) {
|
||||
isDomainOpen(snapshotDomainID, function (canShare) {
|
||||
snapshotOptions = {
|
||||
containsGif: true,
|
||||
processingGif: false,
|
||||
|
|
Loading…
Reference in a new issue