diff --git a/assignment-client/CMakeLists.txt b/assignment-client/CMakeLists.txt index c8e26f5f462..a0ae90ca4d8 100644 --- a/assignment-client/CMakeLists.txt +++ b/assignment-client/CMakeLists.txt @@ -22,6 +22,7 @@ link_hifi_libraries( material-networking model-networking ktx shaders ) include_hifi_library_headers(procedural) +include_hifi_library_headers(entities) add_crashpad() target_breakpad() diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 7db768a1688..6aee312debf 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "AudioLogging.h" #include "AudioHelpers.h" @@ -39,6 +40,8 @@ #include "AvatarAudioStream.h" #include "InjectedAudioStream.h" #include "crash-handler/CrashHandler.h" +#include "../AssignmentDynamicFactory.h" +#include "../entities/AssignmentParentFinder.h" using namespace std; @@ -56,14 +59,15 @@ float AudioMixer::_noiseMutingThreshold{ DEFAULT_NOISE_MUTING_THRESHOLD }; float AudioMixer::_attenuationPerDoublingInDistance{ DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE }; map> AudioMixer::_availableCodecs{ }; QStringList AudioMixer::_codecPreferenceOrder{}; -vector AudioMixer::_audioZones; -vector AudioMixer::_zoneSettings; -vector AudioMixer::_zoneReverbSettings; +unordered_map AudioMixer::_audioZones; AudioMixer::AudioMixer(ReceivedMessage& message) : ThreadedAssignment(message) { + DependencyManager::registerInheritance(); + DependencyManager::set(); + // Always clear settings first // This prevents previous assignment settings from sticking around clearDomainSettings(); @@ -112,6 +116,8 @@ AudioMixer::AudioMixer(ReceivedMessage& message) : PacketReceiver::makeSourcedListenerReference(this, &AudioMixer::handleNodeMuteRequestPacket)); packetReceiver.registerListener(PacketType::KillAvatar, PacketReceiver::makeSourcedListenerReference(this, &AudioMixer::handleKillAvatarPacket)); + packetReceiver.registerListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase }, + PacketReceiver::makeSourcedListenerReference(this, &AudioMixer::handleOctreePacket)); packetReceiver.registerListenerForTypes({ PacketType::ReplicatedMicrophoneAudioNoEcho, @@ -405,7 +411,7 @@ void AudioMixer::start() { // prepare the NodeList nodeList->addSetOfNodeTypesToNodeInterestSet({ - NodeType::Agent, NodeType::EntityScriptServer, + NodeType::Agent, NodeType::EntityScriptServer, NodeType::EntityServer, NodeType::UpstreamAudioMixer, NodeType::DownstreamAudioMixer }); nodeList->linkedDataCreateCallback = [&](Node* node) { getOrCreateClientData(node); }; @@ -417,12 +423,19 @@ void AudioMixer::start() { parseSettingsObject(settingsObject); } + setupEntityQuery(); + // mix state unsigned int frame = 1; while (!_isFinished) { auto ticTimer = _ticTiming.timer(); + // Set our query each frame + { + _entityViewer.queryOctree(); + } + if (_startFrameTimestamp.time_since_epoch().count() == 0) { _startFrameTimestamp = _idealFrameTimestamp = p_high_resolution_clock::now(); } else { @@ -555,8 +568,6 @@ void AudioMixer::clearDomainSettings() { _noiseMutingThreshold = DEFAULT_NOISE_MUTING_THRESHOLD; _codecPreferenceOrder.clear(); _audioZones.clear(); - _zoneSettings.clear(); - _zoneReverbSettings.clear(); } void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { @@ -727,8 +738,13 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { if (allOk) { glm::vec3 corner(xMin, yMin, zMin); glm::vec3 dimensions(xMax - xMin, yMax - yMin, zMax - zMin); - AABox zoneAABox(corner, dimensions); - _audioZones.push_back({ zoneName, zoneAABox }); + + Transform t; + t.setTranslation(corner + 0.5f * dimensions); + t.setScale(dimensions); + _audioZones[zoneName].inverseTransform = t.getInverseMatrix(); + _audioZones[zoneName].volume = dimensions.x * dimensions.y * dimensions.z; + qCDebug(audio) << "Added zone:" << zoneName << "(corner:" << corner << ", dimensions:" << dimensions << ")"; } } @@ -749,28 +765,17 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { coefficientObject.contains(LISTENER) && coefficientObject.contains(COEFFICIENT)) { - auto itSource = find_if(begin(_audioZones), end(_audioZones), [&](const ZoneDescription& description) { - return description.name == coefficientObject.value(SOURCE).toString(); - }); - auto itListener = find_if(begin(_audioZones), end(_audioZones), [&](const ZoneDescription& description) { - return description.name == coefficientObject.value(LISTENER).toString(); - }); + auto itSource = _audioZones.find(coefficientObject.value(SOURCE).toString()); bool ok; float coefficient = coefficientObject.value(COEFFICIENT).toString().toFloat(&ok); + if (ok && coefficient <= 1.0f && itSource != _audioZones.end()) { + auto listener = coefficientObject.value(LISTENER).toString(); + itSource->second.listeners.emplace_back(listener); + itSource->second.coefficients.emplace_back(coefficient); - if (ok && coefficient <= 1.0f && - itSource != end(_audioZones) && - itListener != end(_audioZones)) { - - ZoneSettings settings; - settings.source = itSource - begin(_audioZones); - settings.listener = itListener - begin(_audioZones); - settings.coefficient = coefficient; - - _zoneSettings.push_back(settings); - qCDebug(audio) << "Added Coefficient:" << itSource->name << itListener->name << settings.coefficient; + qCDebug(audio) << "Added Coefficient:" << itSource->first << listener << coefficient; } } } @@ -791,21 +796,16 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { reverbObject.contains(WET_LEVEL)) { bool okReverbTime, okWetLevel; - auto itZone = find_if(begin(_audioZones), end(_audioZones), [&](const ZoneDescription& description) { - return description.name == reverbObject.value(ZONE).toString(); - }); + auto itZone = _audioZones.find(reverbObject.value(ZONE).toString()); float reverbTime = reverbObject.value(REVERB_TIME).toString().toFloat(&okReverbTime); float wetLevel = reverbObject.value(WET_LEVEL).toString().toFloat(&okWetLevel); - if (okReverbTime && okWetLevel && itZone != end(_audioZones)) { - ReverbSettings settings; - settings.zone = itZone - begin(_audioZones); - settings.reverbTime = reverbTime; - settings.wetLevel = wetLevel; + if (okReverbTime && okWetLevel && itZone != _audioZones.end()) { + itZone->second.reverbEnabled = true; + itZone->second.reverbTime = reverbTime; + itZone->second.wetLevel = wetLevel; - _zoneReverbSettings.push_back(settings); - - qCDebug(audio) << "Added Reverb:" << itZone->name << reverbTime << wetLevel; + qCDebug(audio) << "Added Reverb:" << itZone->first << reverbTime << wetLevel; } } } @@ -813,6 +813,108 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { } } +void AudioMixer::setupEntityQuery() { + _entityViewer.init(); + EntityTreePointer entityTree = _entityViewer.getTree(); + entityTree->setIsServer(true); + DependencyManager::registerInheritance(); + DependencyManager::set(entityTree); + + connect(entityTree.get(), &EntityTree::addingEntityPointer, this, &AudioMixer::entityAdded); + connect(entityTree.get(), &EntityTree::deletingEntityPointer, this, &AudioMixer::entityRemoved); + + // ES query: {"type": "Zone"} + QJsonObject zoneQuery; + zoneQuery["type"] = "Zone"; + + QJsonObject queryFlags; + queryFlags["includeAncestors"] = true; + queryFlags["includeDescendants"] = true; + zoneQuery["flags"] = queryFlags; + zoneQuery["name"] = true; // Handy for debugging. + + _entityViewer.getOctreeQuery().setJSONParameters(zoneQuery); +} + +void AudioMixer::handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode) { + PacketType packetType = message->getType(); + + switch (packetType) { + case PacketType::OctreeStats: + { // Ignore stats, but may have a different Entity packet appended. + OctreeHeadlessViewer::parseOctreeStats(message, senderNode); + const auto piggyBackedSizeWithHeader = message->getBytesLeftToRead(); + if (piggyBackedSizeWithHeader > 0) { + // pull out the piggybacked packet and create a new QSharedPointer for it + auto buffer = std::unique_ptr(new char[piggyBackedSizeWithHeader]); + memcpy(buffer.get(), message->getRawMessage() + message->getPosition(), piggyBackedSizeWithHeader); + + auto newPacket = NLPacket::fromReceivedPacket(std::move(buffer), piggyBackedSizeWithHeader, message->getSenderSockAddr()); + auto newMessage = QSharedPointer::create(*newPacket); + handleOctreePacket(newMessage, senderNode); + } + break; + } + + case PacketType::EntityData: + _entityViewer.processDatagram(*message, senderNode); + break; + + case PacketType::EntityErase: + _entityViewer.processEraseMessage(*message, senderNode); + break; + + default: + qCDebug(audio) << "Unexpected packet type:" << packetType; + break; + } +} + +void updateAudioZone(EntityItem* entity, std::unordered_map& audioZones) { + auto zoneEntity = (ZoneEntityItem*)entity; + auto& audioZone = audioZones[entity->getID().toString()]; + auto& audioSettings = zoneEntity->getAudioProperties(); + + vec3 dimensions = entity->getScaledDimensions(); + Transform t; + t.setTranslation(entity->getWorldPosition()); + t.setScale(dimensions); + t.setRotation(entity->getWorldOrientation()); + audioZone.inverseTransform = t.getInverseMatrix(); + audioZone.volume = dimensions.x * dimensions.y * dimensions.z; + + audioZone.reverbEnabled = audioSettings.getReverbEnabled(); + audioZone.reverbTime = audioSettings.getReverbTime(); + audioZone.wetLevel = audioSettings.getReverbWetLevel(); + + audioZone.listeners.clear(); + auto listenerZones = audioSettings.getListenerZones(); + audioZone.listeners.reserve(listenerZones.length()); + for (auto& listener : listenerZones) { + audioZone.listeners.push_back(listener.toString()); + } + + audioZone.coefficients = audioSettings.getListenerAttenuationCoefficients().toStdVector(); + + /*qCDebug(audio) << "Updated audio zone:" << entity->getID().toString() << "(position:" << t.getTranslation() + << ", dimensions:" << t.getScale() << ")";*/ +} + +void AudioMixer::entityAdded(EntityItem* entity) { + if (entity->getType() == EntityTypes::Zone) { + updateAudioZone(entity, _audioZones); + entity->registerChangeHandler([entity](const EntityItemID& entityItemID) { + updateAudioZone(entity, _audioZones); + }); + } +} + +void AudioMixer::entityRemoved(EntityItem* entity) { + if (entity->getType() == EntityTypes::Zone) { + _audioZones.erase(entity->getID().toString()); + } +} + AudioMixer::Timer::Timing::Timing(uint64_t& sum) : _sum(sum) { _timing = p_high_resolution_clock::now(); } diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 6365298d873..22455c6a127 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -14,7 +14,7 @@ #include -#include +#include #include #include #include @@ -25,6 +25,8 @@ #include "AudioMixerStats.h" #include "AudioMixerWorkerPool.h" +#include "../entities/EntityTreeHeadlessViewer.h" + class PositionalAudioStream; class AvatarAudioStream; class AudioHRTF; @@ -36,28 +38,22 @@ class AudioMixer : public ThreadedAssignment { public: AudioMixer(ReceivedMessage& message); - - struct ZoneDescription { - QString name; - AABox area; - }; struct ZoneSettings { - int source; - int listener; - float coefficient; - }; - struct ReverbSettings { - int zone; - float reverbTime; - float wetLevel; + glm::mat4 inverseTransform; + float volume { FLT_MAX }; + + bool reverbEnabled { false }; + float reverbTime { 0.0f }; + float wetLevel { 0.0f }; + + std::vector listeners; + std::vector coefficients; }; static int getStaticJitterFrames() { return _numStaticJitterFrames; } static bool shouldMute(float quietestFrame) { return quietestFrame > _noiseMutingThreshold; } static float getAttenuationPerDoublingInDistance() { return _attenuationPerDoublingInDistance; } - static const std::vector& getAudioZones() { return _audioZones; } - static const std::vector& getZoneSettings() { return _zoneSettings; } - static const std::vector& getReverbSettings() { return _zoneReverbSettings; } + static const std::unordered_map& getAudioZones() { return _audioZones; } static const std::pair negotiateCodec(std::vector codecs); static bool shouldReplicateTo(const Node& from, const Node& to) { @@ -72,12 +68,17 @@ public slots: void run() override; void sendStatsPacket() override; + // Audio zone possibly changed + void entityAdded(EntityItem* entity); + void entityRemoved(EntityItem* entity); + private slots: // packet handlers void handleMuteEnvironmentPacket(QSharedPointer packet, SharedNodePointer sendingNode); void handleNodeMuteRequestPacket(QSharedPointer packet, SharedNodePointer sendingNode); void handleNodeKilled(SharedNodePointer killedNode); void handleKillAvatarPacket(QSharedPointer packet, SharedNodePointer sendingNode); + void handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode); void queueAudioPacket(QSharedPointer packet, SharedNodePointer sendingNode); void queueReplicatedAudioPacket(QSharedPointer packet); @@ -146,14 +147,17 @@ private slots: static std::map _availableCodecs; static QStringList _codecPreferenceOrder; - static std::vector _audioZones; - static std::vector _zoneSettings; - static std::vector _zoneReverbSettings; + static std::unordered_map _audioZones; float _throttleStartTarget = 0.9f; float _throttleBackoffTarget = 0.44f; AudioMixerWorker::SharedData _workerSharedData; + + void setupEntityQuery(); + + // Attach to entity tree for audio zone info. + EntityTreeHeadlessViewer _entityViewer; }; #endif // hifi_AudioMixer_h diff --git a/assignment-client/src/audio/AudioMixerWorker.cpp b/assignment-client/src/audio/AudioMixerWorker.cpp index ffe89f1313d..7a650cd3408 100644 --- a/assignment-client/src/audio/AudioMixerWorker.cpp +++ b/assignment-client/src/audio/AudioMixerWorker.cpp @@ -646,27 +646,36 @@ void sendMutePacket(const SharedNodePointer& node, AudioMixerClientData& data) { data.setShouldMuteClient(false); } +const AABox UNIT_BOX(vec3(-0.5f), vec3(1.0f)); void sendEnvironmentPacket(const SharedNodePointer& node, AudioMixerClientData& data) { bool hasReverb = false; float reverbTime, wetLevel; - auto& reverbSettings = AudioMixer::getReverbSettings(); auto& audioZones = AudioMixer::getAudioZones(); AvatarAudioStream* stream = data.getAvatarAudioStream(); - glm::vec3 streamPosition = stream->getPosition(); + vec4 streamPosition = vec4(stream->getPosition(), 1.0f); // find reverb properties - for (const auto& settings : reverbSettings) { - AABox box = audioZones[settings.zone].area; - if (box.contains(streamPosition)) { - hasReverb = true; - reverbTime = settings.reverbTime; - wetLevel = settings.wetLevel; - break; + QString bestZone; + float bestZoneVolume = FLT_MAX; + for (const auto& zone : audioZones) { + if (zone.second.reverbEnabled) { + vec4 localPosition = zone.second.inverseTransform * streamPosition; + if (UNIT_BOX.contains(localPosition) && zone.second.volume < bestZoneVolume) { + bestZone = zone.first; + bestZoneVolume = zone.second.volume; + } } } + if (bestZoneVolume < FLT_MAX) { + const auto& zone = audioZones.at(bestZone); + hasReverb = zone.reverbEnabled; + reverbTime = zone.reverbTime; + wetLevel = zone.wetLevel; + } + // check if data changed bool dataChanged = (stream->hasReverb() != hasReverb) || (stream->hasReverb() && (stream->getRevebTime() != reverbTime || stream->getWetLevel() != wetLevel)); @@ -759,18 +768,40 @@ float computeGain(float primaryAvatarGain, } auto& audioZones = AudioMixer::getAudioZones(); - auto& zoneSettings = AudioMixer::getZoneSettings(); // find distance attenuation coefficient float attenuationPerDoublingInDistance = AudioMixer::getAttenuationPerDoublingInDistance(); - for (const auto& settings : zoneSettings) { - if (audioZones[settings.source].area.contains(streamToAdd.getPosition()) && - audioZones[settings.listener].area.contains(listeningNodeStream.getPosition())) { - attenuationPerDoublingInDistance = settings.coefficient; - break; + + float bestZonesVolume = FLT_MAX; + float bestZonesCoefficient; + for (const auto& sourceZone : audioZones) { + if (sourceZone.second.listeners.size() > 0 && sourceZone.second.listeners.size() == sourceZone.second.coefficients.size()) { + vec4 localSourcePosition = sourceZone.second.inverseTransform * vec4(streamToAdd.getPosition(), 1.0f); + if (UNIT_BOX.contains(localSourcePosition)) { + size_t listenerIndex = 0; + for (const auto& listener : sourceZone.second.listeners) { + const auto& listenerZone = audioZones.find(listener); + if (listenerZone != audioZones.end()) { + vec4 localListenerPosition = listenerZone->second.inverseTransform * vec4(listeningNodeStream.getPosition(), 1.0f); + if (UNIT_BOX.contains(localListenerPosition)) { + // This isn't an exact solution, but we target the smallest sum of volumes of the source and listener zones + const float zonesVolume = sourceZone.second.volume + listenerZone->second.volume; + if (zonesVolume < bestZonesVolume) { + bestZonesVolume = zonesVolume; + bestZonesCoefficient = sourceZone.second.coefficients[listenerIndex]; + } + } + } + listenerIndex++; + } + } } } + if (bestZonesVolume < FLT_MAX) { + attenuationPerDoublingInDistance = bestZonesCoefficient; + } + if (attenuationPerDoublingInDistance < 0.0f) { // translate a negative zone setting to distance limit const float MIN_DISTANCE_LIMIT = ATTN_DISTANCE_REF + 1.0f; // silent after 1m diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 80c3e1ae953..1daea81ed05 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -1081,11 +1081,12 @@ void AvatarMixer::parseDomainServerSettings(const QJsonObject& domainSettings) { void AvatarMixer::setupEntityQuery() { _entityViewer.init(); EntityTreePointer entityTree = _entityViewer.getTree(); + entityTree->setIsServer(true); DependencyManager::registerInheritance(); DependencyManager::set(entityTree); connect(entityTree.get(), &EntityTree::addingEntityPointer, this, &AvatarMixer::entityAdded); - connect(entityTree.get(), &EntityTree::deletingEntityPointer, this, &AvatarMixer::entityChange); + connect(entityTree.get(), &EntityTree::deletingEntityPointer, this, &AvatarMixer::entityRemoved); // ES query: {"avatarPriority": true, "type": "Zone"} QJsonObject priorityZoneQuery; @@ -1140,7 +1141,7 @@ void AvatarMixer::entityAdded(EntityItem* entity) { if (entity->getType() == EntityTypes::Zone) { _dirtyHeroStatus = true; entity->registerChangeHandler([this](const EntityItemID& entityItemID) { - entityChange(); + _dirtyHeroStatus = true; }); } } @@ -1151,10 +1152,6 @@ void AvatarMixer::entityRemoved(EntityItem * entity) { } } -void AvatarMixer::entityChange() { - _dirtyHeroStatus = true; -} - void AvatarMixer::aboutToFinish() { DependencyManager::destroy(); DependencyManager::destroy(); diff --git a/assignment-client/src/avatars/AvatarMixer.h b/assignment-client/src/avatars/AvatarMixer.h index 9af377231ec..78e158894df 100644 --- a/assignment-client/src/avatars/AvatarMixer.h +++ b/assignment-client/src/avatars/AvatarMixer.h @@ -52,7 +52,6 @@ public slots: // Avatar zone possibly changed void entityAdded(EntityItem* entity); void entityRemoved(EntityItem* entity); - void entityChange(); private slots: void queueIncomingPacket(QSharedPointer message, SharedNodePointer node); diff --git a/assignment-client/src/avatars/ScriptableAvatar.h b/assignment-client/src/avatars/ScriptableAvatar.h index 7e79d25cd0f..97a5f44adc3 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.h +++ b/assignment-client/src/avatars/ScriptableAvatar.h @@ -67,8 +67,6 @@ * @property {boolean} lookAtSnappingEnabled=true - true if the avatar's eyes snap to look at another avatar's * eyes when the other avatar is in the line of sight and also has lookAtSnappingEnabled == true. * @property {string} skeletonModelURL - The avatar's FST file. - * @property {AttachmentData[]} attachmentData - Information on the avatar's attachments. - *

Deprecated: This property is deprecated and will be removed. Use avatar entities instead.

* @property {string[]} jointNames - The list of joints in the current avatar model. Read-only. * @property {Uuid} sessionUUID - Unique ID of the avatar in the domain. Read-only. * @property {Mat4} sensorToWorldMatrix - The scale, rotation, and translation transform from the user's real world to the diff --git a/assignment-client/src/entities/EntityServer.cpp b/assignment-client/src/entities/EntityServer.cpp index ea3ebd07f69..ec83e280c2b 100644 --- a/assignment-client/src/entities/EntityServer.cpp +++ b/assignment-client/src/entities/EntityServer.cpp @@ -16,9 +16,11 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -49,6 +51,9 @@ EntityServer::EntityServer(ReceivedMessage& message) : DependencyManager::set(); // ModelFormatRegistry must be defined before ModelCache. See the ModelCache ctor DependencyManager::set(); + DependencyManager::set(); + DependencyManager::set(); + auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListenerForTypes({ PacketType::EntityAdd, PacketType::EntityClone, @@ -71,6 +76,8 @@ EntityServer::~EntityServer() { void EntityServer::aboutToFinish() { DependencyManager::get()->cleanup(); + DependencyManager::destroy(); + DependencyManager::destroy(); DependencyManager::destroy(); OctreeServer::aboutToFinish(); @@ -90,6 +97,7 @@ OctreePointer EntityServer::createTree() { EntityTreePointer tree = std::make_shared(true); tree->createRootElement(); tree->addNewlyCreatedHook(this); + tree->setIsEntityServer(true); if (!_entitySimulation) { SimpleEntitySimulationPointer simpleSimulation { new SimpleEntitySimulation() }; simpleSimulation->setEntityTree(tree); diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index d9a2faa2de9..983b88e1763 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1239,7 +1239,7 @@ void OctreeServer::beginRunning() { // we need to ask the DS about agents so we can ping/reply with them nodeList->addSetOfNodeTypesToNodeInterestSet({ NodeType::Agent, NodeType::EntityScriptServer, - NodeType::AvatarMixer }); + NodeType::AvatarMixer, NodeType::AudioMixer }); beforeRun(); // after payload has been processed diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index 2b23434195b..7c288334bac 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -316,6 +316,7 @@ void EntityScriptServer::run() { entityScriptingInterface->setEntityTree(_entityViewer.getTree()); auto treePtr = _entityViewer.getTree(); + treePtr->setIsServer(true); DependencyManager::set(treePtr); if (!_entitySimulation) { diff --git a/cmake/macros/GenerateEntityProperties.cmake b/cmake/macros/GenerateEntityProperties.cmake new file mode 100644 index 00000000000..ad5671b4969 --- /dev/null +++ b/cmake/macros/GenerateEntityProperties.cmake @@ -0,0 +1,625 @@ +# +# GenerateEntityProperites.cmake +# +# Created by HifiExperiments on 7/21/24 +# Copyright 2024 Overte e.V. +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# + +macro(CAPITALIZE_FIRST_LETTER) + string(SUBSTRING ${ARGV0} 0 1 FIRST_LETTER) + string(TOUPPER ${FIRST_LETTER} FIRST_LETTER) + string(REGEX REPLACE "^.(.*)" "${FIRST_LETTER}\\1" CAPITALIZE_RESULT "${ARGV0}") +endmacro() + +macro(GENERATE_ENTITY_PROPERTIES) + message(STATUS "Entity property processing start") + + # Define most of our variables. Some are initialized only in the loops below. + set(ENTITY_ITEM_PROPERTY_DEFINES "") + set(ENTITY_ITEM_PROPERTY_INCLUDES "#include \"EntityItem.h\"\n") + set(ENTITY_ITEM_PROPERTY_FRIENDS "\tfriend class EntityItem;\n") + set(ENTITY_ITEM_PROPERTY_STATIC_GROUPS "") + set(ENTITY_ITEM_PROPERTY_DEBUG_DUMP_GROUPS "") + set(ENTITY_ITEM_PROPERTY_CHANGED_PROPERTIES "") + set(ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT "") + set(ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT "") + set(ENTITY_ITEM_PROPERTY_MERGE "") + set(ENTITY_ITEM_PROPERTY_ADD_TO_MAP "") + set(ENTITY_ITEM_PROPERTY_APPEND "") + set(ENTITY_ITEM_PROPERTY_READ "") + set(ENTITY_ITEM_PROPERTY_MARK_CHANGED "") + set(ENTITY_ITEM_PROPERTY_LIST_CHANGED "") + set(ENTITY_ITEM_PROPERTY_DEBUG "") + set(CURRENT_TYPE "Base") + list(APPEND ENTITY_TYPES ${CURRENT_TYPE}) + set(ENTITY_PROPERTY_FLAGS "") + + # These types are passed by value everywhere, anything else is passed by reference. + set(NON_REF_TYPES "bool" "int" "float" "uint8_t" "uint16_t" "quint16" "uint32_t" "quint32" "quint64") + # These property sections are shared by all types. "Common" must be at the end. + set(BASE_ENTITY_TYPES "Core" "Physics" "Cloning" "Scripts" "LocalProps" "Common") + # These types have special methods for converting to/from scripts. + set(TYPED_SCRIPT_CONVERT "u8vec3Color" "vec3Color" "qVectorVec3Color") + set(COMMON_PROPS false) + set(LOCAL_PROPS false) + set(NEEDS_CLOSING_BRACE false) + + # All (non-group) properties are defined in EntityItemProperties.txt. We loop over them in order. + file(STRINGS src/EntityItemProperties.txt ENTITY_PROPERTIES_FILE) + while(ENTITY_PROPERTIES_FILE) + list(POP_FRONT ENTITY_PROPERTIES_FILE LINE) + + # Single-word lines represent sections of properties, which can be base properties like "Physics" or + # Entity types like "Model". We use the section names to generate comments, and also handle indentation + # and opening/closing braces. + if(NOT LINE MATCHES ".*:.*") + if(LINE STREQUAL "Common") + set(COMMON_PROPS true) + else() + set(COMMON_PROPS false) + endif() + if(LINE STREQUAL "LocalProps") + set(LOCAL_PROPS true) + else() + set(LOCAL_PROPS false) + endif() + list(APPEND ENTITY_PROPERTY_FLAGS ${LINE}) + string(CONCAT ENTITY_ITEM_PROPERTY_DEFINES "${ENTITY_ITEM_PROPERTY_DEFINES}" "\t// ${LINE}\n") + string(CONCAT ENTITY_ITEM_PROPERTY_CHANGED_PROPERTIES "${ENTITY_ITEM_PROPERTY_CHANGED_PROPERTIES}" "\t// ${LINE}\n") + if(NEEDS_CLOSING_BRACE) + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT}" "\t}\n") + string(CONCAT ENTITY_ITEM_PROPERTY_APPEND "${ENTITY_ITEM_PROPERTY_APPEND}" "\t\t\t}\n") + string(CONCAT ENTITY_ITEM_PROPERTY_READ "${ENTITY_ITEM_PROPERTY_READ}" "\t}\n") + endif() + if(NOT COMMON_PROPS) + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT}" "\t// ${LINE}\n") + string(CONCAT ENTITY_ITEM_PROPERTY_APPEND "${ENTITY_ITEM_PROPERTY_APPEND}" "\t\t\t// ${LINE}\n") + string(CONCAT ENTITY_ITEM_PROPERTY_READ "${ENTITY_ITEM_PROPERTY_READ}" "\t// ${LINE}\n") + endif() + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT}" "\t// ${LINE}\n") + string(CONCAT ENTITY_ITEM_PROPERTY_MERGE "${ENTITY_ITEM_PROPERTY_MERGE}" "\t// ${LINE}\n") + string(CONCAT ENTITY_ITEM_PROPERTY_ADD_TO_MAP "${ENTITY_ITEM_PROPERTY_ADD_TO_MAP}" "\t\t// ${LINE}\n") + string(CONCAT ENTITY_ITEM_PROPERTY_MARK_CHANGED "${ENTITY_ITEM_PROPERTY_MARK_CHANGED}" "\t// ${LINE}\n") + string(CONCAT ENTITY_ITEM_PROPERTY_LIST_CHANGED "${ENTITY_ITEM_PROPERTY_LIST_CHANGED}" "\t// ${LINE}\n") + + if(NOT ${LINE} IN_LIST BASE_ENTITY_TYPES) + string(CONCAT ENTITY_ITEM_PROPERTY_INCLUDES "${ENTITY_ITEM_PROPERTY_INCLUDES}" "#include \"${LINE}EntityItem.h\"\n") + string(CONCAT ENTITY_ITEM_PROPERTY_FRIENDS "${ENTITY_ITEM_PROPERTY_FRIENDS}" "\tfriend class ${LINE}EntityItem;\n") + if(LINE STREQUAL "Shape") + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT}" "\tif (_type == EntityTypes::Box) {\n\t\tCOPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, QString(\"Box\"));\n\t}\n") + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT}" "\tif (_type == EntityTypes::Sphere) {\n\t\tCOPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, QString(\"Sphere\"));\n\t}\n") + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT}" "\tif (_type == EntityTypes::Box || _type == EntityTypes::Sphere || _type == EntityTypes::Shape) {\n") + string(CONCAT ENTITY_ITEM_PROPERTY_APPEND "${ENTITY_ITEM_PROPERTY_APPEND}" "\t\t\tif (properties.getType() == EntityTypes::Box || properties.getType() == EntityTypes::Sphere || properties.getType() == EntityTypes::Shape) {\n") + string(CONCAT ENTITY_ITEM_PROPERTY_READ "${ENTITY_ITEM_PROPERTY_READ}" "\tif (properties.getType() == EntityTypes::Box || properties.getType() == EntityTypes::Sphere || properties.getType() == EntityTypes::Shape) {\n") + else() + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT}" "\tif (_type == EntityTypes::${LINE}) {\n") + string(CONCAT ENTITY_ITEM_PROPERTY_APPEND "${ENTITY_ITEM_PROPERTY_APPEND}" "\t\t\tif (properties.getType() == EntityTypes::${LINE}) {\n") + string(CONCAT ENTITY_ITEM_PROPERTY_READ "${ENTITY_ITEM_PROPERTY_READ}" "\tif (properties.getType() == EntityTypes::${LINE}) {\n") + endif() + set(NEEDS_CLOSING_BRACE true) + endif() + + if (NEEDS_CLOSING_BRACE) + set(CURRENT_TYPE ${LINE}) + list(APPEND ENTITY_TYPES ${LINE}) + endif() + + if (NOT COMMON_PROPS) + string(CONCAT ${CURRENT_TYPE}_REQUESTED_PROPS "${${CURRENT_TYPE}_REQUESTED_PROPS}" "\t// ${LINE}\n") + string(CONCAT ${CURRENT_TYPE}_ENTITY_APPEND "${${CURRENT_TYPE}_ENTITY_APPEND}" "\t\t// ${LINE}\n") + string(CONCAT ${CURRENT_TYPE}_ENTITY_READ "${${CURRENT_TYPE}_ENTITY_READ}" "\t// ${LINE}\n") + string(CONCAT ${CURRENT_TYPE}_ENTITY_COPY_TO "${${CURRENT_TYPE}_ENTITY_COPY_TO}" "\t// ${LINE}\n") + if (NOT LOCAL_PROPS) + string(CONCAT ${CURRENT_TYPE}_ENTITY_SET_FROM "${${CURRENT_TYPE}_ENTITY_SET_FROM}" "\t// ${LINE}\n") + endif() + endif() + elseif(LINE MATCHES "group:.*,") + # Lines that start with "group:" represent property groups like "grab". + string(REGEX MATCH ".*group:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" ENTITY_PROPERTY_GROUP ${LINE}) + set(ENTITY_PROPERTY_GROUP ${CMAKE_MATCH_1}) + CAPITALIZE_FIRST_LETTER(${ENTITY_PROPERTY_GROUP}) + set(ENTITY_PROPERTY_GROUP_CAPS ${CAPITALIZE_RESULT}) + # Most property groups have the same filenames, e.g. "pulse" to "PulsePropertyGroup", but some are different, + # e.g. "ring" is "RingGizmoPropertyGroup" + string(REGEX MATCH ".*type:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" ENTITY_PROPERTY_GROUP_TYPE ${LINE}) + if (CMAKE_MATCH_1) + set(ENTITY_PROPERTY_GROUP_TYPE "${CMAKE_MATCH_1}PropertyGroup") + else() + set(ENTITY_PROPERTY_GROUP_TYPE "${ENTITY_PROPERTY_GROUP_CAPS}PropertyGroup") + endif() + + if(NOT LINE MATCHES ".*common( |,).*") + list(APPEND ENTITY_PROPERTY_FLAGS "group:${ENTITY_PROPERTY_GROUP}") + string(CONCAT ENTITY_ITEM_PROPERTY_DEFINES "${ENTITY_ITEM_PROPERTY_DEFINES}" "\tDEFINE_PROPERTY_GROUP(${ENTITY_PROPERTY_GROUP_CAPS}, ${ENTITY_PROPERTY_GROUP}, ${ENTITY_PROPERTY_GROUP_TYPE});\n") + string(CONCAT ENTITY_ITEM_PROPERTY_INCLUDES "${ENTITY_ITEM_PROPERTY_INCLUDES}" "#include \"${ENTITY_PROPERTY_GROUP_TYPE}.h\"\n") + string(CONCAT ENTITY_ITEM_PROPERTY_STATIC_GROUPS "${ENTITY_ITEM_PROPERTY_STATIC_GROUPS}" "${ENTITY_PROPERTY_GROUP_TYPE} EntityItemProperties::_static${ENTITY_PROPERTY_GROUP_CAPS};\n") + string(CONCAT ENTITY_ITEM_PROPERTY_DEBUG_DUMP_GROUPS "${ENTITY_ITEM_PROPERTY_DEBUG_DUMP_GROUPS}" "\tget${ENTITY_PROPERTY_GROUP_CAPS}().debugDump();\n") + string(CONCAT ENTITY_ITEM_PROPERTY_CHANGED_PROPERTIES "${ENTITY_ITEM_PROPERTY_CHANGED_PROPERTIES}" "\tchangedProperties += _${ENTITY_PROPERTY_GROUP}.getChangedProperties();\n") + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT}" "\t_${ENTITY_PROPERTY_GROUP}.copyFromScriptValue(object, namesSet, _defaultSettings);\n") + string(CONCAT ENTITY_ITEM_PROPERTY_MERGE "${ENTITY_ITEM_PROPERTY_MERGE}" "\t_${ENTITY_PROPERTY_GROUP}.merge(other._${ENTITY_PROPERTY_GROUP});\n") + string(CONCAT ENTITY_ITEM_PROPERTY_ADD_TO_MAP "${ENTITY_ITEM_PROPERTY_ADD_TO_MAP}" "\t\t${ENTITY_PROPERTY_GROUP_TYPE}::addPropertyMap(_propertyInfos, _enumsToPropertyStrings);\n") + string(CONCAT ENTITY_ITEM_PROPERTY_MARK_CHANGED "${ENTITY_ITEM_PROPERTY_MARK_CHANGED}" "\t_${ENTITY_PROPERTY_GROUP}.markAllChanged();\n") + string(CONCAT ENTITY_ITEM_PROPERTY_LIST_CHANGED "${ENTITY_ITEM_PROPERTY_LIST_CHANGED}" "\tget${ENTITY_PROPERTY_GROUP_CAPS}().listChangedProperties(out);\n") + endif() + if(NEEDS_CLOSING_BRACE) + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT}" "\t") + string(CONCAT ENTITY_ITEM_PROPERTY_APPEND "${ENTITY_ITEM_PROPERTY_APPEND}" "\t") + string(CONCAT ENTITY_ITEM_PROPERTY_READ "${ENTITY_ITEM_PROPERTY_READ}" "\t") + endif() + if(NOT COMMON_PROPS) + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT}" "\t_${ENTITY_PROPERTY_GROUP}.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags, isMyOwnAvatarEntity);\n") + string(CONCAT ENTITY_ITEM_PROPERTY_APPEND "${ENTITY_ITEM_PROPERTY_APPEND}" "\t\t\t_static${ENTITY_PROPERTY_GROUP_CAPS}.setProperties(properties);\n") + if (NEEDS_CLOSING_BRACE) + string(CONCAT ENTITY_ITEM_PROPERTY_APPEND "${ENTITY_ITEM_PROPERTY_APPEND}" "\t") + endif() + string(CONCAT ENTITY_ITEM_PROPERTY_APPEND "${ENTITY_ITEM_PROPERTY_APPEND}" "\t\t\t_static${ENTITY_PROPERTY_GROUP_CAPS}.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState);\n") + string(CONCAT ENTITY_ITEM_PROPERTY_READ "${ENTITY_ITEM_PROPERTY_READ}" "\tproperties.get${ENTITY_PROPERTY_GROUP_CAPS}().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);\n") + string(CONCAT ${CURRENT_TYPE}_ENTITY_PROPS "${${CURRENT_TYPE}_ENTITY_PROPS}" "\t${ENTITY_PROPERTY_GROUP_TYPE} _${ENTITY_PROPERTY_GROUP}Properties;\n") + string(CONCAT ${CURRENT_TYPE}_REQUESTED_PROPS "${${CURRENT_TYPE}_REQUESTED_PROPS}" "\trequestedProperties += _${ENTITY_PROPERTY_GROUP}Properties.getEntityProperties(params);\n") + string(CONCAT ${CURRENT_TYPE}_ENTITY_APPEND "${${CURRENT_TYPE}_ENTITY_APPEND}" "\twithReadLock([&] {\n\t\t_${ENTITY_PROPERTY_GROUP}Properties.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState);\n\t});\n") + if (NOT LINE MATCHES ".*customVariableRead( |,).*") + string(CONCAT ${CURRENT_TYPE}_ENTITY_READ "${${CURRENT_TYPE}_ENTITY_READ}" "\twithWriteLock([&] {\n\t\tint bytesFrom${ENTITY_PROPERTY_GROUP_CAPS} = _${ENTITY_PROPERTY_GROUP}Properties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData, somethingChanged);\n\t\tbytesRead += bytesFrom${ENTITY_PROPERTY_GROUP_CAPS};\n\t\tdataAt += bytesFrom${ENTITY_PROPERTY_GROUP_CAPS};\n\t});\n") + endif() + string(CONCAT ${CURRENT_TYPE}_ENTITY_COPY_TO "${${CURRENT_TYPE}_ENTITY_COPY_TO}" "\twithReadLock([&] {\n\t\t_${ENTITY_PROPERTY_GROUP}Properties.getProperties(properties);\n\t});\n") + if (NOT LINE MATCHES ".*customVariableSetFrom( |,).*") + if (LINE MATCHES ".*recordChange( |,).*") + string(CONCAT ${CURRENT_TYPE}_ENTITY_SET_FROM "${${CURRENT_TYPE}_ENTITY_SET_FROM}" "\twithWriteLock([&] {\n\t\t_${ENTITY_PROPERTY_GROUP}PropertiesChanged |= _${ENTITY_PROPERTY_GROUP}Properties.setProperties(properties);\n\t});\n") + elseif (LINE MATCHES ".*renderUpdateOnSet( |,).*") + string(CONCAT ${CURRENT_TYPE}_ENTITY_SET_FROM "${${CURRENT_TYPE}_ENTITY_SET_FROM}" "\twithWriteLock([&] {\n\t\tbool ${ENTITY_PROPERTY_GROUP}PropertiesChanged = _${ENTITY_PROPERTY_GROUP}Properties.setProperties(properties);\n\t\tsomethingChanged |= ${ENTITY_PROPERTY_GROUP}PropertiesChanged;\n\t\t_needsRenderUpdate |= ${ENTITY_PROPERTY_GROUP}PropertiesChanged;\n\t});\n") + else() + string(CONCAT ${CURRENT_TYPE}_ENTITY_SET_FROM "${${CURRENT_TYPE}_ENTITY_SET_FROM}" "\twithWriteLock([&] {\n\t\tbool ${ENTITY_PROPERTY_GROUP}PropertiesChanged = _${ENTITY_PROPERTY_GROUP}Properties.setProperties(properties);\n\t\tsomethingChanged |= ${ENTITY_PROPERTY_GROUP}PropertiesChanged;\n\t});\n") + endif() + endif() + string(CONCAT ${CURRENT_TYPE}_ENTITY_DEBUG "${${CURRENT_TYPE}_ENTITY_DEBUG}" "\t_${ENTITY_PROPERTY_GROUP}Properties.debugDump();\n") + endif() + else() + # Everything else is just a normal, non-group property. Properties support a wide variety of settings, + # which control things like default/min/max, script conversions, and networking behavior. + string(REGEX MATCH ".*enum:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" ENTITY_PROPERTY_ENUM ${LINE}) + string(CONCAT ENTITY_PROPERTY_ENUM "PROP_" ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*prop:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" ENTITY_PROPERTY_NAME ${LINE}) + set(ENTITY_PROPERTY_NAME ${CMAKE_MATCH_1}) + CAPITALIZE_FIRST_LETTER(${ENTITY_PROPERTY_NAME}) + set(ENTITY_PROPERTY_NAME_CAPS ${CAPITALIZE_RESULT}) + string(REGEX MATCH ".*type:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" ENTITY_PROPERTY_TYPE ${LINE}) + set(ENTITY_PROPERTY_TYPE ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*default:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" ENTITY_PROPERTY_DEFAULT ${LINE}) + set(ENTITY_PROPERTY_DEFAULT ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*min:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" ENTITY_PROPERTY_MIN ${LINE}) + set(ENTITY_PROPERTY_MIN ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*max:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" ENTITY_PROPERTY_MAX ${LINE}) + set(ENTITY_PROPERTY_MAX ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*fromScriptType:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" ENTITY_PROPERTY_FROM_SCRIPT_TYPE ${LINE}) + set(ENTITY_PROPERTY_FROM_SCRIPT_TYPE ${CMAKE_MATCH_1}) + if (NOT ENTITY_PROPERTY_FROM_SCRIPT_TYPE) + set(ENTITY_PROPERTY_FROM_SCRIPT_TYPE ${ENTITY_PROPERTY_TYPE}) + endif() + string(REGEX MATCH ".*getter:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" ENTITY_PROPERTY_GETTER ${LINE}) + set(ENTITY_PROPERTY_GETTER ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*setter:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" ENTITY_PROPERTY_SETTER ${LINE}) + set(ENTITY_PROPERTY_SETTER ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*networkGetter:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" ENTITY_PROPERTY_NETWORK_GETTER ${LINE}) + set(ENTITY_PROPERTY_NETWORK_GETTER ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*variableNetworkGetter:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" ENTITY_VARIABLE_NETWORK_GETTER ${LINE}) + set(ENTITY_VARIABLE_NETWORK_GETTER ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*variableNetworkSetter:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" ENTITY_VARIABLE_NETWORK_SETTER ${LINE}) + set(ENTITY_VARIABLE_NETWORK_SETTER ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*variableCopyGetter:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" ENTITY_VARIABLE_COPY_GETTER ${LINE}) + set(ENTITY_VARIABLE_COPY_GETTER ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*variableCopySetter:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" ENTITY_VARIABLE_COPY_SETTER ${LINE}) + set(ENTITY_VARIABLE_COPY_SETTER ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*readType:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" ENTITY_PROPERTY_READ_TYPE ${LINE}) + set(ENTITY_PROPERTY_READ_TYPE ${CMAKE_MATCH_1}) + if (NOT ENTITY_PROPERTY_READ_TYPE) + set(ENTITY_PROPERTY_READ_TYPE ${ENTITY_PROPERTY_TYPE}) + endif() + string(REGEX MATCH ".*debugString:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" ENTITY_PROPERTY_DEBUG_STRING ${LINE}) + set(ENTITY_PROPERTY_DEBUG_STRING ${CMAKE_MATCH_1}) + if (NOT ENTITY_PROPERTY_DEBUG_STRING) + set(ENTITY_PROPERTY_DEBUG_STRING "\"\"") + endif() + string(REGEX MATCH ".*debugGetter:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" ENTITY_PROPERTY_DEBUG_GETTER ${LINE}) + set(ENTITY_PROPERTY_DEBUG_GETTER ${CMAKE_MATCH_1}) + + if(NOT LINE MATCHES ".*legacy( |,).*") + if(NOT LINE MATCHES ".*common( |,).*") + list(APPEND ENTITY_PROPERTY_FLAGS ${ENTITY_PROPERTY_ENUM}) + set(DEFINE_FUNC "DEFINE_PROPERTY_REF") + if(LINE MATCHES ".*enum( |,).*") + set(DEFINE_FUNC "DEFINE_PROPERTY_REF_ENUM") + elseif(${ENTITY_PROPERTY_TYPE} IN_LIST NON_REF_TYPES) + set(DEFINE_FUNC "DEFINE_PROPERTY") + elseif(LINE MATCHES ".*propertySetter( |,).*") + set(DEFINE_FUNC "DEFINE_PROPERTY_REF_WITH_SETTER") + endif() + string(CONCAT ENTITY_ITEM_PROPERTY_DEFINES "${ENTITY_ITEM_PROPERTY_DEFINES}" "\t${DEFINE_FUNC}(${ENTITY_PROPERTY_NAME_CAPS}, ${ENTITY_PROPERTY_NAME}, ${ENTITY_PROPERTY_TYPE}, ${ENTITY_PROPERTY_DEFAULT});\n") + string(CONCAT ENTITY_ITEM_PROPERTY_CHANGED_PROPERTIES "${ENTITY_ITEM_PROPERTY_CHANGED_PROPERTIES}" "\tCHECK_PROPERTY_CHANGE(${ENTITY_PROPERTY_ENUM}, ${ENTITY_PROPERTY_NAME});\n") + if(NOT LINE MATCHES ".*noScript( |,).*") + if(LINE MATCHES ".*readOnly( |,).*") + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT}" "\tif (!honorReadOnly) {\n\t") + endif() + if(LINE MATCHES ".*enum( |,).*") + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT}" "\tCOPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(${ENTITY_PROPERTY_NAME}, ${ENTITY_PROPERTY_NAME_CAPS});\n") + elseif(ENTITY_PROPERTY_GETTER AND ENTITY_PROPERTY_SETTER) + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT}" "\tCOPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(${ENTITY_PROPERTY_NAME}, ${ENTITY_PROPERTY_FROM_SCRIPT_TYPE}, ${ENTITY_PROPERTY_SETTER}, ${ENTITY_PROPERTY_GETTER});\n") + else() + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT}" "\tCOPY_PROPERTY_FROM_QSCRIPTVALUE(${ENTITY_PROPERTY_NAME}, ${ENTITY_PROPERTY_TYPE}, set${ENTITY_PROPERTY_NAME_CAPS});\n") + endif() + if(LINE MATCHES ".*readOnly( |,).*") + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT}" "\t}\n") + endif() + endif() + string(CONCAT ENTITY_ITEM_PROPERTY_MERGE "${ENTITY_ITEM_PROPERTY_MERGE}" "\tCOPY_PROPERTY_IF_CHANGED(${ENTITY_PROPERTY_NAME});\n") + if(DEFINED ENTITY_PROPERTY_MIN AND DEFINED ENTITY_PROPERTY_MAX) + string(CONCAT ENTITY_ITEM_PROPERTY_ADD_TO_MAP "${ENTITY_ITEM_PROPERTY_ADD_TO_MAP}" "\t\tADD_PROPERTY_TO_MAP_WITH_RANGE(${ENTITY_PROPERTY_ENUM}, ${ENTITY_PROPERTY_NAME}, ${ENTITY_PROPERTY_MIN}, ${ENTITY_PROPERTY_MAX});\n") + else() + string(CONCAT ENTITY_ITEM_PROPERTY_ADD_TO_MAP "${ENTITY_ITEM_PROPERTY_ADD_TO_MAP}" "\t\tADD_PROPERTY_TO_MAP(${ENTITY_PROPERTY_ENUM}, ${ENTITY_PROPERTY_NAME}, ${ENTITY_PROPERTY_TYPE});\n") + endif() + string(CONCAT ENTITY_ITEM_PROPERTY_MARK_CHANGED "${ENTITY_ITEM_PROPERTY_MARK_CHANGED}" "\t_${ENTITY_PROPERTY_NAME}Changed = true;\n") + string(CONCAT ENTITY_ITEM_PROPERTY_LIST_CHANGED "${ENTITY_ITEM_PROPERTY_LIST_CHANGED}" "\tif (${ENTITY_PROPERTY_NAME}Changed()) {\n\t\tout += \"${ENTITY_PROPERTY_NAME}\";\n\t}\n") + if(LINE MATCHES ".*enum( |,).*") + string(CONCAT ENTITY_ITEM_PROPERTY_DEBUG "${ENTITY_ITEM_PROPERTY_DEBUG}" "\tDEBUG_PROPERTY_IF_CHANGED(debug, properties, ${ENTITY_PROPERTY_NAME_CAPS}AsString, ${ENTITY_PROPERTY_NAME}, ${ENTITY_PROPERTY_DEBUG_STRING});\n") + else() + string(CONCAT ENTITY_ITEM_PROPERTY_DEBUG "${ENTITY_ITEM_PROPERTY_DEBUG}" "\tDEBUG_PROPERTY_IF_CHANGED(debug, properties, ${ENTITY_PROPERTY_NAME_CAPS}, ${ENTITY_PROPERTY_NAME}, ${ENTITY_PROPERTY_DEBUG_STRING});\n") + endif() + endif() + if(NOT LINE MATCHES ".*noScript( |,).*") + if(NEEDS_CLOSING_BRACE) + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT}" "\t") + endif() + if(NOT COMMON_PROPS) + if(ENTITY_PROPERTY_GETTER) + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT}" "\tCOPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(${ENTITY_PROPERTY_ENUM}, ${ENTITY_PROPERTY_NAME}, ${ENTITY_PROPERTY_GETTER}());\n") + elseif(LINE MATCHES ".*enum( |,).*") + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT}" "\tCOPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(${ENTITY_PROPERTY_ENUM}, ${ENTITY_PROPERTY_NAME}, get${ENTITY_PROPERTY_NAME_CAPS}AsString());\n") + elseif(${ENTITY_PROPERTY_TYPE} IN_LIST TYPED_SCRIPT_CONVERT) + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT}" "\tCOPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(${ENTITY_PROPERTY_ENUM}, ${ENTITY_PROPERTY_NAME}, ${ENTITY_PROPERTY_TYPE});\n") + elseif(LINE MATCHES ".*urlPermission( |,).*") + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT}" "\tCOPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(${ENTITY_PROPERTY_ENUM}, ${ENTITY_PROPERTY_NAME});\n") + else() + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT}" "\tCOPY_PROPERTY_TO_QSCRIPTVALUE(${ENTITY_PROPERTY_ENUM}, ${ENTITY_PROPERTY_NAME});\n") + endif() + endif() + endif() + if(NOT LINE MATCHES ".*noNetwork( |,).*") + if(NEEDS_CLOSING_BRACE) + string(CONCAT ENTITY_ITEM_PROPERTY_APPEND "${ENTITY_ITEM_PROPERTY_APPEND}" "\t") + string(CONCAT ENTITY_ITEM_PROPERTY_READ "${ENTITY_ITEM_PROPERTY_READ}" "\t") + endif() + if(NOT COMMON_PROPS) + if(LINE MATCHES ".*enum( |,).*") + string(CONCAT ENTITY_ITEM_PROPERTY_APPEND "${ENTITY_ITEM_PROPERTY_APPEND}" "\t\t\tAPPEND_ENTITY_PROPERTY(${ENTITY_PROPERTY_ENUM}, (uint8_t)properties.get${ENTITY_PROPERTY_NAME_CAPS}());\n") + elseif(ENTITY_PROPERTY_NETWORK_GETTER) + string(CONCAT ENTITY_ITEM_PROPERTY_APPEND "${ENTITY_ITEM_PROPERTY_APPEND}" "\t\t\tAPPEND_ENTITY_PROPERTY(${ENTITY_PROPERTY_ENUM}, ${ENTITY_PROPERTY_NETWORK_GETTER});\n") + else() + string(CONCAT ENTITY_ITEM_PROPERTY_APPEND "${ENTITY_ITEM_PROPERTY_APPEND}" "\t\t\tAPPEND_ENTITY_PROPERTY(${ENTITY_PROPERTY_ENUM}, properties.get${ENTITY_PROPERTY_NAME_CAPS}());\n") + endif() + string(CONCAT ENTITY_ITEM_PROPERTY_READ "${ENTITY_ITEM_PROPERTY_READ}" "\tREAD_ENTITY_PROPERTY_TO_PROPERTIES(${ENTITY_PROPERTY_ENUM}, ${ENTITY_PROPERTY_READ_TYPE}, set${ENTITY_PROPERTY_NAME_CAPS});\n") + string(CONCAT ${CURRENT_TYPE}_REQUESTED_PROPS "${${CURRENT_TYPE}_REQUESTED_PROPS}" "\trequestedProperties += ${ENTITY_PROPERTY_ENUM};\n") + if(LINE MATCHES ".*enum( |,).*") + string(CONCAT ${CURRENT_TYPE}_ENTITY_APPEND "${${CURRENT_TYPE}_ENTITY_APPEND}" "\tAPPEND_ENTITY_PROPERTY(${ENTITY_PROPERTY_ENUM}, (uint8_t)get${ENTITY_PROPERTY_NAME_CAPS}());\n") + elseif(ENTITY_VARIABLE_NETWORK_GETTER) + string(CONCAT ${CURRENT_TYPE}_ENTITY_APPEND "${${CURRENT_TYPE}_ENTITY_APPEND}" "\tAPPEND_ENTITY_PROPERTY(${ENTITY_PROPERTY_ENUM}, ${ENTITY_VARIABLE_NETWORK_GETTER});\n") + else() + string(CONCAT ${CURRENT_TYPE}_ENTITY_APPEND "${${CURRENT_TYPE}_ENTITY_APPEND}" "\tAPPEND_ENTITY_PROPERTY(${ENTITY_PROPERTY_ENUM}, get${ENTITY_PROPERTY_NAME_CAPS}());\n") + endif() + if(NOT LINE MATCHES ".*noVariableNetworkSetter( |,).*") + if(ENTITY_VARIABLE_NETWORK_SETTER) + string(CONCAT ${CURRENT_TYPE}_ENTITY_READ "${${CURRENT_TYPE}_ENTITY_READ}" "\tREAD_ENTITY_PROPERTY(${ENTITY_PROPERTY_ENUM}, ${ENTITY_PROPERTY_TYPE}, ${ENTITY_VARIABLE_NETWORK_SETTER});\n") + else() + string(CONCAT ${CURRENT_TYPE}_ENTITY_READ "${${CURRENT_TYPE}_ENTITY_READ}" "\tREAD_ENTITY_PROPERTY(${ENTITY_PROPERTY_ENUM}, ${ENTITY_PROPERTY_TYPE}, set${ENTITY_PROPERTY_NAME_CAPS});\n") + endif() + endif() + endif() + endif() + + if (NOT COMMON_PROPS) + set(VARIABLE_DEFINE_FUNC "DEFINE_VARIABLE_REF") + if(LINE MATCHES ".*noGetterSetterProp( |,).*") + set(VARIABLE_DEFINE_FUNC "DEFINE_VARIABLE_NO_GETTER_SETTER") + elseif(LINE MATCHES ".*enum( |,).*") + set(VARIABLE_DEFINE_FUNC "DEFINE_VARIABLE") + elseif(${ENTITY_PROPERTY_TYPE} IN_LIST NON_REF_TYPES) + set(VARIABLE_DEFINE_FUNC "DEFINE_VARIABLE") + endif() + if(LINE MATCHES ".*basicProp( |,).*") + string(REPLACE "DEFINE_VARIABLE" "DEFINE_VARIABLE_BASIC" VARIABLE_DEFINE_FUNC ${VARIABLE_DEFINE_FUNC}) + elseif(LINE MATCHES ".*renderProp( |,).*") + string(REPLACE "DEFINE_VARIABLE" "DEFINE_VARIABLE_RENDER" VARIABLE_DEFINE_FUNC ${VARIABLE_DEFINE_FUNC}) + endif() + if(NOT LINE MATCHES ".*inherited( |,).*") + string(CONCAT ${CURRENT_TYPE}_ENTITY_PROPS "${${CURRENT_TYPE}_ENTITY_PROPS}" "\t${VARIABLE_DEFINE_FUNC}(${ENTITY_PROPERTY_NAME_CAPS}, ${ENTITY_PROPERTY_NAME}, ${ENTITY_PROPERTY_TYPE}, ${ENTITY_PROPERTY_DEFAULT});\n") + endif() + + if(ENTITY_VARIABLE_COPY_GETTER) + string(CONCAT ${CURRENT_TYPE}_ENTITY_COPY_TO "${${CURRENT_TYPE}_ENTITY_COPY_TO}" "\tCOPY_ENTITY_PROPERTY_TO_PROPERTIES(${ENTITY_PROPERTY_NAME}, ${ENTITY_VARIABLE_COPY_GETTER});\n") + else() + string(CONCAT ${CURRENT_TYPE}_ENTITY_COPY_TO "${${CURRENT_TYPE}_ENTITY_COPY_TO}" "\tCOPY_ENTITY_PROPERTY_TO_PROPERTIES(${ENTITY_PROPERTY_NAME}, get${ENTITY_PROPERTY_NAME_CAPS});\n") + endif() + if (NOT LOCAL_PROPS) + if(ENTITY_VARIABLE_COPY_SETTER) + string(CONCAT ${CURRENT_TYPE}_ENTITY_SET_FROM "${${CURRENT_TYPE}_ENTITY_SET_FROM}" "\tSET_ENTITY_PROPERTY_FROM_PROPERTIES(${ENTITY_PROPERTY_NAME}, ${ENTITY_VARIABLE_COPY_SETTER});\n") + else() + string(CONCAT ${CURRENT_TYPE}_ENTITY_SET_FROM "${${CURRENT_TYPE}_ENTITY_SET_FROM}" "\tSET_ENTITY_PROPERTY_FROM_PROPERTIES(${ENTITY_PROPERTY_NAME}, set${ENTITY_PROPERTY_NAME_CAPS});\n") + endif() + endif() + if(LINE MATCHES ".*enum( |,).*") + string(CONCAT ${CURRENT_TYPE}_ENTITY_DEBUG "${${CURRENT_TYPE}_ENTITY_DEBUG}" "\tqCDebug(entities) << \" ${ENTITY_PROPERTY_NAME}:\" << (int)get${ENTITY_PROPERTY_NAME_CAPS}();\n") + elseif(ENTITY_PROPERTY_DEBUG_GETTER) + string(CONCAT ${CURRENT_TYPE}_ENTITY_DEBUG "${${CURRENT_TYPE}_ENTITY_DEBUG}" "\tqCDebug(entities) << \" ${ENTITY_PROPERTY_NAME}:\" << ${ENTITY_PROPERTY_DEBUG_GETTER};\n") + else() + string(CONCAT ${CURRENT_TYPE}_ENTITY_DEBUG "${${CURRENT_TYPE}_ENTITY_DEBUG}" "\tqCDebug(entities) << \" ${ENTITY_PROPERTY_NAME}:\" << get${ENTITY_PROPERTY_NAME_CAPS}();\n") + endif() + endif() + else() + # We have some "legacy" properties, which are mostly aliases of existing properties with old names or different types. + # They only need to worry about script conversions. + if(NOT LINE MATCHES ".*noScript( |,).*") + string(REGEX MATCH ".*proxy:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" ENTITY_PROPERTY_PROXY ${LINE}) + set(ENTITY_PROPERTY_PROXY ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*proxyType:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" ENTITY_PROPERTY_PROXY_MAP_TYPE ${LINE}) + set(ENTITY_PROPERTY_PROXY_MAP_TYPE ${CMAKE_MATCH_1}) + if (NOT ENTITY_PROPERTY_PROXY_MAP_TYPE) + set(ENTITY_PROPERTY_PROXY_MAP_TYPE ${ENTITY_PROPERTY_TYPE}) + endif() + + if(NOT COMMON_PROPS) + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT}" "\tCOPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(${ENTITY_PROPERTY_ENUM}, ${ENTITY_PROPERTY_PROXY}, ${ENTITY_PROPERTY_NAME}, ${ENTITY_PROPERTY_GETTER}); // legacy support\n") + endif() + if(LINE MATCHES ".*readOnly( |,).*") + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT}" "\tif (!honorReadOnly) {\n\t") + endif() + if(LINE MATCHES ".*enum( |,).*") + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT}" "\tCOPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(${ENTITY_PROPERTY_NAME}, ${ENTITY_PROPERTY_TYPE}); // legacy support\n") + elseif(ENTITY_PROPERTY_GETTER AND ENTITY_PROPERTY_SETTER) + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT}" "\tCOPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(${ENTITY_PROPERTY_NAME}, ${ENTITY_PROPERTY_FROM_SCRIPT_TYPE}, ${ENTITY_PROPERTY_SETTER}, ${ENTITY_PROPERTY_GETTER}); // legacy support\n") + else() + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT}" "\tCOPY_PROPERTY_FROM_QSCRIPTVALUE(${ENTITY_PROPERTY_NAME}, ${ENTITY_PROPERTY_TYPE}, set${ENTITY_PROPERTY_NAME_CAPS}); // legacy support\n") + endif() + if(LINE MATCHES ".*readOnly( |,).*") + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT}" "\t}\n") + endif() + endif() + if(DEFINED ENTITY_PROPERTY_MIN AND DEFINED ENTITY_PROPERTY_MAX) + string(CONCAT ENTITY_ITEM_PROPERTY_ADD_TO_MAP "${ENTITY_ITEM_PROPERTY_ADD_TO_MAP}" "\t\tADD_PROPERTY_TO_MAP_WITH_RANGE(${ENTITY_PROPERTY_ENUM}, ${ENTITY_PROPERTY_NAME}, ${ENTITY_PROPERTY_PROXY_MAP_TYPE}, ${ENTITY_PROPERTY_MIN}, ${ENTITY_PROPERTY_MAX}); // legacy support\n") + else() + string(CONCAT ENTITY_ITEM_PROPERTY_ADD_TO_MAP "${ENTITY_ITEM_PROPERTY_ADD_TO_MAP}" "\t\tADD_PROPERTY_TO_MAP(${ENTITY_PROPERTY_ENUM}, ${ENTITY_PROPERTY_NAME}, ${ENTITY_PROPERTY_PROXY_MAP_TYPE}); // legacy support\n") + endif() + endif() + endif() + endwhile() + + # Final closing parentheses + string(CONCAT ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT "${ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT}" "\t}") + string(CONCAT ENTITY_ITEM_PROPERTY_APPEND "${ENTITY_ITEM_PROPERTY_APPEND}" "\t\t\t}") + string(CONCAT ENTITY_ITEM_PROPERTY_READ "${ENTITY_ITEM_PROPERTY_READ}" "\t}") + + # Generate the real code! + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/src/EntityItemProperties.cpp.in + ${CMAKE_CURRENT_BINARY_DIR}/src/EntityItemProperties.cpp) + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/src/EntityItemProperties.h.in + ${CMAKE_CURRENT_BINARY_DIR}/src/EntityItemProperties.h) + list(APPEND GENERATE_ENTITIES_LIB_SRC ${CMAKE_CURRENT_BINARY_DIR}/src/EntityItemProperties.h ${CMAKE_CURRENT_BINARY_DIR}/src/EntityItemProperties.cpp) + + foreach(TYPE IN LISTS ENTITY_TYPES) + if(TYPE STREQUAL "Base") + set(TYPE "") + endif() + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/src/${TYPE}EntityItem.cpp.in + ${CMAKE_CURRENT_BINARY_DIR}/src/${TYPE}EntityItem.cpp) + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/src/${TYPE}EntityItem.h.in + ${CMAKE_CURRENT_BINARY_DIR}/src/${TYPE}EntityItem.h) + list(APPEND GENERATE_ENTITIES_LIB_SRC ${CMAKE_CURRENT_BINARY_DIR}/src/${TYPE}EntityItem.h ${CMAKE_CURRENT_BINARY_DIR}/src/${TYPE}EntityItem.cpp) + endforeach() + + # Group Properties + set(GROUP_TYPES "") + + # All group properties are defined in EntityItemGroupProperties.txt. We loop over them in order. + file(STRINGS src/EntityItemGroupProperties.txt GROUP_PROPERTIES_FILE) + while(GROUP_PROPERTIES_FILE) + list(POP_FRONT GROUP_PROPERTIES_FILE LINE) + + # Lines that don't end in a comma represent the start of a new property group. + if(NOT LINE MATCHES ".*,") + string(REGEX MATCH ".*type:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+).*" GROUP_PROPERTY_TYPE ${LINE}) + set(GROUP_PROPERTY_TYPE ${CMAKE_MATCH_1}) + + if (GROUP_PROPERTY_TYPE) + string(REGEX MATCH "([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+) type:.*" CURRENT_TYPE ${LINE}) + set(CURRENT_TYPE ${CMAKE_MATCH_1}) + CAPITALIZE_FIRST_LETTER(${CURRENT_TYPE}) + set(CURRENT_TYPE_CAPS ${CAPITALIZE_RESULT}) + + list(APPEND GROUP_TYPES ${GROUP_PROPERTY_TYPE}) + else() + set(CURRENT_TYPE ${LINE}) + CAPITALIZE_FIRST_LETTER(${CURRENT_TYPE}) + set(CURRENT_TYPE_CAPS ${CAPITALIZE_RESULT}) + + list(APPEND GROUP_TYPES ${CURRENT_TYPE_CAPS}) + endif() + else() + # Everything else is just a normal group property. Group properties support almost all of the same + # settings as non-group properties. + string(REGEX MATCH ".*enum:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" GROUP_PROPERTY_ENUM ${LINE}) + string(CONCAT GROUP_PROPERTY_ENUM "PROP_" ${CMAKE_MATCH_1}) + list(APPEND ${CURRENT_TYPE}_PROPERTY_FLAGS ${GROUP_PROPERTY_ENUM}) + string(REGEX MATCH ".*prop:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" GROUP_PROPERTY_NAME ${LINE}) + set(GROUP_PROPERTY_NAME ${CMAKE_MATCH_1}) + CAPITALIZE_FIRST_LETTER(${GROUP_PROPERTY_NAME}) + set(GROUP_PROPERTY_NAME_CAPS ${CAPITALIZE_RESULT}) + string(REGEX MATCH ".*type:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" GROUP_PROPERTY_TYPE ${LINE}) + set(GROUP_PROPERTY_TYPE ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*default:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" GROUP_PROPERTY_DEFAULT ${LINE}) + set(GROUP_PROPERTY_DEFAULT ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*min:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" GROUP_PROPERTY_MIN ${LINE}) + set(GROUP_PROPERTY_MIN ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*max:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" GROUP_PROPERTY_MAX ${LINE}) + set(GROUP_PROPERTY_MAX ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*getter:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" GROUP_PROPERTY_GETTER ${LINE}) + set(GROUP_PROPERTY_GETTER ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*setter:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" GROUP_PROPERTY_SETTER ${LINE}) + set(GROUP_PROPERTY_SETTER ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*networkGetter:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" GROUP_PROPERTY_NETWORK_GETTER ${LINE}) + set(GROUP_PROPERTY_NETWORK_GETTER ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*variableNetworkGetter:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" GROUP_VARIABLE_NETWORK_GETTER ${LINE}) + set(GROUP_VARIABLE_NETWORK_GETTER ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*variableNetworkSetter:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" GROUP_VARIABLE_NETWORK_SETTER ${LINE}) + set(GROUP_VARIABLE_NETWORK_SETTER ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*variableCopyGetter:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" GROUP_VARIABLE_COPY_GETTER ${LINE}) + set(GROUP_VARIABLE_COPY_GETTER ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*variableCopySetter:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" GROUP_VARIABLE_COPY_SETTER ${LINE}) + set(GROUP_VARIABLE_COPY_SETTER ${CMAKE_MATCH_1}) + string(REGEX MATCH ".*debugGetter:+([A-Z0-9a-z_<>::\/\.\"\(\)\+\-]+)( |,)" GROUP_VARIABLE_DEBUG_GETTER ${LINE}) + set(GROUP_VARIABLE_DEBUG_GETTER ${CMAKE_MATCH_1}) + + set(DEFINE_FUNC "DEFINE_PROPERTY_REF") + if(LINE MATCHES ".*enum( |,).*") + set(DEFINE_FUNC "DEFINE_PROPERTY_REF_ENUM") + elseif(${GROUP_PROPERTY_TYPE} IN_LIST NON_REF_TYPES) + set(DEFINE_FUNC "DEFINE_PROPERTY") + elseif(LINE MATCHES ".*propertySetter( |,).*") + set(DEFINE_FUNC "DEFINE_PROPERTY_REF_WITH_SETTER") + endif() + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_PROPS "${${CURRENT_TYPE_CAPS}_GROUP_PROPS}" "\t${DEFINE_FUNC}(${GROUP_PROPERTY_NAME_CAPS}, ${GROUP_PROPERTY_NAME}, ${GROUP_PROPERTY_TYPE}, ${GROUP_PROPERTY_DEFAULT});\n") + + if(GROUP_PROPERTY_GETTER) + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_COPY_TO_SCRIPT "${${CURRENT_TYPE_CAPS}_GROUP_COPY_TO_SCRIPT}" "\tCOPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_GETTER(${GROUP_PROPERTY_ENUM}, ${CURRENT_TYPE_CAPS}, ${CURRENT_TYPE}, ${GROUP_PROPERTY_NAME_CAPS}, ${GROUP_PROPERTY_NAME});\n") + elseif(LINE MATCHES ".*enum( |,).*") + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_COPY_TO_SCRIPT "${${CURRENT_TYPE_CAPS}_GROUP_COPY_TO_SCRIPT}" "\tCOPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_GETTER(${GROUP_PROPERTY_ENUM}, ${CURRENT_TYPE_CAPS}, ${CURRENT_TYPE}, ${GROUP_PROPERTY_NAME_CAPS}, ${GROUP_PROPERTY_NAME}, get${GROUP_PROPERTY_NAME_CAPS}AsString);\n") + elseif(${GROUP_PROPERTY_TYPE} IN_LIST TYPED_SCRIPT_CONVERT) + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_COPY_TO_SCRIPT "${${CURRENT_TYPE_CAPS}_GROUP_COPY_TO_SCRIPT}" "\tCOPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(${GROUP_PROPERTY_ENUM}, ${CURRENT_TYPE_CAPS}, ${CURRENT_TYPE}, ${GROUP_PROPERTY_NAME_CAPS}, ${GROUP_PROPERTY_NAME}, ${GROUP_PROPERTY_TYPE});\n") + elseif(LINE MATCHES ".*urlPermission( |,).*") + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_COPY_TO_SCRIPT "${${CURRENT_TYPE_CAPS}_GROUP_COPY_TO_SCRIPT}" "\tCOPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(${GROUP_PROPERTY_ENUM}, ${CURRENT_TYPE_CAPS}, ${CURRENT_TYPE}, ${GROUP_PROPERTY_NAME_CAPS}, ${GROUP_PROPERTY_NAME});\n") + else() + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_COPY_TO_SCRIPT "${${CURRENT_TYPE_CAPS}_GROUP_COPY_TO_SCRIPT}" "\tCOPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(${GROUP_PROPERTY_ENUM}, ${CURRENT_TYPE_CAPS}, ${CURRENT_TYPE}, ${GROUP_PROPERTY_NAME_CAPS}, ${GROUP_PROPERTY_NAME});\n") + endif() + + if(LINE MATCHES ".*enum( |,).*") + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_COPY_FROM_SCRIPT "${${CURRENT_TYPE_CAPS}_GROUP_COPY_FROM_SCRIPT}" "\tCOPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_ENUM(${CURRENT_TYPE}, ${GROUP_PROPERTY_NAME}, ${GROUP_PROPERTY_NAME_CAPS});\n") + elseif(GROUP_PROPERTY_GETTER AND GROUP_PROPERTY_SETTER) + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_COPY_FROM_SCRIPT "${${CURRENT_TYPE_CAPS}_GROUP_COPY_FROM_SCRIPT}" "\tCOPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_GETTER(${CURRENT_TYPE}, ${GROUP_PROPERTY_NAME}, ${GROUP_PROPERTY_TYPE}, ${GROUP_PROPERTY_SETTER}, ${GROUP_PROPERTY_GETTER});\n") + else() + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_COPY_FROM_SCRIPT "${${CURRENT_TYPE_CAPS}_GROUP_COPY_FROM_SCRIPT}" "\tCOPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(${CURRENT_TYPE}, ${GROUP_PROPERTY_NAME}, ${GROUP_PROPERTY_TYPE}, set${GROUP_PROPERTY_NAME_CAPS});\n") + endif() + + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_MERGE "${${CURRENT_TYPE_CAPS}_GROUP_MERGE}" "\tCOPY_PROPERTY_IF_CHANGED(${GROUP_PROPERTY_NAME});\n") + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_LIST_CHANGED "${${CURRENT_TYPE_CAPS}_GROUP_LIST_CHANGED}" "\tif (${GROUP_PROPERTY_NAME}Changed()) {\n\t\tout += \"${GROUP_PROPERTY_NAME}\";\n\t}\n") + string(CONCAT ${CURRENT_TYPE_CAPS}_REQUESTED_PROPS "${${CURRENT_TYPE_CAPS}_REQUESTED_PROPS}" "\trequestedProperties += ${GROUP_PROPERTY_ENUM};\n") + if(LINE MATCHES ".*enum( |,).*") + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_APPEND "${${CURRENT_TYPE_CAPS}_GROUP_APPEND}" "\tAPPEND_ENTITY_PROPERTY(${GROUP_PROPERTY_ENUM}, (uint8_t)get${GROUP_PROPERTY_NAME_CAPS}());\n") + elseif(GROUP_VARIABLE_NETWORK_GETTER) + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_APPEND "${${CURRENT_TYPE_CAPS}_GROUP_APPEND}" "\tAPPEND_ENTITY_PROPERTY(${GROUP_PROPERTY_ENUM}, ${GROUP_VARIABLE_NETWORK_GETTER});\n") + else() + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_APPEND "${${CURRENT_TYPE_CAPS}_GROUP_APPEND}" "\tAPPEND_ENTITY_PROPERTY(${GROUP_PROPERTY_ENUM}, get${GROUP_PROPERTY_NAME_CAPS}());\n") + endif() + + if(NOT LINE MATCHES ".*noVariableNetworkSetter( |,).*") + if(GROUP_VARIABLE_NETWORK_SETTER) + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_READ "${${CURRENT_TYPE_CAPS}_GROUP_READ}" "\tREAD_ENTITY_PROPERTY(${GROUP_PROPERTY_ENUM}, ${GROUP_PROPERTY_TYPE}, ${GROUP_VARIABLE_NETWORK_SETTER});\n") + else() + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_READ "${${CURRENT_TYPE_CAPS}_GROUP_READ}" "\tREAD_ENTITY_PROPERTY(${GROUP_PROPERTY_ENUM}, ${GROUP_PROPERTY_TYPE}, set${GROUP_PROPERTY_NAME_CAPS});\n") + endif() + endif() + + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_DECODE_CHANGED "${${CURRENT_TYPE_CAPS}_GROUP_DECODE_CHANGED}" "\tDECODE_GROUP_PROPERTY_HAS_CHANGED(${GROUP_PROPERTY_ENUM}, ${GROUP_PROPERTY_NAME_CAPS});\n") + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_MARK_CHANGED "${${CURRENT_TYPE_CAPS}_GROUP_MARK_CHANGED}" "\t_${GROUP_PROPERTY_NAME}Changed = true;\n") + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_CHANGED_PROPERTIES "${${CURRENT_TYPE_CAPS}_GROUP_CHANGED_PROPERTIES}" "\tCHECK_PROPERTY_CHANGE(${GROUP_PROPERTY_ENUM}, ${GROUP_PROPERTY_NAME});\n") + + if(GROUP_VARIABLE_COPY_GETTER) + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_COPY_TO "${${CURRENT_TYPE_CAPS}_GROUP_COPY_TO}" "\tCOPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(${CURRENT_TYPE_CAPS}, ${GROUP_PROPERTY_NAME_CAPS}, ${GROUP_VARIABLE_COPY_GETTER});\n") + else() + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_COPY_TO "${${CURRENT_TYPE_CAPS}_GROUP_COPY_TO}" "\tCOPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(${CURRENT_TYPE_CAPS}, ${GROUP_PROPERTY_NAME_CAPS}, get${GROUP_PROPERTY_NAME_CAPS});\n") + endif() + if(GROUP_VARIABLE_COPY_SETTER) + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_SET_FROM "${${CURRENT_TYPE_CAPS}_GROUP_SET_FROM}" "\tSET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(${CURRENT_TYPE_CAPS}, ${GROUP_PROPERTY_NAME_CAPS}, ${GROUP_PROPERTY_NAME}, ${GROUP_VARIABLE_COPY_SETTER});\n") + else() + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_SET_FROM "${${CURRENT_TYPE_CAPS}_GROUP_SET_FROM}" "\tSET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(${CURRENT_TYPE_CAPS}, ${GROUP_PROPERTY_NAME_CAPS}, ${GROUP_PROPERTY_NAME}, set${GROUP_PROPERTY_NAME_CAPS});\n") + endif() + + if(DEFINED GROUP_PROPERTY_MIN AND DEFINED GROUP_PROPERTY_MAX) + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_ADD_TO_MAP "${${CURRENT_TYPE_CAPS}_GROUP_ADD_TO_MAP}" "\tADD_GROUP_PROPERTY_TO_MAP_WITH_RANGE(${GROUP_PROPERTY_ENUM}, ${CURRENT_TYPE}, ${GROUP_PROPERTY_NAME}, ${GROUP_PROPERTY_MIN}, ${GROUP_PROPERTY_MAX});\n") + else() + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_ADD_TO_MAP "${${CURRENT_TYPE_CAPS}_GROUP_ADD_TO_MAP}" "\tADD_GROUP_PROPERTY_TO_MAP(${GROUP_PROPERTY_ENUM}, ${CURRENT_TYPE}, ${GROUP_PROPERTY_NAME});\n") + endif() + + if(LINE MATCHES ".*enum( |,).*") + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_DEBUG_DUMP "${${CURRENT_TYPE_CAPS}_GROUP_DEBUG_DUMP}" "\tqCDebug(entities) << \" ${CURRENT_TYPE}.${GROUP_PROPERTY_NAME}:\" << (int)get${GROUP_PROPERTY_NAME_CAPS}();\n") + elseif(GROUP_VARIABLE_DEBUG_GETTER) + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_DEBUG_DUMP "${${CURRENT_TYPE_CAPS}_GROUP_DEBUG_DUMP}" "\tqCDebug(entities) << \" ${CURRENT_TYPE}.${GROUP_PROPERTY_NAME}:\" << ${GROUP_VARIABLE_DEBUG_GETTER};\n") + else() + string(CONCAT ${CURRENT_TYPE_CAPS}_GROUP_DEBUG_DUMP "${${CURRENT_TYPE_CAPS}_GROUP_DEBUG_DUMP}" "\tqCDebug(entities) << \" ${CURRENT_TYPE}.${GROUP_PROPERTY_NAME}:\" << get${GROUP_PROPERTY_NAME_CAPS}();\n") + endif() + endif() + endwhile() + + # Generate the real code! + foreach(TYPE IN LISTS GROUP_TYPES) + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/src/${TYPE}PropertyGroup.cpp.in + ${CMAKE_CURRENT_BINARY_DIR}/src/${TYPE}PropertyGroup.cpp) + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/src/${TYPE}PropertyGroup.h.in + ${CMAKE_CURRENT_BINARY_DIR}/src/${TYPE}PropertyGroup.h) + list(APPEND GENERATE_ENTITIES_LIB_SRC ${CMAKE_CURRENT_BINARY_DIR}/src/${TYPE}PropertyGroup.h ${CMAKE_CURRENT_BINARY_DIR}/src/${TYPE}PropertyGroup.cpp) + endforeach() + + # Lastly, now that we have a big list of all of our properties in order, we build our EntityPropertyList enum. + # Shared properties are defined first, and then subclass properties are defined using PROP_DERIVED_XXXX. + set(HAS_REACHED_COMMON_PROPS false) + set(DERIVED_PROP false) + set(DERIVED_PROP_INDEX 0) + foreach(FLAG_LINE IN LISTS ENTITY_PROPERTY_FLAGS) + string(REGEX MATCH "group:+([A-Za-z]+)" FLAG_GROUP ${FLAG_LINE}) + set(FLAG_GROUP ${CMAKE_MATCH_1}) + + if (FLAG_LINE STREQUAL "Common") + set(HAS_REACHED_COMMON_PROPS true) + elseif(NOT FLAG_GROUP AND NOT FLAG_LINE MATCHES "PROP_.*" AND HAS_REACHED_COMMON_PROPS) + set(DERIVED_PROP true) + endif() + + if (DERIVED_PROP) + if (FLAG_GROUP) + string(CONCAT ENTITY_PROPERTY_FLAGS_DERIVED "${ENTITY_PROPERTY_FLAGS_DERIVED}" "\t// ${FLAG_GROUP}\n") + foreach(GROUP_FLAG IN LISTS ${FLAG_GROUP}_PROPERTY_FLAGS) + string(CONCAT ENTITY_PROPERTY_FLAGS_DERIVED "${ENTITY_PROPERTY_FLAGS_DERIVED}" "\t${GROUP_FLAG} = PROP_DERIVED_${DERIVED_PROP_INDEX},\n") + MATH(EXPR DERIVED_PROP_INDEX "${DERIVED_PROP_INDEX}+1") + endforeach() + elseif(FLAG_LINE MATCHES "PROP_.*") + string(CONCAT ENTITY_PROPERTY_FLAGS_DERIVED "${ENTITY_PROPERTY_FLAGS_DERIVED}" "\t${FLAG_LINE} = PROP_DERIVED_${DERIVED_PROP_INDEX},\n") + MATH(EXPR DERIVED_PROP_INDEX "${DERIVED_PROP_INDEX}+1") + else() + string(CONCAT ENTITY_PROPERTY_FLAGS_DERIVED "${ENTITY_PROPERTY_FLAGS_DERIVED}" "\t// ${FLAG_LINE}\n") + set(DERIVED_PROP_INDEX 0) + endif() + else() + if (FLAG_GROUP) + string(CONCAT ENTITY_PROPERTY_FLAGS_COMMON "${ENTITY_PROPERTY_FLAGS_COMMON}" "\t// ${FLAG_GROUP}\n") + foreach(GROUP_FLAG IN LISTS ${FLAG_GROUP}_PROPERTY_FLAGS) + string(CONCAT ENTITY_PROPERTY_FLAGS_COMMON "${ENTITY_PROPERTY_FLAGS_COMMON}" "\t${GROUP_FLAG},\n") + endforeach() + elseif(FLAG_LINE MATCHES "PROP_.*") + string(CONCAT ENTITY_PROPERTY_FLAGS_COMMON "${ENTITY_PROPERTY_FLAGS_COMMON}" "\t${FLAG_LINE},\n") + else() + string(CONCAT ENTITY_PROPERTY_FLAGS_COMMON "${ENTITY_PROPERTY_FLAGS_COMMON}" "\t// ${FLAG_LINE}\n") + endif() + endif() + endforeach() + + # Generate the real code! + configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/src/EntityPropertyFlags.h.in + ${CMAKE_CURRENT_BINARY_DIR}/src/EntityPropertyFlags.h) + list(APPEND GENERATE_ENTITIES_LIB_SRC ${CMAKE_CURRENT_BINARY_DIR}/src/EntityPropertyFlags.h) + + message(STATUS "Entity property processing end") +endmacro() diff --git a/cmake/macros/IncludeHifiLibraryHeaders.cmake b/cmake/macros/IncludeHifiLibraryHeaders.cmake index 008d76a8dc2..0e9c8f03e67 100644 --- a/cmake/macros/IncludeHifiLibraryHeaders.cmake +++ b/cmake/macros/IncludeHifiLibraryHeaders.cmake @@ -11,4 +11,8 @@ macro(include_hifi_library_headers LIBRARY) target_include_directories(${TARGET_NAME} PRIVATE "${HIFI_LIBRARY_DIR}/${LIBRARY}/src") + if (${LIBRARY} STREQUAL "entities") + target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_SOURCE_DIR}/libraries/entities/src") + target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/libraries/entities/src") + endif() endmacro(include_hifi_library_headers _library _root_dir) \ No newline at end of file diff --git a/cmake/macros/SetupHifiLibrary.cmake b/cmake/macros/SetupHifiLibrary.cmake index 5c6eb0a4c60..feffe518a30 100644 --- a/cmake/macros/SetupHifiLibrary.cmake +++ b/cmake/macros/SetupHifiLibrary.cmake @@ -57,9 +57,9 @@ macro(SETUP_HIFI_LIBRARY) # create a library and set the property so it can be referenced later if (${${TARGET_NAME}_SHARED}) - add_library(${TARGET_NAME} SHARED ${LIB_SRCS} ${AUTOSCRIBE_SHADER_LIB_SRC} ${QT_RESOURCES_FILE}) + add_library(${TARGET_NAME} SHARED ${LIB_SRCS} ${AUTOSCRIBE_SHADER_LIB_SRC} ${GENERATE_ENTITIES_LIB_SRC} ${QT_RESOURCES_FILE}) else () - add_library(${TARGET_NAME} ${LIB_SRCS} ${AUTOSCRIBE_SHADER_LIB_SRC} ${QT_RESOURCES_FILE}) + add_library(${TARGET_NAME} ${LIB_SRCS} ${AUTOSCRIBE_SHADER_LIB_SRC} ${GENERATE_ENTITIES_LIB_SRC} ${QT_RESOURCES_FILE}) endif () set(${TARGET_NAME}_DEPENDENCY_QT_MODULES ${ARGN}) @@ -72,8 +72,9 @@ macro(SETUP_HIFI_LIBRARY) target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE}) endforeach() - # Don't make scribed shaders or QT resource files cumulative + # Don't make scribed shaders, generated entity files, or QT resource files cumulative set(AUTOSCRIBE_SHADER_LIB_SRC "") + set(GENERATE_ENTITIES_LIB_SRC "") set(QT_RESOURCES_FILE "") target_glm() diff --git a/cmake/macros/SetupHifiProject.cmake b/cmake/macros/SetupHifiProject.cmake index 8759c949f3d..0961510d18b 100644 --- a/cmake/macros/SetupHifiProject.cmake +++ b/cmake/macros/SetupHifiProject.cmake @@ -22,7 +22,7 @@ macro(SETUP_HIFI_PROJECT) endif () endforeach() - add_executable(${TARGET_NAME} ${TARGET_SRCS} ${AUTOSCRIBE_SHADER_LIB_SRC}) + add_executable(${TARGET_NAME} ${TARGET_SRCS} ${AUTOSCRIBE_SHADER_LIB_SRC} ${GENERATE_ENTITIES_LIB_SRC}) # include the generated application version header target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/includes") diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 98056584921..5b1c3482c12 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -1285,7 +1285,7 @@ { "name": "zones", "type": "table", - "label": "Zones", + "label": "Zones (deprecated, use Zone Entities)", "help": "In this table you can define a set of zones in which you can specify various audio properties.", "numbered": false, "content_setting": true, @@ -1337,7 +1337,7 @@ { "name": "attenuation_coefficients", "type": "table", - "label": "Attenuation Coefficients", + "label": "Attenuation Coefficients (deprecated, use Zone Entities)", "help": "In this table you can set custom attenuation coefficients between audio zones", "content_setting": true, "numbered": true, @@ -1367,7 +1367,7 @@ { "name": "reverb", "type": "table", - "label": "Reverb Settings", + "label": "Reverb Settings (deprecated, use Zone Entities)", "help": "In this table you can set reverb levels for audio zones. For a medium-sized (e.g., 100 square meter) meeting room, try a decay time of around 1.5 seconds and a wet/dry mix of 25%. For an airplane hangar or cathedral, try a decay time of 4 seconds and a wet/dry mix of 50%.", "numbered": true, "content_setting": true, diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index d68f14ca52b..04ab3ab9482 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -233,6 +233,7 @@ link_hifi_libraries( shaders ) include_hifi_library_headers(script-engine) +include_hifi_library_headers(entities) # include the binary directory of render-utils for shader includes target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/libraries/render-utils") diff --git a/interface/resources/qml/+android_interface/Stats.qml b/interface/resources/qml/+android_interface/Stats.qml index 97d076ab6aa..ef3db5d5702 100644 --- a/interface/resources/qml/+android_interface/Stats.qml +++ b/interface/resources/qml/+android_interface/Stats.qml @@ -241,9 +241,9 @@ Item { model: root.downloadUrls delegate: StatText { visible: root.expanded; - text: modelData.length > 30 + text: (modelData.length > 30 ? modelData.substring(0, 5) + "..." + modelData.substring(modelData.length - 22) - : modelData + : modelData) + "\n\t" + (!isNaN(root.downloadPriorities[index]) ? ("Priority: " + root.downloadPriorities[index] + ", ") : "") + "Progress: " + root.downloadProgresses[index] + "%" } } } diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index 0b5eba99d02..1482b6f92fd 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -304,16 +304,16 @@ Item { } ListView { width: geoCol.width - height: root.downloadUrls.length * 15 + height: root.downloadUrls.length * 30 visible: root.expanded && root.downloadUrls.length > 0; model: root.downloadUrls delegate: StatText { visible: root.expanded; - text: modelData.length > 30 + text: (modelData.length > 30 ? modelData.substring(0, 5) + "..." + modelData.substring(modelData.length - 22) - : modelData + : modelData) + "\n\t" + (!isNaN(root.downloadPriorities[index]) ? ("Priority: " + root.downloadPriorities[index] + ", ") : "") + "Progress: " + root.downloadProgresses[index] + "%" } } } diff --git a/interface/resources/qml/hifi/dialogs/graphics/GraphicsSettings.qml b/interface/resources/qml/hifi/dialogs/graphics/GraphicsSettings.qml index 5bac374fb55..a928b1379f1 100644 --- a/interface/resources/qml/hifi/dialogs/graphics/GraphicsSettings.qml +++ b/interface/resources/qml/hifi/dialogs/graphics/GraphicsSettings.qml @@ -4,6 +4,7 @@ // // Created by Zach Fox on 2019-07-10 // Copyright 2019 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -212,8 +213,8 @@ Flickable { ColumnLayout { anchors.left: renderingEffectsHeader.right anchors.leftMargin: 20 - Layout.preferredWidth: parent.width - spacing: 0 + Layout.preferredWidth: parent.width + spacing: 0 enabled: performanceCustom.checked HifiControlsUit.RadioButton { @@ -268,48 +269,57 @@ Flickable { } } HifiControlsUit.CheckBox { - id: renderingEffectLocalLights - enabled: false - //checked: Render.localLightsEnabled - checked: renderingEffectsEnabled.checked + id: renderingEffectHaze + checked: Render.hazeEnabled boxSize: 16 - text: "Local lights" + text: "Haze" spacing: -1 colorScheme: hifi.colorSchemes.dark anchors.left: parent.left anchors.top: renderingEffectShadows.bottom - //onCheckedChanged: { - // Render.localLightsEnabled = renderingEffectLocalLightsEnabled.checked; - //} + onCheckedChanged: { + Render.hazeEnabled = renderingEffectHaze.checked; + } } HifiControlsUit.CheckBox { - id: renderingEffectFog - enabled: false - //checked: Render.fogEnabled - checked: renderingEffectsEnabled.checked + id: renderingEffectBloom + checked: Render.bloomEnabled boxSize: 16 - text: "Fog" + text: "Bloom" spacing: -1 colorScheme: hifi.colorSchemes.dark anchors.left: parent.left - anchors.top: renderingEffectLocalLights.bottom - //onCheckedChanged: { - // Render.fogEnabled = renderingEffectFogEnabled.checked; - //} + anchors.top: renderingEffectHaze.bottom + onCheckedChanged: { + Render.bloomEnabled = renderingEffectBloom.checked; + } } HifiControlsUit.CheckBox { - id: renderingEffectBloom + id: renderingEffectAO + checked: Render.ambientOcclusionEnabled + boxSize: 16 + text: "AO" + spacing: -1 + colorScheme: hifi.colorSchemes.dark + anchors.left: parent.left + anchors.top: renderingEffectBloom.bottom + onCheckedChanged: { + Render.ambientOcclusionEnabled = renderingEffectAO.checked; + } + } + HifiControlsUit.CheckBox { + id: renderingEffectLocalLights enabled: false - //checked: Render.bloomEnabled + //checked: Render.localLightsEnabled checked: renderingEffectsEnabled.checked boxSize: 16 - text: "Bloom" + text: "Local lights" spacing: -1 colorScheme: hifi.colorSchemes.dark anchors.left: parent.left - anchors.top: renderingEffectFog.bottom + anchors.top: renderingEffectAO.bottom //onCheckedChanged: { - // Render.bloomEnabled = renderingEffectBloomEnabled.checked; + // Render.localLightsEnabled = renderingEffectLocalLightsEnabled.checked; //} } } @@ -811,6 +821,42 @@ Flickable { } } + ColumnLayout { + Layout.topMargin: 20 + Layout.preferredWidth: parent.width + spacing: 0 + + Item { + Layout.preferredWidth: parent.width + Layout.preferredHeight: 35 + + HifiStylesUit.RalewayRegular { + id: proceduralMaterialsHeader + text: "Procedural Materials" + anchors.left: parent.left + anchors.top: parent.top + width: 150 + height: parent.height + size: 16 + color: "#FFFFFF" + } + + HifiControlsUit.CheckBox { + id: renderingEffectProceduralMaterials + checked: Render.proceduralMaterialsEnabled + boxSize: 16 + spacing: -1 + colorScheme: hifi.colorSchemes.dark + anchors.left: proceduralMaterialsHeader.right + anchors.leftMargin: 20 + anchors.top: parent.top + onCheckedChanged: { + Render.proceduralMaterialsEnabled = renderingEffectProceduralMaterials.checked; + } + } + } + } + } } diff --git a/interface/resources/shaders/proceduralParticleSwarmRender.frag b/interface/resources/shaders/proceduralParticleSwarmRender.frag new file mode 100644 index 00000000000..746191814c5 --- /dev/null +++ b/interface/resources/shaders/proceduralParticleSwarmRender.frag @@ -0,0 +1,7 @@ +layout(location=2) in vec3 _normalWS; + +float getProceduralFragment(inout ProceduralFragment proceduralData) { + proceduralData.normal = normalize(_normalWS); + proceduralData.diffuse = 0.5 * (proceduralData.normal + 1.0); + return 0.0; +} diff --git a/interface/resources/shaders/proceduralParticleSwarmRender.vert b/interface/resources/shaders/proceduralParticleSwarmRender.vert new file mode 100644 index 00000000000..4f9806d1a3f --- /dev/null +++ b/interface/resources/shaders/proceduralParticleSwarmRender.vert @@ -0,0 +1,86 @@ +uniform float radius = 0.01; +uniform float lifespan = 1.0; // seconds + +layout(location=2) out vec3 _normalWS; + +float bezierInterpolate(float y1, float y2, float y3, float u) { + // https://en.wikipedia.org/wiki/Bezier_curve + return (1.0 - u) * (1.0 - u) * y1 + 2.0 * (1.0 - u) * u * y2 + u * u * y3; +} + +float interpolate3Points(float y1, float y2, float y3, float u) { + // Makes the interpolated values intersect the middle value. + + if ((u <= 0.5f && y1 == y2) || (u >= 0.5f && y2 == y3)) { + // Flat line. + return y2; + } + + float halfSlope; + if ((y2 >= y1 && y2 >= y3) || (y2 <= y1 && y2 <= y3)) { + // U or inverted-U shape. + // Make the slope at y2 = 0, which means that the control points half way between the value points have the value y2. + halfSlope = 0.0f; + + } else { + // L or inverted and/or mirrored L shape. + // Make the slope at y2 be the slope between y1 and y3, up to a maximum of double the minimum of the slopes between y1 + // and y2, and y2 and y3. Use this slope to calculate the control points half way between the value points. + // Note: The maximum ensures that the control points and therefore the interpolated values stay between y1 and y3. + halfSlope = (y3 - y1) / 2.0f; + float slope12 = y2 - y1; + float slope23 = y3 - y2; + + { + float check = float(abs(halfSlope) > abs(slope12)); + halfSlope = mix(halfSlope, slope12, check); + halfSlope = mix(halfSlope, slope23, (1.0 - check) * float(abs(halfSlope) > abs(slope23))); + } + } + + float stepU = step(0.5f, u); // 0.0 if u < 0.5, 1.0 otherwise. + float slopeSign = 2.0f * stepU - 1.0f; // -1.0 if u < 0.5, 1.0 otherwise + float start = (1.0f - stepU) * y1 + stepU * y2; // y1 if u < 0.5, y2 otherwise + float middle = y2 + slopeSign * halfSlope; + float finish = (1.0f - stepU) * y2 + stepU * y3; // y2 if u < 0.5, y3 otherwise + float v = 2.0f * u - step(0.5f, u); // 0.0-0.5 -> 0.0-1.0 and 0.5-1.0 -> 0.0-1.0 + return bezierInterpolate(start, middle, finish, v); +} + +vec3 getProceduralVertex(const int particleID) { + vec4 positionAndAge = getParticleProperty(0, particleID); + vec3 position = positionAndAge.xyz; + + const vec3 UP = vec3(0, 1, 0); + vec3 forward = normalize(getParticleProperty(1, particleID).xyz); + vec3 right = cross(forward, UP); + vec3 up = cross(right, forward); + + const int VERTEX = gl_VertexID % 3; + int TRIANGLE = int(gl_VertexID / 3); + + float age = positionAndAge.w; + float particleRadius = interpolate3Points(0.0, radius, 0.0, clamp(age / lifespan, 0.0, 1.0)); + + if (TRIANGLE < 3) { + const vec3 SIDE_POINTS[3] = vec3[3]( + up, + normalize(-up + right), + normalize(-up - right) + ); + position += particleRadius * (VERTEX == 2 ? forward : SIDE_POINTS[(TRIANGLE + VERTEX) % 3]); + _normalWS = normalize(cross(forward - SIDE_POINTS[TRIANGLE], forward - SIDE_POINTS[(TRIANGLE + 1) % 3])); + } else { + TRIANGLE -= 3; + vec3 backward = -2.0 * normalize(getParticleProperty(2, particleID).xyz); + const vec3 SIDE_POINTS[3] = vec3[3]( + up, + normalize(-up - right), + normalize(-up + right) + ); + position += particleRadius * (VERTEX == 2 ? backward : SIDE_POINTS[(TRIANGLE + VERTEX) % 3]); + _normalWS = normalize(cross(backward - SIDE_POINTS[TRIANGLE], backward - SIDE_POINTS[(TRIANGLE + 1) % 3])); + } + + return position; +} diff --git a/interface/resources/shaders/proceduralParticleSwarmUpdate.frag b/interface/resources/shaders/proceduralParticleSwarmUpdate.frag new file mode 100644 index 00000000000..cd052cb8dbc --- /dev/null +++ b/interface/resources/shaders/proceduralParticleSwarmUpdate.frag @@ -0,0 +1,73 @@ +uniform float lifespan = 1.0; // seconds +uniform float speed = 0.1; // m/s +uniform float speedSpread = 0.25; +uniform float mass = 1.0; + +const float G = 6.67e-11; + +// prop0: xyz: position, w: age +// prop1: xyz: velocity, w: prevUpdateTime +// prop2: xyz: prevVelocity + +vec3 initPosition(const int particleID) { + return 0.5 * (vec3(hifi_hash(particleID + iGlobalTime), + hifi_hash(particleID + iGlobalTime + 1.0), + hifi_hash(particleID + iGlobalTime + 2.0)) - 0.5); +} + +mat3 rotationMatrix(vec3 axis, float angle) { + float s = sin(angle); + float c = cos(angle); + float oc = 1.0 - c; + + return mat3(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, + oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, + oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c); +} + +vec3 initVelocity(const int particleID, const vec3 position) { + const float particleSpeed = speed * ((1.0 - speedSpread) + speedSpread * hifi_hash(particleID + iGlobalTime + 3.0)); + vec3 r = normalize(iWorldPosition - position); + float angle = 2.0 * 3.14159 * hifi_hash(particleID + iGlobalTime + 4.0); + return particleSpeed * rotationMatrix(r, angle) * cross(r, vec3(0, 1, 0)); +} + +void updateParticleProps(const int particleID, inout ParticleUpdateProps particleProps) { + // First draw + if (particleProps.prop1.w < 0.00001) { + particleProps.prop0.xyz = iWorldOrientation * (initPosition(particleID) * iWorldScale) + iWorldPosition; + particleProps.prop0.w = -lifespan * hifi_hash(particleID + iGlobalTime + 3.0); + particleProps.prop1.xyz = initVelocity(particleID, particleProps.prop0.xyz); + particleProps.prop1.w = iGlobalTime; + particleProps.prop2.xyz = particleProps.prop1.xyz; + return; + } + + // Particle expired + if (particleProps.prop0.w >= lifespan) { + particleProps.prop0.xyz = iWorldOrientation * (initPosition(particleID) * iWorldScale) + iWorldPosition; + particleProps.prop0.w = 0.0; + particleProps.prop1.xyz = initVelocity(particleID, particleProps.prop0.xyz); + particleProps.prop1.w = iGlobalTime; + particleProps.prop2.xyz = particleProps.prop1.xyz; + return; + } + + float dt = 0.01666666666;//max(0.0, iGlobalTime - particleProps.prop1.w); + particleProps.prop2.xyz = particleProps.prop1.xyz; + if (particleProps.prop0.w >= 0.0) { + // gravitational acceleration + vec3 r = iWorldPosition - particleProps.prop0.xyz; + vec3 g = (G * mass / max(0.01, dot(r, r))) * r; + + // position + particleProps.prop0.xyz += particleProps.prop1.xyz * dt + (0.5 * dt * dt) * g; + // velocity + particleProps.prop1.xyz += g * dt; + } + + // age + particleProps.prop0.w += dt; + // prevUpdateTime + particleProps.prop1.w = iGlobalTime; +} diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f630bea8637..4ff848fabed 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -316,7 +316,6 @@ static const QString JS_EXTENSION = ".js"; static const QString FST_EXTENSION = ".fst"; static const QString FBX_EXTENSION = ".fbx"; static const QString OBJ_EXTENSION = ".obj"; -static const QString AVA_JSON_EXTENSION = ".ava.json"; static const QString WEB_VIEW_TAG = "noDownload=true"; static const QString ZIP_EXTENSION = ".zip"; static const QString CONTENT_ZIP_EXTENSION = ".content.zip"; @@ -365,7 +364,6 @@ static const QString TESTER_FILE = "/sdcard/_hifi_test_device.txt"; const std::vector> Application::_acceptedExtensions { { SVO_EXTENSION, &Application::importSVOFromURL }, { SVO_JSON_EXTENSION, &Application::importSVOFromURL }, - { AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl }, { JSON_EXTENSION, &Application::importJSONFromURL }, { JS_EXTENSION, &Application::askToLoadScript }, { FST_EXTENSION, &Application::askToSetAvatarUrl }, @@ -2279,12 +2277,12 @@ void Application::initialize(const QCommandLineParser &parser) { auto loadingRequests = ResourceCache::getLoadingRequests(); QJsonArray loadingRequestsStats; - for (const auto& request : loadingRequests) { + for (const auto& requestPair : loadingRequests) { QJsonObject requestStats; - requestStats["filename"] = request->getURL().fileName(); - requestStats["received"] = request->getBytesReceived(); - requestStats["total"] = request->getBytesTotal(); - requestStats["attempts"] = (int)request->getDownloadAttempts(); + requestStats["filename"] = requestPair.first->getURL().fileName(); + requestStats["received"] = requestPair.first->getBytesReceived(); + requestStats["total"] = requestPair.first->getBytesTotal(); + requestStats["attempts"] = (int)requestPair.first->getDownloadAttempts(); loadingRequestsStats.append(requestStats); } @@ -2541,6 +2539,7 @@ void Application::initialize(const QCommandLineParser &parser) { copyViewFrustum(viewFrustum); return viewFrustum.getPosition(); }); + MirrorModeHelpers::setComputeMirrorViewOperator(EntityRenderer::computeMirrorViewOperator); DependencyManager::get()->setKickConfirmationOperator([this] (const QUuid& nodeID, unsigned int banFlags) { userKickConfirmation(nodeID, banFlags); }); @@ -5732,15 +5731,30 @@ void Application::init() { getEntities()->init(); getEntities()->setEntityLoadingPriorityFunction([this](const EntityItem& item) { - auto dims = item.getScaledDimensions(); - auto maxSize = glm::compMax(dims); + if (item.getEntityHostType() == entity::HostType::AVATAR) { + return item.isMyAvatarEntity() ? Avatar::MYAVATAR_ENTITY_LOADING_PRIORITY : Avatar::OTHERAVATAR_ENTITY_LOADING_PRIORITY; + } + const float maxSize = glm::compMax(item.getScaledDimensions()); if (maxSize <= 0.0f) { return 0.0f; } - auto distance = glm::distance(getMyAvatar()->getWorldPosition(), item.getWorldPosition()); - return atan2(maxSize, distance); + const glm::vec3 itemPosition = item.getWorldPosition(); + const float distance = glm::distance(getMyAvatar()->getWorldPosition(), itemPosition); + float result = atan2(maxSize, distance); + + bool isInView = true; + { + QMutexLocker viewLocker(&_viewMutex); + isInView = _viewFrustum.sphereIntersectsKeyhole(itemPosition, maxSize); + } + if (!isInView) { + const float OUT_OF_VIEW_PENALTY = -(float)M_PI_2; + result += OUT_OF_VIEW_PENALTY; + } + + return result; }); ObjectMotionState::setShapeManager(&_shapeManager); @@ -7833,74 +7847,6 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) { return true; } -bool Application::askToWearAvatarAttachmentUrl(const QString& url) { - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - QNetworkRequest networkRequest = QNetworkRequest(url); - networkRequest.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy); - networkRequest.setHeader(QNetworkRequest::UserAgentHeader, NetworkingConstants::OVERTE_USER_AGENT); - QNetworkReply* reply = networkAccessManager.get(networkRequest); - int requestNumber = ++_avatarAttachmentRequest; - connect(reply, &QNetworkReply::finished, [this, reply, url, requestNumber]() { - - if (requestNumber != _avatarAttachmentRequest) { - // this request has been superseded by another more recent request - reply->deleteLater(); - return; - } - - QNetworkReply::NetworkError networkError = reply->error(); - if (networkError == QNetworkReply::NoError) { - // download success - QByteArray contents = reply->readAll(); - - QJsonParseError jsonError; - auto doc = QJsonDocument::fromJson(contents, &jsonError); - if (jsonError.error == QJsonParseError::NoError) { - - auto jsonObject = doc.object(); - - // retrieve optional name field from JSON - QString name = tr("Unnamed Attachment"); - auto nameValue = jsonObject.value("name"); - if (nameValue.isString()) { - name = nameValue.toString(); - } - - auto avatarAttachmentConfirmationTitle = tr("Avatar Attachment Confirmation"); - auto avatarAttachmentConfirmationMessage = tr("Would you like to wear '%1' on your avatar?").arg(name); - ModalDialogListener* dlg = OffscreenUi::asyncQuestion(avatarAttachmentConfirmationTitle, - avatarAttachmentConfirmationMessage, - QMessageBox::Ok | QMessageBox::Cancel); - QObject::connect(dlg, &ModalDialogListener::response, this, [=] (QVariant answer) { - QObject::disconnect(dlg, &ModalDialogListener::response, this, nullptr); - if (static_cast(answer.toInt()) == QMessageBox::Yes) { - // add attachment to avatar - auto myAvatar = getMyAvatar(); - assert(myAvatar); - auto attachmentDataVec = myAvatar->getAttachmentData(); - AttachmentData attachmentData; - attachmentData.fromJson(jsonObject); - attachmentDataVec.push_back(attachmentData); - myAvatar->setAttachmentData(attachmentDataVec); - } else { - qCDebug(interfaceapp) << "User declined to wear the avatar attachment"; - } - }); - } else { - // json parse error - auto avatarAttachmentParseErrorString = tr("Error parsing attachment JSON from url: \"%1\""); - displayAvatarAttachmentWarning(avatarAttachmentParseErrorString.arg(url)); - } - } else { - // download failure - auto avatarAttachmentDownloadErrorString = tr("Error downloading attachment JSON from url: \"%1\""); - displayAvatarAttachmentWarning(avatarAttachmentDownloadErrorString.arg(url)); - } - reply->deleteLater(); - }); - return true; -} - static const QString CONTENT_SET_NAME_QUERY_PARAM = "name"; void Application::replaceDomainContent(const QString& url, const QString& itemName) { @@ -7979,11 +7925,6 @@ bool Application::askToReplaceDomainContent(const QString& url) { return true; } -void Application::displayAvatarAttachmentWarning(const QString& message) const { - auto avatarAttachmentWarningTitle = tr("Avatar Attachment Failure"); - OffscreenUi::asyncWarning(avatarAttachmentWarningTitle, message); -} - void Application::showDialog(const QUrl& widgetUrl, const QUrl& tabletUrl, const QString& name) const { auto tablet = DependencyManager::get()->getTablet(SYSTEM_TABLET); auto hmd = DependencyManager::get(); @@ -9238,7 +9179,7 @@ void Application::createLoginDialog() { properties.getGrab().setGrabbable(false); properties.setIgnorePickIntersection(false); properties.setAlpha(1.0f); - properties.setDPI(DPI); + properties.setDpi(DPI); properties.setVisible(true); auto entityScriptingInterface = DependencyManager::get(); @@ -9322,7 +9263,7 @@ void Application::createAvatarInputsBar() { properties.getGrab().setGrabbable(false); properties.setIgnorePickIntersection(false); properties.setAlpha(1.0f); - properties.setDPI(DPI); + properties.setDpi(DPI); properties.setVisible(true); auto entityScriptingInterface = DependencyManager::get(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 53b827fdb85..f3cbd351eb2 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -556,9 +556,6 @@ private slots: bool askToSetAvatarUrl(const QString& url); bool askToLoadScript(const QString& scriptFilenameOrURL); - bool askToWearAvatarAttachmentUrl(const QString& url); - void displayAvatarAttachmentWarning(const QString& message) const; - bool askToReplaceDomainContent(const QString& url); void setSessionUUID(const QUuid& sessionUUID) const; @@ -810,8 +807,6 @@ private slots: bool _reticleClickPressed { false }; bool _keyboardFocusWaitingOnRenderable { false }; - int _avatarAttachmentRequest = 0; - bool _settingsLoaded { false }; bool _captureMouse { false }; diff --git a/interface/src/AvatarBookmarks.cpp b/interface/src/AvatarBookmarks.cpp index 461c55e64e5..6485840c809 100644 --- a/interface/src/AvatarBookmarks.cpp +++ b/interface/src/AvatarBookmarks.cpp @@ -222,8 +222,6 @@ void AvatarBookmarks::updateAvatarEntities(const QVariantList &avatarEntities) { * @property {number} avatarScale - The target scale of the avatar. * @property {Array>} [avatarEntites] - The avatar entities included with the * bookmark. - * @property {AttachmentData[]} [attachments] - The attachments included with the bookmark. - *

Deprecated: Use avatar entities instead. */ void AvatarBookmarks::loadBookmark(const QString& bookmarkName) { @@ -266,8 +264,6 @@ void AvatarBookmarks::loadBookmarkInternal(const QString& bookmarkName) { myAvatar->clearWornAvatarEntities(); const float& qScale = bookmark.value(ENTRY_AVATAR_SCALE, 1.0f).toFloat(); myAvatar->setAvatarScale(qScale); - QList attachments = bookmark.value(ENTRY_AVATAR_ATTACHMENTS, QList()).toList(); - myAvatar->setAttachmentsVariant(attachments); QVariantList avatarEntities = bookmark.value(ENTRY_AVATAR_ENTITIES, QVariantList()).toList(); addAvatarEntities(avatarEntities); emit bookmarkLoaded(bookmarkName); @@ -335,7 +331,6 @@ QVariantMap AvatarBookmarks::getAvatarDataToBookmark() { const QString& avatarIcon = QString(""); const QVariant& avatarScale = myAvatar->getAvatarScale(); - // If Avatar attachments ever change, this is where to update them, when saving remember to also append to AVATAR_BOOKMARK_VERSION QVariantMap bookmark; bookmark.insert(ENTRY_VERSION, AVATAR_BOOKMARK_VERSION); bookmark.insert(ENTRY_AVATAR_URL, avatarUrl); diff --git a/interface/src/AvatarBookmarks.h b/interface/src/AvatarBookmarks.h index bf06743b3f7..99421bb78b9 100644 --- a/interface/src/AvatarBookmarks.h +++ b/interface/src/AvatarBookmarks.h @@ -66,8 +66,7 @@ public slots: void saveBookmark(const QString& bookmarkName); /*@jsdoc - * Loads an avatar bookmark, setting your avatar model, scale, and avatar entities (or attachments if an old bookmark) to - * those in the bookmark. + * Loads an avatar bookmark, setting your avatar model, scale, and avatar entities to those in the bookmark. * @function AvatarBookmarks.loadBookmark * @param {string} bookmarkName - The name of the avatar bookmark to load (case sensitive). */ @@ -104,8 +103,7 @@ public slots: signals: /*@jsdoc - * Triggered when an avatar bookmark is loaded, setting your avatar model, scale, and avatar entities (or attachments if an - * old bookmark) to those in the bookmark. + * Triggered when an avatar bookmark is loaded, setting your avatar model, scale, and avatar entities to those in the bookmark. * @function AvatarBookmarks.bookmarkLoaded * @param {string} bookmarkName - The name of the avatar bookmark loaded. * @returns {Signal} @@ -155,7 +153,6 @@ protected slots: const QString AVATARBOOKMARKS_FILENAME = "avatarbookmarks.json"; const QString ENTRY_AVATAR_URL = "avatarUrl"; const QString ENTRY_AVATAR_ICON = "avatarIcon"; - const QString ENTRY_AVATAR_ATTACHMENTS = "attachments"; const QString ENTRY_AVATAR_ENTITIES = "avatarEntites"; const QString ENTRY_AVATAR_SCALE = "avatarScale"; const QString ENTRY_VERSION = "version"; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 3a0aec7534b..78ba7dbde87 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -65,7 +65,6 @@ #include "SpeechRecognizer.h" #endif -#include "MeshPartPayload.h" #include "scripting/RenderScriptingInterface.h" extern bool DEV_DECIMATE_TEXTURES; @@ -539,10 +538,8 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ComputeBlendshapes, 0, true, DependencyManager::get().data(), SLOT(setComputeBlendshapes(bool))); - action = addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::MaterialProceduralShaders, 0, false); - connect(action, &QAction::triggered, [action] { - Procedural::enableProceduralShaders = action->isChecked(); - }); + addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::MaterialProceduralShaders, 0, RenderScriptingInterface::getInstance()->getProceduralMaterialsEnabled(), + RenderScriptingInterface::getInstance(), SLOT(setProceduralMaterialsEnabled(bool))); { auto drawStatusConfig = qApp->getRenderEngine()->getConfiguration()->getConfig("RenderMainView.DrawStatus"); diff --git a/interface/src/PerformanceManager.cpp b/interface/src/PerformanceManager.cpp index ddefc780bac..0ba7636939c 100644 --- a/interface/src/PerformanceManager.cpp +++ b/interface/src/PerformanceManager.cpp @@ -95,11 +95,13 @@ void PerformanceManager::applyPerformancePreset(PerformanceManager::PerformanceP RenderScriptingInterface::RenderMethod::DEFERRED : RenderScriptingInterface::RenderMethod::FORWARD ) ); - RenderScriptingInterface::getInstance()->setViewportResolutionScale(recommendedPpiScale); - RenderScriptingInterface::getInstance()->setShadowsEnabled(true); - qApp->getRefreshRateManager().setRefreshRateProfile(RefreshRateManager::RefreshRateProfile::REALTIME); + RenderScriptingInterface::getInstance()->setHazeEnabled(true); + RenderScriptingInterface::getInstance()->setBloomEnabled(true); + RenderScriptingInterface::getInstance()->setAmbientOcclusionEnabled(true); + RenderScriptingInterface::getInstance()->setViewportResolutionScale(recommendedPpiScale); + qApp->getRefreshRateManager().setRefreshRateProfile(RefreshRateManager::RefreshRateProfile::REALTIME); DependencyManager::get()->setWorldDetailQuality(WORLD_DETAIL_MEDIUM); break; @@ -108,30 +110,39 @@ void PerformanceManager::applyPerformancePreset(PerformanceManager::PerformanceP RenderScriptingInterface::RenderMethod::DEFERRED : RenderScriptingInterface::RenderMethod::FORWARD)); + RenderScriptingInterface::getInstance()->setShadowsEnabled(false); + RenderScriptingInterface::getInstance()->setHazeEnabled(true); + RenderScriptingInterface::getInstance()->setBloomEnabled(true); + RenderScriptingInterface::getInstance()->setAmbientOcclusionEnabled(false); RenderScriptingInterface::getInstance()->setViewportResolutionScale(recommendedPpiScale); - RenderScriptingInterface::getInstance()->setShadowsEnabled(false); qApp->getRefreshRateManager().setRefreshRateProfile(RefreshRateManager::RefreshRateProfile::REALTIME); DependencyManager::get()->setWorldDetailQuality(WORLD_DETAIL_MEDIUM); break; case PerformancePreset::LOW: RenderScriptingInterface::getInstance()->setRenderMethod(RenderScriptingInterface::RenderMethod::FORWARD); - RenderScriptingInterface::getInstance()->setShadowsEnabled(false); - qApp->getRefreshRateManager().setRefreshRateProfile(RefreshRateManager::RefreshRateProfile::REALTIME); + RenderScriptingInterface::getInstance()->setShadowsEnabled(false); + RenderScriptingInterface::getInstance()->setHazeEnabled(true); + RenderScriptingInterface::getInstance()->setBloomEnabled(false); + RenderScriptingInterface::getInstance()->setAmbientOcclusionEnabled(false); RenderScriptingInterface::getInstance()->setViewportResolutionScale(recommendedPpiScale); + qApp->getRefreshRateManager().setRefreshRateProfile(RefreshRateManager::RefreshRateProfile::REALTIME); DependencyManager::get()->setWorldDetailQuality(WORLD_DETAIL_LOW); break; case PerformancePreset::LOW_POWER: RenderScriptingInterface::getInstance()->setRenderMethod(RenderScriptingInterface::RenderMethod::FORWARD); - RenderScriptingInterface::getInstance()->setShadowsEnabled(false); - qApp->getRefreshRateManager().setRefreshRateProfile(RefreshRateManager::RefreshRateProfile::ECO); + RenderScriptingInterface::getInstance()->setShadowsEnabled(false); + RenderScriptingInterface::getInstance()->setHazeEnabled(false); + RenderScriptingInterface::getInstance()->setBloomEnabled(false); + RenderScriptingInterface::getInstance()->setAmbientOcclusionEnabled(false); RenderScriptingInterface::getInstance()->setViewportResolutionScale(recommendedPpiScale); + qApp->getRefreshRateManager().setRefreshRateProfile(RefreshRateManager::RefreshRateProfile::ECO); DependencyManager::get()->setWorldDetailQuality(WORLD_DETAIL_LOW); break; diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp index 704d7963e72..130b8c77ea2 100644 --- a/interface/src/SecondaryCamera.cpp +++ b/interface/src/SecondaryCamera.cpp @@ -27,7 +27,7 @@ class SecondaryCameraJob { // Changes renderContext for our framebuffer and vie using Config = SecondaryCameraJobConfig; using JobModel = render::Job::ModelO; SecondaryCameraJob() { - _cachedArgsPointer = std::make_shared(_cachedArgs); + _cachedArgsPointer = std::make_shared(); _attachedEntityPropertyFlags += PROP_POSITION; _attachedEntityPropertyFlags += PROP_ROTATION; } @@ -203,7 +203,6 @@ class SecondaryCameraJob { // Changes renderContext for our framebuffer and vie } protected: - RenderArgs _cachedArgs; RenderArgsPointer _cachedArgsPointer; private: diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 2849ca15a09..1779d64dc69 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -259,7 +259,7 @@ MyAvatar::MyAvatar(QThread* thread) : _headData = new MyHead(this); _skeletonModel = std::make_shared(this, nullptr); - _skeletonModel->setLoadingPriority(MYAVATAR_LOADING_PRIORITY); + _skeletonModel->setLoadingPriorityOperator([]() { return MYAVATAR_LOADING_PRIORITY; }); connect(_skeletonModel.get(), &Model::setURLFinished, this, &Avatar::setModelURLFinished); connect(_skeletonModel.get(), &Model::setURLFinished, this, [this](bool success) { if (success) { @@ -272,12 +272,6 @@ MyAvatar::MyAvatar(QThread* thread) : auto hfmModel = getSkeletonModel()->getHFMModel(); qApp->loadAvatarScripts(hfmModel.scripts); _shouldLoadScripts = false; - } - // Load and convert old attachments to avatar entities - if (_oldAttachmentData.size() > 0) { - setAttachmentData(_oldAttachmentData); - _oldAttachmentData.clear(); - _attachmentData.clear(); } }); connect(_skeletonModel.get(), &Model::rigReady, this, &Avatar::rigReady); @@ -371,10 +365,6 @@ MyAvatar::MyAvatar(QThread* thread) : setWorldPosition(dummyAvatar.getWorldPosition()); setWorldOrientation(dummyAvatar.getWorldOrientation()); - if (!dummyAvatar.getAttachmentData().isEmpty()) { - setAttachmentData(dummyAvatar.getAttachmentData()); - } - auto headData = dummyAvatar.getHeadData(); if (headData && _headData) { // blendshapes @@ -501,11 +491,6 @@ glm::quat MyAvatar::getOrientationOutbound() const { return (slerp(_smoothOrientationInitial, _smoothOrientationTarget, interp)); } -// virtual -void MyAvatar::simulateAttachments(float deltaTime) { - // don't update attachments here, do it in harvestResultsFromPhysicsSimulation() -} - QByteArray MyAvatar::toByteArrayStateful(AvatarDataDetail dataDetail, bool dropFaceTracking) { CameraMode mode = qApp->getCamera().getMode(); _globalPosition = getWorldPosition(); @@ -982,8 +967,7 @@ void MyAvatar::simulate(float deltaTime, bool inView) { } // we've achived our final adjusted position and rotation for the avatar - // and all of its joints, now update our attachements. - Avatar::simulateAttachments(deltaTime); + // and all of its joints, now update our children. relayJointDataToChildren(); if (applyGrabChanges()) { _cauterizationNeedsUpdate = true; @@ -1857,6 +1841,8 @@ void MyAvatar::handleChangedAvatarEntityData() { } }); } + + _hasCheckedForAvatarEntities = true; } bool MyAvatar::updateStaleAvatarEntityBlobs() const { @@ -1912,6 +1898,7 @@ void MyAvatar::prepareAvatarEntityDataForReload() { }); _reloadAvatarEntityDataFromSettings = true; + _hasCheckedForAvatarEntities = false; } AvatarEntityMap MyAvatar::getAvatarEntityData() const { @@ -2175,65 +2162,6 @@ void MyAvatar::loadAvatarEntityDataFromSettings() { }); } -void MyAvatar::saveAttachmentData(const AttachmentData& attachment) const { - Settings settings; - settings.beginGroup("savedAttachmentData"); - settings.beginGroup(_skeletonModel->getURL().toString()); - settings.beginGroup(attachment.modelURL.toString()); - settings.setValue("jointName", attachment.jointName); - - settings.beginGroup(attachment.jointName); - settings.setValue("translation_x", attachment.translation.x); - settings.setValue("translation_y", attachment.translation.y); - settings.setValue("translation_z", attachment.translation.z); - glm::vec3 eulers = safeEulerAngles(attachment.rotation); - settings.setValue("rotation_x", eulers.x); - settings.setValue("rotation_y", eulers.y); - settings.setValue("rotation_z", eulers.z); - settings.setValue("scale", attachment.scale); - - settings.endGroup(); - settings.endGroup(); - settings.endGroup(); - settings.endGroup(); -} - -AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL, const QString& jointName) const { - Settings settings; - settings.beginGroup("savedAttachmentData"); - settings.beginGroup(_skeletonModel->getURL().toString()); - settings.beginGroup(modelURL.toString()); - - AttachmentData attachment; - attachment.modelURL = modelURL; - if (jointName.isEmpty()) { - attachment.jointName = settings.value("jointName").toString(); - } else { - attachment.jointName = jointName; - } - settings.beginGroup(attachment.jointName); - if (settings.contains("translation_x")) { - attachment.translation.x = loadSetting(settings, "translation_x", 0.0f); - attachment.translation.y = loadSetting(settings, "translation_y", 0.0f); - attachment.translation.z = loadSetting(settings, "translation_z", 0.0f); - glm::vec3 eulers; - eulers.x = loadSetting(settings, "rotation_x", 0.0f); - eulers.y = loadSetting(settings, "rotation_y", 0.0f); - eulers.z = loadSetting(settings, "rotation_z", 0.0f); - attachment.rotation = glm::quat(eulers); - attachment.scale = loadSetting(settings, "scale", 1.0f); - } else { - attachment = AttachmentData(); - } - - settings.endGroup(); - settings.endGroup(); - settings.endGroup(); - settings.endGroup(); - - return attachment; -} - bool MyAvatar::isMyAvatarURLProtected() const { return !ScriptPermissions::isCurrentScriptAllowed(ScriptPermissions::Permission::SCRIPT_PERMISSION_GET_AVATAR_URL); } @@ -2994,171 +2922,6 @@ SharedSoundPointer MyAvatar::getCollisionSound() { return _collisionSound; } -void MyAvatar::attach(const QString& modelURL, const QString& jointName, - const glm::vec3& translation, const glm::quat& rotation, - float scale, bool isSoft, - bool allowDuplicates, bool useSaved) { - if (QThread::currentThread() != thread()) { - BLOCKING_INVOKE_METHOD(this, "attach", - Q_ARG(const QString&, modelURL), - Q_ARG(const QString&, jointName), - Q_ARG(const glm::vec3&, translation), - Q_ARG(const glm::quat&, rotation), - Q_ARG(float, scale), - Q_ARG(bool, isSoft), - Q_ARG(bool, allowDuplicates), - Q_ARG(bool, useSaved) - ); - return; - } - if (!DependencyManager::get()->getThisNodeCanRezAvatarEntities()) { - qCDebug(interfaceapp) << "Ignoring attach() because don't have canRezAvatarEntities permission on domain"; - return; - } - - AttachmentData data; - data.modelURL = modelURL; - data.jointName = jointName; - data.translation = translation; - data.rotation = rotation; - data.scale = scale; - data.isSoft = isSoft; - EntityItemProperties properties; - attachmentDataToEntityProperties(data, properties); - DependencyManager::get()->addEntity(properties, true); - emit attachmentsChanged(); -} - -void MyAvatar::detachOne(const QString& modelURL, const QString& jointName) { - if (QThread::currentThread() != thread()) { - BLOCKING_INVOKE_METHOD(this, "detachOne", - Q_ARG(const QString&, modelURL), - Q_ARG(const QString&, jointName) - ); - return; - } - if (!DependencyManager::get()->getThisNodeCanRezAvatarEntities()) { - qCDebug(interfaceapp) << "Ignoring detachOne() because don't have canRezAvatarEntities permission on domain"; - return; - } - - QUuid entityID; - if (findAvatarEntity(modelURL, jointName, entityID)) { - DependencyManager::get()->deleteEntity(entityID); - } - emit attachmentsChanged(); -} - -void MyAvatar::detachAll(const QString& modelURL, const QString& jointName) { - if (QThread::currentThread() != thread()) { - BLOCKING_INVOKE_METHOD(this, "detachAll", - Q_ARG(const QString&, modelURL), - Q_ARG(const QString&, jointName) - ); - return; - } - if (!DependencyManager::get()->getThisNodeCanRezAvatarEntities()) { - qCDebug(interfaceapp) << "Ignoring detachAll() because don't have canRezAvatarEntities permission on domain"; - return; - } - - QUuid entityID; - while (findAvatarEntity(modelURL, jointName, entityID)) { - DependencyManager::get()->deleteEntity(entityID); - } - emit attachmentsChanged(); -} - -void MyAvatar::setAttachmentData(const QVector& attachmentData) { - if (QThread::currentThread() != thread()) { - BLOCKING_INVOKE_METHOD(this, "setAttachmentData", - Q_ARG(const QVector&, attachmentData)); - return; - } - if (!DependencyManager::get()->getThisNodeCanRezAvatarEntities()) { - qCDebug(interfaceapp) << "Ignoring setAttachmentData() because don't have canRezAvatarEntities permission on domain"; - return; - } - - std::vector newEntitiesProperties; - for (auto& data : attachmentData) { - QUuid entityID; - EntityItemProperties properties; - if (findAvatarEntity(data.modelURL.toString(), data.jointName, entityID)) { - properties = DependencyManager::get()->getEntityProperties(entityID); - } - attachmentDataToEntityProperties(data, properties); - newEntitiesProperties.push_back(properties); - } - - // clear any existing wearables - clearWornAvatarEntities(); - - for (auto& properties : newEntitiesProperties) { - DependencyManager::get()->addEntity(properties, true); - } - emit attachmentsChanged(); -} - -QVector MyAvatar::getAttachmentData() const { - QVector attachmentData; - - if (!DependencyManager::get()->getThisNodeCanRezAvatarEntities()) { - qCDebug(interfaceapp) << "Ignoring getAttachmentData() because don't have canRezAvatarEntities permission on domain"; - return attachmentData; - } - - QList avatarEntityIDs; - _avatarEntitiesLock.withReadLock([&] { - avatarEntityIDs = _packedAvatarEntityData.keys(); - }); - for (const auto& entityID : avatarEntityIDs) { - auto properties = DependencyManager::get()->getEntityProperties(entityID); - AttachmentData data = entityPropertiesToAttachmentData(properties); - attachmentData.append(data); - } - return attachmentData; -} - -QVariantList MyAvatar::getAttachmentsVariant() const { - QVariantList result; - - if (!DependencyManager::get()->getThisNodeCanRezAvatarEntities()) { - qCDebug(interfaceapp) - << "Ignoring getAttachmentsVariant() because don't have canRezAvatarEntities permission on domain"; - return result; - } - - for (const auto& attachment : getAttachmentData()) { - result.append(attachment.toVariant()); - } - return result; -} - -void MyAvatar::setAttachmentsVariant(const QVariantList& variant) { - if (QThread::currentThread() != thread()) { - BLOCKING_INVOKE_METHOD(this, "setAttachmentsVariant", - Q_ARG(const QVariantList&, variant)); - return; - } - - if (!DependencyManager::get()->getThisNodeCanRezAvatarEntities()) { - qCDebug(interfaceapp) - << "Ignoring setAttachmentsVariant() because don't have canRezAvatarEntities permission on domain"; - return; - } - - QVector newAttachments; - newAttachments.reserve(variant.size()); - for (const auto& attachmentVar : variant) { - AttachmentData attachment; - if (attachment.fromVariant(attachmentVar)) { - newAttachments.append(attachment); - } - } - setAttachmentData(newAttachments); -} - bool MyAvatar::findAvatarEntity(const QString& modelURL, const QString& jointName, QUuid& entityID) { QList avatarEntityIDs; _avatarEntitiesLock.withReadLock([&] { @@ -3174,34 +2937,6 @@ bool MyAvatar::findAvatarEntity(const QString& modelURL, const QString& jointNam return false; } -AttachmentData MyAvatar::entityPropertiesToAttachmentData(const EntityItemProperties& properties) const { - AttachmentData data; - data.modelURL = properties.getModelURL(); - data.translation = properties.getLocalPosition(); - data.rotation = properties.getLocalRotation(); - data.isSoft = properties.getRelayParentJoints(); - int jointIndex = (int)properties.getParentJointIndex(); - if (jointIndex > -1 && jointIndex < getJointNames().size()) { - data.jointName = getJointNames()[jointIndex]; - } - return data; -} - -void MyAvatar::attachmentDataToEntityProperties(const AttachmentData& data, EntityItemProperties& properties) { - QString url = data.modelURL.toString(); - properties.setName(QFileInfo(url).baseName()); - properties.setType(EntityTypes::Model); - properties.setParentID(AVATAR_SELF_ID); - properties.setLocalPosition(data.translation); - properties.setLocalRotation(data.rotation); - if (!data.isSoft) { - properties.setParentJointIndex(getJointIndex(data.jointName)); - } else { - properties.setRelayParentJoints(true); - } - properties.setModelURL(url); -} - void MyAvatar::initHeadBones() { int neckJointIndex = -1; if (_skeletonModel->isLoaded()) { @@ -3444,22 +3179,6 @@ void MyAvatar::preDisplaySide(const RenderArgs* renderArgs) { if (shouldDrawHead != _prevShouldDrawHead) { _cauterizationNeedsUpdate = true; _skeletonModel->setEnableCauterization(!shouldDrawHead); - - for (int i = 0; i < _attachmentData.size(); i++) { - if (_attachmentData[i].jointName.compare("Head", Qt::CaseInsensitive) == 0 || - _attachmentData[i].jointName.compare("Neck", Qt::CaseInsensitive) == 0 || - _attachmentData[i].jointName.compare("LeftEye", Qt::CaseInsensitive) == 0 || - _attachmentData[i].jointName.compare("RightEye", Qt::CaseInsensitive) == 0 || - _attachmentData[i].jointName.compare("HeadTop_End", Qt::CaseInsensitive) == 0 || - _attachmentData[i].jointName.compare("Face", Qt::CaseInsensitive) == 0) { - uint8_t modelRenderTagBits = shouldDrawHead ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_SECONDARY_VIEW; - - _attachmentModels[i]->setTagMask(modelRenderTagBits); - _attachmentModels[i]->setGroupCulled(false); - _attachmentModels[i]->setCanCastShadow(true); - _attachmentModels[i]->setVisibleInScene(true, qApp->getMain3DScene()); - } - } } _prevShouldDrawHead = shouldDrawHead; } @@ -3530,8 +3249,9 @@ bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const { bool firstPerson = qApp->getCamera().getMode() == CAMERA_MODE_FIRST_PERSON_LOOK_AT || qApp->getCamera().getMode() == CAMERA_MODE_FIRST_PERSON; bool overrideAnim = _skeletonModel ? _skeletonModel->getRig().isPlayingOverrideAnimation() : false; + bool isInMirror = renderArgs->_mirrorDepth > 0; bool insideHead = cameraInsideHead(renderArgs->getViewFrustum().getPosition()); - return !defaultMode || (!firstPerson && !insideHead) || (overrideAnim && !insideHead); + return !defaultMode || isInMirror || (!firstPerson && !insideHead) || (overrideAnim && !insideHead); } void MyAvatar::setRotationRecenterFilterLength(float length) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 60c07ad42cb..2777d2c82fd 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -141,8 +141,6 @@ class MyAvatar : public Avatar { * @property {boolean} lookAtSnappingEnabled=true - true if the avatar's eyes snap to look at another avatar's * eyes when the other avatar is in the line of sight and also has lookAtSnappingEnabled == true. * @property {string} skeletonModelURL - The avatar's FST file. - * @property {AttachmentData[]} attachmentData - Information on the avatar's attachments. - *

Deprecated: This property is deprecated and will be removed. Use avatar entities instead.

* @property {string[]} jointNames - The list of joints in the current avatar model. Read-only. * @property {Uuid} sessionUUID - Unique ID of the avatar in the domain. Read-only. * @property {Mat4} sensorToWorldMatrix - The scale, rotation, and translation transform from the user's real world to the @@ -326,17 +324,10 @@ class MyAvatar : public Avatar { * @borrows Avatar.getJointIndex as getJointIndex * @borrows Avatar.getJointNames as getJointNames * @borrows Avatar.setBlendshape as setBlendshape - * @borrows Avatar.getAttachmentsVariant as getAttachmentsVariant - * @borrows Avatar.setAttachmentsVariant as setAttachmentsVariant * @borrows Avatar.updateAvatarEntity as updateAvatarEntity * @borrows Avatar.clearAvatarEntity as clearAvatarEntity * @borrows Avatar.setForceFaceTrackerConnected as setForceFaceTrackerConnected * @borrows Avatar.setSkeletonModelURL as setSkeletonModelURL - * @borrows Avatar.getAttachmentData as getAttachmentData - * @borrows Avatar.setAttachmentData as setAttachmentData - * @borrows Avatar.attach as attach - * @borrows Avatar.detachOne as detachOne - * @borrows Avatar.detachAll as detachAll * @comment Avatar.getAvatarEntityData as getAvatarEntityData - Don't borrow because implementation is different. * @comment Avatar.setAvatarEntityData as setAvatarEntityData - Don't borrow because implementation is different. * @borrows Avatar.getSensorToWorldMatrix as getSensorToWorldMatrix @@ -590,8 +581,6 @@ class MyAvatar : public Avatar { static void registerMetaTypes(ScriptEnginePointer engine); void registerProperties(ScriptEnginePointer engine); - virtual void simulateAttachments(float deltaTime) override; - AudioListenerMode getAudioListenerModeHead() const { return FROM_HEAD; } AudioListenerMode getAudioListenerModeCamera() const { return FROM_CAMERA; } AudioListenerMode getAudioListenerModeCustom() const { return CUSTOM; } @@ -1073,9 +1062,6 @@ class MyAvatar : public Avatar { void loadData(); void loadAvatarEntityDataFromSettings(); - void saveAttachmentData(const AttachmentData& attachment) const; - AttachmentData loadAttachmentData(const QUrl& modelURL, const QString& jointName = QString()) const; - // Set what driving keys are being pressed to control thrust levels void clearDriveKeys(); void setDriveKey(DriveKeys key, float val); @@ -1822,12 +1808,6 @@ class MyAvatar : public Avatar { float computeStandingHeightMode(const controller::Pose& head); glm::quat computeAverageHeadRotation(const controller::Pose& head); - virtual void setAttachmentData(const QVector& attachmentData) override; - virtual QVector getAttachmentData() const override; - - virtual QVariantList getAttachmentsVariant() const override; - virtual void setAttachmentsVariant(const QVariantList& variant) override; - glm::vec3 getNextPosition() { return _goToPending ? _goToPosition : getWorldPosition(); } void prepareAvatarEntityDataForReload(); @@ -2610,16 +2590,6 @@ public slots: */ void sensorToWorldScaleChanged(float sensorToWorldScale); - /*@jsdoc - * Triggered when the a model is attached to or detached from one of the avatar's joints using one of - * {@link MyAvatar.attach|attach}, {@link MyAvatar.detachOne|detachOne}, {@link MyAvatar.detachAll|detachAll}, or - * {@link MyAvatar.setAttachmentData|setAttachmentData}. - * @function MyAvatar.attachmentsChanged - * @returns {Signal} - * @deprecated This signal is deprecated and will be removed. Use avatar entities instead. - */ - void attachmentsChanged(); - /*@jsdoc * Triggered when the avatar's size changes. This can be due to the user changing the size of their avatar or the domain * limiting the size of their avatar. @@ -2701,18 +2671,7 @@ private slots: void setScriptedMotorFrame(QString frame); void setScriptedMotorMode(QString mode); - // Attachments - virtual void attach(const QString& modelURL, const QString& jointName = QString(), - const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(), - float scale = 1.0f, bool isSoft = false, - bool allowDuplicates = false, bool useSaved = true) override; - - virtual void detachOne(const QString& modelURL, const QString& jointName = QString()) override; - virtual void detachAll(const QString& modelURL, const QString& jointName = QString()) override; - - // Attachments/Avatar Entity - void attachmentDataToEntityProperties(const AttachmentData& data, EntityItemProperties& properties); - AttachmentData entityPropertiesToAttachmentData(const EntityItemProperties& properties) const; + // Avatar Entities bool findAvatarEntity(const QString& modelURL, const QString& jointName, QUuid& entityID); void addAvatarEntitiesToTree(); diff --git a/interface/src/avatar/OtherAvatar.cpp b/interface/src/avatar/OtherAvatar.cpp index fe0e83dfa04..ab33a6f0019 100644 --- a/interface/src/avatar/OtherAvatar.cpp +++ b/interface/src/avatar/OtherAvatar.cpp @@ -44,7 +44,7 @@ OtherAvatar::OtherAvatar(QThread* thread) : Avatar(thread) { // give the pointer to our head to inherited _headData variable from AvatarData _headData = new Head(this); _skeletonModel = std::make_shared(this, nullptr); - _skeletonModel->setLoadingPriority(OTHERAVATAR_LOADING_PRIORITY); + _skeletonModel->setLoadingPriorityOperator([]() { return OTHERAVATAR_LOADING_PRIORITY; }); connect(_skeletonModel.get(), &Model::setURLFinished, this, &Avatar::setModelURLFinished); connect(_skeletonModel.get(), &Model::rigReady, this, &Avatar::rigReady); connect(_skeletonModel.get(), &Model::rigReset, this, &Avatar::rigReset); @@ -316,7 +316,6 @@ void OtherAvatar::simulate(float deltaTime, bool inView) { { PROFILE_RANGE(simulation, "misc"); measureMotionDerivatives(deltaTime); - simulateAttachments(deltaTime); updatePalms(); } { @@ -384,7 +383,7 @@ void OtherAvatar::debugJointData() const { } void OtherAvatar::handleChangedAvatarEntityData() { - PerformanceTimer perfTimer("attachments"); + PerformanceTimer perfTimer("avatarEntities"); // AVATAR ENTITY UPDATE FLOW // - if queueEditEntityMessage() sees "AvatarEntity" HostType it calls _myAvatar->storeAvatarEntityDataPayload() @@ -596,7 +595,8 @@ void OtherAvatar::handleChangedAvatarEntityData() { } }); - setAvatarEntityDataChanged(false); + _avatarEntityDataChanged = false; + _hasCheckedForAvatarEntities = true; } void OtherAvatar::onAddAttachedAvatarEntity(const QUuid& id) { @@ -631,3 +631,11 @@ void OtherAvatar::updateAttachedAvatarEntities() { } } } + +void OtherAvatar::onIdentityRecieved() { + if (_avatarEntityIdentityCountdown > 0) { + _avatarEntityIdentityCountdown--; + } else { + _hasCheckedForAvatarEntities = true; + } +} diff --git a/interface/src/avatar/OtherAvatar.h b/interface/src/avatar/OtherAvatar.h index cfe0c8332d8..094644a1d30 100644 --- a/interface/src/avatar/OtherAvatar.h +++ b/interface/src/avatar/OtherAvatar.h @@ -73,6 +73,8 @@ class OtherAvatar : public Avatar { void onAddAttachedAvatarEntity(const QUuid& id); void onRemoveAttachedAvatarEntity(const QUuid& id); + void onIdentityRecieved() override; + class AvatarEntityDataHash { public: AvatarEntityDataHash(uint32_t h) : hash(h) {}; @@ -91,6 +93,14 @@ class OtherAvatar : public Avatar { uint8_t _workloadRegion { workload::Region::INVALID }; BodyLOD _bodyLOD { BodyLOD::Sphere }; bool _needsDetailedRebuild { false }; + +private: + // When determining _hasCheckedForAvatarEntities for OtherAvatars, we can set it to true in + // handleChangedAvatarEntityData if we have avatar entities. But we never receive explicit + // confirmation from the avatar mixer if we don't have any. So instead, we wait to receive + // a few identity packets, and assume that if we haven't gotten any avatar entities by then, + // that we're safe to say there aren't any. + uint8_t _avatarEntityIdentityCountdown { 2 }; }; using OtherAvatarPointer = std::shared_ptr; diff --git a/interface/src/raypick/ParabolaPointer.h b/interface/src/raypick/ParabolaPointer.h index 59168be5edb..6415baac14e 100644 --- a/interface/src/raypick/ParabolaPointer.h +++ b/interface/src/raypick/ParabolaPointer.h @@ -10,7 +10,7 @@ #include "PathPointer.h" -#include +#include #include diff --git a/interface/src/scripting/AccountServicesScriptingInterface.cpp b/interface/src/scripting/AccountServicesScriptingInterface.cpp index 35e9f3b36d0..e77fb13b891 100644 --- a/interface/src/scripting/AccountServicesScriptingInterface.cpp +++ b/interface/src/scripting/AccountServicesScriptingInterface.cpp @@ -159,8 +159,8 @@ bool DownloadInfoResultFromScriptValue(const ScriptValue& object, DownloadInfoRe DownloadInfoResult AccountServicesScriptingInterface::getDownloadInfo() { DownloadInfoResult result; - foreach(const auto& resource, ResourceCache::getLoadingRequests()) { - result.downloading.append(resource->getProgress() * 100.0f); + foreach(const auto& resourcePair, ResourceCache::getLoadingRequests()) { + result.downloading.append(resourcePair.first->getProgress() * 100.0f); } result.pending = ResourceCache::getPendingRequestCount(); return result; diff --git a/interface/src/scripting/RenderScriptingInterface.cpp b/interface/src/scripting/RenderScriptingInterface.cpp index 12814aa6b6a..e126a5734e6 100644 --- a/interface/src/scripting/RenderScriptingInterface.cpp +++ b/interface/src/scripting/RenderScriptingInterface.cpp @@ -9,12 +9,15 @@ // #include "RenderScriptingInterface.h" +#include #include #include "LightingModel.h" #include #include "ScreenName.h" +#include + STATIC_SCRIPT_TYPES_INITIALIZER((+[](ScriptManager* manager){ auto scriptEngine = manager->engine().get(); @@ -42,16 +45,17 @@ RenderScriptingInterface::RenderScriptingInterface() { }); } - void RenderScriptingInterface::loadSettings() { _renderSettingLock.withReadLock([&] { - _renderMethod = (_renderMethodSetting.get()); - _shadowsEnabled = (_shadowsEnabledSetting.get()); - _ambientOcclusionEnabled = (_ambientOcclusionEnabledSetting.get()); - //_antialiasingMode = (_antialiasingModeSetting.get()); + _renderMethod = _renderMethodSetting.get(); + _shadowsEnabled = _shadowsEnabledSetting.get(); + _hazeEnabled = _hazeEnabledSetting.get(); + _bloomEnabled = _bloomEnabledSetting.get(); + _ambientOcclusionEnabled = _ambientOcclusionEnabledSetting.get(); + _proceduralMaterialsEnabled = _proceduralMaterialsEnabledSetting.get(); _antialiasingMode = static_cast(_antialiasingModeSetting.get()); - _viewportResolutionScale = (_viewportResolutionScaleSetting.get()); - _fullScreenScreen = (_fullScreenScreenSetting.get()); + _viewportResolutionScale = _viewportResolutionScaleSetting.get(); + _fullScreenScreen = _fullScreenScreenSetting.get(); }); // If full screen screen is not initialized, or set to an invalid value, @@ -64,7 +68,10 @@ void RenderScriptingInterface::loadSettings() { forceRenderMethod((RenderMethod)_renderMethod); forceShadowsEnabled(_shadowsEnabled); + forceHazeEnabled(_hazeEnabled); + forceBloomEnabled(_bloomEnabled); forceAmbientOcclusionEnabled(_ambientOcclusionEnabled); + forceProceduralMaterialsEnabled(_proceduralMaterialsEnabled); forceAntialiasingMode(_antialiasingMode); forceViewportResolutionScale(_viewportResolutionScale); } @@ -79,14 +86,35 @@ void RenderScriptingInterface::setRenderMethod(RenderMethod renderMethod) { emit settingsChanged(); } } + +void recursivelyUpdateMirrorRenderMethods(const QString& parentTaskName, int renderMethod, int depth) { + if (depth == RenderMirrorTask::MAX_MIRROR_DEPTH) { + return; + } + + for (size_t mirrorIndex = 0; mirrorIndex < RenderMirrorTask::MAX_MIRRORS_PER_LEVEL; mirrorIndex++) { + std::string mirrorTaskString = parentTaskName.toStdString() + ".RenderMirrorView" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth) + ".DeferredForwardSwitch"; + auto mirrorConfig = dynamic_cast(qApp->getRenderEngine()->getConfiguration()->getConfig(QString::fromStdString(mirrorTaskString))); + if (mirrorConfig) { + mirrorConfig->setBranch((int)renderMethod); + recursivelyUpdateMirrorRenderMethods(QString::fromStdString(mirrorTaskString) + (renderMethod == 1 ? ".RenderForwardTask" : ".RenderShadowsAndDeferredTask.RenderDeferredTask"), + renderMethod, depth + 1); + } + } +} + void RenderScriptingInterface::forceRenderMethod(RenderMethod renderMethod) { _renderSettingLock.withWriteLock([&] { _renderMethod = (int)renderMethod; _renderMethodSetting.set((int)renderMethod); - auto config = dynamic_cast(qApp->getRenderEngine()->getConfiguration()->getConfig("RenderMainView.DeferredForwardSwitch")); + QString configName = "RenderMainView.DeferredForwardSwitch"; + auto config = dynamic_cast(qApp->getRenderEngine()->getConfiguration()->getConfig(configName)); if (config) { config->setBranch((int)renderMethod); + + recursivelyUpdateMirrorRenderMethods(configName + (renderMethod == RenderMethod::FORWARD ? ".RenderForwardTask" : ".RenderShadowsAndDeferredTask.RenderDeferredTask"), + (int)renderMethod, 0); } }); } @@ -96,6 +124,33 @@ QStringList RenderScriptingInterface::getRenderMethodNames() const { return refrenderMethodNames; } +void recursivelyUpdateLightingModel(const QString& parentTaskName, std::function updateLambda, int depth = -1) { + if (depth == -1) { + auto secondaryLightingModelConfig = qApp->getRenderEngine()->getConfiguration()->getConfig("RenderSecondView.LightingModel"); + if (secondaryLightingModelConfig) { + updateLambda(secondaryLightingModelConfig); + } + + auto mainLightingModelConfig = qApp->getRenderEngine()->getConfiguration()->getConfig("RenderMainView.LightingModel"); + if (mainLightingModelConfig) { + updateLambda(mainLightingModelConfig); + } + + recursivelyUpdateLightingModel("RenderMainView", updateLambda, depth + 1); + } else if (depth == RenderMirrorTask::MAX_MIRROR_DEPTH) { + return; + } + + for (size_t mirrorIndex = 0; mirrorIndex < RenderMirrorTask::MAX_MIRRORS_PER_LEVEL; mirrorIndex++) { + std::string mirrorTaskString = parentTaskName.toStdString() + ".RenderMirrorView" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth); + auto lightingModelConfig = qApp->getRenderEngine()->getConfiguration()->getConfig(mirrorTaskString + ".LightingModel"); + if (lightingModelConfig) { + updateLambda(lightingModelConfig); + recursivelyUpdateLightingModel(QString::fromStdString(mirrorTaskString), updateLambda, depth + 1); + } + } +} + bool RenderScriptingInterface::getShadowsEnabled() const { return _shadowsEnabled; } @@ -112,18 +167,49 @@ void RenderScriptingInterface::forceShadowsEnabled(bool enabled) { _shadowsEnabled = (enabled); _shadowsEnabledSetting.set(enabled); - auto renderConfig = qApp->getRenderEngine()->getConfiguration(); - assert(renderConfig); - auto lightingModelConfig = renderConfig->getConfig("RenderMainView.LightingModel"); - if (lightingModelConfig) { - Menu::getInstance()->setIsOptionChecked(MenuOption::Shadows, enabled); - lightingModelConfig->setShadow(enabled); - } - auto secondaryLightingModelConfig = renderConfig->getConfig("RenderSecondView.LightingModel"); - if (secondaryLightingModelConfig) { - Menu::getInstance()->setIsOptionChecked(MenuOption::Shadows, enabled); - secondaryLightingModelConfig->setShadow(enabled); - } + Menu::getInstance()->setIsOptionChecked(MenuOption::Shadows, enabled); + + recursivelyUpdateLightingModel("", [enabled] (MakeLightingModelConfig *config) { config->setShadow(enabled); }); + }); +} + +bool RenderScriptingInterface::getHazeEnabled() const { + return _hazeEnabled; +} + +void RenderScriptingInterface::setHazeEnabled(bool enabled) { + if (_hazeEnabled != enabled) { + forceHazeEnabled(enabled); + emit settingsChanged(); + } +} + +void RenderScriptingInterface::forceHazeEnabled(bool enabled) { + _renderSettingLock.withWriteLock([&] { + _hazeEnabled = (enabled); + _hazeEnabledSetting.set(enabled); + + recursivelyUpdateLightingModel("", [enabled] (MakeLightingModelConfig *config) { config->setHaze(enabled); }); + }); +} + +bool RenderScriptingInterface::getBloomEnabled() const { + return _bloomEnabled; +} + +void RenderScriptingInterface::setBloomEnabled(bool enabled) { + if (_bloomEnabled != enabled) { + forceBloomEnabled(enabled); + emit settingsChanged(); + } +} + +void RenderScriptingInterface::forceBloomEnabled(bool enabled) { + _renderSettingLock.withWriteLock([&] { + _bloomEnabled = (enabled); + _bloomEnabledSetting.set(enabled); + + recursivelyUpdateLightingModel("", [enabled] (MakeLightingModelConfig *config) { config->setBloom(enabled); }); }); } @@ -143,11 +229,30 @@ void RenderScriptingInterface::forceAmbientOcclusionEnabled(bool enabled) { _ambientOcclusionEnabled = (enabled); _ambientOcclusionEnabledSetting.set(enabled); - auto lightingModelConfig = qApp->getRenderEngine()->getConfiguration()->getConfig("RenderMainView.LightingModel"); - if (lightingModelConfig) { - Menu::getInstance()->setIsOptionChecked(MenuOption::AmbientOcclusion, enabled); - lightingModelConfig->setAmbientOcclusion(enabled); - } + Menu::getInstance()->setIsOptionChecked(MenuOption::AmbientOcclusion, enabled); + + recursivelyUpdateLightingModel("", [enabled] (MakeLightingModelConfig *config) { config->setAmbientOcclusion(enabled); }); + }); +} + +bool RenderScriptingInterface::getProceduralMaterialsEnabled() const { + return _proceduralMaterialsEnabled; +} + +void RenderScriptingInterface::setProceduralMaterialsEnabled(bool enabled) { + if (_proceduralMaterialsEnabled != enabled) { + forceProceduralMaterialsEnabled(enabled); + emit settingsChanged(); + } +} + +void RenderScriptingInterface::forceProceduralMaterialsEnabled(bool enabled) { + _renderSettingLock.withWriteLock([&] { + _proceduralMaterialsEnabled = (enabled); + _proceduralMaterialsEnabledSetting.set(enabled); + + Menu::getInstance()->setIsOptionChecked(MenuOption::MaterialProceduralShaders, enabled); + Procedural::enableProceduralShaders = enabled; }); } @@ -187,44 +292,51 @@ void setAntialiasingModeForView(AntialiasingConfig::Mode mode, JitterSampleConfi } } -void RenderScriptingInterface::forceAntialiasingMode(AntialiasingConfig::Mode mode) { - _renderSettingLock.withWriteLock([&] { - _antialiasingMode = mode; - - auto mainViewJitterCamConfig = qApp->getRenderEngine()->getConfiguration()->getConfig("RenderMainView.JitterCam"); - auto mainViewAntialiasingConfig = qApp->getRenderEngine()->getConfiguration()->getConfig("RenderMainView.Antialiasing"); +void recursivelyUpdateAntialiasingMode(const QString& parentTaskName, AntialiasingConfig::Mode mode, int depth = -1) { + if (depth == -1) { auto secondViewJitterCamConfig = qApp->getRenderEngine()->getConfiguration()->getConfig("RenderSecondView.JitterCam"); auto secondViewAntialiasingConfig = qApp->getRenderEngine()->getConfiguration()->getConfig("RenderSecondView.Antialiasing"); - if (mode != AntialiasingConfig::Mode::NONE - && mode != AntialiasingConfig::Mode::TAA - && mode != AntialiasingConfig::Mode::FXAA) { - _antialiasingMode = AntialiasingConfig::Mode::NONE; + if (secondViewJitterCamConfig && secondViewAntialiasingConfig) { + setAntialiasingModeForView(mode, secondViewJitterCamConfig, secondViewAntialiasingConfig); } + + auto mainViewJitterCamConfig = qApp->getRenderEngine()->getConfiguration()->getConfig("RenderMainView.JitterCam"); + auto mainViewAntialiasingConfig = qApp->getRenderEngine()->getConfiguration()->getConfig("RenderMainView.Antialiasing"); if (mainViewJitterCamConfig && mainViewAntialiasingConfig) { setAntialiasingModeForView( mode, mainViewJitterCamConfig, mainViewAntialiasingConfig); } - if (secondViewJitterCamConfig && secondViewAntialiasingConfig) { - setAntialiasingModeForView( mode, secondViewJitterCamConfig, secondViewAntialiasingConfig); - } - - _antialiasingModeSetting.set(_antialiasingMode); - }); -} + recursivelyUpdateAntialiasingMode("RenderMainView", mode, depth + 1); + } else if (depth == RenderMirrorTask::MAX_MIRROR_DEPTH) { + return; + } -float RenderScriptingInterface::getViewportResolutionScale() const { - return _viewportResolutionScale; + for (size_t mirrorIndex = 0; mirrorIndex < RenderMirrorTask::MAX_MIRRORS_PER_LEVEL; mirrorIndex++) { + std::string mirrorTaskString = parentTaskName.toStdString() + ".RenderMirrorView" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth); + auto jitterCamConfig = qApp->getRenderEngine()->getConfiguration()->getConfig(mirrorTaskString + ".JitterCam"); + auto antialiasingConfig = qApp->getRenderEngine()->getConfiguration()->getConfig(mirrorTaskString + ".Antialiasing"); + if (jitterCamConfig && antialiasingConfig) { + setAntialiasingModeForView(mode, jitterCamConfig, antialiasingConfig); + recursivelyUpdateAntialiasingMode(QString::fromStdString(mirrorTaskString), mode, depth + 1); + } + } } -void RenderScriptingInterface::setViewportResolutionScale(float scale) { - if (_viewportResolutionScale != scale) { - forceViewportResolutionScale(scale); - emit settingsChanged(); +void RenderScriptingInterface::forceAntialiasingMode(AntialiasingConfig::Mode mode) { + if ((int)mode < 0 || mode >= AntialiasingConfig::Mode::MODE_COUNT) { + mode = AntialiasingConfig::Mode::NONE; } + + _renderSettingLock.withWriteLock([&] { + _antialiasingMode = mode; + _antialiasingModeSetting.set(_antialiasingMode); + + recursivelyUpdateAntialiasingMode("", _antialiasingMode); + }); } void RenderScriptingInterface::setVerticalFieldOfView(float fieldOfView) { - if (getViewportResolutionScale() != fieldOfView) { + if (qApp->getFieldOfView() != fieldOfView) { qApp->setFieldOfView(fieldOfView); emit settingsChanged(); } @@ -264,6 +376,16 @@ QString RenderScriptingInterface::getFullScreenScreen() const { return _fullScreenScreen; } +float RenderScriptingInterface::getViewportResolutionScale() const { + return _viewportResolutionScale; +} + +void RenderScriptingInterface::setViewportResolutionScale(float scale) { + if (_viewportResolutionScale != scale) { + forceViewportResolutionScale(scale); + emit settingsChanged(); + } +} void RenderScriptingInterface::forceViewportResolutionScale(float scale) { // just not negative values or zero diff --git a/interface/src/scripting/RenderScriptingInterface.h b/interface/src/scripting/RenderScriptingInterface.h index 2025c715105..56b474cf31e 100644 --- a/interface/src/scripting/RenderScriptingInterface.h +++ b/interface/src/scripting/RenderScriptingInterface.h @@ -29,8 +29,12 @@ * * @property {Render.RenderMethod} renderMethod - The render method being used. * @property {boolean} shadowsEnabled - true if shadows are enabled, false if they're disabled. + * @property {boolean} hazeEnabled - true if haze (fog) is enabled, false if it's disabled. + * @property {boolean} bloomEnabled - true if bloom is enabled, false if it's disabled. * @property {boolean} ambientOcclusionEnabled - true if ambient occlusion is enabled, false if it's * disabled. + * @property {boolean} proceduralMaterialsEnabled - true if procedural shaders are enabled, false if + * they're disabled. * @property {integer} antialiasingMode - The active anti-aliasing mode. * @property {number} viewportResolutionScale - The view port resolution scale, > 0.0. */ @@ -38,7 +42,10 @@ class RenderScriptingInterface : public QObject { Q_OBJECT Q_PROPERTY(RenderMethod renderMethod READ getRenderMethod WRITE setRenderMethod NOTIFY settingsChanged) Q_PROPERTY(bool shadowsEnabled READ getShadowsEnabled WRITE setShadowsEnabled NOTIFY settingsChanged) + Q_PROPERTY(bool hazeEnabled READ getHazeEnabled WRITE setHazeEnabled NOTIFY settingsChanged) + Q_PROPERTY(bool bloomEnabled READ getBloomEnabled WRITE setBloomEnabled NOTIFY settingsChanged) Q_PROPERTY(bool ambientOcclusionEnabled READ getAmbientOcclusionEnabled WRITE setAmbientOcclusionEnabled NOTIFY settingsChanged) + Q_PROPERTY(bool proceduralMaterialsEnabled READ getProceduralMaterialsEnabled WRITE setProceduralMaterialsEnabled NOTIFY settingsChanged) Q_PROPERTY(AntialiasingConfig::Mode antialiasingMode READ getAntialiasingMode WRITE setAntialiasingMode NOTIFY settingsChanged) Q_PROPERTY(float viewportResolutionScale READ getViewportResolutionScale WRITE setViewportResolutionScale NOTIFY settingsChanged) Q_PROPERTY(float verticalFieldOfView READ getVerticalFieldOfView WRITE setVerticalFieldOfView NOTIFY settingsChanged) @@ -134,6 +141,34 @@ public slots: */ void setShadowsEnabled(bool enabled); + /*@jsdoc + * Gets whether or not haze is enabled. + * @function Render.getHazeEnabled + * @returns {boolean} true if haze is enabled, false if it's disabled. + */ + bool getHazeEnabled() const; + + /*@jsdoc + * Sets whether or not haze is enabled. + * @function Render.setHazeEnabled + * @param {boolean} enabled - true to enable haze, false to disable. + */ + void setHazeEnabled(bool enabled); + + /*@jsdoc + * Gets whether or not bloom is enabled. + * @function Render.getBloomEnabled + * @returns {boolean} true if bloom is enabled, false if it's disabled. + */ + bool getBloomEnabled() const; + + /*@jsdoc + * Sets whether or not bloom is enabled. + * @function Render.setBloomEnabled + * @param {boolean} enabled - true to enable bloom, false to disable. + */ + void setBloomEnabled(bool enabled); + /*@jsdoc * Gets whether or not ambient occlusion is enabled. * @function Render.getAmbientOcclusionEnabled @@ -148,6 +183,20 @@ public slots: */ void setAmbientOcclusionEnabled(bool enabled); + /*@jsdoc + * Gets whether or not procedural materials are enabled. + * @function Render.getProceduralMaterialsEnabled + * @returns {boolean} true if procedural materials are enabled, false if they're disabled. + */ + bool getProceduralMaterialsEnabled() const; + + /*@jsdoc + * Sets whether or not procedural materials are enabled. + * @function Render.setProceduralMaterialsEnabled + * @param {boolean} enabled - true to enable procedural materials, false to disable. + */ + void setProceduralMaterialsEnabled(bool enabled); + /*@jsdoc * Gets the active anti-aliasing mode. * @function Render.getAntialiasingMode @@ -233,19 +282,23 @@ public slots: mutable ReadWriteLockable _renderSettingLock; // Runtime value of each settings - int _renderMethod{ RENDER_FORWARD ? render::Args::RenderMethod::FORWARD : render::Args::RenderMethod::DEFERRED }; - bool _shadowsEnabled{ true }; - bool _ambientOcclusionEnabled{ false }; - AntialiasingConfig::Mode _antialiasingMode{ AntialiasingConfig::Mode::NONE }; - float _viewportResolutionScale{ 1.0f }; + int _renderMethod { RENDER_FORWARD ? render::Args::RenderMethod::FORWARD : render::Args::RenderMethod::DEFERRED }; + bool _shadowsEnabled { true }; + bool _hazeEnabled { true }; + bool _bloomEnabled { true }; + bool _ambientOcclusionEnabled { true }; + bool _proceduralMaterialsEnabled { true }; + AntialiasingConfig::Mode _antialiasingMode { AntialiasingConfig::Mode::NONE }; + float _viewportResolutionScale { 1.0f }; QString _fullScreenScreen; - // Actual settings saved on disk Setting::Handle _renderMethodSetting { "renderMethod", RENDER_FORWARD ? render::Args::RenderMethod::FORWARD : render::Args::RenderMethod::DEFERRED }; Setting::Handle _shadowsEnabledSetting { "shadowsEnabled", true }; - Setting::Handle _ambientOcclusionEnabledSetting { "ambientOcclusionEnabled", false }; - //Setting::Handle _antialiasingModeSetting { "antialiasingMode", AntialiasingConfig::Mode::TAA }; + Setting::Handle _hazeEnabledSetting { "hazeEnabled", true }; + Setting::Handle _bloomEnabledSetting { "bloomEnabled", true }; + Setting::Handle _ambientOcclusionEnabledSetting { "ambientOcclusionEnabled", true }; + Setting::Handle _proceduralMaterialsEnabledSetting { "proceduralMaterialsEnabled", true }; Setting::Handle _antialiasingModeSetting { "antialiasingMode", AntialiasingConfig::Mode::NONE }; Setting::Handle _viewportResolutionScaleSetting { "viewportResolutionScale", 1.0f }; Setting::Handle _fullScreenScreenSetting { "fullScreenScreen", "" }; @@ -253,7 +306,10 @@ public slots: // Force assign both setting AND runtime value to the parameter value void forceRenderMethod(RenderMethod renderMethod); void forceShadowsEnabled(bool enabled); + void forceHazeEnabled(bool enabled); + void forceBloomEnabled(bool enabled); void forceAmbientOcclusionEnabled(bool enabled); + void forceProceduralMaterialsEnabled(bool enabled); void forceAntialiasingMode(AntialiasingConfig::Mode mode); void forceViewportResolutionScale(float scale); diff --git a/interface/src/ui/DialogsManager.h b/interface/src/ui/DialogsManager.h index 864174296e8..6636c725c80 100644 --- a/interface/src/ui/DialogsManager.h +++ b/interface/src/ui/DialogsManager.h @@ -20,14 +20,10 @@ #include "HMDToolsDialog.h" #include "TestingDialog.h" -class AnimationsDialog; -class AttachmentsDialog; -class CachesSizeDialog; class LodToolsDialog; class OctreeStatsDialog; class ScriptEditorWindow; class TestingDialog; -class QMessageBox; class DomainConnectionDialog; class DialogsManager : public QObject, public Dependency { @@ -77,10 +73,6 @@ private slots: template void maybeCreateDialog(QPointer& member); - QPointer _animationsDialog; - QPointer _attachmentsDialog; - QPointer _cachesSizeDialog; - QPointer _ircInfoBox; QPointer _hmdToolsDialog; QPointer _lodToolsDialog; QPointer _octreeStatsDialog; diff --git a/interface/src/ui/ModelsBrowser.cpp b/interface/src/ui/ModelsBrowser.cpp index 2f422129e31..cd706d0bcb5 100644 --- a/interface/src/ui/ModelsBrowser.cpp +++ b/interface/src/ui/ModelsBrowser.cpp @@ -32,7 +32,7 @@ #include #include -const char* MODEL_TYPE_NAMES[] = { "entities", "heads", "skeletons", "skeletons", "attachments" }; +const char* MODEL_TYPE_NAMES[] = { "entities", "heads", "skeletons", "skeletons" }; static const QString S3_URL = NetworkingConstants::HF_PUBLIC_CDN_URL; static const QString PUBLIC_URL = "http://public.overte.org"; // Changed to Overte but not entirely sure what to do with this yet. diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 0e3a3293757..79e4d0e28c2 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -289,8 +289,8 @@ void Stats::updateStats(bool force) { STAT_UPDATE(entityPacketsInKbps, octreeServerCount ? totalEntityKbps / octreeServerCount : -1); - auto loadingRequests = ResourceCache::getLoadingRequests(); - STAT_UPDATE(downloads, loadingRequests.size()); + auto loadingRequestPairs = ResourceCache::getLoadingRequests(); + STAT_UPDATE(downloads, loadingRequestPairs.size()); STAT_UPDATE(downloadLimit, (int)ResourceCache::getRequestLimit()) STAT_UPDATE(downloadsPending, (int)ResourceCache::getPendingRequestCount()); STAT_UPDATE(processing, DependencyManager::get()->getStat("Processing").toInt()); @@ -298,29 +298,37 @@ void Stats::updateStats(bool force) { // See if the active download urls have changed bool shouldUpdateUrls = _downloads != _downloadUrls.size(); + bool shouldUpdateProgresses = false; if (!shouldUpdateUrls) { for (int i = 0; i < _downloads; i++) { - if (loadingRequests[i]->getURL().toString() != _downloadUrls[i]) { + if (loadingRequestPairs[i].first->getURL().toString() != _downloadUrls[i]) { shouldUpdateUrls = true; break; + } else if (loadingRequestPairs[i].first->getProgress() != _downloadProgresses[i]) { + shouldUpdateProgresses = true; } } } // If the urls have changed, update the list if (shouldUpdateUrls) { _downloadUrls.clear(); - foreach (const auto& resource, loadingRequests) { - _downloadUrls << resource->getURL().toString(); + _downloadPriorities.clear(); + foreach (const auto& resourcePair, loadingRequestPairs) { + _downloadUrls << resourcePair.first->getURL().toString(); + _downloadPriorities << resourcePair.second; } emit downloadUrlsChanged(); + emit downloadPrioritiesChanged(); + shouldUpdateProgresses = true; + } + + if (shouldUpdateProgresses) { + _downloadProgresses.clear(); + foreach (const auto& resourcePair, loadingRequestPairs) { + _downloadProgresses << (int)(100.0f * resourcePair.first->getProgress()); + } + emit downloadProgressesChanged(); } - // TODO fix to match original behavior - //stringstream downloads; - //downloads << "Downloads: "; - //foreach(Resource* resource, ) { - // downloads << (int)(resource->getProgress() * 100.0f) << "% "; - //} - //downloads << "(" << << " pending)"; } // Fourth column, octree stats diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index a3366904bda..b6d5e5ac9c5 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -211,7 +211,10 @@ private: \ * Read-only. * @property {string[]} downloadUrls - The download URLs. * Read-only. - *

Note: Property not available in the API.

+ * @property {number[]} downloadProgresses - The download progresses. + * Read-only. + * @property {number[]} downloadPriorities - The download priorities. + * Read-only. * @property {number} processing - The number of completed downloads being processed. * Read-only. * @property {number} processingPending - The number of completed downloads waiting to be processed. @@ -529,6 +532,8 @@ class Stats : public QQuickItem { STATS_PROPERTY(int, downloadLimit, 0) STATS_PROPERTY(int, downloadsPending, 0) Q_PROPERTY(QStringList downloadUrls READ downloadUrls NOTIFY downloadUrlsChanged) + Q_PROPERTY(QList downloadProgresses READ downloadProgresses NOTIFY downloadProgressesChanged) + Q_PROPERTY(QList downloadPriorities READ downloadPriorities NOTIFY downloadPrioritiesChanged) STATS_PROPERTY(int, processing, 0) STATS_PROPERTY(int, processingPending, 0) STATS_PROPERTY(int, triangles, 0) @@ -622,7 +627,9 @@ class Stats : public QQuickItem { } } - QStringList downloadUrls () { return _downloadUrls; } + QStringList downloadUrls() { return _downloadUrls; } + QList downloadProgresses() { return _downloadProgresses; } + QList downloadPriorities() { return _downloadPriorities; } public slots: @@ -1091,6 +1098,20 @@ public slots: */ void downloadUrlsChanged(); + /*@jsdoc + * Triggered when the value of the downloadProgresses property changes. + * @function Stats.downloadProgressesChanged + * @returns {Signal} + */ + void downloadProgressesChanged(); + + /*@jsdoc + * Triggered when the value of the downloadPriorities property changes. + * @function Stats.downloadPrioritiesChanged + * @returns {Signal} + */ + void downloadPrioritiesChanged(); + /*@jsdoc * Triggered when the value of the processing property changes. * @function Stats.processingChanged @@ -1809,14 +1830,16 @@ public slots: */ private: - int _recentMaxPackets{ 0 } ; // recent max incoming voxel packets to process - bool _resetRecentMaxPacketsSoon{ true }; - bool _expanded{ false }; - bool _showTimingDetails{ false }; - bool _showGameUpdateStats{ false }; + int _recentMaxPackets { 0 } ; // recent max incoming voxel packets to process + bool _resetRecentMaxPacketsSoon { true }; + bool _expanded { false }; + bool _showTimingDetails { false }; + bool _showGameUpdateStats { false }; QString _monospaceFont; const AudioIOStats* _audioStats; - QStringList _downloadUrls = QStringList(); + QStringList _downloadUrls { QStringList() }; + QList _downloadProgresses { QList() }; + QList _downloadPriorities { QList() }; }; #endif // hifi_Stats_h diff --git a/libraries/animation/src/AnimNodeLoader.cpp b/libraries/animation/src/AnimNodeLoader.cpp index 9474c0309f6..066ccec056b 100644 --- a/libraries/animation/src/AnimNodeLoader.cpp +++ b/libraries/animation/src/AnimNodeLoader.cpp @@ -1085,7 +1085,7 @@ AnimNodeLoader::AnimNodeLoader(const QUrl& url) : { _resource = QSharedPointer::create(url); _resource->setSelf(_resource); - _resource->setLoadPriority(this, ANIM_GRAPH_LOAD_PRIORITY); + _resource->setLoadPriorityOperator(this, []() { return ANIM_GRAPH_LOAD_PRIORITY; }); connect(_resource.data(), &Resource::loaded, this, &AnimNodeLoader::onRequestDone); connect(_resource.data(), &Resource::failed, this, &AnimNodeLoader::onRequestError); _resource->ensureLoading(); diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 2df766377f9..8c3a6b118e4 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -132,9 +132,11 @@ void AudioInjector::restart() { bool AudioInjector::inject(bool(AudioInjectorManager::*injection)(const AudioInjectorPointer&)) { AudioInjectorOptions options; + uint32_t numBytes; withWriteLock([&] { _state = AudioInjectorState::NotFinished; options = _options; + numBytes = _audioData->getNumBytes(); }); int byteOffset = 0; @@ -142,6 +144,7 @@ bool AudioInjector::inject(bool(AudioInjectorManager::*injection)(const AudioInj int numChannels = options.ambisonic ? 4 : (options.stereo ? 2 : 1); byteOffset = (int)(AudioConstants::SAMPLE_RATE * options.secondOffset * numChannels); byteOffset *= AudioConstants::SAMPLE_SIZE; + byteOffset = byteOffset % numBytes; } _currentSendOffset = byteOffset; diff --git a/libraries/audio/src/SoundCache.cpp b/libraries/audio/src/SoundCache.cpp index 2b02a566ace..55a32e72375 100644 --- a/libraries/audio/src/SoundCache.cpp +++ b/libraries/audio/src/SoundCache.cpp @@ -35,7 +35,7 @@ SharedSoundPointer SoundCache::getSound(const QUrl& url) { QSharedPointer SoundCache::createResource(const QUrl& url) { auto resource = QSharedPointer(new Sound(url), &Resource::deleter); - resource->setLoadPriority(this, SOUNDS_LOADING_PRIORITY); + resource->setLoadPriorityOperator(this, []() { return SOUNDS_LOADING_PRIORITY; }); return resource; } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index b2d6a6260be..4b63dcb932c 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include "ModelEntityItem.h" @@ -52,13 +51,14 @@ const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f; const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f); const float Avatar::MYAVATAR_LOADING_PRIORITY = (float)M_PI; // Entity priority is computed as atan2(maxDim, distance) which is <= PI / 2 const float Avatar::OTHERAVATAR_LOADING_PRIORITY = MYAVATAR_LOADING_PRIORITY - EPSILON; -const float Avatar::ATTACHMENT_LOADING_PRIORITY = OTHERAVATAR_LOADING_PRIORITY - EPSILON; +const float Avatar::MYAVATAR_ENTITY_LOADING_PRIORITY = MYAVATAR_LOADING_PRIORITY - EPSILON; +const float Avatar::OTHERAVATAR_ENTITY_LOADING_PRIORITY = OTHERAVATAR_LOADING_PRIORITY - EPSILON; namespace render { template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) { ItemKey::Builder keyBuilder = ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(render::hifi::TAG_ALL_VIEWS).withMetaCullGroup(); auto avatarPtr = static_pointer_cast(avatar); - if (!avatarPtr->getEnableMeshVisible()) { + if (!avatarPtr->shouldRender()) { keyBuilder.withInvisible(); } return keyBuilder.build(); @@ -648,22 +648,9 @@ void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& sc _skeletonModel->setTagMask(render::hifi::TAG_ALL_VIEWS); _skeletonModel->setGroupCulled(true); _skeletonModel->setCanCastShadow(true); - _skeletonModel->setVisibleInScene(_isMeshVisible, scene); + _skeletonModel->setVisibleInScene(shouldRender(), scene); processMaterials(); - bool attachmentRenderingNeedsUpdate = false; - for (auto& attachmentModel : _attachmentModels) { - attachmentModel->addToScene(scene, transaction); - attachmentModel->setTagMask(render::hifi::TAG_ALL_VIEWS); - attachmentModel->setGroupCulled(true); - attachmentModel->setCanCastShadow(true); - attachmentModel->setVisibleInScene(_isMeshVisible, scene); - attachmentRenderingNeedsUpdate = true; - } - - if (attachmentRenderingNeedsUpdate) { - updateAttachmentRenderIDs(); - } _mustFadeIn = true; emit DependencyManager::get()->modelAddedToScene(getSessionUUID(), NestableType::Avatar, _skeletonModel); @@ -688,11 +675,6 @@ void Avatar::fadeOut(render::Transaction& transaction, KillAvatarReason reason) void Avatar::fade(render::Transaction& transaction, render::Transition::Type type) { transaction.resetTransitionOnItem(_renderItemID, type); - for (auto& attachmentModel : _attachmentModels) { - for (auto itemId : attachmentModel->fetchRenderItemIDs()) { - transaction.resetTransitionOnItem(itemId, type, _renderItemID); - } - } _lastFadeRequested = type; } @@ -704,9 +686,6 @@ void Avatar::removeFromScene(AvatarSharedPointer self, const render::ScenePointe transaction.removeItem(_renderItemID); render::Item::clearID(_renderItemID); _skeletonModel->removeFromScene(scene, transaction); - for (auto& attachmentModel : _attachmentModels) { - attachmentModel->removeFromScene(scene, transaction); - } emit DependencyManager::get()->modelRemovedFromScene(getSessionUUID(), NestableType::Avatar, _skeletonModel); } @@ -864,10 +843,26 @@ bool Avatar::getEnableMeshVisible() const { } void Avatar::fixupModelsInScene(const render::ScenePointer& scene) { - bool canTryFade{ false }; - - _attachmentsToDelete.clear(); + if (_needsWearablesLoadedCheck && _hasCheckedForAvatarEntities) { + bool wearablesAreLoaded = true; + // Technically, we should be checking for descendant avatar entities that are owned by this avatar. + // But it's sufficient to just check all children entities here. + forEachChild([&](SpatiallyNestablePointer child) { + if (child->getNestableType() == NestableType::Entity) { + auto entity = std::dynamic_pointer_cast(child); + if (entity && !entity->isVisuallyReady()) { + wearablesAreLoaded = false; + } + } + }); + _isReadyToDraw = wearablesAreLoaded; + if (_isReadyToDraw) { + _needMeshVisibleSwitch = true; + } + _needsWearablesLoadedCheck = !wearablesAreLoaded; + } + bool canTryFade = false; // check to see if when we added our models to the scene they were ready, if they were not ready, then // fix them up in the scene render::Transaction transaction; @@ -879,33 +874,15 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) { _skeletonModel->setTagMask(render::hifi::TAG_ALL_VIEWS); _skeletonModel->setGroupCulled(true); _skeletonModel->setCanCastShadow(true); - _skeletonModel->setVisibleInScene(_isMeshVisible, scene); + _skeletonModel->setVisibleInScene(shouldRender(), scene); processMaterials(); canTryFade = true; _isAnimatingScale = true; } - bool attachmentRenderingNeedsUpdate = false; - for (auto attachmentModel : _attachmentModels) { - if (attachmentModel->isRenderable() && attachmentModel->needsFixupInScene()) { - attachmentModel->removeFromScene(scene, transaction); - attachmentModel->addToScene(scene, transaction); - - attachmentModel->setTagMask(render::hifi::TAG_ALL_VIEWS); - attachmentModel->setGroupCulled(true); - attachmentModel->setCanCastShadow(true); - attachmentModel->setVisibleInScene(_isMeshVisible, scene); - attachmentRenderingNeedsUpdate = true; - } - } if (_needMeshVisibleSwitch) { - _skeletonModel->setVisibleInScene(_isMeshVisible, scene); - for (auto attachmentModel : _attachmentModels) { - if (attachmentModel->isRenderable()) { - attachmentModel->setVisibleInScene(_isMeshVisible, scene); - } - } + _skeletonModel->setVisibleInScene(shouldRender(), scene); updateRenderItem(transaction); _needMeshVisibleSwitch = false; } @@ -916,17 +893,6 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) { _mustFadeIn = false; } - for (auto attachmentModelToRemove : _attachmentsToRemove) { - attachmentModelToRemove->removeFromScene(scene, transaction); - attachmentRenderingNeedsUpdate = true; - } - _attachmentsToDelete.insert(_attachmentsToDelete.end(), _attachmentsToRemove.begin(), _attachmentsToRemove.end()); - _attachmentsToRemove.clear(); - - if (attachmentRenderingNeedsUpdate) { - updateAttachmentRenderIDs(); - } - scene->enqueueTransaction(transaction); } @@ -934,48 +900,6 @@ bool Avatar::shouldRenderHead(const RenderArgs* renderArgs) const { return true; } -void Avatar::simulateAttachments(float deltaTime) { - assert(_attachmentModels.size() == _attachmentModelsTexturesLoaded.size()); - PerformanceTimer perfTimer("attachments"); - for (int i = 0; i < (int)_attachmentModels.size(); i++) { - const AttachmentData& attachment = _attachmentData.at(i); - auto& model = _attachmentModels.at(i); - bool texturesLoaded = _attachmentModelsTexturesLoaded.at(i); - - // Watch for texture loading - if (!texturesLoaded && model->getGeometry() && model->getGeometry()->areTexturesLoaded()) { - _attachmentModelsTexturesLoaded[i] = true; - model->updateRenderItems(); - } - - int jointIndex = getJointIndex(attachment.jointName); - glm::vec3 jointPosition; - glm::quat jointRotation; - if (attachment.isSoft) { - // soft attachments do not have transform offsets - model->setTransformNoUpdateRenderItems(Transform(getWorldOrientation() * Quaternions::Y_180, glm::vec3(1.0), getWorldPosition())); - model->simulate(deltaTime); - model->updateRenderItems(); - } else { - if (_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPosition) && - _skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRotation)) { - model->setTransformNoUpdateRenderItems(Transform(jointRotation * attachment.rotation, glm::vec3(1.0), jointPosition + jointRotation * attachment.translation * getModelScale())); - float scale = getModelScale() * attachment.scale; - model->setScaleToFit(true, model->getNaturalDimensions() * scale, true); // hack to force rescale - model->setSnapModelToCenter(false); // hack to force resnap - model->setSnapModelToCenter(true); - model->simulate(deltaTime); - model->updateRenderItems(); - } - } - } - - if (_ancestorChainRenderableVersion != _lastAncestorChainRenderableVersion) { - _lastAncestorChainRenderableVersion = _ancestorChainRenderableVersion; - updateDescendantRenderIDs(); - } -} - float Avatar::getBoundingRadius() const { return getBounds().getLargestDimension() / 2.0f; } @@ -1116,11 +1040,11 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const QByteArray nameUTF8 = renderedDisplayName.toLocal8Bit(); // Render text slightly in front to avoid z-fighting - textTransform.postTranslate(glm::vec3(0.0f, 0.0f, SLIGHTLY_IN_FRONT * displayNameRenderer->getFontSize())); + textTransform.postTranslate(glm::vec3(0.0f, 0.0f, SLIGHTLY_IN_FRONT)); batch.setModelTransform(textTransform); { PROFILE_RANGE_BATCH(batch, __FUNCTION__":renderText"); - displayNameRenderer->draw(batch, text_x, -text_y, glm::vec2(-1.0f), nameUTF8.data(), textColor, true, forward); + displayNameRenderer->draw(batch, { nameUTF8.data(), textColor, { text_x, -text_y }, glm::vec2(-1.0f), forward }); } } } @@ -1580,6 +1504,10 @@ void Avatar::rigReady() { buildSpine2SplineRatioCache(); setSkeletonData(getSkeletonDefaultData()); sendSkeletonData(); + + _needsWearablesLoadedCheck = _skeletonModel && _skeletonModel->isLoaded() && _skeletonModel->getGeometry()->shouldWaitForWearables(); + _needMeshVisibleSwitch = (_isReadyToDraw != !_needsWearablesLoadedCheck); + _isReadyToDraw = !_needsWearablesLoadedCheck; } // rig has been reset. @@ -1631,58 +1559,6 @@ void Avatar::updateFitBoundingBox() { } } -// create new model, can return an instance of a SoftAttachmentModel rather then Model -static std::shared_ptr allocateAttachmentModel(bool isSoft, const Rig& rigOverride, bool isCauterized) { - if (isSoft) { - // cast to std::shared_ptr - std::shared_ptr softModel = std::make_shared(nullptr, rigOverride); - if (isCauterized) { - softModel->flagAsCauterized(); - } - return std::dynamic_pointer_cast(softModel); - } else { - return std::make_shared(); - } -} - -void Avatar::setAttachmentData(const QVector& attachmentData) { - if (QThread::currentThread() != thread()) { - BLOCKING_INVOKE_METHOD(this, "setAttachmentData", - Q_ARG(const QVector, attachmentData)); - return; - } - - auto oldAttachmentData = _attachmentData; - AvatarData::setAttachmentData(attachmentData); - - // if number of attachments has been reduced, remove excess models. - while ((int)_attachmentModels.size() > attachmentData.size()) { - auto attachmentModel = _attachmentModels.back(); - _attachmentModels.pop_back(); - _attachmentModelsTexturesLoaded.pop_back(); - _attachmentsToRemove.push_back(attachmentModel); - } - - for (int i = 0; i < attachmentData.size(); i++) { - if (i == (int)_attachmentModels.size()) { - // if number of attachments has been increased, we need to allocate a new model - _attachmentModels.push_back(allocateAttachmentModel(attachmentData[i].isSoft, _skeletonModel->getRig(), isMyAvatar())); - _attachmentModelsTexturesLoaded.push_back(false); - } else if (i < oldAttachmentData.size() && oldAttachmentData[i].isSoft != attachmentData[i].isSoft) { - // if the attachment has changed type, we need to re-allocate a new one. - _attachmentsToRemove.push_back(_attachmentModels[i]); - _attachmentModels[i] = allocateAttachmentModel(attachmentData[i].isSoft, _skeletonModel->getRig(), isMyAvatar()); - _attachmentModelsTexturesLoaded[i] = false; - } - // If the model URL has changd, we need to wait for the textures to load - if (_attachmentModels[i]->getURL() != attachmentData[i].modelURL) { - _attachmentModelsTexturesLoaded[i] = false; - } - _attachmentModels[i]->setLoadingPriority(ATTACHMENT_LOADING_PRIORITY); - _attachmentModels[i]->setURL(attachmentData[i].modelURL); - } -} - int Avatar::parseDataFromBuffer(const QByteArray& buffer) { PerformanceTimer perfTimer("unpack"); if (!_initialized) { @@ -2102,11 +1978,6 @@ uint32_t Avatar::appendSubMetaItems(render::ItemIDs& subItems) { return _subItemLock.resultWithReadLock([&] { uint32_t total = 0; - if (_attachmentRenderIDs.size() > 0) { - subItems.insert(subItems.end(), _attachmentRenderIDs.begin(), _attachmentRenderIDs.end()); - total += (uint32_t)_attachmentRenderIDs.size(); - } - if (_descendantRenderIDs.size() > 0) { subItems.insert(subItems.end(), _descendantRenderIDs.begin(), _descendantRenderIDs.end()); total += (uint32_t)_descendantRenderIDs.size(); @@ -2116,18 +1987,6 @@ uint32_t Avatar::appendSubMetaItems(render::ItemIDs& subItems) { }); } -void Avatar::updateAttachmentRenderIDs() { - _subItemLock.withWriteLock([&] { - _attachmentRenderIDs.clear(); - for (auto& attachmentModel : _attachmentModels) { - if (attachmentModel && attachmentModel->isRenderable()) { - auto& metaSubItems = attachmentModel->fetchRenderItemIDs(); - _attachmentRenderIDs.insert(_attachmentRenderIDs.end(), metaSubItems.begin(), metaSubItems.end()); - } - } - }); -} - void Avatar::updateDescendantRenderIDs() { _subItemLock.withWriteLock([&] { auto oldRenderingDescendantEntityIDs = _renderingDescendantEntityIDs; diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index c6112d74f2a..2e618350a4d 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -157,7 +157,6 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM void init(); void removeAvatarEntitiesFromTree(); virtual void simulate(float deltaTime, bool inView) = 0; - virtual void simulateAttachments(float deltaTime); virtual void render(RenderArgs* renderArgs); @@ -344,7 +343,6 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM Q_INVOKABLE glm::quat jointToWorldRotation(const glm::quat& rotation, const int jointIndex = -1) const; Q_INVOKABLE virtual void setSkeletonModelURL(const QUrl& skeletonModelURL) override; - virtual void setAttachmentData(const QVector& attachmentData) override; void updateDisplayNameAlpha(bool showDisplayName); virtual void setSessionDisplayName(const QString& sessionDisplayName) override { }; // no-op @@ -556,6 +554,11 @@ class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaM uint32_t appendSubMetaItems(render::ItemIDs& subItems); + virtual bool shouldRender() const { return _isMeshVisible && _isReadyToDraw; } + + static const float MYAVATAR_ENTITY_LOADING_PRIORITY; + static const float OTHERAVATAR_ENTITY_LOADING_PRIORITY; + signals: /*@jsdoc * Triggered when the avatar's target scale is changed. The target scale is the desired scale of the avatar without any @@ -650,10 +653,6 @@ public slots: mutable bool _modelJointsCached { false }; glm::vec3 _skeletonOffset; - std::vector> _attachmentModels; - std::vector _attachmentModelsTexturesLoaded; - std::vector> _attachmentsToRemove; - std::vector> _attachmentsToDelete; float _bodyYawDelta { 0.0f }; // degrees/sec float _seatedBodyYawDelta{ 0.0f }; // degrees/renderframe @@ -748,12 +747,14 @@ public slots: void processMaterials(); AABox _renderBound; - bool _isMeshVisible{ true }; - bool _needMeshVisibleSwitch{ true }; + bool _isMeshVisible { true }; + bool _needMeshVisibleSwitch { true }; + bool _isReadyToDraw { false }; + bool _needsWearablesLoadedCheck { false }; + bool _hasCheckedForAvatarEntities { false }; static const float MYAVATAR_LOADING_PRIORITY; static const float OTHERAVATAR_LOADING_PRIORITY; - static const float ATTACHMENT_LOADING_PRIORITY; LoadingStatus _loadingStatus { LoadingStatus::NoModel }; @@ -773,12 +774,9 @@ public slots: VectorOfIDs _grabsToDelete; // deleted grab IDs -- changes needed to entities or physics ReadWriteLockable _subItemLock; - void updateAttachmentRenderIDs(); - render::ItemIDs _attachmentRenderIDs; void updateDescendantRenderIDs(); render::ItemIDs _descendantRenderIDs; std::unordered_set _renderingDescendantEntityIDs; - uint32_t _lastAncestorChainRenderableVersion { 0 }; }; #endif // hifi_Avatar_h diff --git a/libraries/avatars-renderer/src/avatars-renderer/ScriptAvatar.h b/libraries/avatars-renderer/src/avatars-renderer/ScriptAvatar.h index a4595e9bdea..bffd0561ab1 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/ScriptAvatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/ScriptAvatar.h @@ -58,8 +58,6 @@ * when the other avatar is in the line of sight and also has lookAtSnappingEnabled == true. * * @property {string} skeletonModelURL - The avatar's FST file. - * @property {AttachmentData[]} attachmentData - Information on the avatar's attachments. - *

Deprecated: This property is deprecated and will be removed. Use avatar entities instead.

* @property {string[]} jointNames - The list of joints in the avatar model. * * @property {number} audioLoudness - The instantaneous loudness of the audio input that the avatar is injecting into the diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 4068f7c5477..fc28ad9e028 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -73,17 +73,10 @@ static const float DEFAULT_AVATAR_DENSITY = 1000.0f; // density of water STATIC_SCRIPT_TYPES_INITIALIZER((+[](ScriptManager* manager) { auto scriptEngine = manager->engine().get(); - registerAvatarTypes(scriptEngine); scriptRegisterMetaType(scriptEngine); scriptRegisterMetaType(scriptEngine); })); -STATIC_SCRIPT_INITIALIZER(+[](ScriptManager* manager) { - auto scriptEngine = manager->engine().get(); - - registerAvatarPrototypes(scriptEngine); -}); - size_t AvatarDataPacket::maxFaceTrackerInfoSize(size_t numBlendshapeCoefficients) { return FACE_TRACKER_INFO_SIZE + numBlendshapeCoefficients * sizeof(float); } @@ -2027,7 +2020,6 @@ void AvatarData::processAvatarIdentity(QDataStream& packetStream, bool& identity Identity identity; packetStream - >> identity.attachmentData >> identity.displayName >> identity.sessionDisplayName >> identity.identityFlags @@ -2068,11 +2060,6 @@ void AvatarData::processAvatarIdentity(QDataStream& packetStream, bool& identity } }; - if (identity.attachmentData != _attachmentData) { - setAttachmentData(identity.attachmentData); - identityChanged = true; - } - #ifdef WANT_DEBUG qCDebug(avatars) << __FUNCTION__ << "identity.uuid:" << identity.uuid @@ -2085,6 +2072,8 @@ void AvatarData::processAvatarIdentity(QDataStream& packetStream, bool& identity << "is >=" << (udt::SequenceNumber::Type) incomingSequenceNumber; #endif } + + onIdentityRecieved(); } QUrl AvatarData::getWireSafeSkeletonModelURL() const { @@ -2319,7 +2308,6 @@ QByteArray AvatarData::identityByteArray(bool setIsReplicated) const { identityStream << getSessionUUID() << (udt::SequenceNumber::Type) _identitySequenceNumber - << _attachmentData << _displayName << getSessionDisplayNameForTransport() // depends on _sessionDisplayName << identityFlags; @@ -2353,86 +2341,6 @@ void AvatarData::setDisplayName(const QString& displayName) { markIdentityDataChanged(); } -QVector AvatarData::getAttachmentData() const { - if (QThread::currentThread() != thread()) { - QVector result; - BLOCKING_INVOKE_METHOD(const_cast(this), "getAttachmentData", - Q_RETURN_ARG(QVector, result)); - return result; - } - return _attachmentData; -} - -void AvatarData::setAttachmentData(const QVector& attachmentData) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setAttachmentData", Q_ARG(const QVector&, attachmentData)); - return; - } - _attachmentData = attachmentData; - markIdentityDataChanged(); -} - -void AvatarData::attach(const QString& modelURL, const QString& jointName, - const glm::vec3& translation, const glm::quat& rotation, - float scale, bool isSoft, - bool allowDuplicates, bool useSaved) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "attach", Q_ARG(const QString&, modelURL), Q_ARG(const QString&, jointName), - Q_ARG(const glm::vec3&, translation), Q_ARG(const glm::quat&, rotation), - Q_ARG(float, scale), Q_ARG(bool, isSoft), - Q_ARG(bool, allowDuplicates), Q_ARG(bool, useSaved)); - return; - } - QVector attachmentData = getAttachmentData(); - if (!allowDuplicates) { - foreach (const AttachmentData& data, attachmentData) { - if (data.modelURL == modelURL && (jointName.isEmpty() || data.jointName == jointName)) { - return; - } - } - } - AttachmentData data; - data.modelURL = modelURL; - data.jointName = jointName; - data.translation = translation; - data.rotation = rotation; - data.scale = scale; - data.isSoft = isSoft; - attachmentData.append(data); - setAttachmentData(attachmentData); -} - -void AvatarData::detachOne(const QString& modelURL, const QString& jointName) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "detachOne", Q_ARG(const QString&, modelURL), Q_ARG(const QString&, jointName)); - return; - } - QVector attachmentData = getAttachmentData(); - for (QVector::iterator it = attachmentData.begin(); it != attachmentData.end(); ++it) { - if (it->modelURL == modelURL && (jointName.isEmpty() || it->jointName == jointName)) { - attachmentData.erase(it); - setAttachmentData(attachmentData); - return; - } - } -} - -void AvatarData::detachAll(const QString& modelURL, const QString& jointName) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "detachAll", Q_ARG(const QString&, modelURL), Q_ARG(const QString&, jointName)); - return; - } - QVector attachmentData = getAttachmentData(); - for (QVector::iterator it = attachmentData.begin(); it != attachmentData.end(); ) { - if (it->modelURL == modelURL && (jointName.isEmpty() || it->jointName == jointName)) { - it = attachmentData.erase(it); - } else { - ++it; - } - } - setAttachmentData(attachmentData); -} - int AvatarData::sendAvatarDataPacket(bool sendAll) { auto nodeList = DependencyManager::get(); @@ -2495,149 +2403,6 @@ int AvatarData::sendIdentityPacket() { return identityData.size(); } -static const QString JSON_ATTACHMENT_URL = QStringLiteral("modelUrl"); -static const QString JSON_ATTACHMENT_JOINT_NAME = QStringLiteral("jointName"); -static const QString JSON_ATTACHMENT_TRANSFORM = QStringLiteral("transform"); -static const QString JSON_ATTACHMENT_IS_SOFT = QStringLiteral("isSoft"); - -QJsonObject AttachmentData::toJson() const { - QJsonObject result; - if (modelURL.isValid() && !modelURL.isEmpty()) { - result[JSON_ATTACHMENT_URL] = modelURL.toString(); - } - if (!jointName.isEmpty()) { - result[JSON_ATTACHMENT_JOINT_NAME] = jointName; - } - // FIXME the transform constructor that takes rot/scale/translation - // doesn't return the correct value for isIdentity() - Transform transform; - transform.setRotation(rotation); - transform.setScale(scale); - transform.setTranslation(translation); - if (!transform.isIdentity()) { - result[JSON_ATTACHMENT_TRANSFORM] = Transform::toJson(transform); - } - result[JSON_ATTACHMENT_IS_SOFT] = isSoft; - return result; -} - -void AttachmentData::fromJson(const QJsonObject& json) { - if (json.contains(JSON_ATTACHMENT_URL)) { - const QString modelURLTemp = json[JSON_ATTACHMENT_URL].toString(); - if (modelURLTemp != modelURL.toString()) { - modelURL = modelURLTemp; - } - } - - if (json.contains(JSON_ATTACHMENT_JOINT_NAME)) { - const QString jointNameTemp = json[JSON_ATTACHMENT_JOINT_NAME].toString(); - if (jointNameTemp != jointName) { - jointName = jointNameTemp; - } - } - - if (json.contains(JSON_ATTACHMENT_TRANSFORM)) { - Transform transform = Transform::fromJson(json[JSON_ATTACHMENT_TRANSFORM]); - translation = transform.getTranslation(); - rotation = transform.getRotation(); - scale = transform.getScale().x; - } - - if (json.contains(JSON_ATTACHMENT_IS_SOFT)) { - isSoft = json[JSON_ATTACHMENT_IS_SOFT].toBool(); - } -} - -bool AttachmentData::operator==(const AttachmentData& other) const { - return modelURL == other.modelURL && jointName == other.jointName && translation == other.translation && - rotation == other.rotation && scale == other.scale && isSoft == other.isSoft; -} - -QDataStream& operator<<(QDataStream& out, const AttachmentData& attachment) { - return out << attachment.modelURL << attachment.jointName << - attachment.translation << attachment.rotation << attachment.scale << attachment.isSoft; -} - -QDataStream& operator>>(QDataStream& in, AttachmentData& attachment) { - return in >> attachment.modelURL >> attachment.jointName >> - attachment.translation >> attachment.rotation >> attachment.scale >> attachment.isSoft; -} - -void AttachmentDataObject::setModelURL(const QString& modelURL) { - AttachmentData data = scriptvalue_cast(thisObject()); - data.modelURL = modelURL; - Q_ASSERT(engine()); - thisObject() = engine()->toScriptValue(data); -} - -QString AttachmentDataObject::getModelURL() const { - return scriptvalue_cast(thisObject()).modelURL.toString(); -} - -void AttachmentDataObject::setJointName(const QString& jointName) { - AttachmentData data = scriptvalue_cast(thisObject()); - data.jointName = jointName; - Q_ASSERT(engine()); - thisObject() = engine()->toScriptValue(data); -} - -QString AttachmentDataObject::getJointName() const { - return scriptvalue_cast(thisObject()).jointName; -} - -void AttachmentDataObject::setTranslation(const glm::vec3& translation) { - AttachmentData data = scriptvalue_cast(thisObject()); - data.translation = translation; - Q_ASSERT(engine()); - thisObject() = engine()->toScriptValue(data); -} - -glm::vec3 AttachmentDataObject::getTranslation() const { - return scriptvalue_cast(thisObject()).translation; -} - -void AttachmentDataObject::setRotation(const glm::quat& rotation) { - AttachmentData data = scriptvalue_cast(thisObject()); - data.rotation = rotation; - Q_ASSERT(engine()); - thisObject() = engine()->toScriptValue(data); -} - -glm::quat AttachmentDataObject::getRotation() const { - return scriptvalue_cast(thisObject()).rotation; -} - -void AttachmentDataObject::setScale(float scale) { - AttachmentData data = scriptvalue_cast(thisObject()); - data.scale = scale; - Q_ASSERT(engine()); - thisObject() = engine()->toScriptValue(data); -} - -float AttachmentDataObject::getScale() const { - return scriptvalue_cast(thisObject()).scale; -} - -void AttachmentDataObject::setIsSoft(bool isSoft) { - AttachmentData data = scriptvalue_cast(thisObject()); - data.isSoft = isSoft; - Q_ASSERT(engine()); - thisObject() = engine()->toScriptValue(data); -} - -bool AttachmentDataObject::getIsSoft() const { - return scriptvalue_cast(thisObject()).isSoft; -} - -void registerAvatarTypes(ScriptEngine* engine) { - scriptRegisterSequenceMetaType >(engine); -} - -void registerAvatarPrototypes(ScriptEngine* engine) { - engine->setDefaultPrototype(qMetaTypeId(), engine->newQObject( - new AttachmentDataObject(), ScriptEngine::ScriptOwnership)); -} - void AvatarData::setRecordingBasis(std::shared_ptr recordingBasis) { if (!recordingBasis) { recordingBasis = std::make_shared(); @@ -2670,7 +2435,6 @@ static const QString JSON_AVATAR_HEAD_MODEL = QStringLiteral("headModel"); static const QString JSON_AVATAR_BODY_MODEL = QStringLiteral("bodyModel"); static const QString JSON_AVATAR_DISPLAY_NAME = QStringLiteral("displayName"); // It isn't meaningful to persist sessionDisplayName. -static const QString JSON_AVATAR_ATTACHMENTS = QStringLiteral("attachments"); static const QString JSON_AVATAR_ENTITIES = QStringLiteral("attachedEntities"); static const QString JSON_AVATAR_SCALE = QStringLiteral("scale"); static const QString JSON_AVATAR_VERSION = QStringLiteral("version"); @@ -2838,24 +2602,11 @@ void AvatarData::fromJson(const QJsonObject& json, bool useFrameSkeleton) { setTargetScale((float)json[JSON_AVATAR_SCALE].toDouble()); } - QVector attachments; - if (json.contains(JSON_AVATAR_ATTACHMENTS) && json[JSON_AVATAR_ATTACHMENTS].isArray()) { - QJsonArray attachmentsJson = json[JSON_AVATAR_ATTACHMENTS].toArray(); - for (auto attachmentJson : attachmentsJson) { - AttachmentData attachment; - attachment.fromJson(attachmentJson.toObject()); - attachments.push_back(attachment); - } - } - if (attachments != getAttachmentData()) { - setAttachmentData(attachments); - } - 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(); + QJsonArray avatarEntitiesJSON = json[JSON_AVATAR_ENTITIES].toArray(); + for (auto avatarEntityJSON : avatarEntitiesJSON) { + if (avatarEntityJSON.isObject()) { + QVariantMap entityData = avatarEntityJSON.toObject().toVariantMap(); QUuid id = entityData.value("id").toUuid(); QByteArray data = QByteArray::fromBase64(entityData.value("properties").toByteArray()); updateAvatarEntity(id, data); @@ -2970,30 +2721,6 @@ glm::vec3 AvatarData::getAbsoluteJointTranslationInObjectFrame(int index) const return glm::vec3(); } -/*@jsdoc - * Information on an attachment worn by the avatar. - * @typedef {object} AttachmentData - * @property {string} modelUrl - The URL of the glTF, FBX, or OBJ model file. glTF models may be in JSON or binary format - * (".gltf" or ".glb" URLs respectively). - * @property {string} jointName - The name of the joint that the attachment is parented to. - * @property {Vec3} translation - The offset from the joint that the attachment is positioned at. - * @property {Vec3} rotation - The rotation applied to the model relative to the joint orientation. - * @property {number} scale - The scale applied to the attachment model. - * @property {boolean} soft - If true and the model has a skeleton, the bones of the attached model's skeleton are - * rotated to fit the avatar's current pose. If true, the translation, rotation, and - * scale parameters are ignored. - */ -QVariant AttachmentData::toVariant() const { - QVariantMap result; - result["modelUrl"] = modelURL; - result["jointName"] = jointName; - result["translation"] = vec3ToQMap(translation); - result["rotation"] = vec3ToQMap(glm::degrees(safeEulerAngles(rotation))); - result["scale"] = scale; - result["soft"] = isSoft; - return result; -} - glm::vec3 variantToVec3(const QVariant& var) { auto map = var.toMap(); glm::vec3 result; @@ -3003,52 +2730,6 @@ glm::vec3 variantToVec3(const QVariant& var) { return result; } -bool AttachmentData::fromVariant(const QVariant& variant) { - bool isValid = false; - auto map = variant.toMap(); - if (map.contains("modelUrl")) { - auto urlString = map["modelUrl"].toString(); - modelURL = urlString; - isValid = true; - } - if (map.contains("jointName")) { - jointName = map["jointName"].toString(); - } - if (map.contains("translation")) { - translation = variantToVec3(map["translation"]); - } - if (map.contains("rotation")) { - rotation = glm::quat(glm::radians(variantToVec3(map["rotation"]))); - } - if (map.contains("scale")) { - scale = map["scale"].toFloat(); - } - if (map.contains("soft")) { - isSoft = map["soft"].toBool(); - } - return isValid; -} - -QVariantList AvatarData::getAttachmentsVariant() const { - QVariantList result; - for (const auto& attachment : getAttachmentData()) { - result.append(attachment.toVariant()); - } - return result; -} - -void AvatarData::setAttachmentsVariant(const QVariantList& variant) { - QVector newAttachments; - newAttachments.reserve(variant.size()); - for (const auto& attachmentVar : variant) { - AttachmentData attachment; - if (attachment.fromVariant(attachmentVar)) { - newAttachments.append(attachment); - } - } - setAttachmentData(newAttachments); -} - void AvatarData::storeAvatarEntityDataPayload(const QUuid& entityID, const QByteArray& data) { bool changed = false; _avatarEntitiesLock.withWriteLock([&] { diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 916e09668be..a31291e1fce 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -451,7 +451,6 @@ Q_DECLARE_METATYPE(KillAvatarReason); class QDataStream; -class AttachmentData; class Transform; using TransformPointer = std::shared_ptr; @@ -523,8 +522,6 @@ class AvatarData : public QObject, public SpatiallyNestable { * @property {boolean} lookAtSnappingEnabled=true - true if the avatar's eyes snap to look at another avatar's * eyes when the other avatar is in the line of sight and also has lookAtSnappingEnabled == true. * @property {string} skeletonModelURL - The avatar's FST file. - * @property {AttachmentData[]} attachmentData - Information on the avatar's attachments. - *

Deprecated: This property is deprecated and will be removed. Use avatar entities instead.

* @property {string[]} jointNames - The list of joints in the current avatar model. Read-only. * @property {Uuid} sessionUUID - Unique ID of the avatar in the domain. Read-only. * @property {Mat4} sensorToWorldMatrix - The scale, rotation, and translation transform from the user's real world to the @@ -580,7 +577,6 @@ class AvatarData : public QObject, public SpatiallyNestable { Q_PROPERTY(QString sessionDisplayName READ getSessionDisplayName WRITE setSessionDisplayName NOTIFY sessionDisplayNameChanged) Q_PROPERTY(bool lookAtSnappingEnabled MEMBER _lookAtSnappingEnabled NOTIFY lookAtSnappingChanged) Q_PROPERTY(QString skeletonModelURL READ getSkeletonModelURLFromScript WRITE setSkeletonModelURLFromScript NOTIFY skeletonModelURLChanged) - Q_PROPERTY(QVector attachmentData READ getAttachmentData WRITE setAttachmentData) Q_PROPERTY(QStringList jointNames READ getJointNames) @@ -1145,27 +1141,6 @@ class AvatarData : public QObject, public SpatiallyNestable { */ Q_INVOKABLE void setBlendshape(QString name, float val) { _headData->setBlendshape(name, val); } - - /*@jsdoc - * Gets information about the models currently attached to your avatar. - * @function Avatar.getAttachmentsVariant - * @returns {AttachmentData[]} Information about all models attached to your avatar. - * @deprecated This function is deprecated and will be removed. Use avatar entities instead. - */ - // FIXME: Can this name be improved? Can it be deprecated? - Q_INVOKABLE virtual QVariantList getAttachmentsVariant() const; - - /*@jsdoc - * Sets all models currently attached to your avatar. For example, if you retrieve attachment data using - * {@link MyAvatar.getAttachmentsVariant} or {@link Avatar.getAttachmentsVariant}, make changes to it, and then want to - * update your avatar's attachments per the changed data. - * @function Avatar.setAttachmentsVariant - * @param {AttachmentData[]} variant - The attachment data defining the models to have attached to your avatar. - * @deprecated This function is deprecated and will be removed. Use avatar entities instead. - */ - // FIXME: Can this name be improved? Can it be deprecated? - Q_INVOKABLE virtual void setAttachmentsVariant(const QVariantList& variant); - virtual void storeAvatarEntityDataPayload(const QUuid& entityID, const QByteArray& payload); /*@jsdoc @@ -1209,7 +1184,6 @@ class AvatarData : public QObject, public SpatiallyNestable { const HeadData* getHeadData() const { return _headData; } struct Identity { - QVector attachmentData; QString displayName; QString sessionDisplayName; bool isReplicated; @@ -1254,109 +1228,6 @@ class AvatarData : public QObject, public SpatiallyNestable { } virtual bool isCertifyFailed() const { return _verificationFailed; } - /*@jsdoc - * Gets information about the models currently attached to your avatar. - * @function Avatar.getAttachmentData - * @returns {AttachmentData[]} Information about all models attached to your avatar. - * @deprecated This function is deprecated and will be removed. Use avatar entities instead. - * @example Report the URLs of all current attachments. - * var attachments = MyAvatar.getaAttachmentData(); - * for (var i = 0; i < attachments.length; i++) { - * print(attachments[i].modelURL); - * } - * - * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar". - */ - Q_INVOKABLE virtual QVector getAttachmentData() const; - - /*@jsdoc - * Sets all models currently attached to your avatar. For example, if you retrieve attachment data using - * {@link MyAvatar.getAttachmentData} or {@link Avatar.getAttachmentData}, make changes to it, and then want to update your avatar's attachments per the - * changed data. You can also remove all attachments by using setting attachmentData to null. - * @function Avatar.setAttachmentData - * @param {AttachmentData[]} attachmentData - The attachment data defining the models to have attached to your avatar. Use - * null to remove all attachments. - * @deprecated This function is deprecated and will be removed. Use avatar entities instead. - * @example Remove a hat attachment if your avatar is wearing it. - * var hatURL = "https://apidocs.overte.org/examples/cowboy-hat.fbx"; - * var attachments = MyAvatar.getAttachmentData(); - * - * for (var i = 0; i < attachments.length; i++) { - * if (attachments[i].modelURL === hatURL) { - * attachments.splice(i, 1); - * MyAvatar.setAttachmentData(attachments); - * break; - * } - * } - * - * // Note: If using from the Avatar API, replace all occurrences of "MyAvatar" with "Avatar". - */ - Q_INVOKABLE virtual void setAttachmentData(const QVector& attachmentData); - - /*@jsdoc - * Attaches a model to your avatar. For example, you can give your avatar a hat to wear, a guitar to hold, or a surfboard to - * stand on. - * @function Avatar.attach - * @param {string} modelURL - The URL of the glTF, FBX, or OBJ model to attach. glTF models may be in JSON or binary format - * (".gltf" or ".glb" URLs respectively). - * @param {string} [jointName=""] - The name of the avatar joint (see {@link MyAvatar.getJointNames} or - * {@link Avatar.getJointNames}) to attach the model to. - * @param {Vec3} [translation=Vec3.ZERO] - The offset to apply to the model relative to the joint position. - * @param {Quat} [rotation=Quat.IDENTITY] - The rotation to apply to the model relative to the joint orientation. - * @param {number} [scale=1.0] - The scale to apply to the model. - * @param {boolean} [isSoft=false] - If the model has a skeleton, set this to true so that the bones of the - * attached model's skeleton are rotated to fit the avatar's current pose. isSoft is used, for example, - * to have clothing that moves with the avatar. - *

If true, the translation, rotation, and scale parameters are - * ignored.

- * @param {boolean} [allowDuplicates=false] - If true then more than one copy of any particular model may be - * attached to the same joint; if false then the same model cannot be attached to the same joint. - * @param {boolean} [useSaved=true] - Not used. - * @deprecated This function is deprecated and will be removed. Use avatar entities instead. - * @example Attach a cowboy hat to your avatar's head. - * var attachment = { - * modelURL: "https://apidocs.overte.org/examples/cowboy-hat.fbx", - * jointName: "Head", - * translation: {"x": 0, "y": 0.25, "z": 0}, - * rotation: {"x": 0, "y": 0, "z": 0, "w": 1}, - * scale: 0.01, - * isSoft: false - * }; - * - * MyAvatar.attach(attachment.modelURL, - * attachment.jointName, - * attachment.translation, - * attachment.rotation, - * attachment.scale, - * attachment.isSoft); - * - * // Note: If using from the Avatar API, replace "MyAvatar" with "Avatar". - */ - Q_INVOKABLE virtual void attach(const QString& modelURL, const QString& jointName = QString(), - const glm::vec3& translation = glm::vec3(), const glm::quat& rotation = glm::quat(), - float scale = 1.0f, bool isSoft = false, - bool allowDuplicates = false, bool useSaved = true); - - /*@jsdoc - * Detaches the most recently attached instance of a particular model from either a specific joint or any joint. - * @function Avatar.detachOne - * @param {string} modelURL - The URL of the model to detach. - * @param {string} [jointName=""] - The name of the joint to detach the model from. If "", then the most - * recently attached model is removed from which ever joint it was attached to. - * @deprecated This function is deprecated and will be removed. Use avatar entities instead. - */ - Q_INVOKABLE virtual void detachOne(const QString& modelURL, const QString& jointName = QString()); - - /*@jsdoc - * Detaches all instances of a particular model from either a specific joint or all joints. - * @function Avatar.detachAll - * @param {string} modelURL - The URL of the model to detach. - * @param {string} [jointName=""] - The name of the joint to detach the model from. If "", then the model is - * detached from all joints. - * @deprecated This function is deprecated and will be removed. Use avatar entities instead. - */ - Q_INVOKABLE virtual void detachAll(const QString& modelURL, const QString& jointName = QString()); - QString getSkeletonModelURLFromScript() const; void setSkeletonModelURLFromScript(const QString& skeletonModelString) { setSkeletonModelURL(QUrl(skeletonModelString)); } @@ -1405,7 +1276,6 @@ class AvatarData : public QObject, public SpatiallyNestable { */ Q_INVOKABLE virtual void setAvatarEntityData(const AvatarEntityMap& avatarEntityData); - void setAvatarEntityDataChanged(bool value) { _avatarEntityDataChanged = value; } AvatarEntityIDs getAndClearRecentlyRemovedIDs(); /*@jsdoc @@ -1712,6 +1582,8 @@ public slots: virtual const QString& getSessionDisplayNameForTransport() const { return _sessionDisplayName; } virtual void maybeUpdateSessionDisplayNameFromTransport(const QString& sessionDisplayName) { } // No-op in AvatarMixer + virtual void onIdentityRecieved() {} + // Body scale float _targetScale; float _domainMinimumHeight { MIN_AVATAR_HEIGHT }; @@ -1732,8 +1604,6 @@ public slots: mutable HeadData* _headData { nullptr }; QUrl _skeletonModelURL; - QVector _attachmentData; - QVector _oldAttachmentData; QString _displayName; QString _sessionDisplayName { }; bool _lookAtSnappingEnabled { true }; @@ -1899,66 +1769,6 @@ Q_DECLARE_METATYPE(AvatarData*) QJsonValue toJsonValue(const JointData& joint); JointData jointDataFromJsonValue(const QJsonValue& q); -class AttachmentData { -public: - QUrl modelURL; - QString jointName; - glm::vec3 translation; - glm::quat rotation; - float scale { 1.0f }; - bool isSoft { false }; - - bool isValid() const { return modelURL.isValid(); } - - bool operator==(const AttachmentData& other) const; - - QJsonObject toJson() const; - void fromJson(const QJsonObject& json); - - QVariant toVariant() const; - bool fromVariant(const QVariant& variant); -}; - -QDataStream& operator<<(QDataStream& out, const AttachmentData& attachment); -QDataStream& operator>>(QDataStream& in, AttachmentData& attachment); - -Q_DECLARE_METATYPE(AttachmentData) -Q_DECLARE_METATYPE(QVector) - -/// Scriptable wrapper for attachments. -class AttachmentDataObject : public QObject, protected Scriptable { - Q_OBJECT - Q_PROPERTY(QString modelURL READ getModelURL WRITE setModelURL) - Q_PROPERTY(QString jointName READ getJointName WRITE setJointName) - Q_PROPERTY(glm::vec3 translation READ getTranslation WRITE setTranslation) - Q_PROPERTY(glm::quat rotation READ getRotation WRITE setRotation) - Q_PROPERTY(float scale READ getScale WRITE setScale) - Q_PROPERTY(bool isSoft READ getIsSoft WRITE setIsSoft) - -public: - - Q_INVOKABLE void setModelURL(const QString& modelURL); - Q_INVOKABLE QString getModelURL() const; - - Q_INVOKABLE void setJointName(const QString& jointName); - Q_INVOKABLE QString getJointName() const; - - Q_INVOKABLE void setTranslation(const glm::vec3& translation); - Q_INVOKABLE glm::vec3 getTranslation() const; - - Q_INVOKABLE void setRotation(const glm::quat& rotation); - Q_INVOKABLE glm::quat getRotation() const; - - Q_INVOKABLE void setScale(float scale); - Q_INVOKABLE float getScale() const; - - Q_INVOKABLE void setIsSoft(bool scale); - Q_INVOKABLE bool getIsSoft() const; -}; - -void registerAvatarTypes(ScriptEngine* engine); -void registerAvatarPrototypes(ScriptEngine* engine); - class RayToAvatarIntersectionResult { public: bool intersects { false }; diff --git a/libraries/avatars/src/ScriptAvatarData.cpp b/libraries/avatars/src/ScriptAvatarData.cpp index 1d93a6e954c..43dc5097ef2 100644 --- a/libraries/avatars/src/ScriptAvatarData.cpp +++ b/libraries/avatars/src/ScriptAvatarData.cpp @@ -200,7 +200,7 @@ bool ScriptAvatarData::getLookAtSnappingEnabled() const { // // -// ATTACHMENT AND JOINT PROPERTIES +// JOINT PROPERTIES // START // QString ScriptAvatarData::getSkeletonModelURLFromScript() const { @@ -285,15 +285,8 @@ QStringList ScriptAvatarData::getJointNames() const { return QStringList(); } } -QVector ScriptAvatarData::getAttachmentData() const { - if (AvatarSharedPointer sharedAvatarData = _avatarData.lock()) { - return sharedAvatarData->getAttachmentData(); - } else { - return QVector(); - } -} // -// ATTACHMENT AND JOINT PROPERTIES +// JOINT PROPERTIES // END // diff --git a/libraries/avatars/src/ScriptAvatarData.h b/libraries/avatars/src/ScriptAvatarData.h index 8f9b7b77b13..960423a1eec 100644 --- a/libraries/avatars/src/ScriptAvatarData.h +++ b/libraries/avatars/src/ScriptAvatarData.h @@ -50,10 +50,9 @@ class ScriptAvatarData : public QObject { Q_PROPERTY(bool lookAtSnappingEnabled READ getLookAtSnappingEnabled NOTIFY lookAtSnappingChanged) // - // ATTACHMENT AND JOINT PROPERTIES + // JOINT PROPERTIES // Q_PROPERTY(QString skeletonModelURL READ getSkeletonModelURLFromScript NOTIFY skeletonModelURLChanged) - Q_PROPERTY(QVector attachmentData READ getAttachmentData) Q_PROPERTY(QStringList jointNames READ getJointNames) // @@ -104,7 +103,7 @@ class ScriptAvatarData : public QObject { bool getLookAtSnappingEnabled() const; // - // ATTACHMENT AND JOINT PROPERTIES + // JOINT PROPERTIES // QString getSkeletonModelURLFromScript() const; @@ -204,15 +203,6 @@ class ScriptAvatarData : public QObject { */ Q_INVOKABLE QStringList getJointNames() const; - /*@jsdoc - * Gets information about the models currently attached to the avatar. - * @function ScriptAvatar.getAttachmentData - * @returns {AttachmentData[]} Information about all models attached to the avatar, or [] if the avatar data - * aren't available. - * @deprecated This function is deprecated and will be removed. Use avatar entities instead. - */ - Q_INVOKABLE QVector getAttachmentData() const; - #if DEV_BUILD || PR_BUILD Q_INVOKABLE AvatarEntityMap getAvatarEntities() const; #endif diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 6ea10f6327a..00771927fb8 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -360,7 +360,7 @@ void OpenGLDisplayPlugin::customizeContext() { auto presentThread = DependencyManager::get(); Q_ASSERT(thread() == presentThread->thread()); - getGLBackend()->setCameraCorrection(mat4(), mat4(), true); + getGLBackend()->setCameraCorrection(mat4(), mat4(), true, true); for (auto& cursorValue : _cursorsData) { auto& cursorData = cursorValue.second; @@ -704,7 +704,7 @@ void OpenGLDisplayPlugin::present(const std::shared_ptr& if (_currentFrame) { auto correction = getViewCorrection(); - getGLBackend()->setCameraCorrection(correction, _prevRenderView); + getGLBackend()->setCameraCorrection(correction, _prevRenderView, true); _prevRenderView = correction * _currentFrame->view; { withPresentThreadLock([&] { diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt index 22851d8aa5f..b2ce8f66fda 100644 --- a/libraries/entities-renderer/CMakeLists.txt +++ b/libraries/entities-renderer/CMakeLists.txt @@ -18,6 +18,7 @@ include_hifi_library_headers(avatars) include_hifi_library_headers(controllers) include_hifi_library_headers(task) include_hifi_library_headers(graphics-scripting) # for Forward.h +include_hifi_library_headers(entities) target_bullet() target_polyvox() diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index db8a61312a4..7ca3a5c341e 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -13,6 +13,7 @@ #include "RenderableEntityItem.h" +#include #include #include "RenderableShapeEntityItem.h" @@ -21,6 +22,7 @@ #include "RenderableImageEntityItem.h" #include "RenderableWebEntityItem.h" #include "RenderableParticleEffectEntityItem.h" +#include "RenderableProceduralParticleEffectEntityItem.h" #include "RenderableLineEntityItem.h" #include "RenderablePolyLineEntityItem.h" #include "RenderablePolyVoxEntityItem.h" @@ -193,6 +195,10 @@ ItemKey EntityRenderer::getKey() { builder.withSubMetaCulled(); } + if (_mirrorMode == MirrorMode::MIRROR || (_mirrorMode == MirrorMode::PORTAL && !_portalExitID.isNull())) { + builder.withMirror(); + } + if (!_visible) { builder.withInvisible(); } @@ -224,6 +230,107 @@ bool EntityRenderer::passesZoneOcclusionTest(const std::unordered_set& co return true; } +ItemID EntityRenderer::computeMirrorView(ViewFrustum& viewFrustum) const { + glm::vec3 inPropertiesPosition; + glm::quat inPropertiesRotation; + MirrorMode mirrorMode; + QUuid portalExitID; + withReadLock([&]{ + inPropertiesPosition = _entity->getWorldPosition(); + inPropertiesRotation = _entity->getWorldOrientation(); + mirrorMode = _mirrorMode; + portalExitID = _portalExitID; + }); + return computeMirrorViewOperator(viewFrustum, inPropertiesPosition, inPropertiesRotation, mirrorMode, portalExitID); +} + +ItemID EntityRenderer::computeMirrorViewOperator(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, + MirrorMode mirrorMode, const QUuid& portalExitID) { + glm::mat4 inToWorld = glm::translate(inPropertiesPosition) * glm::mat4_cast(inPropertiesRotation); + glm::mat4 worldToIn = glm::inverse(inToWorld); + + glm::vec3 outPropertiesPosition = inPropertiesPosition; + glm::quat outPropertiesRotation = inPropertiesRotation; + glm::mat4 outToWorld = inToWorld; + bool foundPortalExit = false; + if (mirrorMode == MirrorMode::PORTAL && !portalExitID.isNull()) { + auto renderer = DependencyManager::get(); + if (renderer) { + if (auto renderable = renderer->renderableForEntityId(portalExitID)) { + renderable->withReadLock([&] { + outPropertiesPosition = renderable->_entity->getWorldPosition(); + outPropertiesRotation = renderable->_entity->getWorldOrientation(); + }); + + outToWorld = glm::translate(outPropertiesPosition) * glm::mat4_cast(outPropertiesRotation); + foundPortalExit = true; + } + } + } + + // get mirror camera position by reflecting main camera position's z coordinate in mirror space + glm::vec3 cameraPositionWorld = viewFrustum.getPosition(); + glm::vec3 cameraPositionIn = vec3(worldToIn * vec4(cameraPositionWorld, 1.0f)); + glm::vec3 mirrorCameraPositionIn = vec3(cameraPositionIn.x, cameraPositionIn.y, -cameraPositionIn.z); + if (foundPortalExit) { + // portals also flip over x + mirrorCameraPositionIn.x *= -1.0f; + } + glm::vec3 mirrorCameraPositionWorld = vec3(outToWorld * vec4(mirrorCameraPositionIn, 1.0f)); + + // get mirror camera rotation by reflecting main camera rotation in mirror space + // TODO: we are assuming here that UP is world y-axis + glm::quat mainCameraRotationWorld = viewFrustum.getOrientation(); + glm::quat mainCameraRotationMirror = worldToIn * glm::mat4_cast(mainCameraRotationWorld); + glm::quat mirrorCameraRotationMirror = glm::quat(mainCameraRotationMirror.w, -mainCameraRotationMirror.x, -mainCameraRotationMirror.y, mainCameraRotationMirror.z) * + glm::angleAxis((float)M_PI, glm::vec3(0, 1, 0)); + if (foundPortalExit) { + // portals also flip over x + mirrorCameraRotationMirror = glm::quat(mirrorCameraRotationMirror.w, mirrorCameraRotationMirror.x, -mirrorCameraRotationMirror.y, -mirrorCameraRotationMirror.z); + } + glm::quat mirrorCameraRotationWorld = outToWorld * glm::mat4_cast(mirrorCameraRotationMirror); + + viewFrustum.setPosition(mirrorCameraPositionWorld); + viewFrustum.setOrientation(mirrorCameraRotationWorld); + + // modify the near clip plane to be the XY plane of the mirror + // from: https://terathon.com/lengyel/Lengyel-Oblique.pdf + glm::mat4 view = viewFrustum.getView(); + glm::mat4 projection = viewFrustum.getProjection(); + + //Find the camera-space 4D reflection plane vector + glm::vec3 cameraSpacePosition = glm::inverse(view) * glm::vec4(outPropertiesPosition, 1.0f); + glm::vec3 cameraSpaceNormal = glm::transpose(view) * (outPropertiesRotation * glm::vec4(0, 0, -1, 0)); + glm::vec4 clipPlane = glm::vec4(cameraSpaceNormal, -glm::dot(cameraSpaceNormal, cameraSpacePosition)); + // Make sure we pick the direction facing away from us + if (clipPlane.w > 0.0f) { + clipPlane *= -1.0f; + } + + // Calculate the clip-space corner point opposite the clipping plane + // as (sign(clipPlane.x), sign(clipPlane.y), 1, 1) and + // transform it into camera space by multiplying it + // by the inverse of the projection matrix + glm::vec4 q; + q.x = (glm::sign(clipPlane.x) + projection[0][2]) / projection[0][0]; + q.y = (glm::sign(clipPlane.y) + projection[1][2]) / projection[1][1]; + q.z = -1.0f; + q.w = (1.0f + projection[2][2]) / projection[2][3]; + + // Calculate the scaled plane vector + glm::vec4 c = (2.0f / glm::dot(clipPlane, q)) * clipPlane; + + // Replace the third row of the projection matrix + projection[0][2] = c.x; + projection[1][2] = c.y; + projection[2][2] = c.z + 1.0f; + projection[3][2] = c.w; + + viewFrustum.setProjection(projection, true); + + return foundPortalExit ? DependencyManager::get()->renderableIdForEntityId(portalExitID) : Item::INVALID_ITEM_ID; +} + HighlightStyle EntityRenderer::getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const { std::lock_guard lock(_materialsLock); auto materials = _materials.find("0"); @@ -243,7 +350,7 @@ void EntityRenderer::render(RenderArgs* args) { return; } - if (_visible && (args->_renderMode != RenderArgs::RenderMode::DEFAULT_RENDER_MODE || !_cauterized)) { + if (_visible && (!_cauterized || args->_renderMode != RenderArgs::RenderMode::DEFAULT_RENDER_MODE || args->_mirrorDepth > 0)) { doRender(args); } } @@ -290,6 +397,10 @@ EntityRenderer::Pointer EntityRenderer::addToScene(EntityTreeRenderer& renderer, result = make_renderer(entity); break; + case Type::ProceduralParticleEffect: + result = make_renderer(entity); + break; + case Type::Line: result = make_renderer(entity); break; @@ -343,7 +454,6 @@ bool EntityRenderer::addToScene(const ScenePointer& scene, Transaction& transact transaction.resetItem(_renderItemID, renderPayload); onAddToScene(_entity); updateInScene(scene, transaction); - _entity->bumpAncestorChainRenderableVersion(); return true; } @@ -351,7 +461,6 @@ void EntityRenderer::removeFromScene(const ScenePointer& scene, Transaction& tra onRemoveFromScene(_entity); transaction.removeItem(_renderItemID); Item::clearID(_renderItemID); - _entity->bumpAncestorChainRenderableVersion(); } void EntityRenderer::updateInScene(const ScenePointer& scene, Transaction& transaction) { @@ -464,13 +573,15 @@ void EntityRenderer::doRenderUpdateSynchronous(const ScenePointer& scene, Transa } void EntityRenderer::doRenderUpdateAsynchronous(const EntityItemPointer& entity) { - setIsVisibleInSecondaryCamera(entity->isVisibleInSecondaryCamera()); + setIsVisibleInSecondaryCamera(entity->getIsVisibleInSecondaryCamera()); setRenderLayer(entity->getRenderLayer()); _billboardMode = entity->getBillboardMode(); _primitiveMode = entity->getPrimitiveMode(); _canCastShadow = entity->getCanCastShadow(); setCullWithParent(entity->getCullWithParent()); _cauterized = entity->getCauterized(); + setMirrorMode(entity->getMirrorMode()); + setPortalExitID(entity->getPortalExitID()); if (entity->needsZoneOcclusionUpdate()) { entity->resetNeedsZoneOcclusionUpdate(); _renderWithZones = entity->getRenderWithZones(); @@ -522,6 +633,10 @@ graphics::MaterialPointer EntityRenderer::getTopMaterial() { } EntityRenderer::Pipeline EntityRenderer::getPipelineType(const graphics::MultiMaterial& materials) { + if (_mirrorMode == MirrorMode::MIRROR || (_mirrorMode == MirrorMode::PORTAL && !_portalExitID.isNull())) { + return Pipeline::MIRROR; + } + if (materials.top().material && materials.top().material->isProcedural() && materials.top().material->isReady()) { return Pipeline::PROCEDURAL; } diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index 86ef9dfb542..949590c4729 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -61,12 +61,13 @@ class EntityRenderer : public QObject, public std::enable_shared_from_this& containingZones) const override; + ItemID computeMirrorView(ViewFrustum& viewFrustum) const override; + static ItemID computeMirrorViewOperator(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, + MirrorMode mirrorMode, const QUuid& portalExitID); + virtual void renderSimulate(RenderArgs* args) override {} virtual HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const override; protected: @@ -120,6 +125,8 @@ class EntityRenderer : public QObject, public std::enable_shared_from_this std::shared_ptr asTypedEntity() { return std::static_pointer_cast(_entity); } @@ -156,6 +163,8 @@ class EntityRenderer : public QObject, public std::enable_shared_from_this_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES; + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), true)); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), true)); batch.setModelTransform(transform); Pipeline pipelineType = getPipelineType(materials); diff --git a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp index e374fe29c06..3f40218d468 100644 --- a/libraries/entities-renderer/src/RenderableGridEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableGridEntityItem.cpp @@ -103,8 +103,9 @@ void GridEntityRenderer::doRender(RenderArgs* args) { } else { transform.setTranslation(renderTransform.getTranslation()); } + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch->setModelTransform(transform); auto minCorner = glm::vec2(-0.5f, -0.5f); diff --git a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp index 13ddcffe6f0..0b76038cd4f 100644 --- a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp @@ -146,8 +146,9 @@ void ImageEntityRenderer::doRender(RenderArgs* args) { gpu::Batch* batch = args->_batch; + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); float imageWidth = _texture->getWidth(); float imageHeight = _texture->getHeight(); @@ -197,8 +198,10 @@ void ImageEntityRenderer::doRender(RenderArgs* args) { procedural->prepare(*batch, transform.getTranslation(), transform.getScale(), transform.getRotation(), _created, ProceduralProgramKey(transparent)); } else if (pipelineType == Pipeline::SIMPLE) { batch->setResourceTexture(0, _texture->getGPUTexture()); - } else if (RenderPipelines::bindMaterials(materials, *batch, args->_renderMode, args->_enableTexturing)) { - args->_details._materialSwitches++; + } else if (pipelineType == Pipeline::MATERIAL) { + if (RenderPipelines::bindMaterials(materials, *batch, args->_renderMode, args->_enableTexturing)) { + args->_details._materialSwitches++; + } } DependencyManager::get()->renderQuad( diff --git a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp index a36cdde2123..1117c97c751 100644 --- a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp @@ -47,8 +47,9 @@ void LineEntityRenderer::doRender(RenderArgs* args) { const auto& modelTransform = getModelTransform(); Transform transform = Transform(); transform.setTranslation(modelTransform.getTranslation()); + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(modelTransform.getTranslation(), modelTransform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); if (_linePoints.size() > 1) { DependencyManager::get()->bindSimpleProgram(batch, false, false, false, false, true, diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index 49962decc42..576e842f847 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -325,8 +325,9 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) { proceduralRender = true; } + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); if (!proceduralRender) { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 8ed3f846099..793871e55a3 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1123,37 +1123,7 @@ void ModelEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entit entity->setModel({}); } -void ModelEntityRenderer::animate(const TypedEntityPointer& entity, const ModelPointer& model) { - if (!_animation || !_animation->isLoaded()) { - return; - } - - QVector jointsData; - - const QVector& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy - int frameCount = frames.size(); - if (frameCount <= 0) { - return; - } - - { - float currentFrame = fmod(entity->getAnimationCurrentFrame(), (float)(frameCount)); - if (currentFrame < 0.0f) { - currentFrame += (float)frameCount; - } - int currentIntegerFrame = (int)(glm::floor(currentFrame)); - if (currentIntegerFrame == _lastKnownCurrentFrame) { - return; - } - _lastKnownCurrentFrame = currentIntegerFrame; - } - - if (_jointMapping.size() != model->getJointStateCount()) { - qCWarning(entitiesrenderer) << "RenderableModelEntityItem::getAnimationFrame -- joint count mismatch" - << _jointMapping.size() << model->getJointStateCount(); - return; - } - +void ModelEntityRenderer::updateJointData(const QVector& translations, const QVector& rotations, const TypedEntityPointer& entity, const ModelPointer& model) { QStringList animationJointNames = _animation->getHFMModel().getJointNames(); auto& hfmJoints = _animation->getHFMModel().joints; @@ -1162,10 +1132,7 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity, const ModelP bool allowTranslation = entity->getAnimationAllowTranslation(); - const QVector& rotations = frames[_lastKnownCurrentFrame].rotations; - const QVector& translations = frames[_lastKnownCurrentFrame].translations; - - jointsData.resize(_jointMapping.size()); + QVector jointsData(_jointMapping.size()); for (int j = 0; j < _jointMapping.size(); j++) { int index = _jointMapping[j]; @@ -1206,6 +1173,58 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity, const ModelP entity->copyAnimationJointDataToModel(); } +void ModelEntityRenderer::animate(const TypedEntityPointer& entity, const ModelPointer& model) { + if (!_animation || !_animation->isLoaded()) { + return; + } + + const QVector& frames = _animation->getFramesReference(); // NOTE: getFrames() is too heavy + int frameCount = frames.size(); + if (frameCount <= 0) { + return; + } + + float currentFrame = fmod(entity->getAnimationCurrentFrame(), (float)(frameCount)); + if (currentFrame < 0.0f) { + currentFrame += (float)frameCount; + } + + const bool smoothFrames = entity->getAnimationSmoothFrames(); + const int currentIntegerFrame = (int)(glm::floor(currentFrame)); + if (!smoothFrames && currentIntegerFrame == _lastKnownCurrentIntegerFrame) { + return; + } + _lastKnownCurrentIntegerFrame = currentIntegerFrame; + + if (_jointMapping.size() != model->getJointStateCount()) { + qCWarning(entitiesrenderer) << "RenderableModelEntityItem::getAnimationFrame -- joint count mismatch" + << _jointMapping.size() << model->getJointStateCount(); + return; + } + + if (smoothFrames) { + QVector rotations = frames[_lastKnownCurrentIntegerFrame].rotations; + QVector translations = frames[_lastKnownCurrentIntegerFrame].translations; + + const int nextIntegerFrame = entity->getAnimationNextFrame(_lastKnownCurrentIntegerFrame, frameCount); + + const QVector& nextRotations = frames[nextIntegerFrame].rotations; + const QVector& nextTranslations = frames[nextIntegerFrame].translations; + + const float frac = glm::fract(currentFrame); + for (int i = 0; i < translations.size(); i++) { + translations[i] = glm::mix(translations[i], nextTranslations[i], frac); + } + for (int i = 0; i < rotations.size(); i++) { + rotations[i] = glm::slerp(rotations[i], nextRotations[i], frac); + } + + updateJointData(translations, rotations, entity, model); + } else { + updateJointData(frames[_lastKnownCurrentIntegerFrame].translations, frames[_lastKnownCurrentIntegerFrame].rotations, entity, model); + } +} + bool ModelEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { if (entity->blendshapesChanged()) { return true; @@ -1242,7 +1261,6 @@ void ModelEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint if (!_hasModel) { if (model) { model->removeFromScene(scene, transaction); - entity->bumpAncestorChainRenderableVersion(); emit DependencyManager::get()-> modelRemovedFromScene(entity->getEntityItemID(), NestableType::Entity, model); withWriteLock([&] { _model.reset(); }); @@ -1274,6 +1292,8 @@ void ModelEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint _model->setBillboardMode(_billboardMode, scene); _model->setCullWithParent(_cullWithParent, scene); _model->setRenderWithZones(_renderWithZones, scene); + _model->setMirrorMode(_mirrorMode, scene); + _model->setPortalExitID(_portalExitID, scene); }); if (didVisualGeometryRequestSucceed) { emit DependencyManager::get()-> @@ -1290,6 +1310,10 @@ void ModelEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint scene->enqueueTransaction(transaction); }); entity->setModel(model); + model->setLoadingPriorityOperator([entity]() { + float loadPriority = entity->getLoadPriority(); + return fabs(loadPriority) > EPSILON ? loadPriority : EntityTreeRenderer::getEntityLoadingPriority(*entity); + }); withWriteLock([&] { _model = model; }); } @@ -1297,7 +1321,6 @@ void ModelEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint if (_parsedModelURL != model->getURL()) { _texturesLoaded = false; _jointMappingCompleted = false; - model->setLoadingPriority(EntityTreeRenderer::getEntityLoadingPriority(*entity)); model->setURL(_parsedModelURL); } @@ -1353,6 +1376,8 @@ void ModelEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint model->setBillboardMode(_billboardMode, scene); model->setCullWithParent(_cullWithParent, scene); model->setRenderWithZones(_renderWithZones, scene); + model->setMirrorMode(_mirrorMode, scene); + model->setPortalExitID(_portalExitID, scene); }); if (entity->blendshapesChanged()) { @@ -1368,7 +1393,6 @@ void ModelEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint makeStatusGetters(entity, statusGetters); using namespace std::placeholders; model->addToScene(scene, transaction, statusGetters, std::bind(&ModelEntityRenderer::metaBlendshapeOperator, _renderItemID, _1, _2, _3, _4)); - entity->bumpAncestorChainRenderableVersion(); processMaterials(); } } @@ -1466,6 +1490,18 @@ void ModelEntityRenderer::setCullWithParent(bool value) { setKey(_didLastVisualGeometryRequestSucceed, _model); } +void ModelEntityRenderer::setMirrorMode(MirrorMode value) { + Parent::setMirrorMode(value); + // called within a lock so no need to lock for _model + setKey(_didLastVisualGeometryRequestSucceed, _model); +} + +void ModelEntityRenderer::setPortalExitID(const QUuid& value) { + Parent::setPortalExitID(value); + // called within a lock so no need to lock for _model + setKey(_didLastVisualGeometryRequestSucceed, _model); +} + // NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items void ModelEntityRenderer::doRender(RenderArgs* args) { DETAILED_PROFILE_RANGE(render_detail, "MetaModelRender"); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index f394d389f59..4fd05f39b91 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -170,9 +170,12 @@ class ModelEntityRenderer : public TypedEntityRenderer& translations, const QVector& rotations, const TypedEntityPointer& entity, const ModelPointer& model); void mapJoints(const TypedEntityPointer& entity, const ModelPointer& model); // Transparency is handled in ModelMeshPartPayload @@ -182,7 +185,7 @@ class ModelEntityRenderer : public TypedEntityRendererisLoaded())) { + return; + } + if (_lastSimulated == 0) { _lastSimulated = usecTimestampNow(); return; @@ -460,9 +470,6 @@ void ParticleEffectEntityRenderer::doRender(RenderArgs* args) { return; } - // FIXME migrate simulation to a compute stage - stepSimulation(); - gpu::Batch& batch = *args->_batch; batch.setResourceTexture(0, _networkTexture->getGPUTexture()); diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h index 08d8822d2db..d9a1745b060 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h @@ -24,11 +24,14 @@ class ParticleEffectEntityRenderer : public TypedEntityRenderer +#include #include #include @@ -325,8 +325,9 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) { buildPipelines(); } + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); batch.setPipeline(_pipelines[{args->_renderMethod, isTransparent()}]); diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h index 6e5068c24f3..75309eca4aa 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h @@ -13,7 +13,6 @@ #define hifi_RenderablePolyLineEntityItem_h #include "RenderableEntityItem.h" -#include #include namespace render { namespace entities { diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 483d1c57efa..8cf5b937243 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -185,18 +185,6 @@ void RenderablePolyVoxEntityItem::initializePolyVox() { setVoxelVolumeSize(_voxelVolumeSize); } -bool isEdged(PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle) { - switch (surfaceStyle) { - case PolyVoxEntityItem::SURFACE_CUBIC: - case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: - return false; - case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: - case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES: - return true; - } - return false; -} - void RenderablePolyVoxEntityItem::setVoxelData(const QByteArray& voxelData) { // accept compressed voxel information from the entity-server bool changed = false; @@ -212,7 +200,7 @@ void RenderablePolyVoxEntityItem::setVoxelData(const QByteArray& voxelData) { } } -void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { +void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(uint16_t voxelSurfaceStyle) { // this controls whether the polyvox surface extractor does marching-cubes or makes a cubic mesh. It // also determines if the extra "edged" layer is used. bool volSizeChanged = false; @@ -224,7 +212,7 @@ void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxel // if we are switching to or from "edged" we need to force a resize of _volData. bool wasEdged = isEdged(); - bool willBeEdged = isEdged(voxelSurfaceStyle); + bool willBeEdged = isEdged((PolyVoxSurfaceStyle)voxelSurfaceStyle); if (wasEdged != willBeEdged) { _volData.reset(); @@ -952,7 +940,7 @@ uint8_t RenderablePolyVoxEntityItem::getVoxel(const ivec3& v) const { uint8_t RenderablePolyVoxEntityItem::getVoxelInternal(const ivec3& v) const { - if (!inUserBounds(_volData, _voxelSurfaceStyle, v)) { + if (!inUserBounds(_volData, (PolyVoxSurfaceStyle)_voxelSurfaceStyle, v)) { return 0; } @@ -998,7 +986,7 @@ bool RenderablePolyVoxEntityItem::setVoxelInternal(const ivec3& v, uint8_t toVal bool RenderablePolyVoxEntityItem::updateOnCount(const ivec3& v, uint8_t toValue) { // keep _onCount up to date - if (!inUserBounds(_volData, _voxelSurfaceStyle, v)) { + if (!inUserBounds(_volData, (PolyVoxSurfaceStyle)_voxelSurfaceStyle, v)) { return false; } @@ -1210,7 +1198,7 @@ void RenderablePolyVoxEntityItem::cacheNeighbors() { void RenderablePolyVoxEntityItem::copyUpperEdgesFromNeighbors() { // fill in our upper edges with a copy of our neighbors lower edges so that the meshes knit together - if (_voxelSurfaceStyle != PolyVoxEntityItem::SURFACE_MARCHING_CUBES) { + if ((PolyVoxSurfaceStyle)_voxelSurfaceStyle != PolyVoxEntityItem::SURFACE_MARCHING_CUBES) { return; } @@ -1315,7 +1303,7 @@ void RenderablePolyVoxEntityItem::recomputeMesh() { // use _volData to make a renderable mesh PolyVoxSurfaceStyle voxelSurfaceStyle; withReadLock([&] { - voxelSurfaceStyle = _voxelSurfaceStyle; + voxelSurfaceStyle = (PolyVoxSurfaceStyle)_voxelSurfaceStyle; }); auto entity = std::static_pointer_cast(getThisPointer()); @@ -1414,7 +1402,7 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorker() { graphics::MeshPointer mesh; withReadLock([&] { - voxelSurfaceStyle = _voxelSurfaceStyle; + voxelSurfaceStyle = (PolyVoxSurfaceStyle)_voxelSurfaceStyle; voxelVolumeSize = _voxelVolumeSize; mesh = _mesh; }); @@ -1857,8 +1845,9 @@ void PolyVoxEntityRenderer::doRender(RenderArgs* args) { PerformanceTimer perfTimer("RenderablePolyVoxEntityItem::render"); gpu::Batch& batch = *args->_batch; + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; glm::mat4 rotation = glm::mat4_cast(BillboardModeHelpers::getBillboardRotation(_position, _orientation, _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); Transform transform(glm::translate(_position) * rotation * _lastVoxelToLocalMatrix); batch.setModelTransform(transform); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index 1debeb957c2..2c6f29f4b97 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -81,7 +81,7 @@ class RenderablePolyVoxEntityItem : public PolyVoxEntityItem, public scriptable: virtual void setVoxelData(const QByteArray& voxelData) override; virtual void setVoxelVolumeSize(const glm::vec3& voxelVolumeSize) override; - virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) override; + virtual void setVoxelSurfaceStyle(uint16_t voxelSurfaceStyle) override; virtual ShapeType getShapeType() const override; virtual bool isReadyToComputeShape() const override; diff --git a/libraries/entities-renderer/src/RenderableProceduralParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableProceduralParticleEffectEntityItem.cpp new file mode 100644 index 00000000000..b458a6da3e6 --- /dev/null +++ b/libraries/entities-renderer/src/RenderableProceduralParticleEffectEntityItem.cpp @@ -0,0 +1,220 @@ +// +// RenderableProceduralParticleEffectEntityItem.cpp +// interface/src +// +// Created by HifiExperiements on 11/19/23 +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "RenderableProceduralParticleEffectEntityItem.h" + +#include +#include + +using namespace render; +using namespace render::entities; + +ProceduralParticleEffectEntityRenderer::ProceduralParticleEffectEntityRenderer(const EntityItemPointer& entity) : + Parent(entity) { + _updateProcedural._vertexSource = shader::Source::get(shader::gpu::vertex::DrawUnitQuadTexcoord); + _updateProcedural._opaqueFragmentSource = shader::Source::get(shader::entities_renderer::fragment::proceduralParticleUpdate); + _updateProcedural.setDoesFade(false); + + _renderProcedural._vertexSource = shader::Source::get(shader::entities_renderer::vertex::proceduralParticle); + _renderProcedural._opaqueFragmentSource = shader::Source::get(shader::entities_renderer::fragment::proceduralParticle); + _renderProcedural._transparentFragmentSource = shader::Source::get(shader::entities_renderer::fragment::proceduralParticle_translucent); + _renderProcedural._transparentState->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + _renderProcedural.setDoesFade(false); +} + +void ProceduralParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { + void* key = (void*)this; + AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [this, entity] { + withWriteLock([&] { + _renderTransform = getModelTransform(); + _renderTransform.postScale(entity->getScaledDimensions()); + }); + }); +} + +void ProceduralParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { + bool needsUpdateDefines = false; + bool needsRecreateParticles = false; + + uint32_t numParticles = entity->getNumParticles(); + if (_numParticles != numParticles) { + _numParticles = numParticles; + _particlePropTextureDim = pow(2, ceil(log2(sqrt(_numParticles)))); + needsUpdateDefines = true; + needsRecreateParticles = true; + } + + uint8_t numTrisPerParticle = entity->getNumTrianglesPerParticle(); + if (_numTrianglesPerParticle != numTrisPerParticle) { + _numTrianglesPerParticle = numTrisPerParticle; + needsUpdateDefines = true; + } + + uint8_t numUpdateProps = entity->getNumUpdateProps(); + if (_numUpdateProps != numUpdateProps) { + _numUpdateProps = numUpdateProps; + needsUpdateDefines = true; + needsRecreateParticles = true; + } + + if (needsRecreateParticles) { + recreateParticles(); + } + + bool particleTransparent = entity->getParticleTransparent(); + if (_transparent != particleTransparent) { + _transparent = particleTransparent; + } + + if (needsUpdateDefines) { + std::unordered_map replacements; + + static const std::string PROCEDURAL_PARTICLE_NUM_PARTICLES = "//PROCEDURAL_PARTICLE_NUM_PARTICLES"; + auto numParticlesDefine = "#undef NUM_PARTICLES\n#define NUM_PARTICLES " + std::to_string(_numParticles); + replacements[PROCEDURAL_PARTICLE_NUM_PARTICLES] = numParticlesDefine; + + static const std::string PROCEDURAL_PARTICLE_NUM_UPDATE_PROPS = "//PROCEDURAL_PARTICLE_NUM_UPDATE_PROPS"; + auto numUpdatePropsDefine = "#undef NUM_UPDATE_PROPS\n#define NUM_UPDATE_PROPS " + std::to_string(_numUpdateProps); + replacements[PROCEDURAL_PARTICLE_NUM_UPDATE_PROPS] = numUpdatePropsDefine; + + static const std::string PROCEDURAL_PARTICLE_NUM_TRIS_PER_PARTICLE = "//PROCEDURAL_PARTICLE_NUM_TRIS_PER_PARTICLE"; + auto numTrisPerParticleDefine = "#undef NUM_TRIS_PER_PARTICLE\n#define NUM_TRIS_PER_PARTICLE " + std::to_string(_numTrianglesPerParticle); + replacements[PROCEDURAL_PARTICLE_NUM_TRIS_PER_PARTICLE] = numTrisPerParticleDefine; + + _updateProcedural.setFragmentReplacements(replacements); + _renderProcedural.setFragmentReplacements(replacements); + _renderProcedural.setVertexReplacements(replacements); + } + + QString particleUpdateData = entity->getParticleUpdateData(); + if (_particleUpdateData != particleUpdateData) { + _particleUpdateData = particleUpdateData; + _updateProcedural.setProceduralData(ProceduralData::parse(particleUpdateData)); + } + + QString particleRenderData = entity->getParticleRenderData(); + if (_particleRenderData != particleRenderData) { + _particleRenderData = particleRenderData; + _renderProcedural.setProceduralData(ProceduralData::parse(particleRenderData)); + } +} + +bool ProceduralParticleEffectEntityRenderer::isTransparent() const { + return _transparent || Parent::isTransparent(); +} + +ItemKey ProceduralParticleEffectEntityRenderer::getKey() { + ItemKey::Builder builder = + ItemKey::Builder().withTypeShape().withTypeMeta().withTagBits(getTagMask()).withLayer(getHifiRenderLayer()); + + if (isTransparent()) { + builder.withTransparent(); + } else if (_canCastShadow) { + builder.withShadowCaster(); + } + + if (_cullWithParent) { + builder.withSubMetaCulled(); + } + + if (!_visible) { + builder.withInvisible(); + } + + if (_numUpdateProps > 0) { + builder.withSimulate(); + } + + return builder.build(); +} + +ShapeKey ProceduralParticleEffectEntityRenderer::getShapeKey() { + auto builder = ShapeKey::Builder().withOwnPipeline(); + + if (isTransparent()) { + builder.withTranslucent(); + } + + if (_primitiveMode == PrimitiveMode::LINES) { + builder.withWireframe(); + } + + return builder.build(); +} + +void ProceduralParticleEffectEntityRenderer::recreateParticles() { + for (auto& buffer : _particleBuffers) { + if (!buffer) { + buffer = FramebufferPointer(gpu::Framebuffer::create(("RenderableProceduralParticleEffectEntity " + _entityID.toString()).toStdString())); + } + + buffer->removeRenderBuffers(); + for (size_t i = 0; i < _numUpdateProps; i++) { + TexturePointer texture = TexturePointer(gpu::Texture::createRenderBuffer(gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::RGBA), + (gpu::uint16)_particlePropTextureDim, (gpu::uint16)_particlePropTextureDim, gpu::Texture::SINGLE_MIP, gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT))); + texture->setSource(("RenderableProceduralParticleEffectEntity " + _entityID.toString() + " " + (char)i).toStdString()); + buffer->setRenderBuffer((gpu::uint32)i, texture); + } + } +} + +void ProceduralParticleEffectEntityRenderer::renderSimulate(RenderArgs* args) { + PerformanceTimer perfTimer("RenderableProceduralParticleEffectEntityItem::simulate"); + Q_ASSERT(args->_batch); + gpu::Batch& batch = *args->_batch; + + if (!_visible || _numUpdateProps == 0 || !_updateProcedural.isReady()) { + return; + } + + _evenPass = !_evenPass; + + Transform transform; + withReadLock([&] { + transform = _renderTransform; + }); + + glm::ivec4 viewport = glm::ivec4(0, 0, _particleBuffers[!_evenPass]->getWidth(), _particleBuffers[!_evenPass]->getHeight()); + batch.setViewportTransform(viewport); + batch.setFramebuffer(_particleBuffers[_evenPass]); + + for (size_t i = 0; i < _numUpdateProps; i++) { + batch.setResourceTexture((gpu::uint32)(procedural::slot::texture::ParticleProp0 + i), _particleBuffers[!_evenPass]->getRenderBuffer((gpu::uint32)i)); + } + + _updateProcedural.prepare(batch, transform.getTranslation(), transform.getScale(), transform.getRotation(), _created, ProceduralProgramKey()); + batch.draw(gpu::TRIANGLE_STRIP, 4); +} + +void ProceduralParticleEffectEntityRenderer::doRender(RenderArgs* args) { + PerformanceTimer perfTimer("RenderableProceduralParticleEffectEntityItem::render"); + Q_ASSERT(args->_batch); + gpu::Batch& batch = *args->_batch; + + if (!_visible || _numParticles == 0 || (_numUpdateProps > 0 && !_updateProcedural.isReady()) || !_renderProcedural.isReady()) { + return; + } + + Transform transform; + withReadLock([&] { + transform = _renderTransform; + }); + + for (size_t i = 0; i < _numUpdateProps; i++) { + batch.setResourceTexture((gpu::uint32)(procedural::slot::texture::ParticleProp0 + i), _particleBuffers[_evenPass]->getRenderBuffer((gpu::uint32)i)); + } + + _renderProcedural.prepare(batch, transform.getTranslation(), transform.getScale(), transform.getRotation(), _created, ProceduralProgramKey(_transparent)); + + static const size_t VERTEX_PER_TRIANGLE = 3; + batch.drawInstanced((gpu::uint32)_numParticles, gpu::TRIANGLES, (gpu::uint32)(VERTEX_PER_TRIANGLE * _numTrianglesPerParticle)); +} \ No newline at end of file diff --git a/libraries/entities-renderer/src/RenderableProceduralParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableProceduralParticleEffectEntityItem.h new file mode 100644 index 00000000000..deb3f70f333 --- /dev/null +++ b/libraries/entities-renderer/src/RenderableProceduralParticleEffectEntityItem.h @@ -0,0 +1,63 @@ +// +// RenderableProceduralParticleEffectEntityItem.h +// interface/src/entities +// +// Created by HifiExperiements on 11/19/23 +// Copyright 2023 Overte e.V. +// +// 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_RenderableProceduralParticleEffectEntityItem_h +#define hifi_RenderableProceduralParticleEffectEntityItem_h + +#include "RenderableEntityItem.h" +#include + +#include + +namespace render { namespace entities { + +class ProceduralParticleEffectEntityRenderer : public TypedEntityRenderer { + using Parent = TypedEntityRenderer; + friend class EntityRenderer; + +public: + ProceduralParticleEffectEntityRenderer(const EntityItemPointer& entity); + + virtual void renderSimulate(RenderArgs* args) override; + +protected: + virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; + virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override; + + bool isTransparent() const override; + virtual ItemKey getKey() override; + virtual ShapeKey getShapeKey() override; + virtual void doRender(RenderArgs* args) override; + +private: + using TexturePointer = gpu::TexturePointer; + using FramebufferPointer = gpu::FramebufferPointer; + + void recreateParticles(); + + QString _particleUpdateData; + Procedural _updateProcedural; + QString _particleRenderData; + Procedural _renderProcedural; + + size_t _numParticles { 0 }; + size_t _particlePropTextureDim { 128 }; // 2^ceil(log2(sqrt(10,000))) + size_t _numTrianglesPerParticle { particle::DEFAULT_NUM_TRIS_PER }; + size_t _numUpdateProps { particle::DEFAULT_NUM_UPDATE_PROPS }; + bool _transparent { false }; + + std::array _particleBuffers; + bool _evenPass { true }; +}; + +} } // namespace + +#endif // hifi_RenderableProceduralParticleEffectEntityItem_h diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 02491105f55..e4f42b6133b 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -38,7 +38,7 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce withWriteLock([&] { _shape = entity->getShape(); _renderTransform = getModelTransform(); // contains parent scale, if this entity scales with its parent - if (_shape == entity::Sphere) { + if (_shape == EntityShape::Sphere) { _renderTransform.postScale(SPHERE_ENTITY_SCALE); } @@ -65,6 +65,13 @@ void ShapeEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint materialChanged = true; } + bool unlit = entity->getUnlit(); + if (_unlit != unlit) { + _unlit = unlit; + _material->setUnlit(unlit); + materialChanged = true; + } + auto userData = entity->getUserData(); if (_proceduralData != userData) { _proceduralData = userData; @@ -109,7 +116,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { gpu::Batch& batch = *args->_batch; auto geometryCache = DependencyManager::get(); - GeometryCache::Shape geometryShape = geometryCache->getShapeForEntityShape(_shape); + GeometryCache::Shape geometryShape = geometryCache->getShapeForEntityShape((int)_shape); Transform transform; withReadLock([&] { transform = _renderTransform; @@ -117,9 +124,10 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { bool wireframe = render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES; + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), - _shape < entity::Shape::Cube || _shape > entity::Shape::Icosahedron)); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), + _shape < EntityShape::Cube || _shape > EntityShape::Icosahedron)); batch.setModelTransform(transform); Pipeline pipelineType = getPipelineType(materials); @@ -160,7 +168,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { } } } else { - if (RenderPipelines::bindMaterials(materials, batch, args->_renderMode, args->_enableTexturing)) { + if (pipelineType == Pipeline::MATERIAL && RenderPipelines::bindMaterials(materials, batch, args->_renderMode, args->_enableTexturing)) { args->_details._materialSwitches++; } @@ -176,7 +184,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) { scriptable::ScriptableModelBase ShapeEntityRenderer::getScriptableModel() { scriptable::ScriptableModelBase result; auto geometryCache = DependencyManager::get(); - auto geometryShape = geometryCache->getShapeForEntityShape(_shape); + auto geometryShape = geometryCache->getShapeForEntityShape((int)_shape); glm::vec3 vertexColor; { std::lock_guard lock(_materialsLock); diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.h b/libraries/entities-renderer/src/RenderableShapeEntityItem.h index fd7bd4795b5..aa56f9f34de 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.h +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.h @@ -36,12 +36,13 @@ class ShapeEntityRenderer : public TypedEntityRenderer { virtual bool isTransparent() const override; QString _proceduralData; - entity::Shape _shape { entity::Sphere }; + EntityShape _shape { EntityShape::Sphere }; PulsePropertyGroup _pulseProperties; std::shared_ptr _material { std::make_shared() }; glm::vec3 _color { NAN }; float _alpha { NAN }; + bool _unlit { false }; gpu::BufferPointer _colorBuffer { std::make_shared() }; }; diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp index 5b790d6e608..9aec4c47f13 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp @@ -25,10 +25,6 @@ using namespace render; using namespace render::entities; -static const int FIXED_FONT_POINT_SIZE = 40; -const int FIXED_FONT_SCALING_RATIO = FIXED_FONT_POINT_SIZE * 92.0f; // Determined through experimentation to fit font to line height. -const float LINE_SCALE_RATIO = 1.2f; - TextEntityRenderer::TextEntityRenderer(const EntityItemPointer& entity) : Parent(entity), _textRenderer(TextRenderer3D::getInstance(ROBOTO_FONT_FAMILY)) { @@ -77,6 +73,7 @@ void TextEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointe _effectColor = toGlm(entity->getTextEffectColor()); _effectThickness = entity->getTextEffectThickness(); _alignment = entity->getAlignment(); + _verticalAlignment = entity->getVerticalAlignment(); bool materialChanged = false; glm::vec3 color = toGlm(entity->getBackgroundColor()); @@ -163,8 +160,9 @@ void TextEntityRenderer::doRender(RenderArgs* args) { transform = _renderTransform; }); + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); Pipeline pipelineType = getPipelineType(materials); @@ -179,7 +177,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) { } auto geometryCache = DependencyManager::get(); - if (pipelineType == Pipeline::SIMPLE) { + if (pipelineType == Pipeline::SIMPLE || pipelineType == Pipeline::MIRROR) { geometryCache->renderQuad(batch, glm::vec2(-0.5f), glm::vec2(0.5f), backgroundColor, _geometryID); } else { geometryCache->renderQuad(batch, glm::vec2(-0.5f), glm::vec2(0.5f), glm::vec2(0.0f), glm::vec2(1.0f), backgroundColor, _geometryID); @@ -191,12 +189,8 @@ void TextEntityRenderer::doRender(RenderArgs* args) { QSizeF TextEntityRenderer::textSize(const QString& text) const { auto extents = _textRenderer->computeExtent(text); - extents.y *= 2.0f; - - float maxHeight = (float)_textRenderer->computeExtent("Xy").y * LINE_SCALE_RATIO; - float pointToWorldScale = (maxHeight / FIXED_FONT_SCALING_RATIO) * _lineHeight; - - return QSizeF(extents.x, extents.y) * pointToWorldScale; + float scale = _lineHeight / _textRenderer->getFontHeight(); + return scale * QSizeF(extents.x, extents.y); } void TextEntityRenderer::onAddToSceneTyped(const TypedEntityPointer& entity) { @@ -259,6 +253,10 @@ ItemKey entities::TextPayload::getKey() const { builder.withInvisible(); } + if (textRenderable->_mirrorMode == MirrorMode::MIRROR || (textRenderable->_mirrorMode == MirrorMode::PORTAL && !textRenderable->_portalExitID.isNull())) { + builder.withMirror(); + } + return builder; } } @@ -310,6 +308,17 @@ bool entities::TextPayload::passesZoneOcclusionTest(const std::unordered_set(); + if (entityTreeRenderer) { + auto renderable = entityTreeRenderer->renderableForEntityId(_entityID); + if (renderable) { + return renderable->computeMirrorView(viewFrustum); + } + } + return Item::INVALID_ITEM_ID; +} + void entities::TextPayload::render(RenderArgs* args) { PerformanceTimer perfTimer("TextPayload::render"); Q_ASSERT(args->_batch); @@ -334,12 +343,15 @@ void entities::TextPayload::render(RenderArgs* args) { glm::vec3 dimensions; glm::vec4 textColor; + bool mirror; textRenderable->withReadLock([&] { transform = textRenderable->_renderTransform; dimensions = textRenderable->_dimensions; float fadeRatio = textRenderable->_isFading ? Interpolate::calculateFadeRatio(textRenderable->_fadeStartTime) : 1.0f; textColor = glm::vec4(textRenderable->_textColor, fadeRatio * textRenderable->_textAlpha); + + mirror = textRenderable->_mirrorMode == MirrorMode::MIRROR || (textRenderable->_mirrorMode == MirrorMode::PORTAL && !textRenderable->_portalExitID.isNull()); }); bool forward = textRenderable->_renderLayer != RenderLayer::WORLD || args->_renderMethod == render::Args::FORWARD; @@ -351,18 +363,22 @@ void entities::TextPayload::render(RenderArgs* args) { return; } + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), textRenderable->_billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); - float scale = textRenderable->_lineHeight / textRenderer->getFontSize(); + float scale = 1.0f; + float fontHeight = textRenderer->getFontHeight(); + if (fontHeight > 0.0f) { + scale = textRenderable->_lineHeight / fontHeight; + } transform.postTranslate(glm::vec3(-0.5, 0.5, 1.0f + EPSILON / dimensions.z)); transform.setScale(scale); batch.setModelTransform(transform); glm::vec2 bounds = glm::vec2(dimensions.x - (textRenderable->_leftMargin + textRenderable->_rightMargin), dimensions.y - (textRenderable->_topMargin + textRenderable->_bottomMargin)); - textRenderer->draw(batch, textRenderable->_leftMargin / scale, -textRenderable->_topMargin / scale, bounds / scale, scale, - textRenderable->_text, textRenderable->_font, textColor, effectColor, textRenderable->_effectThickness, textRenderable->_effect, - textRenderable->_alignment, textRenderable->_unlit, forward); + textRenderer->draw(batch, textRenderable->_font, { textRenderable->_text, textColor, effectColor, { textRenderable->_leftMargin / scale, -textRenderable->_topMargin / scale }, + bounds / scale, scale, textRenderable->_effectThickness, textRenderable->_effect, textRenderable->_alignment, textRenderable->_verticalAlignment, textRenderable->_unlit, forward, mirror }); } namespace render { @@ -398,4 +414,11 @@ template <> bool payloadPassesZoneOcclusionTest(const entities::TextPayload::Poi return false; } +template <> ItemID payloadComputeMirrorView(const entities::TextPayload::Pointer& payload, ViewFrustum& viewFrustum) { + if (payload) { + return payload->computeMirrorView(viewFrustum); + } + return Item::INVALID_ITEM_ID; +} + } diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.h b/libraries/entities-renderer/src/RenderableTextEntityItem.h index 8a18554dea3..782b4d4f342 100644 --- a/libraries/entities-renderer/src/RenderableTextEntityItem.h +++ b/libraries/entities-renderer/src/RenderableTextEntityItem.h @@ -74,6 +74,7 @@ class TextEntityRenderer : public TypedEntityRenderer { QString _font { "" }; TextAlignment _alignment { TextAlignment::LEFT }; + TextVerticalAlignment _verticalAlignment { TextVerticalAlignment::TOP }; TextEffect _effect { TextEffect::NO_EFFECT }; glm::vec3 _effectColor { 0 }; float _effectThickness { 0.0f }; @@ -101,6 +102,7 @@ class TextPayload { ShapeKey getShapeKey() const; void render(RenderArgs* args); bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const; + ItemID computeMirrorView(ViewFrustum& viewFrustum) const; protected: QUuid _entityID; @@ -117,6 +119,7 @@ namespace render { template <> const ShapeKey shapeGetShapeKey(const entities::TextPayload::Pointer& payload); template <> void payloadRender(const entities::TextPayload::Pointer& payload, RenderArgs* args); template <> bool payloadPassesZoneOcclusionTest(const entities::TextPayload::Pointer& payload, const std::unordered_set& containingZones); + template <> ItemID payloadComputeMirrorView(const entities::TextPayload::Pointer& payload, ViewFrustum& viewFrustum); } #endif // hifi_RenderableTextEntityItem_h diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index c98bfe7f632..c50e2ee1ad9 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -168,9 +168,10 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene withWriteLock([&] { _inputMode = entity->getInputMode(); - _dpi = entity->getDPI(); + _dpi = entity->getDpi(); _color = entity->getColor(); _alpha = entity->getAlpha(); + _wantsKeyboardFocus = entity->wantsKeyboardFocus(); _pulseProperties = entity->getPulseProperties(); if (_contentType == ContentType::NoContent) { @@ -320,8 +321,9 @@ void WebEntityRenderer::doRender(RenderArgs* args) { batch.setResourceTexture(0, _texture); + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); batch.setModelTransform(transform); // Turn off jitter for these entities diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.h b/libraries/entities-renderer/src/RenderableWebEntityItem.h index 81165d140f8..8182c02603a 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.h +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.h @@ -67,7 +67,7 @@ class WebEntityRenderer : public TypedEntityRenderer { virtual bool isTransparent() const override; virtual bool wantsHandControllerPointerEvents() const override { return true; } - virtual bool wantsKeyboardFocus() const override { return true; } + virtual bool wantsKeyboardFocus() const override { return _wantsKeyboardFocus; } void handlePointerEventAsTouch(const PointerEvent& event); void handlePointerEventAsMouse(const PointerEvent& event); @@ -103,6 +103,7 @@ class WebEntityRenderer : public TypedEntityRenderer { bool _useBackground { false }; QString _userAgent; WebInputMode _inputMode { WebInputMode::TOUCH }; + bool _wantsKeyboardFocus { true }; glm::vec3 _contextPosition; diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index ce2dae8d282..178e122c327 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -68,6 +68,20 @@ void ZoneEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entity _bloomIndex = INVALID_INDEX; } } + + if (_tonemappingStage) { + if (!TonemappingStage::isIndexInvalid(_tonemappingIndex)) { + _tonemappingStage->removeTonemapping(_tonemappingIndex); + _tonemappingIndex = INVALID_INDEX; + } + } + + if (_ambientOcclusionStage) { + if (!AmbientOcclusionStage::isIndexInvalid(_ambientOcclusionIndex)) { + _ambientOcclusionStage->removeAmbientOcclusion(_ambientOcclusionIndex); + _ambientOcclusionIndex = INVALID_INDEX; + } + } } void ZoneEntityRenderer::doRender(RenderArgs* args) { @@ -96,6 +110,16 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { assert(_bloomStage); } + if (!_tonemappingStage) { + _tonemappingStage = args->_scene->getStage(); + assert(_tonemappingStage); + } + + if (!_ambientOcclusionStage) { + _ambientOcclusionStage = args->_scene->getStage(); + assert(_ambientOcclusionStage); + } + { // Sun if (_needSunUpdate) { if (LightStage::isIndexInvalid(_sunIndex)) { @@ -149,6 +173,24 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { } } + { + if (_needTonemappingUpdate) { + if (TonemappingStage::isIndexInvalid(_tonemappingIndex)) { + _tonemappingIndex = _tonemappingStage->addTonemapping(_tonemapping); + } + _needTonemappingUpdate = false; + } + } + + { + if (_needAmbientOcclusionUpdate) { + if (AmbientOcclusionStage::isIndexInvalid(_ambientOcclusionIndex)) { + _ambientOcclusionIndex = _ambientOcclusionStage->addAmbientOcclusion(_ambientOcclusion); + } + _needAmbientOcclusionUpdate = false; + } + } + if (_visible) { // Finally, push the lights visible in the frame // @@ -184,6 +226,18 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) { } else if (_bloomMode == COMPONENT_MODE_ENABLED) { _bloomStage->_currentFrame.pushBloom(_bloomIndex); } + + if (_tonemappingMode == COMPONENT_MODE_DISABLED) { + _tonemappingStage->_currentFrame.pushTonemapping(0); // Use the fallback tonemapping for "off" + } else if (_tonemappingMode == COMPONENT_MODE_ENABLED) { + _tonemappingStage->_currentFrame.pushTonemapping(_tonemappingIndex); + } + + if (_ambientOcclusionMode == COMPONENT_MODE_DISABLED) { + _ambientOcclusionStage->_currentFrame.pushAmbientOcclusion(INVALID_INDEX); + } else if (_ambientOcclusionMode == COMPONENT_MODE_ENABLED) { + _ambientOcclusionStage->_currentFrame.pushAmbientOcclusion(_ambientOcclusionIndex); + } } CullTest::_containingZones.insert(_entityID); @@ -216,6 +270,8 @@ void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointe bool skyboxChanged = entity->skyboxPropertiesChanged() || proceduralUserDataChanged; bool hazeChanged = entity->hazePropertiesChanged(); bool bloomChanged = entity->bloomPropertiesChanged(); + bool tonemappingChanged = entity->tonemappingPropertiesChanged(); + bool ambientOcclusionChanged = entity->ambientOcclusionPropertiesChanged(); entity->resetRenderingPropertiesChanged(); if (transformChanged) { @@ -255,6 +311,16 @@ void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointe updateBloomFromEntity(entity); } + if (tonemappingChanged) { + _tonemappingProperties = entity->getTonemappingProperties(); + updateTonemappingFromEntity(entity); + } + + if (ambientOcclusionChanged) { + _ambientOcclusionProperties = entity->getAmbientOcclusionProperties(); + updateAmbientOcclusionFromEntity(entity); + } + bool visuallyReady = true; uint32_t skyboxMode = entity->getSkyboxMode(); if (skyboxMode == COMPONENT_MODE_ENABLED && !_skyboxTextureURL.isEmpty()) { @@ -275,7 +341,9 @@ bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint entity->ambientLightPropertiesChanged() || entity->hazePropertiesChanged() || entity->bloomPropertiesChanged() || - entity->skyboxPropertiesChanged()) { + entity->skyboxPropertiesChanged() || + entity->tonemappingPropertiesChanged() || + entity->ambientOcclusionPropertiesChanged()) { return true; } @@ -309,10 +377,11 @@ void ZoneEntityRenderer::updateAmbientLightFromEntity(const TypedEntityPointer& ambientLight->setOrientation(_lastRotation); // Set the ambient light + ambientLight->setAmbientColor(ColorUtils::toVec3(_ambientLightProperties.getAmbientColor())); ambientLight->setAmbientIntensity(_ambientLightProperties.getAmbientIntensity()); if (_ambientLightProperties.getAmbientURL().isEmpty()) { - setAmbientURL(_skyboxProperties.getURL()); + setAmbientURL(_skyboxProperties.getUrl()); } else { setAmbientURL(_ambientLightProperties.getAmbientURL()); } @@ -359,13 +428,39 @@ void ZoneEntityRenderer::updateBloomFromEntity(const TypedEntityPointer& entity) bloom->setBloomSize(_bloomProperties.getBloomSize()); } +void ZoneEntityRenderer::updateTonemappingFromEntity(const TypedEntityPointer& entity) { + _tonemappingMode = (ComponentMode)entity->getTonemappingMode(); + + const auto& tonemapping = editTonemapping(); + + tonemapping->setCurve(_tonemappingProperties.getCurve()); + tonemapping->setExposure(_tonemappingProperties.getExposure()); +} + +void ZoneEntityRenderer::updateAmbientOcclusionFromEntity(const TypedEntityPointer& entity) { + _ambientOcclusionMode = (ComponentMode)entity->getAmbientOcclusionMode(); + + const auto& ambientOcclusion = editAmbientOcclusion(); + + ambientOcclusion->setTechnique(_ambientOcclusionProperties.getTechnique()); + ambientOcclusion->setJitter(_ambientOcclusionProperties.getJitter()); + ambientOcclusion->setResolutionLevel(_ambientOcclusionProperties.getResolutionLevel()); + ambientOcclusion->setEdgeSharpness(_ambientOcclusionProperties.getEdgeSharpness()); + ambientOcclusion->setBlurRadius(_ambientOcclusionProperties.getBlurRadius()); + ambientOcclusion->setAORadius(_ambientOcclusionProperties.getAoRadius()); + ambientOcclusion->setAOObscuranceLevel(_ambientOcclusionProperties.getAoObscuranceLevel()); + ambientOcclusion->setAOFalloffAngle(_ambientOcclusionProperties.getAoFalloffAngle()); + ambientOcclusion->setAOSamplingAmount(_ambientOcclusionProperties.getAoSamplingAmount()); + ambientOcclusion->setSSAONumSpiralTurns(_ambientOcclusionProperties.getSsaoNumSpiralTurns()); +} + void ZoneEntityRenderer::updateKeyBackgroundFromEntity(const TypedEntityPointer& entity) { _skyboxMode = (ComponentMode)entity->getSkyboxMode(); editBackground(); setSkyboxColor(toGlm(_skyboxProperties.getColor())); setProceduralUserData(_proceduralUserData); - setSkyboxURL(_skyboxProperties.getURL()); + setSkyboxURL(_skyboxProperties.getUrl()); } void ZoneEntityRenderer::updateKeyZoneItemFromEntity(const TypedEntityPointer& entity) { diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h index d2ee90b1e42..78694514d23 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.h +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include "RenderableEntityItem.h" #include @@ -47,6 +49,8 @@ class ZoneEntityRenderer : public TypedEntityRenderer { void updateHazeFromEntity(const TypedEntityPointer& entity); void updateKeyBackgroundFromEntity(const TypedEntityPointer& entity); void updateBloomFromEntity(const TypedEntityPointer& entity); + void updateTonemappingFromEntity(const TypedEntityPointer& entity); + void updateAmbientOcclusionFromEntity(const TypedEntityPointer& entity); void updateAmbientMap(); void updateSkyboxMap(); void setAmbientURL(const QString& ambientUrl); @@ -61,6 +65,8 @@ class ZoneEntityRenderer : public TypedEntityRenderer { graphics::SkyboxPointer editSkybox() { return editBackground()->getSkybox(); } graphics::HazePointer editHaze() { _needHazeUpdate = true; return _haze; } graphics::BloomPointer editBloom() { _needBloomUpdate = true; return _bloom; } + graphics::TonemappingPointer editTonemapping() { _needTonemappingUpdate = true; return _tonemapping; } + graphics::AmbientOcclusionPointer editAmbientOcclusion() { _needAmbientOcclusionUpdate = true; return _ambientOcclusion; } glm::vec3 _lastPosition; glm::vec3 _lastDimensions; @@ -73,12 +79,16 @@ class ZoneEntityRenderer : public TypedEntityRenderer { const graphics::SunSkyStagePointer _background { std::make_shared() }; const graphics::HazePointer _haze { std::make_shared() }; const graphics::BloomPointer _bloom { std::make_shared() }; + const graphics::TonemappingPointer _tonemapping { std::make_shared() }; + const graphics::AmbientOcclusionPointer _ambientOcclusion { std::make_shared() }; 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 }; + ComponentMode _tonemappingMode { COMPONENT_MODE_INHERIT }; + ComponentMode _ambientOcclusionMode { COMPONENT_MODE_INHERIT }; indexed_container::Index _sunIndex { LightStage::INVALID_INDEX }; indexed_container::Index _ambientIndex { LightStage::INVALID_INDEX }; @@ -92,27 +102,37 @@ class ZoneEntityRenderer : public TypedEntityRenderer { BloomStagePointer _bloomStage; BloomStage::Index _bloomIndex { BloomStage::INVALID_INDEX }; - bool _needUpdate{ true }; - bool _needSunUpdate{ true }; - bool _needAmbientUpdate{ true }; - bool _needBackgroundUpdate{ true }; - bool _needHazeUpdate{ true }; + TonemappingStagePointer _tonemappingStage; + TonemappingStage::Index _tonemappingIndex { TonemappingStage::INVALID_INDEX }; + + AmbientOcclusionStagePointer _ambientOcclusionStage; + AmbientOcclusionStage::Index _ambientOcclusionIndex { AmbientOcclusionStage::INVALID_INDEX }; + + bool _needUpdate { true }; + bool _needSunUpdate { true }; + bool _needAmbientUpdate { true }; + bool _needBackgroundUpdate { true }; + bool _needHazeUpdate { true }; bool _needBloomUpdate { true }; + bool _needTonemappingUpdate { true }; + bool _needAmbientOcclusionUpdate { true }; KeyLightPropertyGroup _keyLightProperties; AmbientLightPropertyGroup _ambientLightProperties; HazePropertyGroup _hazeProperties; SkyboxPropertyGroup _skyboxProperties; BloomPropertyGroup _bloomProperties; + TonemappingPropertyGroup _tonemappingProperties; + AmbientOcclusionPropertyGroup _ambientOcclusionProperties; // More attributes used for rendering: QString _ambientTextureURL; NetworkTexturePointer _ambientTexture; - bool _pendingAmbientTexture{ false }; + bool _pendingAmbientTexture { false }; QString _skyboxTextureURL; NetworkTexturePointer _skyboxTexture; - bool _pendingSkyboxTexture{ false }; + bool _pendingSkyboxTexture { false }; QString _proceduralUserData; }; diff --git a/libraries/entities-renderer/src/entities-renderer/proceduralParticle.slp b/libraries/entities-renderer/src/entities-renderer/proceduralParticle.slp new file mode 100644 index 00000000000..e5119c55e48 --- /dev/null +++ b/libraries/entities-renderer/src/entities-renderer/proceduralParticle.slp @@ -0,0 +1 @@ +DEFINES translucent:f forward:f \ No newline at end of file diff --git a/libraries/entities-renderer/src/proceduralParticle.slf b/libraries/entities-renderer/src/proceduralParticle.slf new file mode 100644 index 00000000000..e2ad5bf7ff5 --- /dev/null +++ b/libraries/entities-renderer/src/proceduralParticle.slf @@ -0,0 +1,172 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// <$_SCRIBE_FILENAME$> +// Generated on <$_SCRIBE_DATE$> +// +// Created by HifiExperiements on 11/21/23 +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@if not HIFI_USE_TRANSLUCENT@> + <@include DeferredBufferWrite.slh@> +<@else@> + <@include DefaultMaterials.slh@> + + <@include GlobalLight.slh@> + <$declareEvalGlobalLightingAlphaBlended()$> + + layout(location=0) out vec4 _fragColor0; +<@endif@> + +<@include gpu/Transform.slh@> +<$declareStandardCameraTransform()$> + +<@include render-utils/ShaderConstants.h@> + +<@include procedural/ProceduralCommon.slh@> +<@include procedural/ProceduralParticleCommon.slh@> +<$declareProceduralParticleRender()$> + +layout(location=0) flat in int particleID; +layout(location=1) in vec4 _positionES; + +#line 1001 +//PROCEDURAL_BLOCK_BEGIN + +vec3 getProceduralColor() { + return vec3(1.0); +} + +float getProceduralColors(inout vec3 diffuse, inout vec3 specular, inout float shininess) { + return 1.0; +} + +float getProceduralFragment(inout ProceduralFragment proceduralData) { + return 1.0; +} + +float getProceduralFragmentWithPosition(inout ProceduralFragmentWithPosition proceduralData) { + return 1.0; +} + +//PROCEDURAL_BLOCK_END + +#line 2030 +void main(void) { + vec3 normal = vec3(0.0, 1.0, 0.0); + vec3 diffuse = vec3(0.0); + vec3 fresnel = DEFAULT_FRESNEL; + float roughness = DEFAULT_ROUGHNESS; + float metallic = DEFAULT_METALLIC; + vec3 emissive = DEFAULT_EMISSIVE; + float occlusion = DEFAULT_OCCLUSION; + float scattering = DEFAULT_SCATTERING; + float alpha = 1.0; + + float emissiveAmount = 0.0; + +<@if HIFI_USE_TRANSLUCENT@> + TransformCamera cam = getTransformCamera(); + vec3 posEye = _positionES.xyz; +<@endif@> + +#if defined(PROCEDURAL_V1) + diffuse = getProceduralColor().rgb; + emissiveAmount = 1.0; + emissive = vec3(1.0); +#elif defined(PROCEDURAL_V2) + vec3 specular = DEFAULT_SPECULAR; + float shininess = DEFAULT_SHININESS; + emissiveAmount = getProceduralColors(diffuse, specular, shininess); + roughness = max(0.0, 1.0 - shininess / 128.0); + metallic = length(specular); + emissive = vec3(clamp(emissiveAmount, 0.0, 1.0)); +#elif defined(PROCEDURAL_V3) || defined(PROCEDURAL_V4) +#if defined(PROCEDURAL_V3) + ProceduralFragment proceduralData = ProceduralFragment( +#else + TransformCamera cam = getTransformCamera(); + vec4 position = cam._viewInverse * _positionES; + ProceduralFragmentWithPosition proceduralData = ProceduralFragmentWithPosition( + position.xyz, +#endif + normal, + diffuse, + fresnel, + emissive, + alpha, + roughness, + metallic, + occlusion, + scattering + ); + +#if defined(PROCEDURAL_V3) + emissiveAmount = getProceduralFragment(proceduralData); +#else + emissiveAmount = getProceduralFragmentWithPosition(proceduralData); +#endif + normal = proceduralData.normal; + diffuse = proceduralData.diffuse; + fresnel = proceduralData.specular; + roughness = proceduralData.roughness; + metallic = proceduralData.metallic; + emissive = proceduralData.emissive; + occlusion = proceduralData.occlusion; + scattering = proceduralData.scattering; + alpha = proceduralData.alpha; + +#if defined(PROCEDURAL_V4) + position = vec4(proceduralData.position, 1.0); + vec4 posEye4 = cam._view * position; +<@if HIFI_USE_TRANSLUCENT@> + posEye = posEye4.xyz; +<@endif@> + vec4 posClip = cam._projection * posEye4; + gl_FragDepth = 0.5 * (posClip.z / posClip.w + 1.0); +#endif + +#endif + +<@if not HIFI_USE_TRANSLUCENT@> + if (emissiveAmount > 0.0) { + packDeferredFragmentLightmap( + normal, + 1.0, + diffuse, + roughness, + metallic, + emissive); + } else { + packDeferredFragment( + normal, + 1.0, + diffuse, + roughness, + metallic, + emissive, + occlusion, + scattering); + } +<@else@> + if (emissiveAmount > 0.0) { + _fragColor0 = vec4(diffuse, alpha); + } else { + _fragColor0 = vec4(evalGlobalLightingAlphaBlended( + cam._viewInverse, + 1.0, + occlusion, + posEye, + normal, + diffuse, + fresnel, + metallic, + emissive, + roughness, alpha), + alpha); + } +<@endif@> +} diff --git a/libraries/entities-renderer/src/proceduralParticle.slv b/libraries/entities-renderer/src/proceduralParticle.slv new file mode 100644 index 00000000000..4d87399fa21 --- /dev/null +++ b/libraries/entities-renderer/src/proceduralParticle.slv @@ -0,0 +1,38 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// <$_SCRIBE_FILENAME$> +// Generated on <$_SCRIBE_DATE$> +// +// Created by HifiExperiements on 11/21/23 +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include gpu/Transform.slh@> +<$declareStandardTransform()$> + +<@include procedural/ProceduralCommon.slh@> +<@include procedural/ProceduralParticleCommon.slh@> +<$declareProceduralParticleRender()$> + +layout(location=0) flat out int particleID; +layout(location=1) out vec4 _positionES; + +#line 1001 +//PROCEDURAL_BLOCK_BEGIN +vec3 getProceduralVertex(const int particleID) { + return vec3(0.0); +} +//PROCEDURAL_BLOCK_END + +#line 2030 +void main(void) { + particleID = gpu_InstanceID(); + vec4 worldPos = vec4(getProceduralVertex(particleID), 1.0); + + TransformCamera cam = getTransformCamera(); + TransformObject obj = getTransformObject(); + <$transformWorldToEyeAndClipPos(cam, worldPos, _positionES, gl_Position)$> +} diff --git a/libraries/entities-renderer/src/proceduralParticleUpdate.slf b/libraries/entities-renderer/src/proceduralParticleUpdate.slf new file mode 100644 index 00000000000..2188bdc4623 --- /dev/null +++ b/libraries/entities-renderer/src/proceduralParticleUpdate.slf @@ -0,0 +1,107 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// <$_SCRIBE_FILENAME$> +// Generated on <$_SCRIBE_DATE$> +// +// Created by HifiExperiements on 11/21/23 +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include procedural/ProceduralCommon.slh@> +<@include procedural/ProceduralParticleCommon.slh@> + +layout(location=0) in vec2 varTexCoord0; + +#if NUM_UPDATE_PROPS > 0 +layout(location=0) out vec4 _prop0; +#endif +#if NUM_UPDATE_PROPS > 1 +layout(location=1) out vec4 _prop1; +#endif +#if NUM_UPDATE_PROPS > 2 +layout(location=2) out vec4 _prop2; +#endif +#if NUM_UPDATE_PROPS > 3 +layout(location=3) out vec4 _prop3; +#endif +#if NUM_UPDATE_PROPS > 4 +layout(location=4) out vec4 _prop4; +#endif + +#if NUM_UPDATE_PROPS > 0 +struct ParticleUpdateProps { + vec4 prop0; +#if NUM_UPDATE_PROPS > 1 + vec4 prop1; +#endif +#if NUM_UPDATE_PROPS > 2 + vec4 prop2; +#endif +#if NUM_UPDATE_PROPS > 3 + vec4 prop3; +#endif +#if NUM_UPDATE_PROPS > 4 + vec4 prop4; +#endif +}; + +ParticleUpdateProps getParticleProps() { + ParticleUpdateProps particleProps; + particleProps.prop0 = texture(_prop0Texture, varTexCoord0); +#if NUM_UPDATE_PROPS > 1 + particleProps.prop1 = texture(_prop1Texture, varTexCoord0); +#endif +#if NUM_UPDATE_PROPS > 2 + particleProps.prop2 = texture(_prop2Texture, varTexCoord0); +#endif +#if NUM_UPDATE_PROPS > 3 + particleProps.prop3 = texture(_prop3Texture, varTexCoord0); +#endif +#if NUM_UPDATE_PROPS > 4 + particleProps.prop4 = texture(_prop4Texture, varTexCoord0); +#endif + return particleProps; +} +#endif + +#line 1001 +#if NUM_UPDATE_PROPS > 0 +//PROCEDURAL_BLOCK_BEGIN + +void updateParticleProps(const int particleID, inout ParticleUpdateProps particleProps) {} + +//PROCEDURAL_BLOCK_END +#endif + +#line 2030 +void main(void) { +#if NUM_UPDATE_PROPS > 0 + const ivec2 textureDims = textureSize(_prop0Texture, 0); + const ivec2 indexXY = ivec2(gl_FragCoord.xy); + const int particleID = indexXY.x + textureDims.x * indexXY.y; + + if (particleID >= NUM_PARTICLES) { + return; + } + + ParticleUpdateProps particleProps = getParticleProps(); + updateParticleProps(particleID, particleProps); + + _prop0 = particleProps.prop0; +#endif +#if NUM_UPDATE_PROPS > 1 + _prop1 = particleProps.prop1; +#endif +#if NUM_UPDATE_PROPS > 2 + _prop2 = particleProps.prop2; +#endif +#if NUM_UPDATE_PROPS > 3 + _prop3 = particleProps.prop3; +#endif +#if NUM_UPDATE_PROPS > 4 + _prop4 = particleProps.prop4; +#endif +} diff --git a/libraries/entities/CMakeLists.txt b/libraries/entities/CMakeLists.txt index e04d9f9fa82..5a2e703de8c 100644 --- a/libraries/entities/CMakeLists.txt +++ b/libraries/entities/CMakeLists.txt @@ -3,8 +3,11 @@ # SPDX-License-Identifier: Apache-2.0 set(TARGET_NAME entities) +generate_entity_properties() setup_hifi_library(Network) target_include_directories(${TARGET_NAME} PRIVATE "${OPENSSL_INCLUDE_DIR}") +target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/libraries/entities/src") +target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_SOURCE_DIR}/libraries/entities/src") include_hifi_library_headers(hfm) include_hifi_library_headers(model-serializers) include_hifi_library_headers(gpu) @@ -12,7 +15,7 @@ include_hifi_library_headers(image) include_hifi_library_headers(ktx) include_hifi_library_headers(material-networking) include_hifi_library_headers(procedural) -link_hifi_libraries(shared shaders networking octree avatars graphics model-networking script-engine) +link_hifi_libraries(audio shared shaders networking octree avatars graphics model-networking script-engine) if (WIN32) add_compile_definitions(_USE_MATH_DEFINES) diff --git a/libraries/entities/src/AmbientLightPropertyGroup.cpp b/libraries/entities/src/AmbientLightPropertyGroup.cpp deleted file mode 100644 index c4306881136..00000000000 --- a/libraries/entities/src/AmbientLightPropertyGroup.cpp +++ /dev/null @@ -1,158 +0,0 @@ -// -// AmbientLightPropertyGroup.cpp -// libraries/entities/src -// -// Created by Nissim Hadar on 2017/12/24. -// Copyright 2013 High Fidelity, Inc. -// Copyright 2023 Overte e.V. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// SPDX-License-Identifier: Apache-2.0 -// - -#include "AmbientLightPropertyGroup.h" - -#include -#include - -#include "EntityItemProperties.h" -#include "EntityItemPropertiesMacros.h" - -const float AmbientLightPropertyGroup::DEFAULT_AMBIENT_LIGHT_INTENSITY = 0.5f; - -void AmbientLightPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, - ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, - bool isMyOwnAvatarEntity) const { - - auto nodeList = DependencyManager::get(); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_AMBIENT_LIGHT_INTENSITY, AmbientLight, ambientLight, AmbientIntensity, ambientIntensity); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_AMBIENT_LIGHT_URL, AmbientLight, ambientLight, AmbientURL, ambientURL); -} - -void AmbientLightPropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) { - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ambientLight, ambientIntensity, float, setAmbientIntensity); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ambientLight, ambientURL, QString, setAmbientURL); - - // legacy property support - COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(ambientLightAmbientIntensity, float, setAmbientIntensity, getAmbientIntensity); -} - -void AmbientLightPropertyGroup::merge(const AmbientLightPropertyGroup& other) { - COPY_PROPERTY_IF_CHANGED(ambientIntensity); - COPY_PROPERTY_IF_CHANGED(ambientURL); -} - -void AmbientLightPropertyGroup::debugDump() const { - qCDebug(entities) << " AmbientLightPropertyGroup: ---------------------------------------------"; - qCDebug(entities) << " ambientIntensity:" << getAmbientIntensity(); -} - -void AmbientLightPropertyGroup::listChangedProperties(QList& out) { - if (ambientIntensityChanged()) { - out << "ambientLight-ambientIntensity"; - } - if (ambientURLChanged()) { - out << "ambientLight-ambientURL"; - } -} - -bool AmbientLightPropertyGroup::appendToEditPacket(OctreePacketData* packetData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const { - - bool successPropertyFits = true; - - APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_INTENSITY, getAmbientIntensity()); - APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_URL, getAmbientURL()); - - return true; -} - -bool AmbientLightPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt, - int& processedBytes) { - - int bytesRead = 0; - bool overwriteLocalData = true; - bool somethingChanged = false; - - READ_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_INTENSITY, float, setAmbientIntensity); - READ_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_URL, QString, setAmbientURL); - - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_AMBIENT_LIGHT_INTENSITY, AmbientIntensity); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_AMBIENT_LIGHT_URL, AmbientURL); - - processedBytes += bytesRead; - - Q_UNUSED(somethingChanged); - - return true; -} - -void AmbientLightPropertyGroup::markAllChanged() { - _ambientIntensityChanged = true; - _ambientURLChanged = true; -} - -EntityPropertyFlags AmbientLightPropertyGroup::getChangedProperties() const { - EntityPropertyFlags changedProperties; - - CHECK_PROPERTY_CHANGE(PROP_AMBIENT_LIGHT_INTENSITY, ambientIntensity); - CHECK_PROPERTY_CHANGE(PROP_AMBIENT_LIGHT_URL, ambientURL); - - return changedProperties; -} - -void AmbientLightPropertyGroup::getProperties(EntityItemProperties& properties) const { - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(AmbientLight, AmbientIntensity, getAmbientIntensity); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(AmbientLight, AmbientURL, getAmbientURL); -} - -bool AmbientLightPropertyGroup::setProperties(const EntityItemProperties& properties) { - bool somethingChanged = false; - - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(AmbientLight, AmbientIntensity, ambientIntensity, setAmbientIntensity); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(AmbientLight, AmbientURL, ambientURL, setAmbientURL); - - return somethingChanged; -} - -EntityPropertyFlags AmbientLightPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { - EntityPropertyFlags requestedProperties; - - requestedProperties += PROP_AMBIENT_LIGHT_INTENSITY; - requestedProperties += PROP_AMBIENT_LIGHT_URL; - - return requestedProperties; -} - -void AmbientLightPropertyGroup::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_AMBIENT_LIGHT_INTENSITY, getAmbientIntensity()); - APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_URL, getAmbientURL()); -} - -int AmbientLightPropertyGroup::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_AMBIENT_LIGHT_INTENSITY, float, setAmbientIntensity); - READ_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_URL, QString, setAmbientURL); - - return bytesRead; -} diff --git a/libraries/entities/src/AmbientLightPropertyGroup.cpp.in b/libraries/entities/src/AmbientLightPropertyGroup.cpp.in new file mode 100644 index 00000000000..374459a937e --- /dev/null +++ b/libraries/entities/src/AmbientLightPropertyGroup.cpp.in @@ -0,0 +1,139 @@ +// +// AmbientLightPropertyGroup.cpp +// libraries/entities/src +// +// Created by Nissim Hadar on 2017/12/24. +// Copyright 2013 High Fidelity, Inc. +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#include "AmbientLightPropertyGroup.h" + +#include + +#include "EntityItemProperties.h" + +const float AmbientLightPropertyGroup::DEFAULT_AMBIENT_LIGHT_INTENSITY = 0.5f; +const glm::u8vec3 AmbientLightPropertyGroup::DEFAULT_COLOR = { 0, 0, 0 }; + +void AmbientLightPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, + bool skipDefaults, EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, bool isMyOwnAvatarEntity) const { + + auto nodeList = DependencyManager::get(); + +@AmbientLight_GROUP_COPY_TO_SCRIPT@ + +} + +void AmbientLightPropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) { + +@AmbientLight_GROUP_COPY_FROM_SCRIPT@ + +} + +void AmbientLightPropertyGroup::merge(const AmbientLightPropertyGroup& other) { + +@AmbientLight_GROUP_MERGE@ + +} + +void AmbientLightPropertyGroup::debugDump() const { + +@AmbientLight_GROUP_DEBUG_DUMP@ + +} + +void AmbientLightPropertyGroup::listChangedProperties(QList& out) { + +@AmbientLight_GROUP_LIST_CHANGED@ + +} + +bool AmbientLightPropertyGroup::appendToEditPacket(OctreePacketData* packetData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@AmbientLight_GROUP_APPEND@ + + return successPropertyFits; +} + +bool AmbientLightPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) { + + int bytesRead = 0; + bool overwriteLocalData = true; + bool somethingChanged = false; + +@AmbientLight_GROUP_READ@ + +@AmbientLight_GROUP_DECODE_CHANGED@ + + processedBytes += bytesRead; + + return somethingChanged; +} + +void AmbientLightPropertyGroup::markAllChanged() { + +@AmbientLight_GROUP_MARK_CHANGED@ + +} + +EntityPropertyFlags AmbientLightPropertyGroup::getChangedProperties() const { + EntityPropertyFlags changedProperties; + +@AmbientLight_GROUP_CHANGED_PROPERTIES@ + + return changedProperties; +} + +void AmbientLightPropertyGroup::getProperties(EntityItemProperties& properties) const { + +@AmbientLight_GROUP_COPY_TO@ + +} + +bool AmbientLightPropertyGroup::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + +@AmbientLight_GROUP_SET_FROM@ + + return somethingChanged; +} + +EntityPropertyFlags AmbientLightPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties; + +@AmbientLight_REQUESTED_PROPS@ + + return requestedProperties; +} + +int AmbientLightPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + +@AmbientLight_GROUP_READ@ + + return bytesRead; +} + +void AmbientLightPropertyGroup::addPropertyMap(QHash& _propertyInfos, + QHash& _enumsToPropertyStrings) { + +@AmbientLight_GROUP_ADD_TO_MAP@ + +} diff --git a/libraries/entities/src/AmbientLightPropertyGroup.h b/libraries/entities/src/AmbientLightPropertyGroup.h deleted file mode 100644 index 67597d17137..00000000000 --- a/libraries/entities/src/AmbientLightPropertyGroup.h +++ /dev/null @@ -1,95 +0,0 @@ -// -// AmbientLightPropertyGroup.h -// libraries/entities/src -// -// Created by Nissim Hadar on 2017/12/24. -// Copyright 2013 High Fidelity, Inc. -// Copyright 2023 Overte e.V. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// SPDX-License-Identifier: Apache-2.0 -// - - -#ifndef hifi_AmbientLightPropertyGroup_h -#define hifi_AmbientLightPropertyGroup_h - -#include - -#include - -#include "EntityItemPropertiesMacros.h" -#include "PropertyGroup.h" - -class EntityItemProperties; -class EncodeBitstreamParams; -class OctreePacketData; -class EntityTreeElementExtraEncodeData; -class ReadBitstreamToTreeParams; -class ScriptEngine; -class ScriptValue; - -/*@jsdoc - * Ambient light is defined by the following properties: - * @typedef {object} Entities.AmbientLight - * @property {number} ambientIntensity=0.5 - The intensity of the light. - * @property {string} ambientURL="" - A cube map image that defines the color of the light coming from each direction. If - * "" then the entity's {@link Entities.Skybox|Skybox} url property value is used, unless that also is "" in which - * case the entity's ambientLightMode property is set to "inherit". - */ -class AmbientLightPropertyGroup : public PropertyGroup { -public: - // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, - ScriptEngine* engine, bool skipDefaults, - EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, - bool isMyOwnAvatarEntity) const override; - virtual void copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) override; - - void merge(const AmbientLightPropertyGroup& other); - - virtual void debugDump() const override; - virtual void listChangedProperties(QList& 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; - - static const float DEFAULT_AMBIENT_LIGHT_INTENSITY; - - DEFINE_PROPERTY(PROP_AMBIENT_LIGHT_INTENSITY, AmbientIntensity, ambientIntensity, float, DEFAULT_AMBIENT_LIGHT_INTENSITY); - DEFINE_PROPERTY_REF(PROP_AMBIENT_LIGHT_URL, AmbientURL, ambientURL, QString, ""); -}; - -#endif // hifi_AmbientLightPropertyGroup_h diff --git a/libraries/entities/src/AmbientLightPropertyGroup.h.in b/libraries/entities/src/AmbientLightPropertyGroup.h.in new file mode 100644 index 00000000000..9d2af7c4fab --- /dev/null +++ b/libraries/entities/src/AmbientLightPropertyGroup.h.in @@ -0,0 +1,56 @@ +// +// AmbientLightPropertyGroup.h +// libraries/entities/src +// +// Created by Nissim Hadar on 2017/12/24. +// Copyright 2013 High Fidelity, Inc. +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + + +#ifndef hifi_AmbientLightPropertyGroup_h +#define hifi_AmbientLightPropertyGroup_h + +#include + +#include + +#include "EntityItemPropertiesMacros.h" +#include "PropertyGroup.h" + +class EntityItemProperties; +class EncodeBitstreamParams; +class OctreePacketData; +class EntityTreeElementExtraEncodeData; +class ReadBitstreamToTreeParams; +class ScriptEngine; +class ScriptValue; + +/*@jsdoc + * Ambient light is defined by the following properties: + * @typedef {object} Entities.AmbientLight + * @property {number} ambientIntensity=0.5 - The intensity of the light. + * @property {string} ambientURL="" - A cube map image that defines the color of the light coming from each direction. If + * "" then the entity's {@link Entities.Skybox|Skybox} url property value is used, unless that also is "" in which + * case the entity's ambientLightMode property is set to "inherit". + * @property {Color} ambientColor=0,0,0 - Sets the color of the ambient light if ambientURL is "", otherwise modifies the + * color of the cube map image. + */ +class AmbientLightPropertyGroup : public PropertyGroup { +public: + ENTITY_PROPERTY_GROUP_METHODS(AmbientLightPropertyGroup) + + static const float DEFAULT_AMBIENT_LIGHT_INTENSITY; + static const glm::u8vec3 DEFAULT_COLOR; + +protected: + +@AmbientLight_GROUP_PROPS@ + +}; + +#endif // hifi_AmbientLightPropertyGroup_h diff --git a/libraries/entities/src/AmbientOcclusionPropertyGroup.cpp.in b/libraries/entities/src/AmbientOcclusionPropertyGroup.cpp.in new file mode 100644 index 00000000000..31e03e15946 --- /dev/null +++ b/libraries/entities/src/AmbientOcclusionPropertyGroup.cpp.in @@ -0,0 +1,149 @@ +// +// AmbientOcclusionPropertyGroup.cpp +// libraries/entities/src +// +// Created by HifiExperiments on 6/23/24 +// Copyright 2024 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#include "AmbientOcclusionPropertyGroup.h" + +#include + +#include "EntityItemProperties.h" + +inline void addAmbientOcclusionTechnique(QHash& lookup, AmbientOcclusionTechnique technique) { lookup[AmbientOcclusionTechniqueHelpers::getNameForAmbientOcclusionTechnique(technique)] = technique; } +const QHash stringToAmbientOcclusionTechniqueLookup = [] { + QHash toReturn; + addAmbientOcclusionTechnique(toReturn, AmbientOcclusionTechnique::SSAO); + addAmbientOcclusionTechnique(toReturn, AmbientOcclusionTechnique::HBAO); + return toReturn; +}(); +QString AmbientOcclusionPropertyGroup::getTechniqueAsString() const { return AmbientOcclusionTechniqueHelpers::getNameForAmbientOcclusionTechnique(_technique); } +void AmbientOcclusionPropertyGroup::setTechniqueFromString(const QString& technique) { + auto techniqueItr = stringToAmbientOcclusionTechniqueLookup.find(technique.toLower()); + if (techniqueItr != stringToAmbientOcclusionTechniqueLookup.end()) { + _technique = techniqueItr.value(); + _techniqueChanged = true; + } +} + +void AmbientOcclusionPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, + bool skipDefaults, EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, bool isMyOwnAvatarEntity) const { + +@AmbientOcclusion_GROUP_COPY_TO_SCRIPT@ + +} + +void AmbientOcclusionPropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) { + +@AmbientOcclusion_GROUP_COPY_FROM_SCRIPT@ + +} + +void AmbientOcclusionPropertyGroup::merge(const AmbientOcclusionPropertyGroup& other) { + +@AmbientOcclusion_GROUP_MERGE@ + +} + +void AmbientOcclusionPropertyGroup::debugDump() const { + +@AmbientOcclusion_GROUP_DEBUG_DUMP@ + +} + +void AmbientOcclusionPropertyGroup::listChangedProperties(QList& out) { + +@AmbientOcclusion_GROUP_LIST_CHANGED@ + +} + +bool AmbientOcclusionPropertyGroup::appendToEditPacket(OctreePacketData* packetData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@AmbientOcclusion_GROUP_APPEND@ + + return successPropertyFits; +} + +bool AmbientOcclusionPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) { + + int bytesRead = 0; + bool overwriteLocalData = true; + bool somethingChanged = false; + +@AmbientOcclusion_GROUP_READ@ + +@AmbientOcclusion_GROUP_DECODE_CHANGED@ + + processedBytes += bytesRead; + + return somethingChanged; +} + +void AmbientOcclusionPropertyGroup::markAllChanged() { + +@AmbientOcclusion_GROUP_MARK_CHANGED@ + +} + +EntityPropertyFlags AmbientOcclusionPropertyGroup::getChangedProperties() const { + EntityPropertyFlags changedProperties; + +@AmbientOcclusion_GROUP_CHANGED_PROPERTIES@ + + return changedProperties; +} + +void AmbientOcclusionPropertyGroup::getProperties(EntityItemProperties& properties) const { + +@AmbientOcclusion_GROUP_COPY_TO@ + +} + +bool AmbientOcclusionPropertyGroup::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + +@AmbientOcclusion_GROUP_SET_FROM@ + + return somethingChanged; +} + +EntityPropertyFlags AmbientOcclusionPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties; + +@AmbientOcclusion_REQUESTED_PROPS@ + + return requestedProperties; +} + +int AmbientOcclusionPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + +@AmbientOcclusion_GROUP_READ@ + + return bytesRead; +} + +void AmbientOcclusionPropertyGroup::addPropertyMap(QHash& _propertyInfos, + QHash& _enumsToPropertyStrings) { + +@AmbientOcclusion_GROUP_ADD_TO_MAP@ + +} diff --git a/libraries/entities/src/AmbientOcclusionPropertyGroup.h.in b/libraries/entities/src/AmbientOcclusionPropertyGroup.h.in new file mode 100644 index 00000000000..27ca160fba6 --- /dev/null +++ b/libraries/entities/src/AmbientOcclusionPropertyGroup.h.in @@ -0,0 +1,58 @@ +// +// AmbientOcclusionPropertyGroup.h +// libraries/entities/src +// +// Created by HifiExperiments on 6/23/24 +// Copyright 2024 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef hifi_AmbientOcclusionPropertyGroup_h +#define hifi_AmbientOcclusionPropertyGroup_h + +#include + +#include "PropertyGroup.h" +#include "EntityItemPropertiesMacros.h" + +class EntityItemProperties; +class EncodeBitstreamParams; +class OctreePacketData; +class EntityTreeElementExtraEncodeData; +class ReadBitstreamToTreeParams; +class ScriptEngine; +class ScriptValue; + +/*@jsdoc + * AmbientOcclusion is defined by the following properties: + * @typedef {object} Entities.AmbientOcclusion + * @property {AmbientOcclusionTechnique} technique="ssao" - The ambient occlusion technique used. Different techniques have + * different tradeoffs. + * @property {boolean} jitter=false - Whether or not the ambient occlusion sampling is jittered. + * @property {number} resolutionLevel=2 - How high the resolution of the ambient occlusion buffer should be. Higher levels + * mean lower resolution buffers. + * @property {number} edgeSharpness=1.0 - How much to sharpen the edges during the ambient occlusion blurring. + * @property {number} blurRadius=4 - The radius used for blurring, in pixels. + * @property {number} aoRadius=1.0 - The radius used for ambient occlusion. + * @property {number} aoObscuranceLevel=0.5 - Intensify or dim ambient occlusion. + * @property {number} aoFalloffAngle=0.25 - The falloff angle for the AO calculation. + * @property {number} aoSamplingAmount=0.5 - The fraction of AO samples to use, out of the maximum for each technique. + * @property {number} ssaoNumSpiralTurns=7.0 - The angle span used to distribute the AO samples ray directions. SSAO only. + */ + +class AmbientOcclusionPropertyGroup : public PropertyGroup { +public: + ENTITY_PROPERTY_GROUP_METHODS(AmbientOcclusionPropertyGroup) + +protected: + + // FIXME: On some machines, SSAO seems to be causing performance problems. Let's default to HBAO for now and maybe + // revisit when we have Vulkan +@AmbientOcclusion_GROUP_PROPS@ + +}; + +#endif // hifi_AmbientOcclusionPropertyGroup_h diff --git a/libraries/entities/src/AnimationPropertyGroup.cpp b/libraries/entities/src/AnimationPropertyGroup.cpp deleted file mode 100644 index c1da24b170a..00000000000 --- a/libraries/entities/src/AnimationPropertyGroup.cpp +++ /dev/null @@ -1,405 +0,0 @@ -// -// AnimationPropertyGroup.cpp -// libraries/entities/src -// -// Created by Brad Hefta-Gaub on 12/4/13. -// Copyright 2013 High Fidelity, Inc. -// Copyright 2023 Overte e.V. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// SPDX-License-Identifier: Apache-2.0 -// - -#include "AnimationPropertyGroup.h" - -#include -#include - - -#include "EntityItemProperties.h" -#include "EntityItemPropertiesMacros.h" - -const float AnimationPropertyGroup::MAXIMUM_POSSIBLE_FRAME = 100000.0f; - -bool operator==(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b) { - return - (a._currentFrame == b._currentFrame) && - (a._running == b._running) && - (a._loop == b._loop) && - (a._hold == b._hold) && - (a._firstFrame == b._firstFrame) && - (a._lastFrame == b._lastFrame) && - (a._fps == b._fps) && - (a._allowTranslation == b._allowTranslation) && - (a._url == b._url); -} - -bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b) { - return - (a._currentFrame != b._currentFrame) || - (a._running != b._running) || - (a._loop != b._loop) || - (a._hold != b._hold) || - (a._firstFrame != b._firstFrame) || - (a._lastFrame != b._lastFrame) || - (a._fps != b._fps) || - (a._allowTranslation != b._allowTranslation) || - (a._url != b._url); -} - - -/*@jsdoc - * An animation is configured by the following properties: - * @typedef {object} Entities.AnimationProperties - * @property {string} url="" - The URL of the glTF or FBX file that has the animation. glTF files may be in JSON or binary - * format (".gltf" or ".glb" URLs respectively). - *

Warning: glTF animations currently do not always animate correctly.

- * @property {boolean} allowTranslation=true - true to enable translations contained in the animation to be - * played, false to disable translations. - * @property {number} fps=30 - The speed in frames/s that the animation is played at. - * @property {number} firstFrame=0 - The first frame to play in the animation. - * @property {number} lastFrame=100000 - The last frame to play in the animation. - * @property {number} currentFrame=0 - The current frame being played in the animation. - * @property {boolean} running=false - true if the animation should play, false if it shouldn't. - * @property {boolean} loop=true - true if the animation is continuously repeated in a loop, false if - * it isn't. - * @property {boolean} hold=false - true if the rotations and translations of the last frame played are - * maintained when the animation stops playing, false if they aren't. - */ -void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, - bool skipDefaults, EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, - bool isMyOwnAvatarEntity) const { - auto nodeList = DependencyManager::get(); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_ANIMATION_URL, Animation, animation, URL, url); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_ALLOW_TRANSLATION, Animation, animation, AllowTranslation, allowTranslation); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FPS, Animation, animation, FPS, fps); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FRAME_INDEX, Animation, animation, CurrentFrame, currentFrame); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_PLAYING, Animation, animation, Running, running); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_LOOP, Animation, animation, Loop, loop); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_FIRST_FRAME, Animation, animation, FirstFrame, firstFrame); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_LAST_FRAME, Animation, animation, LastFrame, lastFrame); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_HOLD, Animation, animation, Hold, hold); -} - - -void AnimationPropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) { - - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, url, QString, setURL); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, allowTranslation, bool, setAllowTranslation); - - // legacy property support - COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(animationURL, QString, setURL, getURL); - COPY_PROPERTY_FROM_QSCRIPTVALUE_NOCHECK(animationSettings, QString, setFromOldAnimationSettings); - - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, fps, float, setFPS); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, currentFrame, float, setCurrentFrame); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, running, bool, setRunning); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, loop, bool, setLoop); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, firstFrame, float, setFirstFrame); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, lastFrame, float, setLastFrame); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(animation, hold, bool, setHold); - - // legacy property support - COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(animationFPS, float, setFPS, getFPS); - COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(animationIsPlaying, bool, setRunning, getRunning); - COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(animationFrameIndex, float, setCurrentFrame, getCurrentFrame); -} - -void AnimationPropertyGroup::merge(const AnimationPropertyGroup& other) { - COPY_PROPERTY_IF_CHANGED(url); - COPY_PROPERTY_IF_CHANGED(allowTranslation); - COPY_PROPERTY_IF_CHANGED(fps); - COPY_PROPERTY_IF_CHANGED(currentFrame); - COPY_PROPERTY_IF_CHANGED(running); - COPY_PROPERTY_IF_CHANGED(loop); - COPY_PROPERTY_IF_CHANGED(firstFrame); - COPY_PROPERTY_IF_CHANGED(lastFrame); - COPY_PROPERTY_IF_CHANGED(hold); -} - -void AnimationPropertyGroup::setFromOldAnimationSettings(const QString& value) { - // the animations setting is a JSON string that may contain various animation settings. - // if it includes fps, currentFrame, or running, those values will be parsed out and - // will over ride the regular animation settings - - float fps = getFPS(); - float currentFrame = getCurrentFrame(); - bool running = getRunning(); - float firstFrame = getFirstFrame(); - float lastFrame = getLastFrame(); - bool loop = getLoop(); - bool hold = getHold(); - bool allowTranslation = getAllowTranslation(); - - QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8()); - QJsonObject settingsAsJsonObject = settingsAsJson.object(); - QVariantMap settingsMap = settingsAsJsonObject.toVariantMap(); - - if (settingsMap.contains("fps")) { - fps = settingsMap["fps"].toFloat(); - } - - // old settings had frameIndex - if (settingsMap.contains("frameIndex")) { - currentFrame = settingsMap["frameIndex"].toFloat(); - } - - if (settingsMap.contains("running")) { - running = settingsMap["running"].toBool(); - } - - if (settingsMap.contains("firstFrame")) { - firstFrame = settingsMap["firstFrame"].toFloat(); - } - - if (settingsMap.contains("lastFrame")) { - lastFrame = settingsMap["lastFrame"].toFloat(); - } - - if (settingsMap.contains("loop")) { - running = settingsMap["loop"].toBool(); - } - - if (settingsMap.contains("hold")) { - running = settingsMap["hold"].toBool(); - } - - if (settingsMap.contains("allowTranslation")) { - allowTranslation = settingsMap["allowTranslation"].toBool(); - } - - - setAllowTranslation(allowTranslation); - setFPS(fps); - setCurrentFrame(currentFrame); - setRunning(running); - setFirstFrame(firstFrame); - setLastFrame(lastFrame); - setLoop(loop); - setHold(hold); -} - - -void AnimationPropertyGroup::debugDump() const { - qCDebug(entities) << " AnimationPropertyGroup: ---------------------------------------------"; - qCDebug(entities) << " fps:" << getFPS() << " has changed:" << fpsChanged(); - qCDebug(entities) << "currentFrame:" << getCurrentFrame() << " has changed:" << currentFrameChanged(); - qCDebug(entities) << "allowTranslation:" << getAllowTranslation() << " has changed:" << allowTranslationChanged(); -} - -void AnimationPropertyGroup::listChangedProperties(QList& out) { - if (urlChanged()) { - out << "animation-url"; - } - if (allowTranslationChanged()) { - out << "animation-allowTranslation"; - } - if (fpsChanged()) { - out << "animation-fps"; - } - if (currentFrameChanged()) { - out << "animation-currentFrame"; - } - if (runningChanged()) { - out << "animation-running"; - } - if (loopChanged()) { - out << "animation-loop"; - } - if (firstFrameChanged()) { - out << "animation-firstFrame"; - } - if (lastFrameChanged()) { - out << "animation-lastFrame"; - } - if (holdChanged()) { - out << "animation-hold"; - } -} - - -bool AnimationPropertyGroup::appendToEditPacket(OctreePacketData* packetData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const { - - bool successPropertyFits = true; - - APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, getURL()); - APPEND_ENTITY_PROPERTY(PROP_ANIMATION_ALLOW_TRANSLATION, getAllowTranslation()); - APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, getFPS()); - APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, getCurrentFrame()); - APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, getRunning()); - APPEND_ENTITY_PROPERTY(PROP_ANIMATION_LOOP, getLoop()); - APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, getFirstFrame()); - APPEND_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, getLastFrame()); - APPEND_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, getHold()); - - return true; -} - - -bool AnimationPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) { - int bytesRead = 0; - bool overwriteLocalData = true; - bool somethingChanged = false; - - READ_ENTITY_PROPERTY(PROP_ANIMATION_URL, QString, setURL); - READ_ENTITY_PROPERTY(PROP_ANIMATION_ALLOW_TRANSLATION, bool, setAllowTranslation); - READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, setFPS); - READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, setCurrentFrame); - READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, setRunning); - READ_ENTITY_PROPERTY(PROP_ANIMATION_LOOP, bool, setLoop); - READ_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, float, setFirstFrame); - READ_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, float, setLastFrame); - READ_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, bool, setHold); - - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_URL, URL); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_ALLOW_TRANSLATION, AllowTranslation); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_FPS, FPS); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_FRAME_INDEX, CurrentFrame); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_PLAYING, Running); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_LOOP, Loop); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_FIRST_FRAME, FirstFrame); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_LAST_FRAME, LastFrame); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_ANIMATION_HOLD, Hold); - - processedBytes += bytesRead; - - Q_UNUSED(somethingChanged); - - return true; -} - -void AnimationPropertyGroup::markAllChanged() { - _urlChanged = true; - _allowTranslationChanged = true; - _fpsChanged = true; - _currentFrameChanged = true; - _runningChanged = true; - _loopChanged = true; - _firstFrameChanged = true; - _lastFrameChanged = true; - _holdChanged = true; -} - -EntityPropertyFlags AnimationPropertyGroup::getChangedProperties() const { - EntityPropertyFlags changedProperties; - - CHECK_PROPERTY_CHANGE(PROP_ANIMATION_URL, url); - CHECK_PROPERTY_CHANGE(PROP_ANIMATION_ALLOW_TRANSLATION, allowTranslation); - CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FPS, fps); - CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FRAME_INDEX, currentFrame); - CHECK_PROPERTY_CHANGE(PROP_ANIMATION_PLAYING, running); - CHECK_PROPERTY_CHANGE(PROP_ANIMATION_LOOP, loop); - CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FIRST_FRAME, firstFrame); - CHECK_PROPERTY_CHANGE(PROP_ANIMATION_LAST_FRAME, lastFrame); - CHECK_PROPERTY_CHANGE(PROP_ANIMATION_HOLD, hold); - - return changedProperties; -} - -void AnimationPropertyGroup::getProperties(EntityItemProperties& properties) const { - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, URL, getURL); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, AllowTranslation, getAllowTranslation); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, FPS, getFPS); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, CurrentFrame, getCurrentFrame); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, Running, getRunning); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, Loop, getLoop); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, FirstFrame, getFirstFrame); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, LastFrame, getLastFrame); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Animation, Hold, getHold); -} - -bool AnimationPropertyGroup::setProperties(const EntityItemProperties& properties) { - bool somethingChanged = false; - - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, URL, url, setURL); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, AllowTranslation, allowTranslation, setAllowTranslation); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, FPS, fps, setFPS); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, CurrentFrame, currentFrame, setCurrentFrame); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, Running, running, setRunning); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, Loop, loop, setLoop); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, FirstFrame, firstFrame, setFirstFrame); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, LastFrame, lastFrame, setLastFrame); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Animation, Hold, hold, setHold); - return somethingChanged; -} - -EntityPropertyFlags AnimationPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { - EntityPropertyFlags requestedProperties; - - requestedProperties += PROP_ANIMATION_URL; - requestedProperties += PROP_ANIMATION_ALLOW_TRANSLATION; - requestedProperties += PROP_ANIMATION_FPS; - requestedProperties += PROP_ANIMATION_FRAME_INDEX; - requestedProperties += PROP_ANIMATION_PLAYING; - requestedProperties += PROP_ANIMATION_LOOP; - requestedProperties += PROP_ANIMATION_FIRST_FRAME; - requestedProperties += PROP_ANIMATION_LAST_FRAME; - requestedProperties += PROP_ANIMATION_HOLD; - - return requestedProperties; -} - -void AnimationPropertyGroup::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_ANIMATION_URL, getURL()); - APPEND_ENTITY_PROPERTY(PROP_ANIMATION_ALLOW_TRANSLATION, getAllowTranslation()); - APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, getFPS()); - APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, getCurrentFrame()); - APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, getRunning()); - APPEND_ENTITY_PROPERTY(PROP_ANIMATION_LOOP, getLoop()); - APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, getFirstFrame()); - APPEND_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, getLastFrame()); - APPEND_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, getHold()); -} - -int AnimationPropertyGroup::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_ANIMATION_URL, QString, setURL); - READ_ENTITY_PROPERTY(PROP_ANIMATION_ALLOW_TRANSLATION, bool, setAllowTranslation); - READ_ENTITY_PROPERTY(PROP_ANIMATION_FPS, float, setFPS); - READ_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, float, setCurrentFrame); - READ_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, bool, setRunning); - READ_ENTITY_PROPERTY(PROP_ANIMATION_LOOP, bool, setLoop); - READ_ENTITY_PROPERTY(PROP_ANIMATION_FIRST_FRAME, float, setFirstFrame); - READ_ENTITY_PROPERTY(PROP_ANIMATION_LAST_FRAME, float, setLastFrame); - READ_ENTITY_PROPERTY(PROP_ANIMATION_HOLD, bool, setHold); - return bytesRead; -} - -float AnimationPropertyGroup::getNumFrames() const { - return _lastFrame - _firstFrame + 1.0f; -} - -float AnimationPropertyGroup::computeLoopedFrame(float frame) const { - float numFrames = getNumFrames(); - if (numFrames > 1.0f) { - frame = getFirstFrame() + fmodf(frame - getFirstFrame(), numFrames); - } else { - frame = getFirstFrame(); - } - return frame; -} - -bool AnimationPropertyGroup::isValidAndRunning() const { - return getRunning() && (getFPS() > 0.0f) && (getNumFrames() > 1.0f) && !(getURL().isEmpty()); -} diff --git a/libraries/entities/src/AnimationPropertyGroup.cpp.in b/libraries/entities/src/AnimationPropertyGroup.cpp.in new file mode 100644 index 00000000000..1c71360d74e --- /dev/null +++ b/libraries/entities/src/AnimationPropertyGroup.cpp.in @@ -0,0 +1,261 @@ +// +// AnimationPropertyGroup.cpp +// libraries/entities/src +// +// Created by Brad Hefta-Gaub on 12/4/13. +// Copyright 2013 High Fidelity, Inc. +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#include "AnimationPropertyGroup.h" + +#include +#include + +#include "EntityItemProperties.h" + +const float AnimationPropertyGroup::MAXIMUM_POSSIBLE_FRAME = 100000.0f; + +bool operator==(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b) { + return + (a._currentFrame == b._currentFrame) && + (a._running == b._running) && + (a._loop == b._loop) && + (a._hold == b._hold) && + (a._firstFrame == b._firstFrame) && + (a._lastFrame == b._lastFrame) && + (a._fps == b._fps) && + (a._allowTranslation == b._allowTranslation) && + (a._url == b._url) && + (a._smoothFrames == b._smoothFrames); +} + + +/*@jsdoc + * An animation is configured by the following properties: + * @typedef {object} Entities.AnimationProperties + * @property {string} url="" - The URL of the glTF or FBX file that has the animation. glTF files may be in JSON or binary + * format (".gltf" or ".glb" URLs respectively). + *

Warning: glTF animations currently do not always animate correctly.

+ * @property {boolean} allowTranslation=true - true to enable translations contained in the animation to be + * played, false to disable translations. + * @property {number} fps=30 - The speed in frames/s that the animation is played at. + * @property {number} firstFrame=0 - The first frame to play in the animation. + * @property {number} lastFrame=100000 - The last frame to play in the animation. + * @property {number} currentFrame=0 - The current frame being played in the animation. + * @property {boolean} running=false - true if the animation should play, false if it shouldn't. + * @property {boolean} loop=true - true if the animation is continuously repeated in a loop, false if + * it isn't. + * @property {boolean} hold=false - true if the rotations and translations of the last frame played are + * maintained when the animation stops playing, false if they aren't. + * @property {boolean} smoothFrames=true - true if the frames of the animation should be linearly interpolated to + * create smoother movement, false if the frames should not be interpolated. + */ + +void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, + bool skipDefaults, EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, bool isMyOwnAvatarEntity) const { + + auto nodeList = DependencyManager::get(); + +@Animation_GROUP_COPY_TO_SCRIPT@ + +} + +void AnimationPropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) { + +@Animation_GROUP_COPY_FROM_SCRIPT@ + + // legacy property support + COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(animationURL, QString, setUrl, getUrl); + COPY_PROPERTY_FROM_QSCRIPTVALUE_NOCHECK(animationSettings, QString, setFromOldAnimationSettings); + COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(animationFPS, float, setFps, getFps); + COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(animationIsPlaying, bool, setRunning, getRunning); + COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(animationFrameIndex, float, setCurrentFrame, getCurrentFrame); + +} + +void AnimationPropertyGroup::merge(const AnimationPropertyGroup& other) { + +@Animation_GROUP_MERGE@ + +} + +void AnimationPropertyGroup::debugDump() const { + +@Animation_GROUP_DEBUG_DUMP@ + +} + +void AnimationPropertyGroup::listChangedProperties(QList& out) { + +@Animation_GROUP_LIST_CHANGED@ + +} + +bool AnimationPropertyGroup::appendToEditPacket(OctreePacketData* packetData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@Animation_GROUP_APPEND@ + + return successPropertyFits; +} + +bool AnimationPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) { + + int bytesRead = 0; + bool overwriteLocalData = true; + bool somethingChanged = false; + +@Animation_GROUP_READ@ + +@Animation_GROUP_DECODE_CHANGED@ + + processedBytes += bytesRead; + + return somethingChanged; +} + +void AnimationPropertyGroup::markAllChanged() { + +@Animation_GROUP_MARK_CHANGED@ + +} + +EntityPropertyFlags AnimationPropertyGroup::getChangedProperties() const { + EntityPropertyFlags changedProperties; + +@Animation_GROUP_CHANGED_PROPERTIES@ + + return changedProperties; +} + +void AnimationPropertyGroup::getProperties(EntityItemProperties& properties) const { + +@Animation_GROUP_COPY_TO@ + +} + +bool AnimationPropertyGroup::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + +@Animation_GROUP_SET_FROM@ + + return somethingChanged; +} + +EntityPropertyFlags AnimationPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties; + +@Animation_REQUESTED_PROPS@ + + return requestedProperties; +} + +int AnimationPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + +@Animation_GROUP_READ@ + + return bytesRead; +} + +void AnimationPropertyGroup::addPropertyMap(QHash& _propertyInfos, + QHash& _enumsToPropertyStrings) { + +@Animation_GROUP_ADD_TO_MAP@ + +} + +void AnimationPropertyGroup::setFromOldAnimationSettings(const QString& value) { + // the animations setting is a JSON string that may contain various animation settings. + // if it includes fps, currentFrame, or running, those values will be parsed out and + // will over ride the regular animation settings + + bool allowTranslation = getAllowTranslation(); + float fps = getFps(); + float currentFrame = getCurrentFrame(); + bool running = getRunning(); + bool loop = getLoop(); + float firstFrame = getFirstFrame(); + float lastFrame = getLastFrame(); + bool hold = getHold(); + + QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8()); + QJsonObject settingsAsJsonObject = settingsAsJson.object(); + QVariantMap settingsMap = settingsAsJsonObject.toVariantMap(); + + if (settingsMap.contains("allowTranslation")) { + allowTranslation = settingsMap["allowTranslation"].toBool(); + } + + if (settingsMap.contains("fps")) { + fps = settingsMap["fps"].toFloat(); + } + + // old settings had frameIndex + if (settingsMap.contains("frameIndex")) { + currentFrame = settingsMap["frameIndex"].toFloat(); + } + + if (settingsMap.contains("running")) { + running = settingsMap["running"].toBool(); + } + + if (settingsMap.contains("firstFrame")) { + firstFrame = settingsMap["firstFrame"].toFloat(); + } + + if (settingsMap.contains("loop")) { + loop = settingsMap["loop"].toBool(); + } + + if (settingsMap.contains("lastFrame")) { + lastFrame = settingsMap["lastFrame"].toFloat(); + } + + if (settingsMap.contains("hold")) { + hold = settingsMap["hold"].toBool(); + } + + setAllowTranslation(allowTranslation); + setFps(fps); + setCurrentFrame(currentFrame); + setRunning(running); + setLoop(loop); + setFirstFrame(firstFrame); + setLastFrame(lastFrame); + setHold(hold); +} + +float AnimationPropertyGroup::getNumFrames() const { + return _lastFrame - _firstFrame + 1.0f; +} + +float AnimationPropertyGroup::computeLoopedFrame(float frame) const { + float numFrames = getNumFrames(); + if (numFrames > 1.0f) { + frame = getFirstFrame() + fmodf(frame - getFirstFrame(), numFrames); + } else { + frame = getFirstFrame(); + } + return frame; +} + +bool AnimationPropertyGroup::isValidAndRunning() const { + return getRunning() && (getFps() > 0.0f) && (getNumFrames() > 1.0f) && !(getUrl().isEmpty()); +} diff --git a/libraries/entities/src/AnimationPropertyGroup.h b/libraries/entities/src/AnimationPropertyGroup.h deleted file mode 100644 index 69073af0655..00000000000 --- a/libraries/entities/src/AnimationPropertyGroup.h +++ /dev/null @@ -1,103 +0,0 @@ -// -// AnimationPropertyGroup.h -// libraries/entities/src -// -// Created by Brad Hefta-Gaub on 2015/9/30. -// Copyright 2013 High Fidelity, Inc. -// Copyright 2023 Overte e.V. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// SPDX-License-Identifier: Apache-2.0 -// - - -#ifndef hifi_AnimationPropertyGroup_h -#define hifi_AnimationPropertyGroup_h - -#include - -#include - -#include "EntityItemPropertiesMacros.h" -#include "PropertyGroup.h" - -class EntityItemProperties; -class EncodeBitstreamParams; -class OctreePacketData; -class EntityTreeElementExtraEncodeData; -class ReadBitstreamToTreeParams; -class ScriptEngine; -class ScriptValue; - -class AnimationPropertyGroup : public PropertyGroup { -public: - static const float MAXIMUM_POSSIBLE_FRAME; - - // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, - ScriptEngine* engine, bool skipDefaults, - EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, - bool isMyOwnAvatarEntity) const override; - virtual void copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) override; - - void merge(const AnimationPropertyGroup& other); - - virtual void debugDump() const override; - virtual void listChangedProperties(QList& 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; - - float getNumFrames() const; - float computeLoopedFrame(float frame) const; - bool isValidAndRunning() const; - - DEFINE_PROPERTY_REF(PROP_ANIMATION_URL, URL, url, QString, ""); - DEFINE_PROPERTY(PROP_ANIMATION_FPS, FPS, fps, float, 30.0f); - DEFINE_PROPERTY(PROP_ANIMATION_FRAME_INDEX, CurrentFrame, currentFrame, float, 0.0f); - DEFINE_PROPERTY(PROP_ANIMATION_PLAYING, Running, running, bool, false); // was animationIsPlaying - DEFINE_PROPERTY(PROP_ANIMATION_LOOP, Loop, loop, bool, true); // was animationSettings.loop - DEFINE_PROPERTY(PROP_ANIMATION_FIRST_FRAME, FirstFrame, firstFrame, float, 0.0f); // was animationSettings.firstFrame - DEFINE_PROPERTY(PROP_ANIMATION_LAST_FRAME, LastFrame, lastFrame, float, MAXIMUM_POSSIBLE_FRAME); // was animationSettings.lastFrame - DEFINE_PROPERTY(PROP_ANIMATION_HOLD, Hold, hold, bool, false); // was animationSettings.hold - DEFINE_PROPERTY(PROP_ANIMATION_ALLOW_TRANSLATION, AllowTranslation, allowTranslation, bool, true); - -protected: - friend bool operator==(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b); - friend bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b); - void setFromOldAnimationSettings(const QString& value); -}; - -#endif // hifi_AnimationPropertyGroup_h diff --git a/libraries/entities/src/AnimationPropertyGroup.h.in b/libraries/entities/src/AnimationPropertyGroup.h.in new file mode 100644 index 00000000000..3de4fd20382 --- /dev/null +++ b/libraries/entities/src/AnimationPropertyGroup.h.in @@ -0,0 +1,52 @@ +// +// AnimationPropertyGroup.h +// libraries/entities/src +// +// Created by Brad Hefta-Gaub on 2015/9/30. +// Copyright 2013 High Fidelity, Inc. +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + + +#ifndef hifi_AnimationPropertyGroup_h +#define hifi_AnimationPropertyGroup_h + +#include + +#include + +#include "EntityItemPropertiesMacros.h" +#include "PropertyGroup.h" + +class EntityItemProperties; +class EncodeBitstreamParams; +class OctreePacketData; +class EntityTreeElementExtraEncodeData; +class ReadBitstreamToTreeParams; +class ScriptEngine; +class ScriptValue; + +class AnimationPropertyGroup : public PropertyGroup { +public: + ENTITY_PROPERTY_GROUP_METHODS(AnimationPropertyGroup) + + static const float MAXIMUM_POSSIBLE_FRAME; + + float getNumFrames() const; + float computeLoopedFrame(float frame) const; + bool isValidAndRunning() const; + +protected: + +@Animation_GROUP_PROPS@ + + friend bool operator==(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b); + friend bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b) { return !(a == b); } + void setFromOldAnimationSettings(const QString& value); +}; + +#endif // hifi_AnimationPropertyGroup_h diff --git a/libraries/entities/src/BloomPropertyGroup.cpp b/libraries/entities/src/BloomPropertyGroup.cpp deleted file mode 100644 index 18ad85d7979..00000000000 --- a/libraries/entities/src/BloomPropertyGroup.cpp +++ /dev/null @@ -1,163 +0,0 @@ -// -// BloomPropertyGroup.cpp -// libraries/entities/src -// -// Created by Sam Gondelman on 8/7/2018 -// Copyright 2018 High Fidelity, Inc. -// Copyright 2023 Overte e.V. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// SPDX-License-Identifier: Apache-2.0 -// - -#include "BloomPropertyGroup.h" - -#include - -#include "EntityItemProperties.h" -#include "EntityItemPropertiesMacros.h" - -void BloomPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, - bool skipDefaults, EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, - bool isMyOwnAvatarEntity) 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 ScriptValue& object, const QSet &namesSet, 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& 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; -} diff --git a/libraries/entities/src/BloomPropertyGroup.cpp.in b/libraries/entities/src/BloomPropertyGroup.cpp.in new file mode 100644 index 00000000000..b567d645b1a --- /dev/null +++ b/libraries/entities/src/BloomPropertyGroup.cpp.in @@ -0,0 +1,134 @@ +// +// BloomPropertyGroup.cpp +// libraries/entities/src +// +// Created by Sam Gondelman on 8/7/2018 +// Copyright 2018 High Fidelity, Inc. +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#include "BloomPropertyGroup.h" + +#include + +#include "EntityItemProperties.h" + +void BloomPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, + bool skipDefaults, EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, bool isMyOwnAvatarEntity) const { + +@Bloom_GROUP_COPY_TO_SCRIPT@ + +} + +void BloomPropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) { + +@Bloom_GROUP_COPY_FROM_SCRIPT@ + +} + +void BloomPropertyGroup::merge(const BloomPropertyGroup& other) { + +@Bloom_GROUP_MERGE@ + +} + +void BloomPropertyGroup::debugDump() const { + +@Bloom_GROUP_DEBUG_DUMP@ + +} + +void BloomPropertyGroup::listChangedProperties(QList& out) { + +@Bloom_GROUP_LIST_CHANGED@ + +} + +bool BloomPropertyGroup::appendToEditPacket(OctreePacketData* packetData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@Bloom_GROUP_APPEND@ + + return successPropertyFits; +} + +bool BloomPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) { + + int bytesRead = 0; + bool overwriteLocalData = true; + bool somethingChanged = false; + +@Bloom_GROUP_READ@ + +@Bloom_GROUP_DECODE_CHANGED@ + + processedBytes += bytesRead; + + return somethingChanged; +} + +void BloomPropertyGroup::markAllChanged() { + +@Bloom_GROUP_MARK_CHANGED@ + +} + +EntityPropertyFlags BloomPropertyGroup::getChangedProperties() const { + EntityPropertyFlags changedProperties; + +@Bloom_GROUP_CHANGED_PROPERTIES@ + + return changedProperties; +} + +void BloomPropertyGroup::getProperties(EntityItemProperties& properties) const { + +@Bloom_GROUP_COPY_TO@ + +} + +bool BloomPropertyGroup::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + +@Bloom_GROUP_SET_FROM@ + + return somethingChanged; +} + +EntityPropertyFlags BloomPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties; + +@Bloom_REQUESTED_PROPS@ + + return requestedProperties; +} + +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; + +@Bloom_GROUP_READ@ + + return bytesRead; +} + +void BloomPropertyGroup::addPropertyMap(QHash& _propertyInfos, + QHash& _enumsToPropertyStrings) { + +@Bloom_GROUP_ADD_TO_MAP@ + +} diff --git a/libraries/entities/src/BloomPropertyGroup.h b/libraries/entities/src/BloomPropertyGroup.h deleted file mode 100644 index d459bb2f3c8..00000000000 --- a/libraries/entities/src/BloomPropertyGroup.h +++ /dev/null @@ -1,96 +0,0 @@ -// -// BloomPropertyGroup.h -// libraries/entities/src -// -// Created by Sam Gondelman on 8/7/2018 -// Copyright 2018 High Fidelity, Inc. -// Copyright 2023 Overte e.V. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// SPDX-License-Identifier: Apache-2.0 -// - -#ifndef hifi_BloomPropertyGroup_h -#define hifi_BloomPropertyGroup_h - -#include -#include - -#include "PropertyGroup.h" -#include "EntityItemPropertiesMacros.h" - -class EntityItemProperties; -class EncodeBitstreamParams; -class OctreePacketData; -class EntityTreeElementExtraEncodeData; -class ReadBitstreamToTreeParams; -class ScriptEngine; -class ScriptValue; - -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, ScriptValue& properties, - ScriptEngine* engine, bool skipDefaults, - EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, - bool isMyOwnAvatarEntity) const override; - virtual void copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) override; - - void merge(const BloomPropertyGroup& other); - - virtual void debugDump() const override; - virtual void listChangedProperties(QList& 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 diff --git a/libraries/entities/src/BloomPropertyGroup.h.in b/libraries/entities/src/BloomPropertyGroup.h.in new file mode 100644 index 00000000000..10e938655e9 --- /dev/null +++ b/libraries/entities/src/BloomPropertyGroup.h.in @@ -0,0 +1,52 @@ +// +// BloomPropertyGroup.h +// libraries/entities/src +// +// Created by Sam Gondelman on 8/7/2018 +// Copyright 2018 High Fidelity, Inc. +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef hifi_BloomPropertyGroup_h +#define hifi_BloomPropertyGroup_h + +#include +#include + +#include "PropertyGroup.h" +#include "EntityItemPropertiesMacros.h" + +class EntityItemProperties; +class EncodeBitstreamParams; +class OctreePacketData; +class EntityTreeElementExtraEncodeData; +class ReadBitstreamToTreeParams; +class ScriptEngine; +class ScriptValue; + +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: + ENTITY_PROPERTY_GROUP_METHODS(BloomPropertyGroup) + +protected: + +@Bloom_GROUP_PROPS@ + +}; + +#endif // hifi_BloomPropertyGroup_h diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp.in similarity index 77% rename from libraries/entities/src/EntityItem.cpp rename to libraries/entities/src/EntityItem.cpp.in index b63f0d91ab8..aed0b2bcb6a 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp.in @@ -75,80 +75,7 @@ EntityItem::~EntityItem() { EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties; - // Core - requestedProperties += PROP_SIMULATION_OWNER; - requestedProperties += PROP_PARENT_ID; - requestedProperties += PROP_PARENT_JOINT_INDEX; - requestedProperties += PROP_VISIBLE; - requestedProperties += PROP_NAME; - requestedProperties += PROP_LOCKED; - requestedProperties += PROP_USER_DATA; - requestedProperties += PROP_PRIVATE_USER_DATA; - requestedProperties += PROP_HREF; - requestedProperties += PROP_DESCRIPTION; - requestedProperties += PROP_POSITION; - requestedProperties += PROP_DIMENSIONS; - requestedProperties += PROP_ROTATION; - requestedProperties += PROP_REGISTRATION_POINT; - requestedProperties += PROP_CREATED; - requestedProperties += PROP_LAST_EDITED_BY; - requestedProperties += PROP_ENTITY_HOST_TYPE; - requestedProperties += PROP_OWNING_AVATAR_ID; - requestedProperties += PROP_PARENT_ID; - requestedProperties += PROP_PARENT_JOINT_INDEX; - requestedProperties += PROP_QUERY_AA_CUBE; - requestedProperties += PROP_CAN_CAST_SHADOW; - requestedProperties += PROP_VISIBLE_IN_SECONDARY_CAMERA; - requestedProperties += PROP_RENDER_LAYER; - requestedProperties += PROP_PRIMITIVE_MODE; - requestedProperties += PROP_IGNORE_PICK_INTERSECTION; - requestedProperties += PROP_RENDER_WITH_ZONES; - requestedProperties += PROP_BILLBOARD_MODE; - requestedProperties += _grabProperties.getEntityProperties(params); - - // Physics - requestedProperties += PROP_DENSITY; - requestedProperties += PROP_VELOCITY; - requestedProperties += PROP_ANGULAR_VELOCITY; - requestedProperties += PROP_GRAVITY; - requestedProperties += PROP_ACCELERATION; - requestedProperties += PROP_DAMPING; - requestedProperties += PROP_ANGULAR_DAMPING; - requestedProperties += PROP_RESTITUTION; - requestedProperties += PROP_FRICTION; - requestedProperties += PROP_LIFETIME; - requestedProperties += PROP_COLLISIONLESS; - requestedProperties += PROP_COLLISION_MASK; - requestedProperties += PROP_DYNAMIC; - requestedProperties += PROP_COLLISION_SOUND_URL; - requestedProperties += PROP_ACTION_DATA; - - // Cloning - requestedProperties += PROP_CLONEABLE; - requestedProperties += PROP_CLONE_LIFETIME; - requestedProperties += PROP_CLONE_LIMIT; - requestedProperties += PROP_CLONE_DYNAMIC; - requestedProperties += PROP_CLONE_AVATAR_ENTITY; - requestedProperties += PROP_CLONE_ORIGIN_ID; - - // Scripts - requestedProperties += PROP_SCRIPT; - requestedProperties += PROP_SCRIPT_TIMESTAMP; - requestedProperties += PROP_SERVER_SCRIPTS; - - // Certifiable properties - requestedProperties += PROP_ITEM_NAME; - requestedProperties += PROP_ITEM_DESCRIPTION; - requestedProperties += PROP_ITEM_CATEGORIES; - requestedProperties += PROP_ITEM_ARTIST; - requestedProperties += PROP_ITEM_LICENSE; - requestedProperties += PROP_LIMITED_RUN; - requestedProperties += PROP_MARKETPLACE_ID; - requestedProperties += PROP_EDITION_NUMBER; - requestedProperties += PROP_ENTITY_INSTANCE_NUMBER; - requestedProperties += PROP_CERTIFICATE_ID; - requestedProperties += PROP_CERTIFICATE_TYPE; - requestedProperties += PROP_STATIC_CERTIFICATE_VERSION; +@Base_REQUESTED_PROPS@ return requestedProperties; } @@ -269,86 +196,14 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet // PROP_PAGED_PROPERTY, // PROP_CUSTOM_PROPERTIES_INCLUDED, - APPEND_ENTITY_PROPERTY(PROP_SIMULATION_OWNER, _simulationOwner.toByteArray()); // convert AVATAR_SELF_ID to actual sessionUUID. QUuid actualParentID = getParentID(); auto nodeList = DependencyManager::get(); if (actualParentID == AVATAR_SELF_ID) { actualParentID = nodeList->getSessionUUID(); } - APPEND_ENTITY_PROPERTY(PROP_PARENT_ID, actualParentID); - APPEND_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, getParentJointIndex()); - APPEND_ENTITY_PROPERTY(PROP_VISIBLE, getVisible()); - APPEND_ENTITY_PROPERTY(PROP_NAME, getName()); - APPEND_ENTITY_PROPERTY(PROP_LOCKED, getLocked()); - APPEND_ENTITY_PROPERTY(PROP_USER_DATA, getUserData()); - APPEND_ENTITY_PROPERTY(PROP_PRIVATE_USER_DATA, privateUserData); - APPEND_ENTITY_PROPERTY(PROP_HREF, getHref()); - APPEND_ENTITY_PROPERTY(PROP_DESCRIPTION, getDescription()); - APPEND_ENTITY_PROPERTY(PROP_POSITION, getLocalPosition()); - APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, getScaledDimensions()); - APPEND_ENTITY_PROPERTY(PROP_ROTATION, getLocalOrientation()); - APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, getRegistrationPoint()); - APPEND_ENTITY_PROPERTY(PROP_CREATED, getCreated()); - APPEND_ENTITY_PROPERTY(PROP_LAST_EDITED_BY, getLastEditedBy()); - // APPEND_ENTITY_PROPERTY(PROP_ENTITY_HOST_TYPE, (uint32_t)getEntityHostType()); // not sent over the wire - // APPEND_ENTITY_PROPERTY(PROP_OWNING_AVATAR_ID, getOwningAvatarID()); // not sent over the wire - APPEND_ENTITY_PROPERTY(PROP_QUERY_AA_CUBE, getQueryAACube()); - APPEND_ENTITY_PROPERTY(PROP_CAN_CAST_SHADOW, getCanCastShadow()); - // APPEND_ENTITY_PROPERTY(PROP_VISIBLE_IN_SECONDARY_CAMERA, getIsVisibleInSecondaryCamera()); // not sent over the wire - APPEND_ENTITY_PROPERTY(PROP_RENDER_LAYER, (uint32_t)getRenderLayer()); - APPEND_ENTITY_PROPERTY(PROP_PRIMITIVE_MODE, (uint32_t)getPrimitiveMode()); - APPEND_ENTITY_PROPERTY(PROP_IGNORE_PICK_INTERSECTION, getIgnorePickIntersection()); - APPEND_ENTITY_PROPERTY(PROP_RENDER_WITH_ZONES, getRenderWithZones()); - APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)getBillboardMode()); - withReadLock([&] { - _grabProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, - propertyFlags, propertiesDidntFit, propertyCount, appendState); - }); - // Physics - APPEND_ENTITY_PROPERTY(PROP_DENSITY, getDensity()); - APPEND_ENTITY_PROPERTY(PROP_VELOCITY, getLocalVelocity()); - APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, getLocalAngularVelocity()); - APPEND_ENTITY_PROPERTY(PROP_GRAVITY, getGravity()); - APPEND_ENTITY_PROPERTY(PROP_ACCELERATION, getAcceleration()); - APPEND_ENTITY_PROPERTY(PROP_DAMPING, getDamping()); - APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, getAngularDamping()); - APPEND_ENTITY_PROPERTY(PROP_RESTITUTION, getRestitution()); - APPEND_ENTITY_PROPERTY(PROP_FRICTION, getFriction()); - APPEND_ENTITY_PROPERTY(PROP_LIFETIME, getLifetime()); - APPEND_ENTITY_PROPERTY(PROP_COLLISIONLESS, getCollisionless()); - APPEND_ENTITY_PROPERTY(PROP_COLLISION_MASK, getCollisionMask()); - APPEND_ENTITY_PROPERTY(PROP_DYNAMIC, getDynamic()); - APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, getCollisionSoundURL()); - APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, getDynamicData()); - - // Cloning - APPEND_ENTITY_PROPERTY(PROP_CLONEABLE, getCloneable()); - APPEND_ENTITY_PROPERTY(PROP_CLONE_LIFETIME, getCloneLifetime()); - APPEND_ENTITY_PROPERTY(PROP_CLONE_LIMIT, getCloneLimit()); - APPEND_ENTITY_PROPERTY(PROP_CLONE_DYNAMIC, getCloneDynamic()); - APPEND_ENTITY_PROPERTY(PROP_CLONE_AVATAR_ENTITY, getCloneAvatarEntity()); - APPEND_ENTITY_PROPERTY(PROP_CLONE_ORIGIN_ID, getCloneOriginID()); - - // Scripts - APPEND_ENTITY_PROPERTY(PROP_SCRIPT, getScript()); - APPEND_ENTITY_PROPERTY(PROP_SCRIPT_TIMESTAMP, getScriptTimestamp()); - APPEND_ENTITY_PROPERTY(PROP_SERVER_SCRIPTS, getServerScripts()); - - // Certifiable Properties - APPEND_ENTITY_PROPERTY(PROP_ITEM_NAME, QString()); - APPEND_ENTITY_PROPERTY(PROP_ITEM_DESCRIPTION, QString()); - APPEND_ENTITY_PROPERTY(PROP_ITEM_CATEGORIES, QString()); - APPEND_ENTITY_PROPERTY(PROP_ITEM_ARTIST, QString()); - APPEND_ENTITY_PROPERTY(PROP_ITEM_LICENSE, QString()); - APPEND_ENTITY_PROPERTY(PROP_LIMITED_RUN, quint32(-1)); - APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString()); - APPEND_ENTITY_PROPERTY(PROP_EDITION_NUMBER, 0U); - APPEND_ENTITY_PROPERTY(PROP_ENTITY_INSTANCE_NUMBER, 0U); - APPEND_ENTITY_PROPERTY(PROP_CERTIFICATE_ID, QString()); - APPEND_ENTITY_PROPERTY(PROP_CERTIFICATE_TYPE, QString()); - APPEND_ENTITY_PROPERTY(PROP_STATIC_CERTIFICATE_VERSION, 0U); +@Base_ENTITY_APPEND@ appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, @@ -804,6 +659,61 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef return otherOverwrites && simulationChanged && (valueChanged || filterRejection); }; + // When we own the simulation we don't accept updates to the entity's transform/velocities + // we also want to ignore any duplicate packets that have the same "recently updated" values + // as a packet we've already recieved. This is because we want multiple edits of the same + // information to be idempotent, but if we applied new physics properties we'd resimulation + // with small differences in results. + + // Because the regular streaming property "setters" only have access to the new value, we've + // made these lambdas that can access other details about the previous updates to suppress + // any duplicates. + + // Note: duplicate packets are expected and not wrong. They may be sent for any number of + // reasons and the contract is that the client handles them in an idempotent manner. + auto customUpdatePositionFromNetwork = [this, shouldUpdate, lastEdited](glm::vec3 value) { + if (shouldUpdate(_lastUpdatedPositionTimestamp, value != _lastUpdatedPositionValue)) { + setPosition(value); + _lastUpdatedPositionTimestamp = lastEdited; + _lastUpdatedPositionValue = value; + } + }; + auto customUpdateRotationFromNetwork = [this, shouldUpdate, lastEdited](glm::quat value) { + if (shouldUpdate(_lastUpdatedRotationTimestamp, value != _lastUpdatedRotationValue)) { + setRotation(value); + _lastUpdatedRotationTimestamp = lastEdited; + _lastUpdatedRotationValue = value; + } + }; + auto customUpdateQueryAACubeFromNetwork = [this, shouldUpdate, lastEdited](AACube value) { + if (shouldUpdate(_lastUpdatedQueryAACubeTimestamp, value != _lastUpdatedQueryAACubeValue)) { + setQueryAACube(value); + _lastUpdatedQueryAACubeTimestamp = lastEdited; + _lastUpdatedQueryAACubeValue = value; + } + }; + auto customUpdateVelocityFromNetwork = [this, shouldUpdate, lastEdited](glm::vec3 value) { + if (shouldUpdate(_lastUpdatedVelocityTimestamp, value != _lastUpdatedVelocityValue)) { + setVelocity(value); + _lastUpdatedVelocityTimestamp = lastEdited; + _lastUpdatedVelocityValue = value; + } + }; + auto customUpdateAngularVelocityFromNetwork = [this, shouldUpdate, lastEdited](glm::vec3 value){ + if (shouldUpdate(_lastUpdatedAngularVelocityTimestamp, value != _lastUpdatedAngularVelocityValue)) { + setAngularVelocity(value); + _lastUpdatedAngularVelocityTimestamp = lastEdited; + _lastUpdatedAngularVelocityValue = value; + } + }; + auto customSetAcceleration = [this, shouldUpdate, lastEdited](glm::vec3 value){ + if (shouldUpdate(_lastUpdatedAccelerationTimestamp, value != _lastUpdatedAccelerationValue)) { + setAcceleration(value); + _lastUpdatedAccelerationTimestamp = lastEdited; + _lastUpdatedAccelerationValue = value; + } + }; + // Core // PROP_SIMULATION_OWNER handled above { // parentID and parentJointIndex are protected by simulation ownership @@ -813,125 +723,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex); overwriteLocalData = oldOverwrite; } - READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible); - READ_ENTITY_PROPERTY(PROP_NAME, QString, setName); - READ_ENTITY_PROPERTY(PROP_LOCKED, bool, setLocked); - READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData); - READ_ENTITY_PROPERTY(PROP_PRIVATE_USER_DATA, QString, setPrivateUserData); - READ_ENTITY_PROPERTY(PROP_HREF, QString, setHref); - READ_ENTITY_PROPERTY(PROP_DESCRIPTION, QString, setDescription); - { // When we own the simulation we don't accept updates to the entity's transform/velocities - // we also want to ignore any duplicate packets that have the same "recently updated" values - // as a packet we've already recieved. This is because we want multiple edits of the same - // information to be idempotent, but if we applied new physics properties we'd resimulation - // with small differences in results. - - // Because the regular streaming property "setters" only have access to the new value, we've - // made these lambdas that can access other details about the previous updates to suppress - // any duplicates. - - // Note: duplicate packets are expected and not wrong. They may be sent for any number of - // reasons and the contract is that the client handles them in an idempotent manner. - auto customUpdatePositionFromNetwork = [this, shouldUpdate, lastEdited](glm::vec3 value) { - if (shouldUpdate(_lastUpdatedPositionTimestamp, value != _lastUpdatedPositionValue)) { - setPosition(value); - _lastUpdatedPositionTimestamp = lastEdited; - _lastUpdatedPositionValue = value; - } - }; - READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, customUpdatePositionFromNetwork); - } - READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, setScaledDimensions); - { // See comment above - auto customUpdateRotationFromNetwork = [this, shouldUpdate, lastEdited](glm::quat value) { - if (shouldUpdate(_lastUpdatedRotationTimestamp, value != _lastUpdatedRotationValue)) { - setRotation(value); - _lastUpdatedRotationTimestamp = lastEdited; - _lastUpdatedRotationValue = value; - } - }; - READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, customUpdateRotationFromNetwork); - } - READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint); - READ_ENTITY_PROPERTY(PROP_CREATED, quint64, setCreated); - READ_ENTITY_PROPERTY(PROP_LAST_EDITED_BY, QUuid, setLastEditedBy); - // READ_ENTITY_PROPERTY(PROP_ENTITY_HOST_TYPE, entity::HostType, setEntityHostType); // not sent over the wire - // READ_ENTITY_PROPERTY(PROP_OWNING_AVATAR_ID, QUuuid, setOwningAvatarID); // not sent over the wire - { // See comment above - auto customUpdateQueryAACubeFromNetwork = [this, shouldUpdate, lastEdited](AACube value) { - if (shouldUpdate(_lastUpdatedQueryAACubeTimestamp, value != _lastUpdatedQueryAACubeValue)) { - setQueryAACube(value); - _lastUpdatedQueryAACubeTimestamp = lastEdited; - _lastUpdatedQueryAACubeValue = value; - } - }; - READ_ENTITY_PROPERTY(PROP_QUERY_AA_CUBE, AACube, customUpdateQueryAACubeFromNetwork); - } - READ_ENTITY_PROPERTY(PROP_CAN_CAST_SHADOW, bool, setCanCastShadow); - // READ_ENTITY_PROPERTY(PROP_VISIBLE_IN_SECONDARY_CAMERA, bool, setIsVisibleInSecondaryCamera); // not sent over the wire - READ_ENTITY_PROPERTY(PROP_RENDER_LAYER, RenderLayer, setRenderLayer); - READ_ENTITY_PROPERTY(PROP_PRIMITIVE_MODE, PrimitiveMode, setPrimitiveMode); - READ_ENTITY_PROPERTY(PROP_IGNORE_PICK_INTERSECTION, bool, setIgnorePickIntersection); - READ_ENTITY_PROPERTY(PROP_RENDER_WITH_ZONES, QVector, setRenderWithZones); - READ_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode); - withWriteLock([&] { - int bytesFromGrab = _grabProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, - somethingChanged); - bytesRead += bytesFromGrab; - dataAt += bytesFromGrab; - }); - READ_ENTITY_PROPERTY(PROP_DENSITY, float, setDensity); - { - auto customUpdateVelocityFromNetwork = [this, shouldUpdate, lastEdited](glm::vec3 value) { - if (shouldUpdate(_lastUpdatedVelocityTimestamp, value != _lastUpdatedVelocityValue)) { - setVelocity(value); - _lastUpdatedVelocityTimestamp = lastEdited; - _lastUpdatedVelocityValue = value; - } - }; - READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, customUpdateVelocityFromNetwork); - auto customUpdateAngularVelocityFromNetwork = [this, shouldUpdate, lastEdited](glm::vec3 value){ - if (shouldUpdate(_lastUpdatedAngularVelocityTimestamp, value != _lastUpdatedAngularVelocityValue)) { - setAngularVelocity(value); - _lastUpdatedAngularVelocityTimestamp = lastEdited; - _lastUpdatedAngularVelocityValue = value; - } - }; - READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, customUpdateAngularVelocityFromNetwork); - READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, setGravity); - auto customSetAcceleration = [this, shouldUpdate, lastEdited](glm::vec3 value){ - if (shouldUpdate(_lastUpdatedAccelerationTimestamp, value != _lastUpdatedAccelerationValue)) { - setAcceleration(value); - _lastUpdatedAccelerationTimestamp = lastEdited; - _lastUpdatedAccelerationValue = value; - } - }; - READ_ENTITY_PROPERTY(PROP_ACCELERATION, glm::vec3, customSetAcceleration); - } - READ_ENTITY_PROPERTY(PROP_DAMPING, float, setDamping); - READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, setAngularDamping); - READ_ENTITY_PROPERTY(PROP_RESTITUTION, float, setRestitution); - READ_ENTITY_PROPERTY(PROP_FRICTION, float, setFriction); - READ_ENTITY_PROPERTY(PROP_LIFETIME, float, setLifetime); - READ_ENTITY_PROPERTY(PROP_COLLISIONLESS, bool, setCollisionless); - READ_ENTITY_PROPERTY(PROP_COLLISION_MASK, uint16_t, setCollisionMask); - READ_ENTITY_PROPERTY(PROP_DYNAMIC, bool, setDynamic); - READ_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL); - READ_ENTITY_PROPERTY(PROP_ACTION_DATA, QByteArray, setDynamicData); - - // Cloning - READ_ENTITY_PROPERTY(PROP_CLONEABLE, bool, setCloneable); - READ_ENTITY_PROPERTY(PROP_CLONE_LIFETIME, float, setCloneLifetime); - READ_ENTITY_PROPERTY(PROP_CLONE_LIMIT, float, setCloneLimit); - READ_ENTITY_PROPERTY(PROP_CLONE_DYNAMIC, bool, setCloneDynamic); - READ_ENTITY_PROPERTY(PROP_CLONE_AVATAR_ENTITY, bool, setCloneAvatarEntity); - READ_ENTITY_PROPERTY(PROP_CLONE_ORIGIN_ID, QUuid, setCloneOriginID); - - // Scripts - READ_ENTITY_PROPERTY(PROP_SCRIPT, QString, setScript); - READ_ENTITY_PROPERTY(PROP_SCRIPT_TIMESTAMP, quint64, setScriptTimestamp); +@Base_ENTITY_READ@ + { // We use this scope to work around an issue stopping server script changes // from being received by an entity script server running a script that continously updates an entity. @@ -943,20 +737,6 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef overwriteLocalData = oldOverwrite; } - // Certifiable props - SKIP_ENTITY_PROPERTY(PROP_ITEM_NAME, QString); - SKIP_ENTITY_PROPERTY(PROP_ITEM_DESCRIPTION, QString); - SKIP_ENTITY_PROPERTY(PROP_ITEM_CATEGORIES, QString); - SKIP_ENTITY_PROPERTY(PROP_ITEM_ARTIST, QString); - SKIP_ENTITY_PROPERTY(PROP_ITEM_LICENSE, QString); - SKIP_ENTITY_PROPERTY(PROP_LIMITED_RUN, quint32); - SKIP_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString); - SKIP_ENTITY_PROPERTY(PROP_EDITION_NUMBER, quint32); - SKIP_ENTITY_PROPERTY(PROP_ENTITY_INSTANCE_NUMBER, quint32); - SKIP_ENTITY_PROPERTY(PROP_CERTIFICATE_ID, QString); - SKIP_ENTITY_PROPERTY(PROP_CERTIFICATE_TYPE, QString); - SKIP_ENTITY_PROPERTY(PROP_STATIC_CERTIFICATE_VERSION, quint32); - bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData, somethingChanged); @@ -1008,11 +788,15 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef } void EntityItem::debugDump() const { - auto position = getWorldPosition(); - qCDebug(entities) << "EntityItem id:" << getEntityItemID(); - qCDebug(entities, " edited ago:%f", (double)getEditedAgo()); - qCDebug(entities, " position:%f,%f,%f", (double)position.x, (double)position.y, (double)position.z); - qCDebug(entities) << " dimensions:" << getScaledDimensions(); + qCDebug(entities) << "EntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " editedAgo:" << debugTime(getLastEdited(), usecTimestampNow()); + qCDebug(entities) << " pointer:" << this; + +@Base_ENTITY_DEBUG@ + } // adjust any internal timestamps to fix clock skew for this server @@ -1075,7 +859,7 @@ void EntityItem::setMass(float mass) { }); } -void EntityItem::setHref(QString value) { +void EntityItem::setHref(const QString& value) { auto href = value.toLower(); // Let's let the user set the value of this property to anything, then let consumers of the property // decide what to do with it. Currently, the only in-engine consumers are `EntityTreeRenderer::mousePressEvent()` @@ -1331,74 +1115,7 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire properties._type = getType(); - // Core - COPY_ENTITY_PROPERTY_TO_PROPERTIES(simulationOwner, getSimulationOwner); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentID, getParentID); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentJointIndex, getParentJointIndex); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(visible, getVisible); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(name, getName); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(locked, getLocked); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(userData, getUserData); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(privateUserData, getPrivateUserData); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(href, getHref); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(description, getDescription); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(position, getLocalPosition); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(dimensions, getScaledDimensions); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(rotation, getLocalOrientation); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(registrationPoint, getRegistrationPoint); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(created, getCreated); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(lastEditedBy, getLastEditedBy); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(entityHostType, getEntityHostType); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(owningAvatarID, getOwningAvatarIDForProperties); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(queryAACube, getQueryAACube); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(canCastShadow, getCanCastShadow); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(isVisibleInSecondaryCamera, isVisibleInSecondaryCamera); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(renderLayer, getRenderLayer); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(primitiveMode, getPrimitiveMode); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(ignorePickIntersection, getIgnorePickIntersection); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(renderWithZones, getRenderWithZones); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(billboardMode, getBillboardMode); - withReadLock([&] { - _grabProperties.getProperties(properties); - }); - - // Physics - COPY_ENTITY_PROPERTY_TO_PROPERTIES(density, getDensity); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(velocity, getLocalVelocity); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(angularVelocity, getLocalAngularVelocity); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(gravity, getGravity); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(acceleration, getAcceleration); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(damping, getDamping); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(angularDamping, getAngularDamping); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(restitution, getRestitution); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(friction, getFriction); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(lifetime, getLifetime); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionless, getCollisionless); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionMask, getCollisionMask); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(dynamic, getDynamic); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionSoundURL, getCollisionSoundURL); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(actionData, getDynamicData); - - // Cloning - COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneable, getCloneable); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneLifetime, getCloneLifetime); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneLimit, getCloneLimit); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneDynamic, getCloneDynamic); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneAvatarEntity, getCloneAvatarEntity); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(cloneOriginID, getCloneOriginID); - - // Scripts - COPY_ENTITY_PROPERTY_TO_PROPERTIES(script, getScript); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(scriptTimestamp, getScriptTimestamp); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(serverScripts, getServerScripts); - - // Script local data - COPY_ENTITY_PROPERTY_TO_PROPERTIES(localPosition, getLocalPosition); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(localRotation, getLocalOrientation); - // FIXME: are these needed? - //COPY_ENTITY_PROPERTY_TO_PROPERTIES(localVelocity, getLocalVelocity); - //COPY_ENTITY_PROPERTY_TO_PROPERTIES(localAngularVelocity, getLocalAngularVelocity); - //COPY_ENTITY_PROPERTY_TO_PROPERTIES(localDimensions, getLocalDimensions); +@Base_ENTITY_COPY_TO@ properties._defaultSettings = false; @@ -1468,67 +1185,7 @@ bool EntityItem::stillWaitingToTakeOwnership(uint64_t timestamp) const { bool EntityItem::setProperties(const EntityItemProperties& properties) { bool somethingChanged = false; - // Core - SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulationOwner, setSimulationOwner); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentID, setParentID); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentJointIndex, setParentJointIndex); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(visible, setVisible); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(name, setName); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(locked, setLocked); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(userData, setUserData); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(privateUserData, setPrivateUserData); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(href, setHref); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(description, setDescription); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, setPosition); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, setScaledDimensions); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, setRotation); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(created, setCreated); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(lastEditedBy, setLastEditedBy); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(entityHostType, setEntityHostType); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(owningAvatarID, setOwningAvatarID); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(queryAACube, setQueryAACube); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(canCastShadow, setCanCastShadow); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(isVisibleInSecondaryCamera, setIsVisibleInSecondaryCamera); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(renderLayer, setRenderLayer); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(primitiveMode, setPrimitiveMode); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignorePickIntersection, setIgnorePickIntersection); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(renderWithZones, setRenderWithZones); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(billboardMode, setBillboardMode); - withWriteLock([&] { - bool grabPropertiesChanged = _grabProperties.setProperties(properties); - somethingChanged |= grabPropertiesChanged; - }); - - // Physics - SET_ENTITY_PROPERTY_FROM_PROPERTIES(density, setDensity); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocity, setVelocity); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularVelocity, setAngularVelocity); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(gravity, setGravity); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(acceleration, setAcceleration); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(damping, setDamping); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularDamping, setAngularDamping); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(restitution, setRestitution); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(friction, setFriction); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, setLifetime); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionless, setCollisionless); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionMask, setCollisionMask); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(dynamic, setDynamic); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionSoundURL, setCollisionSoundURL); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(actionData, setDynamicData); - - // Cloning - SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneable, setCloneable); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneLifetime, setCloneLifetime); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneLimit, setCloneLimit); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneDynamic, setCloneDynamic); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneAvatarEntity, setCloneAvatarEntity); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(cloneOriginID, setCloneOriginID); - - // Scripts - SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, setScript); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(scriptTimestamp, setScriptTimestamp); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(serverScripts, setServerScripts); +@Base_ENTITY_SET_FROM@ if (updateQueryAACube()) { somethingChanged = true; @@ -1807,7 +1464,7 @@ void EntityItem::setRegistrationPoint(const glm::vec3& value) { bool changed = false; withWriteLock([&] { if (value != _registrationPoint) { - _registrationPoint = glm::clamp(value, glm::vec3(ENTITY_ITEM_MIN_REGISTRATION_POINT), + _registrationPoint = glm::clamp(value, glm::vec3(ENTITY_ITEM_MIN_REGISTRATION_POINT), glm::vec3(ENTITY_ITEM_MAX_REGISTRATION_POINT)); changed = true; } @@ -2133,6 +1790,10 @@ void EntityItem::computeCollisionGroupAndFinalMask(int32_t& group, int32_t& mask } } +SimulationOwner EntityItem::getSimulationOwner() const { + return _simulationOwner; +} + void EntityItem::setSimulationOwner(const QUuid& id, uint8_t priority) { if (wantTerseEditLogging() && (id != _simulationOwner.getID() || priority != _simulationOwner.getPriority())) { qCDebug(entities) << "sim ownership for" << getDebugName() << "is now" << id << priority; @@ -2701,11 +2362,9 @@ bool EntityItem::matchesJSONFilters(const QJsonObject& jsonFilters) const { } quint64 EntityItem::getLastSimulated() const { - quint64 result; - withReadLock([&] { - result = _lastSimulated; + return resultWithReadLock([&] { + return _lastSimulated; }); - return result; } void EntityItem::setLastSimulated(quint64 now) { @@ -2715,11 +2374,9 @@ void EntityItem::setLastSimulated(quint64 now) { } quint64 EntityItem::getLastEdited() const { - quint64 result; - withReadLock([&] { - result = _lastEdited; + return resultWithReadLock([&] { + return _lastEdited; }); - return result; } void EntityItem::setLastEdited(quint64 lastEdited) { @@ -2738,11 +2395,9 @@ void EntityItem::markAsChangedOnServer() { } quint64 EntityItem::getLastChangedOnServer() const { - quint64 result; - withReadLock([&] { - result = _changedOnServer; + return resultWithReadLock([&] { + return _changedOnServer; }); - return result; } void EntityItem::update(const quint64& now) { @@ -2752,11 +2407,9 @@ void EntityItem::update(const quint64& now) { } quint64 EntityItem::getLastUpdated() const { - quint64 result; - withReadLock([&] { - result = _lastUpdated; + return resultWithReadLock([&] { + return _lastUpdated; }); - return result; } void EntityItem::requiresRecalcBoxes() { @@ -2767,111 +2420,65 @@ void EntityItem::requiresRecalcBoxes() { }); } -QString EntityItem::getHref() const { - QString result; - withReadLock([&] { - result = _href; - }); - return result; -} - -QString EntityItem::getDescription() const { - QString result; - withReadLock([&] { - result = _description; +QString EntityItem::getUserData() const { + return resultWithReadLock([&] { + return _userData; }); - return result; } -void EntityItem::setDescription(const QString& value) { +void EntityItem::setUserData(const QString& value) { withWriteLock([&] { - _description = value; - }); -} - -glm::vec3 EntityItem::getGravity() const { - glm::vec3 result; - withReadLock([&] { - result = _gravity; + _userData = value; }); - return result; } -glm::vec3 EntityItem::getAcceleration() const { - glm::vec3 result; - withReadLock([&] { - result = _acceleration; +QString EntityItem::getHref() const { + return resultWithReadLock([&] { + return _href; }); - return result; } -void EntityItem::setAcceleration(const glm::vec3& value) { - withWriteLock([&] { - _acceleration = value; +glm::vec3 EntityItem::getGravity() const { + return resultWithReadLock([&] { + return _gravity; }); } float EntityItem::getDamping() const { - float result; - withReadLock([&] { - result = _damping; + return resultWithReadLock([&] { + return _damping; }); - return result; } float EntityItem::getRestitution() const { - float result; - withReadLock([&] { - result = _restitution; + return resultWithReadLock([&] { + return _restitution; }); - return result; } float EntityItem::getFriction() const { - float result; - withReadLock([&] { - result = _friction; + return resultWithReadLock([&] { + return _friction; }); - return result; } // lifetime related properties. float EntityItem::getLifetime() const { - float result; - withReadLock([&] { - result = _lifetime; + return resultWithReadLock([&] { + return _lifetime; }); - return result; } quint64 EntityItem::getCreated() const { - quint64 result; - withReadLock([&] { - result = _created; - }); - return result; -} - -QString EntityItem::getScript() const { - QString result; - withReadLock([&] { - result = _script; - }); - return result; -} - -void EntityItem::setScript(const QString& value) { - withWriteLock([&] { - _script = value; + return resultWithReadLock([&] { + return _created; }); } quint64 EntityItem::getScriptTimestamp() const { - quint64 result; - withReadLock([&] { - result = _scriptTimestamp; + return resultWithReadLock([&] { + return _scriptTimestamp; }); - return result; } void EntityItem::setScriptTimestamp(const quint64 value) { @@ -2881,11 +2488,9 @@ void EntityItem::setScriptTimestamp(const quint64 value) { } QString EntityItem::getServerScripts() const { - QString result; - withReadLock([&] { - result = _serverScripts; + return resultWithReadLock([&] { + return _serverScripts; }); - return result; } void EntityItem::setServerScripts(const QString& serverScripts) { @@ -2896,11 +2501,9 @@ void EntityItem::setServerScripts(const QString& serverScripts) { } QString EntityItem::getCollisionSoundURL() const { - QString result; - withReadLock([&] { - result = _collisionSoundURL; + return resultWithReadLock([&] { + return _collisionSoundURL; }); - return result; } glm::vec3 EntityItem::getRegistrationPoint() const { @@ -2910,19 +2513,15 @@ glm::vec3 EntityItem::getRegistrationPoint() const { } float EntityItem::getAngularDamping() const { - float result; - withReadLock([&] { - result = _angularDamping; + return resultWithReadLock([&] { + return _angularDamping; }); - return result; } QString EntityItem::getName() const { - QString result; - withReadLock([&] { - result = _name; + return resultWithReadLock([&] { + return _name; }); - return result; } void EntityItem::setName(const QString& value) { @@ -2939,68 +2538,6 @@ QString EntityItem::getDebugName() { return result; } -bool EntityItem::getVisible() const { - bool result; - withReadLock([&] { - result = _visible; - }); - return result; -} - -void EntityItem::setVisible(bool value) { - bool changed; - withWriteLock([&] { - changed = _visible != value; - _needsRenderUpdate |= changed; - _visible = value; - }); - - if (changed) { - bumpAncestorChainRenderableVersion(); - } -} - -bool EntityItem::isVisibleInSecondaryCamera() const { - bool result; - withReadLock([&] { - result = _isVisibleInSecondaryCamera; - }); - return result; -} - -void EntityItem::setIsVisibleInSecondaryCamera(bool value) { - withWriteLock([&] { - _needsRenderUpdate |= _isVisibleInSecondaryCamera != value; - _isVisibleInSecondaryCamera = value; - }); -} - -RenderLayer EntityItem::getRenderLayer() const { - return resultWithReadLock([&] { - return _renderLayer; - }); -} - -void EntityItem::setRenderLayer(RenderLayer value) { - withWriteLock([&] { - _needsRenderUpdate |= _renderLayer != value; - _renderLayer = value; - }); -} - -PrimitiveMode EntityItem::getPrimitiveMode() const { - return resultWithReadLock([&] { - return _primitiveMode; - }); -} - -void EntityItem::setPrimitiveMode(PrimitiveMode value) { - withWriteLock([&] { - _needsRenderUpdate |= _primitiveMode != value; - _primitiveMode = value; - }); -} - bool EntityItem::getCauterized() const { return resultWithReadLock([&] { return _cauterized; @@ -3019,39 +2556,10 @@ void EntityItem::setCauterized(bool value) { } } -bool EntityItem::getIgnorePickIntersection() const { - return resultWithReadLock([&] { - return _ignorePickIntersection; - }); -} - -void EntityItem::setIgnorePickIntersection(bool value) { - withWriteLock([&] { - _ignorePickIntersection = value; - }); -} - -bool EntityItem::getCanCastShadow() const { - bool result; - withReadLock([&] { - result = _canCastShadow; - }); - return result; -} - -void EntityItem::setCanCastShadow(bool value) { - withWriteLock([&] { - _needsRenderUpdate |= _canCastShadow != value; - _canCastShadow = value; - }); -} - bool EntityItem::getCullWithParent() const { - bool result; - withReadLock([&] { - result = _cullWithParent; + return resultWithReadLock([&] { + return _cullWithParent; }); - return result; } void EntityItem::setCullWithParent(bool value) { @@ -3072,11 +2580,9 @@ bool EntityItem::isChildOfMyAvatar() const { } bool EntityItem::getCollisionless() const { - bool result; - withReadLock([&] { - result = _collisionless; + return resultWithReadLock([&] { + return _collisionless; }); - return result; } uint16_t EntityItem::getCollisionMask() const { @@ -3111,40 +2617,10 @@ void EntityItem::setLocked(bool value) { } } -QString EntityItem::getUserData() const { - QString result; - withReadLock([&] { - result = _userData; - }); - return result; -} - -void EntityItem::setUserData(const QString& value) { - withWriteLock([&] { - _userData = value; - }); -} - -QString EntityItem::getPrivateUserData() const { - QString result; - withReadLock([&] { - result = _privateUserData; - }); - return result; -} - -void EntityItem::setPrivateUserData(const QString& value) { - withWriteLock([&] { - _privateUserData = value; - }); -} - uint32_t EntityItem::getDirtyFlags() const { - uint32_t result; - withReadLock([&] { - result = _flags & Simulation::DIRTY_FLAGS_MASK; + return resultWithReadLock([&] { + return _flags & Simulation::DIRTY_FLAGS_MASK; }); - return result; } void EntityItem::markDirtyFlags(uint32_t mask) { @@ -3162,11 +2638,9 @@ void EntityItem::clearDirtyFlags(uint32_t mask) { } uint32_t EntityItem::getSpecialFlags() const { - uint32_t result; - withReadLock([&] { - result = _flags & Simulation::SPECIAL_FLAGS_MASK; + return resultWithReadLock([&] { + return _flags & Simulation::SPECIAL_FLAGS_MASK; }); - return result; } void EntityItem::markSpecialFlags(uint32_t mask) { @@ -3184,11 +2658,9 @@ void EntityItem::clearSpecialFlags(uint32_t mask) { } float EntityItem::getDensity() const { - float result; - withReadLock([&] { - result = _density; + return resultWithReadLock([&] { + return _density; }); - return result; } EntityItem::ChangeHandlerId EntityItem::registerChangeHandler(const ChangeHandlerCallback& handler) { @@ -3239,90 +2711,6 @@ void EntityItem::setSpaceIndex(int32_t index) { void EntityItem::preDelete() { } -bool EntityItem::getCloneable() const { - bool result; - withReadLock([&] { - result = _cloneable; - }); - return result; -} - -void EntityItem::setCloneable(bool value) { - withWriteLock([&] { - _cloneable = value; - }); -} - -float EntityItem::getCloneLifetime() const { - float result; - withReadLock([&] { - result = _cloneLifetime; - }); - return result; -} - -void EntityItem::setCloneLifetime(float value) { - withWriteLock([&] { - _cloneLifetime = value; - }); -} - -float EntityItem::getCloneLimit() const { - float result; - withReadLock([&] { - result = _cloneLimit; - }); - return result; -} - -void EntityItem::setCloneLimit(float value) { - withWriteLock([&] { - _cloneLimit = value; - }); -} - -bool EntityItem::getCloneDynamic() const { - bool result; - withReadLock([&] { - result = _cloneDynamic; - }); - return result; -} - -void EntityItem::setCloneDynamic(bool value) { - withWriteLock([&] { - _cloneDynamic = value; - }); -} - -bool EntityItem::getCloneAvatarEntity() const { - bool result; - withReadLock([&] { - result = _cloneAvatarEntity; - }); - return result; -} - -void EntityItem::setCloneAvatarEntity(bool value) { - withWriteLock([&] { - _cloneAvatarEntity = value; - }); -} - -const QUuid EntityItem::getCloneOriginID() const { - QUuid result; - withReadLock([&] { - result = _cloneOriginID; - }); - return result; -} - -void EntityItem::setCloneOriginID(const QUuid& value) { - withWriteLock([&] { - _cloneOriginID = value; - }); -} - void EntityItem::addCloneID(const QUuid& cloneID) { withWriteLock([&] { if (!_cloneIDs.contains(cloneID)) { @@ -3341,11 +2729,9 @@ void EntityItem::removeCloneID(const QUuid& cloneID) { } const QVector EntityItem::getCloneIDs() const { - QVector result; - withReadLock([&] { - result = _cloneIDs; + return resultWithReadLock>([&] { + return _cloneIDs; }); - return result; } void EntityItem::setCloneIDs(const QVector& cloneIDs) { @@ -3407,7 +2793,7 @@ bool EntityItem::isWearable() const { } bool EntityItem::isMyAvatarEntity() const { - return _hostType == entity::HostType::AVATAR && AVATAR_SELF_ID == _owningAvatarID; + return _entityHostType == entity::HostType::AVATAR && AVATAR_SELF_ID == _owningAvatarID; }; QUuid EntityItem::getOwningAvatarIDForProperties() const { @@ -3420,6 +2806,10 @@ QUuid EntityItem::getOwningAvatarIDForProperties() const { return _owningAvatarID; } +QUuid EntityItem::getOwningAvatarID() const { + return _owningAvatarID; +} + void EntityItem::setOwningAvatarID(const QUuid& owningAvatarID) { if (!owningAvatarID.isNull() && owningAvatarID == Physics::getSessionUUID()) { _owningAvatarID = AVATAR_SELF_ID; @@ -3540,16 +2930,3 @@ QVector EntityItem::getRenderWithZones() const { return _renderWithZones; }); } - -BillboardMode EntityItem::getBillboardMode() const { - return resultWithReadLock([&] { - return _billboardMode; - }); -} - -void EntityItem::setBillboardMode(BillboardMode value) { - withWriteLock([&] { - _needsRenderUpdate |= _billboardMode != value; - _billboardMode = value; - }); -} diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h.in similarity index 80% rename from libraries/entities/src/EntityItem.h rename to libraries/entities/src/EntityItem.h.in index ec84b0ccb28..837c84714c5 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h.in @@ -69,7 +69,7 @@ class MeshProxyList; #endif namespace entity { -enum class HostType { +enum class HostType : uint8_t { DOMAIN = 0, AVATAR, LOCAL @@ -147,9 +147,6 @@ class EntityItem : public QObject, public SpatiallyNestable, public ReadWriteLoc int& propertyCount, OctreeElement::AppendState& appendState) const { /* do nothing*/ }; - static EntityItemID readEntityItemIDFromBuffer(const unsigned char* data, int bytesLeftToRead, - ReadBitstreamToTreeParams& args); - int readEntityDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args); virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, @@ -182,25 +179,21 @@ class EntityItem : public QObject, public SpatiallyNestable, public ReadWriteLoc const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const { return true; } + virtual bool getRotateForPicking() const { return false; } // attributes applicable to all entity types EntityTypes::EntityType getType() const { return _type; } + QString getUserData() const; + virtual void setUserData(const QString& value); + inline glm::vec3 getCenterPosition(bool& success) const { return getTransformToCenter(success).getTranslation(); } - void setCenterPosition(const glm::vec3& position); const Transform getTransformToCenter(bool& success) const; const Transform getTransformToCenterWithOnlyLocalRotation(bool& success) const; void requiresRecalcBoxes(); - // Hyperlink related getters and setters - QString getHref() const; - void setHref(QString value); - - QString getDescription() const; - void setDescription(const QString& value); - /// Dimensions in meters (0.0 - TREE_SCALE) virtual glm::vec3 getScaledDimensions() const; virtual void setScaledDimensions(const glm::vec3& value); @@ -210,39 +203,14 @@ class EntityItem : public QObject, public SpatiallyNestable, public ReadWriteLoc glm::vec3 getUnscaledDimensions() const; virtual void setUnscaledDimensions(const glm::vec3& value); - void setDensity(float density); float computeMass() const; void setMass(float mass); - float getDensity() const; - bool hasVelocity() const { return getWorldVelocity() != ENTITY_ITEM_ZERO_VEC3; } bool hasLocalVelocity() const { return getLocalVelocity() != ENTITY_ITEM_ZERO_VEC3; } - - glm::vec3 getGravity() const; /// get gravity in meters - void setGravity(const glm::vec3& value); /// gravity in meters bool hasGravity() const { return getGravity() != ENTITY_ITEM_ZERO_VEC3; } - - glm::vec3 getAcceleration() const; /// get acceleration in meters/second/second - void setAcceleration(const glm::vec3& value); /// acceleration in meters/second/second bool hasAcceleration() const { return getAcceleration() != ENTITY_ITEM_ZERO_VEC3; } - float getDamping() const; - void setDamping(float value); - - float getRestitution() const; - void setRestitution(float value); - - float getFriction() const; - void setFriction(float value); - - // lifetime related properties. - float getLifetime() const; /// get the lifetime in seconds for the entity - void setLifetime(float value); /// set the lifetime in seconds for the entity - - quint64 getCreated() const; /// get the created-time in useconds for the entity - void setCreated(quint64 value); /// set the created-time in useconds for the entity - /// is this entity immortal, in that it has no lifetime set, and will exist until manually deleted bool isImmortal() const { return getLifetime() == ENTITY_ITEM_IMMORTAL_LIFETIME; } @@ -263,18 +231,6 @@ class EntityItem : public QObject, public SpatiallyNestable, public ReadWriteLoc virtual AACube getQueryAACube(bool& success) const override; virtual bool shouldPuffQueryAACube() const override; - QString getScript() const; - void setScript(const QString& value); - - quint64 getScriptTimestamp() const; - void setScriptTimestamp(const quint64 value); - - QString getServerScripts() const; - void setServerScripts(const QString& serverScripts); - - QString getCollisionSoundURL() const; - void setCollisionSoundURL(const QString& value); - glm::vec3 getRegistrationPoint() const; /// registration point as ratio of entity /// registration point as ratio of entity virtual void setRegistrationPoint(const glm::vec3& value); // FIXME: this is suspicious! @@ -284,31 +240,10 @@ class EntityItem : public QObject, public SpatiallyNestable, public ReadWriteLoc virtual void setAngularVelocity(const glm::vec3& angularVelocity); - float getAngularDamping() const; - void setAngularDamping(float value); - virtual QString getName() const override; void setName(const QString& value); QString getDebugName(); - bool getVisible() const; - void setVisible(bool value); - - bool isVisibleInSecondaryCamera() const; - void setIsVisibleInSecondaryCamera(bool value); - - RenderLayer getRenderLayer() const; - void setRenderLayer(RenderLayer value); - - PrimitiveMode getPrimitiveMode() const; - void setPrimitiveMode(PrimitiveMode value); - - bool getIgnorePickIntersection() const; - void setIgnorePickIntersection(bool value); - - bool getCanCastShadow() const; - void setCanCastShadow(bool value); - bool getCullWithParent() const; void setCullWithParent(bool value); @@ -320,33 +255,13 @@ class EntityItem : public QObject, public SpatiallyNestable, public ReadWriteLoc bool isChildOfMyAvatar() const; - bool getCollisionless() const; - void setCollisionless(bool value); - - uint16_t getCollisionMask() const; - void setCollisionMask(uint16_t value); - void computeCollisionGroupAndFinalMask(int32_t& group, int32_t& mask) const; - bool getDynamic() const; - void setDynamic(bool value); - virtual bool shouldBePhysical() const { return !isDead() && getShapeType() != SHAPE_TYPE_NONE && !isLocalEntity(); } bool isVisuallyReady() const { return _visuallyReady; } - bool getLocked() const; - void setLocked(bool value); - - QString getUserData() const; - virtual void setUserData(const QString& value); // FIXME: This is suspicious - - QString getPrivateUserData() const; - void setPrivateUserData(const QString& value); - // FIXME not thread safe? - const SimulationOwner& getSimulationOwner() const { return _simulationOwner; } void setSimulationOwner(const QUuid& id, uint8_t priority); - void setSimulationOwner(const SimulationOwner& owner); uint8_t getSimulationPriority() const { return _simulationOwner.getPriority(); } QUuid getSimulatorID() const { return _simulationOwner.getID(); } @@ -363,19 +278,6 @@ class EntityItem : public QObject, public SpatiallyNestable, public ReadWriteLoc bool pendingRelease(uint64_t timestamp) const; bool stillWaitingToTakeOwnership(uint64_t timestamp) const; - bool getCloneable() const; - void setCloneable(bool value); - float getCloneLifetime() const; - void setCloneLifetime(float value); - float getCloneLimit() const; - void setCloneLimit(float value); - bool getCloneDynamic() const; - void setCloneDynamic(bool value); - bool getCloneAvatarEntity() const; - void setCloneAvatarEntity(bool value); - const QUuid getCloneOriginID() const; - void setCloneOriginID(const QUuid& value); - // TODO: get rid of users of getRadius()... float getRadius() const; @@ -486,26 +388,19 @@ class EntityItem : public QObject, public SpatiallyNestable, public ReadWriteLoc void setScriptHasFinishedPreload(bool value); bool isScriptPreloadFinished(); virtual bool isWearable() const; - bool isDomainEntity() const { return _hostType == entity::HostType::DOMAIN; } - bool isAvatarEntity() const { return _hostType == entity::HostType::AVATAR; } + bool isDomainEntity() const { return _entityHostType == entity::HostType::DOMAIN; } + bool isAvatarEntity() const { return _entityHostType == entity::HostType::AVATAR; } bool isMyAvatarEntity() const; - bool isLocalEntity() const { return _hostType == entity::HostType::LOCAL; } - entity::HostType getEntityHostType() const { return _hostType; } - virtual void setEntityHostType(entity::HostType hostType) { _hostType = hostType; } + bool isLocalEntity() const { return _entityHostType == entity::HostType::LOCAL; } // if this entity is an avatar entity, which avatar is it associated with? - QUuid getOwningAvatarID() const { return _owningAvatarID; } QUuid getOwningAvatarIDForProperties() const; - void setOwningAvatarID(const QUuid& owningAvatarID); virtual bool wantsHandControllerPointerEvents() const { return false; } virtual bool wantsKeyboardFocus() const { return false; } virtual void setProxyWindow(QWindow* proxyWindow) {} virtual QObject* getEventHandler() { return nullptr; } - QUuid getLastEditedBy() const { return _lastEditedBy; } - void setLastEditedBy(QUuid value) { _lastEditedBy = value; } - virtual bool matchesJSONFilters(const QJsonObject& jsonFilters) const; virtual bool getMeshes(MeshProxyList& result) { return true; } @@ -550,19 +445,16 @@ class EntityItem : public QObject, public SpatiallyNestable, public ReadWriteLoc bool needsRenderUpdate() const { return _needsRenderUpdate; } void setNeedsRenderUpdate(bool needsRenderUpdate) { _needsRenderUpdate = needsRenderUpdate; } - void setRenderWithZones(const QVector& renderWithZones); - QVector getRenderWithZones() const; bool needsZoneOcclusionUpdate() const { return _needsZoneOcclusionUpdate; } void resetNeedsZoneOcclusionUpdate() { withWriteLock([&] { _needsZoneOcclusionUpdate = false; }); } - void setBillboardMode(BillboardMode value); - BillboardMode getBillboardMode() const; - virtual bool getRotateForPicking() const { return false; } - signals: void spaceUpdate(std::pair data); protected: + +@Base_ENTITY_PROPS@ + QHash _changeHandlers; void somethingChangedNotification(); @@ -581,12 +473,10 @@ class EntityItem : public QObject, public SpatiallyNestable, public ReadWriteLoc // and physics changes quint64 _lastUpdated { 0 }; // last time this entity called update(), this includes animations and non-physics changes quint64 _lastEdited { 0 }; // last official local or remote edit time - QUuid _lastEditedBy { ENTITY_ITEM_DEFAULT_LAST_EDITED_BY }; // id of last editor quint64 _lastBroadcast; // the last time we sent an edit packet about this entity quint64 _lastEditedFromRemote { 0 }; // last time we received and edit from the server quint64 _lastEditedFromRemoteInRemoteTime { 0 }; // last time we received an edit from the server (in server-time-frame) - quint64 _created { 0 }; quint64 _changedOnServer { 0 }; mutable AABox _cachedAABox; @@ -596,24 +486,14 @@ class EntityItem : public QObject, public SpatiallyNestable, public ReadWriteLoc mutable bool _recalcMinAACube { true }; mutable bool _recalcMaxAACube { true }; - float _density { ENTITY_ITEM_DEFAULT_DENSITY }; // kg/m^3 // NOTE: _volumeMultiplier is used to allow some mass properties code exist in the EntityItem base class // rather than in all of the derived classes. If we ever collapse these classes to one we could do it a // different way. float _volumeMultiplier { 1.0f }; - glm::vec3 _gravity { ENTITY_ITEM_DEFAULT_GRAVITY }; - glm::vec3 _acceleration { ENTITY_ITEM_DEFAULT_ACCELERATION }; - float _damping { ENTITY_ITEM_DEFAULT_DAMPING }; - float _restitution { ENTITY_ITEM_DEFAULT_RESTITUTION }; - float _friction { ENTITY_ITEM_DEFAULT_FRICTION }; - float _lifetime { ENTITY_ITEM_DEFAULT_LIFETIME }; - - QString _script { ENTITY_ITEM_DEFAULT_SCRIPT }; /// the value of the script property + QString _loadedScript; /// the value of _script when the last preload signal was sent - quint64 _scriptTimestamp { ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP }; /// the script loaded property used for forced reload bool _scriptPreloadFinished { false }; - QString _serverScripts; /// keep track of time when _serverScripts property was last changed quint64 _serverScriptsChangedTimestamp { ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP }; @@ -621,27 +501,8 @@ class EntityItem : public QObject, public SpatiallyNestable, public ReadWriteLoc // NOTE: on construction we want this to be different from _scriptTimestamp so we intentionally bump it quint64 _loadedScriptTimestamp { ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP + 1 }; - QString _collisionSoundURL { ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL }; glm::vec3 _registrationPoint { ENTITY_ITEM_DEFAULT_REGISTRATION_POINT }; - float _angularDamping { ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING }; - bool _visible { ENTITY_ITEM_DEFAULT_VISIBLE }; - bool _isVisibleInSecondaryCamera { ENTITY_ITEM_DEFAULT_VISIBLE_IN_SECONDARY_CAMERA }; - RenderLayer _renderLayer { RenderLayer::WORLD }; - PrimitiveMode _primitiveMode { PrimitiveMode::SOLID }; - bool _canCastShadow{ ENTITY_ITEM_DEFAULT_CAN_CAST_SHADOW }; - bool _ignorePickIntersection { false }; - bool _collisionless { ENTITY_ITEM_DEFAULT_COLLISIONLESS }; - uint16_t _collisionMask { ENTITY_COLLISION_MASK_DEFAULT }; - bool _dynamic { ENTITY_ITEM_DEFAULT_DYNAMIC }; - bool _locked { ENTITY_ITEM_DEFAULT_LOCKED }; - QString _userData { ENTITY_ITEM_DEFAULT_USER_DATA }; - QString _privateUserData{ ENTITY_ITEM_DEFAULT_PRIVATE_USER_DATA }; - SimulationOwner _simulationOwner; bool _shouldHighlight { false }; - QString _name { ENTITY_ITEM_DEFAULT_NAME }; - QString _href; //Hyperlink href - QString _description; //Hyperlink description - // NOTE: Damping is applied like this: v *= pow(1 - damping, dt) // @@ -687,9 +548,7 @@ class EntityItem : public QObject, public SpatiallyNestable, public ReadWriteLoc QUuid _sourceUUID; /// the server node UUID we came from - entity::HostType _hostType { entity::HostType::DOMAIN }; bool _transitingWithAvatar{ false }; - QUuid _owningAvatarID; // physics related changes from the network to suppress any duplicates and make // sure redundant applications are idempotent @@ -721,23 +580,12 @@ class EntityItem : public QObject, public SpatiallyNestable, public ReadWriteLoc bool _cauterized { false }; // if true, don't draw because it would obscure 1st-person camera - bool _cloneable { ENTITY_ITEM_DEFAULT_CLONEABLE }; - float _cloneLifetime { ENTITY_ITEM_DEFAULT_CLONE_LIFETIME }; - float _cloneLimit { ENTITY_ITEM_DEFAULT_CLONE_LIMIT }; - bool _cloneDynamic { ENTITY_ITEM_DEFAULT_CLONE_DYNAMIC }; - bool _cloneAvatarEntity { ENTITY_ITEM_DEFAULT_CLONE_AVATAR_ENTITY }; - QUuid _cloneOriginID; QVector _cloneIDs; - GrabPropertyGroup _grabProperties; - QHash _grabActions; - QVector _renderWithZones; mutable bool _needsZoneOcclusionUpdate { false }; - BillboardMode _billboardMode { BillboardMode::NONE }; - bool _cullWithParent { false }; mutable bool _needsRenderUpdate { false }; diff --git a/libraries/entities/src/EntityItemGroupProperties.txt b/libraries/entities/src/EntityItemGroupProperties.txt new file mode 100644 index 00000000000..3877f88bd27 --- /dev/null +++ b/libraries/entities/src/EntityItemGroupProperties.txt @@ -0,0 +1,101 @@ +grab +enum:GRAB_GRABBABLE prop:grabbable type:bool default:INITIAL_GRABBABLE, +enum:GRAB_KINEMATIC prop:grabKinematic type:bool default:INITIAL_KINEMATIC, +enum:GRAB_FOLLOWS_CONTROLLER prop:grabFollowsController type:bool default:INITIAL_FOLLOWS_CONTROLLER, +enum:GRAB_TRIGGERABLE prop:triggerable type:bool default:INITIAL_TRIGGERABLE, +enum:GRAB_EQUIPPABLE prop:equippable type:bool default:INITIAL_EQUIPPABLE, +enum:GRAB_DELEGATE_TO_PARENT prop:grabDelegateToParent type:bool default:INITIAL_GRAB_DELEGATE_TO_PARENT, +enum:GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET prop:equippableLeftPosition type:vec3 default:INITIAL_LEFT_EQUIPPABLE_POSITION, +enum:GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET prop:equippableLeftRotation type:quat default:INITIAL_LEFT_EQUIPPABLE_ROTATION, +enum:GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET prop:equippableRightPosition type:vec3 default:INITIAL_RIGHT_EQUIPPABLE_POSITION, +enum:GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET prop:equippableRightRotation type:quat default:INITIAL_RIGHT_EQUIPPABLE_ROTATION, +enum:GRAB_EQUIPPABLE_INDICATOR_URL prop:equippableIndicatorURL type:QString default:"" urlPermission, +enum:GRAB_EQUIPPABLE_INDICATOR_SCALE prop:equippableIndicatorScale type:vec3 default:INITIAL_EQUIPPABLE_INDICATOR_SCALE, +enum:GRAB_EQUIPPABLE_INDICATOR_OFFSET prop:equippableIndicatorOffset type:vec3 default:INITIAL_EQUIPPABLE_INDICATOR_OFFSET, +pulse +enum:PULSE_MIN prop:min type:float default:0.0f, +enum:PULSE_MAX prop:max type:float default:1.0f, +enum:PULSE_PERIOD prop:period type:float default:1.0f, +enum:PULSE_COLOR_MODE prop:colorMode type:PulseMode default:PulseMode::NONE enum, +enum:PULSE_ALPHA_MODE prop:alphaMode type:PulseMode default:PulseMode::NONE enum, +animation +enum:ANIMATION_URL prop:url type:QString default:"" urlPermission, +enum:ANIMATION_FPS prop:fps type:float default:30.0f, +enum:ANIMATION_FRAME_INDEX prop:currentFrame type:float default:0.0f, +enum:ANIMATION_PLAYING prop:running type:bool default:false, +enum:ANIMATION_LOOP prop:loop type:bool default:true, +enum:ANIMATION_FIRST_FRAME prop:firstFrame type:float default:0.0f, +enum:ANIMATION_LAST_FRAME prop:lastFrame type:float default:MAXIMUM_POSSIBLE_FRAME, +enum:ANIMATION_HOLD prop:hold type:bool default:false, +enum:ANIMATION_ALLOW_TRANSLATION prop:allowTranslation type:bool default:true, +enum:ANIMATION_SMOOTH_FRAMES prop:smoothFrames type:bool default:true, +keyLight +enum:KEYLIGHT_COLOR prop:color type:u8vec3Color default:DEFAULT_KEYLIGHT_COLOR, +enum:KEYLIGHT_INTENSITY prop:intensity type:float default:DEFAULT_KEYLIGHT_INTENSITY, +enum:KEYLIGHT_DIRECTION prop:direction type:vec3 default:DEFAULT_KEYLIGHT_DIRECTION, +enum:KEYLIGHT_CAST_SHADOW prop:castShadows type:bool default:DEFAULT_KEYLIGHT_CAST_SHADOWS, +enum:KEYLIGHT_SHADOW_BIAS prop:shadowBias type:float default:DEFAULT_KEYLIGHT_SHADOW_BIAS min:0.0f max:1.0f, +enum:KEYLIGHT_SHADOW_MAX_DISTANCE prop:shadowMaxDistance type:float default:DEFAULT_KEYLIGHT_SHADOW_MAX_DISTANCE min:1.0f max:250.0f, +ambientLight +enum:AMBIENT_LIGHT_INTENSITY prop:ambientIntensity type:float default:DEFAULT_AMBIENT_LIGHT_INTENSITY, +enum:AMBIENT_LIGHT_URL prop:ambientURL type:QString default:"" urlPermission, +enum:AMBIENT_LIGHT_COLOR prop:ambientColor type:u8vec3Color default:DEFAULT_COLOR, +skybox +enum:SKYBOX_COLOR prop:color type:u8vec3Color default:DEFAULT_COLOR, +enum:SKYBOX_URL prop:url type:QString default:"" urlPermission, +haze +enum:HAZE_RANGE prop:hazeRange type:float default:INITIAL_HAZE_RANGE, +enum:HAZE_COLOR prop:hazeColor type:u8vec3Color default:initialHazeColor, +enum:HAZE_GLARE_COLOR prop:hazeGlareColor type:u8vec3Color default:initialHazeGlareColor, +enum:HAZE_ENABLE_GLARE prop:hazeEnableGlare type:bool default:false, +enum:HAZE_GLARE_ANGLE prop:hazeGlareAngle type:float default:INITIAL_HAZE_GLARE_ANGLE, +enum:HAZE_ALTITUDE_EFFECT prop:hazeAltitudeEffect type:bool default:false, +enum:HAZE_CEILING prop:hazeCeiling type:float default:INITIAL_HAZE_BASE_REFERENCE+INITIAL_HAZE_HEIGHT, +enum:HAZE_BASE_REF prop:hazeBaseRef type:float default:INITIAL_HAZE_BASE_REFERENCE, +enum:HAZE_BACKGROUND_BLEND prop:hazeBackgroundBlend type:float default:INITIAL_HAZE_BACKGROUND_BLEND, +enum:PROP_HAZE_ATTENUATE_KEYLIGHT prop:hazeAttenuateKeyLight type:bool default:false, +enum:PROP_HAZE_KEYLIGHT_RANGE prop:hazeKeyLightRange type:float default:INITIAL_KEY_LIGHT_RANGE, +enum:PROP_HAZE_KEYLIGHT_ALTITUDE prop:hazeKeyLightAltitude type:float default:INITIAL_KEY_LIGHT_ALTITUDE, +bloom +enum:BLOOM_INTENSITY prop:bloomIntensity type:float default:INITIAL_BLOOM_INTENSITY, +enum:BLOOM_THRESHOLD prop:bloomThreshold type:float default:INITIAL_BLOOM_THRESHOLD, +enum:BLOOM_SIZE prop:bloomSize type:float default:INITIAL_BLOOM_SIZE, +audio type:ZoneAudio +enum:REVERB_ENABLED prop:reverbEnabled type:bool default:false, +enum:REVERB_TIME prop:reverbTime type:float default:1.0f, +enum:REVERB_WET_LEVEL prop:reverbWetLevel type:float default:50.0f, +enum:LISTENER_ZONES prop:listenerZones type:qVectorQUuid default:QVector(), +enum:LISTENER_ATTENUATION_COEFFICIENTS prop:listenerAttenuationCoefficients type:qVectorFloat default:QVector(), +tonemapping +enum:TONEMAPPING_CURVE prop:curve type:TonemappingCurve default:TonemappingCurve::SRGB enum, +enum:TONEMAPPING_EXPOSURE prop:exposure type:float default:0.0f min:-4.0f max:4.0f, +ambientOcclusion +enum:AMBIENT_OCCLUSION_TECHNIQUE prop:technique type:AmbientOcclusionTechnique default:AmbientOcclusionTechnique::HBAO enum, +enum:AMBIENT_OCCLUSION_JITTER prop:jitter type:bool default:false, +enum:AMBIENT_OCCLUSION_RESOLUTION_LEVEL prop:resolutionLevel type:uint8_t default:2 min:0 max:4, +enum:AMBIENT_OCCLUSION_EDGE_SHARPNESS prop:edgeSharpness type:float default:1.0f min:0.0f max:1.0f, +enum:AMBIENT_OCCLUSION_BLUR_RADIUS prop:blurRadius type:uint8_t default:4 min:0 max:15, +enum:AMBIENT_OCCLUSION_AO_RADIUS prop:aoRadius type:float default:1.0f min:0.01f max:2.0f, +enum:AMBIENT_OCCLUSION_AO_OBSCURANCE_LEVEL prop:aoObscuranceLevel type:float default:0.5f min:0.01f max:1.0f, +enum:AMBIENT_OCCLUSION_AO_FALLOFF_ANGLE prop:aoFalloffAngle type:float default:0.25f min:0.0f max:1.0f, +enum:AMBIENT_OCCLUSION_AO_SAMPLING_AMOUNT prop:aoSamplingAmount type:float default:0.5f min:0.0f max:1.0f, +enum:AMBIENT_OCCLUSION_SSAO_NUM_SPIRAL_TURNS prop:ssaoNumSpiralTurns type:float default:7.0f min:0.0f max:10.0f, +ring type:RingGizmo +enum:START_ANGLE prop:startAngle type:float default:0.0f min:RingGizmoPropertyGroup::MIN_ANGLE max:RingGizmoPropertyGroup::MAX_ANGLE, +enum:END_ANGLE prop:endAngle type:float default:360.0f min:RingGizmoPropertyGroup::MIN_ANGLE max:RingGizmoPropertyGroup::MAX_ANGLE, +enum:INNER_RADIUS prop:innerRadius type:float default:0.0f min:RingGizmoPropertyGroup::MIN_RADIUS max:RingGizmoPropertyGroup::MAX_RADIUS, +enum:INNER_START_COLOR prop:innerStartColor type:u8vec3Color default:ENTITY_ITEM_DEFAULT_COLOR, +enum:INNER_END_COLOR prop:innerEndColor type:u8vec3Color default:ENTITY_ITEM_DEFAULT_COLOR, +enum:OUTER_START_COLOR prop:outerStartColor type:u8vec3Color default:ENTITY_ITEM_DEFAULT_COLOR, +enum:OUTER_END_COLOR prop:outerEndColor type:u8vec3Color default:ENTITY_ITEM_DEFAULT_COLOR, +enum:INNER_START_ALPHA prop:innerStartAlpha type:float default:ENTITY_ITEM_DEFAULT_ALPHA min:RingGizmoPropertyGroup::MIN_ALPHA max:RingGizmoPropertyGroup::MAX_ALPHA, +enum:INNER_END_ALPHA prop:innerEndAlpha type:float default:ENTITY_ITEM_DEFAULT_ALPHA min:RingGizmoPropertyGroup::MIN_ALPHA max:RingGizmoPropertyGroup::MAX_ALPHA, +enum:OUTER_START_ALPHA prop:outerStartAlpha type:float default:ENTITY_ITEM_DEFAULT_ALPHA min:RingGizmoPropertyGroup::MIN_ALPHA max:RingGizmoPropertyGroup::MAX_ALPHA, +enum:OUTER_END_ALPHA prop:outerEndAlpha type:float default:ENTITY_ITEM_DEFAULT_ALPHA min:RingGizmoPropertyGroup::MIN_ALPHA max:RingGizmoPropertyGroup::MAX_ALPHA, +enum:HAS_TICK_MARKS prop:hasTickMarks type:bool default:false, +enum:MAJOR_TICK_MARKS_ANGLE prop:majorTickMarksAngle type:float default:0.0f min:RingGizmoPropertyGroup::MIN_ANGLE max:RingGizmoPropertyGroup::MAX_ANGLE, +enum:MINOR_TICK_MARKS_ANGLE prop:minorTickMarksAngle type:float default:0.0f min:RingGizmoPropertyGroup::MIN_ANGLE max:RingGizmoPropertyGroup::MAX_ANGLE, +enum:MAJOR_TICK_MARKS_LENGTH prop:majorTickMarksLength type:float default:0.0f, +enum:MINOR_TICK_MARKS_LENGTH prop:minorTickMarksLength type:float default:0.0f, +enum:MAJOR_TICK_MARKS_COLOR prop:majorTickMarksColor type:u8vec3Color default:ENTITY_ITEM_DEFAULT_COLOR, +enum:MINOR_TICK_MARKS_COLOR prop:minorTickMarksColor type:u8vec3Color default:ENTITY_ITEM_DEFAULT_COLOR, \ No newline at end of file diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp deleted file mode 100644 index 0f57ee333d1..00000000000 --- a/libraries/entities/src/EntityItemProperties.cpp +++ /dev/null @@ -1,4966 +0,0 @@ -// -// EntityItemProperties.cpp -// libraries/entities/src -// -// Created by Brad Hefta-Gaub on 12/4/13. -// Copyright 2013 High Fidelity, Inc. -// Copyright 2020 Vircadia contributors. -// Copyright 2022-2023 Overte e.V. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// SPDX-License-Identifier: Apache-2.0 -// - -#include "EntityItemProperties.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "EntitiesLogging.h" -#include "EntityItem.h" -#include "ModelEntityItem.h" -#include "PolyLineEntityItem.h" -#include "WarningsSuppression.h" - -AnimationPropertyGroup EntityItemProperties::_staticAnimation; -SkyboxPropertyGroup EntityItemProperties::_staticSkybox; -HazePropertyGroup EntityItemProperties::_staticHaze; -BloomPropertyGroup EntityItemProperties::_staticBloom; -KeyLightPropertyGroup EntityItemProperties::_staticKeyLight; -AmbientLightPropertyGroup EntityItemProperties::_staticAmbientLight; -GrabPropertyGroup EntityItemProperties::_staticGrab; -PulsePropertyGroup EntityItemProperties::_staticPulse; -RingGizmoPropertyGroup EntityItemProperties::_staticRing; - -EntityPropertyList PROP_LAST_ITEM = (EntityPropertyList)(PROP_AFTER_LAST_ITEM - 1); - -EntityItemProperties::EntityItemProperties(EntityPropertyFlags desiredProperties) : - _id(UNKNOWN_ENTITY_ID), - _idSet(false), - _lastEdited(0), - _type(EntityTypes::Unknown), - - _defaultSettings(true), - _naturalDimensions(1.0f, 1.0f, 1.0f), - _naturalPosition(0.0f, 0.0f, 0.0f), - _desiredProperties(desiredProperties) -{ - -} - -void EntityItemProperties::calculateNaturalPosition(const vec3& min, const vec3& max) { - vec3 halfDimension = (max - min) / 2.0f; - _naturalPosition = max - halfDimension; -} - -void EntityItemProperties::debugDump() const { - qCDebug(entities) << "EntityItemProperties..."; - qCDebug(entities) << " _type=" << EntityTypes::getEntityTypeName(_type); - qCDebug(entities) << " _id=" << _id; - qCDebug(entities) << " _idSet=" << _idSet; - qCDebug(entities) << " _position=" << _position.x << "," << _position.y << "," << _position.z; - qCDebug(entities) << " _dimensions=" << getDimensions(); - qCDebug(entities) << " _modelURL=" << _modelURL; - qCDebug(entities) << " _compoundShapeURL=" << _compoundShapeURL; - - getAnimation().debugDump(); - getSkybox().debugDump(); - getHaze().debugDump(); - getKeyLight().debugDump(); - getAmbientLight().debugDump(); - getBloom().debugDump(); - getGrab().debugDump(); - - qCDebug(entities) << " changed properties..."; - EntityPropertyFlags props = getChangedProperties(); - props.debugDumpBits(); -} - -void EntityItemProperties::setLastEdited(quint64 usecTime) { - _lastEdited = usecTime > _created ? usecTime : _created; -} - -bool EntityItemProperties::constructFromBuffer(const unsigned char* data, int dataLength) { - ReadBitstreamToTreeParams args; - EntityItemPointer tempEntity = EntityTypes::constructEntityItem(data, dataLength); - if (!tempEntity) { - return false; - } - tempEntity->readEntityDataFromBuffer(data, dataLength, args); - (*this) = tempEntity->getProperties(); - return true; -} - -inline void addShapeType(QHash& lookup, ShapeType type) { lookup[ShapeInfo::getNameForShapeType(type)] = type; } -QHash stringToShapeTypeLookup = [] { - QHash toReturn; - addShapeType(toReturn, SHAPE_TYPE_NONE); - addShapeType(toReturn, SHAPE_TYPE_BOX); - addShapeType(toReturn, SHAPE_TYPE_SPHERE); - addShapeType(toReturn, SHAPE_TYPE_CAPSULE_X); - addShapeType(toReturn, SHAPE_TYPE_CAPSULE_Y); - addShapeType(toReturn, SHAPE_TYPE_CAPSULE_Z); - addShapeType(toReturn, SHAPE_TYPE_CYLINDER_X); - addShapeType(toReturn, SHAPE_TYPE_CYLINDER_Y); - addShapeType(toReturn, SHAPE_TYPE_CYLINDER_Z); - addShapeType(toReturn, SHAPE_TYPE_HULL); - addShapeType(toReturn, SHAPE_TYPE_PLANE); - addShapeType(toReturn, SHAPE_TYPE_COMPOUND); - addShapeType(toReturn, SHAPE_TYPE_SIMPLE_HULL); - addShapeType(toReturn, SHAPE_TYPE_SIMPLE_COMPOUND); - addShapeType(toReturn, SHAPE_TYPE_STATIC_MESH); - addShapeType(toReturn, SHAPE_TYPE_ELLIPSOID); - addShapeType(toReturn, SHAPE_TYPE_CIRCLE); - return toReturn; -}(); -QString EntityItemProperties::getShapeTypeAsString() const { return ShapeInfo::getNameForShapeType(_shapeType); } -void EntityItemProperties::setShapeTypeFromString(const QString& shapeName) { - auto shapeTypeItr = stringToShapeTypeLookup.find(shapeName.toLower()); - if (shapeTypeItr != stringToShapeTypeLookup.end()) { - _shapeType = shapeTypeItr.value(); - _shapeTypeChanged = true; - } -} - -inline void addMaterialMappingMode(QHash& lookup, MaterialMappingMode mode) { lookup[MaterialMappingModeHelpers::getNameForMaterialMappingMode(mode)] = mode; } -const QHash stringToMaterialMappingModeLookup = [] { - QHash toReturn; - addMaterialMappingMode(toReturn, UV); - addMaterialMappingMode(toReturn, PROJECTED); - return toReturn; -}(); -QString EntityItemProperties::getMaterialMappingModeAsString() const { return MaterialMappingModeHelpers::getNameForMaterialMappingMode(_materialMappingMode); } -void EntityItemProperties::setMaterialMappingModeFromString(const QString& materialMappingMode) { - auto materialMappingModeItr = stringToMaterialMappingModeLookup.find(materialMappingMode.toLower()); - if (materialMappingModeItr != stringToMaterialMappingModeLookup.end()) { - _materialMappingMode = materialMappingModeItr.value(); - _materialMappingModeChanged = true; - } -} - -inline void addBillboardMode(QHash& lookup, BillboardMode mode) { lookup[BillboardModeHelpers::getNameForBillboardMode(mode)] = mode; } -const QHash stringToBillboardModeLookup = [] { - QHash toReturn; - addBillboardMode(toReturn, BillboardMode::NONE); - addBillboardMode(toReturn, BillboardMode::YAW); - addBillboardMode(toReturn, BillboardMode::FULL); - return toReturn; -}(); -QString EntityItemProperties::getBillboardModeAsString() const { return BillboardModeHelpers::getNameForBillboardMode(_billboardMode); } -void EntityItemProperties::setBillboardModeFromString(const QString& billboardMode) { - auto billboardModeItr = stringToBillboardModeLookup.find(billboardMode.toLower()); - if (billboardModeItr != stringToBillboardModeLookup.end()) { - _billboardMode = billboardModeItr.value(); - _billboardModeChanged = true; - } -} - -inline void addRenderLayer(QHash& lookup, RenderLayer mode) { lookup[RenderLayerHelpers::getNameForRenderLayer(mode)] = mode; } -const QHash stringToRenderLayerLookup = [] { - QHash toReturn; - addRenderLayer(toReturn, RenderLayer::WORLD); - addRenderLayer(toReturn, RenderLayer::FRONT); - addRenderLayer(toReturn, RenderLayer::HUD); - return toReturn; -}(); -QString EntityItemProperties::getRenderLayerAsString() const { return RenderLayerHelpers::getNameForRenderLayer(_renderLayer); } -void EntityItemProperties::setRenderLayerFromString(const QString& renderLayer) { - auto renderLayerItr = stringToRenderLayerLookup.find(renderLayer.toLower()); - if (renderLayerItr != stringToRenderLayerLookup.end()) { - _renderLayer = renderLayerItr.value(); - _renderLayerChanged = true; - } -} - -inline void addPrimitiveMode(QHash& lookup, PrimitiveMode mode) { lookup[PrimitiveModeHelpers::getNameForPrimitiveMode(mode)] = mode; } -const QHash stringToPrimitiveModeLookup = [] { - QHash toReturn; - addPrimitiveMode(toReturn, PrimitiveMode::SOLID); - addPrimitiveMode(toReturn, PrimitiveMode::LINES); - return toReturn; -}(); -QString EntityItemProperties::getPrimitiveModeAsString() const { return PrimitiveModeHelpers::getNameForPrimitiveMode(_primitiveMode); } -void EntityItemProperties::setPrimitiveModeFromString(const QString& primitiveMode) { - auto primitiveModeItr = stringToPrimitiveModeLookup.find(primitiveMode.toLower()); - if (primitiveModeItr != stringToPrimitiveModeLookup.end()) { - _primitiveMode = primitiveModeItr.value(); - _primitiveModeChanged = true; - } -} - -inline void addWebInputMode(QHash& lookup, WebInputMode mode) { lookup[WebInputModeHelpers::getNameForWebInputMode(mode)] = mode; } -const QHash stringToWebInputModeLookup = [] { - QHash toReturn; - addWebInputMode(toReturn, WebInputMode::TOUCH); - addWebInputMode(toReturn, WebInputMode::MOUSE); - return toReturn; -}(); -QString EntityItemProperties::getInputModeAsString() const { return WebInputModeHelpers::getNameForWebInputMode(_inputMode); } -void EntityItemProperties::setInputModeFromString(const QString& webInputMode) { - auto webInputModeItr = stringToWebInputModeLookup.find(webInputMode.toLower()); - if (webInputModeItr != stringToWebInputModeLookup.end()) { - _inputMode = webInputModeItr.value(); - _inputModeChanged = true; - } -} - -inline void addGizmoType(QHash& lookup, GizmoType mode) { lookup[GizmoTypeHelpers::getNameForGizmoType(mode)] = mode; } -const QHash stringToGizmoTypeLookup = [] { - QHash toReturn; - addGizmoType(toReturn, GizmoType::RING); - return toReturn; -}(); -QString EntityItemProperties::getGizmoTypeAsString() const { return GizmoTypeHelpers::getNameForGizmoType(_gizmoType); } -void EntityItemProperties::setGizmoTypeFromString(const QString& gizmoType) { - auto gizmoTypeItr = stringToGizmoTypeLookup.find(gizmoType.toLower()); - if (gizmoTypeItr != stringToGizmoTypeLookup.end()) { - _gizmoType = gizmoTypeItr.value(); - _gizmoTypeChanged = true; - } -} - -inline void addComponentMode(QHash& lookup, ComponentMode mode) { lookup[ComponentModeHelpers::getNameForComponentMode(mode)] = mode; } -const QHash stringToComponentMode = [] { - QHash toReturn; - addComponentMode(toReturn, ComponentMode::COMPONENT_MODE_INHERIT); - addComponentMode(toReturn, ComponentMode::COMPONENT_MODE_DISABLED); - addComponentMode(toReturn, ComponentMode::COMPONENT_MODE_ENABLED); - return toReturn; -}(); -QString EntityItemProperties::getComponentModeAsString(uint32_t mode) { return ComponentModeHelpers::getNameForComponentMode((ComponentMode)mode); } -QString EntityItemProperties::getSkyboxModeAsString() const { return getComponentModeAsString(_skyboxMode); } -QString EntityItemProperties::getKeyLightModeAsString() const { return getComponentModeAsString(_keyLightMode); } -QString EntityItemProperties::getAmbientLightModeAsString() const { return getComponentModeAsString(_ambientLightMode); } -QString EntityItemProperties::getHazeModeAsString() const { return getComponentModeAsString(_hazeMode); } -QString EntityItemProperties::getBloomModeAsString() const { return getComponentModeAsString(_bloomMode); } -void EntityItemProperties::setSkyboxModeFromString(const QString& mode) { - auto modeItr = stringToComponentMode.find(mode.toLower()); - if (modeItr != stringToComponentMode.end()) { - _skyboxMode = modeItr.value(); - _skyboxModeChanged = true; - } -} -void EntityItemProperties::setKeyLightModeFromString(const QString& mode) { - auto modeItr = stringToComponentMode.find(mode.toLower()); - if (modeItr != stringToComponentMode.end()) { - _keyLightMode = modeItr.value(); - _keyLightModeChanged = true; - } -} -void EntityItemProperties::setAmbientLightModeFromString(const QString& mode) { - auto modeItr = stringToComponentMode.find(mode.toLower()); - if (modeItr != stringToComponentMode.end()) { - _ambientLightMode = modeItr.value(); - _ambientLightModeChanged = true; - } -} -void EntityItemProperties::setHazeModeFromString(const QString& mode) { - auto modeItr = stringToComponentMode.find(mode.toLower()); - if (modeItr != stringToComponentMode.end()) { - _hazeMode = modeItr.value(); - _hazeModeChanged = true; - } -} -void EntityItemProperties::setBloomModeFromString(const QString& mode) { - auto modeItr = stringToComponentMode.find(mode.toLower()); - if (modeItr != stringToComponentMode.end()) { - _bloomMode = modeItr.value(); - _bloomModeChanged = true; - } -} - -inline void addAvatarPriorityMode(QHash& lookup, AvatarPriorityMode mode) { lookup[AvatarPriorityModeHelpers::getNameForAvatarPriorityMode(mode)] = mode; } -const QHash stringToAvatarPriority = [] { - QHash toReturn; - addAvatarPriorityMode(toReturn, AvatarPriorityMode::AVATAR_PRIORITY_INHERIT); - addAvatarPriorityMode(toReturn, AvatarPriorityMode::AVATAR_PRIORITY_CROWD); - addAvatarPriorityMode(toReturn, AvatarPriorityMode::AVATAR_PRIORITY_HERO); - return toReturn; -}(); -QString EntityItemProperties::getAvatarPriorityAsString() const { return AvatarPriorityModeHelpers::getNameForAvatarPriorityMode((AvatarPriorityMode)_avatarPriority); } -void EntityItemProperties::setAvatarPriorityFromString(const QString& mode) { - auto modeItr = stringToAvatarPriority.find(mode.toLower()); - if (modeItr != stringToAvatarPriority.end()) { - _avatarPriority = modeItr.value(); - _avatarPriorityChanged = true; - } -} - -QString EntityItemProperties::getScreenshareAsString() const { return getComponentModeAsString(_screenshare); } -void EntityItemProperties::setScreenshareFromString(const QString& mode) { - auto modeItr = stringToComponentMode.find(mode.toLower()); - if (modeItr != stringToComponentMode.end()) { - _screenshare = modeItr.value(); - _screenshareChanged = true; - } -} - -inline void addTextEffect(QHash& lookup, TextEffect effect) { lookup[TextEffectHelpers::getNameForTextEffect(effect)] = effect; } -const QHash stringToTextEffectLookup = [] { - QHash toReturn; - addTextEffect(toReturn, TextEffect::NO_EFFECT); - addTextEffect(toReturn, TextEffect::OUTLINE_EFFECT); - addTextEffect(toReturn, TextEffect::OUTLINE_WITH_FILL_EFFECT); - addTextEffect(toReturn, TextEffect::SHADOW_EFFECT); - return toReturn; -}(); -QString EntityItemProperties::getTextEffectAsString() const { return TextEffectHelpers::getNameForTextEffect(_textEffect); } -void EntityItemProperties::setTextEffectFromString(const QString& effect) { - auto textEffectItr = stringToTextEffectLookup.find(effect.toLower()); - if (textEffectItr != stringToTextEffectLookup.end()) { - _textEffect = textEffectItr.value(); - _textEffectChanged = true; - } -} - -inline void addTextAlignment(QHash& lookup, TextAlignment alignment) { lookup[TextAlignmentHelpers::getNameForTextAlignment(alignment)] = alignment; } -const QHash stringToTextAlignmentLookup = [] { - QHash toReturn; - addTextAlignment(toReturn, TextAlignment::LEFT); - addTextAlignment(toReturn, TextAlignment::CENTER); - addTextAlignment(toReturn, TextAlignment::RIGHT); - return toReturn; -}(); -QString EntityItemProperties::getAlignmentAsString() const { return TextAlignmentHelpers::getNameForTextAlignment(_alignment); } -void EntityItemProperties::setAlignmentFromString(const QString& alignment) { - auto textAlignmentItr = stringToTextAlignmentLookup.find(alignment.toLower()); - if (textAlignmentItr != stringToTextAlignmentLookup.end()) { - _alignment = textAlignmentItr.value(); - _alignmentChanged = true; - } -} - -QString getCollisionGroupAsString(uint16_t group) { - switch (group) { - case USER_COLLISION_GROUP_DYNAMIC: - return "dynamic"; - case USER_COLLISION_GROUP_STATIC: - return "static"; - case USER_COLLISION_GROUP_KINEMATIC: - return "kinematic"; - case USER_COLLISION_GROUP_MY_AVATAR: - return "myAvatar"; - case USER_COLLISION_GROUP_OTHER_AVATAR: - return "otherAvatar"; - }; - return ""; -} - -uint16_t getCollisionGroupAsBitMask(const QStringRef& name) { - if (0 == name.compare(QString("dynamic"))) { - return USER_COLLISION_GROUP_DYNAMIC; - } else if (0 == name.compare(QString("static"))) { - return USER_COLLISION_GROUP_STATIC; - } else if (0 == name.compare(QString("kinematic"))) { - return USER_COLLISION_GROUP_KINEMATIC; - } else if (0 == name.compare(QString("myAvatar"))) { - return USER_COLLISION_GROUP_MY_AVATAR; - } else if (0 == name.compare(QString("otherAvatar"))) { - return USER_COLLISION_GROUP_OTHER_AVATAR; - } - return 0; -} - -QString EntityItemProperties::getCollisionMaskAsString() const { - QString maskString(""); - for (int i = 0; i < NUM_USER_COLLISION_GROUPS; ++i) { - uint16_t group = 0x0001 << i; - if (group & _collisionMask) { - maskString.append(getCollisionGroupAsString(group)); - maskString.append(','); - } - } - return maskString; -} - -void EntityItemProperties::setCollisionMaskFromString(const QString& maskString) { - QVector groups = maskString.splitRef(','); - uint16_t mask = 0x0000; - for (auto groupName : groups) { - mask |= getCollisionGroupAsBitMask(groupName); - } - _collisionMask = mask; - _collisionMaskChanged = true; -} - -QString EntityItemProperties::getEntityHostTypeAsString() const { - switch (_entityHostType) { - case entity::HostType::DOMAIN: - return "domain"; - case entity::HostType::AVATAR: - return "avatar"; - case entity::HostType::LOCAL: - return "local"; - default: - return ""; - } -} - -void EntityItemProperties::setEntityHostTypeFromString(const QString& entityHostType) { - if (entityHostType == "domain") { - _entityHostType = entity::HostType::DOMAIN; - } else if (entityHostType == "avatar") { - _entityHostType = entity::HostType::AVATAR; - } else if (entityHostType == "local") { - _entityHostType = entity::HostType::LOCAL; - } -} - -EntityPropertyFlags EntityItemProperties::getChangedProperties() const { - EntityPropertyFlags changedProperties; - - // Core - CHECK_PROPERTY_CHANGE(PROP_SIMULATION_OWNER, simulationOwner); - CHECK_PROPERTY_CHANGE(PROP_PARENT_ID, parentID); - CHECK_PROPERTY_CHANGE(PROP_PARENT_JOINT_INDEX, parentJointIndex); - CHECK_PROPERTY_CHANGE(PROP_VISIBLE, visible); - CHECK_PROPERTY_CHANGE(PROP_NAME, name); - CHECK_PROPERTY_CHANGE(PROP_LOCKED, locked); - CHECK_PROPERTY_CHANGE(PROP_USER_DATA, userData); - CHECK_PROPERTY_CHANGE(PROP_PRIVATE_USER_DATA, privateUserData); - CHECK_PROPERTY_CHANGE(PROP_HREF, href); - CHECK_PROPERTY_CHANGE(PROP_DESCRIPTION, description); - CHECK_PROPERTY_CHANGE(PROP_POSITION, position); - CHECK_PROPERTY_CHANGE(PROP_DIMENSIONS, dimensions); - CHECK_PROPERTY_CHANGE(PROP_ROTATION, rotation); - CHECK_PROPERTY_CHANGE(PROP_REGISTRATION_POINT, registrationPoint); - CHECK_PROPERTY_CHANGE(PROP_CREATED, created); - CHECK_PROPERTY_CHANGE(PROP_LAST_EDITED_BY, lastEditedBy); - CHECK_PROPERTY_CHANGE(PROP_ENTITY_HOST_TYPE, entityHostType); - CHECK_PROPERTY_CHANGE(PROP_OWNING_AVATAR_ID, owningAvatarID); - CHECK_PROPERTY_CHANGE(PROP_QUERY_AA_CUBE, queryAACube); - CHECK_PROPERTY_CHANGE(PROP_CAN_CAST_SHADOW, canCastShadow); - CHECK_PROPERTY_CHANGE(PROP_VISIBLE_IN_SECONDARY_CAMERA, isVisibleInSecondaryCamera); - CHECK_PROPERTY_CHANGE(PROP_RENDER_LAYER, renderLayer); - CHECK_PROPERTY_CHANGE(PROP_PRIMITIVE_MODE, primitiveMode); - CHECK_PROPERTY_CHANGE(PROP_IGNORE_PICK_INTERSECTION, ignorePickIntersection); - CHECK_PROPERTY_CHANGE(PROP_RENDER_WITH_ZONES, renderWithZones); - CHECK_PROPERTY_CHANGE(PROP_BILLBOARD_MODE, billboardMode); - changedProperties += _grab.getChangedProperties(); - - // Physics - CHECK_PROPERTY_CHANGE(PROP_DENSITY, density); - CHECK_PROPERTY_CHANGE(PROP_VELOCITY, velocity); - CHECK_PROPERTY_CHANGE(PROP_ANGULAR_VELOCITY, angularVelocity); - CHECK_PROPERTY_CHANGE(PROP_GRAVITY, gravity); - CHECK_PROPERTY_CHANGE(PROP_ACCELERATION, acceleration); - CHECK_PROPERTY_CHANGE(PROP_DAMPING, damping); - CHECK_PROPERTY_CHANGE(PROP_ANGULAR_DAMPING, angularDamping); - CHECK_PROPERTY_CHANGE(PROP_RESTITUTION, restitution); - CHECK_PROPERTY_CHANGE(PROP_FRICTION, friction); - CHECK_PROPERTY_CHANGE(PROP_LIFETIME, lifetime); - CHECK_PROPERTY_CHANGE(PROP_COLLISIONLESS, collisionless); - CHECK_PROPERTY_CHANGE(PROP_COLLISION_MASK, collisionMask); - CHECK_PROPERTY_CHANGE(PROP_DYNAMIC, dynamic); - CHECK_PROPERTY_CHANGE(PROP_COLLISION_SOUND_URL, collisionSoundURL); - CHECK_PROPERTY_CHANGE(PROP_ACTION_DATA, actionData); - - // Cloning - CHECK_PROPERTY_CHANGE(PROP_CLONEABLE, cloneable); - CHECK_PROPERTY_CHANGE(PROP_CLONE_LIFETIME, cloneLifetime); - CHECK_PROPERTY_CHANGE(PROP_CLONE_LIMIT, cloneLimit); - CHECK_PROPERTY_CHANGE(PROP_CLONE_DYNAMIC, cloneDynamic); - CHECK_PROPERTY_CHANGE(PROP_CLONE_AVATAR_ENTITY, cloneAvatarEntity); - CHECK_PROPERTY_CHANGE(PROP_CLONE_ORIGIN_ID, cloneOriginID); - - // Scripts - CHECK_PROPERTY_CHANGE(PROP_SCRIPT, script); - CHECK_PROPERTY_CHANGE(PROP_SCRIPT_TIMESTAMP, scriptTimestamp); - CHECK_PROPERTY_CHANGE(PROP_SERVER_SCRIPTS, serverScripts); - - // Location data for scripts - CHECK_PROPERTY_CHANGE(PROP_LOCAL_POSITION, localPosition); - CHECK_PROPERTY_CHANGE(PROP_LOCAL_ROTATION, localRotation); - CHECK_PROPERTY_CHANGE(PROP_LOCAL_VELOCITY, localVelocity); - CHECK_PROPERTY_CHANGE(PROP_LOCAL_ANGULAR_VELOCITY, localAngularVelocity); - CHECK_PROPERTY_CHANGE(PROP_LOCAL_DIMENSIONS, localDimensions); - - // Common - CHECK_PROPERTY_CHANGE(PROP_SHAPE_TYPE, shapeType); - CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL); - CHECK_PROPERTY_CHANGE(PROP_COLOR, color); - CHECK_PROPERTY_CHANGE(PROP_ALPHA, alpha); - changedProperties += _pulse.getChangedProperties(); - CHECK_PROPERTY_CHANGE(PROP_TEXTURES, textures); - - // Particles - CHECK_PROPERTY_CHANGE(PROP_MAX_PARTICLES, maxParticles); - CHECK_PROPERTY_CHANGE(PROP_LIFESPAN, lifespan); - CHECK_PROPERTY_CHANGE(PROP_EMITTING_PARTICLES, isEmitting); - CHECK_PROPERTY_CHANGE(PROP_EMIT_RATE, emitRate); - CHECK_PROPERTY_CHANGE(PROP_EMIT_SPEED, emitSpeed); - CHECK_PROPERTY_CHANGE(PROP_SPEED_SPREAD, speedSpread); - CHECK_PROPERTY_CHANGE(PROP_EMIT_ORIENTATION, emitOrientation); - CHECK_PROPERTY_CHANGE(PROP_EMIT_DIMENSIONS, emitDimensions); - CHECK_PROPERTY_CHANGE(PROP_EMIT_RADIUS_START, emitRadiusStart); - CHECK_PROPERTY_CHANGE(PROP_POLAR_START, polarStart); - CHECK_PROPERTY_CHANGE(PROP_POLAR_FINISH, polarFinish); - CHECK_PROPERTY_CHANGE(PROP_AZIMUTH_START, azimuthStart); - CHECK_PROPERTY_CHANGE(PROP_AZIMUTH_FINISH, azimuthFinish); - CHECK_PROPERTY_CHANGE(PROP_EMIT_ACCELERATION, emitAcceleration); - CHECK_PROPERTY_CHANGE(PROP_ACCELERATION_SPREAD, accelerationSpread); - CHECK_PROPERTY_CHANGE(PROP_PARTICLE_RADIUS, particleRadius); - CHECK_PROPERTY_CHANGE(PROP_RADIUS_SPREAD, radiusSpread); - CHECK_PROPERTY_CHANGE(PROP_RADIUS_START, radiusStart); - CHECK_PROPERTY_CHANGE(PROP_RADIUS_FINISH, radiusFinish); - CHECK_PROPERTY_CHANGE(PROP_COLOR_SPREAD, colorSpread); - CHECK_PROPERTY_CHANGE(PROP_COLOR_START, colorStart); - CHECK_PROPERTY_CHANGE(PROP_COLOR_FINISH, colorFinish); - CHECK_PROPERTY_CHANGE(PROP_ALPHA_SPREAD, alphaSpread); - CHECK_PROPERTY_CHANGE(PROP_ALPHA_START, alphaStart); - CHECK_PROPERTY_CHANGE(PROP_ALPHA_FINISH, alphaFinish); - CHECK_PROPERTY_CHANGE(PROP_EMITTER_SHOULD_TRAIL, emitterShouldTrail); - CHECK_PROPERTY_CHANGE(PROP_PARTICLE_SPIN, particleSpin); - CHECK_PROPERTY_CHANGE(PROP_SPIN_SPREAD, spinSpread); - CHECK_PROPERTY_CHANGE(PROP_SPIN_START, spinStart); - CHECK_PROPERTY_CHANGE(PROP_SPIN_FINISH, spinFinish); - CHECK_PROPERTY_CHANGE(PROP_PARTICLE_ROTATE_WITH_ENTITY, rotateWithEntity); - - // Model - CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL); - CHECK_PROPERTY_CHANGE(PROP_MODEL_SCALE, modelScale); - CHECK_PROPERTY_CHANGE(PROP_JOINT_ROTATIONS_SET, jointRotationsSet); - CHECK_PROPERTY_CHANGE(PROP_JOINT_ROTATIONS, jointRotations); - CHECK_PROPERTY_CHANGE(PROP_JOINT_TRANSLATIONS_SET, jointTranslationsSet); - CHECK_PROPERTY_CHANGE(PROP_JOINT_TRANSLATIONS, jointTranslations); - CHECK_PROPERTY_CHANGE(PROP_RELAY_PARENT_JOINTS, relayParentJoints); - CHECK_PROPERTY_CHANGE(PROP_GROUP_CULLED, groupCulled); - CHECK_PROPERTY_CHANGE(PROP_BLENDSHAPE_COEFFICIENTS, blendshapeCoefficients); - CHECK_PROPERTY_CHANGE(PROP_USE_ORIGINAL_PIVOT, useOriginalPivot); - changedProperties += _animation.getChangedProperties(); - - // Light - CHECK_PROPERTY_CHANGE(PROP_IS_SPOTLIGHT, isSpotlight); - CHECK_PROPERTY_CHANGE(PROP_INTENSITY, intensity); - CHECK_PROPERTY_CHANGE(PROP_EXPONENT, exponent); - CHECK_PROPERTY_CHANGE(PROP_CUTOFF, cutoff); - CHECK_PROPERTY_CHANGE(PROP_FALLOFF_RADIUS, falloffRadius); - - // Text - CHECK_PROPERTY_CHANGE(PROP_TEXT, text); - CHECK_PROPERTY_CHANGE(PROP_LINE_HEIGHT, lineHeight); - CHECK_PROPERTY_CHANGE(PROP_TEXT_COLOR, textColor); - CHECK_PROPERTY_CHANGE(PROP_TEXT_ALPHA, textAlpha); - CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_COLOR, backgroundColor); - CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_ALPHA, backgroundAlpha); - CHECK_PROPERTY_CHANGE(PROP_LEFT_MARGIN, leftMargin); - CHECK_PROPERTY_CHANGE(PROP_RIGHT_MARGIN, rightMargin); - CHECK_PROPERTY_CHANGE(PROP_TOP_MARGIN, topMargin); - CHECK_PROPERTY_CHANGE(PROP_BOTTOM_MARGIN, bottomMargin); - CHECK_PROPERTY_CHANGE(PROP_UNLIT, unlit); - CHECK_PROPERTY_CHANGE(PROP_FONT, font); - CHECK_PROPERTY_CHANGE(PROP_TEXT_EFFECT, textEffect); - CHECK_PROPERTY_CHANGE(PROP_TEXT_EFFECT_COLOR, textEffectColor); - CHECK_PROPERTY_CHANGE(PROP_TEXT_EFFECT_THICKNESS, textEffectThickness); - CHECK_PROPERTY_CHANGE(PROP_TEXT_ALIGNMENT, alignment); - - // Zone - changedProperties += _keyLight.getChangedProperties(); - changedProperties += _ambientLight.getChangedProperties(); - changedProperties += _skybox.getChangedProperties(); - changedProperties += _haze.getChangedProperties(); - changedProperties += _bloom.getChangedProperties(); - CHECK_PROPERTY_CHANGE(PROP_FLYING_ALLOWED, flyingAllowed); - CHECK_PROPERTY_CHANGE(PROP_GHOSTING_ALLOWED, ghostingAllowed); - CHECK_PROPERTY_CHANGE(PROP_FILTER_URL, filterURL); - 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_HAZE_MODE, hazeMode); - CHECK_PROPERTY_CHANGE(PROP_BLOOM_MODE, bloomMode); - CHECK_PROPERTY_CHANGE(PROP_AVATAR_PRIORITY, avatarPriority); - CHECK_PROPERTY_CHANGE(PROP_SCREENSHARE, screenshare); - - // Polyvox - CHECK_PROPERTY_CHANGE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize); - CHECK_PROPERTY_CHANGE(PROP_VOXEL_DATA, voxelData); - CHECK_PROPERTY_CHANGE(PROP_VOXEL_SURFACE_STYLE, voxelSurfaceStyle); - CHECK_PROPERTY_CHANGE(PROP_X_TEXTURE_URL, xTextureURL); - CHECK_PROPERTY_CHANGE(PROP_Y_TEXTURE_URL, yTextureURL); - CHECK_PROPERTY_CHANGE(PROP_Z_TEXTURE_URL, zTextureURL); - CHECK_PROPERTY_CHANGE(PROP_X_N_NEIGHBOR_ID, xNNeighborID); - CHECK_PROPERTY_CHANGE(PROP_Y_N_NEIGHBOR_ID, yNNeighborID); - CHECK_PROPERTY_CHANGE(PROP_Z_N_NEIGHBOR_ID, zNNeighborID); - CHECK_PROPERTY_CHANGE(PROP_X_P_NEIGHBOR_ID, xPNeighborID); - CHECK_PROPERTY_CHANGE(PROP_Y_P_NEIGHBOR_ID, yPNeighborID); - CHECK_PROPERTY_CHANGE(PROP_Z_P_NEIGHBOR_ID, zPNeighborID); - - // Web - CHECK_PROPERTY_CHANGE(PROP_SOURCE_URL, sourceUrl); - CHECK_PROPERTY_CHANGE(PROP_DPI, dpi); - CHECK_PROPERTY_CHANGE(PROP_SCRIPT_URL, scriptURL); - CHECK_PROPERTY_CHANGE(PROP_MAX_FPS, maxFPS); - CHECK_PROPERTY_CHANGE(PROP_INPUT_MODE, inputMode); - CHECK_PROPERTY_CHANGE(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, showKeyboardFocusHighlight); - CHECK_PROPERTY_CHANGE(PROP_WEB_USE_BACKGROUND, useBackground); - CHECK_PROPERTY_CHANGE(PROP_USER_AGENT, userAgent); - - // Polyline - CHECK_PROPERTY_CHANGE(PROP_LINE_POINTS, linePoints); - CHECK_PROPERTY_CHANGE(PROP_STROKE_WIDTHS, strokeWidths); - CHECK_PROPERTY_CHANGE(PROP_STROKE_NORMALS, normals); - CHECK_PROPERTY_CHANGE(PROP_STROKE_COLORS, strokeColors); - CHECK_PROPERTY_CHANGE(PROP_IS_UV_MODE_STRETCH, isUVModeStretch); - CHECK_PROPERTY_CHANGE(PROP_LINE_GLOW, glow); - CHECK_PROPERTY_CHANGE(PROP_LINE_FACE_CAMERA, faceCamera); - - // Shape - CHECK_PROPERTY_CHANGE(PROP_SHAPE, shape); - - // Material - CHECK_PROPERTY_CHANGE(PROP_MATERIAL_URL, materialURL); - CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_MODE, materialMappingMode); - CHECK_PROPERTY_CHANGE(PROP_MATERIAL_PRIORITY, priority); - CHECK_PROPERTY_CHANGE(PROP_PARENT_MATERIAL_NAME, parentMaterialName); - CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_POS, materialMappingPos); - CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_SCALE, materialMappingScale); - CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_ROT, materialMappingRot); - CHECK_PROPERTY_CHANGE(PROP_MATERIAL_DATA, materialData); - CHECK_PROPERTY_CHANGE(PROP_MATERIAL_REPEAT, materialRepeat); - - // Image - CHECK_PROPERTY_CHANGE(PROP_IMAGE_URL, imageURL); - CHECK_PROPERTY_CHANGE(PROP_EMISSIVE, emissive); - CHECK_PROPERTY_CHANGE(PROP_KEEP_ASPECT_RATIO, keepAspectRatio); - CHECK_PROPERTY_CHANGE(PROP_SUB_IMAGE, subImage); - - // Grid - CHECK_PROPERTY_CHANGE(PROP_GRID_FOLLOW_CAMERA, followCamera); - CHECK_PROPERTY_CHANGE(PROP_MAJOR_GRID_EVERY, majorGridEvery); - CHECK_PROPERTY_CHANGE(PROP_MINOR_GRID_EVERY, minorGridEvery); - - // Gizmo - CHECK_PROPERTY_CHANGE(PROP_GIZMO_TYPE, gizmoType); - changedProperties += _ring.getChangedProperties(); - - return changedProperties; -} - -/*@jsdoc - * Different entity types have different properties: some common to all entities (listed in the table) and some specific to - * each {@link Entities.EntityType|EntityType} (linked to below). - * - * @typedef {object} Entities.EntityProperties - * @property {Uuid} id - The ID of the entity. Read-only. - * @property {string} name="" - A name for the entity. Need not be unique. - * @property {Entities.EntityType} type - The entity's type. You cannot change the type of an entity after it's created. - * However, its value may switch among "Box", "Shape", and "Sphere" depending on - * changes to the shape property set for entities of these types. Read-only. - * - * @property {Entities.EntityHostType} entityHostType="domain" - How the entity is hosted and sent to others for display. - * The value can only be set at entity creation by one of the {@link Entities.addEntity} methods. Read-only. - * @property {boolean} avatarEntity=false - true if the entity is an {@link Entities.EntityHostType|avatar entity}, - * false if it isn't. The value is per the entityHostType property value, set at entity creation - * by one of the {@link Entities.addEntity} methods. Read-only. - * @property {boolean} clientOnly=false - A synonym for avatarEntity. Read-only. - * @property {boolean} localEntity=false - true if the entity is a {@link Entities.EntityHostType|local entity}, - * false if it isn't. The value is per the entityHostType property value, set at entity creation - * by one of the {@link Entities.addEntity} methods. Read-only. - * - * @property {Uuid} owningAvatarID=Uuid.NULL - The session ID of the owning avatar if avatarEntity is - * true, otherwise {@link Uuid(0)|Uuid.NULL}. Read-only. - * - * @property {number} created - When the entity was created, expressed as the number of microseconds since - * 1970-01-01T00:00:00 UTC. Read-only. - * @property {number} age - The age of the entity in seconds since it was created. Read-only. - * @property {string} ageAsText - The age of the entity since it was created, formatted as h hours m minutes s - * seconds. - * @property {number} lifetime=-1 - How long an entity lives for, in seconds, before being automatically deleted. A value of - * -1 means that the entity lives for ever. - * @property {number} lastEdited - When the entity was last edited, expressed as the number of microseconds since - * 1970-01-01T00:00:00 UTC. Read-only. - * @property {Uuid} lastEditedBy - The session ID of the avatar or agent that most recently created or edited the entity. - * Read-only. - * - * @property {boolean} locked=false - true if properties other than locked cannot be changed and the - * entity cannot be deleted, false if all properties can be changed and the entity can be deleted. - * @property {boolean} visible=true - true if the entity is rendered, false if it isn't. - * @property {boolean} canCastShadow=true - true if the entity can cast a shadow, false if it can't. - * Currently applicable only to {@link Entities.EntityProperties-Model|Model} and - * {@link Entities.EntityProperties-Shape|Shape} entities. Shadows are cast if inside a - * {@link Entities.EntityProperties-Zone|Zone} entity with castShadows enabled in its keyLight - * property. - * @property {boolean} isVisibleInSecondaryCamera=true - true if the entity is rendered in the secondary camera, - * false if it isn't. - * @property {Entities.RenderLayer} renderLayer="world" - The layer that the entity renders in. - * @property {Entities.PrimitiveMode} primitiveMode="solid" - How the entity's geometry is rendered. - * @property {boolean} ignorePickIntersection=false - true if {@link Picks} and {@link RayPick} ignore the entity, - * false if they don't. - * - * @property {Vec3} position=0,0,0 - The position of the entity in world coordinates. - * @property {Quat} rotation=0,0,0,1 - The orientation of the entity in world coordinates. - * @property {Vec3} registrationPoint=0.5,0.5,0.5 - The point in the entity that is set to the entity's position and is rotated - * about, range {@link Vec3(0)|Vec3.ZERO} – {@link Vec3(0)|Vec3.ONE}. A value of {@link Vec3(0)|Vec3.ZERO} is the - * entity's minimum x, y, z corner; a value of {@link Vec3(0)|Vec3.ONE} is the entity's maximum x, y, z corner. - * - * @property {Vec3} naturalPosition=0,0,0 - The center of the entity's unscaled mesh model if it has one, otherwise - * {@link Vec3(0)|Vec3.ZERO}. Read-only. - * @property {Vec3} naturalDimensions - The dimensions of the entity's unscaled mesh model or image if it has one, otherwise - * {@link Vec3(0)|Vec3.ONE}. Read-only. - * - * @property {Vec3} velocity=0,0,0 - The linear velocity of the entity in m/s with respect to world coordinates. - * @property {number} damping=0.39347 - How much the linear velocity of an entity slows down over time, range - * 0.01.0. A higher damping value slows down the entity more quickly. The default value - * is for an exponential decay timescale of 2.0s, where it takes 2.0s for the movement to slow to 1/e = 0.368 - * of its initial value. - * @property {Vec3} angularVelocity=0,0,0 - The angular velocity of the entity in rad/s with respect to its axes, about its - * registration point. - * @property {number} angularDamping=0.39347 - How much the angular velocity of an entity slows down over time, range - * 0.01.0. A higher damping value slows down the entity more quickly. The default value - * is for an exponential decay timescale of 2.0s, where it takes 2.0s for the movement to slow to 1/e = 0.368 - * of its initial value. - * - * @property {Vec3} gravity=0,0,0 - The acceleration due to gravity in m/s2 that the entity should move with, in - * world coordinates. Use a value of { x: 0, y: -9.8, z: 0 } to simulate Earth's gravity. Gravity is applied - * to an entity's motion only if its dynamic property is true. - *

If changing an entity's gravity from {@link Vec3(0)|Vec3.ZERO}, you need to give it a small - * velocity in order to kick off physics simulation.

- * @property {Vec3} acceleration - The current, measured acceleration of the entity, in m/s2. - *

Deprecated: This property is deprecated and will be removed.

- * @property {number} restitution=0.5 - The "bounciness" of an entity when it collides, range 0.0 – - * 0.99. The higher the value, the more bouncy. - * @property {number} friction=0.5 - How much an entity slows down when it's moving against another, range 0.0 - * – 10.0. The higher the value, the more quickly it slows down. Examples: 0.1 for ice, - * 0.9 for sandpaper. - * @property {number} density=1000 - The density of the entity in kg/m3, range 100 – - * 10000. Examples: 100 for balsa wood, 10000 for silver. The density is used in - * conjunction with the entity's bounding box volume to work out its mass in the application of physics. - * - * @property {boolean} collisionless=false - true if the entity shouldn't collide, false if it - * collides with items per its collisionMask property. - * @property {boolean} ignoreForCollisions - Synonym for collisionless. - * @property {CollisionMask} collisionMask=31 - What types of items the entity should collide with. - * @property {string} collidesWith="static,dynamic,kinematic,myAvatar,otherAvatar," - Synonym for collisionMask, - * in text format. - * @property {string} collisionSoundURL="" - The sound that's played when the entity experiences a collision. Valid file - * formats are per {@link SoundObject}. - * @property {boolean} dynamic=false - true if the entity's movement is affected by collisions, false - * if it isn't. - * @property {boolean} collisionsWillMove - A synonym for dynamic. - * - * @property {string} href="" - A "hifi://" directory services address that a user is teleported to when they click on the entity. - * @property {string} description="" - A description of the href property value. - * - * @property {string} userData="" - Used to store extra data about the entity in JSON format. - *

Warning: Other apps may also use this property, so make sure you handle data stored by other apps: - * edit only your bit and leave the rest of the data intact. You can use JSON.parse() to parse the string into - * a JavaScript object which you can manipulate the properties of, and use JSON.stringify() to convert the - * object into a string to put back in the property.

- * - * @property {string} privateUserData="" - Like userData, but only accessible by server entity scripts, assignment - * client scripts, and users who have "Can Get and Set Private User Data" permissions in the domain. - * - * @property {string} script="" - The URL of the client entity script, if any, that is attached to the entity. - * @property {number} scriptTimestamp=0 - Used to indicate when the client entity script was loaded. Should be - * an integer number of milliseconds since midnight GMT on January 1, 1970 (e.g., as supplied by Date.now(). - * If you update the property's value, the script is re-downloaded and reloaded. This is how the "reload" - * button beside the "script URL" field in properties tab of the Create app works. - * @property {string} serverScripts="" - The URL of the server entity script, if any, that is attached to the entity. - * - * @property {Uuid} parentID=Uuid.NULL - The ID of the entity or avatar that the entity is parented to. A value of - * {@link Uuid(0)|Uuid.NULL} is used if the entity is not parented. - * @property {number} parentJointIndex=65535 - The joint of the entity or avatar that the entity is parented to. Use - * 65535 or -1 to parent to the entity or avatar's position and orientation rather than a joint. - * @property {Vec3} localPosition=0,0,0 - The position of the entity relative to its parent if the entity is parented, - * otherwise the same value as position. If the entity is parented to an avatar and is an avatar entity - * so that it scales with the avatar, this value remains the original local position value while the avatar scale changes. - * @property {Quat} localRotation=0,0,0,1 - The rotation of the entity relative to its parent if the entity is parented, - * otherwise the same value as rotation. - * @property {Vec3} localVelocity=0,0,0 - The velocity of the entity relative to its parent if the entity is parented, - * otherwise the same value as velocity. - * @property {Vec3} localAngularVelocity=0,0,0 - The angular velocity of the entity relative to its parent if the entity is - * parented, otherwise the same value as angularVelocity. - * @property {Vec3} localDimensions - The dimensions of the entity. If the entity is parented to an avatar and is an - * avatar entity so that it scales with the avatar, this value remains the original dimensions value while the - * avatar scale changes. - * - * @property {Entities.BoundingBox} boundingBox - The axis-aligned bounding box that tightly encloses the entity. - * Read-only. - * @property {AACube} queryAACube - The axis-aligned cube that determines where the entity lives in the entity server's octree. - * The cube may be considerably larger than the entity in some situations, e.g., when the entity is grabbed by an avatar: - * the position of the entity is determined through avatar mixer updates and so the AA cube is expanded in order to reduce - * unnecessary entity server updates. Scripts should not change this property's value. - * - * @property {string} actionData="" - Base-64 encoded compressed dump of the actions associated with the entity. This property - * is typically not used in scripts directly; rather, functions that manipulate an entity's actions update it, e.g., - * {@link Entities.addAction}. The size of this property increases with the number of actions. Because this property value - * has to fit within a Overte datagram packet, there is a limit to the number of actions that an entity can have; - * edits which would result in overflow are rejected. Read-only. - * @property {Entities.RenderInfo} renderInfo - Information on the cost of rendering the entity. Currently information is only - * provided for Model entities. Read-only. - * - * @property {boolean} cloneable=false - true if the domain or avatar entity can be cloned via - * {@link Entities.cloneEntity}, false if it can't be. - * @property {number} cloneLifetime=300 - The entity lifetime for clones created from this entity. - * @property {number} cloneLimit=0 - The total number of clones of this entity that can exist in the domain at any given time. - * @property {boolean} cloneDynamic=false - true if clones created from this entity will have their - * dynamic property set to true, false if they won't. - * @property {boolean} cloneAvatarEntity=false - true if clones created from this entity will be created as - * avatar entities, false if they won't be. - * @property {Uuid} cloneOriginID - The ID of the entity that this entity was cloned from. - * - * @property {Uuid[]} renderWithZones=[]] - A list of entity IDs representing with which zones this entity should render. - * If it is empty, this entity will render normally. Otherwise, this entity will only render if your avatar is within - * one of the zones in this list. - * @property {BillboardMode} billboardMode="none" - Whether the entity is billboarded to face the camera. Use the rotation - * property to control which axis is facing you. - * - * @property {Entities.Grab} grab - The entity's grab-related properties. - * - * @comment The different entity types have additional properties as follows: - * @see {@link Entities.EntityProperties-Box|EntityProperties-Box} - * @see {@link Entities.EntityProperties-Gizmo|EntityProperties-Gizmo} - * @see {@link Entities.EntityProperties-Grid|EntityProperties-Grid} - * @see {@link Entities.EntityProperties-Image|EntityProperties-Image} - * @see {@link Entities.EntityProperties-Light|EntityProperties-Light} - * @see {@link Entities.EntityProperties-Line|EntityProperties-Line} - * @see {@link Entities.EntityProperties-Material|EntityProperties-Material} - * @see {@link Entities.EntityProperties-Model|EntityProperties-Model} - * @see {@link Entities.EntityProperties-ParticleEffect|EntityProperties-ParticleEffect} - * @see {@link Entities.EntityProperties-PolyLine|EntityProperties-PolyLine} - * @see {@link Entities.EntityProperties-PolyVox|EntityProperties-PolyVox} - * @see {@link Entities.EntityProperties-Shape|EntityProperties-Shape} - * @see {@link Entities.EntityProperties-Sphere|EntityProperties-Sphere} - * @see {@link Entities.EntityProperties-Text|EntityProperties-Text} - * @see {@link Entities.EntityProperties-Web|EntityProperties-Web} - * @see {@link Entities.EntityProperties-Zone|EntityProperties-Zone} - */ - -/*@jsdoc - * The "Box" {@link Entities.EntityType|EntityType} is the same as the "Shape" - * {@link Entities.EntityType|EntityType} except that its shape value is always set to "Cube" - * when the entity is created. If its shape property value is subsequently changed then the entity's - * type will be reported as "Sphere" if the shape is set to "Sphere", - * otherwise it will be reported as "Shape". - * - * @typedef {object} Entities.EntityProperties-Box - * @see {@link Entities.EntityProperties-Shape|EntityProperties-Shape} - */ - -/*@jsdoc - * The "Light" {@link Entities.EntityType|EntityType} adds local lighting effects. It has properties in addition - * to the common {@link Entities.EntityProperties|EntityProperties}. - * - * @typedef {object} Entities.EntityProperties-Light - * @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the entity. Surfaces outside these dimensions are not lit - * by the light. - * @property {Color} color=255,255,255 - The color of the light emitted. - * @property {number} intensity=1 - The brightness of the light. - * @property {number} falloffRadius=0.1 - The distance from the light's center at which intensity is reduced by 25%. - * @property {boolean} isSpotlight=false - true if the light is directional, emitting along the entity's - * local negative z-axis; false if the light is a point light which emanates in all directions. - * @property {number} exponent=0 - Affects the softness of the spotlight beam: the higher the value the softer the beam. - * @property {number} cutoff=1.57 - Affects the size of the spotlight beam: the higher the value the larger the beam. - * @example Create a spotlight pointing at the ground. - * Entities.addEntity({ - * type: "Light", - * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -4 })), - * rotation: Quat.fromPitchYawRollDegrees(-75, 0, 0), - * dimensions: { x: 5, y: 5, z: 5 }, - * intensity: 100, - * falloffRadius: 0.3, - * isSpotlight: true, - * exponent: 20, - * cutoff: 30, - * lifetime: 300 // Delete after 5 minutes. - * }); - */ - -/*@jsdoc - * The "Line" {@link Entities.EntityType|EntityType} draws thin, straight lines between a sequence of two or more - * points. It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. - *

Deprecated: Use {@link Entities.EntityProperties-PolyLine|PolyLine} entities instead.

- * - * @typedef {object} Entities.EntityProperties-Line - * @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the entity. Must be sufficient to contain all the - * linePoints. - * @property {Vec3[]} linePoints=[]] - The sequence of points to draw lines between. The values are relative to the entity's - * position. A maximum of 70 points can be specified. The property's value is set only if all the linePoints - * lie within the entity's dimensions. - * @property {Color} color=255,255,255 - The color of the line. - * @example Draw lines in a "V". - * var entity = Entities.addEntity({ - * type: "Line", - * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.75, z: -5 })), - * rotation: MyAvatar.orientation, - * dimensions: { x: 2, y: 2, z: 1 }, - * linePoints: [ - * { x: -1, y: 1, z: 0 }, - * { x: 0, y: -1, z: 0 }, - * { x: 1, y: 1, z: 0 }, - * ], - * color: { red: 255, green: 0, blue: 0 }, - * lifetime: 300 // Delete after 5 minutes. - * }); - */ - -/*@jsdoc - * The "Material" {@link Entities.EntityType|EntityType} modifies existing materials on entities and avatars. It - * has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. - *

To apply a material to an entity, set the material entity's parentID property to the entity ID. - * To apply a material to an avatar, set the material entity's parentID property to the avatar's session UUID. - * To apply a material to your avatar such that it persists across domains and log-ins, create the material as an avatar entity - * by setting the entityHostType parameter in {@link Entities.addEntity} to "avatar" and set the - * entity's parentID property to MyAvatar.SELF_ID. - * Material entities render as non-scalable spheres if they don't have their parent set.

- * - * @typedef {object} Entities.EntityProperties-Material - * @property {Vec3} dimensions=0.1,0.1,0.1 - Used when materialMappingMode == "projected". - * @property {string} materialURL="" - URL to a {@link Entities.MaterialResource|MaterialResource}. Alternatively, set the - * property value to "materialData" to use the materialData property for the - * {@link Entities.MaterialResource|MaterialResource} values. If you append "#name" to the URL, the material - * with that name will be applied to the entity. You can also use the ID of another Material entity as the URL, in which - * case this material will act as a copy of that material, with its own unique material transform, priority, etc. - * @property {string} materialData="" - Used to store {@link Entities.MaterialResource|MaterialResource} data as a JSON string. - * You can use JSON.parse() to parse the string into a JavaScript object which you can manipulate the - * properties of, and use JSON.stringify() to convert the object into a string to put in the property. - * @property {number} priority=0 - The priority for applying the material to its parent. Only the highest priority material is - * applied, with materials of the same priority randomly assigned. Materials that come with the model have a priority of - * 0. - * @property {string} parentMaterialName="0" - Selects the mesh part or parts within the parent to which to apply the material. - * If in the format "mat::string", all mesh parts with material name "string" are replaced. - * If "all", then all mesh parts are replaced. - * Otherwise the property value is parsed as an unsigned integer, specifying the mesh part index to modify. - *

If the string represents an array (starts with "[" and ends with "]"), the string is split - * at each "," and each element parsed as either a number or a string if it starts with "mat::". - * For example, "[0,1,mat::string,mat::string2]" will replace mesh parts 0 and 1, and any mesh parts with - * material "string" or "string2". Do not put spaces around the commas. Invalid values are parsed - * to 0.

- * @property {string} materialMappingMode="uv" - How the material is mapped to the entity. Either "uv" or - * "projected". In "uv" mode, the material is evaluated within the UV space of the mesh it is - * applied to. In "projected" mode, the 3D transform (position, rotation, and dimensions) of the Material - * entity is used to evaluate the texture coordinates for the material. - * @property {Vec2} materialMappingPos=0,0 - Offset position in UV-space of the top left of the material, range - * { x: 0, y: 0 }{ x: 1, y: 1 }. - * @property {Vec2} materialMappingScale=1,1 - How much to scale the material within the parent's UV-space. - * @property {number} materialMappingRot=0 - How much to rotate the material within the parent's UV-space, in degrees. - * @property {boolean} materialRepeat=true - true if the material repeats, false if it doesn't. If - * false, fragments outside of texCoord 0 – 1 will be discarded. Works in both "uv" and - * "projected" modes. - * @example Color a sphere using a Material entity. - * var entityID = Entities.addEntity({ - * type: "Sphere", - * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })), - * dimensions: { x: 1, y: 1, z: 1 }, - * color: { red: 128, green: 128, blue: 128 }, - * lifetime: 300 // Delete after 5 minutes. - * }); - * - * var materialID = Entities.addEntity({ - * type: "Material", - * parentID: entityID, - * materialURL: "materialData", - * priority: 1, - * materialData: JSON.stringify({ - * materialVersion: 1, - * materials: { - * // Value overrides entity's "color" property. - * albedo: [1.0, 1.0, 0] // Yellow - * } - * }) - * }); - */ - -/*@jsdoc - * The "Model" {@link Entities.EntityType|EntityType} displays a glTF, FBX, or OBJ model. When adding an entity, - * if no dimensions value is specified then the model is automatically sized to its - * {@link Entities.EntityProperties|naturalDimensions}. It has properties in addition to the common - * {@link Entities.EntityProperties|EntityProperties}. - * - * @typedef {object} Entities.EntityProperties-Model - * @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the entity. When adding an entity, if no dimensions - * value is specified then the model is automatically sized to its - * {@link Entities.EntityProperties|naturalDimensions}. - * @property {string} modelURL="" - The URL of the glTF, FBX, or OBJ model. glTF models may be in JSON or binary format - * (".gltf" or ".glb" URLs respectively). Baked models' URLs have ".baked" before the file type. Model files may also be - * compressed in GZ format, in which case the URL ends in ".gz". - * @property {Vec3} modelScale - The scale factor applied to the model's dimensions. - *

Deprecated: This property is deprecated and will be removed.

- * @property {string} blendshapeCoefficients - A JSON string of a map of blendshape names to values. Only stores set values. - * When editing this property, only coefficients that you are editing will change; it will not explicitly reset other - * coefficients. - * @property {boolean} useOriginalPivot=false - If false, the model will be centered based on its content, - * ignoring any offset in the model itself. If true, the model will respect its original offset. Currently, - * only pivots relative to {x: 0, y: 0, z: 0} are supported. - * @property {string} textures="" - A JSON string of texture name, URL pairs used when rendering the model in place of the - * model's original textures. Use a texture name from the originalTextures property to override that texture. - * Only the texture names and URLs to be overridden need be specified; original textures are used where there are no - * overrides. You can use JSON.stringify() to convert a JavaScript object of name, URL pairs into a JSON - * string. - * @property {string} originalTextures="{}" - A JSON string of texture name, URL pairs used in the model. The property value is - * filled in after the entity has finished rezzing (i.e., textures have loaded). You can use JSON.parse() to - * parse the JSON string into a JavaScript object of name, URL pairs. Read-only. - * @property {Color} color=255,255,255 - Currently not used. - * - * @property {ShapeType} shapeType="none" - The shape of the collision hull used if collisions are enabled. - * @property {string} compoundShapeURL="" - The model file to use for the compound shape if shapeType is - * "compound". - * - * @property {Entities.AnimationProperties} animation - An animation to play on the model. - * - * @property {Quat[]} jointRotations=[]] - Joint rotations applied to the model; [] if none are applied or the - * model hasn't loaded. The array indexes are per {@link Entities.getJointIndex|getJointIndex}. Rotations are relative to - * each joint's parent. - *

Joint rotations can be set by {@link Entities.setLocalJointRotation|setLocalJointRotation} and similar functions, or - * by setting the value of this property. If you set a joint rotation using this property, you also need to set the - * corresponding jointRotationsSet value to true.

- * @property {boolean[]} jointRotationsSet=[]] - true values for joints that have had rotations applied, - * false otherwise; [] if none are applied or the model hasn't loaded. The array indexes are per - * {@link Entities.getJointIndex|getJointIndex}. - * @property {Vec3[]} jointTranslations=[]] - Joint translations applied to the model; [] if none are applied or - * the model hasn't loaded. The array indexes are per {@link Entities.getJointIndex|getJointIndex}. Translations are - * relative to each joint's parent. - *

Joint translations can be set by {@link Entities.setLocalJointTranslation|setLocalJointTranslation} and similar - * functions, or by setting the value of this property. If you set a joint translation using this property you also need to - * set the corresponding jointTranslationsSet value to true.

- * @property {boolean[]} jointTranslationsSet=[]] - true values for joints that have had translations applied, - * false otherwise; [] if none are applied or the model hasn't loaded. The array indexes are per - * {@link Entities.getJointIndex|getJointIndex}. - * @property {boolean} relayParentJoints=false - true if when the entity is parented to an avatar, the avatar's - * joint rotations are applied to the entity's joints; false if a parent avatar's joint rotations are not - * applied to the entity's joints. - * @property {boolean} groupCulled=false - true if the mesh parts of the model are LOD culled as a group, - * false if separate mesh parts are LOD culled individually. - * - * @example Rez a cowboy hat. - * var entity = Entities.addEntity({ - * type: "Model", - * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.75, z: -2 })), - * rotation: MyAvatar.orientation, - * modelURL: "https://apidocs.overte.org/examples/cowboy-hat.fbx", - * dimensions: { x: 0.8569, y: 0.3960, z: 1.0744 }, - * lifetime: 300 // Delete after 5 minutes. - * }); - */ - -/*@jsdoc - * The "ParticleEffect" {@link Entities.EntityType|EntityType} displays a particle system that can be used to - * simulate things such as fire, smoke, snow, magic spells, etc. The particles emanate from an ellipsoid or part thereof. - * It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. - * - * @typedef {object} Entities.EntityProperties-ParticleEffect - * @property {boolean} isEmitting=true - true if particles are being emitted, false if they aren't. - * @property {number} maxParticles=1000 - The maximum number of particles to render at one time. Older particles are deleted if - * necessary when new ones are created. - * @property {number} lifespan=3s - How long, in seconds, each particle lives. - * @property {number} emitRate=15 - The number of particles per second to emit. - * @property {number} emitSpeed=5 - The speed, in m/s, that each particle is emitted at. - * @property {number} speedSpread=1 - The spread in speeds at which particles are emitted at. For example, if - * emitSpeed == 5 and speedSpread == 1, particles will be emitted with speeds in the range - * 46m/s. - * @property {Vec3} emitAcceleration=0,-9.8,0 - The acceleration that is applied to each particle during its lifetime. The - * default is Earth's gravity value. - * @property {Vec3} accelerationSpread=0,0,0 - The spread in accelerations that each particle is given. For example, if - * emitAccelerations == {x: 0, y: -9.8, z: 0} and accelerationSpread == - * {x: 0, y: 1, z: 0}, each particle will have an acceleration in the range {x: 0, y: -10.8, z: 0} - * – {x: 0, y: -8.8, z: 0}. - * @property {Vec3} dimensions - The dimensions of the particle effect, i.e., a bounding box containing all the particles - * during their lifetimes, assuming that emitterShouldTrail == false. Read-only. - * @property {boolean} emitterShouldTrail=false - true if particles are "left behind" as the emitter moves, - * false if they stay within the entity's dimensions. - * - * @property {Quat} emitOrientation=-0.707,0,0,0.707 - The orientation of particle emission relative to the entity's axes. By - * default, particles emit along the entity's local z-axis, and azimuthStart and azimuthFinish - * are relative to the entity's local x-axis. The default value is a rotation of -90 degrees about the local x-axis, i.e., - * the particles emit vertically. - * - * @property {ShapeType} shapeType="ellipsoid" - The shape from which particles are emitted. - * @property {string} compoundShapeURL="" - The model file to use for the compound shape if shapeType == - * "compound". - * @property {Vec3} emitDimensions=0,0,0 - The dimensions of the shape from which particles are emitted. - * @property {number} emitRadiusStart=1 - The starting radius within the shape at which particles start being emitted; - * range 0.01.0 for the center to the surface, respectively. - * Particles are emitted from the portion of the shape that lies between emitRadiusStart and the - * shape's surface. - * @property {number} polarStart=0 - The angle in radians from the entity's local z-axis at which particles start being emitted - * within the shape; range 0Math.PI. Particles are emitted from the portion of the - * shape that lies between polarStart and polarFinish. Only used if shapeType is - * "ellipsoid" or "sphere". - * @property {number} polarFinish=0 - The angle in radians from the entity's local z-axis at which particles stop being emitted - * within the shape; range 0Math.PI. Particles are emitted from the portion of the - * shape that lies between polarStart and polarFinish. Only used if shapeType is - * "ellipsoid" or "sphere". - * @property {number} azimuthStart=-Math.PI - The angle in radians from the entity's local x-axis about the entity's local - * z-axis at which particles start being emitted; range -Math.PIMath.PI. Particles are - * emitted from the portion of the shape that lies between azimuthStart and azimuthFinish. - * Only used if shapeType is "ellipsoid", "sphere", or "circle". - * @property {number} azimuthFinish=Math.PI - The angle in radians from the entity's local x-axis about the entity's local - * z-axis at which particles stop being emitted; range -Math.PIMath.PI. Particles are - * emitted from the portion of the shape that lies between azimuthStart and azimuthFinish. - * Only used if shapeType is "ellipsoid", "sphere", or "circle". - * - * @property {string} textures="" - The URL of a JPG or PNG image file to display for each particle. If you want transparency, - * use PNG format. - * @property {number} particleRadius=0.025 - The radius of each particle at the middle of its life. - * @property {number} radiusStart=null - The radius of each particle at the start of its life. If null, the - * particleRadius value is used. - * @property {number} radiusFinish=null - The radius of each particle at the end of its life. If null, the - * particleRadius value is used. - * @property {number} radiusSpread=0 - The spread in radius that each particle is given. For example, if - * particleRadius == 0.5 and radiusSpread == 0.25, each particle will have a radius in the range - * 0.250.75. - * @property {Color} color=255,255,255 - The color of each particle at the middle of its life. - * @property {ColorFloat} colorStart=null,null,null - The color of each particle at the start of its life. If any of the - * component values are undefined, the color value is used. - * @property {ColorFloat} colorFinish=null,null,null - The color of each particle at the end of its life. If any of the - * component values are undefined, the color value is used. - * @property {Color} colorSpread=0,0,0 - The spread in color that each particle is given. For example, if - * color == {red: 100, green: 100, blue: 100} and colorSpread == - * {red: 10, green: 25, blue: 50}, each particle will have a color in the range - * {red: 90, green: 75, blue: 50}{red: 110, green: 125, blue: 150}. - * @property {number} alpha=1 - The opacity of each particle at the middle of its life. - * @property {number} alphaStart=null - The opacity of each particle at the start of its life. If null, the - * alpha value is used. - * @property {number} alphaFinish=null - The opacity of each particle at the end of its life. If null, the - * alpha value is used. - * @property {number} alphaSpread=0 - The spread in alpha that each particle is given. For example, if - * alpha == 0.5 and alphaSpread == 0.25, each particle will have an alpha in the range - * 0.250.75. - * @property {Entities.Pulse} pulse - Color and alpha pulse. - *

Deprecated: This property is deprecated and will be removed.

- * @property {number} particleSpin=0 - The rotation of each particle at the middle of its life, range -2 * Math.PI - * – 2 * Math.PI radians. - * @property {number} spinStart=null - The rotation of each particle at the start of its life, range -2 * Math.PI - * – 2 * Math.PI radians. If null, the particleSpin value is used. - * @property {number} spinFinish=null - The rotation of each particle at the end of its life, range -2 * Math.PI - * – 2 * Math.PI radians. If null, the particleSpin value is used. - * @property {number} spinSpread=0 - The spread in spin that each particle is given, range 0 – - * 2 * Math.PI radians. For example, if particleSpin == Math.PI and - * spinSpread == Math.PI / 2, each particle will have a rotation in the range Math.PI / 2 – - * 3 * Math.PI / 2. - * @property {boolean} rotateWithEntity=false - true if the particles' rotations are relative to the entity's - * instantaneous rotation, false if they're relative to world coordinates. If true with - * particleSpin == 0, the particles keep oriented per the entity's orientation. - * - * @example Create a ball of green smoke. - * particles = Entities.addEntity({ - * type: "ParticleEffect", - * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -4 })), - * lifespan: 5, - * emitRate: 10, - * emitSpeed: 0.02, - * speedSpread: 0.01, - * emitAcceleration: { x: 0, y: 0.02, z: 0 }, - * polarFinish: Math.PI, - * textures: "https://content.overte.org/Bazaar/Assets/Textures/Defaults/Interface/default_particle.png", - * particleRadius: 0.1, - * color: { red: 0, green: 255, blue: 0 }, - * alphaFinish: 0, - * lifetime: 300 // Delete after 5 minutes. - * }); - */ - -/*@jsdoc - * The "PolyLine" {@link Entities.EntityType|EntityType} draws textured, straight lines between a sequence of - * points. It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. - * - * @typedef {object} Entities.EntityProperties-PolyLine - * @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the entity, i.e., the size of the bounding box that contains the - * lines drawn. Read-only. - * @property {Vec3[]} linePoints=[]] - The sequence of points to draw lines between. The values are relative to the entity's - * position. A maximum of 70 points can be specified. - * @property {Vec3[]} normals=[]] - The normal vectors for the line's surface at the linePoints. The values are - * relative to the entity's orientation. Must be specified in order for the entity to render. - * @property {number[]} strokeWidths=[]] - The widths, in m, of the line at the linePoints. Must be specified in - * order for the entity to render. - * @property {Vec3[]} strokeColors=[]] - The base colors of each point, with values in the range 0.0,0.0,0.0 - * – 1.0,1.0,1.0. These colors are multiplied with the color of the texture. If there are more line - * points than stroke colors, the color property value is used for the remaining points. - *

Warning: The ordinate values are in the range 0.01.0.

- * @property {Color} color=255,255,255 - Used as the color for each point if strokeColors doesn't have a value for - * the point. - * @property {string} textures="" - The URL of a JPG or PNG texture to use for the lines. If you want transparency, use PNG - * format. - * @property {boolean} isUVModeStretch=true - true if the texture is stretched to fill the whole line, - * false if the texture repeats along the line. - * @property {boolean} glow=false - true if the opacity of the strokes drops off away from the line center, - * false if it doesn't. - * @property {boolean} faceCamera=false - true if each line segment rotates to face the camera, false - * if they don't. - * @example Draw a textured "V". - * var entity = Entities.addEntity({ - * type: "PolyLine", - * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.75, z: -5 })), - * rotation: MyAvatar.orientation, - * linePoints: [ - * { x: -1, y: 0.5, z: 0 }, - * { x: 0, y: 0, z: 0 }, - * { x: 1, y: 0.5, z: 0 } - * ], - * normals: [ - * { x: 0, y: 0, z: 1 }, - * { x: 0, y: 0, z: 1 }, - * { x: 0, y: 0, z: 1 } - * ], - * strokeWidths: [ 0.1, 0.1, 0.1 ], - * color: { red: 255, green: 0, blue: 0 }, // Use just the red channel from the image. - * textures: "https://hifi-content/DomainContent/Toybox/flowArts/trails.png", - * isUVModeStretch: true, - * lifetime: 300 // Delete after 5 minutes. - * }); - */ - -/*@jsdoc - * The "PolyVox" {@link Entities.EntityType|EntityType} displays a set of textured voxels. - * It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. - * If you have two or more neighboring PolyVox entities of the same size abutting each other, you can display them as joined by - * configuring their voxelSurfaceStyle and various neighbor ID properties. - *

PolyVox entities uses a library from Volumes of Fun. Their - * library documentation may be useful to read.

- * - * @typedef {object} Entities.EntityProperties-PolyVox - * @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the entity. - * @property {Vec3} voxelVolumeSize=32,32,32 - Integer number of voxels along each axis of the entity, in the range - * 1,1,1 to 128,128,128. The dimensions of each voxel is - * dimensions / voxelVolumesize. - * @property {string} voxelData="ABAAEAAQAAAAHgAAEAB42u3BAQ0AAADCoPdPbQ8HFAAAAPBuEAAAAQ==" - Base-64 encoded compressed dump of - * the PolyVox data. This property is typically not used in scripts directly; rather, functions that manipulate a PolyVox - * entity update it. - *

The size of this property increases with the size and complexity of the PolyVox entity, with the size depending on how - * the particular entity's voxels compress. Because this property value has to fit within a Overte datagram packet, - * there is a limit to the size and complexity of a PolyVox entity; edits which would result in an overflow are rejected.

- * @property {Entities.PolyVoxSurfaceStyle} voxelSurfaceStyle=2 - The style of rendering the voxels' surface and how - * neighboring PolyVox entities are joined. - * @property {string} xTextureURL="" - The URL of the texture to map to surfaces perpendicular to the entity's local x-axis. - * JPG or PNG format. If no texture is specified the surfaces display white. - * @property {string} yTextureURL="" - The URL of the texture to map to surfaces perpendicular to the entity's local y-axis. - * JPG or PNG format. If no texture is specified the surfaces display white. - * @property {string} zTextureURL="" - The URL of the texture to map to surfaces perpendicular to the entity's local z-axis. - * JPG or PNG format. If no texture is specified the surfaces display white. - * @property {Uuid} xNNeighborID=Uuid.NULL - The ID of the neighboring PolyVox entity in the entity's -ve local x-axis - * direction, if you want them joined. Set to {@link Uuid(0)|Uuid.NULL} if there is none or you don't want to join them. - * @property {Uuid} yNNeighborID=Uuid.NULL - The ID of the neighboring PolyVox entity in the entity's -ve local y-axis - * direction, if you want them joined. Set to {@link Uuid(0)|Uuid.NULL} if there is none or you don't want to join them. - * @property {Uuid} zNNeighborID=Uuid.NULL - The ID of the neighboring PolyVox entity in the entity's -ve local z-axis - * direction, if you want them joined. Set to {@link Uuid(0)|Uuid.NULL} if there is none or you don't want to join them. - * @property {Uuid} xPNeighborID=Uuid.NULL - The ID of the neighboring PolyVox entity in the entity's +ve local x-axis - * direction, if you want them joined. Set to {@link Uuid(0)|Uuid.NULL} if there is none or you don't want to join them. - * @property {Uuid} yPNeighborID=Uuid.NULL - The ID of the neighboring PolyVox entity in the entity's +ve local y-axis - * direction, if you want them joined. Set to {@link Uuid(0)|Uuid.NULL} if there is none or you don't want to join them. - * @property {Uuid} zPNeighborID=Uuid.NULL - The ID of the neighboring PolyVox entity in the entity's +ve local z-axis - * direction, if you want them joined. Set to {@link Uuid(0)|Uuid.NULL} if there is none or you don't want to join them. - * @example Create a textured PolyVox sphere. - * var position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -8 })); - * var texture = "http://public.highfidelity.com/cozza13/tuscany/Concrete2.jpg"; - * var polyVox = Entities.addEntity({ - * type: "PolyVox", - * position: position, - * dimensions: { x: 2, y: 2, z: 2 }, - * voxelVolumeSize: { x: 16, y: 16, z: 16 }, - * voxelSurfaceStyle: 2, - * xTextureURL: texture, - * yTextureURL: texture, - * zTextureURL: texture, - * lifetime: 300 // Delete after 5 minutes. - * }); - * Entities.setVoxelSphere(polyVox, position, 0.8, 255); - */ - -/*@jsdoc - * The "Shape" {@link Entities.EntityType|EntityType} displays an entity of a specified shape. - * It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. - * - * @typedef {object} Entities.EntityProperties-Shape - * @property {Entities.Shape} shape="Sphere" - The shape of the entity. - * @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the entity. - * @property {Color} color=255,255,255 - The color of the entity. - * @property {number} alpha=1 - The opacity of the entity, range 0.01.0. - * @property {Entities.Pulse} pulse - Color and alpha pulse. - *

Deprecated: This property is deprecated and will be removed.

- * @example Create a cylinder. - * var shape = Entities.addEntity({ - * type: "Shape", - * shape: "Cylinder", - * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })), - * dimensions: { x: 0.4, y: 0.6, z: 0.4 }, - * lifetime: 300 // Delete after 5 minutes. - * }); - */ - -/*@jsdoc - * The "Sphere" {@link Entities.EntityType|EntityType} is the same as the "Shape" - * {@link Entities.EntityType|EntityType} except that its shape value is always set to "Sphere" - * when the entity is created. If its shape property value is subsequently changed then the entity's - * type will be reported as "Box" if the shape is set to "Cube", - * otherwise it will be reported as "Shape". - * - * @typedef {object} Entities.EntityProperties-Sphere - * @see {@link Entities.EntityProperties-Shape|EntityProperties-Shape} - */ - -/*@jsdoc - * The "Text" {@link Entities.EntityType|EntityType} displays a 2D rectangle of text in the domain. - * It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. - * - * @typedef {object} Entities.EntityProperties-Text - * @property {Vec3} dimensions=0.1,0.1,0.01 - The dimensions of the entity. - * @property {string} text="" - The text to display on the face of the entity. Text wraps if necessary to fit. New lines can be - * created using \n. Overflowing lines are not displayed. - * @property {number} lineHeight=0.1 - The height of each line of text (thus determining the font size). - * @property {Color} textColor=255,255,255 - The color of the text. - * @property {number} textAlpha=1.0 - The opacity of the text. - * @property {Color} backgroundColor=0,0,0 - The color of the background rectangle. - * @property {number} backgroundAlpha=1.0 - The opacity of the background. - * @property {Entities.Pulse} pulse - Color and alpha pulse. - *

Deprecated: This property is deprecated and will be removed.

- * @property {number} leftMargin=0.0 - The left margin, in meters. - * @property {number} rightMargin=0.0 - The right margin, in meters. - * @property {number} topMargin=0.0 - The top margin, in meters. - * @property {number} bottomMargin=0.0 - The bottom margin, in meters. - * @property {boolean} unlit=false - true if the entity is unaffected by lighting, false if it is lit - * by the key light and local lights. - * @property {string} font="" - The font to render the text with. It can be one of the following: "Courier", - * "Inconsolata", "Roboto", "Timeless", or a path to a PNG MTSDF .arfont file generated - * by the msdf-atlas-gen tool (https://github.com/Chlumsky/msdf-atlas-gen). - * @property {Entities.TextEffect} textEffect="none" - The effect that is applied to the text. - * @property {Color} textEffectColor=255,255,255 - The color of the effect. - * @property {number} textEffectThickness=0.2 - The magnitude of the text effect, range 0.00.5. - * @property {Entities.TextAlignment} alignment="left" - How the text is aligned against its background. - * @property {boolean} faceCamera - true if billboardMode is "yaw", false - * if it isn't. Setting this property to false sets the billboardMode to "none". - *

Deprecated: This property is deprecated and will be removed.

- * @property {boolean} isFacingAvatar - true if billboardMode is "full", - * false if it isn't. Setting this property to false sets the billboardMode to - * "none". - *

Deprecated: This property is deprecated and will be removed.

- * @example Create a text entity. - * var text = Entities.addEntity({ - * type: "Text", - * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })), - * dimensions: { x: 0.6, y: 0.3, z: 0.01 }, - * lineHeight: 0.12, - * text: "Hello\nthere!", - * billboardMode: "yaw", - * lifetime: 300 // Delete after 5 minutes. - * }); - */ - -/*@jsdoc - * The "Web" {@link Entities.EntityType|EntityType} displays a browsable web page. Each user views their own copy - * of the web page: if one user navigates to another page on the entity, other users do not see the change; if a video is being - * played, users don't see it in sync. Internally, a Web entity is rendered as a non-repeating, upside down texture, so additional - * transformations may be necessary if you reference a Web entity texture by UUID. It has properties in addition to the common - * {@link Entities.EntityProperties|EntityProperties}. - * - * @typedef {object} Entities.EntityProperties-Web - * @property {Vec3} dimensions=0.1,0.1,0.01 - The dimensions of the entity. - * @property {string} sourceUrl="" - The URL of the web page to display. This value does not change as you or others navigate - * on the Web entity. - * @property {Color} color=255,255,255 - The color of the web surface. This color tints the web page displayed: the pixel - * colors on the web page are multiplied by the property color. For example, a value of - * { red: 255, green: 0, blue: 0 } lets only the red channel of pixels' colors through. - * @property {number} alpha=1 - The opacity of the web surface. - * @property {Entities.Pulse} pulse - Color and alpha pulse. - *

Deprecated: This property is deprecated and will be removed.

- * @property {boolean} faceCamera - true if billboardMode is "yaw", false - * if it isn't. Setting this property to false sets the billboardMode to "none". - *

Deprecated: This property is deprecated and will be removed.

- * @property {boolean} isFacingAvatar - true if billboardMode is "full", - * false if it isn't. Setting this property to false sets the billboardMode to - * "none". - *

Deprecated: This property is deprecated and will be removed.

- * @property {number} dpi=30 - The resolution to display the page at, in dots per inch. If you convert this to dots per meter - * (multiply by 1 / 0.0254 = 39.3701) then multiply dimensions.x and dimensions.y by that value - * you get the resolution in pixels. - * @property {string} scriptURL="" - The URL of a JavaScript file to inject into the web page. - * @property {number} maxFPS=10 - The maximum update rate for the web content, in frames/second. - * @property {WebInputMode} inputMode="touch" - The user input mode to use. - * @property {boolean} showKeyboardFocusHighlight=true - true if the entity is highlighted when it has keyboard - * focus, false if it isn't. - * @property {boolean} useBackground=true - true if the web entity should have a background, - * false if the web entity's background should be transparent. The webpage must have CSS properties for transparency set - * on the background-color for this property to have an effect. - * @property {string} userAgent - The user agent for the web entity to use when visiting web pages. - * Default value: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) - * Chrome/69.0.3497.113 Mobile Safari/537.36 - * @example Create a Web entity displaying at 1920 x 1080 resolution. - * var METERS_TO_INCHES = 39.3701; - * var entity = Entities.addEntity({ - * type: "Web", - * sourceUrl: "https://overte.org/", - * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.75, z: -4 })), - * rotation: MyAvatar.orientation, - * dimensions: { - * x: 3, - * y: 3 * 1080 / 1920, - * z: 0.01 - * }, - * dpi: 1920 / (3 * METERS_TO_INCHES), - * lifetime: 300 // Delete after 5 minutes. - * }); - */ - -/*@jsdoc - * The "Zone" {@link Entities.EntityType|EntityType} is a volume of lighting effects and avatar permissions. - * Avatar interaction events such as {@link Entities.enterEntity} are also often used with a Zone entity. It has properties in - * addition to the common {@link Entities.EntityProperties|EntityProperties}. - * - * @typedef {object} Entities.EntityProperties-Zone - * @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the volume in which the zone's lighting effects and avatar - * permissions have effect. - * - * @property {ShapeType} shapeType="box" - The shape of the volume in which the zone's lighting effects and avatar - * permissions have effect. Reverts to the default value if set to "none", or set to "compound" - * and compoundShapeURL is "". - * @property {string} compoundShapeURL="" - The model file to use for the compound shape if shapeType is - * "compound". - * - * @property {Entities.ComponentMode} keyLightMode="inherit" - Configures the key light in the zone. - * @property {Entities.KeyLight} keyLight - The key light properties of the zone. - * - * @property {Entities.ComponentMode} ambientLightMode="inherit" - Configures the ambient light in the zone. - * @property {Entities.AmbientLight} ambientLight - The ambient light properties of the zone. - * - * @property {Entities.ComponentMode} skyboxMode="inherit" - Configures the skybox displayed in the zone. - * @property {Entities.Skybox} skybox - The skybox properties of the zone. - * - * @property {Entities.ComponentMode} hazeMode="inherit" - Configures the haze in the zone. - * @property {Entities.Haze} haze - The haze properties of the zone. - * - * @property {Entities.ComponentMode} bloomMode="inherit" - Configures the bloom in the zone. - * @property {Entities.Bloom} bloom - The bloom properties of the zone. - * - * @property {boolean} flyingAllowed=true - true if visitors can fly in the zone; false if they - * cannot. Only works for domain entities. - * @property {boolean} ghostingAllowed=true - true if visitors with avatar collisions turned off will not - * collide with content in the zone; false if visitors will always collide with content in the zone. Only - * works for domain entities. - * - * @property {string} filterURL="" - The URL of a JavaScript file that filters changes to properties of entities within the - * zone. It is periodically executed for each entity in the zone. It can, for example, be used to not allow changes to - * certain properties: - *
- * function filter(properties) {
- *     // Check and edit properties object values,
- *     // e.g., properties.modelURL, as required.
- *     return properties;
- * }
- * 
- * - * @property {Entities.AvatarPriorityMode} avatarPriority="inherit" - Configures the priority of updates from avatars in the - * zone to other clients. - * - * @property {Entities.ScreenshareMode} screenshare="inherit" - Configures a zone for screen-sharing. - * - * @example Create a zone that casts a red key light along the x-axis. - * var zone = Entities.addEntity({ - * type: "Zone", - * position: MyAvatar.position, - * dimensions: { x: 100, y: 100, z: 100 }, - * keyLightMode: "enabled", - * keyLight: { - * "color": { "red": 255, "green": 0, "blue": 0 }, - * "direction": { "x": 1, "y": 0, "z": 0 } - * }, - * lifetime: 300 // Delete after 5 minutes. - * }); - */ - -/*@jsdoc - * The "Image" {@link Entities.EntityType|EntityType} displays an image on a 2D rectangle in the domain. - * It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. - * - * @typedef {object} Entities.EntityProperties-Image - * @property {Vec3} dimensions=0.1,0.1,0.01 - The dimensions of the entity. - * @property {string} imageURL="" - The URL of the image to use. - * @property {boolean} emissive=false - true if the image should be emissive (unlit), false if it - * shouldn't. - * @property {boolean} keepAspectRatio=true - true if the image should maintain its aspect ratio, - * false if it shouldn't. - * @property {Rect} subImage=0,0,0,0 - The portion of the image to display. If width or height are 0, it defaults - * to the full image in that dimension. - * @property {Color} color=255,255,255 - The color of the image. - * @property {number} alpha=1 - The opacity of the image. - * @property {Entities.Pulse} pulse - Color and alpha pulse. - *

Deprecated: This property is deprecated and will be removed.

- * @property {boolean} faceCamera - true if billboardMode is "yaw", false - * if it isn't. Setting this property to false sets the billboardMode to "none". - *

Deprecated: This property is deprecated and will be removed.

- * @property {boolean} isFacingAvatar - true if billboardMode is "full", - * false if it isn't. Setting this property to false sets the billboardMode to - * "none". - *

Deprecated: This property is deprecated and will be removed.

- * @example Create an image entity. - * var image = Entities.addEntity({ - * type: "Image", - * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })), - * dimensions: { x: 0.6, y: 0.3, z: 0.01 }, - * imageURL: "https://images.pexels.com/photos/1020315/pexels-photo-1020315.jpeg", - * billboardMode: "yaw", - * lifetime: 300 // Delete after 5 minutes. - * }); - */ - -/*@jsdoc - * The "Grid" {@link Entities.EntityType|EntityType} displays a grid on a 2D plane. - * It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. - * - * @typedef {object} Entities.EntityProperties-Grid - * @property {Vec3} dimensions - 0.1,0.1,0.01 - The dimensions of the entity. - * @property {Color} color=255,255,255 - The color of the grid. - * @property {number} alpha=1 - The opacity of the grid. - * @property {Entities.Pulse} pulse - Color and alpha pulse. - *

Deprecated: This property is deprecated and will be removed.

- * @property {boolean} followCamera=true - true if the grid is always visible even as the camera moves to another - * position, false if it doesn't follow the camrmea. - * @property {number} majorGridEvery=5 - Integer number of minorGridEvery intervals at which to draw a thick grid - * line. Minimum value = 1. - * @property {number} minorGridEvery=1 - Real number of meters at which to draw thin grid lines. Minimum value = - * 0.001. - * @example Create a grid entity. - * var grid = Entities.addEntity({ - * type: "Grid", - * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })), - * dimensions: { x: 100.0, y: 100.0, z: 0.01 }, - * followCamera: false, - * majorGridEvery: 4, - * minorGridEvery: 0.5, - * lifetime: 300 // Delete after 5 minutes. - * }); - */ - -/*@jsdoc - * The "Gizmo" {@link Entities.EntityType|EntityType} displays an entity that could be used as UI. - * It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. - * - * @typedef {object} Entities.EntityProperties-Gizmo - * @property {Vec3} dimensions=0.1,0.001,0.1 - The dimensions of the entity. - * @property {Entities.GizmoType} gizmoType="ring" - The gizmo type of the entity. - * @property {Entities.RingGizmo} ring - The ring gizmo properties. - */ - -ScriptValue EntityItemProperties::copyToScriptValue(ScriptEngine* engine, bool skipDefaults, bool allowUnknownCreateTime, - bool strictSemantics, - EntityPseudoPropertyFlags pseudoPropertyFlags) const { - - // If strictSemantics is true and skipDefaults is false, then all and only those properties are copied for which the property flag - // is included in _desiredProperties, or is one of the specially enumerated ALWAYS properties below. - // (There may be exceptions, but if so, they are bugs.) - // In all other cases, you are welcome to inspect the code and try to figure out what was intended. I wish you luck. -HRS 1/18/17 - ScriptValue properties = engine->newObject(); - EntityItemProperties defaultEntityProperties; - - const bool pseudoPropertyFlagsActive = pseudoPropertyFlags.test(EntityPseudoPropertyFlag::FlagsActive); - // Fix to skip the default return all mechanism, when pseudoPropertyFlagsActive - const bool returnNothingOnEmptyPropertyFlags = pseudoPropertyFlagsActive; - - if (_created == UNKNOWN_CREATED_TIME && !allowUnknownCreateTime) { - // No entity properties can have been set so return without setting any default, zero property values. - return properties; - } - - auto nodeList = DependencyManager::get(); - bool isMyOwnAvatarEntity = _entityHostType == entity::HostType::AVATAR && (_owningAvatarID == AVATAR_SELF_ID || _owningAvatarID == Physics::getSessionUUID()); - if (_idSet && (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::ID))) { - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(id, _id.toString()); - } - if (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::Type)) { - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(type, EntityTypes::getEntityTypeName(_type)); - } - if ((!skipDefaults || _lifetime != defaultEntityProperties._lifetime) && !strictSemantics) { - if (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::Age)) { - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(age, getAge()); // gettable, but not settable - } - if (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::AgeAsText)) { - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(ageAsText, formatSecondsElapsed(getAge())); // gettable, but not settable - } - } - if (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::LastEdited)) { - properties.setProperty("lastEdited", convertScriptValue(engine, _lastEdited)); - } - if (!skipDefaults) { - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DIMENSIONS, naturalDimensions); // gettable, but not settable - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_POSITION, naturalPosition); - } - - // Core properties - //COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SIMULATION_OWNER, simulationOwner); // not exposed yet - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_ID, parentID); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_JOINT_INDEX, parentJointIndex); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VISIBLE, visible); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_NAME, name); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCKED, locked); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USER_DATA, userData); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PRIVATE_USER_DATA, privateUserData); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_HREF, href); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DESCRIPTION, description); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_POSITION, position); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DIMENSIONS, dimensions); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ROTATION, rotation); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_REGISTRATION_POINT, registrationPoint); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CREATED, created); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LAST_EDITED_BY, lastEditedBy); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_ENTITY_HOST_TYPE, entityHostType, getEntityHostTypeAsString()); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_OWNING_AVATAR_ID, owningAvatarID); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_QUERY_AA_CUBE, queryAACube); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CAN_CAST_SHADOW, canCastShadow); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VISIBLE_IN_SECONDARY_CAMERA, isVisibleInSecondaryCamera); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_RENDER_LAYER, renderLayer, getRenderLayerAsString()); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_PRIMITIVE_MODE, primitiveMode, getPrimitiveModeAsString()); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IGNORE_PICK_INTERSECTION, ignorePickIntersection); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RENDER_WITH_ZONES, renderWithZones); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BILLBOARD_MODE, billboardMode, getBillboardModeAsString()); - _grab.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags, isMyOwnAvatarEntity); - - // Physics - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DENSITY, density); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VELOCITY, velocity); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANGULAR_VELOCITY, angularVelocity); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAVITY, gravity); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ACCELERATION, acceleration); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DAMPING, damping); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANGULAR_DAMPING, angularDamping); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RESTITUTION, restitution); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FRICTION, friction); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LIFETIME, lifetime); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISIONLESS, collisionless); - COPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_COLLISIONLESS, collisionless, ignoreForCollisions, getCollisionless()); // legacy support - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_MASK, collisionMask); - COPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_COLLISION_MASK, collisionMask, collidesWith, getCollisionMaskAsString()); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DYNAMIC, dynamic); - COPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_DYNAMIC, dynamic, collisionsWillMove, getDynamic()); // legacy support - COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_COLLISION_SOUND_URL, collisionSoundURL); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ACTION_DATA, actionData); - - // Cloning - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONEABLE, cloneable); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONE_LIFETIME, cloneLifetime); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONE_LIMIT, cloneLimit); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONE_DYNAMIC, cloneDynamic); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONE_AVATAR_ENTITY, cloneAvatarEntity); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CLONE_ORIGIN_ID, cloneOriginID); - - // Scripts - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SCRIPT, script); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SCRIPT_TIMESTAMP, scriptTimestamp); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SERVER_SCRIPTS, serverScripts); - - // Local props for scripts - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_POSITION, localPosition); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localRotation); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_VELOCITY, localVelocity); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ANGULAR_VELOCITY, localAngularVelocity); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_DIMENSIONS, localDimensions); - - // Particles only - if (_type == EntityTypes::ParticleEffect) { - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, getShapeTypeAsString()); - COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_COMPOUND_SHAPE_URL, compoundShapeURL); - COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha); - _pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags, isMyOwnAvatarEntity); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXTURES, textures); - - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MAX_PARTICLES, maxParticles); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LIFESPAN, lifespan); - - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMITTING_PARTICLES, isEmitting); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_RATE, emitRate); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_SPEED, emitSpeed); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SPEED_SPREAD, speedSpread); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_ORIENTATION, emitOrientation); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_DIMENSIONS, emitDimensions); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_RADIUS_START, emitRadiusStart); - - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_POLAR_START, polarStart); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_POLAR_FINISH, polarFinish); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_AZIMUTH_START, azimuthStart); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_AZIMUTH_FINISH, azimuthFinish); - - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMIT_ACCELERATION, emitAcceleration); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ACCELERATION_SPREAD, accelerationSpread); - - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARTICLE_RADIUS, particleRadius); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RADIUS_SPREAD, radiusSpread); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RADIUS_START, radiusStart); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RADIUS_FINISH, radiusFinish); - - COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR_SPREAD, colorSpread, u8vec3Color); - COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR_START, colorStart, vec3Color); - COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR_FINISH, colorFinish, vec3Color); - - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_SPREAD, alphaSpread); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_START, alphaStart); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_FINISH, alphaFinish); - - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMITTER_SHOULD_TRAIL, emitterShouldTrail); - - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARTICLE_SPIN, particleSpin); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SPIN_SPREAD, spinSpread); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SPIN_START, spinStart); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SPIN_FINISH, spinFinish); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARTICLE_ROTATE_WITH_ENTITY, rotateWithEntity); - } - - // Models only - if (_type == EntityTypes::Model) { - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, getShapeTypeAsString()); - COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_COMPOUND_SHAPE_URL, compoundShapeURL); - COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXTURES, textures); - - COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_MODEL_URL, modelURL); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MODEL_SCALE, modelScale); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_ROTATIONS_SET, jointRotationsSet); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_ROTATIONS, jointRotations); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_TRANSLATIONS_SET, jointTranslationsSet); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_TRANSLATIONS, jointTranslations); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RELAY_PARENT_JOINTS, relayParentJoints); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_GROUP_CULLED, groupCulled); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_BLENDSHAPE_COEFFICIENTS, blendshapeCoefficients); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USE_ORIGINAL_PIVOT, useOriginalPivot); - _animation.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags, isMyOwnAvatarEntity); - } - - // FIXME: Shouldn't provide a shapeType property for Box and Sphere entities. - if (_type == EntityTypes::Box) { - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, QString("Box")); - } - if (_type == EntityTypes::Sphere) { - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, QString("Sphere")); - } - - if (_type == EntityTypes::Box || _type == EntityTypes::Sphere || _type == EntityTypes::Shape) { - COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha); - _pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags, isMyOwnAvatarEntity); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SHAPE, shape); - } - - // Lights only - if (_type == EntityTypes::Light) { - COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IS_SPOTLIGHT, isSpotlight); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_INTENSITY, intensity); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EXPONENT, exponent); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_CUTOFF, cutoff); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FALLOFF_RADIUS, falloffRadius); - } - - // Text only - if (_type == EntityTypes::Text) { - _pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags, isMyOwnAvatarEntity); - - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXT, text); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_HEIGHT, lineHeight); - COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_TEXT_COLOR, textColor, u8vec3Color); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXT_ALPHA, textAlpha); - COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_BACKGROUND_COLOR, backgroundColor, u8vec3Color); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_BACKGROUND_ALPHA, backgroundAlpha); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LEFT_MARGIN, leftMargin); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_RIGHT_MARGIN, rightMargin); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TOP_MARGIN, topMargin); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_BOTTOM_MARGIN, bottomMargin); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_UNLIT, unlit); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FONT, font); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_TEXT_EFFECT, textEffect, getTextEffectAsString()); - COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_TEXT_EFFECT_COLOR, textEffectColor, u8vec3Color); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXT_EFFECT_THICKNESS, textEffectThickness); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_TEXT_ALIGNMENT, alignment, getAlignmentAsString()); - } - - // Zones only - if (_type == EntityTypes::Zone) { - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SHAPE_TYPE, shapeType, getShapeTypeAsString()); - COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_COMPOUND_SHAPE_URL, compoundShapeURL); - - _keyLight.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags, isMyOwnAvatarEntity); - _ambientLight.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags, isMyOwnAvatarEntity); - _skybox.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags, isMyOwnAvatarEntity); - _haze.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags, isMyOwnAvatarEntity); - _bloom.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags, isMyOwnAvatarEntity); - - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_FLYING_ALLOWED, flyingAllowed); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_GHOSTING_ALLOWED, ghostingAllowed); - COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_FILTER_URL, filterURL); - - 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()); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_HAZE_MODE, hazeMode, getHazeModeAsString()); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BLOOM_MODE, bloomMode, getBloomModeAsString()); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_AVATAR_PRIORITY, avatarPriority, getAvatarPriorityAsString()); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SCREENSHARE, screenshare, getScreenshareAsString()); - } - - // Web only - if (_type == EntityTypes::Web) { - COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha); - _pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags, isMyOwnAvatarEntity); - - COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_SOURCE_URL, sourceUrl); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DPI, dpi); - COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_SCRIPT_URL, scriptURL); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MAX_FPS, maxFPS); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_INPUT_MODE, inputMode, getInputModeAsString()); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, showKeyboardFocusHighlight); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_WEB_USE_BACKGROUND, useBackground); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_USER_AGENT, userAgent); - } - - // PolyVoxel only - if (_type == EntityTypes::PolyVox) { - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VOXEL_DATA, voxelData); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VOXEL_SURFACE_STYLE, voxelSurfaceStyle); - COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_X_TEXTURE_URL, xTextureURL); - COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_Y_TEXTURE_URL, yTextureURL); - COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_Z_TEXTURE_URL, zTextureURL); - - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_X_N_NEIGHBOR_ID, xNNeighborID); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Y_N_NEIGHBOR_ID, yNNeighborID); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Z_N_NEIGHBOR_ID, zNNeighborID); - - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_X_P_NEIGHBOR_ID, xPNeighborID); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Y_P_NEIGHBOR_ID, yPNeighborID); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_Z_P_NEIGHBOR_ID, zPNeighborID); - } - - // Lines - if (_type == EntityTypes::Line) { - COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color); - - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_POINTS, linePoints); - } - - // Polylines - if (_type == EntityTypes::PolyLine) { - COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXTURES, textures); - - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_POINTS, linePoints); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_STROKE_WIDTHS, strokeWidths); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_STROKE_NORMALS, normals); - COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_STROKE_COLORS, strokeColors, qVectorVec3Color); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IS_UV_MODE_STRETCH, isUVModeStretch); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_GLOW, glow); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LINE_FACE_CAMERA, faceCamera); - } - - // Materials - if (_type == EntityTypes::Material) { - COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_MATERIAL_URL, materialURL); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_MATERIAL_MAPPING_MODE, materialMappingMode, getMaterialMappingModeAsString()); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_PRIORITY, priority); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_MATERIAL_NAME, parentMaterialName); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_MAPPING_POS, materialMappingPos); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_MAPPING_SCALE, materialMappingScale); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_MAPPING_ROT, materialMappingRot); - COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_MATERIAL_DATA, materialData); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_REPEAT, materialRepeat); - } - - // Image only - if (_type == EntityTypes::Image) { - COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha); - _pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags, isMyOwnAvatarEntity); - - COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_IMAGE_URL, imageURL); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMISSIVE, emissive); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_KEEP_ASPECT_RATIO, keepAspectRatio); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SUB_IMAGE, subImage); - - // Handle conversions to old 'textures' property from "imageURL" - if ((isMyOwnAvatarEntity || nodeList->getThisNodeCanViewAssetURLs()) && - ((!returnNothingOnEmptyPropertyFlags && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(PROP_IMAGE_URL)) && - (!skipDefaults || defaultEntityProperties._imageURL != _imageURL)) { - ScriptValue textures = engine->newObject(); - textures.setProperty("tex.picture", _imageURL); - properties.setProperty("textures", textures); - } - } - - // Grid only - if (_type == EntityTypes::Grid) { - COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_COLOR, color, u8vec3Color); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA, alpha); - _pulse.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags, isMyOwnAvatarEntity); - - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_GRID_FOLLOW_CAMERA, followCamera); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MAJOR_GRID_EVERY, majorGridEvery); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MINOR_GRID_EVERY, minorGridEvery); - } - - // Gizmo only - if (_type == EntityTypes::Gizmo) { - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_GIZMO_TYPE, gizmoType, getGizmoTypeAsString()); - _ring.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties, returnNothingOnEmptyPropertyFlags, isMyOwnAvatarEntity); - } - - /*@jsdoc - * The axis-aligned bounding box of an entity. - * @typedef {object} Entities.BoundingBox - * @property {Vec3} brn - The bottom right near (minimum axes values) corner of the AA box. - * @property {Vec3} tfl - The top far left (maximum axes values) corner of the AA box. - * @property {Vec3} center - The center of the AA box. - * @property {Vec3} dimensions - The dimensions of the AA box. - */ - if (!skipDefaults && !strictSemantics && - (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::BoundingBox))) { - - AABox aaBox = getAABox(); - ScriptValue boundingBox = engine->newObject(); - ScriptValue bottomRightNear = vec3ToScriptValue(engine, aaBox.getCorner()); - ScriptValue topFarLeft = vec3ToScriptValue(engine, aaBox.calcTopFarLeft()); - ScriptValue center = vec3ToScriptValue(engine, aaBox.calcCenter()); - ScriptValue boundingBoxDimensions = vec3ToScriptValue(engine, aaBox.getDimensions()); - boundingBox.setProperty("brn", bottomRightNear); - boundingBox.setProperty("tfl", topFarLeft); - boundingBox.setProperty("center", center); - boundingBox.setProperty("dimensions", boundingBoxDimensions); - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(boundingBox, boundingBox); // gettable, but not settable - } - - QString textureNamesStr = QJsonDocument::fromVariant(_textureNames).toJson(); - if (!skipDefaults && !strictSemantics && (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::OriginalTextures))) { - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(originalTextures, textureNamesStr); // gettable, but not settable - } - - // Rendering info - if (!skipDefaults && !strictSemantics && - (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::RenderInfo))) { - - ScriptValue renderInfo = engine->newObject(); - - /*@jsdoc - * Information on how an entity is rendered. Properties are only filled in for Model entities; other - * entity types have an empty object, {}. - * @typedef {object} Entities.RenderInfo - * @property {number} verticesCount - The number of vertices in the entity. - * @property {number} texturesCount - The number of textures in the entity. - * @property {number} texturesSize - The total size of the textures in the entity, in bytes. - * @property {boolean} hasTransparent - true if any of the textures has transparency, false - * if none of them do. - * @property {number} drawCalls - The number of draw calls required to render the entity. - */ - // currently only supported by models - if (_type == EntityTypes::Model) { - renderInfo.setProperty("verticesCount", (int)getRenderInfoVertexCount()); // FIXME - theoretically the number of vertex could be > max int - renderInfo.setProperty("texturesSize", (int)getRenderInfoTextureSize()); // FIXME - theoretically the size of textures could be > max int - renderInfo.setProperty("hasTransparent", getRenderInfoHasTransparent()); - renderInfo.setProperty("drawCalls", getRenderInfoDrawCalls()); - renderInfo.setProperty("texturesCount", getRenderInfoTextureCount()); - } - - COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(renderInfo, renderInfo); // Gettable but not settable - } - - if (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::ClientOnly)) { - properties.setProperty("clientOnly", convertScriptValue(engine, getEntityHostType() == entity::HostType::AVATAR)); - } - if (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::AvatarEntity)) { - properties.setProperty("avatarEntity", convertScriptValue(engine, getEntityHostType() == entity::HostType::AVATAR)); - } - if (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::LocalEntity)) { - properties.setProperty("localEntity", convertScriptValue(engine, getEntityHostType() == entity::HostType::LOCAL)); - } - - if (_type != EntityTypes::PolyLine && (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::FaceCamera))) { - properties.setProperty("faceCamera", convertScriptValue(engine, getBillboardMode() == BillboardMode::YAW)); - } - if (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::IsFacingAvatar)) { - properties.setProperty("isFacingAvatar", convertScriptValue(engine, getBillboardMode() == BillboardMode::FULL)); - } - - return properties; -} - -void EntityItemProperties::copyFromScriptValue(const ScriptValue& object, bool honorReadOnly) { - //qDebug() << "EntityItemProperties::copyFromScriptValue: properties: " << object.getPropertyNames(); - QList namesList = object.getPropertyNames(); - - QSet namesSet; - for (auto name = namesList.cbegin(); name != namesList.cend(); name++) { - namesSet.insert(*name); - } - - ScriptValue typeScriptValue = object.property("type"); - if (typeScriptValue.isValid()) { - setType(typeScriptValue.toVariant().toString()); - } - - // Core - if (!honorReadOnly) { - // not handled yet - // COPY_PROPERTY_FROM_QSCRIPTVALUE(simulationOwner, SimulationOwner, setSimulationOwner); - } - COPY_PROPERTY_FROM_QSCRIPTVALUE(parentID, QUuid, setParentID); - COPY_PROPERTY_FROM_QSCRIPTVALUE(parentJointIndex, quint16, setParentJointIndex); - COPY_PROPERTY_FROM_QSCRIPTVALUE(visible, bool, setVisible); - COPY_PROPERTY_FROM_QSCRIPTVALUE(name, QString, setName); - COPY_PROPERTY_FROM_QSCRIPTVALUE(locked, bool, setLocked); - COPY_PROPERTY_FROM_QSCRIPTVALUE(userData, QString, setUserData); - COPY_PROPERTY_FROM_QSCRIPTVALUE(privateUserData, QString, setPrivateUserData); - COPY_PROPERTY_FROM_QSCRIPTVALUE(href, QString, setHref); - COPY_PROPERTY_FROM_QSCRIPTVALUE(description, QString, setDescription); - COPY_PROPERTY_FROM_QSCRIPTVALUE(position, vec3, setPosition); - COPY_PROPERTY_FROM_QSCRIPTVALUE(dimensions, vec3, setDimensions); - COPY_PROPERTY_FROM_QSCRIPTVALUE(rotation, quat, setRotation); - COPY_PROPERTY_FROM_QSCRIPTVALUE(registrationPoint, vec3, setRegistrationPoint); - if (!honorReadOnly) { - COPY_PROPERTY_FROM_QSCRIPTVALUE(created, quint64, setCreated); - COPY_PROPERTY_FROM_QSCRIPTVALUE(lastEditedBy, QUuid, setLastEditedBy); - COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(entityHostType, EntityHostType); - COPY_PROPERTY_FROM_QSCRIPTVALUE(owningAvatarID, QUuid, setOwningAvatarID); - } - COPY_PROPERTY_FROM_QSCRIPTVALUE(queryAACube, AACube, setQueryAACube); // TODO: should scripts be able to set this? - COPY_PROPERTY_FROM_QSCRIPTVALUE(canCastShadow, bool, setCanCastShadow); - COPY_PROPERTY_FROM_QSCRIPTVALUE(isVisibleInSecondaryCamera, bool, setIsVisibleInSecondaryCamera); - COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(renderLayer, RenderLayer); - COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(primitiveMode, PrimitiveMode); - COPY_PROPERTY_FROM_QSCRIPTVALUE(ignorePickIntersection, bool, setIgnorePickIntersection); - COPY_PROPERTY_FROM_QSCRIPTVALUE(renderWithZones, qVectorQUuid, setRenderWithZones); - COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(billboardMode, BillboardMode); - _grab.copyFromScriptValue(object, namesSet, _defaultSettings); - - // Physics - COPY_PROPERTY_FROM_QSCRIPTVALUE(density, float, setDensity); - COPY_PROPERTY_FROM_QSCRIPTVALUE(velocity, vec3, setVelocity); - COPY_PROPERTY_FROM_QSCRIPTVALUE(angularVelocity, vec3, setAngularVelocity); - COPY_PROPERTY_FROM_QSCRIPTVALUE(gravity, vec3, setGravity); - COPY_PROPERTY_FROM_QSCRIPTVALUE(acceleration, vec3, setAcceleration); - COPY_PROPERTY_FROM_QSCRIPTVALUE(damping, float, setDamping); - COPY_PROPERTY_FROM_QSCRIPTVALUE(angularDamping, float, setAngularDamping); - COPY_PROPERTY_FROM_QSCRIPTVALUE(restitution, float, setRestitution); - COPY_PROPERTY_FROM_QSCRIPTVALUE(friction, float, setFriction); - COPY_PROPERTY_FROM_QSCRIPTVALUE(lifetime, float, setLifetime); - COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionless, bool, setCollisionless); - COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(ignoreForCollisions, bool, setCollisionless, getCollisionless); // legacy support - COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionMask, uint16_t, setCollisionMask); - COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(collidesWith, CollisionMask); - COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(collisionsWillMove, bool, setDynamic, getDynamic); // legacy support - COPY_PROPERTY_FROM_QSCRIPTVALUE(dynamic, bool, setDynamic); - COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionSoundURL, QString, setCollisionSoundURL); - if (!honorReadOnly) { - COPY_PROPERTY_FROM_QSCRIPTVALUE(actionData, QByteArray, setActionData); - } - - // Cloning - COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneable, bool, setCloneable); - COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneLifetime, float, setCloneLifetime); - COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneLimit, float, setCloneLimit); - COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneDynamic, bool, setCloneDynamic); - COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneAvatarEntity, bool, setCloneAvatarEntity); - COPY_PROPERTY_FROM_QSCRIPTVALUE(cloneOriginID, QUuid, setCloneOriginID); - - // Scripts - COPY_PROPERTY_FROM_QSCRIPTVALUE(script, QString, setScript); - COPY_PROPERTY_FROM_QSCRIPTVALUE(scriptTimestamp, quint64, setScriptTimestamp); - COPY_PROPERTY_FROM_QSCRIPTVALUE(serverScripts, QString, setServerScripts); - - // Script location data - COPY_PROPERTY_FROM_QSCRIPTVALUE(localPosition, vec3, setLocalPosition); - COPY_PROPERTY_FROM_QSCRIPTVALUE(localRotation, quat, setLocalRotation); - COPY_PROPERTY_FROM_QSCRIPTVALUE(localVelocity, vec3, setLocalVelocity); - COPY_PROPERTY_FROM_QSCRIPTVALUE(localAngularVelocity, vec3, setLocalAngularVelocity); - COPY_PROPERTY_FROM_QSCRIPTVALUE(localDimensions, vec3, setLocalDimensions); - - // Common - COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(shapeType, ShapeType); - COPY_PROPERTY_FROM_QSCRIPTVALUE(compoundShapeURL, QString, setCompoundShapeURL); - COPY_PROPERTY_FROM_QSCRIPTVALUE(color, u8vec3Color, setColor); - COPY_PROPERTY_FROM_QSCRIPTVALUE(alpha, float, setAlpha); - _pulse.copyFromScriptValue(object, namesSet, _defaultSettings); - COPY_PROPERTY_FROM_QSCRIPTVALUE(textures, QString, setTextures); - - // Particles - COPY_PROPERTY_FROM_QSCRIPTVALUE(maxParticles, quint32, setMaxParticles); - COPY_PROPERTY_FROM_QSCRIPTVALUE(lifespan, float, setLifespan); - COPY_PROPERTY_FROM_QSCRIPTVALUE(isEmitting, bool, setIsEmitting); - COPY_PROPERTY_FROM_QSCRIPTVALUE(emitRate, float, setEmitRate); - COPY_PROPERTY_FROM_QSCRIPTVALUE(emitSpeed, float, setEmitSpeed); - COPY_PROPERTY_FROM_QSCRIPTVALUE(speedSpread, float, setSpeedSpread); - COPY_PROPERTY_FROM_QSCRIPTVALUE(emitOrientation, quat, setEmitOrientation); - COPY_PROPERTY_FROM_QSCRIPTVALUE(emitDimensions, vec3, setEmitDimensions); - COPY_PROPERTY_FROM_QSCRIPTVALUE(emitRadiusStart, float, setEmitRadiusStart); - COPY_PROPERTY_FROM_QSCRIPTVALUE(polarStart, float, setPolarStart); - COPY_PROPERTY_FROM_QSCRIPTVALUE(polarFinish, float, setPolarFinish); - COPY_PROPERTY_FROM_QSCRIPTVALUE(azimuthStart, float, setAzimuthStart); - COPY_PROPERTY_FROM_QSCRIPTVALUE(azimuthFinish, float, setAzimuthFinish); - COPY_PROPERTY_FROM_QSCRIPTVALUE(emitAcceleration, vec3, setEmitAcceleration); - COPY_PROPERTY_FROM_QSCRIPTVALUE(accelerationSpread, vec3, setAccelerationSpread); - COPY_PROPERTY_FROM_QSCRIPTVALUE(particleRadius, float, setParticleRadius); - COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusSpread, float, setRadiusSpread); - COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusStart, float, setRadiusStart); - COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusFinish, float, setRadiusFinish); - COPY_PROPERTY_FROM_QSCRIPTVALUE(colorSpread, u8vec3Color, setColorSpread); - COPY_PROPERTY_FROM_QSCRIPTVALUE(colorStart, vec3Color, setColorStart); - COPY_PROPERTY_FROM_QSCRIPTVALUE(colorFinish, vec3Color, setColorFinish); - COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaSpread, float, setAlphaSpread); - COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaStart, float, setAlphaStart); - COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaFinish, float, setAlphaFinish); - COPY_PROPERTY_FROM_QSCRIPTVALUE(emitterShouldTrail, bool, setEmitterShouldTrail); - COPY_PROPERTY_FROM_QSCRIPTVALUE(particleSpin, float, setParticleSpin); - COPY_PROPERTY_FROM_QSCRIPTVALUE(spinSpread, float, setSpinSpread); - COPY_PROPERTY_FROM_QSCRIPTVALUE(spinStart, float, setSpinStart); - COPY_PROPERTY_FROM_QSCRIPTVALUE(spinFinish, float, setSpinFinish); - COPY_PROPERTY_FROM_QSCRIPTVALUE(rotateWithEntity, bool, setRotateWithEntity); - - // Model - COPY_PROPERTY_FROM_QSCRIPTVALUE(modelURL, QString, setModelURL); - COPY_PROPERTY_FROM_QSCRIPTVALUE(modelScale, vec3, setModelScale); - COPY_PROPERTY_FROM_QSCRIPTVALUE(jointRotationsSet, qVectorBool, setJointRotationsSet); - COPY_PROPERTY_FROM_QSCRIPTVALUE(jointRotations, qVectorQuat, setJointRotations); - COPY_PROPERTY_FROM_QSCRIPTVALUE(jointTranslationsSet, qVectorBool, setJointTranslationsSet); - COPY_PROPERTY_FROM_QSCRIPTVALUE(jointTranslations, qVectorVec3, setJointTranslations); - COPY_PROPERTY_FROM_QSCRIPTVALUE(relayParentJoints, bool, setRelayParentJoints); - COPY_PROPERTY_FROM_QSCRIPTVALUE(groupCulled, bool, setGroupCulled); - COPY_PROPERTY_FROM_QSCRIPTVALUE(blendshapeCoefficients, QString, setBlendshapeCoefficients); - COPY_PROPERTY_FROM_QSCRIPTVALUE(useOriginalPivot, bool, setUseOriginalPivot); - _animation.copyFromScriptValue(object, namesSet, _defaultSettings); - - // Light - COPY_PROPERTY_FROM_QSCRIPTVALUE(isSpotlight, bool, setIsSpotlight); - COPY_PROPERTY_FROM_QSCRIPTVALUE(intensity, float, setIntensity); - COPY_PROPERTY_FROM_QSCRIPTVALUE(exponent, float, setExponent); - COPY_PROPERTY_FROM_QSCRIPTVALUE(cutoff, float, setCutoff); - COPY_PROPERTY_FROM_QSCRIPTVALUE(falloffRadius, float, setFalloffRadius); - - // Text - COPY_PROPERTY_FROM_QSCRIPTVALUE(text, QString, setText); - COPY_PROPERTY_FROM_QSCRIPTVALUE(lineHeight, float, setLineHeight); - COPY_PROPERTY_FROM_QSCRIPTVALUE(textColor, u8vec3Color, setTextColor); - COPY_PROPERTY_FROM_QSCRIPTVALUE(textAlpha, float, setTextAlpha); - COPY_PROPERTY_FROM_QSCRIPTVALUE(backgroundColor, u8vec3Color, setBackgroundColor); - COPY_PROPERTY_FROM_QSCRIPTVALUE(backgroundAlpha, float, setBackgroundAlpha); - COPY_PROPERTY_FROM_QSCRIPTVALUE(leftMargin, float, setLeftMargin); - COPY_PROPERTY_FROM_QSCRIPTVALUE(rightMargin, float, setRightMargin); - COPY_PROPERTY_FROM_QSCRIPTVALUE(topMargin, float, setTopMargin); - COPY_PROPERTY_FROM_QSCRIPTVALUE(bottomMargin, float, setBottomMargin); - COPY_PROPERTY_FROM_QSCRIPTVALUE(unlit, bool, setUnlit); - COPY_PROPERTY_FROM_QSCRIPTVALUE(font, QString, setFont); - COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(textEffect, TextEffect); - COPY_PROPERTY_FROM_QSCRIPTVALUE(textEffectColor, u8vec3Color, setTextEffectColor); - COPY_PROPERTY_FROM_QSCRIPTVALUE(textEffectThickness, float, setTextEffectThickness); - COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(alignment, Alignment); - - // Zone - _keyLight.copyFromScriptValue(object, namesSet, _defaultSettings); - _ambientLight.copyFromScriptValue(object, namesSet, _defaultSettings); - _skybox.copyFromScriptValue(object, namesSet, _defaultSettings); - _haze.copyFromScriptValue(object, namesSet, _defaultSettings); - _bloom.copyFromScriptValue(object, namesSet, _defaultSettings); - COPY_PROPERTY_FROM_QSCRIPTVALUE(flyingAllowed, bool, setFlyingAllowed); - COPY_PROPERTY_FROM_QSCRIPTVALUE(ghostingAllowed, bool, setGhostingAllowed); - COPY_PROPERTY_FROM_QSCRIPTVALUE(filterURL, QString, setFilterURL); - 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(hazeMode, HazeMode); - COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(bloomMode, BloomMode); - COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(avatarPriority, AvatarPriority); - COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(screenshare, Screenshare); - - // Polyvox - COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelVolumeSize, vec3, setVoxelVolumeSize); - COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelData, QByteArray, setVoxelData); - COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelSurfaceStyle, uint16_t, setVoxelSurfaceStyle); - COPY_PROPERTY_FROM_QSCRIPTVALUE(xTextureURL, QString, setXTextureURL); - COPY_PROPERTY_FROM_QSCRIPTVALUE(yTextureURL, QString, setYTextureURL); - COPY_PROPERTY_FROM_QSCRIPTVALUE(zTextureURL, QString, setZTextureURL); - COPY_PROPERTY_FROM_QSCRIPTVALUE(xNNeighborID, EntityItemID, setXNNeighborID); - COPY_PROPERTY_FROM_QSCRIPTVALUE(yNNeighborID, EntityItemID, setYNNeighborID); - COPY_PROPERTY_FROM_QSCRIPTVALUE(zNNeighborID, EntityItemID, setZNNeighborID); - COPY_PROPERTY_FROM_QSCRIPTVALUE(xPNeighborID, EntityItemID, setXPNeighborID); - COPY_PROPERTY_FROM_QSCRIPTVALUE(yPNeighborID, EntityItemID, setYPNeighborID); - COPY_PROPERTY_FROM_QSCRIPTVALUE(zPNeighborID, EntityItemID, setZPNeighborID); - - // Web - COPY_PROPERTY_FROM_QSCRIPTVALUE(sourceUrl, QString, setSourceUrl); - COPY_PROPERTY_FROM_QSCRIPTVALUE(dpi, uint16_t, setDPI); - COPY_PROPERTY_FROM_QSCRIPTVALUE(scriptURL, QString, setScriptURL); - COPY_PROPERTY_FROM_QSCRIPTVALUE(maxFPS, uint8_t, setMaxFPS); - COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(inputMode, InputMode); - COPY_PROPERTY_FROM_QSCRIPTVALUE(showKeyboardFocusHighlight, bool, setShowKeyboardFocusHighlight); - COPY_PROPERTY_FROM_QSCRIPTVALUE(useBackground, bool, setUseBackground); - COPY_PROPERTY_FROM_QSCRIPTVALUE(userAgent, QString, setUserAgent); - - // Polyline - COPY_PROPERTY_FROM_QSCRIPTVALUE(linePoints, qVectorVec3, setLinePoints); - COPY_PROPERTY_FROM_QSCRIPTVALUE(strokeWidths, qVectorFloat, setStrokeWidths); - COPY_PROPERTY_FROM_QSCRIPTVALUE(normals, qVectorVec3, setNormals); - COPY_PROPERTY_FROM_QSCRIPTVALUE(strokeColors, qVectorVec3, setStrokeColors); - COPY_PROPERTY_FROM_QSCRIPTVALUE(isUVModeStretch, bool, setIsUVModeStretch); - COPY_PROPERTY_FROM_QSCRIPTVALUE(glow, bool, setGlow); - COPY_PROPERTY_FROM_QSCRIPTVALUE(faceCamera, bool, setFaceCamera); - - // Shape - COPY_PROPERTY_FROM_QSCRIPTVALUE(shape, QString, setShape); - - // Material - COPY_PROPERTY_FROM_QSCRIPTVALUE(materialURL, QString, setMaterialURL); - COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(materialMappingMode, MaterialMappingMode); - COPY_PROPERTY_FROM_QSCRIPTVALUE(priority, quint16, setPriority); - COPY_PROPERTY_FROM_QSCRIPTVALUE(parentMaterialName, QString, setParentMaterialName); - COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingPos, vec2, setMaterialMappingPos); - COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingScale, vec2, setMaterialMappingScale); - COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingRot, float, setMaterialMappingRot); - COPY_PROPERTY_FROM_QSCRIPTVALUE(materialData, QString, setMaterialData); - COPY_PROPERTY_FROM_QSCRIPTVALUE(materialRepeat, bool, setMaterialRepeat); - - // Image - COPY_PROPERTY_FROM_QSCRIPTVALUE(imageURL, QString, setImageURL); - COPY_PROPERTY_FROM_QSCRIPTVALUE(emissive, bool, setEmissive); - COPY_PROPERTY_FROM_QSCRIPTVALUE(keepAspectRatio, bool, setKeepAspectRatio); - COPY_PROPERTY_FROM_QSCRIPTVALUE(subImage, QRect, setSubImage); - - // Grid - COPY_PROPERTY_FROM_QSCRIPTVALUE(followCamera, bool, setFollowCamera); - COPY_PROPERTY_FROM_QSCRIPTVALUE(majorGridEvery, uint32_t, setMajorGridEvery); - COPY_PROPERTY_FROM_QSCRIPTVALUE(minorGridEvery, float, setMinorGridEvery); - - // Gizmo - COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(gizmoType, GizmoType); - _ring.copyFromScriptValue(object, namesSet, _defaultSettings); - - // Handle conversions from old 'textures' property to "imageURL" - if (namesSet.contains("textures")) { - ScriptValue V = object.property("textures"); - if (_type == EntityTypes::Image && V.isValid() && !object.property("imageURL").isValid()) { - bool isValid = false; - QString textures = QString_convertFromScriptValue(V, isValid); - if (isValid) { - QVariantMap texturesMap = parseTexturesToMap(textures, QVariantMap()); - auto texPicture = texturesMap.find("tex.picture"); - if (texPicture != texturesMap.end()) { - auto imageURL = texPicture.value().toString(); - if (_defaultSettings || imageURL != _imageURL) { - setImageURL(imageURL); - } - } - } - } - } - - // Handle old "faceCamera" and "isFacingAvatar" props - if (_type != EntityTypes::PolyLine && namesSet.contains("textures")) { - ScriptValue P = object.property("faceCamera"); - if (P.isValid() && !object.property("billboardMode").isValid()) { - bool newValue = P.toVariant().toBool(); - bool oldValue = getBillboardMode() == BillboardMode::YAW; - if (_defaultSettings || newValue != oldValue) { - setBillboardMode(newValue ? BillboardMode::YAW : BillboardMode::NONE); - } - } - } - if (namesSet.contains("isFacingAvatar")) { - ScriptValue P = object.property("isFacingAvatar"); - if (P.isValid() && !object.property("billboardMode").isValid() && !object.property("faceCamera").isValid()) { - bool newValue = P.toVariant().toBool(); - bool oldValue = getBillboardMode() == BillboardMode::FULL; - if (_defaultSettings || newValue != oldValue) { - setBillboardMode(newValue ? BillboardMode::FULL : BillboardMode::NONE); - } - } - } - - _lastEdited = usecTimestampNow(); -} - -void EntityItemProperties::copyFromJSONString(ScriptEngine& scriptEngine, const QString& jsonString) { - // DANGER: this method is expensive - QJsonDocument propertiesDoc = QJsonDocument::fromJson(jsonString.toUtf8()); - QJsonObject propertiesObj = propertiesDoc.object(); - QVariant propertiesVariant(propertiesObj); - QVariantMap propertiesMap = propertiesVariant.toMap(); - ScriptValue propertiesScriptValue = variantMapToScriptValue(propertiesMap, scriptEngine); - bool honorReadOnly = true; - copyFromScriptValue(propertiesScriptValue, honorReadOnly); -} - - -void EntityItemProperties::merge(const EntityItemProperties& other) { - // Core - COPY_PROPERTY_IF_CHANGED(simulationOwner); - COPY_PROPERTY_IF_CHANGED(parentID); - COPY_PROPERTY_IF_CHANGED(parentJointIndex); - COPY_PROPERTY_IF_CHANGED(visible); - COPY_PROPERTY_IF_CHANGED(name); - COPY_PROPERTY_IF_CHANGED(locked); - COPY_PROPERTY_IF_CHANGED(userData); - COPY_PROPERTY_IF_CHANGED(privateUserData); - COPY_PROPERTY_IF_CHANGED(href); - COPY_PROPERTY_IF_CHANGED(description); - COPY_PROPERTY_IF_CHANGED(position); - COPY_PROPERTY_IF_CHANGED(dimensions); - COPY_PROPERTY_IF_CHANGED(rotation); - COPY_PROPERTY_IF_CHANGED(registrationPoint); - COPY_PROPERTY_IF_CHANGED(created); - COPY_PROPERTY_IF_CHANGED(lastEditedBy); - COPY_PROPERTY_IF_CHANGED(entityHostType); - COPY_PROPERTY_IF_CHANGED(owningAvatarID); - COPY_PROPERTY_IF_CHANGED(queryAACube); - COPY_PROPERTY_IF_CHANGED(canCastShadow); - COPY_PROPERTY_IF_CHANGED(isVisibleInSecondaryCamera); - COPY_PROPERTY_IF_CHANGED(renderLayer); - COPY_PROPERTY_IF_CHANGED(primitiveMode); - COPY_PROPERTY_IF_CHANGED(ignorePickIntersection); - COPY_PROPERTY_IF_CHANGED(renderWithZones); - COPY_PROPERTY_IF_CHANGED(billboardMode); - _grab.merge(other._grab); - - // Physics - COPY_PROPERTY_IF_CHANGED(density); - COPY_PROPERTY_IF_CHANGED(velocity); - COPY_PROPERTY_IF_CHANGED(angularVelocity); - COPY_PROPERTY_IF_CHANGED(gravity); - COPY_PROPERTY_IF_CHANGED(acceleration); - COPY_PROPERTY_IF_CHANGED(damping); - COPY_PROPERTY_IF_CHANGED(angularDamping); - COPY_PROPERTY_IF_CHANGED(restitution); - COPY_PROPERTY_IF_CHANGED(friction); - COPY_PROPERTY_IF_CHANGED(lifetime); - COPY_PROPERTY_IF_CHANGED(collisionless); - COPY_PROPERTY_IF_CHANGED(collisionMask); - COPY_PROPERTY_IF_CHANGED(dynamic); - COPY_PROPERTY_IF_CHANGED(collisionSoundURL); - COPY_PROPERTY_IF_CHANGED(actionData); - - // Cloning - COPY_PROPERTY_IF_CHANGED(cloneable); - COPY_PROPERTY_IF_CHANGED(cloneLifetime); - COPY_PROPERTY_IF_CHANGED(cloneLimit); - COPY_PROPERTY_IF_CHANGED(cloneDynamic); - COPY_PROPERTY_IF_CHANGED(cloneAvatarEntity); - COPY_PROPERTY_IF_CHANGED(cloneOriginID); - - // Scripts - COPY_PROPERTY_IF_CHANGED(script); - COPY_PROPERTY_IF_CHANGED(scriptTimestamp); - COPY_PROPERTY_IF_CHANGED(serverScripts); - - // Local props for scripts - COPY_PROPERTY_IF_CHANGED(localPosition); - COPY_PROPERTY_IF_CHANGED(localRotation); - COPY_PROPERTY_IF_CHANGED(localVelocity); - COPY_PROPERTY_IF_CHANGED(localAngularVelocity); - COPY_PROPERTY_IF_CHANGED(localDimensions); - - // Common - COPY_PROPERTY_IF_CHANGED(shapeType); - COPY_PROPERTY_IF_CHANGED(compoundShapeURL); - COPY_PROPERTY_IF_CHANGED(color); - COPY_PROPERTY_IF_CHANGED(alpha); - _pulse.merge(other._pulse); - COPY_PROPERTY_IF_CHANGED(textures); - - // Particles - COPY_PROPERTY_IF_CHANGED(maxParticles); - COPY_PROPERTY_IF_CHANGED(lifespan); - COPY_PROPERTY_IF_CHANGED(isEmitting); - COPY_PROPERTY_IF_CHANGED(emitRate); - COPY_PROPERTY_IF_CHANGED(emitSpeed); - COPY_PROPERTY_IF_CHANGED(speedSpread); - COPY_PROPERTY_IF_CHANGED(emitOrientation); - COPY_PROPERTY_IF_CHANGED(emitDimensions); - COPY_PROPERTY_IF_CHANGED(emitRadiusStart); - COPY_PROPERTY_IF_CHANGED(polarStart); - COPY_PROPERTY_IF_CHANGED(polarFinish); - COPY_PROPERTY_IF_CHANGED(azimuthStart); - COPY_PROPERTY_IF_CHANGED(azimuthFinish); - COPY_PROPERTY_IF_CHANGED(emitAcceleration); - COPY_PROPERTY_IF_CHANGED(accelerationSpread); - COPY_PROPERTY_IF_CHANGED(particleRadius); - COPY_PROPERTY_IF_CHANGED(radiusSpread); - COPY_PROPERTY_IF_CHANGED(radiusStart); - COPY_PROPERTY_IF_CHANGED(radiusFinish); - COPY_PROPERTY_IF_CHANGED(colorSpread); - COPY_PROPERTY_IF_CHANGED(colorStart); - COPY_PROPERTY_IF_CHANGED(colorFinish); - COPY_PROPERTY_IF_CHANGED(alphaSpread); - COPY_PROPERTY_IF_CHANGED(alphaStart); - COPY_PROPERTY_IF_CHANGED(alphaFinish); - COPY_PROPERTY_IF_CHANGED(emitterShouldTrail); - COPY_PROPERTY_IF_CHANGED(particleSpin); - COPY_PROPERTY_IF_CHANGED(spinSpread); - COPY_PROPERTY_IF_CHANGED(spinStart); - COPY_PROPERTY_IF_CHANGED(spinFinish); - COPY_PROPERTY_IF_CHANGED(rotateWithEntity); - - // Model - COPY_PROPERTY_IF_CHANGED(modelURL); - COPY_PROPERTY_IF_CHANGED(modelScale); - COPY_PROPERTY_IF_CHANGED(jointRotationsSet); - COPY_PROPERTY_IF_CHANGED(jointRotations); - COPY_PROPERTY_IF_CHANGED(jointTranslationsSet); - COPY_PROPERTY_IF_CHANGED(jointTranslations); - COPY_PROPERTY_IF_CHANGED(relayParentJoints); - COPY_PROPERTY_IF_CHANGED(groupCulled); - COPY_PROPERTY_IF_CHANGED(blendshapeCoefficients); - COPY_PROPERTY_IF_CHANGED(useOriginalPivot); - _animation.merge(other._animation); - - // Light - COPY_PROPERTY_IF_CHANGED(isSpotlight); - COPY_PROPERTY_IF_CHANGED(intensity); - COPY_PROPERTY_IF_CHANGED(exponent); - COPY_PROPERTY_IF_CHANGED(cutoff); - COPY_PROPERTY_IF_CHANGED(falloffRadius); - - // Text - COPY_PROPERTY_IF_CHANGED(text); - COPY_PROPERTY_IF_CHANGED(lineHeight); - COPY_PROPERTY_IF_CHANGED(textColor); - COPY_PROPERTY_IF_CHANGED(textAlpha); - COPY_PROPERTY_IF_CHANGED(backgroundColor); - COPY_PROPERTY_IF_CHANGED(backgroundAlpha); - COPY_PROPERTY_IF_CHANGED(leftMargin); - COPY_PROPERTY_IF_CHANGED(rightMargin); - COPY_PROPERTY_IF_CHANGED(topMargin); - COPY_PROPERTY_IF_CHANGED(bottomMargin); - COPY_PROPERTY_IF_CHANGED(unlit); - COPY_PROPERTY_IF_CHANGED(font); - COPY_PROPERTY_IF_CHANGED(textEffect); - COPY_PROPERTY_IF_CHANGED(textEffectColor); - COPY_PROPERTY_IF_CHANGED(textEffectThickness); - COPY_PROPERTY_IF_CHANGED(alignment); - - // Zone - _keyLight.merge(other._keyLight); - _ambientLight.merge(other._ambientLight); - _skybox.merge(other._skybox); - _haze.merge(other._haze); - _bloom.merge(other._bloom); - COPY_PROPERTY_IF_CHANGED(flyingAllowed); - COPY_PROPERTY_IF_CHANGED(ghostingAllowed); - COPY_PROPERTY_IF_CHANGED(filterURL); - COPY_PROPERTY_IF_CHANGED(keyLightMode); - COPY_PROPERTY_IF_CHANGED(ambientLightMode); - COPY_PROPERTY_IF_CHANGED(skyboxMode); - COPY_PROPERTY_IF_CHANGED(hazeMode); - COPY_PROPERTY_IF_CHANGED(bloomMode); - COPY_PROPERTY_IF_CHANGED(avatarPriority); - COPY_PROPERTY_IF_CHANGED(screenshare); - - // Polyvox - COPY_PROPERTY_IF_CHANGED(voxelVolumeSize); - COPY_PROPERTY_IF_CHANGED(voxelData); - COPY_PROPERTY_IF_CHANGED(voxelSurfaceStyle); - COPY_PROPERTY_IF_CHANGED(xTextureURL); - COPY_PROPERTY_IF_CHANGED(yTextureURL); - COPY_PROPERTY_IF_CHANGED(zTextureURL); - COPY_PROPERTY_IF_CHANGED(xNNeighborID); - COPY_PROPERTY_IF_CHANGED(yNNeighborID); - COPY_PROPERTY_IF_CHANGED(zNNeighborID); - COPY_PROPERTY_IF_CHANGED(xPNeighborID); - COPY_PROPERTY_IF_CHANGED(yPNeighborID); - COPY_PROPERTY_IF_CHANGED(zPNeighborID); - - // Web - COPY_PROPERTY_IF_CHANGED(sourceUrl); - COPY_PROPERTY_IF_CHANGED(dpi); - COPY_PROPERTY_IF_CHANGED(scriptURL); - COPY_PROPERTY_IF_CHANGED(maxFPS); - COPY_PROPERTY_IF_CHANGED(inputMode); - COPY_PROPERTY_IF_CHANGED(showKeyboardFocusHighlight); - COPY_PROPERTY_IF_CHANGED(useBackground); - COPY_PROPERTY_IF_CHANGED(userAgent); - - // Polyline - COPY_PROPERTY_IF_CHANGED(linePoints); - COPY_PROPERTY_IF_CHANGED(strokeWidths); - COPY_PROPERTY_IF_CHANGED(normals); - COPY_PROPERTY_IF_CHANGED(strokeColors); - COPY_PROPERTY_IF_CHANGED(isUVModeStretch); - COPY_PROPERTY_IF_CHANGED(glow); - COPY_PROPERTY_IF_CHANGED(faceCamera); - - // Shape - COPY_PROPERTY_IF_CHANGED(shape); - - // Material - COPY_PROPERTY_IF_CHANGED(materialURL); - COPY_PROPERTY_IF_CHANGED(materialMappingMode); - COPY_PROPERTY_IF_CHANGED(priority); - COPY_PROPERTY_IF_CHANGED(parentMaterialName); - COPY_PROPERTY_IF_CHANGED(materialMappingPos); - COPY_PROPERTY_IF_CHANGED(materialMappingScale); - COPY_PROPERTY_IF_CHANGED(materialMappingRot); - COPY_PROPERTY_IF_CHANGED(materialData); - COPY_PROPERTY_IF_CHANGED(materialRepeat); - - // Image - COPY_PROPERTY_IF_CHANGED(imageURL); - COPY_PROPERTY_IF_CHANGED(emissive); - COPY_PROPERTY_IF_CHANGED(keepAspectRatio); - COPY_PROPERTY_IF_CHANGED(subImage); - - // Grid - COPY_PROPERTY_IF_CHANGED(followCamera); - COPY_PROPERTY_IF_CHANGED(majorGridEvery); - COPY_PROPERTY_IF_CHANGED(minorGridEvery); - - // Gizmo - COPY_PROPERTY_IF_CHANGED(gizmoType); - _ring.merge(other._ring); - - _lastEdited = usecTimestampNow(); -} - -ScriptValue EntityItemPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties) { - return properties.copyToScriptValue(engine, false); -} - -ScriptValue EntityItemNonDefaultPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties) { - return properties.copyToScriptValue(engine, true); -} - -bool EntityItemPropertiesFromScriptValueIgnoreReadOnly(const ScriptValue &object, EntityItemProperties& properties) { - properties.copyFromScriptValue(object, false); - return true; -} - -bool EntityItemPropertiesFromScriptValueHonorReadOnly(const ScriptValue &object, EntityItemProperties& properties) { - properties.copyFromScriptValue(object, true); - return true; -} - -ScriptValue EntityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags) { - return EntityItemProperties::entityPropertyFlagsToScriptValue(engine, flags); -} - -bool EntityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags) { - return EntityItemProperties::entityPropertyFlagsFromScriptValue(object, flags); -} - - -ScriptValue EntityItemProperties::entityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags) { - ScriptValue result = engine->newObject(); - return result; -} - -bool EntityItemProperties::entityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags) { - if (object.isString()) { - EntityPropertyInfo propertyInfo; - if (getPropertyInfo(object.toString(), propertyInfo)) { - flags << propertyInfo.propertyEnums; - } - } - else if (object.isArray()) { - quint32 length = object.property("length").toInt32(); - for (quint32 i = 0; i < length; i++) { - QString propertyName = object.property(i).toString(); - EntityPropertyInfo propertyInfo; - if (getPropertyInfo(propertyName, propertyInfo)) { - flags << propertyInfo.propertyEnums; - } - } - } - return true; -} - -static QHash _propertyInfos; -static QHash _enumsToPropertyStrings; - -bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPropertyInfo& propertyInfo) { - - static std::once_flag initMap; - // V8TODO: Probably needs mutex before call_once - std::call_once(initMap, []() { - // Core - ADD_PROPERTY_TO_MAP(PROP_SIMULATION_OWNER, SimulationOwner, simulationOwner, SimulationOwner); - ADD_PROPERTY_TO_MAP(PROP_PARENT_ID, ParentID, parentID, QUuid); - ADD_PROPERTY_TO_MAP(PROP_PARENT_JOINT_INDEX, ParentJointIndex, parentJointIndex, uint16_t); - ADD_PROPERTY_TO_MAP(PROP_VISIBLE, Visible, visible, bool); - ADD_PROPERTY_TO_MAP(PROP_NAME, Name, name, QString); - ADD_PROPERTY_TO_MAP(PROP_LOCKED, Locked, locked, bool); - ADD_PROPERTY_TO_MAP(PROP_USER_DATA, UserData, userData, QString); - ADD_PROPERTY_TO_MAP(PROP_PRIVATE_USER_DATA, PrivateUserData, privateUserData, QString); - ADD_PROPERTY_TO_MAP(PROP_HREF, Href, href, QString); - ADD_PROPERTY_TO_MAP(PROP_DESCRIPTION, Description, description, QString); - ADD_PROPERTY_TO_MAP(PROP_POSITION, Position, position, vec3); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_DIMENSIONS, Dimensions, dimensions, vec3, ENTITY_ITEM_MIN_DIMENSION, FLT_MAX); - ADD_PROPERTY_TO_MAP(PROP_ROTATION, Rotation, rotation, quat); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_REGISTRATION_POINT, RegistrationPoint, registrationPoint, vec3, - ENTITY_ITEM_MIN_REGISTRATION_POINT, ENTITY_ITEM_MAX_REGISTRATION_POINT); - ADD_PROPERTY_TO_MAP(PROP_CREATED, Created, created, quint64); - ADD_PROPERTY_TO_MAP(PROP_LAST_EDITED_BY, LastEditedBy, lastEditedBy, QUuid); - ADD_PROPERTY_TO_MAP(PROP_ENTITY_HOST_TYPE, EntityHostType, entityHostType, entity::HostType); - ADD_PROPERTY_TO_MAP(PROP_OWNING_AVATAR_ID, OwningAvatarID, owningAvatarID, QUuid); - ADD_PROPERTY_TO_MAP(PROP_QUERY_AA_CUBE, QueryAACube, queryAACube, AACube); - ADD_PROPERTY_TO_MAP(PROP_CAN_CAST_SHADOW, CanCastShadow, canCastShadow, bool); - ADD_PROPERTY_TO_MAP(PROP_VISIBLE_IN_SECONDARY_CAMERA, IsVisibleInSecondaryCamera, isVisibleInSecondaryCamera, bool); - ADD_PROPERTY_TO_MAP(PROP_RENDER_LAYER, RenderLayer, renderLayer, RenderLayer); - ADD_PROPERTY_TO_MAP(PROP_PRIMITIVE_MODE, PrimitiveMode, primitiveMode, PrimitiveMode); - ADD_PROPERTY_TO_MAP(PROP_IGNORE_PICK_INTERSECTION, IgnorePickIntersection, ignorePickIntersection, bool); - ADD_PROPERTY_TO_MAP(PROP_RENDER_WITH_ZONES, RenderWithZones, renderWithZones, QVector); - ADD_PROPERTY_TO_MAP(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode); - { // Grab - ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_GRABBABLE, Grab, grab, Grabbable, grabbable); - ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_KINEMATIC, Grab, grab, GrabKinematic, grabKinematic); - ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_FOLLOWS_CONTROLLER, Grab, grab, GrabFollowsController, grabFollowsController); - ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_TRIGGERABLE, Grab, grab, Triggerable, triggerable); - ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_EQUIPPABLE, Grab, grab, Equippable, equippable); - ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_DELEGATE_TO_PARENT, Grab, grab, GrabDelegateToParent, grabDelegateToParent); - ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, Grab, grab, - EquippableLeftPosition, equippableLeftPosition); - ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, Grab, grab, - EquippableLeftRotation, equippableLeftRotation); - ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, Grab, grab, - EquippableRightPosition, equippableRightPosition); - ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, Grab, grab, - EquippableRightRotation, equippableRightRotation); - ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, Grab, grab, - EquippableIndicatorURL, equippableIndicatorURL); - ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, Grab, grab, - EquippableIndicatorScale, equippableIndicatorScale); - ADD_GROUP_PROPERTY_TO_MAP(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, Grab, grab, - EquippableIndicatorOffset, equippableIndicatorOffset); - } - - // Physics - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_DENSITY, Density, density, float, - ENTITY_ITEM_MIN_DENSITY, ENTITY_ITEM_MAX_DENSITY); - ADD_PROPERTY_TO_MAP(PROP_VELOCITY, Velocity, velocity, vec3); - ADD_PROPERTY_TO_MAP(PROP_ANGULAR_VELOCITY, AngularVelocity, angularVelocity, vec3); - ADD_PROPERTY_TO_MAP(PROP_GRAVITY, Gravity, gravity, vec3); - ADD_PROPERTY_TO_MAP(PROP_ACCELERATION, Acceleration, acceleration, vec3); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_DAMPING, Damping, damping, float, - ENTITY_ITEM_MIN_DAMPING, ENTITY_ITEM_MAX_DAMPING); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_ANGULAR_DAMPING, AngularDamping, angularDamping, float, - ENTITY_ITEM_MIN_DAMPING, ENTITY_ITEM_MAX_DAMPING); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_RESTITUTION, Restitution, restitution, float, - ENTITY_ITEM_MIN_RESTITUTION, ENTITY_ITEM_MAX_RESTITUTION); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_FRICTION, Friction, friction, float, - ENTITY_ITEM_MIN_FRICTION, ENTITY_ITEM_MAX_FRICTION); - ADD_PROPERTY_TO_MAP(PROP_LIFETIME, Lifetime, lifetime, float); - ADD_PROPERTY_TO_MAP(PROP_COLLISIONLESS, Collisionless, collisionless, bool); - ADD_PROPERTY_TO_MAP(PROP_COLLISIONLESS, unused, ignoreForCollisions, bool); // legacy support - ADD_PROPERTY_TO_MAP(PROP_COLLISION_MASK, unused, collisionMask, uint16_t); - ADD_PROPERTY_TO_MAP(PROP_COLLISION_MASK, unused, collidesWith, uint16_t); - ADD_PROPERTY_TO_MAP(PROP_DYNAMIC, unused, collisionsWillMove, bool); // legacy support - ADD_PROPERTY_TO_MAP(PROP_DYNAMIC, unused, dynamic, bool); - ADD_PROPERTY_TO_MAP(PROP_COLLISION_SOUND_URL, CollisionSoundURL, collisionSoundURL, QString); - ADD_PROPERTY_TO_MAP(PROP_ACTION_DATA, ActionData, actionData, QByteArray); - - // Cloning - ADD_PROPERTY_TO_MAP(PROP_CLONEABLE, Cloneable, cloneable, bool); - ADD_PROPERTY_TO_MAP(PROP_CLONE_LIFETIME, CloneLifetime, cloneLifetime, float); - ADD_PROPERTY_TO_MAP(PROP_CLONE_LIMIT, CloneLimit, cloneLimit, float); - ADD_PROPERTY_TO_MAP(PROP_CLONE_DYNAMIC, CloneDynamic, cloneDynamic, bool); - ADD_PROPERTY_TO_MAP(PROP_CLONE_AVATAR_ENTITY, CloneAvatarEntity, cloneAvatarEntity, bool); - ADD_PROPERTY_TO_MAP(PROP_CLONE_ORIGIN_ID, CloneOriginID, cloneOriginID, QUuid); - - // Scripts - ADD_PROPERTY_TO_MAP(PROP_SCRIPT, Script, script, QString); - ADD_PROPERTY_TO_MAP(PROP_SCRIPT_TIMESTAMP, ScriptTimestamp, scriptTimestamp, quint64); - ADD_PROPERTY_TO_MAP(PROP_SERVER_SCRIPTS, ServerScripts, serverScripts, QString); - - // Local script props - ADD_PROPERTY_TO_MAP(PROP_LOCAL_POSITION, LocalPosition, localPosition, vec3); - ADD_PROPERTY_TO_MAP(PROP_LOCAL_ROTATION, LocalRotation, localRotation, quat); - ADD_PROPERTY_TO_MAP(PROP_LOCAL_VELOCITY, LocalVelocity, localVelocity, vec3); - ADD_PROPERTY_TO_MAP(PROP_LOCAL_ANGULAR_VELOCITY, LocalAngularVelocity, localAngularVelocity, vec3); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_LOCAL_DIMENSIONS, LocalDimensions, localDimensions, vec3, - ENTITY_ITEM_MIN_DIMENSION, FLT_MAX); - - // Common - ADD_PROPERTY_TO_MAP(PROP_SHAPE_TYPE, ShapeType, shapeType, ShapeType); - ADD_PROPERTY_TO_MAP(PROP_COMPOUND_SHAPE_URL, CompoundShapeURL, compoundShapeURL, QString); - ADD_PROPERTY_TO_MAP(PROP_COLOR, Color, color, u8vec3Color); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_ALPHA, Alpha, alpha, float, particle::MINIMUM_ALPHA, particle::MAXIMUM_ALPHA); - { // Pulse - ADD_GROUP_PROPERTY_TO_MAP(PROP_PULSE_MIN, Pulse, pulse, Min, min); - ADD_GROUP_PROPERTY_TO_MAP(PROP_PULSE_MAX, Pulse, pulse, Max, max); - ADD_GROUP_PROPERTY_TO_MAP(PROP_PULSE_PERIOD, Pulse, pulse, Period, period); - ADD_GROUP_PROPERTY_TO_MAP(PROP_PULSE_COLOR_MODE, Pulse, pulse, ColorMode, colorMode); - ADD_GROUP_PROPERTY_TO_MAP(PROP_PULSE_ALPHA_MODE, Pulse, pulse, AlphaMode, alphaMode); - } - ADD_PROPERTY_TO_MAP(PROP_TEXTURES, Textures, textures, QString); - - // Particles - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_MAX_PARTICLES, MaxParticles, maxParticles, quint32, - particle::MINIMUM_MAX_PARTICLES, particle::MAXIMUM_MAX_PARTICLES); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_LIFESPAN, Lifespan, lifespan, float, - particle::MINIMUM_LIFESPAN, particle::MAXIMUM_LIFESPAN); - ADD_PROPERTY_TO_MAP(PROP_EMITTING_PARTICLES, IsEmitting, isEmitting, bool); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_EMIT_RATE, EmitRate, emitRate, float, - particle::MINIMUM_EMIT_RATE, particle::MAXIMUM_EMIT_RATE); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_EMIT_SPEED, EmitSpeed, emitSpeed, vec3, - particle::MINIMUM_EMIT_SPEED, particle::MAXIMUM_EMIT_SPEED); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_SPEED_SPREAD, SpeedSpread, speedSpread, vec3, - particle::MINIMUM_EMIT_SPEED, particle::MAXIMUM_EMIT_SPEED); - ADD_PROPERTY_TO_MAP(PROP_EMIT_ORIENTATION, EmitOrientation, emitOrientation, quat); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_EMIT_DIMENSIONS, EmitDimensions, emitDimensions, vec3, - particle::MINIMUM_EMIT_DIMENSION, particle::MAXIMUM_EMIT_DIMENSION); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_EMIT_RADIUS_START, EmitRadiusStart, emitRadiusStart, float, - particle::MINIMUM_EMIT_RADIUS_START, particle::MAXIMUM_EMIT_RADIUS_START); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_POLAR_START, EmitPolarStart, polarStart, float, - particle::MINIMUM_POLAR, particle::MAXIMUM_POLAR); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_POLAR_FINISH, EmitPolarFinish, polarFinish, float, - particle::MINIMUM_POLAR, particle::MAXIMUM_POLAR); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_AZIMUTH_START, EmitAzimuthStart, azimuthStart, float, - particle::MINIMUM_AZIMUTH, particle::MAXIMUM_AZIMUTH); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_AZIMUTH_FINISH, EmitAzimuthFinish, azimuthFinish, float, - particle::MINIMUM_AZIMUTH, particle::MAXIMUM_AZIMUTH); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_EMIT_ACCELERATION, EmitAcceleration, emitAcceleration, vec3, - particle::MINIMUM_EMIT_ACCELERATION, particle::MAXIMUM_EMIT_ACCELERATION); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_ACCELERATION_SPREAD, AccelerationSpread, accelerationSpread, vec3, - particle::MINIMUM_ACCELERATION_SPREAD, particle::MAXIMUM_ACCELERATION_SPREAD); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_PARTICLE_RADIUS, ParticleRadius, particleRadius, float, - particle::MINIMUM_PARTICLE_RADIUS, particle::MAXIMUM_PARTICLE_RADIUS); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_RADIUS_SPREAD, RadiusSpread, radiusSpread, float, - particle::MINIMUM_PARTICLE_RADIUS, particle::MAXIMUM_PARTICLE_RADIUS); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_RADIUS_START, RadiusStart, radiusStart, float, - particle::MINIMUM_PARTICLE_RADIUS, particle::MAXIMUM_PARTICLE_RADIUS); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float, - particle::MINIMUM_PARTICLE_RADIUS, particle::MAXIMUM_PARTICLE_RADIUS); - ADD_PROPERTY_TO_MAP(PROP_COLOR_SPREAD, ColorSpread, colorSpread, u8vec3Color); - ADD_PROPERTY_TO_MAP(PROP_COLOR_START, ColorStart, colorStart, vec3Color); - ADD_PROPERTY_TO_MAP(PROP_COLOR_FINISH, ColorFinish, colorFinish, vec3Color); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_ALPHA_SPREAD, AlphaSpread, alphaSpread, float, - particle::MINIMUM_ALPHA, particle::MAXIMUM_ALPHA); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_ALPHA_START, AlphaStart, alphaStart, float, - particle::MINIMUM_ALPHA, particle::MAXIMUM_ALPHA); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_ALPHA_FINISH, AlphaFinish, alphaFinish, float, - particle::MINIMUM_ALPHA, particle::MAXIMUM_ALPHA); - ADD_PROPERTY_TO_MAP(PROP_EMITTER_SHOULD_TRAIL, EmitterShouldTrail, emitterShouldTrail, bool); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_PARTICLE_SPIN, ParticleSpin, particleSpin, float, - particle::MINIMUM_PARTICLE_SPIN, particle::MAXIMUM_PARTICLE_SPIN); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_SPIN_SPREAD, SpinSpread, spinSpread, float, - particle::MINIMUM_PARTICLE_SPIN, particle::MAXIMUM_PARTICLE_SPIN); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_SPIN_START, SpinStart, spinStart, float, - particle::MINIMUM_PARTICLE_SPIN, particle::MAXIMUM_PARTICLE_SPIN); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_SPIN_FINISH, SpinFinish, spinFinish, float, - particle::MINIMUM_PARTICLE_SPIN, particle::MAXIMUM_PARTICLE_SPIN); - ADD_PROPERTY_TO_MAP(PROP_PARTICLE_ROTATE_WITH_ENTITY, RotateWithEntity, rotateWithEntity, float); - - // Model - ADD_PROPERTY_TO_MAP(PROP_MODEL_URL, ModelURL, modelURL, QString); - ADD_PROPERTY_TO_MAP(PROP_MODEL_SCALE, ModelScale, modelScale, vec3); - ADD_PROPERTY_TO_MAP(PROP_JOINT_ROTATIONS_SET, JointRotationsSet, jointRotationsSet, QVector); - ADD_PROPERTY_TO_MAP(PROP_JOINT_ROTATIONS, JointRotations, jointRotations, QVector); - ADD_PROPERTY_TO_MAP(PROP_JOINT_TRANSLATIONS_SET, JointTranslationsSet, jointTranslationsSet, QVector); - ADD_PROPERTY_TO_MAP(PROP_JOINT_TRANSLATIONS, JointTranslations, jointTranslations, QVector); - ADD_PROPERTY_TO_MAP(PROP_RELAY_PARENT_JOINTS, RelayParentJoints, relayParentJoints, bool); - ADD_PROPERTY_TO_MAP(PROP_GROUP_CULLED, GroupCulled, groupCulled, bool); - ADD_PROPERTY_TO_MAP(PROP_BLENDSHAPE_COEFFICIENTS, BlendshapeCoefficients, blendshapeCoefficients, QString); - ADD_PROPERTY_TO_MAP(PROP_USE_ORIGINAL_PIVOT, UseOriginalPivot, useOriginalPivot, bool); - { // Animation - ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_URL, Animation, animation, URL, url); - ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_ALLOW_TRANSLATION, Animation, animation, AllowTranslation, allowTranslation); - ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_FPS, Animation, animation, FPS, fps); - ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_FRAME_INDEX, Animation, animation, CurrentFrame, currentFrame); - ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_PLAYING, Animation, animation, Running, running); - ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_LOOP, Animation, animation, Loop, loop); - ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_FIRST_FRAME, Animation, animation, FirstFrame, firstFrame); - ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_LAST_FRAME, Animation, animation, LastFrame, lastFrame); - ADD_GROUP_PROPERTY_TO_MAP(PROP_ANIMATION_HOLD, Animation, animation, Hold, hold); - } - - // Light - ADD_PROPERTY_TO_MAP(PROP_IS_SPOTLIGHT, IsSpotlight, isSpotlight, bool); - ADD_PROPERTY_TO_MAP(PROP_INTENSITY, Intensity, intensity, float); - ADD_PROPERTY_TO_MAP(PROP_EXPONENT, Exponent, exponent, float); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_CUTOFF, Cutoff, cutoff, float, - LightEntityItem::MIN_CUTOFF, LightEntityItem::MAX_CUTOFF); - ADD_PROPERTY_TO_MAP(PROP_FALLOFF_RADIUS, FalloffRadius, falloffRadius, float); - - // Text - ADD_PROPERTY_TO_MAP(PROP_TEXT, Text, text, QString); - ADD_PROPERTY_TO_MAP(PROP_LINE_HEIGHT, LineHeight, lineHeight, float); - ADD_PROPERTY_TO_MAP(PROP_TEXT_COLOR, TextColor, textColor, u8vec3Color); - ADD_PROPERTY_TO_MAP(PROP_TEXT_ALPHA, TextAlpha, textAlpha, float); - ADD_PROPERTY_TO_MAP(PROP_BACKGROUND_COLOR, BackgroundColor, backgroundColor, u8vec3Color); - ADD_PROPERTY_TO_MAP(PROP_BACKGROUND_ALPHA, BackgroundAlpha, backgroundAlpha, float); - ADD_PROPERTY_TO_MAP(PROP_LEFT_MARGIN, LeftMargin, leftMargin, float); - ADD_PROPERTY_TO_MAP(PROP_RIGHT_MARGIN, RightMargin, rightMargin, float); - ADD_PROPERTY_TO_MAP(PROP_TOP_MARGIN, TopMargin, topMargin, float); - ADD_PROPERTY_TO_MAP(PROP_BOTTOM_MARGIN, BottomMargin, bottomMargin, float); - ADD_PROPERTY_TO_MAP(PROP_UNLIT, Unlit, unlit, bool); - ADD_PROPERTY_TO_MAP(PROP_FONT, Font, font, QString); - ADD_PROPERTY_TO_MAP(PROP_TEXT_EFFECT, TextEffect, textEffect, TextEffect); - ADD_PROPERTY_TO_MAP(PROP_TEXT_EFFECT_COLOR, TextEffectColor, textEffectColor, u8vec3Color); - ADD_PROPERTY_TO_MAP_WITH_RANGE(PROP_TEXT_EFFECT_THICKNESS, TextEffectThickness, textEffectThickness, float, 0.0, 0.5); - ADD_PROPERTY_TO_MAP(PROP_TEXT_ALIGNMENT, Alignment, alignment, TextAlignment); - - // Zone - { // Keylight - ADD_GROUP_PROPERTY_TO_MAP(PROP_KEYLIGHT_COLOR, KeyLight, keyLight, Color, color); - ADD_GROUP_PROPERTY_TO_MAP(PROP_KEYLIGHT_INTENSITY, KeyLight, keyLight, Intensity, intensity); - ADD_GROUP_PROPERTY_TO_MAP(PROP_KEYLIGHT_DIRECTION, KeyLight, keyLight, Direction, direction); - ADD_GROUP_PROPERTY_TO_MAP(PROP_KEYLIGHT_CAST_SHADOW, KeyLight, keyLight, CastShadows, castShadows); - ADD_GROUP_PROPERTY_TO_MAP_WITH_RANGE(PROP_KEYLIGHT_SHADOW_BIAS, KeyLight, keyLight, ShadowBias, shadowBias, 0.0f, 1.0f); - ADD_GROUP_PROPERTY_TO_MAP_WITH_RANGE(PROP_KEYLIGHT_SHADOW_MAX_DISTANCE, KeyLight, keyLight, ShadowMaxDistance, shadowMaxDistance, 1.0f, 250.0f); - } - { // Ambient light - ADD_GROUP_PROPERTY_TO_MAP(PROP_AMBIENT_LIGHT_INTENSITY, AmbientLight, ambientLight, Intensity, intensity); - ADD_GROUP_PROPERTY_TO_MAP(PROP_AMBIENT_LIGHT_URL, AmbientLight, ambientLight, URL, url); - } - { // Skybox - ADD_GROUP_PROPERTY_TO_MAP(PROP_SKYBOX_COLOR, Skybox, skybox, Color, color); - ADD_GROUP_PROPERTY_TO_MAP(PROP_SKYBOX_URL, Skybox, skybox, URL, url); - } - { // Haze - ADD_GROUP_PROPERTY_TO_MAP(PROP_HAZE_RANGE, Haze, haze, HazeRange, hazeRange); - ADD_GROUP_PROPERTY_TO_MAP(PROP_HAZE_COLOR, Haze, haze, HazeColor, hazeColor); - ADD_GROUP_PROPERTY_TO_MAP(PROP_HAZE_GLARE_COLOR, Haze, haze, HazeGlareColor, hazeGlareColor); - ADD_GROUP_PROPERTY_TO_MAP(PROP_HAZE_ENABLE_GLARE, Haze, haze, HazeEnableGlare, hazeEnableGlare); - ADD_GROUP_PROPERTY_TO_MAP(PROP_HAZE_GLARE_ANGLE, Haze, haze, HazeGlareAngle, hazeGlareAngle); - - ADD_GROUP_PROPERTY_TO_MAP(PROP_HAZE_ALTITUDE_EFFECT, Haze, haze, HazeAltitudeEffect, hazeAltitudeEfect); - ADD_GROUP_PROPERTY_TO_MAP(PROP_HAZE_CEILING, Haze, haze, HazeCeiling, hazeCeiling); - ADD_GROUP_PROPERTY_TO_MAP(PROP_HAZE_BASE_REF, Haze, haze, HazeBaseRef, hazeBaseRef); - - ADD_GROUP_PROPERTY_TO_MAP(PROP_HAZE_BACKGROUND_BLEND, Haze, haze, HazeBackgroundBlend, hazeBackgroundBlend); - - ADD_GROUP_PROPERTY_TO_MAP(PROP_HAZE_ATTENUATE_KEYLIGHT, Haze, haze, HazeAttenuateKeyLight, hazeAttenuateKeyLight); - 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); - } - { // Bloom - 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_FLYING_ALLOWED, FlyingAllowed, flyingAllowed, bool); - ADD_PROPERTY_TO_MAP(PROP_GHOSTING_ALLOWED, GhostingAllowed, ghostingAllowed, bool); - ADD_PROPERTY_TO_MAP(PROP_FILTER_URL, FilterURL, filterURL, QString); - 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); - ADD_PROPERTY_TO_MAP(PROP_HAZE_MODE, HazeMode, hazeMode, uint32_t); - ADD_PROPERTY_TO_MAP(PROP_BLOOM_MODE, BloomMode, bloomMode, uint32_t); - ADD_PROPERTY_TO_MAP(PROP_AVATAR_PRIORITY, AvatarPriority, avatarPriority, uint32_t); - ADD_PROPERTY_TO_MAP(PROP_SCREENSHARE, Screenshare, screenshare, uint32_t); - - // Polyvox - ADD_PROPERTY_TO_MAP(PROP_VOXEL_VOLUME_SIZE, VoxelVolumeSize, voxelVolumeSize, vec3); - ADD_PROPERTY_TO_MAP(PROP_VOXEL_DATA, VoxelData, voxelData, QByteArray); - ADD_PROPERTY_TO_MAP(PROP_VOXEL_SURFACE_STYLE, VoxelSurfaceStyle, voxelSurfaceStyle, uint16_t); - ADD_PROPERTY_TO_MAP(PROP_X_TEXTURE_URL, XTextureURL, xTextureURL, QString); - ADD_PROPERTY_TO_MAP(PROP_Y_TEXTURE_URL, YTextureURL, yTextureURL, QString); - ADD_PROPERTY_TO_MAP(PROP_Z_TEXTURE_URL, ZTextureURL, zTextureURL, QString); - ADD_PROPERTY_TO_MAP(PROP_X_N_NEIGHBOR_ID, XNNeighborID, xNNeighborID, EntityItemID); - ADD_PROPERTY_TO_MAP(PROP_Y_N_NEIGHBOR_ID, YNNeighborID, yNNeighborID, EntityItemID); - ADD_PROPERTY_TO_MAP(PROP_Z_N_NEIGHBOR_ID, ZNNeighborID, zNNeighborID, EntityItemID); - ADD_PROPERTY_TO_MAP(PROP_X_P_NEIGHBOR_ID, XPNeighborID, xPNeighborID, EntityItemID); - ADD_PROPERTY_TO_MAP(PROP_Y_P_NEIGHBOR_ID, YPNeighborID, yPNeighborID, EntityItemID); - ADD_PROPERTY_TO_MAP(PROP_Z_P_NEIGHBOR_ID, ZPNeighborID, zPNeighborID, EntityItemID); - - // Web - ADD_PROPERTY_TO_MAP(PROP_SOURCE_URL, SourceUrl, sourceUrl, QString); - ADD_PROPERTY_TO_MAP(PROP_DPI, DPI, dpi, uint16_t); - ADD_PROPERTY_TO_MAP(PROP_SCRIPT_URL, ScriptURL, scriptURL, QString); - ADD_PROPERTY_TO_MAP(PROP_MAX_FPS, MaxFPS, maxFPS, uint8_t); - ADD_PROPERTY_TO_MAP(PROP_INPUT_MODE, InputMode, inputMode, WebInputMode); - ADD_PROPERTY_TO_MAP(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, ShowKeyboardFocusHighlight, showKeyboardFocusHighlight, bool); - ADD_PROPERTY_TO_MAP(PROP_WEB_USE_BACKGROUND, useBackground, useBackground, bool); - ADD_PROPERTY_TO_MAP(PROP_USER_AGENT, UserAgent, userAgent, QString); - - // Polyline - ADD_PROPERTY_TO_MAP(PROP_LINE_POINTS, LinePoints, linePoints, QVector); - ADD_PROPERTY_TO_MAP(PROP_STROKE_WIDTHS, StrokeWidths, strokeWidths, QVector); - ADD_PROPERTY_TO_MAP(PROP_STROKE_NORMALS, Normals, normals, QVector); - ADD_PROPERTY_TO_MAP(PROP_STROKE_COLORS, StrokeColors, strokeColors, QVector); - ADD_PROPERTY_TO_MAP(PROP_IS_UV_MODE_STRETCH, IsUVModeStretch, isUVModeStretch, QVector); - ADD_PROPERTY_TO_MAP(PROP_LINE_GLOW, Glow, glow, bool); - ADD_PROPERTY_TO_MAP(PROP_LINE_FACE_CAMERA, FaceCamera, faceCamera, bool); - - // Shape - ADD_PROPERTY_TO_MAP(PROP_SHAPE, Shape, shape, QString); - - // Material - ADD_PROPERTY_TO_MAP(PROP_MATERIAL_URL, MaterialURL, materialURL, QString); - ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_MODE, MaterialMappingMode, materialMappingMode, MaterialMappingMode); - ADD_PROPERTY_TO_MAP(PROP_MATERIAL_PRIORITY, Priority, priority, quint16); - ADD_PROPERTY_TO_MAP(PROP_PARENT_MATERIAL_NAME, ParentMaterialName, parentMaterialName, QString); - ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_POS, MaterialMappingPos, materialMappingPos, vec2); - ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_SCALE, MaterialMappingScale, materialMappingScale, vec2); - ADD_PROPERTY_TO_MAP(PROP_MATERIAL_MAPPING_ROT, MaterialMappingRot, materialMappingRot, float); - ADD_PROPERTY_TO_MAP(PROP_MATERIAL_DATA, MaterialData, materialData, QString); - ADD_PROPERTY_TO_MAP(PROP_MATERIAL_REPEAT, MaterialRepeat, materialRepeat, bool); - - // Image - ADD_PROPERTY_TO_MAP(PROP_IMAGE_URL, ImageURL, imageURL, QString); - ADD_PROPERTY_TO_MAP(PROP_EMISSIVE, Emissive, emissive, bool); - ADD_PROPERTY_TO_MAP(PROP_KEEP_ASPECT_RATIO, KeepAspectRatio, keepAspectRatio, bool); - ADD_PROPERTY_TO_MAP(PROP_SUB_IMAGE, SubImage, subImage, QRect); - - // Grid - ADD_PROPERTY_TO_MAP(PROP_GRID_FOLLOW_CAMERA, FollowCamera, followCamera, bool); - ADD_PROPERTY_TO_MAP(PROP_MAJOR_GRID_EVERY, MajorGridEvery, majorGridEvery, uint32_t); - ADD_PROPERTY_TO_MAP(PROP_MINOR_GRID_EVERY, MinorGridEvery, minorGridEvery, float); - - // Gizmo - ADD_PROPERTY_TO_MAP(PROP_GIZMO_TYPE, GizmoType, gizmoType, GizmoType); - { // RingGizmo - ADD_GROUP_PROPERTY_TO_MAP_WITH_RANGE(PROP_START_ANGLE, Ring, ring, StartAngle, startAngle, RingGizmoPropertyGroup::MIN_ANGLE, RingGizmoPropertyGroup::MAX_ANGLE); - ADD_GROUP_PROPERTY_TO_MAP_WITH_RANGE(PROP_END_ANGLE, Ring, ring, EndAngle, endAngle, RingGizmoPropertyGroup::MIN_ANGLE, RingGizmoPropertyGroup::MAX_ANGLE); - ADD_GROUP_PROPERTY_TO_MAP_WITH_RANGE(PROP_INNER_RADIUS, Ring, ring, InnerRadius, innerRadius, RingGizmoPropertyGroup::MIN_RADIUS, RingGizmoPropertyGroup::MAX_RADIUS); - - ADD_GROUP_PROPERTY_TO_MAP(PROP_INNER_START_COLOR, Ring, ring, InnerStartColor, innerStartColor); - ADD_GROUP_PROPERTY_TO_MAP(PROP_INNER_END_COLOR, Ring, ring, InnerEndColor, innerEndColor); - ADD_GROUP_PROPERTY_TO_MAP(PROP_OUTER_START_COLOR, Ring, ring, OuterStartColor, outerStartColor); - ADD_GROUP_PROPERTY_TO_MAP(PROP_OUTER_END_COLOR, Ring, ring, OuterEndColor, outerEndColor); - - ADD_GROUP_PROPERTY_TO_MAP_WITH_RANGE(PROP_INNER_START_ALPHA, Ring, ring, InnerStartAlpha, innerStartAlpha, RingGizmoPropertyGroup::MIN_ALPHA, RingGizmoPropertyGroup::MAX_ALPHA); - ADD_GROUP_PROPERTY_TO_MAP_WITH_RANGE(PROP_INNER_END_ALPHA, Ring, ring, InnerEndAlpha, innerEndAlpha, RingGizmoPropertyGroup::MIN_ALPHA, RingGizmoPropertyGroup::MAX_ALPHA); - ADD_GROUP_PROPERTY_TO_MAP_WITH_RANGE(PROP_OUTER_START_ALPHA, Ring, ring, OuterStartAlpha, outerStartAlpha, RingGizmoPropertyGroup::MIN_ALPHA, RingGizmoPropertyGroup::MAX_ALPHA); - ADD_GROUP_PROPERTY_TO_MAP_WITH_RANGE(PROP_OUTER_END_ALPHA, Ring, ring, OuterEndAlpha, outerEndAlpha, RingGizmoPropertyGroup::MIN_ALPHA, RingGizmoPropertyGroup::MAX_ALPHA); - - ADD_GROUP_PROPERTY_TO_MAP(PROP_HAS_TICK_MARKS, Ring, ring, HasTickMarks, hasTickMarks); - ADD_GROUP_PROPERTY_TO_MAP_WITH_RANGE(PROP_MAJOR_TICK_MARKS_ANGLE, Ring, ring, MajorTickMarksAngle, majorTickMarksAngle, RingGizmoPropertyGroup::MIN_ANGLE, RingGizmoPropertyGroup::MAX_ANGLE); - ADD_GROUP_PROPERTY_TO_MAP_WITH_RANGE(PROP_MINOR_TICK_MARKS_ANGLE, Ring, ring, MinorTickMarksAngle, minorTickMarksAngle, RingGizmoPropertyGroup::MIN_ANGLE, RingGizmoPropertyGroup::MAX_ANGLE); - ADD_GROUP_PROPERTY_TO_MAP(PROP_MAJOR_TICK_MARKS_LENGTH, Ring, ring, MajorTickMarksLength, majorTickMarksLength); - ADD_GROUP_PROPERTY_TO_MAP(PROP_MINOR_TICK_MARKS_LENGTH, Ring, ring, MinorTickMarksLength, minorTickMarksLength); - ADD_GROUP_PROPERTY_TO_MAP(PROP_MAJOR_TICK_MARKS_COLOR, Ring, ring, MajorTickMarksColor, majorTickMarksColor); - ADD_GROUP_PROPERTY_TO_MAP(PROP_MINOR_TICK_MARKS_COLOR, Ring, ring, MinorTickMarksColor, minorTickMarksColor); - } - }); - - auto iter = _propertyInfos.find(propertyName); - if (iter != _propertyInfos.end()) { - propertyInfo = *iter; - return true; - } - - return false; -} - -/*@jsdoc - * Information about an entity property. - * @typedef {object} Entities.EntityPropertyInfo - * @property {number} propertyEnum - The internal number of the property. - * @property {string} minimum - The minimum numerical value the property may have, if available, otherwise "". - * @property {string} maximum - The maximum numerical value the property may have, if available, otherwise "". - */ -ScriptValue EntityPropertyInfoToScriptValue(ScriptEngine* engine, const EntityPropertyInfo& propertyInfo) { - ScriptValue obj = engine->newObject(); - obj.setProperty("propertyEnum", propertyInfo.propertyEnums.firstFlag()); - obj.setProperty("minimum", propertyInfo.minimum.toString()); - obj.setProperty("maximum", propertyInfo.maximum.toString()); - return obj; -} - -bool EntityPropertyInfoFromScriptValue(const ScriptValue& object, EntityPropertyInfo& propertyInfo) { - propertyInfo.propertyEnums = (EntityPropertyList)object.property("propertyEnum").toVariant().toUInt(); - propertyInfo.minimum = object.property("minimum").toVariant(); - propertyInfo.maximum = object.property("maximum").toVariant(); - return true; -} - -// TODO: Implement support for edit packets that can span an MTU sized buffer. We need to implement a mechanism for the -// encodeEntityEditPacket() method to communicate the the caller which properties couldn't fit in the buffer. Similar -// to how we handle this in the Octree streaming case. -// -// TODO: Right now, all possible properties for all subclasses are handled here. Ideally we'd prefer -// to handle this in a more generic way. Allowing subclasses of EntityItem to register their properties -// -// TODO: There's a lot of repeated patterns in the code below to handle each property. It would be nice if the property -// registration mechanism allowed us to collapse these repeated sections of code into a single implementation that -// utilized the registration table to shorten up and simplify this code. -// -// TODO: Implement support for paged properties, spanning MTU, and custom properties -// -// TODO: Implement support for script and visible properties. -// -OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties, - QByteArray& buffer, EntityPropertyFlags requestedProperties, EntityPropertyFlags& didntFitProperties) { - - OctreePacketData ourDataPacket(false, buffer.size()); // create a packetData object to add out packet details too. - OctreePacketData* packetData = &ourDataPacket; // we want a pointer to this so we can use our APPEND_ENTITY_PROPERTY macro - - bool success = true; // assume the best - OctreeElement::AppendState appendState = OctreeElement::COMPLETED; // assume the best - - // TODO: We need to review how jurisdictions should be handled for entities. (The old Models and Particles code - // didn't do anything special for jurisdictions, so we're keeping that same behavior here.) - // - // Always include the root octcode. This is only because the OctreeEditPacketSender will check these octcodes - // to determine which server to send the changes to in the case of multiple jurisdictions. The root will be sent - // to all servers. - vec3 rootPosition(0); - float rootScale = 0.5f; - unsigned char* octcode = pointToOctalCode(rootPosition.x, rootPosition.y, rootPosition.z, rootScale); - - success = packetData->startSubTree(octcode); - delete[] octcode; - - // assuming we have room to fit our octalCode, proceed... - if (success) { - - // Now add our edit content details... - - // id - // encode our ID as a byte count coded byte stream - QByteArray encodedID = id.toRfc4122(); // NUM_BYTES_RFC4122_UUID - - // encode our ID as a byte count coded byte stream - ByteCountCoded tokenCoder; - QByteArray encodedToken; - - // encode our type as a byte count coded byte stream - ByteCountCoded typeCoder = (quint32)properties.getType(); - QByteArray encodedType = typeCoder; - - quint64 updateDelta = 0; // this is an edit so by definition, it's update is in sync - ByteCountCoded updateDeltaCoder = updateDelta; - QByteArray encodedUpdateDelta = updateDeltaCoder; - - EntityPropertyFlags propertyFlags(PROP_LAST_ITEM); - EntityPropertyFlags propertiesDidntFit = requestedProperties; - - LevelDetails entityLevel = packetData->startLevel(); - - // Last Edited quint64 always first, before any other details, which allows us easy access to adjusting this - // timestamp for clock skew - quint64 lastEdited = properties.getLastEdited(); - bool successLastEditedFits = packetData->appendValue(lastEdited); - - bool successIDFits = packetData->appendRawData(encodedID); - if (successIDFits) { - successIDFits = packetData->appendRawData(encodedToken); - } - bool successTypeFits = packetData->appendRawData(encodedType); - - // NOTE: We intentionally do not send "created" times in edit messages. This is because: - // 1) if the edit is to an existing entity, the created time can not be changed - // 2) if the edit is to a new entity, the created time is the last edited time - - // TODO: Should we get rid of this in this in edit packets, since this has to always be 0? - bool successLastUpdatedFits = packetData->appendRawData(encodedUpdateDelta); - - int propertyFlagsOffset = packetData->getUncompressedByteOffset(); - QByteArray encodedPropertyFlags = propertyFlags; - int oldPropertyFlagsLength = encodedPropertyFlags.length(); - bool successPropertyFlagsFits = packetData->appendRawData(encodedPropertyFlags); - int propertyCount = 0; - - bool headerFits = successIDFits && successTypeFits && successLastEditedFits && - successLastUpdatedFits && successPropertyFlagsFits; - - int startOfEntityItemData = packetData->getUncompressedByteOffset(); - - if (headerFits) { - bool successPropertyFits; - propertyFlags -= PROP_LAST_ITEM; // clear the last item for now, we may or may not set it as the actual item - - // These items would go here once supported.... - // PROP_PAGED_PROPERTY, - // PROP_CUSTOM_PROPERTIES_INCLUDED, - - - APPEND_ENTITY_PROPERTY(PROP_SIMULATION_OWNER, properties._simulationOwner.toByteArray()); - APPEND_ENTITY_PROPERTY(PROP_PARENT_ID, properties.getParentID()); - APPEND_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, properties.getParentJointIndex()); - APPEND_ENTITY_PROPERTY(PROP_VISIBLE, properties.getVisible()); - APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName()); - APPEND_ENTITY_PROPERTY(PROP_LOCKED, properties.getLocked()); - APPEND_ENTITY_PROPERTY(PROP_USER_DATA, properties.getUserData()); - APPEND_ENTITY_PROPERTY(PROP_PRIVATE_USER_DATA, properties.getPrivateUserData()); - APPEND_ENTITY_PROPERTY(PROP_HREF, properties.getHref()); - APPEND_ENTITY_PROPERTY(PROP_DESCRIPTION, properties.getDescription()); - APPEND_ENTITY_PROPERTY(PROP_POSITION, properties.getPosition()); - APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, properties.getDimensions()); - APPEND_ENTITY_PROPERTY(PROP_ROTATION, properties.getRotation()); - APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, properties.getRegistrationPoint()); - APPEND_ENTITY_PROPERTY(PROP_CREATED, properties.getCreated()); - APPEND_ENTITY_PROPERTY(PROP_LAST_EDITED_BY, properties.getLastEditedBy()); - // APPEND_ENTITY_PROPERTY(PROP_ENTITY_HOST_TYPE, (uint32_t)properties.getEntityHostType()); // not sent over the wire - // APPEND_ENTITY_PROPERTY(PROP_OWNING_AVATAR_ID, properties.getOwningAvatarID()); // not sent over the wire - APPEND_ENTITY_PROPERTY(PROP_QUERY_AA_CUBE, properties.getQueryAACube()); - APPEND_ENTITY_PROPERTY(PROP_CAN_CAST_SHADOW, properties.getCanCastShadow()); - // APPEND_ENTITY_PROPERTY(PROP_VISIBLE_IN_SECONDARY_CAMERA, properties.getIsVisibleInSecondaryCamera()); // not sent over the wire - APPEND_ENTITY_PROPERTY(PROP_RENDER_LAYER, (uint32_t)properties.getRenderLayer()); - APPEND_ENTITY_PROPERTY(PROP_PRIMITIVE_MODE, (uint32_t)properties.getPrimitiveMode()); - APPEND_ENTITY_PROPERTY(PROP_IGNORE_PICK_INTERSECTION, properties.getIgnorePickIntersection()); - APPEND_ENTITY_PROPERTY(PROP_RENDER_WITH_ZONES, properties.getRenderWithZones()); - APPEND_ENTITY_PROPERTY(PROP_BILLBOARD_MODE, (uint32_t)properties.getBillboardMode()); - _staticGrab.setProperties(properties); - _staticGrab.appendToEditPacket(packetData, requestedProperties, propertyFlags, - propertiesDidntFit, propertyCount, appendState); - - // Physics - APPEND_ENTITY_PROPERTY(PROP_DENSITY, properties.getDensity()); - APPEND_ENTITY_PROPERTY(PROP_VELOCITY, properties.getVelocity()); - APPEND_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, properties.getAngularVelocity()); - APPEND_ENTITY_PROPERTY(PROP_GRAVITY, properties.getGravity()); - APPEND_ENTITY_PROPERTY(PROP_ACCELERATION, properties.getAcceleration()); - APPEND_ENTITY_PROPERTY(PROP_DAMPING, properties.getDamping()); - APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, properties.getAngularDamping()); - APPEND_ENTITY_PROPERTY(PROP_RESTITUTION, properties.getRestitution()); - APPEND_ENTITY_PROPERTY(PROP_FRICTION, properties.getFriction()); - APPEND_ENTITY_PROPERTY(PROP_LIFETIME, properties.getLifetime()); - APPEND_ENTITY_PROPERTY(PROP_COLLISIONLESS, properties.getCollisionless()); - APPEND_ENTITY_PROPERTY(PROP_COLLISION_MASK, properties.getCollisionMask()); - APPEND_ENTITY_PROPERTY(PROP_DYNAMIC, properties.getDynamic()); - APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL()); - APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, properties.getActionData()); - - // Cloning - APPEND_ENTITY_PROPERTY(PROP_CLONEABLE, properties.getCloneable()); - APPEND_ENTITY_PROPERTY(PROP_CLONE_LIFETIME, properties.getCloneLifetime()); - APPEND_ENTITY_PROPERTY(PROP_CLONE_LIMIT, properties.getCloneLimit()); - APPEND_ENTITY_PROPERTY(PROP_CLONE_DYNAMIC, properties.getCloneDynamic()); - APPEND_ENTITY_PROPERTY(PROP_CLONE_AVATAR_ENTITY, properties.getCloneAvatarEntity()); - APPEND_ENTITY_PROPERTY(PROP_CLONE_ORIGIN_ID, properties.getCloneOriginID()); - - // Scripts - APPEND_ENTITY_PROPERTY(PROP_SCRIPT, properties.getScript()); - APPEND_ENTITY_PROPERTY(PROP_SCRIPT_TIMESTAMP, properties.getScriptTimestamp()); - APPEND_ENTITY_PROPERTY(PROP_SERVER_SCRIPTS, properties.getServerScripts()); - - if (properties.getType() == EntityTypes::ParticleEffect) { - APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)(properties.getShapeType())); - APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, properties.getCompoundShapeURL()); - APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor()); - APPEND_ENTITY_PROPERTY(PROP_ALPHA, properties.getAlpha()); - _staticPulse.setProperties(properties); - _staticPulse.appendToEditPacket(packetData, requestedProperties, propertyFlags, - propertiesDidntFit, propertyCount, appendState); - APPEND_ENTITY_PROPERTY(PROP_TEXTURES, properties.getTextures()); - - APPEND_ENTITY_PROPERTY(PROP_MAX_PARTICLES, properties.getMaxParticles()); - APPEND_ENTITY_PROPERTY(PROP_LIFESPAN, properties.getLifespan()); - - APPEND_ENTITY_PROPERTY(PROP_EMITTING_PARTICLES, properties.getIsEmitting()); - APPEND_ENTITY_PROPERTY(PROP_EMIT_RATE, properties.getEmitRate()); - APPEND_ENTITY_PROPERTY(PROP_EMIT_SPEED, properties.getEmitSpeed()); - APPEND_ENTITY_PROPERTY(PROP_SPEED_SPREAD, properties.getSpeedSpread()); - APPEND_ENTITY_PROPERTY(PROP_EMIT_ORIENTATION, properties.getEmitOrientation()); - APPEND_ENTITY_PROPERTY(PROP_EMIT_DIMENSIONS, properties.getEmitDimensions()); - APPEND_ENTITY_PROPERTY(PROP_EMIT_RADIUS_START, properties.getEmitRadiusStart()); - - APPEND_ENTITY_PROPERTY(PROP_POLAR_START, properties.getPolarStart()); - APPEND_ENTITY_PROPERTY(PROP_POLAR_FINISH, properties.getPolarFinish()); - APPEND_ENTITY_PROPERTY(PROP_AZIMUTH_START, properties.getAzimuthStart()); - APPEND_ENTITY_PROPERTY(PROP_AZIMUTH_FINISH, properties.getAzimuthFinish()); - - APPEND_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, properties.getEmitAcceleration()); - APPEND_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, properties.getAccelerationSpread()); - - APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, properties.getParticleRadius()); - APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, properties.getRadiusSpread()); - APPEND_ENTITY_PROPERTY(PROP_RADIUS_START, properties.getRadiusStart()); - APPEND_ENTITY_PROPERTY(PROP_RADIUS_FINISH, properties.getRadiusFinish()); - - APPEND_ENTITY_PROPERTY(PROP_COLOR_SPREAD, properties.getColorSpread()); - APPEND_ENTITY_PROPERTY(PROP_COLOR_START, properties.getColorStart()); - APPEND_ENTITY_PROPERTY(PROP_COLOR_FINISH, properties.getColorFinish()); - - APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, properties.getAlphaSpread()); - APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, properties.getAlphaStart()); - APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, properties.getAlphaFinish()); - - APPEND_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, properties.getEmitterShouldTrail()); - - APPEND_ENTITY_PROPERTY(PROP_PARTICLE_SPIN, properties.getParticleSpin()); - APPEND_ENTITY_PROPERTY(PROP_SPIN_SPREAD, properties.getSpinSpread()); - APPEND_ENTITY_PROPERTY(PROP_SPIN_START, properties.getSpinStart()); - APPEND_ENTITY_PROPERTY(PROP_SPIN_FINISH, properties.getSpinFinish()); - APPEND_ENTITY_PROPERTY(PROP_PARTICLE_ROTATE_WITH_ENTITY, properties.getRotateWithEntity()) - } - - if (properties.getType() == EntityTypes::Model) { - APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)(properties.getShapeType())); - APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, properties.getCompoundShapeURL()); - APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor()); - APPEND_ENTITY_PROPERTY(PROP_TEXTURES, properties.getTextures()); - - APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, properties.getModelURL()); - APPEND_ENTITY_PROPERTY(PROP_MODEL_SCALE, properties.getModelScale()); - APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS_SET, properties.getJointRotationsSet()); - APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS, properties.getJointRotations()); - APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, properties.getJointTranslationsSet()); - APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS, properties.getJointTranslations()); - APPEND_ENTITY_PROPERTY(PROP_RELAY_PARENT_JOINTS, properties.getRelayParentJoints()); - APPEND_ENTITY_PROPERTY(PROP_GROUP_CULLED, properties.getGroupCulled()); - APPEND_ENTITY_PROPERTY(PROP_BLENDSHAPE_COEFFICIENTS, properties.getBlendshapeCoefficients()); - APPEND_ENTITY_PROPERTY(PROP_USE_ORIGINAL_PIVOT, properties.getUseOriginalPivot()); - - _staticAnimation.setProperties(properties); - _staticAnimation.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); - } - - if (properties.getType() == EntityTypes::Light) { - APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor()); - APPEND_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, properties.getIsSpotlight()); - APPEND_ENTITY_PROPERTY(PROP_INTENSITY, properties.getIntensity()); - APPEND_ENTITY_PROPERTY(PROP_EXPONENT, properties.getExponent()); - APPEND_ENTITY_PROPERTY(PROP_CUTOFF, properties.getCutoff()); - APPEND_ENTITY_PROPERTY(PROP_FALLOFF_RADIUS, properties.getFalloffRadius()); - } - - if (properties.getType() == EntityTypes::Text) { - _staticPulse.setProperties(properties); - _staticPulse.appendToEditPacket(packetData, requestedProperties, propertyFlags, - propertiesDidntFit, propertyCount, appendState); - - APPEND_ENTITY_PROPERTY(PROP_TEXT, properties.getText()); - APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, properties.getLineHeight()); - APPEND_ENTITY_PROPERTY(PROP_TEXT_COLOR, properties.getTextColor()); - APPEND_ENTITY_PROPERTY(PROP_TEXT_ALPHA, properties.getTextAlpha()); - APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, properties.getBackgroundColor()); - APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_ALPHA, properties.getBackgroundAlpha()); - APPEND_ENTITY_PROPERTY(PROP_LEFT_MARGIN, properties.getLeftMargin()); - APPEND_ENTITY_PROPERTY(PROP_RIGHT_MARGIN, properties.getRightMargin()); - APPEND_ENTITY_PROPERTY(PROP_TOP_MARGIN, properties.getTopMargin()); - APPEND_ENTITY_PROPERTY(PROP_BOTTOM_MARGIN, properties.getBottomMargin()); - APPEND_ENTITY_PROPERTY(PROP_UNLIT, properties.getUnlit()); - APPEND_ENTITY_PROPERTY(PROP_FONT, properties.getFont()); - APPEND_ENTITY_PROPERTY(PROP_TEXT_EFFECT, (uint32_t)properties.getTextEffect()); - APPEND_ENTITY_PROPERTY(PROP_TEXT_EFFECT_COLOR, properties.getTextEffectColor()); - APPEND_ENTITY_PROPERTY(PROP_TEXT_EFFECT_THICKNESS, properties.getTextEffectThickness()); - APPEND_ENTITY_PROPERTY(PROP_TEXT_ALIGNMENT, (uint32_t)properties.getAlignment()); - } - - if (properties.getType() == EntityTypes::Zone) { - APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)properties.getShapeType()); - APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, properties.getCompoundShapeURL()); - - _staticKeyLight.setProperties(properties); - _staticKeyLight.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); - - _staticAmbientLight.setProperties(properties); - _staticAmbientLight.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); - - _staticSkybox.setProperties(properties); - _staticSkybox.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); - - _staticHaze.setProperties(properties); - _staticHaze.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); - - _staticBloom.setProperties(properties); - _staticBloom.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); - - APPEND_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, properties.getFlyingAllowed()); - APPEND_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, properties.getGhostingAllowed()); - APPEND_ENTITY_PROPERTY(PROP_FILTER_URL, properties.getFilterURL()); - - 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()); - APPEND_ENTITY_PROPERTY(PROP_HAZE_MODE, (uint32_t)properties.getHazeMode()); - APPEND_ENTITY_PROPERTY(PROP_BLOOM_MODE, (uint32_t)properties.getBloomMode()); - APPEND_ENTITY_PROPERTY(PROP_AVATAR_PRIORITY, (uint32_t)properties.getAvatarPriority()); - APPEND_ENTITY_PROPERTY(PROP_SCREENSHARE, (uint32_t)properties.getScreenshare()); - } - - if (properties.getType() == EntityTypes::PolyVox) { - APPEND_ENTITY_PROPERTY(PROP_VOXEL_VOLUME_SIZE, properties.getVoxelVolumeSize()); - APPEND_ENTITY_PROPERTY(PROP_VOXEL_DATA, properties.getVoxelData()); - APPEND_ENTITY_PROPERTY(PROP_VOXEL_SURFACE_STYLE, properties.getVoxelSurfaceStyle()); - APPEND_ENTITY_PROPERTY(PROP_X_TEXTURE_URL, properties.getXTextureURL()); - APPEND_ENTITY_PROPERTY(PROP_Y_TEXTURE_URL, properties.getYTextureURL()); - APPEND_ENTITY_PROPERTY(PROP_Z_TEXTURE_URL, properties.getZTextureURL()); - APPEND_ENTITY_PROPERTY(PROP_X_N_NEIGHBOR_ID, properties.getXNNeighborID()); - APPEND_ENTITY_PROPERTY(PROP_Y_N_NEIGHBOR_ID, properties.getYNNeighborID()); - APPEND_ENTITY_PROPERTY(PROP_Z_N_NEIGHBOR_ID, properties.getZNNeighborID()); - APPEND_ENTITY_PROPERTY(PROP_X_P_NEIGHBOR_ID, properties.getXPNeighborID()); - APPEND_ENTITY_PROPERTY(PROP_Y_P_NEIGHBOR_ID, properties.getYPNeighborID()); - APPEND_ENTITY_PROPERTY(PROP_Z_P_NEIGHBOR_ID, properties.getZPNeighborID()); - } - - if (properties.getType() == EntityTypes::Web) { - APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor()); - APPEND_ENTITY_PROPERTY(PROP_ALPHA, properties.getAlpha()); - _staticPulse.setProperties(properties); - _staticPulse.appendToEditPacket(packetData, requestedProperties, propertyFlags, - propertiesDidntFit, propertyCount, appendState); - - APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, properties.getSourceUrl()); - APPEND_ENTITY_PROPERTY(PROP_DPI, properties.getDPI()); - APPEND_ENTITY_PROPERTY(PROP_SCRIPT_URL, properties.getScriptURL()); - APPEND_ENTITY_PROPERTY(PROP_MAX_FPS, properties.getMaxFPS()); - APPEND_ENTITY_PROPERTY(PROP_INPUT_MODE, (uint32_t)properties.getInputMode()); - APPEND_ENTITY_PROPERTY(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, properties.getShowKeyboardFocusHighlight()); - APPEND_ENTITY_PROPERTY(PROP_WEB_USE_BACKGROUND, properties.getUseBackground()); - APPEND_ENTITY_PROPERTY(PROP_USER_AGENT, properties.getUserAgent()); - } - - if (properties.getType() == EntityTypes::Line) { - APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor()); - - APPEND_ENTITY_PROPERTY(PROP_LINE_POINTS, properties.getLinePoints()); - } - - if (properties.getType() == EntityTypes::PolyLine) { - APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor()); - APPEND_ENTITY_PROPERTY(PROP_TEXTURES, properties.getTextures()); - - APPEND_ENTITY_PROPERTY(PROP_LINE_POINTS, properties.getLinePoints()); - APPEND_ENTITY_PROPERTY(PROP_STROKE_WIDTHS, properties.getStrokeWidths()); - APPEND_ENTITY_PROPERTY(PROP_STROKE_NORMALS, properties.getPackedNormals()); - APPEND_ENTITY_PROPERTY(PROP_STROKE_COLORS, properties.getPackedStrokeColors()); - APPEND_ENTITY_PROPERTY(PROP_IS_UV_MODE_STRETCH, properties.getIsUVModeStretch()); - APPEND_ENTITY_PROPERTY(PROP_LINE_GLOW, properties.getGlow()); - APPEND_ENTITY_PROPERTY(PROP_LINE_FACE_CAMERA, properties.getFaceCamera()); - } - - // NOTE: Spheres and Boxes are just special cases of Shape, and they need to include their PROP_SHAPE - // when encoding/decoding edits because otherwise they can't polymorph to other shape types - if (properties.getType() == EntityTypes::Shape || - properties.getType() == EntityTypes::Box || - properties.getType() == EntityTypes::Sphere) { - APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor()); - APPEND_ENTITY_PROPERTY(PROP_ALPHA, properties.getAlpha()); - _staticPulse.setProperties(properties); - _staticPulse.appendToEditPacket(packetData, requestedProperties, propertyFlags, - propertiesDidntFit, propertyCount, appendState); - APPEND_ENTITY_PROPERTY(PROP_SHAPE, properties.getShape()); - } - - // Materials - if (properties.getType() == EntityTypes::Material) { - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_URL, properties.getMaterialURL()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_MODE, (uint32_t)properties.getMaterialMappingMode()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, properties.getPriority()); - APPEND_ENTITY_PROPERTY(PROP_PARENT_MATERIAL_NAME, properties.getParentMaterialName()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_POS, properties.getMaterialMappingPos()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_SCALE, properties.getMaterialMappingScale()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_ROT, properties.getMaterialMappingRot()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_DATA, properties.getMaterialData()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_REPEAT, properties.getMaterialRepeat()); - } - - // Image - if (properties.getType() == EntityTypes::Image) { - APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor()); - APPEND_ENTITY_PROPERTY(PROP_ALPHA, properties.getAlpha()); - _staticPulse.setProperties(properties); - _staticPulse.appendToEditPacket(packetData, requestedProperties, propertyFlags, - propertiesDidntFit, propertyCount, appendState); - - APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, properties.getImageURL()); - APPEND_ENTITY_PROPERTY(PROP_EMISSIVE, properties.getEmissive()); - APPEND_ENTITY_PROPERTY(PROP_KEEP_ASPECT_RATIO, properties.getKeepAspectRatio()); - APPEND_ENTITY_PROPERTY(PROP_SUB_IMAGE, properties.getSubImage()); - } - - // Grid - if (properties.getType() == EntityTypes::Grid) { - APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor()); - APPEND_ENTITY_PROPERTY(PROP_ALPHA, properties.getAlpha()); - _staticPulse.setProperties(properties); - _staticPulse.appendToEditPacket(packetData, requestedProperties, propertyFlags, - propertiesDidntFit, propertyCount, appendState); - - APPEND_ENTITY_PROPERTY(PROP_GRID_FOLLOW_CAMERA, properties.getFollowCamera()); - APPEND_ENTITY_PROPERTY(PROP_MAJOR_GRID_EVERY, properties.getMajorGridEvery()); - APPEND_ENTITY_PROPERTY(PROP_MINOR_GRID_EVERY, properties.getMinorGridEvery()); - } - - if (properties.getType() == EntityTypes::Gizmo) { - APPEND_ENTITY_PROPERTY(PROP_GIZMO_TYPE, (uint32_t)properties.getGizmoType()); - _staticRing.setProperties(properties); - _staticRing.appendToEditPacket(packetData, requestedProperties, propertyFlags, - propertiesDidntFit, propertyCount, appendState); - } - } - - if (propertyCount > 0) { - int endOfEntityItemData = packetData->getUncompressedByteOffset(); - - encodedPropertyFlags = propertyFlags; - int newPropertyFlagsLength = encodedPropertyFlags.length(); - packetData->updatePriorBytes(propertyFlagsOffset, (const unsigned char*)encodedPropertyFlags.constData(), - encodedPropertyFlags.length()); - - // if the size of the PropertyFlags shrunk, we need to shift everything down to front of packet. - if (newPropertyFlagsLength < oldPropertyFlagsLength) { - int oldSize = packetData->getUncompressedSize(); - - const unsigned char* modelItemData = packetData->getUncompressedData(propertyFlagsOffset + oldPropertyFlagsLength); - int modelItemDataLength = endOfEntityItemData - startOfEntityItemData; - int newEntityItemDataStart = propertyFlagsOffset + newPropertyFlagsLength; - packetData->updatePriorBytes(newEntityItemDataStart, modelItemData, modelItemDataLength); - - int newSize = oldSize - (oldPropertyFlagsLength - newPropertyFlagsLength); - packetData->setUncompressedSize(newSize); - - } else { - assert(newPropertyFlagsLength == oldPropertyFlagsLength); // should not have grown - } - - packetData->endLevel(entityLevel); - } else { - packetData->discardLevel(entityLevel); - appendState = OctreeElement::NONE; // if we got here, then we didn't include the item - } - - // If any part of the model items didn't fit, then the element is considered partial - if (appendState != OctreeElement::COMPLETED) { - didntFitProperties = propertiesDidntFit; - } - - packetData->endSubTree(); - - const char* finalizedData = reinterpret_cast(packetData->getFinalizedData()); - int finalizedSize = packetData->getFinalizedSize(); - - if (finalizedSize <= buffer.size()) { - buffer.replace(0, finalizedSize, finalizedData, finalizedSize); - buffer.resize(finalizedSize); - } else { - qCDebug(entities) << "ERROR - encoded edit message doesn't fit in output buffer."; - appendState = OctreeElement::NONE; // if we got here, then we didn't include the item - // maybe we should assert!!! - } - } else { - packetData->discardSubTree(); - } - - return appendState; -} - -QByteArray EntityItemProperties::getPackedNormals() const { - return packNormals(getNormals()); -} - -QByteArray EntityItemProperties::packNormals(const QVector& normals) const { - int normalsSize = normals.size(); - QByteArray packedNormals = QByteArray(normalsSize * 6 + 1, '0'); - // add size of the array - packedNormals[0] = ((uint8_t)normalsSize); - - int index = 1; - for (int i = 0; i < normalsSize; i++) { - int numBytes = packFloatVec3ToSignedTwoByteFixed((unsigned char*)packedNormals.data() + index, normals[i], 15); - index += numBytes; - } - return packedNormals; -} - -QByteArray EntityItemProperties::getPackedStrokeColors() const { - return packStrokeColors(getStrokeColors()); -} -QByteArray EntityItemProperties::packStrokeColors(const QVector& strokeColors) const { - int strokeColorsSize = strokeColors.size(); - QByteArray packedStrokeColors = QByteArray(strokeColorsSize * 3 + 1, '0'); - - // add size of the array - packedStrokeColors[0] = ((uint8_t)strokeColorsSize); - - - for (int i = 0; i < strokeColorsSize; i++) { - // add the color to the QByteArray - packedStrokeColors[i * 3 + 1] = strokeColors[i].x * 255; - packedStrokeColors[i * 3 + 2] = strokeColors[i].y * 255; - packedStrokeColors[i * 3 + 3] = strokeColors[i].z * 255; - } - return packedStrokeColors; -} - -// TODO: -// how to handle lastEdited? -// how to handle lastUpdated? -// consider handling case where no properties are included... we should just ignore this packet... -// -// TODO: Right now, all possible properties for all subclasses are handled here. Ideally we'd prefer -// to handle this in a more generic way. Allowing subclasses of EntityItem to register their properties -// -// TODO: There's a lot of repeated patterns in the code below to handle each property. It would be nice if the property -// registration mechanism allowed us to collapse these repeated sections of code into a single implementation that -// utilized the registration table to shorten up and simplify this code. -// -// TODO: Implement support for paged properties, spanning MTU, and custom properties -// -// TODO: Implement support for script and visible properties. -// -bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes, - EntityItemID& entityID, EntityItemProperties& properties) { - bool valid = false; - - const unsigned char* dataAt = data; - processedBytes = 0; - - // the first part of the data is an octcode, this is a required element of the edit packet format, but we don't - // actually use it, we do need to skip it and read to the actual data we care about. - int octets = numberOfThreeBitSectionsInCode(data); - int bytesToReadOfOctcode = (int)bytesRequiredForCodeLength(octets); - - // we don't actually do anything with this octcode... - dataAt += bytesToReadOfOctcode; - processedBytes += bytesToReadOfOctcode; - - // Edit packets have a last edited time stamp immediately following the octcode. - // NOTE: the edit times have been set by the editor to match out clock, so we don't need to adjust - // these times for clock skew at this point. - quint64 lastEdited; - memcpy(&lastEdited, dataAt, sizeof(lastEdited)); - dataAt += sizeof(lastEdited); - processedBytes += sizeof(lastEdited); - properties.setLastEdited(lastEdited); - - // encoded id - QUuid editID = QUuid::fromRfc4122(QByteArray::fromRawData(reinterpret_cast(dataAt), NUM_BYTES_RFC4122_UUID)); - dataAt += NUM_BYTES_RFC4122_UUID; - processedBytes += NUM_BYTES_RFC4122_UUID; - - entityID = editID; - valid = true; - - // Entity Type... - QByteArray encodedType((const char*)dataAt, (bytesToRead - processedBytes)); - ByteCountCoded typeCoder = encodedType; - quint32 entityTypeCode = typeCoder; - properties.setType((EntityTypes::EntityType)entityTypeCode); - encodedType = typeCoder; // determine true bytesToRead - dataAt += encodedType.size(); - processedBytes += encodedType.size(); - - // Update Delta - when was this item updated relative to last edit... this really should be 0 - // TODO: Should we get rid of this in this in edit packets, since this has to always be 0? - // TODO: do properties need to handle lastupdated??? - - // last updated is stored as ByteCountCoded delta from lastEdited - QByteArray encodedUpdateDelta((const char*)dataAt, (bytesToRead - processedBytes)); - ByteCountCoded updateDeltaCoder = encodedUpdateDelta; - encodedUpdateDelta = updateDeltaCoder; // determine true bytesToRead - dataAt += encodedUpdateDelta.size(); - processedBytes += encodedUpdateDelta.size(); - - // TODO: Do we need this lastUpdated?? We don't seem to use it. - //quint64 updateDelta = updateDeltaCoder; - //quint64 lastUpdated = lastEdited + updateDelta; // don't adjust for clock skew since we already did that for lastEdited - - // Property Flags... - QByteArray encodedPropertyFlags((const char*)dataAt, (bytesToRead - processedBytes)); - EntityPropertyFlags propertyFlags = encodedPropertyFlags; - dataAt += propertyFlags.getEncodedLength(); - processedBytes += propertyFlags.getEncodedLength(); - - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SIMULATION_OWNER, QByteArray, setSimulationOwner); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_ID, QUuid, setParentID); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE, bool, setVisible); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCKED, bool, setLocked); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USER_DATA, QString, setUserData); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PRIVATE_USER_DATA, QString, setPrivateUserData); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_HREF, QString, setHref); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DESCRIPTION, QString, setDescription); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_POSITION, vec3, setPosition); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DIMENSIONS, vec3, setDimensions); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ROTATION, quat, setRotation); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_REGISTRATION_POINT, vec3, setRegistrationPoint); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CREATED, quint64, setCreated); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LAST_EDITED_BY, QUuid, setLastEditedBy); - // READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ENTITY_HOST_TYPE, entity::HostType, setEntityHostType); // not sent over the wire - // READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_OWNING_AVATAR_ID, QUuid, setOwningAvatarID); // not sent over the wire - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_QUERY_AA_CUBE, AACube, setQueryAACube); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CAN_CAST_SHADOW, bool, setCanCastShadow); - // READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE_IN_SECONDARY_CAMERA, bool, setIsVisibleInSecondaryCamera); // not sent over the wire - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RENDER_LAYER, RenderLayer, setRenderLayer); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PRIMITIVE_MODE, PrimitiveMode, setPrimitiveMode); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IGNORE_PICK_INTERSECTION, bool, setIgnorePickIntersection); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RENDER_WITH_ZONES, QVector, setRenderWithZones); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BILLBOARD_MODE, BillboardMode, setBillboardMode); - properties.getGrab().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); - - // Physics - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DENSITY, float, setDensity); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VELOCITY, vec3, setVelocity); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_VELOCITY, vec3, setAngularVelocity); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_GRAVITY, vec3, setGravity); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACCELERATION, vec3, setAcceleration); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DAMPING, float, setDamping); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_DAMPING, float, setAngularDamping); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RESTITUTION, float, setRestitution); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FRICTION, float, setFriction); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LIFETIME, float, setLifetime); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISIONLESS, bool, setCollisionless); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_MASK, uint16_t, setCollisionMask); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DYNAMIC, bool, setDynamic); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACTION_DATA, QByteArray, setActionData); - - // Cloning - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONEABLE, bool, setCloneable); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONE_LIFETIME, float, setCloneLifetime); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONE_LIMIT, float, setCloneLimit); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONE_DYNAMIC, bool, setCloneDynamic); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONE_AVATAR_ENTITY, bool, setCloneAvatarEntity); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CLONE_ORIGIN_ID, QUuid, setCloneOriginID); - - // Scripts - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SCRIPT, QString, setScript); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SCRIPT_TIMESTAMP, quint64, setScriptTimestamp); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SERVER_SCRIPTS, QString, setServerScripts); - - if (properties.getType() == EntityTypes::ParticleEffect) { - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha); - properties.getPulse().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXTURES, QString, setTextures); - - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MAX_PARTICLES, quint32, setMaxParticles); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LIFESPAN, float, setLifespan); - - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMITTING_PARTICLES, bool, setIsEmitting); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_RATE, float, setEmitRate); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_SPEED, float, setEmitSpeed); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SPEED_SPREAD, float, setSpeedSpread); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_ORIENTATION, quat, setEmitOrientation); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_DIMENSIONS, vec3, setEmitDimensions); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_RADIUS_START, float, setEmitRadiusStart); - - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_POLAR_START, float, setPolarStart); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_POLAR_FINISH, float, setPolarFinish); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_AZIMUTH_START, float, setAzimuthStart); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_AZIMUTH_FINISH, float, setAzimuthFinish); - - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_ACCELERATION, vec3, setEmitAcceleration); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACCELERATION_SPREAD, vec3, setAccelerationSpread); - - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARTICLE_RADIUS, float, setParticleRadius); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_SPREAD, float, setRadiusSpread); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_START, float, setRadiusStart); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_FINISH, float, setRadiusFinish); - - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_SPREAD, u8vec3Color, setColorSpread); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_START, vec3Color, setColorStart); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_FINISH, vec3Color, setColorFinish); - - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_SPREAD, float, setAlphaSpread); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_START, float, setAlphaStart); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_FINISH, float, setAlphaFinish); - - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMITTER_SHOULD_TRAIL, bool, setEmitterShouldTrail); - - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARTICLE_SPIN, float, setParticleSpin); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SPIN_SPREAD, float, setSpinSpread); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SPIN_START, float, setSpinStart); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SPIN_FINISH, float, setSpinFinish); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARTICLE_ROTATE_WITH_ENTITY, bool, setRotateWithEntity); - } - - if (properties.getType() == EntityTypes::Model) { - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXTURES, QString, setTextures); - - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MODEL_URL, QString, setModelURL); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MODEL_SCALE, vec3, setModelScale); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_JOINT_ROTATIONS_SET, QVector, setJointRotationsSet); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_JOINT_ROTATIONS, QVector, setJointRotations); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_JOINT_TRANSLATIONS_SET, QVector, setJointTranslationsSet); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_JOINT_TRANSLATIONS, QVector, setJointTranslations); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RELAY_PARENT_JOINTS, bool, setRelayParentJoints); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_GROUP_CULLED, bool, setGroupCulled); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BLENDSHAPE_COEFFICIENTS, QString, setBlendshapeCoefficients); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USE_ORIGINAL_PIVOT, bool, setUseOriginalPivot); - - properties.getAnimation().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); - } - - if (properties.getType() == EntityTypes::Light) { - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor); - - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IS_SPOTLIGHT, bool, setIsSpotlight); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_INTENSITY, float, setIntensity); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EXPONENT, float, setExponent); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CUTOFF, float, setCutoff); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FALLOFF_RADIUS, float, setFalloffRadius); - } - - if (properties.getType() == EntityTypes::Text) { - properties.getPulse().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); - - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT, QString, setText); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_HEIGHT, float, setLineHeight); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT_COLOR, u8vec3Color, setTextColor); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT_ALPHA, float, setTextAlpha); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BACKGROUND_COLOR, u8vec3Color, setBackgroundColor); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BACKGROUND_ALPHA, float, setBackgroundAlpha); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LEFT_MARGIN, float, setLeftMargin); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RIGHT_MARGIN, float, setRightMargin); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TOP_MARGIN, float, setTopMargin); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BOTTOM_MARGIN, float, setBottomMargin); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_UNLIT, bool, setUnlit); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FONT, QString, setFont); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT_EFFECT, TextEffect, setTextEffect); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT_EFFECT_COLOR, u8vec3Color, setTextEffectColor); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT_EFFECT_THICKNESS, float, setTextEffectThickness); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT_ALIGNMENT, TextAlignment, setAlignment); - } - - if (properties.getType() == EntityTypes::Zone) { - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL); - - properties.getKeyLight().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); - properties.getAmbientLight().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); - properties.getSkybox().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); - properties.getHaze().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); - properties.getBloom().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); - - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FLYING_ALLOWED, bool, setFlyingAllowed); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_GHOSTING_ALLOWED, bool, setGhostingAllowed); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_FILTER_URL, QString, setFilterURL); - - 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); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_HAZE_MODE, uint32_t, setHazeMode); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BLOOM_MODE, uint32_t, setBloomMode); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_AVATAR_PRIORITY, uint32_t, setAvatarPriority); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SCREENSHARE, uint32_t, setScreenshare); - } - - if (properties.getType() == EntityTypes::PolyVox) { - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VOXEL_VOLUME_SIZE, vec3, setVoxelVolumeSize); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VOXEL_DATA, QByteArray, setVoxelData); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VOXEL_SURFACE_STYLE, uint16_t, setVoxelSurfaceStyle); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_X_TEXTURE_URL, QString, setXTextureURL); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_Y_TEXTURE_URL, QString, setYTextureURL); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_Z_TEXTURE_URL, QString, setZTextureURL); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_X_N_NEIGHBOR_ID, EntityItemID, setXNNeighborID); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_Y_N_NEIGHBOR_ID, EntityItemID, setYNNeighborID); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_Z_N_NEIGHBOR_ID, EntityItemID, setZNNeighborID); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_X_P_NEIGHBOR_ID, EntityItemID, setXPNeighborID); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_Y_P_NEIGHBOR_ID, EntityItemID, setYPNeighborID); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_Z_P_NEIGHBOR_ID, EntityItemID, setZPNeighborID); - } - - if (properties.getType() == EntityTypes::Web) { - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha); - properties.getPulse().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); - - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SOURCE_URL, QString, setSourceUrl); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DPI, uint16_t, setDPI); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SCRIPT_URL, QString, setScriptURL); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MAX_FPS, uint8_t, setMaxFPS); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_INPUT_MODE, WebInputMode, setInputMode); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, bool, setShowKeyboardFocusHighlight); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_WEB_USE_BACKGROUND, bool, setUseBackground); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USER_AGENT, QString, setUserAgent); - } - - if (properties.getType() == EntityTypes::Line) { - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor); - - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_POINTS, QVector, setLinePoints); - } - - if (properties.getType() == EntityTypes::PolyLine) { - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXTURES, QString, setTextures); - - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_POINTS, QVector, setLinePoints); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STROKE_WIDTHS, QVector, setStrokeWidths); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STROKE_NORMALS, QByteArray, setPackedNormals); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STROKE_COLORS, QByteArray, setPackedStrokeColors); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IS_UV_MODE_STRETCH, bool, setIsUVModeStretch); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_GLOW, bool, setGlow); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_FACE_CAMERA, bool, setFaceCamera); - } - - // NOTE: Spheres and Boxes are just special cases of Shape, and they need to include their PROP_SHAPE - // when encoding/decoding edits because otherwise they can't polymorph to other shape types - if (properties.getType() == EntityTypes::Shape || - properties.getType() == EntityTypes::Box || - properties.getType() == EntityTypes::Sphere) { - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha); - properties.getPulse().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); - - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE, QString, setShape); - } - - // Materials - if (properties.getType() == EntityTypes::Material) { - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_URL, QString, setMaterialURL); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_MAPPING_MODE, MaterialMappingMode, setMaterialMappingMode); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_PRIORITY, quint16, setPriority); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARENT_MATERIAL_NAME, QString, setParentMaterialName); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_MAPPING_POS, vec2, setMaterialMappingPos); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_MAPPING_SCALE, vec2, setMaterialMappingScale); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_MAPPING_ROT, float, setMaterialMappingRot); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_DATA, QString, setMaterialData); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MATERIAL_REPEAT, bool, setMaterialRepeat); - } - - // Image - if (properties.getType() == EntityTypes::Image) { - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha); - properties.getPulse().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); - - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IMAGE_URL, QString, setImageURL); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMISSIVE, bool, setEmissive); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEEP_ASPECT_RATIO, bool, setKeepAspectRatio); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SUB_IMAGE, QRect, setSubImage); - } - - // Grid - if (properties.getType() == EntityTypes::Grid) { - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR, u8vec3Color, setColor); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha); - properties.getPulse().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); - - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_GRID_FOLLOW_CAMERA, bool, setFollowCamera); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MAJOR_GRID_EVERY, uint32_t, setMajorGridEvery); - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MINOR_GRID_EVERY, float, setMinorGridEvery); - } - - if (properties.getType() == EntityTypes::Gizmo) { - READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_GIZMO_TYPE, GizmoType, setGizmoType); - properties.getRing().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); - } - - return valid; -} - -void EntityItemProperties::setPackedNormals(const QByteArray& value) { - setNormals(unpackNormals(value)); -} - -QVector EntityItemProperties::unpackNormals(const QByteArray& normals) { - // the size of the vector is packed first - QVector unpackedNormals = QVector((int)normals[0]); - - if ((int)normals[0] == normals.size() / 6) { - int j = 0; - for (int i = 1; i < normals.size();) { - vec3 aux = vec3(); - i += unpackFloatVec3FromSignedTwoByteFixed((unsigned char*)normals.data() + i, aux, 15); - unpackedNormals[j] = aux; - j++; - } - } else { - qCDebug(entities) << "WARNING - Expected received size for normals does not match. Expected: " << (int)normals[0] - << " Received: " << (normals.size() / 6); - } - return unpackedNormals; -} - -void EntityItemProperties::setPackedStrokeColors(const QByteArray& value) { - setStrokeColors(unpackStrokeColors(value)); -} - -QVector EntityItemProperties::unpackStrokeColors(const QByteArray& strokeColors) { - // the size of the vector is packed first - QVector unpackedStrokeColors = QVector((int)strokeColors[0]); - - if ((int)strokeColors[0] == strokeColors.size() / 3) { - int j = 0; - for (int i = 1; i < strokeColors.size();) { - - float r = (uint8_t)strokeColors[i++] / 255.0f; - float g = (uint8_t)strokeColors[i++] / 255.0f; - float b = (uint8_t)strokeColors[i++] / 255.0f; - unpackedStrokeColors[j++] = vec3(r, g, b); - } - } else { - qCDebug(entities) << "WARNING - Expected received size for stroke colors does not match. Expected: " - << (int)strokeColors[0] << " Received: " << (strokeColors.size() / 3); - } - - return unpackedStrokeColors; -} - -// NOTE: This version will only encode the portion of the edit message immediately following the -// header it does not include the send times and sequence number because that is handled by the -// edit packet sender... -bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityItemID, QByteArray& buffer) { - - uint16_t numberOfIds = 1; // only one entity ID in this message - - if (buffer.size() < (int)(sizeof(numberOfIds) + NUM_BYTES_RFC4122_UUID)) { - qCDebug(entities) << "ERROR - encodeEraseEntityMessage() called with buffer that is too small!"; - return false; - } - - buffer.resize(0); - buffer.append(reinterpret_cast(&numberOfIds), sizeof(numberOfIds)); - buffer.append(entityItemID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID); - - return true; -} - -bool EntityItemProperties::encodeCloneEntityMessage(const EntityItemID& entityIDToClone, const EntityItemID& newEntityID, QByteArray& buffer) { - if (buffer.size() < (int)(NUM_BYTES_RFC4122_UUID * 2)) { - qCDebug(entities) << "ERROR - encodeCloneEntityMessage() called with buffer that is too small!"; - return false; - } - - buffer.resize(0); - buffer.append(entityIDToClone.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID); - buffer.append(newEntityID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID); - - return true; -} - -bool EntityItemProperties::decodeCloneEntityMessage(const QByteArray& buffer, int& processedBytes, EntityItemID& entityIDToClone, EntityItemID& newEntityID) { - const unsigned char* packetData = (const unsigned char*)buffer.constData(); - const unsigned char* dataAt = packetData; - size_t packetLength = buffer.size(); - processedBytes = 0; - - if (NUM_BYTES_RFC4122_UUID * 2 > packetLength) { - qCDebug(entities) << "EntityItemProperties::decodeCloneEntityMessage().... bailing because not enough bytes in buffer"; - return false; // bail to prevent buffer overflow - } - - QByteArray encodedID = buffer.mid((int)processedBytes, NUM_BYTES_RFC4122_UUID); - entityIDToClone = QUuid::fromRfc4122(encodedID); - dataAt += encodedID.size(); - processedBytes += encodedID.size(); - - encodedID = buffer.mid((int)processedBytes, NUM_BYTES_RFC4122_UUID); - newEntityID = QUuid::fromRfc4122(encodedID); - dataAt += encodedID.size(); - processedBytes += encodedID.size(); - - return true; -} - -void EntityItemProperties::markAllChanged() { - // Core - _simulationOwnerChanged = true; - _parentIDChanged = true; - _parentJointIndexChanged = true; - _visibleChanged = true; - _nameChanged = true; - _lockedChanged = true; - _userDataChanged = true; - _privateUserDataChanged = true; - _hrefChanged = true; - _descriptionChanged = true; - _positionChanged = true; - _dimensionsChanged = true; - _rotationChanged = true; - _registrationPointChanged = true; - _createdChanged = true; - _lastEditedByChanged = true; - _entityHostTypeChanged = true; - _owningAvatarIDChanged = true; - _queryAACubeChanged = true; - _canCastShadowChanged = true; - _isVisibleInSecondaryCameraChanged = true; - _renderLayerChanged = true; - _primitiveModeChanged = true; - _ignorePickIntersectionChanged = true; - _renderWithZonesChanged = true; - _billboardModeChanged = true; - _grab.markAllChanged(); - - // Physics - _densityChanged = true; - _velocityChanged = true; - _angularVelocityChanged = true; - _gravityChanged = true; - _accelerationChanged = true; - _dampingChanged = true; - _angularDampingChanged = true; - _restitutionChanged = true; - _frictionChanged = true; - _lifetimeChanged = true; - _collisionlessChanged = true; - _collisionMaskChanged = true; - _dynamicChanged = true; - _collisionSoundURLChanged = true; - _actionDataChanged = true; - - // Cloning - _cloneableChanged = true; - _cloneLifetimeChanged = true; - _cloneLimitChanged = true; - _cloneDynamicChanged = true; - _cloneAvatarEntityChanged = true; - _cloneOriginIDChanged = true; - - // Scripts - _scriptChanged = true; - _scriptTimestampChanged = true; - _serverScriptsChanged = true; - - // Common - _shapeTypeChanged = true; - _compoundShapeURLChanged = true; - _colorChanged = true; - _alphaChanged = true; - _pulse.markAllChanged(); - _texturesChanged = true; - - // Particles - _maxParticlesChanged = true; - _lifespanChanged = true; - _isEmittingChanged = true; - _emitRateChanged = true; - _emitSpeedChanged = true; - _speedSpreadChanged = true; - _emitOrientationChanged = true; - _emitDimensionsChanged = true; - _emitRadiusStartChanged = true; - _polarStartChanged = true; - _polarFinishChanged = true; - _azimuthStartChanged = true; - _azimuthFinishChanged = true; - _emitAccelerationChanged = true; - _accelerationSpreadChanged = true; - _particleRadiusChanged = true; - _radiusSpreadChanged = true; - _radiusStartChanged = true; - _radiusFinishChanged = true; - _colorSpreadChanged = true; - _colorStartChanged = true; - _colorFinishChanged = true; - _alphaSpreadChanged = true; - _alphaStartChanged = true; - _alphaFinishChanged = true; - _emitterShouldTrailChanged = true; - _particleSpinChanged = true; - _spinStartChanged = true; - _spinFinishChanged = true; - _spinSpreadChanged = true; - _rotateWithEntityChanged = true; - - // Model - _modelURLChanged = true; - _modelScaleChanged = true; - _jointRotationsSetChanged = true; - _jointRotationsChanged = true; - _jointTranslationsSetChanged = true; - _jointTranslationsChanged = true; - _relayParentJointsChanged = true; - _groupCulledChanged = true; - _blendshapeCoefficientsChanged = true; - _useOriginalPivotChanged = true; - _animation.markAllChanged(); - - // Light - _isSpotlightChanged = true; - _intensityChanged = true; - _exponentChanged = true; - _cutoffChanged = true; - _falloffRadiusChanged = true; - - // Text - _textChanged = true; - _lineHeightChanged = true; - _textColorChanged = true; - _textAlphaChanged = true; - _backgroundColorChanged = true; - _backgroundAlphaChanged = true; - _leftMarginChanged = true; - _rightMarginChanged = true; - _topMarginChanged = true; - _bottomMarginChanged = true; - _unlitChanged = true; - _fontChanged = true; - _textEffectChanged = true; - _textEffectColorChanged = true; - _textEffectThicknessChanged = true; - _alignmentChanged = true; - - // Zone - _keyLight.markAllChanged(); - _ambientLight.markAllChanged(); - _skybox.markAllChanged(); - _haze.markAllChanged(); - _bloom.markAllChanged(); - _flyingAllowedChanged = true; - _ghostingAllowedChanged = true; - _filterURLChanged = true; - _keyLightModeChanged = true; - _ambientLightModeChanged = true; - _skyboxModeChanged = true; - _hazeModeChanged = true; - _bloomModeChanged = true; - _avatarPriorityChanged = true; - _screenshareChanged = true; - - // Polyvox - _voxelVolumeSizeChanged = true; - _voxelDataChanged = true; - _voxelSurfaceStyleChanged = true; - _xTextureURLChanged = true; - _yTextureURLChanged = true; - _zTextureURLChanged = true; - _xNNeighborIDChanged = true; - _yNNeighborIDChanged = true; - _zNNeighborIDChanged = true; - _xPNeighborIDChanged = true; - _yPNeighborIDChanged = true; - _zPNeighborIDChanged = true; - - // Web - _sourceUrlChanged = true; - _dpiChanged = true; - _scriptURLChanged = true; - _maxFPSChanged = true; - _inputModeChanged = true; - _showKeyboardFocusHighlightChanged = true; - _useBackgroundChanged = true; - _userAgentChanged = true; - - // Polyline - _linePointsChanged = true; - _strokeWidthsChanged = true; - _normalsChanged = true; - _strokeColorsChanged = true; - _isUVModeStretchChanged = true; - _glowChanged = true; - _faceCameraChanged = true; - - // Shape - _shapeChanged = true; - - // Material - _materialURLChanged = true; - _materialMappingModeChanged = true; - _priorityChanged = true; - _parentMaterialNameChanged = true; - _materialMappingPosChanged = true; - _materialMappingScaleChanged = true; - _materialMappingRotChanged = true; - _materialDataChanged = true; - _materialRepeatChanged = true; - - // Image - _imageURLChanged = true; - _emissiveChanged = true; - _keepAspectRatioChanged = true; - _subImageChanged = true; - - // Grid - _followCameraChanged = true; - _majorGridEveryChanged = true; - _minorGridEveryChanged = true; - - // Gizmo - _gizmoTypeChanged = true; - _ring.markAllChanged(); -} - -// The minimum bounding box for the entity. -AABox EntityItemProperties::getAABox() const { - - // _position represents the position of the registration point. - vec3 registrationRemainder = vec3(1.0f) - _registrationPoint; - - vec3 unrotatedMinRelativeToEntity = -(_dimensions * _registrationPoint); - vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder; - Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; - Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(_rotation); - - // shift the extents to be relative to the position/registration point - rotatedExtentsRelativeToRegistrationPoint.shiftBy(_position); - - return AABox(rotatedExtentsRelativeToRegistrationPoint); -} - -bool EntityItemProperties::hasTransformOrVelocityChanges() const { - return _positionChanged || _localPositionChanged - || _rotationChanged || _localRotationChanged - || _velocityChanged || _localVelocityChanged - || _angularVelocityChanged || _localAngularVelocityChanged - || _accelerationChanged; -} - -void EntityItemProperties::clearTransformOrVelocityChanges() { - _positionChanged = false; - _localPositionChanged = false; - _rotationChanged = false; - _localRotationChanged = false; - _velocityChanged = false; - _localVelocityChanged = false; - _angularVelocityChanged = false; - _localAngularVelocityChanged = false; - _accelerationChanged = false; -} - -bool EntityItemProperties::hasMiscPhysicsChanges() const { - return _gravityChanged || _dimensionsChanged || _densityChanged || _frictionChanged - || _restitutionChanged || _dampingChanged || _angularDampingChanged || _registrationPointChanged || - _compoundShapeURLChanged || _dynamicChanged || _collisionlessChanged || _collisionMaskChanged; -} - -bool EntityItemProperties::hasSimulationRestrictedChanges() const { - return _positionChanged || _localPositionChanged - || _rotationChanged || _localRotationChanged - || _velocityChanged || _localVelocityChanged - || _localDimensionsChanged || _dimensionsChanged - || _angularVelocityChanged || _localAngularVelocityChanged - || _accelerationChanged - || _parentIDChanged || _parentJointIndexChanged; -} - -void EntityItemProperties::copySimulationRestrictedProperties(const EntityItemPointer& entity) { - if (!_parentIDChanged) { - setParentID(entity->getParentID()); - } - if (!_parentJointIndexChanged) { - setParentJointIndex(entity->getParentJointIndex()); - } - if (!_localPositionChanged && !_positionChanged) { - setPosition(entity->getWorldPosition()); - } - if (!_localRotationChanged && !_rotationChanged) { - setRotation(entity->getWorldOrientation()); - } - if (!_localVelocityChanged && !_velocityChanged) { - setVelocity(entity->getWorldVelocity()); - } - if (!_localAngularVelocityChanged && !_angularVelocityChanged) { - setAngularVelocity(entity->getWorldAngularVelocity()); - } - if (!_accelerationChanged) { - setAcceleration(entity->getAcceleration()); - } - if (!_localDimensionsChanged && !_dimensionsChanged) { - setLocalDimensions(entity->getScaledDimensions()); - } -} - -void EntityItemProperties::clearSimulationRestrictedProperties() { - _positionChanged = false; - _localPositionChanged = false; - _rotationChanged = false; - _localRotationChanged = false; - _velocityChanged = false; - _localVelocityChanged = false; - _angularVelocityChanged = false; - _localAngularVelocityChanged = false; - _accelerationChanged = false; - _parentIDChanged = false; - _parentJointIndexChanged = false; -} - -void EntityItemProperties::clearSimulationOwner() { - _simulationOwner.clear(); - _simulationOwnerChanged = true; -} - -void EntityItemProperties::setSimulationOwner(const QUuid& id, uint8_t priority) { - if (!_simulationOwner.matchesValidID(id) || _simulationOwner.getPriority() != priority) { - _simulationOwner.set(id, priority); - _simulationOwnerChanged = true; - } -} - -void EntityItemProperties::setSimulationOwner(const QByteArray& data) { - if (_simulationOwner.fromByteArray(data)) { - _simulationOwnerChanged = true; - } -} - -uint8_t EntityItemProperties::computeSimulationBidPriority() const { - uint8_t priority = 0; - if (_parentIDChanged || _parentJointIndexChanged) { - // we need higher simulation ownership priority to chang parenting info - priority = SCRIPT_GRAB_SIMULATION_PRIORITY; - } else if (_positionChanged || _localPositionChanged - || _rotationChanged || _localRotationChanged - || _velocityChanged || _localVelocityChanged - || _angularVelocityChanged || _localAngularVelocityChanged) { - priority = SCRIPT_POKE_SIMULATION_PRIORITY; - } - return priority; -} - -QList EntityItemProperties::listChangedProperties() { - QList out; - - // Core - if (simulationOwnerChanged()) { - out += "simulationOwner"; - } - if (parentIDChanged()) { - out += "parentID"; - } - if (parentJointIndexChanged()) { - out += "parentJointIndex"; - } - if (visibleChanged()) { - out += "visible"; - } - if (nameChanged()) { - out += "name"; - } - if (lockedChanged()) { - out += "locked"; - } - if (userDataChanged()) { - out += "userData"; - } - if (privateUserDataChanged()) { - out += "privateUserData"; - } - if (hrefChanged()) { - out += "href"; - } - if (descriptionChanged()) { - out += "description"; - } - if (containsPositionChange()) { - out += "position"; - } - if (dimensionsChanged()) { - out += "dimensions"; - } - if (rotationChanged()) { - out += "rotation"; - } - if (registrationPointChanged()) { - out += "registrationPoint"; - } - if (createdChanged()) { - out += "created"; - } - if (lastEditedByChanged()) { - out += "lastEditedBy"; - } - if (entityHostTypeChanged()) { - out += "entityHostType"; - } - if (owningAvatarIDChanged()) { - out += "owningAvatarID"; - } - if (queryAACubeChanged()) { - out += "queryAACube"; - } - if (canCastShadowChanged()) { - out += "canCastShadow"; - } - if (isVisibleInSecondaryCameraChanged()) { - out += "isVisibleInSecondaryCamera"; - } - if (renderLayerChanged()) { - out += "renderLayer"; - } - if (primitiveModeChanged()) { - out += "primitiveMode"; - } - if (ignorePickIntersectionChanged()) { - out += "ignorePickIntersection"; - } - if (renderWithZonesChanged()) { - out += "renderWithZones"; - } - if (billboardModeChanged()) { - out += "billboardMode"; - } - getGrab().listChangedProperties(out); - - // Physics - if (densityChanged()) { - out += "density"; - } - if (velocityChanged()) { - out += "velocity"; - } - if (angularVelocityChanged()) { - out += "angularVelocity"; - } - if (gravityChanged()) { - out += "gravity"; - } - if (accelerationChanged()) { - out += "acceleration"; - } - if (dampingChanged()) { - out += "damping"; - } - if (angularDampingChanged()) { - out += "angularDamping"; - } - if (restitutionChanged()) { - out += "restitution"; - } - if (frictionChanged()) { - out += "friction"; - } - if (lifetimeChanged()) { - out += "lifetime"; - } - if (collisionlessChanged()) { - out += "collisionless"; - } - if (collisionMaskChanged()) { - out += "collisionMask"; - } - if (dynamicChanged()) { - out += "dynamic"; - } - if (collisionSoundURLChanged()) { - out += "collisionSoundURL"; - } - if (actionDataChanged()) { - out += "actionData"; - } - - // Cloning - if (cloneableChanged()) { - out += "cloneable"; - } - if (cloneLifetimeChanged()) { - out += "cloneLifetime"; - } - if (cloneLimitChanged()) { - out += "cloneLimit"; - } - if (cloneDynamicChanged()) { - out += "cloneDynamic"; - } - if (cloneAvatarEntityChanged()) { - out += "cloneAvatarEntity"; - } - if (cloneOriginIDChanged()) { - out += "cloneOriginID"; - } - - // Scripts - if (scriptChanged()) { - out += "script"; - } - if (scriptTimestampChanged()) { - out += "scriptTimestamp"; - } - if (serverScriptsChanged()) { - out += "serverScripts"; - } - - // Common - if (shapeTypeChanged()) { - out += "shapeType"; - } - if (compoundShapeURLChanged()) { - out += "compoundShapeURL"; - } - if (colorChanged()) { - out += "color"; - } - if (alphaChanged()) { - out += "alpha"; - } - getPulse().listChangedProperties(out); - if (texturesChanged()) { - out += "textures"; - } - - // Particles - if (maxParticlesChanged()) { - out += "maxParticles"; - } - if (lifespanChanged()) { - out += "lifespan"; - } - if (isEmittingChanged()) { - out += "isEmitting"; - } - if (emitRateChanged()) { - out += "emitRate"; - } - if (emitSpeedChanged()) { - out += "emitSpeed"; - } - if (speedSpreadChanged()) { - out += "speedSpread"; - } - if (emitOrientationChanged()) { - out += "emitOrientation"; - } - if (emitDimensionsChanged()) { - out += "emitDimensions"; - } - if (emitRadiusStartChanged()) { - out += "emitRadiusStart"; - } - if (polarStartChanged()) { - out += "polarStart"; - } - if (polarFinishChanged()) { - out += "polarFinish"; - } - if (azimuthStartChanged()) { - out += "azimuthStart"; - } - if (azimuthFinishChanged()) { - out += "azimuthFinish"; - } - if (emitAccelerationChanged()) { - out += "emitAcceleration"; - } - if (accelerationSpreadChanged()) { - out += "accelerationSpread"; - } - if (particleRadiusChanged()) { - out += "particleRadius"; - } - if (radiusSpreadChanged()) { - out += "radiusSpread"; - } - if (radiusStartChanged()) { - out += "radiusStart"; - } - if (radiusFinishChanged()) { - out += "radiusFinish"; - } - if (colorSpreadChanged()) { - out += "colorSpread"; - } - if (colorStartChanged()) { - out += "colorStart"; - } - if (colorFinishChanged()) { - out += "colorFinish"; - } - if (alphaSpreadChanged()) { - out += "alphaSpread"; - } - if (alphaStartChanged()) { - out += "alphaStart"; - } - if (alphaFinishChanged()) { - out += "alphaFinish"; - } - if (emitterShouldTrailChanged()) { - out += "emitterShouldTrail"; - } - if (particleSpinChanged()) { - out += "particleSpin"; - } - if (spinSpreadChanged()) { - out += "spinSpread"; - } - if (spinStartChanged()) { - out += "spinStart"; - } - if (spinFinishChanged()) { - out += "spinFinish"; - } - if (rotateWithEntityChanged()) { - out += "rotateWithEntity"; - } - - // Model - if (modelURLChanged()) { - out += "modelURL"; - } - if (modelScaleChanged()) { - out += "scale"; - } - if (jointRotationsSetChanged()) { - out += "jointRotationsSet"; - } - if (jointRotationsChanged()) { - out += "jointRotations"; - } - if (jointTranslationsSetChanged()) { - out += "jointTranslationsSet"; - } - if (jointTranslationsChanged()) { - out += "jointTranslations"; - } - if (relayParentJointsChanged()) { - out += "relayParentJoints"; - } - if (groupCulledChanged()) { - out += "groupCulled"; - } - if (blendshapeCoefficientsChanged()) { - out += "blendshapeCoefficients"; - } - if (useOriginalPivotChanged()) { - out += "useOriginalPivot"; - } - getAnimation().listChangedProperties(out); - - // Light - if (isSpotlightChanged()) { - out += "isSpotlight"; - } - if (intensityChanged()) { - out += "intensity"; - } - if (exponentChanged()) { - out += "exponent"; - } - if (cutoffChanged()) { - out += "cutoff"; - } - if (falloffRadiusChanged()) { - out += "falloffRadius"; - } - - // Text - if (textChanged()) { - out += "text"; - } - if (lineHeightChanged()) { - out += "lineHeight"; - } - if (textColorChanged()) { - out += "textColor"; - } - if (textAlphaChanged()) { - out += "textAlpha"; - } - if (backgroundColorChanged()) { - out += "backgroundColor"; - } - if (backgroundAlphaChanged()) { - out += "backgroundAlpha"; - } - if (leftMarginChanged()) { - out += "leftMargin"; - } - if (rightMarginChanged()) { - out += "rightMargin"; - } - if (topMarginChanged()) { - out += "topMargin"; - } - if (bottomMarginChanged()) { - out += "bottomMargin"; - } - if (unlitChanged()) { - out += "unlit"; - } - if (fontChanged()) { - out += "font"; - } - if (textEffectChanged()) { - out += "textEffect"; - } - if (textEffectColorChanged()) { - out += "textEffectColor"; - } - if (textEffectThicknessChanged()) { - out += "textEffectThickness"; - } - if (alignmentChanged()) { - out += "alignment"; - } - - // Zone - getKeyLight().listChangedProperties(out); - getAmbientLight().listChangedProperties(out); - getSkybox().listChangedProperties(out); - getHaze().listChangedProperties(out); - getBloom().listChangedProperties(out); - if (flyingAllowedChanged()) { - out += "flyingAllowed"; - } - if (ghostingAllowedChanged()) { - out += "ghostingAllowed"; - } - if (filterURLChanged()) { - out += "filterURL"; - } - if (keyLightModeChanged()) { - out += "keyLightMode"; - } - if (ambientLightModeChanged()) { - out += "ambientLightMode"; - } - if (skyboxModeChanged()) { - out += "skyboxMode"; - } - if (hazeModeChanged()) { - out += "hazeMode"; - } - if (bloomModeChanged()) { - out += "bloomMode"; - } - if (avatarPriorityChanged()) { - out += "avatarPriority"; - } - if (screenshareChanged()) { - out += "screenshare"; - } - - // Polyvox - if (voxelVolumeSizeChanged()) { - out += "voxelVolumeSize"; - } - if (voxelDataChanged()) { - out += "voxelData"; - } - if (voxelSurfaceStyleChanged()) { - out += "voxelSurfaceStyle"; - } - if (xTextureURLChanged()) { - out += "xTextureURL"; - } - if (yTextureURLChanged()) { - out += "yTextureURL"; - } - if (zTextureURLChanged()) { - out += "zTextureURL"; - } - if (xNNeighborIDChanged()) { - out += "xNNeighborID"; - } - if (yNNeighborIDChanged()) { - out += "yNNeighborID"; - } - if (zNNeighborIDChanged()) { - out += "zNNeighborID"; - } - if (xPNeighborIDChanged()) { - out += "xPNeighborID"; - } - if (yPNeighborIDChanged()) { - out += "yPNeighborID"; - } - if (zPNeighborIDChanged()) { - out += "zPNeighborID"; - } - - // Web - if (sourceUrlChanged()) { - out += "sourceUrl"; - } - if (dpiChanged()) { - out += "dpi"; - } - if (scriptURLChanged()) { - out += "scriptURL"; - } - if (maxFPSChanged()) { - out += "maxFPS"; - } - if (inputModeChanged()) { - out += "inputMode"; - } - - // Polyline - if (linePointsChanged()) { - out += "linePoints"; - } - if (strokeWidthsChanged()) { - out += "strokeWidths"; - } - if (normalsChanged()) { - out += "normals"; - } - if (strokeColorsChanged()) { - out += "strokeColors"; - } - if (isUVModeStretchChanged()) { - out += "isUVModeStretch"; - } - if (glowChanged()) { - out += "glow"; - } - if (faceCameraChanged()) { - out += "faceCamera"; - } - if (showKeyboardFocusHighlightChanged()) { - out += "showKeyboardFocusHighlight"; - } - if (useBackgroundChanged()) { - out += "useBackground"; - } - if (userAgentChanged()) { - out += "userAgent"; - } - - // Shape - if (shapeChanged()) { - out += "shape"; - } - - // Material - if (materialURLChanged()) { - out += "materialURL"; - } - if (materialMappingModeChanged()) { - out += "materialMappingMode"; - } - if (priorityChanged()) { - out += "priority"; - } - if (parentMaterialNameChanged()) { - out += "parentMaterialName"; - } - if (materialMappingPosChanged()) { - out += "materialMappingPos"; - } - if (materialMappingScaleChanged()) { - out += "materialMappingScale"; - } - if (materialMappingRotChanged()) { - out += "materialMappingRot"; - } - if (materialDataChanged()) { - out += "materialData"; - } - if (materialRepeatChanged()) { - out += "materialRepeat"; - } - - // Image - if (imageURLChanged()) { - out += "imageURL"; - } - if (emissiveChanged()) { - out += "emissive"; - } - if (keepAspectRatioChanged()) { - out += "keepAspectRatio"; - } - if (subImageChanged()) { - out += "subImage"; - } - - // Grid - if (followCameraChanged()) { - out += "followCamera"; - } - if (majorGridEveryChanged()) { - out += "majorGridEvery"; - } - if (minorGridEveryChanged()) { - out += "minorGridEvery"; - } - - // Gizmo - if (gizmoTypeChanged()) { - out += "gizmoType"; - } - getRing().listChangedProperties(out); - - return out; -} - -bool EntityItemProperties::transformChanged() const { - return positionChanged() || rotationChanged() || - localPositionChanged() || localRotationChanged(); -} - -bool EntityItemProperties::getScalesWithParent() const { - // keep this logic the same as in EntityItem::getScalesWithParent - bool scalesWithParent { false }; - if (parentIDChanged()) { - bool success; - SpatiallyNestablePointer parent = SpatiallyNestable::findByID(getParentID(), success); - if (success && parent) { - bool avatarAncestor = (parent->getNestableType() == NestableType::Avatar || - parent->hasAncestorOfType(NestableType::Avatar)); - scalesWithParent = getEntityHostType() == entity::HostType::AVATAR && avatarAncestor; - } - } - return scalesWithParent; -} - -bool EntityItemProperties::parentRelatedPropertyChanged() const { - return positionChanged() || rotationChanged() || - localPositionChanged() || localRotationChanged() || - localDimensionsChanged() || - parentIDChanged() || parentJointIndexChanged(); -} - -bool EntityItemProperties::queryAACubeRelatedPropertyChanged() const { - return parentRelatedPropertyChanged() || dimensionsChanged(); -} - -bool EntityItemProperties::grabbingRelatedPropertyChanged() const { - const GrabPropertyGroup& grabProperties = getGrab(); - return grabProperties.triggerableChanged() || grabProperties.grabbableChanged() || - grabProperties.grabFollowsControllerChanged() || grabProperties.grabKinematicChanged() || - grabProperties.equippableChanged() || grabProperties.equippableLeftPositionChanged() || - grabProperties.equippableRightPositionChanged() || grabProperties.equippableLeftRotationChanged() || - grabProperties.equippableRightRotationChanged() || grabProperties.equippableIndicatorURLChanged() || - grabProperties.equippableIndicatorScaleChanged() || grabProperties.equippableIndicatorOffsetChanged(); -} - -void EntityItemProperties::convertToCloneProperties(const EntityItemID& entityIDToClone) { - setName(getName() + "-clone-" + entityIDToClone.toString()); - setLocked(false); - setParentID(QUuid()); - setParentJointIndex(-1); - setLifetime(getCloneLifetime()); - setDynamic(getCloneDynamic()); - if (getEntityHostType() != entity::HostType::LOCAL) { - setEntityHostType(getCloneAvatarEntity() ? entity::HostType::AVATAR : entity::HostType::DOMAIN); - } else { - // Local Entities clone as local entities - setEntityHostType(entity::HostType::LOCAL); - setCollisionless(true); - } - uint64_t now = usecTimestampNow(); - setCreated(now); - setLastEdited(now); - setCloneable(ENTITY_ITEM_DEFAULT_CLONEABLE); - setCloneLifetime(ENTITY_ITEM_DEFAULT_CLONE_LIFETIME); - setCloneLimit(ENTITY_ITEM_DEFAULT_CLONE_LIMIT); - setCloneDynamic(ENTITY_ITEM_DEFAULT_CLONE_DYNAMIC); - setCloneAvatarEntity(ENTITY_ITEM_DEFAULT_CLONE_AVATAR_ENTITY); -} - -bool EntityItemProperties::blobToProperties(ScriptEngine& scriptEngine, const QByteArray& blob, EntityItemProperties& properties) { - // DANGER: this method is NOT efficient. - // begin recipe for converting unfortunately-formatted-binary-blob to EntityItemProperties - OVERTE_IGNORE_DEPRECATED_BEGIN - QJsonDocument jsonProperties = QJsonDocument::fromBinaryData(blob); - OVERTE_IGNORE_DEPRECATED_END - if (jsonProperties.isEmpty() || jsonProperties.isNull() || !jsonProperties.isObject() || jsonProperties.object().isEmpty()) { - qCDebug(entities) << "bad avatarEntityData json" << QString(blob.toHex()); - return false; - } - QVariant variant = jsonProperties.toVariant(); - QVariantMap variantMap = variant.toMap(); - ScriptValue scriptValue = variantMapToScriptValue(variantMap, scriptEngine); - EntityItemPropertiesFromScriptValueIgnoreReadOnly(scriptValue, properties); - // end recipe - return true; -} - -void EntityItemProperties::propertiesToBlob(ScriptEngine& scriptEngine, const QUuid& myAvatarID, - const EntityItemProperties& properties, QByteArray& blob, bool allProperties) { - // DANGER: this method is NOT efficient. - // begin recipe for extracting unfortunately-formatted-binary-blob from EntityItem - ScriptValue scriptValue = allProperties - ? EntityItemPropertiesToScriptValue(&scriptEngine, properties) - : EntityItemNonDefaultPropertiesToScriptValue(&scriptEngine, properties); - QVariant variantProperties = scriptValue.toVariant(); - QJsonDocument jsonProperties = QJsonDocument::fromVariant(variantProperties); - // the ID of the parent/avatar changes from session to session. use a special UUID to indicate the avatar - QJsonObject jsonObject = jsonProperties.object(); - if (jsonObject.contains("parentID")) { - if (QUuid(jsonObject["parentID"].toString()) == myAvatarID) { - jsonObject["parentID"] = AVATAR_SELF_ID.toString(); - } - } - jsonProperties = QJsonDocument(jsonObject); - OVERTE_IGNORE_DEPRECATED_BEGIN - blob = jsonProperties.toBinaryData(); - OVERTE_IGNORE_DEPRECATED_END - // end recipe -} - -QDebug& operator<<(QDebug& dbg, const EntityPropertyFlags& f) { - QString result = "[ "; - - for (int i = 0; i < PROP_AFTER_LAST_ITEM; i++) { - auto prop = EntityPropertyList(i); - if (f.getHasProperty(prop)) { - result = result + _enumsToPropertyStrings[prop] + " "; - } - } - - result += "]"; - dbg.nospace() << result; - return dbg; -} diff --git a/libraries/entities/src/EntityItemProperties.cpp.in b/libraries/entities/src/EntityItemProperties.cpp.in new file mode 100644 index 00000000000..e5d16aaf94e --- /dev/null +++ b/libraries/entities/src/EntityItemProperties.cpp.in @@ -0,0 +1,1463 @@ +// +// EntityItemProperties.cpp +// libraries/entities/src +// +// Created by Brad Hefta-Gaub on 12/4/13. +// Copyright 2013 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. +// Copyright 2022-2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#include "EntityItemProperties.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "EntitiesLogging.h" +#include "WarningsSuppression.h" + +@ENTITY_ITEM_PROPERTY_STATIC_GROUPS@ + +EntityPropertyList PROP_LAST_ITEM = (EntityPropertyList)(PROP_AFTER_LAST_ITEM - 1); + +EntityItemProperties::EntityItemProperties(EntityPropertyFlags desiredProperties) : + _id(UNKNOWN_ENTITY_ID), + _idSet(false), + _lastEdited(0), + _type(EntityTypes::Unknown), + + _defaultSettings(true), + _naturalDimensions(1.0f, 1.0f, 1.0f), + _naturalPosition(0.0f, 0.0f, 0.0f), + _desiredProperties(desiredProperties) +{ + +} + +void EntityItemProperties::calculateNaturalPosition(const vec3& min, const vec3& max) { + vec3 halfDimension = (max - min) / 2.0f; + _naturalPosition = max - halfDimension; +} + +void EntityItemProperties::debugDump() const { + qCDebug(entities) << "EntityItemProperties..."; + qCDebug(entities) << " _type=" << EntityTypes::getEntityTypeName(_type); + qCDebug(entities) << " _id=" << _id; + qCDebug(entities) << " _idSet=" << _idSet; + qCDebug(entities) << " _position=" << _position.x << "," << _position.y << "," << _position.z; + qCDebug(entities) << " _dimensions=" << getDimensions(); + qCDebug(entities) << " _modelURL=" << _modelURL; + qCDebug(entities) << " _compoundShapeURL=" << _compoundShapeURL; + +@ENTITY_ITEM_PROPERTY_DEBUG_DUMP_GROUPS@ + + qCDebug(entities) << " changed properties..."; + EntityPropertyFlags props = getChangedProperties(); + props.debugDumpBits(); +} + +void EntityItemProperties::setLastEdited(quint64 usecTime) { + _lastEdited = usecTime > _created ? usecTime : _created; +} + +bool EntityItemProperties::constructFromBuffer(const unsigned char* data, int dataLength) { + ReadBitstreamToTreeParams args; + EntityItemPointer tempEntity = EntityTypes::constructEntityItem(data, dataLength); + if (!tempEntity) { + return false; + } + tempEntity->readEntityDataFromBuffer(data, dataLength, args); + (*this) = tempEntity->getProperties(); + return true; +} + +inline void addEntityShape(QHash& lookup, EntityShape type) { lookup[EntityShapeHelpers::getNameForEntityShape(type)] = type; } +QHash stringToEntityShapeLookup = [] { + QHash toReturn; + addEntityShape(toReturn, EntityShape::Triangle); + addEntityShape(toReturn, EntityShape::Quad); + addEntityShape(toReturn, EntityShape::Hexagon); + addEntityShape(toReturn, EntityShape::Octagon); + addEntityShape(toReturn, EntityShape::Circle); + addEntityShape(toReturn, EntityShape::Cube); + addEntityShape(toReturn, EntityShape::Sphere); + addEntityShape(toReturn, EntityShape::Tetrahedron); + addEntityShape(toReturn, EntityShape::Octahedron); + addEntityShape(toReturn, EntityShape::Dodecahedron); + addEntityShape(toReturn, EntityShape::Icosahedron); + addEntityShape(toReturn, EntityShape::Torus); + addEntityShape(toReturn, EntityShape::Cone); + addEntityShape(toReturn, EntityShape::Cylinder); + return toReturn; +}(); +QString EntityItemProperties::getShapeAsString() const { return EntityShapeHelpers::getNameForEntityShape(_shape); } +void EntityItemProperties::setShapeFromString(const QString& shapeName) { + auto shapeItr = stringToEntityShapeLookup.find(shapeName); + if (shapeItr != stringToEntityShapeLookup.end()) { + _shape = shapeItr.value(); + _shapeChanged = true; + } +} + +inline void addShapeType(QHash& lookup, ShapeType type) { lookup[ShapeInfo::getNameForShapeType(type)] = type; } +QHash stringToShapeTypeLookup = [] { + QHash toReturn; + addShapeType(toReturn, SHAPE_TYPE_NONE); + addShapeType(toReturn, SHAPE_TYPE_BOX); + addShapeType(toReturn, SHAPE_TYPE_SPHERE); + addShapeType(toReturn, SHAPE_TYPE_CAPSULE_X); + addShapeType(toReturn, SHAPE_TYPE_CAPSULE_Y); + addShapeType(toReturn, SHAPE_TYPE_CAPSULE_Z); + addShapeType(toReturn, SHAPE_TYPE_CYLINDER_X); + addShapeType(toReturn, SHAPE_TYPE_CYLINDER_Y); + addShapeType(toReturn, SHAPE_TYPE_CYLINDER_Z); + addShapeType(toReturn, SHAPE_TYPE_HULL); + addShapeType(toReturn, SHAPE_TYPE_PLANE); + addShapeType(toReturn, SHAPE_TYPE_COMPOUND); + addShapeType(toReturn, SHAPE_TYPE_SIMPLE_HULL); + addShapeType(toReturn, SHAPE_TYPE_SIMPLE_COMPOUND); + addShapeType(toReturn, SHAPE_TYPE_STATIC_MESH); + addShapeType(toReturn, SHAPE_TYPE_ELLIPSOID); + addShapeType(toReturn, SHAPE_TYPE_CIRCLE); + return toReturn; +}(); +QString EntityItemProperties::getShapeTypeAsString() const { return ShapeInfo::getNameForShapeType(_shapeType); } +void EntityItemProperties::setShapeTypeFromString(const QString& shapeName) { + auto shapeTypeItr = stringToShapeTypeLookup.find(shapeName.toLower()); + if (shapeTypeItr != stringToShapeTypeLookup.end()) { + _shapeType = shapeTypeItr.value(); + _shapeTypeChanged = true; + } +} + +inline void addMaterialMappingMode(QHash& lookup, MaterialMappingMode mode) { lookup[MaterialMappingModeHelpers::getNameForMaterialMappingMode(mode)] = mode; } +const QHash stringToMaterialMappingModeLookup = [] { + QHash toReturn; + addMaterialMappingMode(toReturn, UV); + addMaterialMappingMode(toReturn, PROJECTED); + return toReturn; +}(); +QString EntityItemProperties::getMaterialMappingModeAsString() const { return MaterialMappingModeHelpers::getNameForMaterialMappingMode(_materialMappingMode); } +void EntityItemProperties::setMaterialMappingModeFromString(const QString& materialMappingMode) { + auto materialMappingModeItr = stringToMaterialMappingModeLookup.find(materialMappingMode.toLower()); + if (materialMappingModeItr != stringToMaterialMappingModeLookup.end()) { + _materialMappingMode = materialMappingModeItr.value(); + _materialMappingModeChanged = true; + } +} + +inline void addBillboardMode(QHash& lookup, BillboardMode mode) { lookup[BillboardModeHelpers::getNameForBillboardMode(mode)] = mode; } +const QHash stringToBillboardModeLookup = [] { + QHash toReturn; + addBillboardMode(toReturn, BillboardMode::NONE); + addBillboardMode(toReturn, BillboardMode::YAW); + addBillboardMode(toReturn, BillboardMode::FULL); + return toReturn; +}(); +QString EntityItemProperties::getBillboardModeAsString() const { return BillboardModeHelpers::getNameForBillboardMode(_billboardMode); } +void EntityItemProperties::setBillboardModeFromString(const QString& billboardMode) { + auto billboardModeItr = stringToBillboardModeLookup.find(billboardMode.toLower()); + if (billboardModeItr != stringToBillboardModeLookup.end()) { + _billboardMode = billboardModeItr.value(); + _billboardModeChanged = true; + } +} + +inline void addRenderLayer(QHash& lookup, RenderLayer mode) { lookup[RenderLayerHelpers::getNameForRenderLayer(mode)] = mode; } +const QHash stringToRenderLayerLookup = [] { + QHash toReturn; + addRenderLayer(toReturn, RenderLayer::WORLD); + addRenderLayer(toReturn, RenderLayer::FRONT); + addRenderLayer(toReturn, RenderLayer::HUD); + return toReturn; +}(); +QString EntityItemProperties::getRenderLayerAsString() const { return RenderLayerHelpers::getNameForRenderLayer(_renderLayer); } +void EntityItemProperties::setRenderLayerFromString(const QString& renderLayer) { + auto renderLayerItr = stringToRenderLayerLookup.find(renderLayer.toLower()); + if (renderLayerItr != stringToRenderLayerLookup.end()) { + _renderLayer = renderLayerItr.value(); + _renderLayerChanged = true; + } +} + +inline void addPrimitiveMode(QHash& lookup, PrimitiveMode mode) { lookup[PrimitiveModeHelpers::getNameForPrimitiveMode(mode)] = mode; } +const QHash stringToPrimitiveModeLookup = [] { + QHash toReturn; + addPrimitiveMode(toReturn, PrimitiveMode::SOLID); + addPrimitiveMode(toReturn, PrimitiveMode::LINES); + return toReturn; +}(); +QString EntityItemProperties::getPrimitiveModeAsString() const { return PrimitiveModeHelpers::getNameForPrimitiveMode(_primitiveMode); } +void EntityItemProperties::setPrimitiveModeFromString(const QString& primitiveMode) { + auto primitiveModeItr = stringToPrimitiveModeLookup.find(primitiveMode.toLower()); + if (primitiveModeItr != stringToPrimitiveModeLookup.end()) { + _primitiveMode = primitiveModeItr.value(); + _primitiveModeChanged = true; + } +} + +inline void addWebInputMode(QHash& lookup, WebInputMode mode) { lookup[WebInputModeHelpers::getNameForWebInputMode(mode)] = mode; } +const QHash stringToWebInputModeLookup = [] { + QHash toReturn; + addWebInputMode(toReturn, WebInputMode::TOUCH); + addWebInputMode(toReturn, WebInputMode::MOUSE); + return toReturn; +}(); +QString EntityItemProperties::getInputModeAsString() const { return WebInputModeHelpers::getNameForWebInputMode(_inputMode); } +void EntityItemProperties::setInputModeFromString(const QString& webInputMode) { + auto webInputModeItr = stringToWebInputModeLookup.find(webInputMode.toLower()); + if (webInputModeItr != stringToWebInputModeLookup.end()) { + _inputMode = webInputModeItr.value(); + _inputModeChanged = true; + } +} + +inline void addGizmoType(QHash& lookup, GizmoType mode) { lookup[GizmoTypeHelpers::getNameForGizmoType(mode)] = mode; } +const QHash stringToGizmoTypeLookup = [] { + QHash toReturn; + addGizmoType(toReturn, GizmoType::RING); + return toReturn; +}(); +QString EntityItemProperties::getGizmoTypeAsString() const { return GizmoTypeHelpers::getNameForGizmoType(_gizmoType); } +void EntityItemProperties::setGizmoTypeFromString(const QString& gizmoType) { + auto gizmoTypeItr = stringToGizmoTypeLookup.find(gizmoType.toLower()); + if (gizmoTypeItr != stringToGizmoTypeLookup.end()) { + _gizmoType = gizmoTypeItr.value(); + _gizmoTypeChanged = true; + } +} + +inline void addComponentMode(QHash& lookup, ComponentMode mode) { lookup[ComponentModeHelpers::getNameForComponentMode(mode)] = mode; } +const QHash stringToComponentMode = [] { + QHash toReturn; + addComponentMode(toReturn, ComponentMode::COMPONENT_MODE_INHERIT); + addComponentMode(toReturn, ComponentMode::COMPONENT_MODE_DISABLED); + addComponentMode(toReturn, ComponentMode::COMPONENT_MODE_ENABLED); + return toReturn; +}(); +QString EntityItemProperties::getComponentModeAsString(uint8_t mode) { return ComponentModeHelpers::getNameForComponentMode((ComponentMode)mode); } +QString EntityItemProperties::getSkyboxModeAsString() const { return getComponentModeAsString(_skyboxMode); } +QString EntityItemProperties::getKeyLightModeAsString() const { return getComponentModeAsString(_keyLightMode); } +QString EntityItemProperties::getAmbientLightModeAsString() const { return getComponentModeAsString(_ambientLightMode); } +QString EntityItemProperties::getHazeModeAsString() const { return getComponentModeAsString(_hazeMode); } +QString EntityItemProperties::getBloomModeAsString() const { return getComponentModeAsString(_bloomMode); } +QString EntityItemProperties::getTonemappingModeAsString() const { return getComponentModeAsString(_tonemappingMode); } +QString EntityItemProperties::getAmbientOcclusionModeAsString() const { return getComponentModeAsString(_ambientOcclusionMode); } +void EntityItemProperties::setSkyboxModeFromString(const QString& mode) { + auto modeItr = stringToComponentMode.find(mode.toLower()); + if (modeItr != stringToComponentMode.end()) { + _skyboxMode = modeItr.value(); + _skyboxModeChanged = true; + } +} +void EntityItemProperties::setKeyLightModeFromString(const QString& mode) { + auto modeItr = stringToComponentMode.find(mode.toLower()); + if (modeItr != stringToComponentMode.end()) { + _keyLightMode = modeItr.value(); + _keyLightModeChanged = true; + } +} +void EntityItemProperties::setAmbientLightModeFromString(const QString& mode) { + auto modeItr = stringToComponentMode.find(mode.toLower()); + if (modeItr != stringToComponentMode.end()) { + _ambientLightMode = modeItr.value(); + _ambientLightModeChanged = true; + } +} +void EntityItemProperties::setHazeModeFromString(const QString& mode) { + auto modeItr = stringToComponentMode.find(mode.toLower()); + if (modeItr != stringToComponentMode.end()) { + _hazeMode = modeItr.value(); + _hazeModeChanged = true; + } +} +void EntityItemProperties::setBloomModeFromString(const QString& mode) { + auto modeItr = stringToComponentMode.find(mode.toLower()); + if (modeItr != stringToComponentMode.end()) { + _bloomMode = modeItr.value(); + _bloomModeChanged = true; + } +} +void EntityItemProperties::setTonemappingModeFromString(const QString& mode) { + auto modeItr = stringToComponentMode.find(mode.toLower()); + if (modeItr != stringToComponentMode.end()) { + _tonemappingMode = modeItr.value(); + _tonemappingModeChanged = true; + } +} +void EntityItemProperties::setAmbientOcclusionModeFromString(const QString& mode) { + auto modeItr = stringToComponentMode.find(mode.toLower()); + if (modeItr != stringToComponentMode.end()) { + _ambientOcclusionMode = modeItr.value(); + _ambientOcclusionModeChanged = true; + } +} + +inline void addAvatarPriorityMode(QHash& lookup, AvatarPriorityMode mode) { lookup[AvatarPriorityModeHelpers::getNameForAvatarPriorityMode(mode)] = mode; } +const QHash stringToAvatarPriority = [] { + QHash toReturn; + addAvatarPriorityMode(toReturn, AvatarPriorityMode::AVATAR_PRIORITY_INHERIT); + addAvatarPriorityMode(toReturn, AvatarPriorityMode::AVATAR_PRIORITY_CROWD); + addAvatarPriorityMode(toReturn, AvatarPriorityMode::AVATAR_PRIORITY_HERO); + return toReturn; +}(); +QString EntityItemProperties::getAvatarPriorityAsString() const { return AvatarPriorityModeHelpers::getNameForAvatarPriorityMode((AvatarPriorityMode)_avatarPriority); } +void EntityItemProperties::setAvatarPriorityFromString(const QString& mode) { + auto modeItr = stringToAvatarPriority.find(mode.toLower()); + if (modeItr != stringToAvatarPriority.end()) { + _avatarPriority = modeItr.value(); + _avatarPriorityChanged = true; + } +} + +QString EntityItemProperties::getScreenshareAsString() const { return getComponentModeAsString(_screenshare); } +void EntityItemProperties::setScreenshareFromString(const QString& mode) { + auto modeItr = stringToComponentMode.find(mode.toLower()); + if (modeItr != stringToComponentMode.end()) { + _screenshare = modeItr.value(); + _screenshareChanged = true; + } +} + +inline void addTextEffect(QHash& lookup, TextEffect effect) { lookup[TextEffectHelpers::getNameForTextEffect(effect)] = effect; } +const QHash stringToTextEffectLookup = [] { + QHash toReturn; + addTextEffect(toReturn, TextEffect::NO_EFFECT); + addTextEffect(toReturn, TextEffect::OUTLINE_EFFECT); + addTextEffect(toReturn, TextEffect::OUTLINE_WITH_FILL_EFFECT); + addTextEffect(toReturn, TextEffect::SHADOW_EFFECT); + return toReturn; +}(); +QString EntityItemProperties::getTextEffectAsString() const { return TextEffectHelpers::getNameForTextEffect(_textEffect); } +void EntityItemProperties::setTextEffectFromString(const QString& effect) { + auto textEffectItr = stringToTextEffectLookup.find(effect.toLower()); + if (textEffectItr != stringToTextEffectLookup.end()) { + _textEffect = textEffectItr.value(); + _textEffectChanged = true; + } +} + +inline void addTextAlignment(QHash& lookup, TextAlignment alignment) { lookup[TextAlignmentHelpers::getNameForTextAlignment(alignment)] = alignment; } +const QHash stringToTextAlignmentLookup = [] { + QHash toReturn; + addTextAlignment(toReturn, TextAlignment::LEFT); + addTextAlignment(toReturn, TextAlignment::CENTER); + addTextAlignment(toReturn, TextAlignment::RIGHT); + return toReturn; +}(); +QString EntityItemProperties::getAlignmentAsString() const { return TextAlignmentHelpers::getNameForTextAlignment(_alignment); } +void EntityItemProperties::setAlignmentFromString(const QString& alignment) { + auto textAlignmentItr = stringToTextAlignmentLookup.find(alignment.toLower()); + if (textAlignmentItr != stringToTextAlignmentLookup.end()) { + _alignment = textAlignmentItr.value(); + _alignmentChanged = true; + } +} + +inline void addTextVerticalAlignment(QHash& lookup, TextVerticalAlignment verticalAlignment) { lookup[TextVerticalAlignmentHelpers::getNameForTextVerticalAlignment(verticalAlignment)] = verticalAlignment; } +const QHash stringToTextVerticalAlignmentLookup = [] { + QHash toReturn; + addTextVerticalAlignment(toReturn, TextVerticalAlignment::TOP); + addTextVerticalAlignment(toReturn, TextVerticalAlignment::BOTTOM); + addTextVerticalAlignment(toReturn, TextVerticalAlignment::CENTER); + return toReturn; +}(); +QString EntityItemProperties::getVerticalAlignmentAsString() const { return TextVerticalAlignmentHelpers::getNameForTextVerticalAlignment(_verticalAlignment); } +void EntityItemProperties::setVerticalAlignmentFromString(const QString& verticalAlignment) { + auto textVerticalAlignmentItr = stringToTextVerticalAlignmentLookup.find(verticalAlignment.toLower()); + if (textVerticalAlignmentItr != stringToTextVerticalAlignmentLookup.end()) { + _verticalAlignment = textVerticalAlignmentItr.value(); + _verticalAlignmentChanged = true; + } +} + +QString getCollisionGroupAsString(uint16_t group) { + switch (group) { + case USER_COLLISION_GROUP_DYNAMIC: + return "dynamic"; + case USER_COLLISION_GROUP_STATIC: + return "static"; + case USER_COLLISION_GROUP_KINEMATIC: + return "kinematic"; + case USER_COLLISION_GROUP_MY_AVATAR: + return "myAvatar"; + case USER_COLLISION_GROUP_OTHER_AVATAR: + return "otherAvatar"; + }; + return ""; +} + +uint16_t getCollisionGroupAsBitMask(const QStringRef& name) { + if (0 == name.compare(QString("dynamic"))) { + return USER_COLLISION_GROUP_DYNAMIC; + } else if (0 == name.compare(QString("static"))) { + return USER_COLLISION_GROUP_STATIC; + } else if (0 == name.compare(QString("kinematic"))) { + return USER_COLLISION_GROUP_KINEMATIC; + } else if (0 == name.compare(QString("myAvatar"))) { + return USER_COLLISION_GROUP_MY_AVATAR; + } else if (0 == name.compare(QString("otherAvatar"))) { + return USER_COLLISION_GROUP_OTHER_AVATAR; + } + return 0; +} + +QString EntityItemProperties::getCollisionMaskAsString() const { + QString maskString(""); + for (int i = 0; i < NUM_USER_COLLISION_GROUPS; ++i) { + uint16_t group = 0x0001 << i; + if (group & _collisionMask) { + maskString.append(getCollisionGroupAsString(group)); + maskString.append(','); + } + } + return maskString; +} + +void EntityItemProperties::setCollisionMaskFromString(const QString& maskString) { + QVector groups = maskString.splitRef(','); + uint16_t mask = 0x0000; + for (auto groupName : groups) { + mask |= getCollisionGroupAsBitMask(groupName); + } + _collisionMask = mask; + _collisionMaskChanged = true; +} + +QString EntityItemProperties::getEntityHostTypeAsString() const { + switch (_entityHostType) { + case entity::HostType::DOMAIN: + return "domain"; + case entity::HostType::AVATAR: + return "avatar"; + case entity::HostType::LOCAL: + return "local"; + default: + return ""; + } +} + +void EntityItemProperties::setEntityHostTypeFromString(const QString& entityHostType) { + if (entityHostType == "domain") { + _entityHostType = entity::HostType::DOMAIN; + } else if (entityHostType == "avatar") { + _entityHostType = entity::HostType::AVATAR; + } else if (entityHostType == "local") { + _entityHostType = entity::HostType::LOCAL; + } +} + +inline void addMirrorMode(QHash& lookup, MirrorMode mirrorMode) { lookup[MirrorModeHelpers::getNameForMirrorMode(mirrorMode)] = mirrorMode; } +const QHash stringToMirrorModeLookup = [] { + QHash toReturn; + addMirrorMode(toReturn, MirrorMode::NONE); + addMirrorMode(toReturn, MirrorMode::MIRROR); + addMirrorMode(toReturn, MirrorMode::PORTAL); + return toReturn; +}(); +QString EntityItemProperties::getMirrorModeAsString() const { return MirrorModeHelpers::getNameForMirrorMode(_mirrorMode); } +void EntityItemProperties::setMirrorModeFromString(const QString& mirrorMode) { + auto mirrorModeItr = stringToMirrorModeLookup.find(mirrorMode.toLower()); + if (mirrorModeItr != stringToMirrorModeLookup.end()) { + _mirrorMode = mirrorModeItr.value(); + _mirrorModeChanged = true; + } +} + +QVector EntityItemProperties::getTagsAsVector() const { + QVector tags; + for (const QString& tag : _tags) { + tags.push_back(tag); + } + return tags; +} + +void EntityItemProperties::setTagsFromVector(const QVector& tags) { + _tags.clear(); + for (const QString& tag : tags) { + _tags.insert(tag); + } +} + +EntityPropertyFlags EntityItemProperties::getChangedProperties() const { + EntityPropertyFlags changedProperties; + +@ENTITY_ITEM_PROPERTY_CHANGED_PROPERTIES@ + + return changedProperties; +} + +ScriptValue EntityItemProperties::copyToScriptValue(ScriptEngine* engine, bool skipDefaults, bool allowUnknownCreateTime, + bool strictSemantics, + EntityPseudoPropertyFlags pseudoPropertyFlags) const { + + // If strictSemantics is true and skipDefaults is false, then all and only those properties are copied for which the property flag + // is included in _desiredProperties, or is one of the specially enumerated ALWAYS properties below. + // (There may be exceptions, but if so, they are bugs.) + // In all other cases, you are welcome to inspect the code and try to figure out what was intended. I wish you luck. -HRS 1/18/17 + ScriptValue properties = engine->newObject(); + EntityItemProperties defaultEntityProperties; + + const bool pseudoPropertyFlagsActive = pseudoPropertyFlags.test(EntityPseudoPropertyFlag::FlagsActive); + // Fix to skip the default return all mechanism, when pseudoPropertyFlagsActive + const bool returnNothingOnEmptyPropertyFlags = pseudoPropertyFlagsActive; + + if (_created == UNKNOWN_CREATED_TIME && !allowUnknownCreateTime) { + // No entity properties can have been set so return without setting any default, zero property values. + return properties; + } + + auto nodeList = DependencyManager::get(); + bool isMyOwnAvatarEntity = _entityHostType == entity::HostType::AVATAR && (_owningAvatarID == AVATAR_SELF_ID || _owningAvatarID == Physics::getSessionUUID()); + if (_idSet && (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::ID))) { + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(id, _id.toString()); + } + if (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::Type)) { + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(type, EntityTypes::getEntityTypeName(_type)); + } + if ((!skipDefaults || _lifetime != defaultEntityProperties._lifetime) && !strictSemantics) { + if (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::Age)) { + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(age, getAge()); // gettable, but not settable + } + if (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::AgeAsText)) { + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(ageAsText, formatSecondsElapsed(getAge())); // gettable, but not settable + } + } + if (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::LastEdited)) { + properties.setProperty("lastEdited", convertScriptValue(engine, _lastEdited)); + } + if (!skipDefaults) { + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DIMENSIONS, naturalDimensions); // gettable, but not settable + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_POSITION, naturalPosition); + } + + // FIXME: Shouldn't provide a shapeType property for Box and Sphere entities. +@ENTITY_ITEM_PROPERTY_COPY_TO_SCRIPT@ + + if (_type == EntityTypes::Image) { + // Handle conversions to old 'textures' property from "imageURL" + if ((isMyOwnAvatarEntity || nodeList->getThisNodeCanViewAssetURLs()) && + ((!returnNothingOnEmptyPropertyFlags && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(PROP_IMAGE_URL)) && + (!skipDefaults || defaultEntityProperties._imageURL != _imageURL)) { + ScriptValue textures = engine->newObject(); + textures.setProperty("tex.picture", _imageURL); + properties.setProperty("textures", textures); + } + } + + /*@jsdoc + * The axis-aligned bounding box of an entity. + * @typedef {object} Entities.BoundingBox + * @property {Vec3} brn - The bottom right near (minimum axes values) corner of the AA box. + * @property {Vec3} tfl - The top far left (maximum axes values) corner of the AA box. + * @property {Vec3} center - The center of the AA box. + * @property {Vec3} dimensions - The dimensions of the AA box. + */ + if (!skipDefaults && !strictSemantics && + (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::BoundingBox))) { + + AABox aaBox = getAABox(); + ScriptValue boundingBox = engine->newObject(); + ScriptValue bottomRightNear = vec3ToScriptValue(engine, aaBox.getCorner()); + ScriptValue topFarLeft = vec3ToScriptValue(engine, aaBox.calcTopFarLeft()); + ScriptValue center = vec3ToScriptValue(engine, aaBox.calcCenter()); + ScriptValue boundingBoxDimensions = vec3ToScriptValue(engine, aaBox.getDimensions()); + boundingBox.setProperty("brn", bottomRightNear); + boundingBox.setProperty("tfl", topFarLeft); + boundingBox.setProperty("center", center); + boundingBox.setProperty("dimensions", boundingBoxDimensions); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(boundingBox, boundingBox); // gettable, but not settable + } + + QString textureNamesStr = QJsonDocument::fromVariant(_textureNames).toJson(); + if (!skipDefaults && !strictSemantics && (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::OriginalTextures))) { + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(originalTextures, textureNamesStr); // gettable, but not settable + } + + // Rendering info + if (!skipDefaults && !strictSemantics && + (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::RenderInfo))) { + + ScriptValue renderInfo = engine->newObject(); + + /*@jsdoc + * Information on how an entity is rendered. Properties are only filled in for Model entities; other + * entity types have an empty object, {}. + * @typedef {object} Entities.RenderInfo + * @property {number} verticesCount - The number of vertices in the entity. + * @property {number} texturesCount - The number of textures in the entity. + * @property {number} texturesSize - The total size of the textures in the entity, in bytes. + * @property {boolean} hasTransparent - true if any of the textures has transparency, false + * if none of them do. + * @property {number} drawCalls - The number of draw calls required to render the entity. + */ + // currently only supported by models + if (_type == EntityTypes::Model) { + renderInfo.setProperty("verticesCount", (int)getRenderInfoVertexCount()); // FIXME - theoretically the number of vertex could be > max int + renderInfo.setProperty("texturesSize", (int)getRenderInfoTextureSize()); // FIXME - theoretically the size of textures could be > max int + renderInfo.setProperty("hasTransparent", getRenderInfoHasTransparent()); + renderInfo.setProperty("drawCalls", getRenderInfoDrawCalls()); + renderInfo.setProperty("texturesCount", getRenderInfoTextureCount()); + } + + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(renderInfo, renderInfo); // Gettable but not settable + } + + if (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::ClientOnly)) { + properties.setProperty("clientOnly", convertScriptValue(engine, getEntityHostType() == entity::HostType::AVATAR)); + } + if (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::AvatarEntity)) { + properties.setProperty("avatarEntity", convertScriptValue(engine, getEntityHostType() == entity::HostType::AVATAR)); + } + if (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::LocalEntity)) { + properties.setProperty("localEntity", convertScriptValue(engine, getEntityHostType() == entity::HostType::LOCAL)); + } + + if (_type != EntityTypes::PolyLine && (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::FaceCamera))) { + properties.setProperty("faceCamera", convertScriptValue(engine, getBillboardMode() == BillboardMode::YAW)); + } + if (!pseudoPropertyFlagsActive || pseudoPropertyFlags.test(EntityPseudoPropertyFlag::IsFacingAvatar)) { + properties.setProperty("isFacingAvatar", convertScriptValue(engine, getBillboardMode() == BillboardMode::FULL)); + } + + return properties; +} + +void EntityItemProperties::copyFromScriptValue(const ScriptValue& object, bool honorReadOnly) { + //qDebug() << "EntityItemProperties::copyFromScriptValue: properties: " << object.getPropertyNames(); + QList namesList = object.getPropertyNames(); + + QSet namesSet; + for (auto name = namesList.cbegin(); name != namesList.cend(); name++) { + namesSet.insert(*name); + } + + ScriptValue typeScriptValue = object.property("type"); + if (typeScriptValue.isValid()) { + setType(typeScriptValue.toVariant().toString()); + } + + // TODO: should scripts be able to set queryAACube? +@ENTITY_ITEM_PROPERTY_COPY_FROM_SCRIPT@ + + // Handle conversions from old 'textures' property to "imageURL" + if (namesSet.contains("textures")) { + ScriptValue V = object.property("textures"); + if (_type == EntityTypes::Image && V.isValid() && !object.property("imageURL").isValid()) { + bool isValid = false; + QString textures = QString_convertFromScriptValue(V, isValid); + if (isValid) { + QVariantMap texturesMap = parseTexturesToMap(textures, QVariantMap()); + auto texPicture = texturesMap.find("tex.picture"); + if (texPicture != texturesMap.end()) { + auto imageURL = texPicture.value().toString(); + if (_defaultSettings || imageURL != _imageURL) { + setImageURL(imageURL); + } + } + } + } + } + + // Handle old "faceCamera" and "isFacingAvatar" props + if (_type != EntityTypes::PolyLine && namesSet.contains("faceCamera")) { + ScriptValue P = object.property("faceCamera"); + if (P.isValid() && !object.property("billboardMode").isValid()) { + bool newValue = P.toVariant().toBool(); + bool oldValue = getBillboardMode() == BillboardMode::YAW; + if (_defaultSettings || newValue != oldValue) { + setBillboardMode(newValue ? BillboardMode::YAW : BillboardMode::NONE); + } + } + } + if (namesSet.contains("isFacingAvatar")) { + ScriptValue P = object.property("isFacingAvatar"); + if (P.isValid() && !object.property("billboardMode").isValid() && !object.property("faceCamera").isValid()) { + bool newValue = P.toVariant().toBool(); + bool oldValue = getBillboardMode() == BillboardMode::FULL; + if (_defaultSettings || newValue != oldValue) { + setBillboardMode(newValue ? BillboardMode::FULL : BillboardMode::NONE); + } + } + } + + _lastEdited = usecTimestampNow(); +} + +void EntityItemProperties::copyFromJSONString(ScriptEngine& scriptEngine, const QString& jsonString) { + // DANGER: this method is expensive + QJsonDocument propertiesDoc = QJsonDocument::fromJson(jsonString.toUtf8()); + QJsonObject propertiesObj = propertiesDoc.object(); + QVariant propertiesVariant(propertiesObj); + QVariantMap propertiesMap = propertiesVariant.toMap(); + ScriptValue propertiesScriptValue = variantMapToScriptValue(propertiesMap, scriptEngine); + bool honorReadOnly = true; + copyFromScriptValue(propertiesScriptValue, honorReadOnly); +} + + +void EntityItemProperties::merge(const EntityItemProperties& other) { +@ENTITY_ITEM_PROPERTY_MERGE@ + + _lastEdited = usecTimestampNow(); +} + +ScriptValue EntityItemPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties) { + return properties.copyToScriptValue(engine, false); +} + +ScriptValue EntityItemNonDefaultPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties) { + return properties.copyToScriptValue(engine, true); +} + +bool EntityItemPropertiesFromScriptValueIgnoreReadOnly(const ScriptValue &object, EntityItemProperties& properties) { + properties.copyFromScriptValue(object, false); + return true; +} + +bool EntityItemPropertiesFromScriptValueHonorReadOnly(const ScriptValue &object, EntityItemProperties& properties) { + properties.copyFromScriptValue(object, true); + return true; +} + +ScriptValue EntityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags) { + return EntityItemProperties::entityPropertyFlagsToScriptValue(engine, flags); +} + +bool EntityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags) { + return EntityItemProperties::entityPropertyFlagsFromScriptValue(object, flags); +} + + +ScriptValue EntityItemProperties::entityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags) { + ScriptValue result = engine->newObject(); + return result; +} + +bool EntityItemProperties::entityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags) { + if (object.isString()) { + EntityPropertyInfo propertyInfo; + if (getPropertyInfo(object.toString(), propertyInfo)) { + flags << propertyInfo.propertyEnums; + } + } + else if (object.isArray()) { + quint32 length = object.property("length").toInt32(); + for (quint32 i = 0; i < length; i++) { + QString propertyName = object.property(i).toString(); + EntityPropertyInfo propertyInfo; + if (getPropertyInfo(propertyName, propertyInfo)) { + flags << propertyInfo.propertyEnums; + } + } + } + return true; +} + +static QHash _propertyInfos; +static QHash _enumsToPropertyStrings; + +bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPropertyInfo& propertyInfo) { + + static std::once_flag initMap; + // V8TODO: Probably needs mutex before call_once + std::call_once(initMap, []() { +@ENTITY_ITEM_PROPERTY_ADD_TO_MAP@ + }); + + auto iter = _propertyInfos.find(propertyName); + if (iter != _propertyInfos.end()) { + propertyInfo = *iter; + return true; + } + + return false; +} + +/*@jsdoc + * Information about an entity property. + * @typedef {object} Entities.EntityPropertyInfo + * @property {number} propertyEnum - The internal number of the property. + * @property {string} minimum - The minimum numerical value the property may have, if available, otherwise "". + * @property {string} maximum - The maximum numerical value the property may have, if available, otherwise "". + */ +ScriptValue EntityPropertyInfoToScriptValue(ScriptEngine* engine, const EntityPropertyInfo& propertyInfo) { + ScriptValue obj = engine->newObject(); + obj.setProperty("propertyEnum", propertyInfo.propertyEnums.firstFlag()); + obj.setProperty("minimum", propertyInfo.minimum.toString()); + obj.setProperty("maximum", propertyInfo.maximum.toString()); + return obj; +} + +bool EntityPropertyInfoFromScriptValue(const ScriptValue& object, EntityPropertyInfo& propertyInfo) { + propertyInfo.propertyEnums = (EntityPropertyList)object.property("propertyEnum").toVariant().toUInt(); + propertyInfo.minimum = object.property("minimum").toVariant(); + propertyInfo.maximum = object.property("maximum").toVariant(); + return true; +} + +// TODO: Implement support for edit packets that can span an MTU sized buffer. We need to implement a mechanism for the +// encodeEntityEditPacket() method to communicate the the caller which properties couldn't fit in the buffer. Similar +// to how we handle this in the Octree streaming case. +// +// TODO: Right now, all possible properties for all subclasses are handled here. Ideally we'd prefer +// to handle this in a more generic way. Allowing subclasses of EntityItem to register their properties +// +// TODO: There's a lot of repeated patterns in the code below to handle each property. It would be nice if the property +// registration mechanism allowed us to collapse these repeated sections of code into a single implementation that +// utilized the registration table to shorten up and simplify this code. +// +// TODO: Implement support for paged properties, spanning MTU, and custom properties +// +// TODO: Implement support for script and visible properties. +// +OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties, + QByteArray& buffer, EntityPropertyFlags requestedProperties, EntityPropertyFlags& didntFitProperties) { + + OctreePacketData ourDataPacket(false, buffer.size()); // create a packetData object to add out packet details too. + OctreePacketData* packetData = &ourDataPacket; // we want a pointer to this so we can use our APPEND_ENTITY_PROPERTY macro + + bool success = true; // assume the best + OctreeElement::AppendState appendState = OctreeElement::COMPLETED; // assume the best + + // TODO: We need to review how jurisdictions should be handled for entities. (The old Models and Particles code + // didn't do anything special for jurisdictions, so we're keeping that same behavior here.) + // + // Always include the root octcode. This is only because the OctreeEditPacketSender will check these octcodes + // to determine which server to send the changes to in the case of multiple jurisdictions. The root will be sent + // to all servers. + vec3 rootPosition(0); + float rootScale = 0.5f; + unsigned char* octcode = pointToOctalCode(rootPosition.x, rootPosition.y, rootPosition.z, rootScale); + + success = packetData->startSubTree(octcode); + delete[] octcode; + + // assuming we have room to fit our octalCode, proceed... + if (success) { + + // Now add our edit content details... + + // id + // encode our ID as a byte count coded byte stream + QByteArray encodedID = id.toRfc4122(); // NUM_BYTES_RFC4122_UUID + + // encode our ID as a byte count coded byte stream + ByteCountCoded tokenCoder; + QByteArray encodedToken; + + // encode our type as a byte count coded byte stream + ByteCountCoded typeCoder = (quint32)properties.getType(); + QByteArray encodedType = typeCoder; + + quint64 updateDelta = 0; // this is an edit so by definition, it's update is in sync + ByteCountCoded updateDeltaCoder = updateDelta; + QByteArray encodedUpdateDelta = updateDeltaCoder; + + EntityPropertyFlags propertyFlags(PROP_LAST_ITEM); + EntityPropertyFlags propertiesDidntFit = requestedProperties; + + LevelDetails entityLevel = packetData->startLevel(); + + // Last Edited quint64 always first, before any other details, which allows us easy access to adjusting this + // timestamp for clock skew + quint64 lastEdited = properties.getLastEdited(); + bool successLastEditedFits = packetData->appendValue(lastEdited); + + bool successIDFits = packetData->appendRawData(encodedID); + if (successIDFits) { + successIDFits = packetData->appendRawData(encodedToken); + } + bool successTypeFits = packetData->appendRawData(encodedType); + + // NOTE: We intentionally do not send "created" times in edit messages. This is because: + // 1) if the edit is to an existing entity, the created time can not be changed + // 2) if the edit is to a new entity, the created time is the last edited time + + // TODO: Should we get rid of this in this in edit packets, since this has to always be 0? + bool successLastUpdatedFits = packetData->appendRawData(encodedUpdateDelta); + + int propertyFlagsOffset = packetData->getUncompressedByteOffset(); + QByteArray encodedPropertyFlags = propertyFlags; + int oldPropertyFlagsLength = encodedPropertyFlags.length(); + bool successPropertyFlagsFits = packetData->appendRawData(encodedPropertyFlags); + int propertyCount = 0; + + bool headerFits = successIDFits && successTypeFits && successLastEditedFits && + successLastUpdatedFits && successPropertyFlagsFits; + + int startOfEntityItemData = packetData->getUncompressedByteOffset(); + + if (headerFits) { + bool successPropertyFits; + propertyFlags -= PROP_LAST_ITEM; // clear the last item for now, we may or may not set it as the actual item + + // These items would go here once supported.... + // PROP_PAGED_PROPERTY, + // PROP_CUSTOM_PROPERTIES_INCLUDED, + +@ENTITY_ITEM_PROPERTY_APPEND@ + + } + + if (propertyCount > 0) { + int endOfEntityItemData = packetData->getUncompressedByteOffset(); + + encodedPropertyFlags = propertyFlags; + int newPropertyFlagsLength = encodedPropertyFlags.length(); + packetData->updatePriorBytes(propertyFlagsOffset, (const unsigned char*)encodedPropertyFlags.constData(), + encodedPropertyFlags.length()); + + // if the size of the PropertyFlags shrunk, we need to shift everything down to front of packet. + if (newPropertyFlagsLength < oldPropertyFlagsLength) { + int oldSize = packetData->getUncompressedSize(); + + const unsigned char* modelItemData = packetData->getUncompressedData(propertyFlagsOffset + oldPropertyFlagsLength); + int modelItemDataLength = endOfEntityItemData - startOfEntityItemData; + int newEntityItemDataStart = propertyFlagsOffset + newPropertyFlagsLength; + packetData->updatePriorBytes(newEntityItemDataStart, modelItemData, modelItemDataLength); + + int newSize = oldSize - (oldPropertyFlagsLength - newPropertyFlagsLength); + packetData->setUncompressedSize(newSize); + + } else { + assert(newPropertyFlagsLength == oldPropertyFlagsLength); // should not have grown + } + + packetData->endLevel(entityLevel); + } else { + packetData->discardLevel(entityLevel); + appendState = OctreeElement::NONE; // if we got here, then we didn't include the item + } + + // If any part of the model items didn't fit, then the element is considered partial + if (appendState != OctreeElement::COMPLETED) { + didntFitProperties = propertiesDidntFit; + } + + packetData->endSubTree(); + + const char* finalizedData = reinterpret_cast(packetData->getFinalizedData()); + int finalizedSize = packetData->getFinalizedSize(); + + if (finalizedSize <= buffer.size()) { + buffer.replace(0, finalizedSize, finalizedData, finalizedSize); + buffer.resize(finalizedSize); + } else { + qCDebug(entities) << "ERROR - encoded edit message doesn't fit in output buffer."; + appendState = OctreeElement::NONE; // if we got here, then we didn't include the item + // maybe we should assert!!! + } + } else { + packetData->discardSubTree(); + } + + return appendState; +} + +QByteArray EntityItemProperties::getPackedNormals() const { + return packNormals(getNormals()); +} + +QByteArray EntityItemProperties::packNormals(const QVector& normals) const { + int normalsSize = normals.size(); + QByteArray packedNormals = QByteArray(normalsSize * 6 + 1, '0'); + // add size of the array + packedNormals[0] = ((uint8_t)normalsSize); + + int index = 1; + for (int i = 0; i < normalsSize; i++) { + int numBytes = packFloatVec3ToSignedTwoByteFixed((unsigned char*)packedNormals.data() + index, normals[i], 15); + index += numBytes; + } + return packedNormals; +} + +QByteArray EntityItemProperties::getPackedStrokeColors() const { + return packStrokeColors(getStrokeColors()); +} +QByteArray EntityItemProperties::packStrokeColors(const QVector& strokeColors) const { + int strokeColorsSize = strokeColors.size(); + QByteArray packedStrokeColors = QByteArray(strokeColorsSize * 3 + 1, '0'); + + // add size of the array + packedStrokeColors[0] = ((uint8_t)strokeColorsSize); + + + for (int i = 0; i < strokeColorsSize; i++) { + // add the color to the QByteArray + packedStrokeColors[i * 3 + 1] = strokeColors[i].x * 255; + packedStrokeColors[i * 3 + 2] = strokeColors[i].y * 255; + packedStrokeColors[i * 3 + 3] = strokeColors[i].z * 255; + } + return packedStrokeColors; +} + +// TODO: +// how to handle lastEdited? +// how to handle lastUpdated? +// consider handling case where no properties are included... we should just ignore this packet... +// +// TODO: Right now, all possible properties for all subclasses are handled here. Ideally we'd prefer +// to handle this in a more generic way. Allowing subclasses of EntityItem to register their properties +// +// TODO: There's a lot of repeated patterns in the code below to handle each property. It would be nice if the property +// registration mechanism allowed us to collapse these repeated sections of code into a single implementation that +// utilized the registration table to shorten up and simplify this code. +// +// TODO: Implement support for paged properties, spanning MTU, and custom properties +// +// TODO: Implement support for script and visible properties. +// +bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes, + EntityItemID& entityID, EntityItemProperties& properties) { + bool valid = false; + + const unsigned char* dataAt = data; + processedBytes = 0; + + // the first part of the data is an octcode, this is a required element of the edit packet format, but we don't + // actually use it, we do need to skip it and read to the actual data we care about. + int octets = numberOfThreeBitSectionsInCode(data); + int bytesToReadOfOctcode = (int)bytesRequiredForCodeLength(octets); + + // we don't actually do anything with this octcode... + dataAt += bytesToReadOfOctcode; + processedBytes += bytesToReadOfOctcode; + + // Edit packets have a last edited time stamp immediately following the octcode. + // NOTE: the edit times have been set by the editor to match out clock, so we don't need to adjust + // these times for clock skew at this point. + quint64 lastEdited; + memcpy(&lastEdited, dataAt, sizeof(lastEdited)); + dataAt += sizeof(lastEdited); + processedBytes += sizeof(lastEdited); + properties.setLastEdited(lastEdited); + + // encoded id + QUuid editID = QUuid::fromRfc4122(QByteArray::fromRawData(reinterpret_cast(dataAt), NUM_BYTES_RFC4122_UUID)); + dataAt += NUM_BYTES_RFC4122_UUID; + processedBytes += NUM_BYTES_RFC4122_UUID; + + entityID = editID; + valid = true; + + // Entity Type... + QByteArray encodedType((const char*)dataAt, (bytesToRead - processedBytes)); + ByteCountCoded typeCoder = encodedType; + quint32 entityTypeCode = typeCoder; + properties.setType((EntityTypes::EntityType)entityTypeCode); + encodedType = typeCoder; // determine true bytesToRead + dataAt += encodedType.size(); + processedBytes += encodedType.size(); + + // Update Delta - when was this item updated relative to last edit... this really should be 0 + // TODO: Should we get rid of this in this in edit packets, since this has to always be 0? + // TODO: do properties need to handle lastupdated??? + + // last updated is stored as ByteCountCoded delta from lastEdited + QByteArray encodedUpdateDelta((const char*)dataAt, (bytesToRead - processedBytes)); + ByteCountCoded updateDeltaCoder = encodedUpdateDelta; + encodedUpdateDelta = updateDeltaCoder; // determine true bytesToRead + dataAt += encodedUpdateDelta.size(); + processedBytes += encodedUpdateDelta.size(); + + // TODO: Do we need this lastUpdated?? We don't seem to use it. + //quint64 updateDelta = updateDeltaCoder; + //quint64 lastUpdated = lastEdited + updateDelta; // don't adjust for clock skew since we already did that for lastEdited + + // Property Flags... + QByteArray encodedPropertyFlags((const char*)dataAt, (bytesToRead - processedBytes)); + EntityPropertyFlags propertyFlags = encodedPropertyFlags; + dataAt += propertyFlags.getEncodedLength(); + processedBytes += propertyFlags.getEncodedLength(); + +@ENTITY_ITEM_PROPERTY_READ@ + + return valid; +} + +void EntityItemProperties::setPackedNormals(const QByteArray& value) { + setNormals(unpackNormals(value)); +} + +QVector EntityItemProperties::unpackNormals(const QByteArray& normals) { + // the size of the vector is packed first + QVector unpackedNormals = QVector((int)normals[0]); + + if ((int)normals[0] == normals.size() / 6) { + int j = 0; + for (int i = 1; i < normals.size();) { + vec3 aux = vec3(); + i += unpackFloatVec3FromSignedTwoByteFixed((unsigned char*)normals.data() + i, aux, 15); + unpackedNormals[j] = aux; + j++; + } + } else { + qCDebug(entities) << "WARNING - Expected received size for normals does not match. Expected: " << (int)normals[0] + << " Received: " << (normals.size() / 6); + } + return unpackedNormals; +} + +void EntityItemProperties::setPackedStrokeColors(const QByteArray& value) { + setStrokeColors(unpackStrokeColors(value)); +} + +QVector EntityItemProperties::unpackStrokeColors(const QByteArray& strokeColors) { + // the size of the vector is packed first + QVector unpackedStrokeColors = QVector((int)strokeColors[0]); + + if ((int)strokeColors[0] == strokeColors.size() / 3) { + int j = 0; + for (int i = 1; i < strokeColors.size();) { + + float r = (uint8_t)strokeColors[i++] / 255.0f; + float g = (uint8_t)strokeColors[i++] / 255.0f; + float b = (uint8_t)strokeColors[i++] / 255.0f; + unpackedStrokeColors[j++] = vec3(r, g, b); + } + } else { + qCDebug(entities) << "WARNING - Expected received size for stroke colors does not match. Expected: " + << (int)strokeColors[0] << " Received: " << (strokeColors.size() / 3); + } + + return unpackedStrokeColors; +} + +// NOTE: This version will only encode the portion of the edit message immediately following the +// header it does not include the send times and sequence number because that is handled by the +// edit packet sender... +bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityItemID, QByteArray& buffer) { + + uint16_t numberOfIds = 1; // only one entity ID in this message + + if (buffer.size() < (int)(sizeof(numberOfIds) + NUM_BYTES_RFC4122_UUID)) { + qCDebug(entities) << "ERROR - encodeEraseEntityMessage() called with buffer that is too small!"; + return false; + } + + buffer.resize(0); + buffer.append(reinterpret_cast(&numberOfIds), sizeof(numberOfIds)); + buffer.append(entityItemID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID); + + return true; +} + +bool EntityItemProperties::encodeCloneEntityMessage(const EntityItemID& entityIDToClone, const EntityItemID& newEntityID, QByteArray& buffer) { + if (buffer.size() < (int)(NUM_BYTES_RFC4122_UUID * 2)) { + qCDebug(entities) << "ERROR - encodeCloneEntityMessage() called with buffer that is too small!"; + return false; + } + + buffer.resize(0); + buffer.append(entityIDToClone.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID); + buffer.append(newEntityID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID); + + return true; +} + +bool EntityItemProperties::decodeCloneEntityMessage(const QByteArray& buffer, int& processedBytes, EntityItemID& entityIDToClone, EntityItemID& newEntityID) { + const unsigned char* packetData = (const unsigned char*)buffer.constData(); + const unsigned char* dataAt = packetData; + size_t packetLength = buffer.size(); + processedBytes = 0; + + if (NUM_BYTES_RFC4122_UUID * 2 > packetLength) { + qCDebug(entities) << "EntityItemProperties::decodeCloneEntityMessage().... bailing because not enough bytes in buffer"; + return false; // bail to prevent buffer overflow + } + + QByteArray encodedID = buffer.mid((int)processedBytes, NUM_BYTES_RFC4122_UUID); + entityIDToClone = QUuid::fromRfc4122(encodedID); + dataAt += encodedID.size(); + processedBytes += encodedID.size(); + + encodedID = buffer.mid((int)processedBytes, NUM_BYTES_RFC4122_UUID); + newEntityID = QUuid::fromRfc4122(encodedID); + dataAt += encodedID.size(); + processedBytes += encodedID.size(); + + return true; +} + +void EntityItemProperties::markAllChanged() { +@ENTITY_ITEM_PROPERTY_MARK_CHANGED@ +} + +// The minimum bounding box for the entity. +AABox EntityItemProperties::getAABox() const { + + // _position represents the position of the registration point. + vec3 registrationRemainder = vec3(1.0f) - _registrationPoint; + + vec3 unrotatedMinRelativeToEntity = -(_dimensions * _registrationPoint); + vec3 unrotatedMaxRelativeToEntity = _dimensions * registrationRemainder; + Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; + Extents rotatedExtentsRelativeToRegistrationPoint = unrotatedExtentsRelativeToRegistrationPoint.getRotated(_rotation); + + // shift the extents to be relative to the position/registration point + rotatedExtentsRelativeToRegistrationPoint.shiftBy(_position); + + return AABox(rotatedExtentsRelativeToRegistrationPoint); +} + +bool EntityItemProperties::hasTransformOrVelocityChanges() const { + return _positionChanged || _localPositionChanged + || _rotationChanged || _localRotationChanged + || _velocityChanged || _localVelocityChanged + || _angularVelocityChanged || _localAngularVelocityChanged + || _accelerationChanged; +} + +void EntityItemProperties::clearTransformOrVelocityChanges() { + _positionChanged = false; + _localPositionChanged = false; + _rotationChanged = false; + _localRotationChanged = false; + _velocityChanged = false; + _localVelocityChanged = false; + _angularVelocityChanged = false; + _localAngularVelocityChanged = false; + _accelerationChanged = false; +} + +bool EntityItemProperties::hasMiscPhysicsChanges() const { + return _gravityChanged || _dimensionsChanged || _densityChanged || _frictionChanged + || _restitutionChanged || _dampingChanged || _angularDampingChanged || _registrationPointChanged || + _compoundShapeURLChanged || _dynamicChanged || _collisionlessChanged || _collisionMaskChanged; +} + +bool EntityItemProperties::hasSimulationRestrictedChanges() const { + return _positionChanged || _localPositionChanged + || _rotationChanged || _localRotationChanged + || _velocityChanged || _localVelocityChanged + || _localDimensionsChanged || _dimensionsChanged + || _angularVelocityChanged || _localAngularVelocityChanged + || _accelerationChanged + || _parentIDChanged || _parentJointIndexChanged; +} + +void EntityItemProperties::copySimulationRestrictedProperties(const EntityItemPointer& entity) { + if (!_parentIDChanged) { + setParentID(entity->getParentID()); + } + if (!_parentJointIndexChanged) { + setParentJointIndex(entity->getParentJointIndex()); + } + if (!_localPositionChanged && !_positionChanged) { + setPosition(entity->getWorldPosition()); + } + if (!_localRotationChanged && !_rotationChanged) { + setRotation(entity->getWorldOrientation()); + } + if (!_localVelocityChanged && !_velocityChanged) { + setVelocity(entity->getWorldVelocity()); + } + if (!_localAngularVelocityChanged && !_angularVelocityChanged) { + setAngularVelocity(entity->getWorldAngularVelocity()); + } + if (!_accelerationChanged) { + setAcceleration(entity->getAcceleration()); + } + if (!_localDimensionsChanged && !_dimensionsChanged) { + setLocalDimensions(entity->getScaledDimensions()); + } +} + +void EntityItemProperties::clearSimulationRestrictedProperties() { + _positionChanged = false; + _localPositionChanged = false; + _rotationChanged = false; + _localRotationChanged = false; + _velocityChanged = false; + _localVelocityChanged = false; + _angularVelocityChanged = false; + _localAngularVelocityChanged = false; + _accelerationChanged = false; + _parentIDChanged = false; + _parentJointIndexChanged = false; +} + +void EntityItemProperties::clearSimulationOwner() { + _simulationOwner.clear(); + _simulationOwnerChanged = true; +} + +void EntityItemProperties::setSimulationOwner(const QUuid& id, uint8_t priority) { + if (!_simulationOwner.matchesValidID(id) || _simulationOwner.getPriority() != priority) { + _simulationOwner.set(id, priority); + _simulationOwnerChanged = true; + } +} + +void EntityItemProperties::setSimulationOwner(const QByteArray& data) { + if (_simulationOwner.fromByteArray(data)) { + _simulationOwnerChanged = true; + } +} + +uint8_t EntityItemProperties::computeSimulationBidPriority() const { + uint8_t priority = 0; + if (_parentIDChanged || _parentJointIndexChanged) { + // we need higher simulation ownership priority to chang parenting info + priority = SCRIPT_GRAB_SIMULATION_PRIORITY; + } else if (_positionChanged || _localPositionChanged + || _rotationChanged || _localRotationChanged + || _velocityChanged || _localVelocityChanged + || _angularVelocityChanged || _localAngularVelocityChanged) { + priority = SCRIPT_POKE_SIMULATION_PRIORITY; + } + return priority; +} + +QList EntityItemProperties::listChangedProperties() { + QList out; + +@ENTITY_ITEM_PROPERTY_LIST_CHANGED@ + + return out; +} + +bool EntityItemProperties::transformChanged() const { + return positionChanged() || rotationChanged() || + localPositionChanged() || localRotationChanged(); +} + +bool EntityItemProperties::getScalesWithParent() const { + // keep this logic the same as in EntityItem::getScalesWithParent + bool scalesWithParent { false }; + if (parentIDChanged()) { + bool success; + SpatiallyNestablePointer parent = SpatiallyNestable::findByID(getParentID(), success); + if (success && parent) { + bool avatarAncestor = (parent->getNestableType() == NestableType::Avatar || + parent->hasAncestorOfType(NestableType::Avatar)); + scalesWithParent = getEntityHostType() == entity::HostType::AVATAR && avatarAncestor; + } + } + return scalesWithParent; +} + +bool EntityItemProperties::parentRelatedPropertyChanged() const { + return positionChanged() || rotationChanged() || + localPositionChanged() || localRotationChanged() || + localDimensionsChanged() || + parentIDChanged() || parentJointIndexChanged(); +} + +bool EntityItemProperties::queryAACubeRelatedPropertyChanged() const { + return parentRelatedPropertyChanged() || dimensionsChanged(); +} + +bool EntityItemProperties::grabbingRelatedPropertyChanged() const { + const GrabPropertyGroup& grabProperties = getGrab(); + return grabProperties.triggerableChanged() || grabProperties.grabbableChanged() || + grabProperties.grabFollowsControllerChanged() || grabProperties.grabKinematicChanged() || + grabProperties.equippableChanged() || grabProperties.equippableLeftPositionChanged() || + grabProperties.equippableRightPositionChanged() || grabProperties.equippableLeftRotationChanged() || + grabProperties.equippableRightRotationChanged() || grabProperties.equippableIndicatorURLChanged() || + grabProperties.equippableIndicatorScaleChanged() || grabProperties.equippableIndicatorOffsetChanged(); +} + +void EntityItemProperties::convertToCloneProperties(const EntityItemID& entityIDToClone) { + setName(getName() + "-clone-" + entityIDToClone.toString()); + setLocked(false); + setParentID(QUuid()); + setParentJointIndex(-1); + setLifetime(getCloneLifetime()); + setDynamic(getCloneDynamic()); + if (getEntityHostType() != entity::HostType::LOCAL) { + setEntityHostType(getCloneAvatarEntity() ? entity::HostType::AVATAR : entity::HostType::DOMAIN); + } else { + // Local Entities clone as local entities + setEntityHostType(entity::HostType::LOCAL); + setCollisionless(true); + } + uint64_t now = usecTimestampNow(); + setCreated(now); + setLastEdited(now); + setCloneable(ENTITY_ITEM_DEFAULT_CLONEABLE); + setCloneLifetime(ENTITY_ITEM_DEFAULT_CLONE_LIFETIME); + setCloneLimit(ENTITY_ITEM_DEFAULT_CLONE_LIMIT); + setCloneDynamic(ENTITY_ITEM_DEFAULT_CLONE_DYNAMIC); + setCloneAvatarEntity(ENTITY_ITEM_DEFAULT_CLONE_AVATAR_ENTITY); +} + +bool EntityItemProperties::blobToProperties(ScriptEngine& scriptEngine, const QByteArray& blob, EntityItemProperties& properties) { + // DANGER: this method is NOT efficient. + // begin recipe for converting unfortunately-formatted-binary-blob to EntityItemProperties + OVERTE_IGNORE_DEPRECATED_BEGIN + QJsonDocument jsonProperties = QJsonDocument::fromBinaryData(blob); + OVERTE_IGNORE_DEPRECATED_END + if (jsonProperties.isEmpty() || jsonProperties.isNull() || !jsonProperties.isObject() || jsonProperties.object().isEmpty()) { + qCDebug(entities) << "bad avatarEntityData json" << QString(blob.toHex()); + return false; + } + QVariant variant = jsonProperties.toVariant(); + QVariantMap variantMap = variant.toMap(); + ScriptValue scriptValue = variantMapToScriptValue(variantMap, scriptEngine); + EntityItemPropertiesFromScriptValueIgnoreReadOnly(scriptValue, properties); + // end recipe + return true; +} + +void EntityItemProperties::propertiesToBlob(ScriptEngine& scriptEngine, const QUuid& myAvatarID, + const EntityItemProperties& properties, QByteArray& blob, bool allProperties) { + // DANGER: this method is NOT efficient. + // begin recipe for extracting unfortunately-formatted-binary-blob from EntityItem + ScriptValue scriptValue = allProperties + ? EntityItemPropertiesToScriptValue(&scriptEngine, properties) + : EntityItemNonDefaultPropertiesToScriptValue(&scriptEngine, properties); + QVariant variantProperties = scriptValue.toVariant(); + QJsonDocument jsonProperties = QJsonDocument::fromVariant(variantProperties); + // the ID of the parent/avatar changes from session to session. use a special UUID to indicate the avatar + QJsonObject jsonObject = jsonProperties.object(); + if (jsonObject.contains("parentID")) { + if (QUuid(jsonObject["parentID"].toString()) == myAvatarID) { + jsonObject["parentID"] = AVATAR_SELF_ID.toString(); + } + } + jsonProperties = QJsonDocument(jsonObject); + OVERTE_IGNORE_DEPRECATED_BEGIN + blob = jsonProperties.toBinaryData(); + OVERTE_IGNORE_DEPRECATED_END + // end recipe +} + +QDebug& operator<<(QDebug& dbg, const EntityPropertyFlags& f) { + QString result = "[ "; + + for (int i = 0; i < PROP_AFTER_LAST_ITEM; i++) { + auto prop = EntityPropertyList(i); + if (f.getHasProperty(prop)) { + result = result + _enumsToPropertyStrings[prop] + " "; + } + } + + result += "]"; + dbg.nospace() << result; + return dbg; +} diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h deleted file mode 100644 index 4b6838fa1e5..00000000000 --- a/libraries/entities/src/EntityItemProperties.h +++ /dev/null @@ -1,699 +0,0 @@ -// -// EntityItemProperties.h -// libraries/entities/src -// -// Created by Brad Hefta-Gaub on 12/4/13. -// Copyright 2013 High Fidelity, Inc. -// Copyright 2020 Vircadia contributors. -// Copyright 2023 Overte e.V. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// SPDX-License-Identifier: Apache-2.0 -// - -#ifndef hifi_EntityItemProperties_h -#define hifi_EntityItemProperties_h - -#include - -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include "FontFamilies.h" -#include - -#include -#include "EntityItemPropertiesDefaults.h" -#include "EntityItemPropertiesMacros.h" -#include "EntityTypes.h" -#include "EntityPropertyFlags.h" -#include "EntityPseudoPropertyFlags.h" -#include "SimulationOwner.h" - -#include "TextEntityItem.h" -#include "WebEntityItem.h" -#include "ParticleEffectEntityItem.h" -#include "LineEntityItem.h" -#include "PolyVoxEntityItem.h" -#include "GridEntityItem.h" -#include "GizmoEntityItem.h" -#include "LightEntityItem.h" -#include "ZoneEntityItem.h" - -#include "AnimationPropertyGroup.h" -#include "SkyboxPropertyGroup.h" -#include "HazePropertyGroup.h" -#include "BloomPropertyGroup.h" -#include "PulsePropertyGroup.h" -#include "RingGizmoPropertyGroup.h" - -#include "MaterialMappingMode.h" -#include "BillboardMode.h" -#include "RenderLayer.h" -#include "PrimitiveMode.h" -#include "WebInputMode.h" -#include "GizmoType.h" -#include "TextEffect.h" -#include "TextAlignment.h" - -class ScriptEngine; - -const quint64 UNKNOWN_CREATED_TIME = 0; - -using vec3Color = glm::vec3; -using u8vec3Color = glm::u8vec3; - -struct EntityPropertyInfo { - EntityPropertyInfo(EntityPropertyList propEnum) : - propertyEnums(propEnum) {} - EntityPropertyInfo(EntityPropertyList propEnum, QVariant min, QVariant max) : - propertyEnums(propEnum), minimum(min), maximum(max) {} - EntityPropertyInfo() = default; - EntityPropertyFlags propertyEnums; - QVariant minimum; - QVariant maximum; -}; - -template -EntityPropertyInfo makePropertyInfo(EntityPropertyList p, typename std::enable_if::value>::type* = 0) { - return EntityPropertyInfo(p); -} - -template -EntityPropertyInfo makePropertyInfo(EntityPropertyList p, typename std::enable_if::value>::type* = 0) { - return EntityPropertyInfo(p, std::numeric_limits::min(), std::numeric_limits::max()); -} - -/// A collection of properties of an entity item used in the scripting API. Translates between the actual properties of an -/// entity and a JavaScript style hash/ScriptValue storing a set of properties. Used in scripting to set/get the complete -/// set of entity item properties via JavaScript hashes/QScriptValues -/// all units for SI units (meter, second, radian, etc) -class EntityItemProperties { - // TODO: consider removing these friend relationship and use public methods - friend class EntityItem; - friend class BoxEntityItem; - friend class SphereEntityItem; - friend class ShapeEntityItem; - friend class ModelEntityItem; - friend class TextEntityItem; - friend class ImageEntityItem; - friend class WebEntityItem; - friend class ParticleEffectEntityItem; - friend class LineEntityItem; - friend class PolyLineEntityItem; - friend class PolyVoxEntityItem; - friend class GridEntityItem; - friend class GizmoEntityItem; - friend class LightEntityItem; - friend class ZoneEntityItem; - friend class MaterialEntityItem; -public: - static bool blobToProperties(ScriptEngine& scriptEngine, const QByteArray& blob, EntityItemProperties& properties); - static void propertiesToBlob(ScriptEngine& scriptEngine, const QUuid& myAvatarID, const EntityItemProperties& properties, - QByteArray& blob, bool allProperties = false); - - EntityItemProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()); - EntityItemProperties(const EntityItemProperties&) = default; - - virtual ~EntityItemProperties() = default; - - void merge(const EntityItemProperties& other); - - EntityTypes::EntityType getType() const { return _type; } - void setType(EntityTypes::EntityType type) { _type = type; } - - virtual ScriptValue copyToScriptValue(ScriptEngine* engine, bool skipDefaults, bool allowUnknownCreateTime = false, - bool strictSemantics = false, EntityPseudoPropertyFlags pseudoPropertyFlags = EntityPseudoPropertyFlags()) const; - virtual void copyFromScriptValue(const ScriptValue& object, bool honorReadOnly); - void copyFromJSONString(ScriptEngine& scriptEngine, const QString& jsonString); - - static ScriptValue entityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags); - static bool entityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags); - - static bool getPropertyInfo(const QString& propertyName, EntityPropertyInfo& propertyInfo); - - // editing related features supported by all entities - quint64 getLastEdited() const { return _lastEdited; } - float getEditedAgo() const /// Elapsed seconds since this entity was last edited - { return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; } - - EntityPropertyFlags getChangedProperties() const; - - bool transformChanged() const; - bool getScalesWithParent() const; - bool parentRelatedPropertyChanged() const; - bool queryAACubeRelatedPropertyChanged() const; - bool grabbingRelatedPropertyChanged() const; - - AABox getAABox() const; - - void debugDump() const; - void setLastEdited(quint64 usecTime); - EntityPropertyFlags getDesiredProperties() { return _desiredProperties; } - void setDesiredProperties(EntityPropertyFlags properties) { _desiredProperties = properties; } - - bool constructFromBuffer(const unsigned char* data, int dataLength); - - // Note: DEFINE_PROPERTY(PROP_FOO, Foo, foo, type, value) creates the following methods and variables: - // type getFoo() const; - // void setFoo(type); - // bool fooChanged() const; - // type _foo { value }; - // bool _fooChanged { false }; - - // Core Properties - DEFINE_PROPERTY_REF(PROP_SIMULATION_OWNER, SimulationOwner, simulationOwner, SimulationOwner, SimulationOwner()); - DEFINE_PROPERTY_REF(PROP_PARENT_ID, ParentID, parentID, QUuid, UNKNOWN_ENTITY_ID); - DEFINE_PROPERTY_REF(PROP_PARENT_JOINT_INDEX, ParentJointIndex, parentJointIndex, quint16, -1); - DEFINE_PROPERTY(PROP_VISIBLE, Visible, visible, bool, ENTITY_ITEM_DEFAULT_VISIBLE); - DEFINE_PROPERTY_REF(PROP_NAME, Name, name, QString, ENTITY_ITEM_DEFAULT_NAME); - DEFINE_PROPERTY(PROP_LOCKED, Locked, locked, bool, ENTITY_ITEM_DEFAULT_LOCKED); - DEFINE_PROPERTY_REF(PROP_USER_DATA, UserData, userData, QString, ENTITY_ITEM_DEFAULT_USER_DATA); - DEFINE_PROPERTY_REF(PROP_PRIVATE_USER_DATA, PrivateUserData, privateUserData, QString, ENTITY_ITEM_DEFAULT_PRIVATE_USER_DATA); - DEFINE_PROPERTY_REF(PROP_HREF, Href, href, QString, ""); - DEFINE_PROPERTY_REF(PROP_DESCRIPTION, Description, description, QString, ""); - DEFINE_PROPERTY_REF_WITH_SETTER(PROP_POSITION, Position, position, glm::vec3, ENTITY_ITEM_ZERO_VEC3); - DEFINE_PROPERTY_REF(PROP_DIMENSIONS, Dimensions, dimensions, glm::vec3, ENTITY_ITEM_DEFAULT_DIMENSIONS); - DEFINE_PROPERTY_REF(PROP_ROTATION, Rotation, rotation, glm::quat, ENTITY_ITEM_DEFAULT_ROTATION); - DEFINE_PROPERTY_REF(PROP_REGISTRATION_POINT, RegistrationPoint, registrationPoint, glm::vec3, ENTITY_ITEM_DEFAULT_REGISTRATION_POINT); - DEFINE_PROPERTY(PROP_CREATED, Created, created, quint64, UNKNOWN_CREATED_TIME); - DEFINE_PROPERTY_REF(PROP_LAST_EDITED_BY, LastEditedBy, lastEditedBy, QUuid, ENTITY_ITEM_DEFAULT_LAST_EDITED_BY); - DEFINE_PROPERTY_REF_ENUM(PROP_ENTITY_HOST_TYPE, EntityHostType, entityHostType, entity::HostType, entity::HostType::DOMAIN); - DEFINE_PROPERTY_REF_WITH_SETTER(PROP_OWNING_AVATAR_ID, OwningAvatarID, owningAvatarID, QUuid, UNKNOWN_ENTITY_ID); - DEFINE_PROPERTY_REF(PROP_QUERY_AA_CUBE, QueryAACube, queryAACube, AACube, AACube()); - DEFINE_PROPERTY(PROP_CAN_CAST_SHADOW, CanCastShadow, canCastShadow, bool, ENTITY_ITEM_DEFAULT_CAN_CAST_SHADOW); - DEFINE_PROPERTY(PROP_VISIBLE_IN_SECONDARY_CAMERA, IsVisibleInSecondaryCamera, isVisibleInSecondaryCamera, bool, ENTITY_ITEM_DEFAULT_VISIBLE_IN_SECONDARY_CAMERA); - DEFINE_PROPERTY_REF_ENUM(PROP_RENDER_LAYER, RenderLayer, renderLayer, RenderLayer, RenderLayer::WORLD); - DEFINE_PROPERTY_REF_ENUM(PROP_PRIMITIVE_MODE, PrimitiveMode, primitiveMode, PrimitiveMode, PrimitiveMode::SOLID); - DEFINE_PROPERTY(PROP_IGNORE_PICK_INTERSECTION, IgnorePickIntersection, ignorePickIntersection, bool, false); - DEFINE_PROPERTY_REF(PROP_RENDER_WITH_ZONES, RenderWithZones, renderWithZones, QVector, QVector()); - DEFINE_PROPERTY_REF_ENUM(PROP_BILLBOARD_MODE, BillboardMode, billboardMode, BillboardMode, BillboardMode::NONE); - DEFINE_PROPERTY_GROUP(Grab, grab, GrabPropertyGroup); - - // Physics - DEFINE_PROPERTY(PROP_DENSITY, Density, density, float, ENTITY_ITEM_DEFAULT_DENSITY); - DEFINE_PROPERTY_REF(PROP_VELOCITY, Velocity, velocity, glm::vec3, ENTITY_ITEM_DEFAULT_VELOCITY); - DEFINE_PROPERTY_REF(PROP_ANGULAR_VELOCITY, AngularVelocity, angularVelocity, glm::vec3, ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY); - DEFINE_PROPERTY_REF(PROP_GRAVITY, Gravity, gravity, glm::vec3, ENTITY_ITEM_DEFAULT_GRAVITY); - DEFINE_PROPERTY_REF(PROP_ACCELERATION, Acceleration, acceleration, glm::vec3, ENTITY_ITEM_DEFAULT_ACCELERATION); - DEFINE_PROPERTY(PROP_DAMPING, Damping, damping, float, ENTITY_ITEM_DEFAULT_DAMPING); - DEFINE_PROPERTY(PROP_ANGULAR_DAMPING, AngularDamping, angularDamping, float, ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING); - DEFINE_PROPERTY(PROP_RESTITUTION, Restitution, restitution, float, ENTITY_ITEM_DEFAULT_RESTITUTION); - DEFINE_PROPERTY(PROP_FRICTION, Friction, friction, float, ENTITY_ITEM_DEFAULT_FRICTION); - DEFINE_PROPERTY(PROP_LIFETIME, Lifetime, lifetime, float, ENTITY_ITEM_DEFAULT_LIFETIME); - DEFINE_PROPERTY(PROP_COLLISIONLESS, Collisionless, collisionless, bool, ENTITY_ITEM_DEFAULT_COLLISIONLESS); - DEFINE_PROPERTY(PROP_COLLISION_MASK, CollisionMask, collisionMask, uint16_t, ENTITY_COLLISION_MASK_DEFAULT); - DEFINE_PROPERTY(PROP_DYNAMIC, Dynamic, dynamic, bool, ENTITY_ITEM_DEFAULT_DYNAMIC); - DEFINE_PROPERTY_REF(PROP_COLLISION_SOUND_URL, CollisionSoundURL, collisionSoundURL, QString, ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL); - DEFINE_PROPERTY_REF(PROP_ACTION_DATA, ActionData, actionData, QByteArray, QByteArray()); - - // Cloning - DEFINE_PROPERTY(PROP_CLONEABLE, Cloneable, cloneable, bool, ENTITY_ITEM_DEFAULT_CLONEABLE); - DEFINE_PROPERTY(PROP_CLONE_LIFETIME, CloneLifetime, cloneLifetime, float, ENTITY_ITEM_DEFAULT_CLONE_LIFETIME); - DEFINE_PROPERTY(PROP_CLONE_LIMIT, CloneLimit, cloneLimit, float, ENTITY_ITEM_DEFAULT_CLONE_LIMIT); - DEFINE_PROPERTY(PROP_CLONE_DYNAMIC, CloneDynamic, cloneDynamic, bool, ENTITY_ITEM_DEFAULT_CLONE_DYNAMIC); - DEFINE_PROPERTY(PROP_CLONE_AVATAR_ENTITY, CloneAvatarEntity, cloneAvatarEntity, bool, ENTITY_ITEM_DEFAULT_CLONE_AVATAR_ENTITY); - DEFINE_PROPERTY_REF(PROP_CLONE_ORIGIN_ID, CloneOriginID, cloneOriginID, QUuid, ENTITY_ITEM_DEFAULT_CLONE_ORIGIN_ID); - - // Scripts - DEFINE_PROPERTY_REF(PROP_SCRIPT, Script, script, QString, ENTITY_ITEM_DEFAULT_SCRIPT); - DEFINE_PROPERTY(PROP_SCRIPT_TIMESTAMP, ScriptTimestamp, scriptTimestamp, quint64, ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP); - DEFINE_PROPERTY_REF(PROP_SERVER_SCRIPTS, ServerScripts, serverScripts, QString, ENTITY_ITEM_DEFAULT_SERVER_SCRIPTS); - - // these are used when bouncing location data into and out of scripts - DEFINE_PROPERTY_REF(PROP_LOCAL_POSITION, LocalPosition, localPosition, glm::vec3, ENTITY_ITEM_ZERO_VEC3); - DEFINE_PROPERTY_REF(PROP_LOCAL_ROTATION, LocalRotation, localRotation, quat, ENTITY_ITEM_DEFAULT_ROTATION); - DEFINE_PROPERTY_REF(PROP_LOCAL_VELOCITY, LocalVelocity, localVelocity, glm::vec3, ENTITY_ITEM_ZERO_VEC3); - DEFINE_PROPERTY_REF(PROP_LOCAL_ANGULAR_VELOCITY, LocalAngularVelocity, localAngularVelocity, glm::vec3, ENTITY_ITEM_ZERO_VEC3); - DEFINE_PROPERTY_REF(PROP_LOCAL_DIMENSIONS, LocalDimensions, localDimensions, glm::vec3, ENTITY_ITEM_ZERO_VEC3); - - // Common - DEFINE_PROPERTY_REF_ENUM(PROP_SHAPE_TYPE, ShapeType, shapeType, ShapeType, SHAPE_TYPE_NONE); - DEFINE_PROPERTY_REF(PROP_COMPOUND_SHAPE_URL, CompoundShapeURL, compoundShapeURL, QString, ""); - DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, u8vec3Color, ENTITY_ITEM_DEFAULT_COLOR); - DEFINE_PROPERTY(PROP_ALPHA, Alpha, alpha, float, ENTITY_ITEM_DEFAULT_ALPHA); - DEFINE_PROPERTY_GROUP(Pulse, pulse, PulsePropertyGroup); - DEFINE_PROPERTY_REF(PROP_TEXTURES, Textures, textures, QString, ""); - - // Particles - DEFINE_PROPERTY(PROP_MAX_PARTICLES, MaxParticles, maxParticles, quint32, particle::DEFAULT_MAX_PARTICLES); - DEFINE_PROPERTY(PROP_LIFESPAN, Lifespan, lifespan, float, particle::DEFAULT_LIFESPAN); - DEFINE_PROPERTY(PROP_EMITTING_PARTICLES, IsEmitting, isEmitting, bool, true); - DEFINE_PROPERTY(PROP_EMIT_RATE, EmitRate, emitRate, float, particle::DEFAULT_EMIT_RATE); - DEFINE_PROPERTY(PROP_EMIT_SPEED, EmitSpeed, emitSpeed, float, particle::DEFAULT_EMIT_SPEED); - DEFINE_PROPERTY(PROP_SPEED_SPREAD, SpeedSpread, speedSpread, float, particle::DEFAULT_SPEED_SPREAD); - DEFINE_PROPERTY_REF(PROP_EMIT_ORIENTATION, EmitOrientation, emitOrientation, glm::quat, particle::DEFAULT_EMIT_ORIENTATION); - DEFINE_PROPERTY_REF(PROP_EMIT_DIMENSIONS, EmitDimensions, emitDimensions, glm::vec3, particle::DEFAULT_EMIT_DIMENSIONS); - DEFINE_PROPERTY(PROP_EMIT_RADIUS_START, EmitRadiusStart, emitRadiusStart, float, particle::DEFAULT_EMIT_RADIUS_START); - DEFINE_PROPERTY(PROP_POLAR_START, PolarStart, polarStart, float, particle::DEFAULT_POLAR_START); - DEFINE_PROPERTY(PROP_POLAR_FINISH, PolarFinish, polarFinish, float, particle::DEFAULT_POLAR_FINISH); - DEFINE_PROPERTY(PROP_AZIMUTH_START, AzimuthStart, azimuthStart, float, particle::DEFAULT_AZIMUTH_START); - DEFINE_PROPERTY(PROP_AZIMUTH_FINISH, AzimuthFinish, azimuthFinish, float, particle::DEFAULT_AZIMUTH_FINISH); - DEFINE_PROPERTY_REF(PROP_EMIT_ACCELERATION, EmitAcceleration, emitAcceleration, glm::vec3, particle::DEFAULT_EMIT_ACCELERATION); - DEFINE_PROPERTY_REF(PROP_ACCELERATION_SPREAD, AccelerationSpread, accelerationSpread, glm::vec3, particle::DEFAULT_ACCELERATION_SPREAD); - DEFINE_PROPERTY(PROP_PARTICLE_RADIUS, ParticleRadius, particleRadius, float, particle::DEFAULT_PARTICLE_RADIUS); - DEFINE_PROPERTY(PROP_RADIUS_SPREAD, RadiusSpread, radiusSpread, float, particle::DEFAULT_RADIUS_SPREAD); - DEFINE_PROPERTY(PROP_RADIUS_START, RadiusStart, radiusStart, float, particle::DEFAULT_RADIUS_START); - DEFINE_PROPERTY(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float, particle::DEFAULT_RADIUS_FINISH); - DEFINE_PROPERTY_REF(PROP_COLOR_SPREAD, ColorSpread, colorSpread, u8vec3Color, particle::DEFAULT_COLOR_SPREAD); - DEFINE_PROPERTY_REF(PROP_COLOR_START, ColorStart, colorStart, glm::vec3, particle::DEFAULT_COLOR_UNINITIALIZED); - DEFINE_PROPERTY_REF(PROP_COLOR_FINISH, ColorFinish, colorFinish, glm::vec3, particle::DEFAULT_COLOR_UNINITIALIZED); - DEFINE_PROPERTY(PROP_ALPHA_SPREAD, AlphaSpread, alphaSpread, float, particle::DEFAULT_ALPHA_SPREAD); - DEFINE_PROPERTY(PROP_ALPHA_START, AlphaStart, alphaStart, float, particle::DEFAULT_ALPHA_START); - DEFINE_PROPERTY(PROP_ALPHA_FINISH, AlphaFinish, alphaFinish, float, particle::DEFAULT_ALPHA_FINISH); - DEFINE_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, EmitterShouldTrail, emitterShouldTrail, bool, particle::DEFAULT_EMITTER_SHOULD_TRAIL); - DEFINE_PROPERTY(PROP_PARTICLE_SPIN, ParticleSpin, particleSpin, float, particle::DEFAULT_PARTICLE_SPIN); - DEFINE_PROPERTY(PROP_SPIN_SPREAD, SpinSpread, spinSpread, float, particle::DEFAULT_SPIN_SPREAD); - DEFINE_PROPERTY(PROP_SPIN_START, SpinStart, spinStart, float, particle::DEFAULT_SPIN_START); - DEFINE_PROPERTY(PROP_SPIN_FINISH, SpinFinish, spinFinish, float, particle::DEFAULT_SPIN_FINISH); - DEFINE_PROPERTY(PROP_PARTICLE_ROTATE_WITH_ENTITY, RotateWithEntity, rotateWithEntity, bool, particle::DEFAULT_ROTATE_WITH_ENTITY); - - // Model - DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString, ""); - DEFINE_PROPERTY_REF(PROP_MODEL_SCALE, ModelScale, modelScale, glm::vec3, glm::vec3(1.0f)); - DEFINE_PROPERTY_REF(PROP_JOINT_ROTATIONS_SET, JointRotationsSet, jointRotationsSet, QVector, QVector()); - DEFINE_PROPERTY_REF(PROP_JOINT_ROTATIONS, JointRotations, jointRotations, QVector, QVector()); - DEFINE_PROPERTY_REF(PROP_JOINT_TRANSLATIONS_SET, JointTranslationsSet, jointTranslationsSet, QVector, QVector()); - DEFINE_PROPERTY_REF(PROP_JOINT_TRANSLATIONS, JointTranslations, jointTranslations, QVector, ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC); - DEFINE_PROPERTY(PROP_RELAY_PARENT_JOINTS, RelayParentJoints, relayParentJoints, bool, ENTITY_ITEM_DEFAULT_RELAY_PARENT_JOINTS); - DEFINE_PROPERTY_REF(PROP_GROUP_CULLED, GroupCulled, groupCulled, bool, false); - DEFINE_PROPERTY_REF(PROP_BLENDSHAPE_COEFFICIENTS, BlendshapeCoefficients, blendshapeCoefficients, QString, ""); - DEFINE_PROPERTY_REF(PROP_USE_ORIGINAL_PIVOT, UseOriginalPivot, useOriginalPivot, bool, false); - DEFINE_PROPERTY_GROUP(Animation, animation, AnimationPropertyGroup); - - // Light - DEFINE_PROPERTY(PROP_IS_SPOTLIGHT, IsSpotlight, isSpotlight, bool, LightEntityItem::DEFAULT_IS_SPOTLIGHT); - DEFINE_PROPERTY(PROP_INTENSITY, Intensity, intensity, float, LightEntityItem::DEFAULT_INTENSITY); - DEFINE_PROPERTY(PROP_EXPONENT, Exponent, exponent, float, LightEntityItem::DEFAULT_EXPONENT); - DEFINE_PROPERTY(PROP_CUTOFF, Cutoff, cutoff, float, LightEntityItem::DEFAULT_CUTOFF); - DEFINE_PROPERTY(PROP_FALLOFF_RADIUS, FalloffRadius, falloffRadius, float, LightEntityItem::DEFAULT_FALLOFF_RADIUS); - - // Text - DEFINE_PROPERTY_REF(PROP_TEXT, Text, text, QString, TextEntityItem::DEFAULT_TEXT); - DEFINE_PROPERTY(PROP_LINE_HEIGHT, LineHeight, lineHeight, float, TextEntityItem::DEFAULT_LINE_HEIGHT); - DEFINE_PROPERTY_REF(PROP_TEXT_COLOR, TextColor, textColor, u8vec3Color, TextEntityItem::DEFAULT_TEXT_COLOR); - DEFINE_PROPERTY_REF(PROP_TEXT_ALPHA, TextAlpha, textAlpha, float, TextEntityItem::DEFAULT_TEXT_ALPHA); - DEFINE_PROPERTY_REF(PROP_BACKGROUND_COLOR, BackgroundColor, backgroundColor, u8vec3Color, TextEntityItem::DEFAULT_BACKGROUND_COLOR); - DEFINE_PROPERTY_REF(PROP_BACKGROUND_ALPHA, BackgroundAlpha, backgroundAlpha, float, TextEntityItem::DEFAULT_TEXT_ALPHA); - DEFINE_PROPERTY_REF(PROP_LEFT_MARGIN, LeftMargin, leftMargin, float, TextEntityItem::DEFAULT_MARGIN); - DEFINE_PROPERTY_REF(PROP_RIGHT_MARGIN, RightMargin, rightMargin, float, TextEntityItem::DEFAULT_MARGIN); - DEFINE_PROPERTY_REF(PROP_TOP_MARGIN, TopMargin, topMargin, float, TextEntityItem::DEFAULT_MARGIN); - DEFINE_PROPERTY_REF(PROP_BOTTOM_MARGIN, BottomMargin, bottomMargin, float, TextEntityItem::DEFAULT_MARGIN); - DEFINE_PROPERTY_REF(PROP_UNLIT, Unlit, unlit, bool, false); - DEFINE_PROPERTY_REF(PROP_FONT, Font, font, QString, ROBOTO_FONT_FAMILY); - DEFINE_PROPERTY_REF_ENUM(PROP_TEXT_EFFECT, TextEffect, textEffect, TextEffect, TextEffect::NO_EFFECT); - DEFINE_PROPERTY_REF(PROP_TEXT_EFFECT_COLOR, TextEffectColor, textEffectColor, u8vec3Color, TextEntityItem::DEFAULT_TEXT_COLOR); - DEFINE_PROPERTY(PROP_TEXT_EFFECT_THICKNESS, TextEffectThickness, textEffectThickness, float, TextEntityItem::DEFAULT_TEXT_EFFECT_THICKNESS); - DEFINE_PROPERTY_REF_ENUM(PROP_TEXT_ALIGNMENT, Alignment, alignment, TextAlignment, TextAlignment::LEFT); - - // Zone - DEFINE_PROPERTY_GROUP(KeyLight, keyLight, KeyLightPropertyGroup); - DEFINE_PROPERTY_GROUP(AmbientLight, ambientLight, AmbientLightPropertyGroup); - DEFINE_PROPERTY_GROUP(Skybox, skybox, SkyboxPropertyGroup); - DEFINE_PROPERTY_GROUP(Haze, haze, HazePropertyGroup); - DEFINE_PROPERTY_GROUP(Bloom, bloom, BloomPropertyGroup); - DEFINE_PROPERTY(PROP_FLYING_ALLOWED, FlyingAllowed, flyingAllowed, bool, ZoneEntityItem::DEFAULT_FLYING_ALLOWED); - DEFINE_PROPERTY(PROP_GHOSTING_ALLOWED, GhostingAllowed, ghostingAllowed, bool, ZoneEntityItem::DEFAULT_GHOSTING_ALLOWED); - DEFINE_PROPERTY(PROP_FILTER_URL, FilterURL, filterURL, QString, ZoneEntityItem::DEFAULT_FILTER_URL); - DEFINE_PROPERTY_REF_ENUM(PROP_KEY_LIGHT_MODE, KeyLightMode, keyLightMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); - 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_REF_ENUM(PROP_AVATAR_PRIORITY, AvatarPriority, avatarPriority, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); - DEFINE_PROPERTY_REF_ENUM(PROP_SCREENSHARE, Screenshare, screenshare, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); - - // Polyvox - DEFINE_PROPERTY_REF(PROP_VOXEL_VOLUME_SIZE, VoxelVolumeSize, voxelVolumeSize, glm::vec3, PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE); - DEFINE_PROPERTY_REF(PROP_VOXEL_DATA, VoxelData, voxelData, QByteArray, PolyVoxEntityItem::DEFAULT_VOXEL_DATA); - DEFINE_PROPERTY_REF(PROP_VOXEL_SURFACE_STYLE, VoxelSurfaceStyle, voxelSurfaceStyle, uint16_t, PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE); - DEFINE_PROPERTY_REF(PROP_X_TEXTURE_URL, XTextureURL, xTextureURL, QString, ""); - DEFINE_PROPERTY_REF(PROP_Y_TEXTURE_URL, YTextureURL, yTextureURL, QString, ""); - DEFINE_PROPERTY_REF(PROP_Z_TEXTURE_URL, ZTextureURL, zTextureURL, QString, ""); - DEFINE_PROPERTY_REF(PROP_X_N_NEIGHBOR_ID, XNNeighborID, xNNeighborID, EntityItemID, UNKNOWN_ENTITY_ID); - DEFINE_PROPERTY_REF(PROP_Y_N_NEIGHBOR_ID, YNNeighborID, yNNeighborID, EntityItemID, UNKNOWN_ENTITY_ID); - DEFINE_PROPERTY_REF(PROP_Z_N_NEIGHBOR_ID, ZNNeighborID, zNNeighborID, EntityItemID, UNKNOWN_ENTITY_ID); - DEFINE_PROPERTY_REF(PROP_X_P_NEIGHBOR_ID, XPNeighborID, xPNeighborID, EntityItemID, UNKNOWN_ENTITY_ID); - DEFINE_PROPERTY_REF(PROP_Y_P_NEIGHBOR_ID, YPNeighborID, yPNeighborID, EntityItemID, UNKNOWN_ENTITY_ID); - DEFINE_PROPERTY_REF(PROP_Z_P_NEIGHBOR_ID, ZPNeighborID, zPNeighborID, EntityItemID, UNKNOWN_ENTITY_ID); - - // Web - DEFINE_PROPERTY_REF(PROP_SOURCE_URL, SourceUrl, sourceUrl, QString, WebEntityItem::DEFAULT_SOURCE_URL); - DEFINE_PROPERTY_REF(PROP_DPI, DPI, dpi, uint16_t, ENTITY_ITEM_DEFAULT_DPI); - DEFINE_PROPERTY_REF(PROP_SCRIPT_URL, ScriptURL, scriptURL, QString, ""); - DEFINE_PROPERTY_REF(PROP_MAX_FPS, MaxFPS, maxFPS, uint8_t, WebEntityItem::DEFAULT_MAX_FPS); - DEFINE_PROPERTY_REF_ENUM(PROP_INPUT_MODE, InputMode, inputMode, WebInputMode, WebInputMode::TOUCH); - DEFINE_PROPERTY_REF(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, ShowKeyboardFocusHighlight, showKeyboardFocusHighlight, bool, true); - DEFINE_PROPERTY_REF(PROP_WEB_USE_BACKGROUND, UseBackground, useBackground, bool, true); - DEFINE_PROPERTY_REF(PROP_USER_AGENT, UserAgent, userAgent, QString, WebEntityItem::DEFAULT_USER_AGENT); - - // Polyline - DEFINE_PROPERTY_REF(PROP_LINE_POINTS, LinePoints, linePoints, QVector, ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC); - DEFINE_PROPERTY(PROP_STROKE_WIDTHS, StrokeWidths, strokeWidths, QVector, QVector()); - DEFINE_PROPERTY(PROP_STROKE_NORMALS, Normals, normals, QVector, ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC); - DEFINE_PROPERTY(PROP_STROKE_COLORS, StrokeColors, strokeColors, QVector, ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC); - DEFINE_PROPERTY(PROP_IS_UV_MODE_STRETCH, IsUVModeStretch, isUVModeStretch, bool, true); - DEFINE_PROPERTY(PROP_LINE_GLOW, Glow, glow, bool, false); - DEFINE_PROPERTY(PROP_LINE_FACE_CAMERA, FaceCamera, faceCamera, bool, false); - - // Shape - DEFINE_PROPERTY_REF(PROP_SHAPE, Shape, shape, QString, "Sphere"); - - // Material - DEFINE_PROPERTY_REF(PROP_MATERIAL_URL, MaterialURL, materialURL, QString, ""); - DEFINE_PROPERTY_REF_ENUM(PROP_MATERIAL_MAPPING_MODE, MaterialMappingMode, materialMappingMode, MaterialMappingMode, UV); - DEFINE_PROPERTY_REF(PROP_MATERIAL_PRIORITY, Priority, priority, quint16, 0); - DEFINE_PROPERTY_REF(PROP_PARENT_MATERIAL_NAME, ParentMaterialName, parentMaterialName, QString, "0"); - DEFINE_PROPERTY_REF(PROP_MATERIAL_MAPPING_POS, MaterialMappingPos, materialMappingPos, glm::vec2, glm::vec2(0.0f)); - DEFINE_PROPERTY_REF(PROP_MATERIAL_MAPPING_SCALE, MaterialMappingScale, materialMappingScale, glm::vec2, glm::vec2(1.0f)); - DEFINE_PROPERTY_REF(PROP_MATERIAL_MAPPING_ROT, MaterialMappingRot, materialMappingRot, float, 0); - DEFINE_PROPERTY_REF(PROP_MATERIAL_DATA, MaterialData, materialData, QString, ""); - DEFINE_PROPERTY_REF(PROP_MATERIAL_REPEAT, MaterialRepeat, materialRepeat, bool, true); - - // Image - DEFINE_PROPERTY_REF(PROP_IMAGE_URL, ImageURL, imageURL, QString, ""); - DEFINE_PROPERTY_REF(PROP_EMISSIVE, Emissive, emissive, bool, false); - DEFINE_PROPERTY_REF(PROP_KEEP_ASPECT_RATIO, KeepAspectRatio, keepAspectRatio, bool, true); - DEFINE_PROPERTY_REF(PROP_SUB_IMAGE, SubImage, subImage, QRect, QRect()); - - // Grid - DEFINE_PROPERTY_REF(PROP_GRID_FOLLOW_CAMERA, FollowCamera, followCamera, bool, true); - DEFINE_PROPERTY(PROP_MAJOR_GRID_EVERY, MajorGridEvery, majorGridEvery, uint32_t, GridEntityItem::DEFAULT_MAJOR_GRID_EVERY); - DEFINE_PROPERTY(PROP_MINOR_GRID_EVERY, MinorGridEvery, minorGridEvery, float, GridEntityItem::DEFAULT_MINOR_GRID_EVERY); - - // Gizmo - DEFINE_PROPERTY_REF_ENUM(PROP_GIZMO_TYPE, GizmoType, gizmoType, GizmoType, GizmoType::RING); - DEFINE_PROPERTY_GROUP(Ring, ring, RingGizmoPropertyGroup); - - static QString getComponentModeAsString(uint32_t mode); - -public: - float getMaxDimension() const { return glm::compMax(_dimensions); } - - float getAge() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; } - bool hasCreatedTime() const { return (_created != UNKNOWN_CREATED_TIME); } - - bool containsBoundsProperties() const { return (_positionChanged || _dimensionsChanged); } - bool containsPositionChange() const { return _positionChanged; } - bool containsDimensionsChange() const { return _dimensionsChanged; } - - static OctreeElement::AppendState encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties, - QByteArray& buffer, EntityPropertyFlags requestedProperties, EntityPropertyFlags& didntFitProperties); - - static bool encodeEraseEntityMessage(const EntityItemID& entityItemID, QByteArray& buffer); - static bool encodeCloneEntityMessage(const EntityItemID& entityIDToClone, const EntityItemID& newEntityID, QByteArray& buffer); - static bool decodeCloneEntityMessage(const QByteArray& buffer, int& processedBytes, EntityItemID& entityIDToClone, EntityItemID& newEntityID); - - static bool decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes, - EntityItemID& entityID, EntityItemProperties& properties); - - void clearID() { _id = UNKNOWN_ENTITY_ID; _idSet = false; } - void markAllChanged(); - - const glm::vec3& getNaturalDimensions() const { return _naturalDimensions; } - void setNaturalDimensions(const glm::vec3& value) { _naturalDimensions = value; } - - const glm::vec3& getNaturalPosition() const { return _naturalPosition; } - void calculateNaturalPosition(const glm::vec3& min, const glm::vec3& max); - - const QVariantMap& getTextureNames() const { return _textureNames; } - void setTextureNames(const QVariantMap& value) { _textureNames = value; } - - QString getSimulatorIDAsString() const { return _simulationOwner.getID().toString().mid(1,36).toUpper(); } - - void setVoxelDataDirty() { _voxelDataChanged = true; } - - void setLinePointsDirty() {_linePointsChanged = true; } - - void setQueryAACubeDirty() { _queryAACubeChanged = true; } - - void setLocationDirty() { _positionChanged = true; _rotationChanged = true; } - - bool hasTransformOrVelocityChanges() const; - void clearTransformOrVelocityChanges(); - bool hasMiscPhysicsChanges() const; - - bool hasSimulationRestrictedChanges() const; - void copySimulationRestrictedProperties(const EntityItemPointer& entity); - void clearSimulationRestrictedProperties(); - - void clearSimulationOwner(); - void setSimulationOwner(const QUuid& id, uint8_t priority); - void setSimulationOwner(const QByteArray& data); - void setSimulationPriority(uint8_t priority) { _simulationOwner.setPriority(priority); } - uint8_t computeSimulationBidPriority() const; - - void setActionDataDirty() { _actionDataChanged = true; } - - QList listChangedProperties(); - - bool getDimensionsInitialized() const { return _dimensionsInitialized; } - void setDimensionsInitialized(bool dimensionsInitialized) { _dimensionsInitialized = dimensionsInitialized; } - - void setJointRotationsDirty() { _jointRotationsSetChanged = true; _jointRotationsChanged = true; } - void setJointTranslationsDirty() { _jointTranslationsSetChanged = true; _jointTranslationsChanged = true; } - - // render info related items - size_t getRenderInfoVertexCount() const { return _renderInfoVertexCount; } - void setRenderInfoVertexCount(size_t value) { _renderInfoVertexCount = value; } - int getRenderInfoTextureCount() const { return _renderInfoTextureCount; } - void setRenderInfoTextureCount(int value) { _renderInfoTextureCount = value; } - size_t getRenderInfoTextureSize() const { return _renderInfoTextureSize; } - void setRenderInfoTextureSize(size_t value) { _renderInfoTextureSize = value; } - int getRenderInfoDrawCalls() const { return _renderInfoDrawCalls; } - void setRenderInfoDrawCalls(int value) { _renderInfoDrawCalls = value; } - bool getRenderInfoHasTransparent() const { return _renderInfoHasTransparent; } - void setRenderInfoHasTransparent(bool value) { _renderInfoHasTransparent = value; } - - void setPackedNormals(const QByteArray& value); - QVector unpackNormals(const QByteArray& normals); - - void setPackedStrokeColors(const QByteArray& value); - QVector unpackStrokeColors(const QByteArray& strokeColors); - - QByteArray getPackedNormals() const; - QByteArray packNormals(const QVector& normals) const; - - QByteArray getPackedStrokeColors() const; - QByteArray packStrokeColors(const QVector& strokeColors) const; - - void convertToCloneProperties(const EntityItemID& entityIDToClone); - -protected: - QString getCollisionMaskAsString() const; - void setCollisionMaskFromString(const QString& maskString); - -private: - QUuid _id; - bool _idSet; - quint64 _lastEdited; - EntityTypes::EntityType _type; - void setType(const QString& typeName) { _type = EntityTypes::getEntityTypeFromName(typeName); } - - bool _defaultSettings; - bool _dimensionsInitialized = true; // Only false if creating an entity locally with no dimensions properties - - // NOTE: The following are pseudo client only properties. They are only used in clients which can access - // properties of model geometry. But these properties are not serialized like other properties. - QVariantMap _textureNames; - glm::vec3 _naturalDimensions; - glm::vec3 _naturalPosition; - - size_t _renderInfoVertexCount { 0 }; - int _renderInfoTextureCount { 0 }; - size_t _renderInfoTextureSize { 0 }; - int _renderInfoDrawCalls { 0 }; - bool _renderInfoHasTransparent { false }; - - EntityPropertyFlags _desiredProperties; // if set will narrow scopes of copy/to/from to just these properties -}; - -Q_DECLARE_METATYPE(EntityItemProperties); -ScriptValue EntityItemPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties); -ScriptValue EntityItemNonDefaultPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties); -bool EntityItemPropertiesFromScriptValueIgnoreReadOnly(const ScriptValue& object, EntityItemProperties& properties); -bool EntityItemPropertiesFromScriptValueHonorReadOnly(const ScriptValue& object, EntityItemProperties& properties); - -Q_DECLARE_METATYPE(EntityPropertyFlags); -ScriptValue EntityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags); -bool EntityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags); - -Q_DECLARE_METATYPE(EntityPropertyInfo); -ScriptValue EntityPropertyInfoToScriptValue(ScriptEngine* engine, const EntityPropertyInfo& propertyInfo); -bool EntityPropertyInfoFromScriptValue(const ScriptValue& object, EntityPropertyInfo& propertyInfo); - -// define these inline here so the macros work -inline void EntityItemProperties::setPosition(const glm::vec3& value) - { _position = glm::clamp(value, (float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); _positionChanged = true; } - -inline void EntityItemProperties::setOwningAvatarID(const QUuid& id) { - _owningAvatarID = id; - if (!_owningAvatarID.isNull()) { - // for AvatarEntities there's no entity-server to tell us we're the simulation owner, - // so always set the simulationOwner to the owningAvatarID and a high priority. - setSimulationOwner(_owningAvatarID, AVATAR_ENTITY_SIMULATION_PRIORITY); - } - _owningAvatarIDChanged = true; -} - -QDebug& operator<<(QDebug& dbg, const EntityPropertyFlags& f); - -inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { - debug << "EntityItemProperties[" << "\n"; - - debug << " _type:" << properties.getType() << "\n"; - - // TODO: figure out why position and animationSettings don't seem to like the macro approach - if (properties.containsPositionChange()) { - debug << " position:" << properties.getPosition() << "in meters" << "\n"; - } - - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Dimensions, dimensions, "in meters"); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Velocity, velocity, "in meters"); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Name, name, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Visible, visible, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, CanCastShadow, canCastShadow, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Rotation, rotation, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Density, density, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Gravity, gravity, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Acceleration, acceleration, "in meters per second"); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Damping, damping, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Restitution, restitution, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Friction, friction, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Created, created, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Lifetime, lifetime, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Script, script, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, ScriptTimestamp, scriptTimestamp, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, CollisionSoundURL, collisionSoundURL, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Color, color, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, ColorSpread, colorSpread, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, ColorStart, colorStart, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, ColorFinish, colorFinish, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Alpha, alpha, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaSpread, alphaSpread, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaStart, alphaStart, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaFinish, alphaFinish, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, ModelURL, modelURL, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, CompoundShapeURL, compoundShapeURL, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, RegistrationPoint, registrationPoint, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, AngularVelocity, angularVelocity, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, AngularDamping, angularDamping, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Collisionless, collisionless, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Dynamic, dynamic, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, IsSpotlight, isSpotlight, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Intensity, intensity, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, FalloffRadius, falloffRadius, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Exponent, exponent, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Cutoff, cutoff, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Locked, locked, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Textures, textures, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, UserData, userData, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, PrivateUserData, privateUserData, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, SimulationOwner, simulationOwner, SimulationOwner()); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Text, text, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, LineHeight, lineHeight, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, TextColor, textColor, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, BackgroundColor, backgroundColor, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, ShapeType, shapeType, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, MaxParticles, maxParticles, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Lifespan, lifespan, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, IsEmitting, isEmitting, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitRate, emitRate, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitSpeed, emitSpeed, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, SpeedSpread, speedSpread, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitOrientation, emitOrientation, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitDimensions, emitDimensions, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitRadiusStart, emitRadiusStart, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, PolarStart, polarStart, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, PolarFinish, polarFinish, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, AzimuthStart, azimuthStart, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, AzimuthFinish, azimuthFinish, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitAcceleration, emitAcceleration, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, AccelerationSpread, accelerationSpread, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParticleRadius, particleRadius, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusSpread, radiusSpread, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusStart, radiusStart, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusFinish, radiusFinish, ""); - - DEBUG_PROPERTY_IF_CHANGED(debug, properties, LocalPosition, localPosition, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, LocalRotation, localRotation, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, LocalVelocity, localVelocity, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, LocalAngularVelocity, localAngularVelocity, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, LocalDimensions, localDimensions, ""); - - DEBUG_PROPERTY_IF_CHANGED(debug, properties, HazeMode, hazeMode, ""); - 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, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, CloneLimit, cloneLimit, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, CloneDynamic, cloneDynamic, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, CloneAvatarEntity, cloneAvatarEntity, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, CloneOriginID, cloneOriginID, ""); - - DEBUG_PROPERTY_IF_CHANGED(debug, properties, VoxelVolumeSize, voxelVolumeSize, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, VoxelData, voxelData, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, VoxelSurfaceStyle, voxelSurfaceStyle, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Href, href, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Description, description, ""); - if (properties.actionDataChanged()) { - debug << " " << "actionData" << ":" << properties.getActionData().toHex() << "" << "\n"; - } - DEBUG_PROPERTY_IF_CHANGED(debug, properties, XTextureURL, xTextureURL, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, YTextureURL, yTextureURL, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, ZTextureURL, zTextureURL, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, XNNeighborID, xNNeighborID, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, YNNeighborID, yNNeighborID, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, ZNNeighborID, zNNeighborID, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, XPNeighborID, xPNeighborID, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, YPNeighborID, yPNeighborID, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, ZPNeighborID, zPNeighborID, ""); - - DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParentID, parentID, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParentJointIndex, parentJointIndex, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, QueryAACube, queryAACube, ""); - - DEBUG_PROPERTY_IF_CHANGED(debug, properties, JointRotationsSet, jointRotationsSet, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, JointRotations, jointRotations, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, JointTranslationsSet, jointTranslationsSet, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, JointTranslations, jointTranslations, ""); - - DEBUG_PROPERTY_IF_CHANGED(debug, properties, FlyingAllowed, flyingAllowed, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, GhostingAllowed, ghostingAllowed, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, FilterURL, filterURL, ""); - - DEBUG_PROPERTY_IF_CHANGED(debug, properties, AvatarPriority, avatarPriority, ""); - - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Screenshare, screenshare, ""); - - DEBUG_PROPERTY_IF_CHANGED(debug, properties, EntityHostTypeAsString, entityHostType, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, OwningAvatarID, owningAvatarID, ""); - - DEBUG_PROPERTY_IF_CHANGED(debug, properties, LastEditedBy, lastEditedBy, ""); - - debug << " last edited:" << properties.getLastEdited() << "\n"; - debug << " edited ago:" << properties.getEditedAgo() << "\n"; - debug << "]"; - - return debug; -} - -#endif // hifi_EntityItemProperties_h diff --git a/libraries/entities/src/EntityItemProperties.h.in b/libraries/entities/src/EntityItemProperties.h.in new file mode 100644 index 00000000000..c838e1d0d74 --- /dev/null +++ b/libraries/entities/src/EntityItemProperties.h.in @@ -0,0 +1,290 @@ +// +// EntityItemProperties.h +// libraries/entities/src +// +// Created by Brad Hefta-Gaub on 12/4/13. +// Copyright 2013 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef hifi_EntityItemProperties_h +#define hifi_EntityItemProperties_h + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "FontFamilies.h" +#include + +#include +#include "EntityItemPropertiesDefaults.h" +#include "EntityItemPropertiesMacros.h" +#include "EntityTypes.h" +#include "EntityPropertyFlags.h" +#include "EntityPseudoPropertyFlags.h" +#include "SimulationOwner.h" + +@ENTITY_ITEM_PROPERTY_INCLUDES@ + +#include "MaterialMappingMode.h" +#include "BillboardMode.h" +#include "RenderLayer.h" +#include "PrimitiveMode.h" +#include "WebInputMode.h" +#include "GizmoType.h" +#include "TextEffect.h" +#include "TextAlignment.h" +#include "TextVerticalAlignment.h" +#include "MirrorMode.h" +#include "EntityShape.h" + +class ScriptEngine; + +/// A collection of properties of an entity item used in the scripting API. Translates between the actual properties of an +/// entity and a JavaScript style hash/ScriptValue storing a set of properties. Used in scripting to set/get the complete +/// set of entity item properties via JavaScript hashes/QScriptValues +/// all units for SI units (meter, second, radian, etc) +class EntityItemProperties { + // TODO: consider removing these friend relationship and use public methods +@ENTITY_ITEM_PROPERTY_FRIENDS@ +public: + static bool blobToProperties(ScriptEngine& scriptEngine, const QByteArray& blob, EntityItemProperties& properties); + static void propertiesToBlob(ScriptEngine& scriptEngine, const QUuid& myAvatarID, const EntityItemProperties& properties, + QByteArray& blob, bool allProperties = false); + + EntityItemProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()); + EntityItemProperties(const EntityItemProperties&) = default; + + virtual ~EntityItemProperties() = default; + + void merge(const EntityItemProperties& other); + + EntityTypes::EntityType getType() const { return _type; } + void setType(EntityTypes::EntityType type) { _type = type; } + + virtual ScriptValue copyToScriptValue(ScriptEngine* engine, bool skipDefaults, bool allowUnknownCreateTime = false, + bool strictSemantics = false, EntityPseudoPropertyFlags pseudoPropertyFlags = EntityPseudoPropertyFlags()) const; + virtual void copyFromScriptValue(const ScriptValue& object, bool honorReadOnly); + void copyFromJSONString(ScriptEngine& scriptEngine, const QString& jsonString); + + static ScriptValue entityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags); + static bool entityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags); + + static bool getPropertyInfo(const QString& propertyName, EntityPropertyInfo& propertyInfo); + + // editing related features supported by all entities + quint64 getLastEdited() const { return _lastEdited; } + float getEditedAgo() const /// Elapsed seconds since this entity was last edited + { return (float)(usecTimestampNow() - getLastEdited()) / (float)USECS_PER_SECOND; } + + EntityPropertyFlags getChangedProperties() const; + + bool transformChanged() const; + bool getScalesWithParent() const; + bool parentRelatedPropertyChanged() const; + bool queryAACubeRelatedPropertyChanged() const; + bool grabbingRelatedPropertyChanged() const; + + AABox getAABox() const; + + void debugDump() const; + void setLastEdited(quint64 usecTime); + EntityPropertyFlags getDesiredProperties() { return _desiredProperties; } + void setDesiredProperties(EntityPropertyFlags properties) { _desiredProperties = properties; } + + bool constructFromBuffer(const unsigned char* data, int dataLength); + +@ENTITY_ITEM_PROPERTY_DEFINES@ + + static QString getComponentModeAsString(uint8_t mode); + +public: + float getMaxDimension() const { return glm::compMax(_dimensions); } + + float getAge() const { return (float)(usecTimestampNow() - _created) / (float)USECS_PER_SECOND; } + bool hasCreatedTime() const { return (_created != UNKNOWN_CREATED_TIME); } + + bool containsBoundsProperties() const { return (_positionChanged || _dimensionsChanged); } + bool containsPositionChange() const { return _positionChanged; } + bool containsDimensionsChange() const { return _dimensionsChanged; } + + static OctreeElement::AppendState encodeEntityEditPacket(PacketType command, EntityItemID id, const EntityItemProperties& properties, + QByteArray& buffer, EntityPropertyFlags requestedProperties, EntityPropertyFlags& didntFitProperties); + + static bool encodeEraseEntityMessage(const EntityItemID& entityItemID, QByteArray& buffer); + static bool encodeCloneEntityMessage(const EntityItemID& entityIDToClone, const EntityItemID& newEntityID, QByteArray& buffer); + static bool decodeCloneEntityMessage(const QByteArray& buffer, int& processedBytes, EntityItemID& entityIDToClone, EntityItemID& newEntityID); + + static bool decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes, + EntityItemID& entityID, EntityItemProperties& properties); + + void clearID() { _id = UNKNOWN_ENTITY_ID; _idSet = false; } + void markAllChanged(); + + const glm::vec3& getNaturalDimensions() const { return _naturalDimensions; } + void setNaturalDimensions(const glm::vec3& value) { _naturalDimensions = value; } + + const glm::vec3& getNaturalPosition() const { return _naturalPosition; } + void calculateNaturalPosition(const glm::vec3& min, const glm::vec3& max); + + const QVariantMap& getTextureNames() const { return _textureNames; } + void setTextureNames(const QVariantMap& value) { _textureNames = value; } + + QString getSimulatorIDAsString() const { return _simulationOwner.getID().toString().mid(1,36).toUpper(); } + + void setVoxelDataDirty() { _voxelDataChanged = true; } + + void setLinePointsDirty() {_linePointsChanged = true; } + + void setQueryAACubeDirty() { _queryAACubeChanged = true; } + + void setLocationDirty() { _positionChanged = true; _rotationChanged = true; } + + bool hasTransformOrVelocityChanges() const; + void clearTransformOrVelocityChanges(); + bool hasMiscPhysicsChanges() const; + + bool hasSimulationRestrictedChanges() const; + void copySimulationRestrictedProperties(const EntityItemPointer& entity); + void clearSimulationRestrictedProperties(); + + void clearSimulationOwner(); + void setSimulationOwner(const QUuid& id, uint8_t priority); + void setSimulationOwner(const QByteArray& data); + void setSimulationPriority(uint8_t priority) { _simulationOwner.setPriority(priority); } + uint8_t computeSimulationBidPriority() const; + + void setActionDataDirty() { _actionDataChanged = true; } + + QList listChangedProperties(); + + bool getDimensionsInitialized() const { return _dimensionsInitialized; } + void setDimensionsInitialized(bool dimensionsInitialized) { _dimensionsInitialized = dimensionsInitialized; } + + void setJointRotationsDirty() { _jointRotationsSetChanged = true; _jointRotationsChanged = true; } + void setJointTranslationsDirty() { _jointTranslationsSetChanged = true; _jointTranslationsChanged = true; } + + // render info related items + size_t getRenderInfoVertexCount() const { return _renderInfoVertexCount; } + void setRenderInfoVertexCount(size_t value) { _renderInfoVertexCount = value; } + int getRenderInfoTextureCount() const { return _renderInfoTextureCount; } + void setRenderInfoTextureCount(int value) { _renderInfoTextureCount = value; } + size_t getRenderInfoTextureSize() const { return _renderInfoTextureSize; } + void setRenderInfoTextureSize(size_t value) { _renderInfoTextureSize = value; } + int getRenderInfoDrawCalls() const { return _renderInfoDrawCalls; } + void setRenderInfoDrawCalls(int value) { _renderInfoDrawCalls = value; } + bool getRenderInfoHasTransparent() const { return _renderInfoHasTransparent; } + void setRenderInfoHasTransparent(bool value) { _renderInfoHasTransparent = value; } + + void setPackedNormals(const QByteArray& value); + QVector unpackNormals(const QByteArray& normals); + + void setPackedStrokeColors(const QByteArray& value); + QVector unpackStrokeColors(const QByteArray& strokeColors); + + QByteArray getPackedNormals() const; + QByteArray packNormals(const QVector& normals) const; + + QByteArray getPackedStrokeColors() const; + QByteArray packStrokeColors(const QVector& strokeColors) const; + + void convertToCloneProperties(const EntityItemID& entityIDToClone); + +protected: + QString getCollisionMaskAsString() const; + void setCollisionMaskFromString(const QString& maskString); + + QVector getTagsAsVector() const; + void setTagsFromVector(const QVector& tags); + +private: + QUuid _id; + bool _idSet; + quint64 _lastEdited; + EntityTypes::EntityType _type; + void setType(const QString& typeName) { _type = EntityTypes::getEntityTypeFromName(typeName); } + + bool _defaultSettings; + bool _dimensionsInitialized = true; // Only false if creating an entity locally with no dimensions properties + + // NOTE: The following are pseudo client only properties. They are only used in clients which can access + // properties of model geometry. But these properties are not serialized like other properties. + QVariantMap _textureNames; + glm::vec3 _naturalDimensions; + glm::vec3 _naturalPosition; + + size_t _renderInfoVertexCount { 0 }; + int _renderInfoTextureCount { 0 }; + size_t _renderInfoTextureSize { 0 }; + int _renderInfoDrawCalls { 0 }; + bool _renderInfoHasTransparent { false }; + + EntityPropertyFlags _desiredProperties; // if set will narrow scopes of copy/to/from to just these properties +}; + +Q_DECLARE_METATYPE(EntityItemProperties); +ScriptValue EntityItemPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties); +ScriptValue EntityItemNonDefaultPropertiesToScriptValue(ScriptEngine* engine, const EntityItemProperties& properties); +bool EntityItemPropertiesFromScriptValueIgnoreReadOnly(const ScriptValue& object, EntityItemProperties& properties); +bool EntityItemPropertiesFromScriptValueHonorReadOnly(const ScriptValue& object, EntityItemProperties& properties); + +Q_DECLARE_METATYPE(EntityPropertyFlags); +ScriptValue EntityPropertyFlagsToScriptValue(ScriptEngine* engine, const EntityPropertyFlags& flags); +bool EntityPropertyFlagsFromScriptValue(const ScriptValue& object, EntityPropertyFlags& flags); + +Q_DECLARE_METATYPE(EntityPropertyInfo); +ScriptValue EntityPropertyInfoToScriptValue(ScriptEngine* engine, const EntityPropertyInfo& propertyInfo); +bool EntityPropertyInfoFromScriptValue(const ScriptValue& object, EntityPropertyInfo& propertyInfo); + +// define these inline here so the macros work +inline void EntityItemProperties::setPosition(const glm::vec3& value) + { _position = glm::clamp(value, (float)-HALF_TREE_SCALE, (float)HALF_TREE_SCALE); _positionChanged = true; } + +inline void EntityItemProperties::setOwningAvatarID(const QUuid& id) { + _owningAvatarID = id; + if (!_owningAvatarID.isNull()) { + // for AvatarEntities there's no entity-server to tell us we're the simulation owner, + // so always set the simulationOwner to the owningAvatarID and a high priority. + setSimulationOwner(_owningAvatarID, AVATAR_ENTITY_SIMULATION_PRIORITY); + } + _owningAvatarIDChanged = true; +} + +QDebug& operator<<(QDebug& dbg, const EntityPropertyFlags& f); + +inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { + debug << "EntityItemProperties[" << "\n"; + + debug << " _type:" << properties.getType() << "\n"; + +@ENTITY_ITEM_PROPERTY_DEBUG@ + + debug << " last edited:" << properties.getLastEdited() << "\n"; + debug << " edited ago:" << properties.getEditedAgo() << "\n"; + debug << "]"; + + return debug; +} + +#endif // hifi_EntityItemProperties_h diff --git a/libraries/entities/src/EntityItemProperties.txt b/libraries/entities/src/EntityItemProperties.txt new file mode 100644 index 00000000000..251c9766d10 --- /dev/null +++ b/libraries/entities/src/EntityItemProperties.txt @@ -0,0 +1,269 @@ +Core +enum:SIMULATION_OWNER prop:simulationOwner type:SimulationOwner default:SimulationOwner() noScript readType:QByteArray networkGetter:properties._simulationOwner.toByteArray() variableNetworkGetter:_simulationOwner.toByteArray() noVariableNetworkSetter, +enum:PARENT_ID prop:parentID type:QUuid default:UNKNOWN_ENTITY_ID inherited variableNetworkGetter:actualParentID noVariableNetworkSetter, +enum:PARENT_JOINT_INDEX prop:parentJointIndex type:uint16_t default:ENTITY_ITEM_DEFAULT_PARENT_INDEX inherited noVariableNetworkSetter, +enum:VISIBLE prop:visible type:bool default:ENTITY_ITEM_DEFAULT_VISIBLE renderProp, +enum:NAME prop:name type:QString default:ENTITY_ITEM_DEFAULT_NAME noGetterSetterProp, +enum:LOCKED prop:locked type:bool default:ENTITY_ITEM_DEFAULT_LOCKED, +enum:USER_DATA prop:userData type:QString default:ENTITY_ITEM_DEFAULT_USER_DATA noGetterSetterProp, +enum:PRIVATE_USER_DATA prop:privateUserData type:QString default:ENTITY_ITEM_DEFAULT_PRIVATE_USER_DATA variableNetworkGetter:privateUserData basicProp, +enum:HREF prop:href type:QString default:"", +enum:DESCRIPTION prop:description type:QString default:"" basicProp, +enum:POSITION prop:position type:vec3 default:ENTITY_ITEM_ZERO_VEC3 propertySetter inherited variableCopyGetter:getLocalPosition variableNetworkGetter:getLocalPosition() variableNetworkSetter:customUpdatePositionFromNetwork debugString:"meters" debugGetter:getWorldPosition(), +enum:DIMENSIONS prop:dimensions type:vec3 default:ENTITY_ITEM_DEFAULT_DIMENSIONS min:ENTITY_ITEM_MIN_DIMENSION max:FLT_MAX inherited variableCopyGetter:getScaledDimensions variableCopySetter:setScaledDimensions variableNetworkGetter:getScaledDimensions() variableNetworkSetter:setScaledDimensions debugString:"meters" debugGetter:getScaledDimensions(), +enum:ROTATION prop:rotation type:quat default:ENTITY_ITEM_DEFAULT_ROTATION inherited variableCopyGetter:getLocalOrientation variableNetworkGetter:getLocalOrientation() variableNetworkSetter:customUpdateRotationFromNetwork debugGetter:getWorldOrientation(), +enum:REGISTRATION_POINT prop:registrationPoint type:vec3 default:ENTITY_ITEM_DEFAULT_REGISTRATION_POINT min:ENTITY_ITEM_MIN_REGISTRATION_POINT max:ENTITY_ITEM_MAX_REGISTRATION_POINT inherited, +enum:CREATED prop:created type:quint64 default:UNKNOWN_CREATED_TIME readOnly, +enum:LAST_EDITED_BY prop:lastEditedBy type:QUuid default:ENTITY_ITEM_DEFAULT_LAST_EDITED_BY readOnly basicProp, +enum:ENTITY_HOST_TYPE prop:entityHostType type:entity::HostType default:entity::HostType::DOMAIN enum readOnly noNetwork basicProp, +enum:OWNING_AVATAR_ID prop:owningAvatarID type:QUuid default:UNKNOWN_ENTITY_ID propertySetter variableCopyGetter:getOwningAvatarIDForProperties readOnly noNetwork, +enum:QUERY_AA_CUBE prop:queryAACube type:AACube default:AACube() inherited variableNetworkSetter:customUpdateQueryAACubeFromNetwork, +enum:CAN_CAST_SHADOW prop:canCastShadow type:bool default:ENTITY_ITEM_DEFAULT_CAN_CAST_SHADOW renderProp, +enum:VISIBLE_IN_SECONDARY_CAMERA prop:isVisibleInSecondaryCamera type:bool default:ENTITY_ITEM_DEFAULT_VISIBLE_IN_SECONDARY_CAMERA noNetwork renderProp, +enum:RENDER_LAYER prop:renderLayer type:RenderLayer default:RenderLayer::WORLD enum renderProp, +enum:PRIMITIVE_MODE prop:primitiveMode type:PrimitiveMode default:PrimitiveMode::SOLID enum renderProp, +enum:IGNORE_PICK_INTERSECTION prop:ignorePickIntersection type:bool default:false basicProp, +enum:RENDER_WITH_ZONES prop:renderWithZones type:qVectorQUuid default:QVector(), +enum:BILLBOARD_MODE prop:billboardMode type:BillboardMode default:BillboardMode::NONE enum renderProp, +enum:TAGS prop:tags type:qSetQString default:QSet() fromScriptType:qVectorQString getter:getTagsAsVector setter:setTagsFromVector basicProp, +group:grab, +enum:MIRROR_MODE prop:mirrorMode type:MirrorMode default:MirrorMode::NONE enum renderProp, +enum:PORTAL_EXIT_ID prop:portalExitID type:QUuid default:UNKNOWN_ENTITY_ID renderProp, +Physics +enum:DENSITY prop:density type:float default:ENTITY_ITEM_DEFAULT_DENSITY min:ENTITY_ITEM_MIN_DENSITY max:ENTITY_ITEM_MIN_DENSITY, +enum:VELOCITY prop:velocity type:vec3 default:ENTITY_ITEM_DEFAULT_VELOCITY inherited variableCopyGetter:getLocalVelocity variableNetworkGetter:getLocalVelocity() variableNetworkSetter:customUpdateVelocityFromNetwork debugString:"m/s" debugGetter:getWorldVelocity(), +enum:ANGULAR_VELOCITY prop:angularVelocity type:vec3 default:ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY inherited variableCopyGetter:getLocalAngularVelocity variableNetworkGetter:getLocalAngularVelocity() variableNetworkSetter:customUpdateAngularVelocityFromNetwork debugGetter:getWorldAngularVelocity(), +enum:GRAVITY prop:gravity type:vec3 default:ENTITY_ITEM_DEFAULT_GRAVITY debugString:"m/s^2", +enum:ACCELERATION prop:acceleration type:vec3 default:ENTITY_ITEM_DEFAULT_ACCELERATION variableNetworkSetter:customSetAcceleration basicProp debugString:"m/s^2", +enum:DAMPING prop:damping type:float default:ENTITY_ITEM_DEFAULT_DAMPING min:ENTITY_ITEM_MIN_DAMPING max:ENTITY_ITEM_MAX_DAMPING, +enum:ANGULAR_DAMPING prop:angularDamping type:float default:ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING min:ENTITY_ITEM_MIN_DAMPING max:ENTITY_ITEM_MAX_DAMPING, +enum:RESTITUTION prop:restitution type:float default:ENTITY_ITEM_DEFAULT_RESTITUTION min:ENTITY_ITEM_MIN_RESTITUTION max:ENTITY_ITEM_MAX_RESTITUTION, +enum:FRICTION prop:friction type:float default:ENTITY_ITEM_DEFAULT_FRICTION min:ENTITY_ITEM_MIN_FRICTION max:ENTITY_ITEM_MAX_FRICTION, +enum:LIFETIME prop:lifetime type:float default:ENTITY_ITEM_DEFAULT_LIFETIME debugString:"seconds", +enum:COLLISIONLESS prop:collisionless type:bool default:ENTITY_ITEM_DEFAULT_COLLISIONLESS, +enum:COLLISIONLESS prop:ignoreForCollisions proxy:collisionless type:bool legacy getter:getCollisionless setter:setCollisionless, +enum:COLLISION_MASK prop:collisionMask type:uint16_t default:ENTITY_COLLISION_MASK_DEFAULT, +enum:COLLISION_MASK prop:collidesWith proxy:collisionMask type:CollisionMask proxyType:uint16_t enum legacy getter:getCollisionMaskAsString, +enum:DYNAMIC prop:dynamic type:bool default:ENTITY_ITEM_DEFAULT_DYNAMIC, +enum:DYNAMIC prop:collisionWillMove proxy:dynamic type:bool legacy getter:getDynamic setter:setDynamic, +enum:COLLISION_SOUND_URL prop:collisionSoundURL type:QString default:ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL urlPermission, +enum:ACTION_DATA prop:actionData type:QByteArray default:QByteArray() readOnly inherited variableCopyGetter:getDynamicData variableCopySetter:setDynamicData variableNetworkGetter:getDynamicData() variableNetworkSetter:setDynamicData debugGetter:getDynamicData(), +Cloning +enum:CLONEABLE prop:cloneable type:bool default:ENTITY_ITEM_DEFAULT_CLONEABLE basicProp, +enum:CLONE_LIFETIME prop:cloneLifetime type:float default:ENTITY_ITEM_DEFAULT_CLONE_LIFETIME basicProp debugString:"seconds", +enum:CLONE_LIMIT prop:cloneLimit type:float default:ENTITY_ITEM_DEFAULT_CLONE_LIMIT basicProp, +enum:CLONE_DYNAMIC prop:cloneDynamic type:bool default:ENTITY_ITEM_DEFAULT_CLONE_DYNAMIC basicProp, +enum:CLONE_AVATAR_ENTITY prop:cloneAvatarEntity type:bool default:ENTITY_ITEM_DEFAULT_CLONE_AVATAR_ENTITY basicProp, +enum:CLONE_ORIGIN_ID prop:cloneOriginID type:QUuid default:ENTITY_ITEM_DEFAULT_CLONE_ORIGIN_ID basicProp, +Scripts +enum:SCRIPT prop:script type:QString default:ENTITY_ITEM_DEFAULT_SCRIPT basicProp, +enum:SCRIPT_TIMESTAMP prop:scriptTimestamp type:quint64 default:ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP, +enum:SERVER_SCRIPTS prop:serverScripts type:QString default:ENTITY_ITEM_DEFAULT_SERVER_SCRIPTS noVariableNetworkSetter, +LocalProps +enum:LOCAL_POSITION prop:localPosition type:vec3 default:ENTITY_ITEM_ZERO_VEC3 noNetwork inherited debugString:"meters", +enum:LOCAL_ROTATION prop:localRotation type:quat default:ENTITY_ITEM_DEFAULT_ROTATION noNetwork inherited variableCopyGetter:getLocalOrientation debugGetter:getLocalOrientation(), +enum:LOCAL_VELOCITY prop:localVelocity type:vec3 default:ENTITY_ITEM_ZERO_VEC3 noNetwork inherited debugString:"m/s", +enum:LOCAL_ANGULAR_VELOCITY prop:localAngularVelocity type:vec3 default:ENTITY_ITEM_ZERO_VEC3 noNetwork inherited, +enum:LOCAL_DIMENSIONS prop:localDimensions type:vec3 default:ENTITY_ITEM_ZERO_VEC3 min:ENTITY_ITEM_MIN_DIMENSION max:FLT_MAX noNetwork inherited variableCopyGetter:getUnscaledDimensions debugString:"meters" debugGetter:getUnscaledDimensions(), +Common +enum:SHAPE_TYPE prop:shapeType type:ShapeType enum default:SHAPE_TYPE_NONE, +enum:COMPOUND_SHAPE_URL prop:compoundShapeURL type:QString default:"" urlPermission, +enum:COLOR prop:color type:u8vec3Color default:ENTITY_ITEM_DEFAULT_COLOR, +enum:ALPHA prop:alpha type:float default:ENTITY_ITEM_DEFAULT_ALPHA min:0.0f max:1.0f, +enum:UNLIT prop:unlit type:bool default:false, +group:pulse, +enum:TEXTURES prop:textures type:QString default:"", +enum:LINE_POINTS prop:linePoints type:qVectorVec3 default:ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC, +ParticleEffect +enum:SHAPE_TYPE prop:shapeType type:ShapeType enum default:SHAPE_TYPE_NONE common noGetterSetterProp, +enum:COMPOUND_SHAPE_URL prop:compoundShapeURL type:QString default:"" urlPermission common renderProp, +enum:COLOR prop:color type:u8vec3Color default:ENTITY_ITEM_DEFAULT_COLOR common, +enum:ALPHA prop:alpha type:float default:ENTITY_ITEM_DEFAULT_ALPHA min:0.0f max:1.0f common, +group:pulse common renderUpdateOnSet, +enum:TEXTURES prop:textures type:QString default:"" common, +enum:MAX_PARTICLES prop:maxParticles type:quint32 default:particle::DEFAULT_MAX_PARTICLES min:particle::MINIMUM_MAX_PARTICLES max:particle::MAXIMUM_MAX_PARTICLES, +enum:LIFESPAN prop:lifespan type:float default:particle::DEFAULT_LIFESPAN min:particle::MINIMUM_LIFESPAN max:particle::MAXIMUM_LIFESPAN, +enum:EMITTING_PARTICLES prop:isEmitting type:bool default:true renderProp, +enum:EMIT_RATE prop:emitRate type:float default:particle::DEFAULT_EMIT_RATE min:particle::MINIMUM_EMIT_RATE max:particle::MAXIMUM_EMIT_RATE, +enum:EMIT_SPEED prop:emitSpeed type:float default:particle::DEFAULT_EMIT_SPEED min:particle::MINIMUM_EMIT_SPEED max:particle::MAXIMUM_EMIT_SPEED, +enum:SPEED_SPREAD prop:speedSpread type:float default:particle::DEFAULT_SPEED_SPREAD min:particle::MINIMUM_EMIT_SPEED max:particle::MAXIMUM_EMIT_SPEED, +enum:EMIT_ORIENTATION prop:emitOrientation type:quat default:particle::DEFAULT_EMIT_ORIENTATION, +enum:EMIT_DIMENSIONS prop:emitDimensions type:vec3 default:particle::DEFAULT_EMIT_DIMENSIONS min:particle::MINIMUM_EMIT_DIMENSION max:particle::MAXIMUM_EMIT_DIMENSION, +enum:EMIT_RADIUS_START prop:emitRadiusStart type:float default:particle::DEFAULT_EMIT_RADIUS_START min:particle::MINIMUM_EMIT_RADIUS_START max:particle::MAXIMUM_EMIT_RADIUS_START, +enum:POLAR_START prop:polarStart type:float default:particle::DEFAULT_POLAR_START min:particle::MINIMUM_POLAR max:particle::MAXIMUM_POLAR, +enum:POLAR_FINISH prop:polarFinish type:float default:particle::DEFAULT_POLAR_FINISH min:particle::MINIMUM_POLAR max:particle::MAXIMUM_POLAR, +enum:AZIMUTH_START prop:azimuthStart type:float default:particle::DEFAULT_AZIMUTH_START min:particle::MINIMUM_AZIMUTH max:particle::MAXIMUM_AZIMUTH, +enum:AZIMUTH_FINISH prop:azimuthFinish type:float default:particle::DEFAULT_AZIMUTH_FINISH min:particle::MINIMUM_AZIMUTH max:particle::MAXIMUM_AZIMUTH, +enum:EMIT_ACCELERATION prop:emitAcceleration type:vec3 default:particle::DEFAULT_EMIT_ACCELERATION min:particle::MINIMUM_EMIT_ACCELERATION max:particle::MAXIMUM_EMIT_ACCELERATION, +enum:ACCELERATION_SPREAD prop:accelerationSpread type:vec3 default:particle::DEFAULT_ACCELERATION_SPREAD min:particle::MINIMUM_ACCELERATION_SPREAD max:particle::MAXIMUM_ACCELERATION_SPREAD, +enum:PARTICLE_RADIUS prop:particleRadius type:float default:particle::DEFAULT_PARTICLE_RADIUS min:particle::MINIMUM_PARTICLE_RADIUS max:particle::MAXIMUM_PARTICLE_RADIUS, +enum:RADIUS_SPREAD prop:radiusSpread type:float default:particle::DEFAULT_RADIUS_SPREAD min:particle::MINIMUM_PARTICLE_RADIUS max:particle::MAXIMUM_PARTICLE_RADIUS, +enum:RADIUS_START prop:radiusStart type:float default:particle::DEFAULT_RADIUS_START min:particle::MINIMUM_PARTICLE_RADIUS max:particle::MAXIMUM_PARTICLE_RADIUS, +enum:RADIUS_FINISH prop:radiusFinish type:float default:particle::DEFAULT_RADIUS_FINISH min:particle::MINIMUM_PARTICLE_RADIUS max:particle::MAXIMUM_PARTICLE_RADIUS, +enum:COLOR_SPREAD prop:colorSpread type:u8vec3Color default:particle::DEFAULT_COLOR_SPREAD, +enum:COLOR_START prop:colorStart type:vec3Color default:particle::DEFAULT_COLOR_UNINITIALIZED, +enum:COLOR_FINISH prop:colorFinish type:vec3Color default:particle::DEFAULT_COLOR_UNINITIALIZED, +enum:ALPHA_SPREAD prop:alphaSpread type:float default:particle::DEFAULT_ALPHA_SPREAD min:particle::MINIMUM_ALPHA max:particle::MAXIMUM_ALPHA, +enum:ALPHA_START prop:alphaStart type:float default:particle::DEFAULT_ALPHA_START min:particle::MINIMUM_ALPHA max:particle::MAXIMUM_ALPHA, +enum:ALPHA_FINISH prop:alphaFinish type:float default:particle::DEFAULT_ALPHA_FINISH min:particle::MINIMUM_ALPHA max:particle::MAXIMUM_ALPHA, +enum:EMITTER_SHOULD_TRAIL prop:emitterShouldTrail type:bool default:particle::DEFAULT_EMITTER_SHOULD_TRAIL, +enum:PARTICLE_SPIN prop:particleSpin type:float default:particle::DEFAULT_PARTICLE_SPIN min:particle::MINIMUM_PARTICLE_SPIN max:particle::MAXIMUM_PARTICLE_SPIN, +enum:SPIN_SPREAD prop:spinSpread type:float default:particle::DEFAULT_SPIN_SPREAD min:particle::MINIMUM_PARTICLE_SPIN max:particle::MAXIMUM_PARTICLE_SPIN, +enum:SPIN_START prop:spinStart type:float default:particle::DEFAULT_SPIN_START min:particle::MINIMUM_PARTICLE_SPIN max:particle::MAXIMUM_PARTICLE_SPIN, +enum:SPIN_FINISH prop:spinFinish type:float default:particle::DEFAULT_SPIN_FINISH min:particle::MINIMUM_PARTICLE_SPIN max:particle::MAXIMUM_PARTICLE_SPIN, +enum:PARTICLE_ROTATE_WITH_ENTITY prop:rotateWithEntity type:bool default:particle::DEFAULT_ROTATE_WITH_ENTITY, +ProceduralParticleEffect +enum:PROCEDURAL_PARTICLE_NUM_PARTICLES prop:numParticles type:uint32_t default:particle::DEFAULT_NUM_PROCEDURAL_PARTICLES min:particle::MINIMUM_MAX_PARTICLES max:particle::MAXIMUM_NUM_PROCEDURAL_PARTICLES renderProp, +enum:PROCEDURAL_PARTICLE_NUM_TRIS_PER prop:numTrianglesPerParticle type:uint8_t default:particle::DEFAULT_NUM_TRIS_PER min:particle::MINIMUM_TRIS_PER max:particle::MAXIMUM_TRIS_PER renderProp, +enum:PROCEDURAL_PARTICLE_NUM_UPDATE_PROPS prop:numUpdateProps type:uint8_t default:particle::DEFAULT_NUM_UPDATE_PROPS min:particle::MINIMUM_NUM_UPDATE_PROPS max:particle::MAXIMUM_NUM_UPDATE_PROPS renderProp, +enum:PROCEDURAL_PARTICLE_TRANSPARENT prop:particleTransparent type:bool default:false renderProp, +enum:PROCEDURAL_PARTCILE_UPDATE_DATA prop:particleUpdateData type:QString default:"" renderProp, +enum:PROCEDURAL_PARTCILE_RENDER_DATA prop:particleRenderData type:QString default:"" renderProp, +Model +enum:SHAPE_TYPE prop:shapeType type:ShapeType enum default:SHAPE_TYPE_NONE common noGetterSetterProp, +enum:COMPOUND_SHAPE_URL prop:compoundShapeURL type:QString default:"" urlPermission common noGetterSetterProp, +enum:COLOR prop:color type:u8vec3Color default:ENTITY_ITEM_DEFAULT_COLOR common renderProp, +enum:TEXTURES prop:textures type:QString default:"" common renderProp, +enum:MODEL_URL prop:modelURL type:QString default:"" urlPermission noGetterSetterProp, +enum:MODEL_SCALE prop:modelScale type:vec3 default:glm::vec3(1.0f) basicProp, +enum:JOINT_ROTATIONS_SET prop:jointRotationsSet type:qVectorBool default:QVector() noGetterSetterProp, +enum:JOINT_ROTATIONS prop:jointRotations type:qVectorQuat default:QVector() noGetterSetterProp, +enum:JOINT_TRANSLATIONS_SET prop:jointTranslationsSet type:qVectorBool default:QVector() noGetterSetterProp, +enum:JOINT_TRANSLATIONS prop:jointTranslations type:qVectorVec3 default:ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC noGetterSetterProp, +enum:RELAY_PARENT_JOINTS prop:relayParentJoints type:bool default:ENTITY_ITEM_DEFAULT_RELAY_PARENT_JOINTS basicProp, +enum:GROUP_CULLED prop:groupCulled type:bool default:false renderProp, +enum:BLENDSHAPE_COEFFICIENTS prop:blendshapeCoefficients type:QString default:"", +enum:USE_ORIGINAL_PIVOT prop:useOriginalPivot type:bool default:false, +enum:LOAD_PRIORITY prop:loadPriority type:float default:0.0f basicProp, +group:animation customVariableSetFrom customVariableRead, +Light +enum:COLOR prop:color type:u8vec3Color default:ENTITY_ITEM_DEFAULT_COLOR common renderProp, +enum:IS_SPOTLIGHT prop:isSpotlight type:bool default:LightEntityItem::DEFAULT_IS_SPOTLIGHT, +enum:INTENSITY prop:intensity type:float default:LightEntityItem::DEFAULT_INTENSITY renderProp, +enum:EXPONENT prop:exponent type:float default:LightEntityItem::DEFAULT_EXPONENT renderProp, +enum:CUTOFF prop:cutoff type:float default:LightEntityItem::DEFAULT_CUTOFF min:LightEntityItem::MIN_CUTOFF max:LightEntityItem::MAX_CUTOFF, +enum:FALLOFF_RADIUS prop:falloffRadius type:float default:LightEntityItem::DEFAULT_FALLOFF_RADIUS, +Text +enum:UNLIT prop:unlit type:bool default:false common renderProp, +group:pulse common renderUpdateOnSet, +enum:TEXT prop:text type:QString default:TextEntityItem::DEFAULT_TEXT renderProp, +enum:LINE_HEIGHT prop:lineHeight type:float default:TextEntityItem::DEFAULT_LINE_HEIGHT renderProp, +enum:TEXT_COLOR prop:textColor type:u8vec3Color default:TextEntityItem::DEFAULT_TEXT_COLOR renderProp, +enum:TEXT_ALPHA prop:textAlpha type:float default:TextEntityItem::DEFAULT_TEXT_ALPHA renderProp, +enum:BACKGROUND_COLOR prop:backgroundColor type:u8vec3Color default:TextEntityItem::DEFAULT_BACKGROUND_COLOR renderProp, +enum:BACKGROUND_ALPHA prop:backgroundAlpha type:float default:TextEntityItem::DEFAULT_TEXT_ALPHA renderProp, +enum:LEFT_MARGIN prop:leftMargin type:float default:TextEntityItem::DEFAULT_MARGIN renderProp, +enum:RIGHT_MARGIN prop:rightMargin type:float default:TextEntityItem::DEFAULT_MARGIN renderProp, +enum:TOP_MARGIN prop:topMargin type:float default:TextEntityItem::DEFAULT_MARGIN renderProp, +enum:BOTTOM_MARGIN prop:bottomMargin type:float default:TextEntityItem::DEFAULT_MARGIN renderProp, +enum:FONT prop:font type:QString default:"Roboto" renderProp, +enum:TEXT_EFFECT prop:textEffect type:TextEffect default:TextEffect::NO_EFFECT enum renderProp, +enum:TEXT_EFFECT_COLOR prop:textEffectColor type:u8vec3Color default:TextEntityItem::DEFAULT_TEXT_COLOR renderProp, +enum:TEXT_EFFECT_THICKNESS prop:textEffectThickness type:float default:TextEntityItem::DEFAULT_TEXT_EFFECT_THICKNESS min:0.0f max:0.5f renderProp, +enum:TEXT_ALIGNMENT prop:alignment type:TextAlignment default:TextAlignment::LEFT enum renderProp, +enum:TEXT_VERTICAL_ALIGNMENT prop:verticalAlignment type:TextVerticalAlignment default:TextVerticalAlignment::TOP enum renderProp, +Zone +enum:SHAPE_TYPE prop:shapeType type:ShapeType enum default:SHAPE_TYPE_NONE common noGetterSetterProp, +enum:COMPOUND_SHAPE_URL prop:compoundShapeURL type:QString default:"" urlPermission common, +group:keyLight recordChange, +group:ambientLight recordChange, +group:skybox recordChange, +group:haze recordChange, +group:bloom recordChange, +group:audio type:ZoneAudio, +group:tonemapping recordChange, +group:ambientOcclusion recordChange, +enum:FLYING_ALLOWED prop:flyingAllowed type:bool default:ZoneEntityItem::DEFAULT_FLYING_ALLOWED basicProp, +enum:GHOSTING_ALLOWED prop:ghostingAllowed type:bool default:ZoneEntityItem::DEFAULT_GHOSTING_ALLOWED basicProp, +enum:FILTER_URL prop:filterURL type:QString default:ZoneEntityItem::DEFAULT_FILTER_URL urlPermission, +enum:KEY_LIGHT_MODE prop:keyLightMode type:uint8_t default:(uint8_t)COMPONENT_MODE_INHERIT enum, +enum:AMBIENT_LIGHT_MODE prop:ambientLightMode type:uint8_t default:(uint8_t)COMPONENT_MODE_INHERIT enum, +enum:SKYBOX_MODE prop:skyboxMode type:uint8_t default:(uint8_t)COMPONENT_MODE_INHERIT enum, +enum:HAZE_MODE prop:hazeMode type:uint8_t default:(uint8_t)COMPONENT_MODE_INHERIT enum, +enum:BLOOM_MODE prop:bloomMode type:uint8_t default:(uint8_t)COMPONENT_MODE_INHERIT enum, +enum:AVATAR_PRIORITY prop:avatarPriority type:uint8_t default:(uint8_t)COMPONENT_MODE_INHERIT enum basicProp, +enum:SCREENSHARE prop:screenshare type:uint8_t default:(uint8_t)COMPONENT_MODE_INHERIT enum basicProp, +enum:TONEMAPPING_MODE prop:tonemappingMode type:uint8_t default:(uint8_t)COMPONENT_MODE_INHERIT enum, +enum:AMBIENT_OCCLUSION_MODE prop:ambientOcclusionMode type:uint8_t default:(uint8_t)COMPONENT_MODE_INHERIT enum, +PolyVox +enum:VOXEL_VOLUME_SIZE prop:voxelVolumeSize type:vec3 default:PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE noGetterSetterProp, +enum:VOXEL_DATA prop:voxelData type:QByteArray default:PolyVoxEntityItem::DEFAULT_VOXEL_DATA noGetterSetterProp, +enum:VOXEL_SURFACE_STYLE prop:voxelSurfaceStyle type:uint16_t default:PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE noGetterSetterProp, +enum:X_TEXTURE_URL prop:xTextureURL type:QString default:"" urlPermission renderProp, +enum:Y_TEXTURE_URL prop:yTextureURL type:QString default:"" urlPermission renderProp, +enum:Z_TEXTURE_URL prop:zTextureURL type:QString default:"" urlPermission renderProp, +enum:X_N_NEIGHBOR_ID prop:xNNeighborID type:EntityItemID default:UNKNOWN_ENTITY_ID noGetterSetterProp, +enum:Y_N_NEIGHBOR_ID prop:yNNeighborID type:EntityItemID default:UNKNOWN_ENTITY_ID noGetterSetterProp, +enum:Z_N_NEIGHBOR_ID prop:zNNeighborID type:EntityItemID default:UNKNOWN_ENTITY_ID noGetterSetterProp, +enum:X_P_NEIGHBOR_ID prop:xPNeighborID type:EntityItemID default:UNKNOWN_ENTITY_ID noGetterSetterProp, +enum:Y_P_NEIGHBOR_ID prop:yPNeighborID type:EntityItemID default:UNKNOWN_ENTITY_ID noGetterSetterProp, +enum:Z_P_NEIGHBOR_ID prop:zPNeighborID type:EntityItemID default:UNKNOWN_ENTITY_ID noGetterSetterProp, +Web +enum:COLOR prop:color type:u8vec3Color default:ENTITY_ITEM_DEFAULT_COLOR common renderProp, +enum:ALPHA prop:alpha type:float default:ENTITY_ITEM_DEFAULT_ALPHA min:0.0f max:1.0f common renderProp, +group:pulse common renderUpdateOnSet, +enum:SOURCE_URL prop:sourceUrl type:QString default:WebEntityItem::DEFAULT_SOURCE_URL urlPermission renderProp, +enum:DPI prop:dpi type:uint16_t default:ENTITY_ITEM_DEFAULT_DPI renderProp, +enum:SCRIPT_URL prop:scriptURL type:QString default:"" urlPermission noGetterSetterProp, +enum:MAX_FPS prop:maxFPS type:uint8_t default:WebEntityItem::DEFAULT_MAX_FPS renderProp, +enum:INPUT_MODE prop:inputMode type:WebInputMode default:WebInputMode::TOUCH enum renderProp, +enum:WANTS_KEYBOARD_FOCUS prop:wantsKeyboardFocus type:bool default:true renderProp, +enum:SHOW_KEYBOARD_FOCUS_HIGHLIGHT prop:showKeyboardFocusHighlight type:bool default:true basicProp, +enum:WEB_USE_BACKGROUND prop:useBackground type:bool default:true renderProp, +enum:USER_AGENT prop:userAgent type:QString default:WebEntityItem::DEFAULT_USER_AGENT renderProp, +Line +enum:COLOR prop:color type:u8vec3Color default:ENTITY_ITEM_DEFAULT_COLOR common renderProp, +enum:LINE_POINTS prop:linePoints type:qVectorVec3 default:ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC common noGetterSetterProp, +PolyLine +enum:COLOR prop:color type:u8vec3Color default:ENTITY_ITEM_DEFAULT_COLOR common, +enum:TEXTURES prop:textures type:QString default:"" common, +enum:LINE_POINTS prop:linePoints type:qVectorVec3 default:ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC common, +enum:STROKE_WIDTHS prop:strokeWidths type:qVectorFloat default:QVector(), +enum:STROKE_NORMALS prop:normals type:qVectorVec3 default:ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC, +enum:STROKE_COLORS prop:strokeColors type:qVectorVec3 default:ENTITY_ITEM_DEFAULT_EMPTY_VEC3_QVEC, +enum:IS_UV_MODE_STRETCH prop:isUVModeStretch type:bool default:true renderProp, +enum:LINE_GLOW prop:glow type:bool default:false renderProp, +enum:LINE_FACE_CAMERA prop:faceCamera type:bool default:false renderProp, +Shape +enum:COLOR prop:color type:u8vec3Color default:ENTITY_ITEM_DEFAULT_COLOR common renderProp, +enum:ALPHA prop:alpha type:float default:ENTITY_ITEM_DEFAULT_ALPHA min:0.0f max:1.0f common renderProp, +enum:UNLIT prop:unlit type:bool default:false common renderProp, +group:pulse common renderUpdateOnSet, +enum:SHAPE prop:shape type:EntityShape default:EntityShape::Sphere enum, +Material +enum:MATERIAL_URL prop:materialURL type:QString default:"" urlPermission renderProp, +enum:MATERIAL_MAPPING_MODE prop:materialMappingMode type:MaterialMappingMode default:UV enum renderProp, +enum:MATERIAL_PRIORITY prop:priority type:quint16 default:0 renderProp, +enum:PARENT_MATERIAL_NAME prop:parentMaterialName type:QString default:"0" renderProp, +enum:MATERIAL_MAPPING_POS prop:materialMappingPos type:vec2 default:glm::vec2(0.0f) renderProp, +enum:MATERIAL_MAPPING_SCALE prop:materialMappingScale type:vec2 default:glm::vec2(1.0f) renderProp, +enum:MATERIAL_MAPPING_ROT prop:materialMappingRot type:float default:0 renderProp, +enum:MATERIAL_DATA prop:materialData type:QString default:"" urlPermission renderProp, +enum:MATERIAL_REPEAT prop:materialRepeat type:bool default:true renderProp, +Image +enum:COLOR prop:color type:u8vec3Color default:ENTITY_ITEM_DEFAULT_COLOR common renderProp, +enum:ALPHA prop:alpha type:float default:ENTITY_ITEM_DEFAULT_ALPHA min:0.0f max:1.0f common renderProp, +group:pulse common renderUpdateOnSet, +enum:IMAGE_URL prop:imageURL type:QString default:"" urlPermission renderProp, +enum:EMISSIVE prop:emissive type:bool default:false renderProp, +enum:KEEP_ASPECT_RATIO prop:keepAspectRatio type:bool default:true renderProp, +enum:SUB_IMAGE prop:subImage type:QRect default:QRect() renderProp, +Grid +enum:COLOR prop:color type:u8vec3Color default:ENTITY_ITEM_DEFAULT_COLOR common renderProp, +enum:ALPHA prop:alpha type:float default:ENTITY_ITEM_DEFAULT_ALPHA min:0.0f max:1.0f common renderProp, +group:pulse common renderUpdateOnSet, +enum:GRID_FOLLOW_CAMERA prop:followCamera type:bool default:true renderProp, +enum:MAJOR_GRID_EVERY prop:majorGridEvery type:uint32_t default:GridEntityItem::DEFAULT_MAJOR_GRID_EVERY, +enum:MINOR_GRID_EVERY prop:minorGridEvery type:float default:GridEntityItem::DEFAULT_MINOR_GRID_EVERY, +Gizmo +enum:GIZMO_TYPE prop:gizmoType type:GizmoType default:GizmoType::RING enum renderProp, +group:ring type:RingGizmo renderUpdateOnSet, +Sound +enum:SOUND_URL prop:soundURL type:QString default:"", +enum:SOUND_VOLUME prop:volume type:float default:1.0f min:0.0f max:1.0f, +enum:SOUND_TIME_OFFSET prop:timeOffset type:float default:0.0f, +enum:SOUND_PITCH, prop:pitch type:float default:1.0f min:1.0f/16.0f max:16.0f, +enum:SOUND_PLAYING prop:playing type:bool default:true, +enum:SOUND_LOOP prop:loop type:bool default:true, +enum:SOUND_POSITIONAL prop:positional type:bool default:true, +enum:SOUND_LOCAL_ONLY prop:localOnly type:bool default:false, \ No newline at end of file diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h index ad9de6ac182..b79f011a706 100644 --- a/libraries/entities/src/EntityItemPropertiesDefaults.h +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -89,6 +89,8 @@ const uint16_t ENTITY_ITEM_DEFAULT_DPI = 30; const QUuid ENTITY_ITEM_DEFAULT_LAST_EDITED_BY = QUuid(); +const uint16_t ENTITY_ITEM_DEFAULT_PARENT_INDEX = -1; + const bool ENTITY_ITEM_DEFAULT_RELAY_PARENT_JOINTS = false; const bool ENTITY_ITEM_DEFAULT_CLONEABLE = false; diff --git a/libraries/entities/src/EntityItemPropertiesDocs.cpp b/libraries/entities/src/EntityItemPropertiesDocs.cpp new file mode 100644 index 00000000000..2e1c0013e3a --- /dev/null +++ b/libraries/entities/src/EntityItemPropertiesDocs.cpp @@ -0,0 +1,1005 @@ +// +// EntityItemPropertiesDocs.cpp +// libraries/entities/src +// +// Created by HifiExperiments on 7/24/24. +// Copyright 2024 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +/*@jsdoc + * Different entity types have different properties: some common to all entities (listed in the table) and some specific to + * each {@link Entities.EntityType|EntityType} (linked to below). + * + * @typedef {object} Entities.EntityProperties + * @property {Uuid} id - The ID of the entity. Read-only. + * @property {string} name="" - A name for the entity. Need not be unique. + * @property {Entities.EntityType} type - The entity's type. You cannot change the type of an entity after it's created. + * However, its value may switch among "Box", "Shape", and "Sphere" depending on + * changes to the shape property set for entities of these types. Read-only. + * + * @property {Entities.EntityHostType} entityHostType="domain" - How the entity is hosted and sent to others for display. + * The value can only be set at entity creation by one of the {@link Entities.addEntity} methods. Read-only. + * @property {boolean} avatarEntity=false - true if the entity is an {@link Entities.EntityHostType|avatar entity}, + * false if it isn't. The value is per the entityHostType property value, set at entity creation + * by one of the {@link Entities.addEntity} methods. Read-only. + * @property {boolean} clientOnly=false - A synonym for avatarEntity. Read-only. + * @property {boolean} localEntity=false - true if the entity is a {@link Entities.EntityHostType|local entity}, + * false if it isn't. The value is per the entityHostType property value, set at entity creation + * by one of the {@link Entities.addEntity} methods. Read-only. + * + * @property {Uuid} owningAvatarID=Uuid.NULL - The session ID of the owning avatar if avatarEntity is + * true, otherwise {@link Uuid(0)|Uuid.NULL}. Read-only. + * + * @property {number} created - When the entity was created, expressed as the number of microseconds since + * 1970-01-01T00:00:00 UTC. Read-only. + * @property {number} age - The age of the entity in seconds since it was created. Read-only. + * @property {string} ageAsText - The age of the entity since it was created, formatted as h hours m minutes s + * seconds. + * @property {number} lifetime=-1 - How long an entity lives for, in seconds, before being automatically deleted. A value of + * -1 means that the entity lives for ever. + * @property {number} lastEdited - When the entity was last edited, expressed as the number of microseconds since + * 1970-01-01T00:00:00 UTC. Read-only. + * @property {Uuid} lastEditedBy - The session ID of the avatar or agent that most recently created or edited the entity. + * Read-only. + * + * @property {boolean} locked=false - true if properties other than locked cannot be changed and the + * entity cannot be deleted, false if all properties can be changed and the entity can be deleted. + * @property {boolean} visible=true - true if the entity is rendered, false if it isn't. + * @property {boolean} canCastShadow=true - true if the entity can cast a shadow, false if it can't. + * Currently applicable only to {@link Entities.EntityProperties-Model|Model} and + * {@link Entities.EntityProperties-Shape|Shape} entities. Shadows are cast if inside a + * {@link Entities.EntityProperties-Zone|Zone} entity with castShadows enabled in its keyLight + * property. + * @property {boolean} isVisibleInSecondaryCamera=true - true if the entity is rendered in the secondary camera, + * false if it isn't. + * @property {Entities.RenderLayer} renderLayer="world" - The layer that the entity renders in. + * @property {Entities.PrimitiveMode} primitiveMode="solid" - How the entity's geometry is rendered. + * @property {boolean} ignorePickIntersection=false - true if {@link Picks} and {@link RayPick} ignore the entity, + * false if they don't. + * + * @property {Vec3} position=0,0,0 - The position of the entity in world coordinates. + * @property {Quat} rotation=0,0,0,1 - The orientation of the entity in world coordinates. + * @property {Vec3} registrationPoint=0.5,0.5,0.5 - The point in the entity that is set to the entity's position and is rotated + * about, range {@link Vec3(0)|Vec3.ZERO} – {@link Vec3(0)|Vec3.ONE}. A value of {@link Vec3(0)|Vec3.ZERO} is the + * entity's minimum x, y, z corner; a value of {@link Vec3(0)|Vec3.ONE} is the entity's maximum x, y, z corner. + * + * @property {Vec3} naturalPosition=0,0,0 - The center of the entity's unscaled mesh model if it has one, otherwise + * {@link Vec3(0)|Vec3.ZERO}. Read-only. + * @property {Vec3} naturalDimensions - The dimensions of the entity's unscaled mesh model or image if it has one, otherwise + * {@link Vec3(0)|Vec3.ONE}. Read-only. + * + * @property {Vec3} velocity=0,0,0 - The linear velocity of the entity in m/s with respect to world coordinates. + * @property {number} damping=0.39347 - How much the linear velocity of an entity slows down over time, range + * 0.01.0. A higher damping value slows down the entity more quickly. The default value + * is for an exponential decay timescale of 2.0s, where it takes 2.0s for the movement to slow to 1/e = 0.368 + * of its initial value. + * @property {Vec3} angularVelocity=0,0,0 - The angular velocity of the entity in rad/s with respect to its axes, about its + * registration point. + * @property {number} angularDamping=0.39347 - How much the angular velocity of an entity slows down over time, range + * 0.01.0. A higher damping value slows down the entity more quickly. The default value + * is for an exponential decay timescale of 2.0s, where it takes 2.0s for the movement to slow to 1/e = 0.368 + * of its initial value. + * + * @property {Vec3} gravity=0,0,0 - The acceleration due to gravity in m/s2 that the entity should move with, in + * world coordinates. Use a value of { x: 0, y: -9.8, z: 0 } to simulate Earth's gravity. Gravity is applied + * to an entity's motion only if its dynamic property is true. + *

If changing an entity's gravity from {@link Vec3(0)|Vec3.ZERO}, you need to give it a small + * velocity in order to kick off physics simulation.

+ * @property {Vec3} acceleration - The current, measured acceleration of the entity, in m/s2. + *

Deprecated: This property is deprecated and will be removed.

+ * @property {number} restitution=0.5 - The "bounciness" of an entity when it collides, range 0.0 – + * 0.99. The higher the value, the more bouncy. + * @property {number} friction=0.5 - How much an entity slows down when it's moving against another, range 0.0 + * – 10.0. The higher the value, the more quickly it slows down. Examples: 0.1 for ice, + * 0.9 for sandpaper. + * @property {number} density=1000 - The density of the entity in kg/m3, range 100 – + * 10000. Examples: 100 for balsa wood, 10000 for silver. The density is used in + * conjunction with the entity's bounding box volume to work out its mass in the application of physics. + * + * @property {boolean} collisionless=false - true if the entity shouldn't collide, false if it + * collides with items per its collisionMask property. + * @property {boolean} ignoreForCollisions - Synonym for collisionless. + * @property {CollisionMask} collisionMask=31 - What types of items the entity should collide with. + * @property {string} collidesWith="static,dynamic,kinematic,myAvatar,otherAvatar," - Synonym for collisionMask, + * in text format. + * @property {string} collisionSoundURL="" - The sound that's played when the entity experiences a collision. Valid file + * formats are per {@link SoundObject}. + * @property {boolean} dynamic=false - true if the entity's movement is affected by collisions, false + * if it isn't. + * @property {boolean} collisionsWillMove - A synonym for dynamic. + * + * @property {string} href="" - A "hifi://" directory services address that a user is teleported to when they click on the entity. + * @property {string} description="" - A description of the href property value. + * + * @property {string} userData="" - Used to store extra data about the entity in JSON format. + *

Warning: Other apps may also use this property, so make sure you handle data stored by other apps: + * edit only your bit and leave the rest of the data intact. You can use JSON.parse() to parse the string into + * a JavaScript object which you can manipulate the properties of, and use JSON.stringify() to convert the + * object into a string to put back in the property.

+ * + * @property {string} privateUserData="" - Like userData, but only accessible by server entity scripts, assignment + * client scripts, and users who have "Can Get and Set Private User Data" permissions in the domain. + * + * @property {string} script="" - The URL of the client entity script, if any, that is attached to the entity. + * @property {number} scriptTimestamp=0 - Used to indicate when the client entity script was loaded. Should be + * an integer number of milliseconds since midnight GMT on January 1, 1970 (e.g., as supplied by Date.now(). + * If you update the property's value, the script is re-downloaded and reloaded. This is how the "reload" + * button beside the "script URL" field in properties tab of the Create app works. + * @property {string} serverScripts="" - The URL of the server entity script, if any, that is attached to the entity. + * + * @property {Uuid} parentID=Uuid.NULL - The ID of the entity or avatar that the entity is parented to. A value of + * {@link Uuid(0)|Uuid.NULL} is used if the entity is not parented. + * @property {number} parentJointIndex=65535 - The joint of the entity or avatar that the entity is parented to. Use + * 65535 or -1 to parent to the entity or avatar's position and orientation rather than a joint. + * @property {Vec3} localPosition=0,0,0 - The position of the entity relative to its parent if the entity is parented, + * otherwise the same value as position. If the entity is parented to an avatar and is an avatar entity + * so that it scales with the avatar, this value remains the original local position value while the avatar scale changes. + * @property {Quat} localRotation=0,0,0,1 - The rotation of the entity relative to its parent if the entity is parented, + * otherwise the same value as rotation. + * @property {Vec3} localVelocity=0,0,0 - The velocity of the entity relative to its parent if the entity is parented, + * otherwise the same value as velocity. + * @property {Vec3} localAngularVelocity=0,0,0 - The angular velocity of the entity relative to its parent if the entity is + * parented, otherwise the same value as angularVelocity. + * @property {Vec3} localDimensions - The dimensions of the entity. If the entity is parented to an avatar and is an + * avatar entity so that it scales with the avatar, this value remains the original dimensions value while the + * avatar scale changes. + * + * @property {Entities.BoundingBox} boundingBox - The axis-aligned bounding box that tightly encloses the entity. + * Read-only. + * @property {AACube} queryAACube - The axis-aligned cube that determines where the entity lives in the entity server's octree. + * The cube may be considerably larger than the entity in some situations, e.g., when the entity is grabbed by an avatar: + * the position of the entity is determined through avatar mixer updates and so the AA cube is expanded in order to reduce + * unnecessary entity server updates. Scripts should not change this property's value. + * + * @property {string} actionData="" - Base-64 encoded compressed dump of the actions associated with the entity. This property + * is typically not used in scripts directly; rather, functions that manipulate an entity's actions update it, e.g., + * {@link Entities.addAction}. The size of this property increases with the number of actions. Because this property value + * has to fit within a Overte datagram packet, there is a limit to the number of actions that an entity can have; + * edits which would result in overflow are rejected. Read-only. + * @property {Entities.RenderInfo} renderInfo - Information on the cost of rendering the entity. Currently information is only + * provided for Model entities. Read-only. + * + * @property {boolean} cloneable=false - true if the domain or avatar entity can be cloned via + * {@link Entities.cloneEntity}, false if it can't be. + * @property {number} cloneLifetime=300 - The entity lifetime for clones created from this entity. + * @property {number} cloneLimit=0 - The total number of clones of this entity that can exist in the domain at any given time. + * @property {boolean} cloneDynamic=false - true if clones created from this entity will have their + * dynamic property set to true, false if they won't. + * @property {boolean} cloneAvatarEntity=false - true if clones created from this entity will be created as + * avatar entities, false if they won't be. + * @property {Uuid} cloneOriginID - The ID of the entity that this entity was cloned from. + * + * @property {Uuid[]} renderWithZones=[] - A list of entity IDs representing with which zones this entity should render. + * If it is empty, this entity will render normally. Otherwise, this entity will only render if your avatar is within + * one of the zones in this list. + * @property {BillboardMode} billboardMode="none" - Whether the entity is billboarded to face the camera. Use the rotation + * property to control which axis is facing you. + * @property {string[]} tags=[] - A set of tags describing this entity. + * + * @property {Entities.Grab} grab - The entity's grab-related properties. + * + * @property {MirrorMode} mirrorMode="none" - If this entity should render as a mirror (reflecting the view of the camera), + * a portal (reflecting the view through its portalExitID), or normally. + * @property {Uuid} portalExitID=Uuid.NULL - The ID of the entity that should act as the portal exit if the mirrorMode + * is set to portal. + * + * @comment The different entity types have additional properties as follows: + * @see {@link Entities.EntityProperties-Box|EntityProperties-Box} + * @see {@link Entities.EntityProperties-Gizmo|EntityProperties-Gizmo} + * @see {@link Entities.EntityProperties-Grid|EntityProperties-Grid} + * @see {@link Entities.EntityProperties-Image|EntityProperties-Image} + * @see {@link Entities.EntityProperties-Light|EntityProperties-Light} + * @see {@link Entities.EntityProperties-Line|EntityProperties-Line} + * @see {@link Entities.EntityProperties-Material|EntityProperties-Material} + * @see {@link Entities.EntityProperties-Model|EntityProperties-Model} + * @see {@link Entities.EntityProperties-ParticleEffect|EntityProperties-ParticleEffect} + * @see {@link Entities.EntityProperties-PolyLine|EntityProperties-PolyLine} + * @see {@link Entities.EntityProperties-PolyVox|EntityProperties-PolyVox} + * @see {@link Entities.EntityProperties-ProceduralParticleEffect|EntityProperties-ProceduralParticleEffect} + * @see {@link Entities.EntityProperties-Shape|EntityProperties-Shape} + * @see {@link Entities.EntityProperties-Sound|EntityProperties-Sound} + * @see {@link Entities.EntityProperties-Sphere|EntityProperties-Sphere} + * @see {@link Entities.EntityProperties-Text|EntityProperties-Text} + * @see {@link Entities.EntityProperties-Web|EntityProperties-Web} + * @see {@link Entities.EntityProperties-Zone|EntityProperties-Zone} + */ + +/*@jsdoc + * The "Box" {@link Entities.EntityType|EntityType} is the same as the "Shape" + * {@link Entities.EntityType|EntityType} except that its shape value is always set to "Cube" + * when the entity is created. If its shape property value is subsequently changed then the entity's + * type will be reported as "Sphere" if the shape is set to "Sphere", + * otherwise it will be reported as "Shape". + * + * @typedef {object} Entities.EntityProperties-Box + * @see {@link Entities.EntityProperties-Shape|EntityProperties-Shape} + */ + +/*@jsdoc + * The "Light" {@link Entities.EntityType|EntityType} adds local lighting effects. It has properties in addition + * to the common {@link Entities.EntityProperties|EntityProperties}. + * + * @typedef {object} Entities.EntityProperties-Light + * @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the entity. Surfaces outside these dimensions are not lit + * by the light. + * @property {Color} color=255,255,255 - The color of the light emitted. + * @property {number} intensity=1 - The brightness of the light. + * @property {number} falloffRadius=0.1 - The distance from the light's center at which intensity is reduced by 25%. + * @property {boolean} isSpotlight=false - true if the light is directional, emitting along the entity's + * local negative z-axis; false if the light is a point light which emanates in all directions. + * @property {number} exponent=0 - Affects the softness of the spotlight beam: the higher the value the softer the beam. + * @property {number} cutoff=1.57 - Affects the size of the spotlight beam: the higher the value the larger the beam. + * @example Create a spotlight pointing at the ground. + * Entities.addEntity({ + * type: "Light", + * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -4 })), + * rotation: Quat.fromPitchYawRollDegrees(-75, 0, 0), + * dimensions: { x: 5, y: 5, z: 5 }, + * intensity: 100, + * falloffRadius: 0.3, + * isSpotlight: true, + * exponent: 20, + * cutoff: 30, + * lifetime: 300 // Delete after 5 minutes. + * }); + */ + +/*@jsdoc + * The "Line" {@link Entities.EntityType|EntityType} draws thin, straight lines between a sequence of two or more + * points. It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. + *

Deprecated: Use {@link Entities.EntityProperties-PolyLine|PolyLine} entities instead.

+ * + * @typedef {object} Entities.EntityProperties-Line + * @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the entity. Must be sufficient to contain all the + * linePoints. + * @property {Vec3[]} linePoints=[]] - The sequence of points to draw lines between. The values are relative to the entity's + * position. A maximum of 70 points can be specified. The property's value is set only if all the linePoints + * lie within the entity's dimensions. + * @property {Color} color=255,255,255 - The color of the line. + * @example Draw lines in a "V". + * var entity = Entities.addEntity({ + * type: "Line", + * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.75, z: -5 })), + * rotation: MyAvatar.orientation, + * dimensions: { x: 2, y: 2, z: 1 }, + * linePoints: [ + * { x: -1, y: 1, z: 0 }, + * { x: 0, y: -1, z: 0 }, + * { x: 1, y: 1, z: 0 }, + * ], + * color: { red: 255, green: 0, blue: 0 }, + * lifetime: 300 // Delete after 5 minutes. + * }); + */ + +/*@jsdoc + * The "Material" {@link Entities.EntityType|EntityType} modifies existing materials on entities and avatars. It + * has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. + *

To apply a material to an entity, set the material entity's parentID property to the entity ID. + * To apply a material to an avatar, set the material entity's parentID property to the avatar's session UUID. + * To apply a material to your avatar such that it persists across domains and log-ins, create the material as an avatar entity + * by setting the entityHostType parameter in {@link Entities.addEntity} to "avatar" and set the + * entity's parentID property to MyAvatar.SELF_ID. + * Material entities render as non-scalable spheres if they don't have their parent set.

+ * + * @typedef {object} Entities.EntityProperties-Material + * @property {Vec3} dimensions=0.1,0.1,0.1 - Used when materialMappingMode == "projected". + * @property {string} materialURL="" - URL to a {@link Entities.MaterialResource|MaterialResource}. Alternatively, set the + * property value to "materialData" to use the materialData property for the + * {@link Entities.MaterialResource|MaterialResource} values. If you append "#name" to the URL, the material + * with that name will be applied to the entity. You can also use the ID of another Material entity as the URL, in which + * case this material will act as a copy of that material, with its own unique material transform, priority, etc. + * @property {string} materialData="" - Used to store {@link Entities.MaterialResource|MaterialResource} data as a JSON string. + * You can use JSON.parse() to parse the string into a JavaScript object which you can manipulate the + * properties of, and use JSON.stringify() to convert the object into a string to put in the property. + * @property {number} priority=0 - The priority for applying the material to its parent. Only the highest priority material is + * applied, with materials of the same priority randomly assigned. Materials that come with the model have a priority of + * 0. + * @property {string} parentMaterialName="0" - Selects the mesh part or parts within the parent to which to apply the material. + * If in the format "mat::string", all mesh parts with material name "string" are replaced. + * If "all", then all mesh parts are replaced. + * Otherwise the property value is parsed as an unsigned integer, specifying the mesh part index to modify. + *

If the string represents an array (starts with "[" and ends with "]"), the string is split + * at each "," and each element parsed as either a number or a string if it starts with "mat::". + * For example, "[0,1,mat::string,mat::string2]" will replace mesh parts 0 and 1, and any mesh parts with + * material "string" or "string2". Do not put spaces around the commas. Invalid values are parsed + * to 0.

+ * @property {string} materialMappingMode="uv" - How the material is mapped to the entity. Either "uv" or + * "projected". In "uv" mode, the material is evaluated within the UV space of the mesh it is + * applied to. In "projected" mode, the 3D transform (position, rotation, and dimensions) of the Material + * entity is used to evaluate the texture coordinates for the material. + * @property {Vec2} materialMappingPos=0,0 - Offset position in UV-space of the top left of the material, range + * { x: 0, y: 0 }{ x: 1, y: 1 }. + * @property {Vec2} materialMappingScale=1,1 - How much to scale the material within the parent's UV-space. + * @property {number} materialMappingRot=0 - How much to rotate the material within the parent's UV-space, in degrees. + * @property {boolean} materialRepeat=true - true if the material repeats, false if it doesn't. If + * false, fragments outside of texCoord 0 – 1 will be discarded. Works in both "uv" and + * "projected" modes. + * @example Color a sphere using a Material entity. + * var entityID = Entities.addEntity({ + * type: "Sphere", + * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })), + * dimensions: { x: 1, y: 1, z: 1 }, + * color: { red: 128, green: 128, blue: 128 }, + * lifetime: 300 // Delete after 5 minutes. + * }); + * + * var materialID = Entities.addEntity({ + * type: "Material", + * parentID: entityID, + * materialURL: "materialData", + * priority: 1, + * materialData: JSON.stringify({ + * materialVersion: 1, + * materials: { + * // Value overrides entity's "color" property. + * albedo: [1.0, 1.0, 0] // Yellow + * } + * }) + * }); + */ + +/*@jsdoc + * The "Model" {@link Entities.EntityType|EntityType} displays a glTF, FBX, or OBJ model. When adding an entity, + * if no dimensions value is specified then the model is automatically sized to its + * {@link Entities.EntityProperties|naturalDimensions}. It has properties in addition to the common + * {@link Entities.EntityProperties|EntityProperties}. + * + * @typedef {object} Entities.EntityProperties-Model + * @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the entity. When adding an entity, if no dimensions + * value is specified then the model is automatically sized to its + * {@link Entities.EntityProperties|naturalDimensions}. + * @property {string} modelURL="" - The URL of the glTF, FBX, or OBJ model. glTF models may be in JSON or binary format + * (".gltf" or ".glb" URLs respectively). Baked models' URLs have ".baked" before the file type. Model files may also be + * compressed in GZ format, in which case the URL ends in ".gz". + * @property {Vec3} modelScale - The scale factor applied to the model's dimensions. + *

Deprecated: This property is deprecated and will be removed.

+ * @property {string} blendshapeCoefficients - A JSON string of a map of blendshape names to values. Only stores set values. + * When editing this property, only coefficients that you are editing will change; it will not explicitly reset other + * coefficients. + * @property {boolean} useOriginalPivot=false - If false, the model will be centered based on its content, + * ignoring any offset in the model itself. If true, the model will respect its original offset. Currently, + * only pivots relative to {x: 0, y: 0, z: 0} are supported. + * @property {number} loadPriority=0.0 - If 0, the model download will be prioritized based on distance, size, and + * other factors, and assigned a priority automatically between 0 and PI / 2. Otherwise, the + * download will be ordered based on the set loadPriority. + * @property {string} textures="" - A JSON string of texture name, URL pairs used when rendering the model in place of the + * model's original textures. Use a texture name from the originalTextures property to override that texture. + * Only the texture names and URLs to be overridden need be specified; original textures are used where there are no + * overrides. You can use JSON.stringify() to convert a JavaScript object of name, URL pairs into a JSON + * string. + * @property {string} originalTextures="{}" - A JSON string of texture name, URL pairs used in the model. The property value is + * filled in after the entity has finished rezzing (i.e., textures have loaded). You can use JSON.parse() to + * parse the JSON string into a JavaScript object of name, URL pairs. Read-only. + * @property {Color} color=255,255,255 - Currently not used. + * + * @property {ShapeType} shapeType="none" - The shape of the collision hull used if collisions are enabled. + * @property {string} compoundShapeURL="" - The model file to use for the compound shape if shapeType is + * "compound". + * + * @property {Entities.AnimationProperties} animation - An animation to play on the model. + * + * @property {Quat[]} jointRotations=[]] - Joint rotations applied to the model; [] if none are applied or the + * model hasn't loaded. The array indexes are per {@link Entities.getJointIndex|getJointIndex}. Rotations are relative to + * each joint's parent. + *

Joint rotations can be set by {@link Entities.setLocalJointRotation|setLocalJointRotation} and similar functions, or + * by setting the value of this property. If you set a joint rotation using this property, you also need to set the + * corresponding jointRotationsSet value to true.

+ * @property {boolean[]} jointRotationsSet=[]] - true values for joints that have had rotations applied, + * false otherwise; [] if none are applied or the model hasn't loaded. The array indexes are per + * {@link Entities.getJointIndex|getJointIndex}. + * @property {Vec3[]} jointTranslations=[]] - Joint translations applied to the model; [] if none are applied or + * the model hasn't loaded. The array indexes are per {@link Entities.getJointIndex|getJointIndex}. Translations are + * relative to each joint's parent. + *

Joint translations can be set by {@link Entities.setLocalJointTranslation|setLocalJointTranslation} and similar + * functions, or by setting the value of this property. If you set a joint translation using this property you also need to + * set the corresponding jointTranslationsSet value to true.

+ * @property {boolean[]} jointTranslationsSet=[]] - true values for joints that have had translations applied, + * false otherwise; [] if none are applied or the model hasn't loaded. The array indexes are per + * {@link Entities.getJointIndex|getJointIndex}. + * @property {boolean} relayParentJoints=false - true if when the entity is parented to an avatar, the avatar's + * joint rotations are applied to the entity's joints; false if a parent avatar's joint rotations are not + * applied to the entity's joints. + * @property {boolean} groupCulled=false - true if the mesh parts of the model are LOD culled as a group, + * false if separate mesh parts are LOD culled individually. + * + * @example Rez a cowboy hat. + * var entity = Entities.addEntity({ + * type: "Model", + * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.75, z: -2 })), + * rotation: MyAvatar.orientation, + * modelURL: "https://apidocs.overte.org/examples/cowboy-hat.fbx", + * dimensions: { x: 0.8569, y: 0.3960, z: 1.0744 }, + * lifetime: 300 // Delete after 5 minutes. + * }); + */ + +/*@jsdoc + * The "ParticleEffect" {@link Entities.EntityType|EntityType} displays a particle system that can be used to + * simulate things such as fire, smoke, snow, magic spells, etc. The particles emanate from an ellipsoid or part thereof. + * It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. + * + * @typedef {object} Entities.EntityProperties-ParticleEffect + * @property {boolean} isEmitting=true - true if particles are being emitted, false if they aren't. + * @property {number} maxParticles=1000 - The maximum number of particles to render at one time. Older particles are deleted if + * necessary when new ones are created. + * @property {number} lifespan=3s - How long, in seconds, each particle lives. + * @property {number} emitRate=15 - The number of particles per second to emit. + * @property {number} emitSpeed=5 - The speed, in m/s, that each particle is emitted at. + * @property {number} speedSpread=1 - The spread in speeds at which particles are emitted at. For example, if + * emitSpeed == 5 and speedSpread == 1, particles will be emitted with speeds in the range + * 46m/s. + * @property {Vec3} emitAcceleration=0,-9.8,0 - The acceleration that is applied to each particle during its lifetime. The + * default is Earth's gravity value. + * @property {Vec3} accelerationSpread=0,0,0 - The spread in accelerations that each particle is given. For example, if + * emitAccelerations == {x: 0, y: -9.8, z: 0} and accelerationSpread == + * {x: 0, y: 1, z: 0}, each particle will have an acceleration in the range {x: 0, y: -10.8, z: 0} + * – {x: 0, y: -8.8, z: 0}. + * @property {Vec3} dimensions - The dimensions of the particle effect, i.e., a bounding box containing all the particles + * during their lifetimes, assuming that emitterShouldTrail == false. Read-only. + * @property {boolean} emitterShouldTrail=false - true if particles are "left behind" as the emitter moves, + * false if they stay within the entity's dimensions. + * + * @property {Quat} emitOrientation=-0.707,0,0,0.707 - The orientation of particle emission relative to the entity's axes. By + * default, particles emit along the entity's local z-axis, and azimuthStart and azimuthFinish + * are relative to the entity's local x-axis. The default value is a rotation of -90 degrees about the local x-axis, i.e., + * the particles emit vertically. + * + * @property {ShapeType} shapeType="ellipsoid" - The shape from which particles are emitted. + * @property {string} compoundShapeURL="" - The model file to use for the compound shape if shapeType == + * "compound". + * @property {Vec3} emitDimensions=0,0,0 - The dimensions of the shape from which particles are emitted. + * @property {number} emitRadiusStart=1 - The starting radius within the shape at which particles start being emitted; + * range 0.01.0 for the center to the surface, respectively. + * Particles are emitted from the portion of the shape that lies between emitRadiusStart and the + * shape's surface. + * @property {number} polarStart=0 - The angle in radians from the entity's local z-axis at which particles start being emitted + * within the shape; range 0Math.PI. Particles are emitted from the portion of the + * shape that lies between polarStart and polarFinish. Only used if shapeType is + * "ellipsoid" or "sphere". + * @property {number} polarFinish=0 - The angle in radians from the entity's local z-axis at which particles stop being emitted + * within the shape; range 0Math.PI. Particles are emitted from the portion of the + * shape that lies between polarStart and polarFinish. Only used if shapeType is + * "ellipsoid" or "sphere". + * @property {number} azimuthStart=-Math.PI - The angle in radians from the entity's local x-axis about the entity's local + * z-axis at which particles start being emitted; range -Math.PIMath.PI. Particles are + * emitted from the portion of the shape that lies between azimuthStart and azimuthFinish. + * Only used if shapeType is "ellipsoid", "sphere", or "circle". + * @property {number} azimuthFinish=Math.PI - The angle in radians from the entity's local x-axis about the entity's local + * z-axis at which particles stop being emitted; range -Math.PIMath.PI. Particles are + * emitted from the portion of the shape that lies between azimuthStart and azimuthFinish. + * Only used if shapeType is "ellipsoid", "sphere", or "circle". + * + * @property {string} textures="" - The URL of a JPG or PNG image file to display for each particle. If you want transparency, + * use PNG format. + * @property {number} particleRadius=0.025 - The radius of each particle at the middle of its life. + * @property {number} radiusStart=null - The radius of each particle at the start of its life. If null, the + * particleRadius value is used. + * @property {number} radiusFinish=null - The radius of each particle at the end of its life. If null, the + * particleRadius value is used. + * @property {number} radiusSpread=0 - The spread in radius that each particle is given. For example, if + * particleRadius == 0.5 and radiusSpread == 0.25, each particle will have a radius in the range + * 0.250.75. + * @property {Color} color=255,255,255 - The color of each particle at the middle of its life. + * @property {ColorFloat} colorStart=null,null,null - The color of each particle at the start of its life. If any of the + * component values are undefined, the color value is used. + * @property {ColorFloat} colorFinish=null,null,null - The color of each particle at the end of its life. If any of the + * component values are undefined, the color value is used. + * @property {Color} colorSpread=0,0,0 - The spread in color that each particle is given. For example, if + * color == {red: 100, green: 100, blue: 100} and colorSpread == + * {red: 10, green: 25, blue: 50}, each particle will have a color in the range + * {red: 90, green: 75, blue: 50}{red: 110, green: 125, blue: 150}. + * @property {number} alpha=1 - The opacity of each particle at the middle of its life. + * @property {number} alphaStart=null - The opacity of each particle at the start of its life. If null, the + * alpha value is used. + * @property {number} alphaFinish=null - The opacity of each particle at the end of its life. If null, the + * alpha value is used. + * @property {number} alphaSpread=0 - The spread in alpha that each particle is given. For example, if + * alpha == 0.5 and alphaSpread == 0.25, each particle will have an alpha in the range + * 0.250.75. + * @property {Entities.Pulse} pulse - Color and alpha pulse. + *

Deprecated: This property is deprecated and will be removed.

+ * @property {number} particleSpin=0 - The rotation of each particle at the middle of its life, range -2 * Math.PI + * – 2 * Math.PI radians. + * @property {number} spinStart=null - The rotation of each particle at the start of its life, range -2 * Math.PI + * – 2 * Math.PI radians. If null, the particleSpin value is used. + * @property {number} spinFinish=null - The rotation of each particle at the end of its life, range -2 * Math.PI + * – 2 * Math.PI radians. If null, the particleSpin value is used. + * @property {number} spinSpread=0 - The spread in spin that each particle is given, range 0 – + * 2 * Math.PI radians. For example, if particleSpin == Math.PI and + * spinSpread == Math.PI / 2, each particle will have a rotation in the range Math.PI / 2 – + * 3 * Math.PI / 2. + * @property {boolean} rotateWithEntity=false - true if the particles' rotations are relative to the entity's + * instantaneous rotation, false if they're relative to world coordinates. If true with + * particleSpin == 0, the particles keep oriented per the entity's orientation. + * + * @example Create a ball of green smoke. + * particles = Entities.addEntity({ + * type: "ParticleEffect", + * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -4 })), + * lifespan: 5, + * emitRate: 10, + * emitSpeed: 0.02, + * speedSpread: 0.01, + * emitAcceleration: { x: 0, y: 0.02, z: 0 }, + * polarFinish: Math.PI, + * textures: "https://content.overte.org/Bazaar/Assets/Textures/Defaults/Interface/default_particle.png", + * particleRadius: 0.1, + * color: { red: 0, green: 255, blue: 0 }, + * alphaFinish: 0, + * lifetime: 300 // Delete after 5 minutes. + * }); + */ + +/*@jsdoc + * The "PolyLine" {@link Entities.EntityType|EntityType} draws textured, straight lines between a sequence of + * points. It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. + * + * @typedef {object} Entities.EntityProperties-PolyLine + * @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the entity, i.e., the size of the bounding box that contains the + * lines drawn. Read-only. + * @property {Vec3[]} linePoints=[]] - The sequence of points to draw lines between. The values are relative to the entity's + * position. A maximum of 70 points can be specified. + * @property {Vec3[]} normals=[]] - The normal vectors for the line's surface at the linePoints. The values are + * relative to the entity's orientation. Must be specified in order for the entity to render. + * @property {number[]} strokeWidths=[]] - The widths, in m, of the line at the linePoints. Must be specified in + * order for the entity to render. + * @property {Vec3[]} strokeColors=[]] - The base colors of each point, with values in the range 0.0,0.0,0.0 + * – 1.0,1.0,1.0. These colors are multiplied with the color of the texture. If there are more line + * points than stroke colors, the color property value is used for the remaining points. + *

Warning: The ordinate values are in the range 0.01.0.

+ * @property {Color} color=255,255,255 - Used as the color for each point if strokeColors doesn't have a value for + * the point. + * @property {string} textures="" - The URL of a JPG or PNG texture to use for the lines. If you want transparency, use PNG + * format. + * @property {boolean} isUVModeStretch=true - true if the texture is stretched to fill the whole line, + * false if the texture repeats along the line. + * @property {boolean} glow=false - true if the opacity of the strokes drops off away from the line center, + * false if it doesn't. + * @property {boolean} faceCamera=false - true if each line segment rotates to face the camera, false + * if they don't. + * @example Draw a textured "V". + * var entity = Entities.addEntity({ + * type: "PolyLine", + * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.75, z: -5 })), + * rotation: MyAvatar.orientation, + * linePoints: [ + * { x: -1, y: 0.5, z: 0 }, + * { x: 0, y: 0, z: 0 }, + * { x: 1, y: 0.5, z: 0 } + * ], + * normals: [ + * { x: 0, y: 0, z: 1 }, + * { x: 0, y: 0, z: 1 }, + * { x: 0, y: 0, z: 1 } + * ], + * strokeWidths: [ 0.1, 0.1, 0.1 ], + * color: { red: 255, green: 0, blue: 0 }, // Use just the red channel from the image. + * textures: "https://hifi-content/DomainContent/Toybox/flowArts/trails.png", + * isUVModeStretch: true, + * lifetime: 300 // Delete after 5 minutes. + * }); + */ + +/*@jsdoc + * The "PolyVox" {@link Entities.EntityType|EntityType} displays a set of textured voxels. + * It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. + * If you have two or more neighboring PolyVox entities of the same size abutting each other, you can display them as joined by + * configuring their voxelSurfaceStyle and various neighbor ID properties. + *

PolyVox entities uses a library from Volumes of Fun. Their + * library documentation may be useful to read.

+ * + * @typedef {object} Entities.EntityProperties-PolyVox + * @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the entity. + * @property {Vec3} voxelVolumeSize=32,32,32 - Integer number of voxels along each axis of the entity, in the range + * 1,1,1 to 128,128,128. The dimensions of each voxel is + * dimensions / voxelVolumesize. + * @property {string} voxelData="ABAAEAAQAAAAHgAAEAB42u3BAQ0AAADCoPdPbQ8HFAAAAPBuEAAAAQ==" - Base-64 encoded compressed dump of + * the PolyVox data. This property is typically not used in scripts directly; rather, functions that manipulate a PolyVox + * entity update it. + *

The size of this property increases with the size and complexity of the PolyVox entity, with the size depending on how + * the particular entity's voxels compress. Because this property value has to fit within a Overte datagram packet, + * there is a limit to the size and complexity of a PolyVox entity; edits which would result in an overflow are rejected.

+ * @property {Entities.PolyVoxSurfaceStyle} voxelSurfaceStyle=2 - The style of rendering the voxels' surface and how + * neighboring PolyVox entities are joined. + * @property {string} xTextureURL="" - The URL of the texture to map to surfaces perpendicular to the entity's local x-axis. + * JPG or PNG format. If no texture is specified the surfaces display white. + * @property {string} yTextureURL="" - The URL of the texture to map to surfaces perpendicular to the entity's local y-axis. + * JPG or PNG format. If no texture is specified the surfaces display white. + * @property {string} zTextureURL="" - The URL of the texture to map to surfaces perpendicular to the entity's local z-axis. + * JPG or PNG format. If no texture is specified the surfaces display white. + * @property {Uuid} xNNeighborID=Uuid.NULL - The ID of the neighboring PolyVox entity in the entity's -ve local x-axis + * direction, if you want them joined. Set to {@link Uuid(0)|Uuid.NULL} if there is none or you don't want to join them. + * @property {Uuid} yNNeighborID=Uuid.NULL - The ID of the neighboring PolyVox entity in the entity's -ve local y-axis + * direction, if you want them joined. Set to {@link Uuid(0)|Uuid.NULL} if there is none or you don't want to join them. + * @property {Uuid} zNNeighborID=Uuid.NULL - The ID of the neighboring PolyVox entity in the entity's -ve local z-axis + * direction, if you want them joined. Set to {@link Uuid(0)|Uuid.NULL} if there is none or you don't want to join them. + * @property {Uuid} xPNeighborID=Uuid.NULL - The ID of the neighboring PolyVox entity in the entity's +ve local x-axis + * direction, if you want them joined. Set to {@link Uuid(0)|Uuid.NULL} if there is none or you don't want to join them. + * @property {Uuid} yPNeighborID=Uuid.NULL - The ID of the neighboring PolyVox entity in the entity's +ve local y-axis + * direction, if you want them joined. Set to {@link Uuid(0)|Uuid.NULL} if there is none or you don't want to join them. + * @property {Uuid} zPNeighborID=Uuid.NULL - The ID of the neighboring PolyVox entity in the entity's +ve local z-axis + * direction, if you want them joined. Set to {@link Uuid(0)|Uuid.NULL} if there is none or you don't want to join them. + * @example Create a textured PolyVox sphere. + * var position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -8 })); + * var texture = "http://public.highfidelity.com/cozza13/tuscany/Concrete2.jpg"; + * var polyVox = Entities.addEntity({ + * type: "PolyVox", + * position: position, + * dimensions: { x: 2, y: 2, z: 2 }, + * voxelVolumeSize: { x: 16, y: 16, z: 16 }, + * voxelSurfaceStyle: 2, + * xTextureURL: texture, + * yTextureURL: texture, + * zTextureURL: texture, + * lifetime: 300 // Delete after 5 minutes. + * }); + * Entities.setVoxelSphere(polyVox, position, 0.8, 255); + */ + +/*@jsdoc + * The "ProceduralParticleEffect" {@link Entities.EntityType|EntityType} displays a particle system that can be + * used to simulate things such as fire, smoke, snow, magic spells, etc. The particles are fully controlled by the provided + * update and rendering shaders on the GPU. + * It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. + * + * @typedef {object} Entities.EntityProperties-ProceduralParticleEffect + * @property {number} numParticles=10000 - The number of particles to render. + * @property {number} numTrianglesPerParticle=1 - The number of triangles to render per particle. By default, these triangles + * still need to be positioned in the particleRenderData vertex shader. + * @property {number} numUpdateProps=0 - The number of persistent Vec4 values stored per particle and updated once per frame. + * These can be modified in the particleUpdateData fragment shader and read in the + * particleRenderData vertex/fragment shaders. + * @property {boolean} particleTransparent=false - Whether the particles should render as transparent (with additive blending) + * or opaque. + * @property {ProceduralData} particleUpdateData="" - Used to store {@link ProceduralData} data as a JSON string to control + * per-particle updates if numUpdateProps > 0. You can use JSON.parse() to parse the string + * into a JavaScript object which you can manipulate the properties of, and use JSON.stringify() to convert + * the object into a string to put in the property. + * @property {ProceduralData} particleRenderData="" - Used to store {@link ProceduralData} data as a JSON string to control + * per-particle rendering. You can use JSON.parse() to parse the string into a JavaScript object which you + * can manipulate the properties of, and use JSON.stringify() to convert the object into a string to put in + * the property. + * + * @example A cube of oscillating, unlit, billboarded triangles, with the oscillation in the update (computed once per particle instead of once per vertex). + * particles = Entities.addEntity({ + * type: "ProceduralParticleEffect", + * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -4 })), + * dimensions: 3, + * numParticles: 10000, + * numTrianglesPerParticle: 1, + * numUpdateProps: 1, + * particleUpdateData: JSON.stringify({ + * version: 1.0, + * fragmentShaderURL: "https://gist.githubusercontent.com/HifiExperiments/9049fb4a8dcd2c1401ff4321103dce16/raw/4f9474ed82c66c1f94c1055d2724af808cd7aace/proceduralParticleUpdate.fs", + * }), + * particleRenderData: JSON.stringify({ + * version: 1.0, + * vertexShaderURL: "https://gist.github.com/HifiExperiments/5dda24e28e7de1719e3a594d81306343/raw/92e0c5b82a9fa87685064cdbab92ed0c16f49f94/proceduralParticle2.vs", + * fragmentShaderURL: "https://gist.github.com/HifiExperiments/7def54504362c7bc79b5c85cd515b98b/raw/93b3828c2ec66b12b789a625dd141f533c595ede/proceduralParticle.fs", + * uniforms: { + * radius: 0.03 + * } + * }), + * lifetime: 300 // Delete after 5 minutes. + * }); + */ + +/*@jsdoc + * The "Shape" {@link Entities.EntityType|EntityType} displays an entity of a specified shape. + * It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. + * + * @typedef {object} Entities.EntityProperties-Shape + * @property {Entities.Shape} shape="Sphere" - The shape of the entity. + * @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the entity. + * @property {Color} color=255,255,255 - The color of the entity. + * @property {number} alpha=1 - The opacity of the entity, range 0.01.0. + * @property {boolean} unlit=false - true if the entity is unaffected by lighting, false if it is lit + * by the key light and local lights. + * @property {Entities.Pulse} pulse - Color and alpha pulse. + *

Deprecated: This property is deprecated and will be removed.

+ * @example Create a cylinder. + * var shape = Entities.addEntity({ + * type: "Shape", + * shape: "Cylinder", + * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })), + * dimensions: { x: 0.4, y: 0.6, z: 0.4 }, + * lifetime: 300 // Delete after 5 minutes. + * }); + */ + +/*@jsdoc + * The "Sound" {@link Entities.EntityType|EntityType} plays a sound from a URL. It has properties in addition to + * the common {@link Entities.EntityProperties|EntityProperties}. + * + * @typedef {object} Entities.EntityProperties-Sound + * @property {string} soundURL="" - The URL of the sound to play, as a wav, mp3, or raw file. Supports stereo and ambisonic. + * Note: ambisonic sounds can only play as localOnly. + * @property {boolean} playing=true - Whether or not the sound should play. + * @property {number} volume=1.0 - The volume of the sound, from 0 to 1. + * @property {number} pitch=1.0 - The relative sample rate at which to resample the sound, within +/- 2 octaves. + * @property {number} timeOffset=0.0 - The time (in seconds) at which to start playback within the sound file. If looping, + * this only affects the first loop. + * @property {boolean} loop=true - Whether or not to loop the sound. + * @property {boolean} positional=true - Whether or not the volume of the sound should decay with distance. + * @property {boolean} localOnly=false - Whether or not the sound should play locally for everyone (unsynced), or synchronously + * for everyone via the Entity Mixer. + * @example Create a Sound entity. + * var entity = Entities.addEntity({ + * type: "Sound", + * soundURL: "https://themushroomkingdom.net/sounds/wav/lm/lm_gold_mouse.wav", + * positional: true, + * volume: 0.75, + * localOnly: true, + * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.75, z: -4 })), + * rotation: MyAvatar.orientation, + * lifetime: 300 // Delete after 5 minutes. + * }); + */ + +/*@jsdoc + * The "Sphere" {@link Entities.EntityType|EntityType} is the same as the "Shape" + * {@link Entities.EntityType|EntityType} except that its shape value is always set to "Sphere" + * when the entity is created. If its shape property value is subsequently changed then the entity's + * type will be reported as "Box" if the shape is set to "Cube", + * otherwise it will be reported as "Shape". + * + * @typedef {object} Entities.EntityProperties-Sphere + * @see {@link Entities.EntityProperties-Shape|EntityProperties-Shape} + */ + +/*@jsdoc + * The "Text" {@link Entities.EntityType|EntityType} displays a 2D rectangle of text in the domain. + * It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. + * + * @typedef {object} Entities.EntityProperties-Text + * @property {Vec3} dimensions=0.1,0.1,0.01 - The dimensions of the entity. + * @property {string} text="" - The text to display on the face of the entity. Text wraps if necessary to fit. New lines can be + * created using \n. Overflowing lines are not displayed. + * @property {number} lineHeight=0.1 - The height of each line of text (thus determining the font size). + * @property {Color} textColor=255,255,255 - The color of the text. + * @property {number} textAlpha=1.0 - The opacity of the text. + * @property {Color} backgroundColor=0,0,0 - The color of the background rectangle. + * @property {number} backgroundAlpha=1.0 - The opacity of the background. + * @property {Entities.Pulse} pulse - Color and alpha pulse. + *

Deprecated: This property is deprecated and will be removed.

+ * @property {number} leftMargin=0.0 - The left margin, in meters. + * @property {number} rightMargin=0.0 - The right margin, in meters. + * @property {number} topMargin=0.0 - The top margin, in meters. + * @property {number} bottomMargin=0.0 - The bottom margin, in meters. + * @property {boolean} unlit=false - true if the entity is unaffected by lighting, false if it is lit + * by the key light and local lights. + * @property {string} font="" - The font to render the text with. It can be one of the following: "Courier", + * "Inconsolata", "Roboto", "Timeless", or a path to a PNG MTSDF .arfont file generated + * by the msdf-atlas-gen tool (https://github.com/Chlumsky/msdf-atlas-gen). + * @property {Entities.TextEffect} textEffect="none" - The effect that is applied to the text. + * @property {Color} textEffectColor=255,255,255 - The color of the effect. + * @property {number} textEffectThickness=0.2 - The magnitude of the text effect, range 0.00.5. + * @property {Entities.TextAlignment} alignment="left" - How the text is horizontally aligned against its background. + * @property {Entities.TextVerticalAlignment} verticalAlignment="top" - How the text is vertically aligned against its background. + * @property {boolean} faceCamera - true if billboardMode is "yaw", false + * if it isn't. Setting this property to false sets the billboardMode to "none". + *

Deprecated: This property is deprecated and will be removed.

+ * @property {boolean} isFacingAvatar - true if billboardMode is "full", + * false if it isn't. Setting this property to false sets the billboardMode to + * "none". + *

Deprecated: This property is deprecated and will be removed.

+ * @example Create a text entity. + * var text = Entities.addEntity({ + * type: "Text", + * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })), + * dimensions: { x: 0.6, y: 0.3, z: 0.01 }, + * lineHeight: 0.12, + * text: "Hello\nthere!", + * billboardMode: "yaw", + * lifetime: 300 // Delete after 5 minutes. + * }); + */ + +/*@jsdoc + * The "Web" {@link Entities.EntityType|EntityType} displays a browsable web page. Each user views their own copy + * of the web page: if one user navigates to another page on the entity, other users do not see the change; if a video is being + * played, users don't see it in sync. Internally, a Web entity is rendered as a non-repeating, upside down texture, so additional + * transformations may be necessary if you reference a Web entity texture by UUID. It has properties in addition to the common + * {@link Entities.EntityProperties|EntityProperties}. + * + * @typedef {object} Entities.EntityProperties-Web + * @property {Vec3} dimensions=0.1,0.1,0.01 - The dimensions of the entity. + * @property {string} sourceUrl="" - The URL of the web page to display. This value does not change as you or others navigate + * on the Web entity. + * @property {Color} color=255,255,255 - The color of the web surface. This color tints the web page displayed: the pixel + * colors on the web page are multiplied by the property color. For example, a value of + * { red: 255, green: 0, blue: 0 } lets only the red channel of pixels' colors through. + * @property {number} alpha=1 - The opacity of the web surface. + * @property {Entities.Pulse} pulse - Color and alpha pulse. + *

Deprecated: This property is deprecated and will be removed.

+ * @property {boolean} faceCamera - true if billboardMode is "yaw", false + * if it isn't. Setting this property to false sets the billboardMode to "none". + *

Deprecated: This property is deprecated and will be removed.

+ * @property {boolean} isFacingAvatar - true if billboardMode is "full", + * false if it isn't. Setting this property to false sets the billboardMode to + * "none". + *

Deprecated: This property is deprecated and will be removed.

+ * @property {number} dpi=30 - The resolution to display the page at, in dots per inch. If you convert this to dots per meter + * (multiply by 1 / 0.0254 = 39.3701) then multiply dimensions.x and dimensions.y by that value + * you get the resolution in pixels. + * @property {string} scriptURL="" - The URL of a JavaScript file to inject into the web page. + * @property {number} maxFPS=10 - The maximum update rate for the web content, in frames/second. + * @property {WebInputMode} inputMode="touch" - The user input mode to use. + * @property {boolean} wantsKeyboardFocus=true - true if the entity should capture keyboard focus, false if it + * shouldn't. + * @property {boolean} showKeyboardFocusHighlight=true - true if the entity is highlighted when it has keyboard + * focus, false if it isn't. + * @property {boolean} useBackground=true - true if the web entity should have a background, + * false if the web entity's background should be transparent. The webpage must have CSS properties for transparency set + * on the background-color for this property to have an effect. + * @property {string} userAgent - The user agent for the web entity to use when visiting web pages. + * Default value: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) + * Chrome/69.0.3497.113 Mobile Safari/537.36 + * @example Create a Web entity displaying at 1920 x 1080 resolution. + * var METERS_TO_INCHES = 39.3701; + * var entity = Entities.addEntity({ + * type: "Web", + * sourceUrl: "https://overte.org/", + * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.75, z: -4 })), + * rotation: MyAvatar.orientation, + * dimensions: { + * x: 3, + * y: 3 * 1080 / 1920, + * z: 0.01 + * }, + * dpi: 1920 / (3 * METERS_TO_INCHES), + * lifetime: 300 // Delete after 5 minutes. + * }); + */ + +/*@jsdoc + * The "Zone" {@link Entities.EntityType|EntityType} is a volume of lighting effects and avatar permissions. + * Avatar interaction events such as {@link Entities.enterEntity} are also often used with a Zone entity. It has properties in + * addition to the common {@link Entities.EntityProperties|EntityProperties}. + * + * @typedef {object} Entities.EntityProperties-Zone + * @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the volume in which the zone's lighting effects and avatar + * permissions have effect. + * + * @property {ShapeType} shapeType="box" - The shape of the volume in which the zone's lighting effects and avatar + * permissions have effect. Reverts to the default value if set to "none", or set to "compound" + * and compoundShapeURL is "". + * @property {string} compoundShapeURL="" - The model file to use for the compound shape if shapeType is + * "compound". + * + * @property {Entities.ComponentMode} keyLightMode="inherit" - Configures the key light in the zone. + * @property {Entities.KeyLight} keyLight - The key light properties of the zone. + * + * @property {Entities.ComponentMode} ambientLightMode="inherit" - Configures the ambient light in the zone. + * @property {Entities.AmbientLight} ambientLight - The ambient light properties of the zone. + * + * @property {Entities.ComponentMode} skyboxMode="inherit" - Configures the skybox displayed in the zone. + * @property {Entities.Skybox} skybox - The skybox properties of the zone. + * + * @property {Entities.ComponentMode} hazeMode="inherit" - Configures the haze in the zone. + * @property {Entities.Haze} haze - The haze properties of the zone. + * + * @property {Entities.ComponentMode} bloomMode="inherit" - Configures the bloom in the zone. + * @property {Entities.Bloom} bloom - The bloom properties of the zone. + * + * @property {Entities.ZoneAudio} audio - The audio properties of the zone. + * + * @property {Entities.ComponentMode} tonemappingMode="inherit" - Configures the tonemapping in the zone. + * @property {Entities.Tonemapping} tonemapping - The tonemapping properties of the zone. + * + * @property {Entities.ComponentMode} ambientOcclusionMode="inherit" - Configures the ambient occlusion in the zone. + * @property {Entities.AmbientOcclusion} ambientOcclusion - The ambient occlusion properties of the zone. + * + * @property {boolean} flyingAllowed=true - true if visitors can fly in the zone; false if they + * cannot. Only works for domain entities. + * @property {boolean} ghostingAllowed=true - true if visitors with avatar collisions turned off will not + * collide with content in the zone; false if visitors will always collide with content in the zone. Only + * works for domain entities. + * + * @property {string} filterURL="" - The URL of a JavaScript file that filters changes to properties of entities within the + * zone. It is periodically executed for each entity in the zone. It can, for example, be used to not allow changes to + * certain properties: + *
+ * function filter(properties) {
+ *     // Check and edit properties object values,
+ *     // e.g., properties.modelURL, as required.
+ *     return properties;
+ * }
+ * 
+ * + * @property {Entities.AvatarPriorityMode} avatarPriority="inherit" - Configures the priority of updates from avatars in the + * zone to other clients. + * + * @property {Entities.ScreenshareMode} screenshare="inherit" - Configures a zone for screen-sharing. + * + * @example Create a zone that casts a red key light along the x-axis. + * var zone = Entities.addEntity({ + * type: "Zone", + * position: MyAvatar.position, + * dimensions: { x: 100, y: 100, z: 100 }, + * keyLightMode: "enabled", + * keyLight: { + * "color": { "red": 255, "green": 0, "blue": 0 }, + * "direction": { "x": 1, "y": 0, "z": 0 } + * }, + * lifetime: 300 // Delete after 5 minutes. + * }); + */ + +/*@jsdoc + * The "Image" {@link Entities.EntityType|EntityType} displays an image on a 2D rectangle in the domain. + * It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. + * + * @typedef {object} Entities.EntityProperties-Image + * @property {Vec3} dimensions=0.1,0.1,0.01 - The dimensions of the entity. + * @property {string} imageURL="" - The URL of the image to use. + * @property {boolean} emissive=false - true if the image should be emissive (unlit), false if it + * shouldn't. + * @property {boolean} keepAspectRatio=true - true if the image should maintain its aspect ratio, + * false if it shouldn't. + * @property {Rect} subImage=0,0,0,0 - The portion of the image to display. If width or height are 0, it defaults + * to the full image in that dimension. + * @property {Color} color=255,255,255 - The color of the image. + * @property {number} alpha=1 - The opacity of the image. + * @property {Entities.Pulse} pulse - Color and alpha pulse. + *

Deprecated: This property is deprecated and will be removed.

+ * @property {boolean} faceCamera - true if billboardMode is "yaw", false + * if it isn't. Setting this property to false sets the billboardMode to "none". + *

Deprecated: This property is deprecated and will be removed.

+ * @property {boolean} isFacingAvatar - true if billboardMode is "full", + * false if it isn't. Setting this property to false sets the billboardMode to + * "none". + *

Deprecated: This property is deprecated and will be removed.

+ * @example Create an image entity. + * var image = Entities.addEntity({ + * type: "Image", + * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })), + * dimensions: { x: 0.6, y: 0.3, z: 0.01 }, + * imageURL: "https://images.pexels.com/photos/1020315/pexels-photo-1020315.jpeg", + * billboardMode: "yaw", + * lifetime: 300 // Delete after 5 minutes. + * }); + */ + +/*@jsdoc + * The "Grid" {@link Entities.EntityType|EntityType} displays a grid on a 2D plane. + * It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. + * + * @typedef {object} Entities.EntityProperties-Grid + * @property {Vec3} dimensions - 0.1,0.1,0.01 - The dimensions of the entity. + * @property {Color} color=255,255,255 - The color of the grid. + * @property {number} alpha=1 - The opacity of the grid. + * @property {Entities.Pulse} pulse - Color and alpha pulse. + *

Deprecated: This property is deprecated and will be removed.

+ * @property {boolean} followCamera=true - true if the grid is always visible even as the camera moves to another + * position, false if it doesn't follow the camrmea. + * @property {number} majorGridEvery=5 - Integer number of minorGridEvery intervals at which to draw a thick grid + * line. Minimum value = 1. + * @property {number} minorGridEvery=1 - Real number of meters at which to draw thin grid lines. Minimum value = + * 0.001. + * @example Create a grid entity. + * var grid = Entities.addEntity({ + * type: "Grid", + * position: Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0, z: -5 })), + * dimensions: { x: 100.0, y: 100.0, z: 0.01 }, + * followCamera: false, + * majorGridEvery: 4, + * minorGridEvery: 0.5, + * lifetime: 300 // Delete after 5 minutes. + * }); + */ + +/*@jsdoc + * The "Gizmo" {@link Entities.EntityType|EntityType} displays an entity that could be used as UI. + * It has properties in addition to the common {@link Entities.EntityProperties|EntityProperties}. + * + * @typedef {object} Entities.EntityProperties-Gizmo + * @property {Vec3} dimensions=0.1,0.001,0.1 - The dimensions of the entity. + * @property {Entities.GizmoType} gizmoType="ring" - The gizmo type of the entity. + * @property {Entities.RingGizmo} ring - The ring gizmo properties. + */ diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index dfd41b8a366..71ddb956484 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -16,11 +16,38 @@ #define hifi_EntityItemPropertiesMacros_h #include +#include #include #include #include #include +const quint64 UNKNOWN_CREATED_TIME = 0; + +using vec3Color = glm::vec3; +using u8vec3Color = glm::u8vec3; + +struct EntityPropertyInfo { + EntityPropertyInfo(EntityPropertyList propEnum) : + propertyEnums(propEnum) {} + EntityPropertyInfo(EntityPropertyList propEnum, QVariant min, QVariant max) : + propertyEnums(propEnum), minimum(min), maximum(max) {} + EntityPropertyInfo() = default; + EntityPropertyFlags propertyEnums; + QVariant minimum; + QVariant maximum; +}; + +template +EntityPropertyInfo makePropertyInfo(EntityPropertyList p, typename std::enable_if::value>::type* = 0) { + return EntityPropertyInfo(p); +} + +template +EntityPropertyInfo makePropertyInfo(EntityPropertyList p, typename std::enable_if::value>::type* = 0) { + return EntityPropertyInfo(p, std::numeric_limits::min(), std::numeric_limits::max()); +} + #define APPEND_ENTITY_PROPERTY(P,V) \ if (requestedProperties.getHasProperty(P)) { \ LevelDetails propertyLevel = packetData->startLevel(); \ @@ -125,6 +152,7 @@ inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector& inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector& v) {return qVectorBoolToScriptValue(e, v); } inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector& v) { return qVectorFloatToScriptValue(e, v); } inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector& v) { return qVectorQUuidToScriptValue(e, v); } +inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector& v) { return qVectorQStringToScriptValue(e, v); } inline ScriptValue convertScriptValue(ScriptEngine* e, const QRect& v) { return qRectToScriptValue(e, v); } @@ -200,7 +228,7 @@ inline ScriptValue convertScriptValue(ScriptEngine* e, const AACube& v) { return #define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_TYPED(p, P, G, T) \ if ((_desiredProperties.isEmpty() || _desiredProperties.getHasProperty(p)) && \ (!skipDefaults || defaultEntityProperties._##P != _##P)) { \ - ScriptValue V = T##_convertScriptValue(engine, G); \ + ScriptValue V = T##_convertScriptValue(engine, G()); \ properties.setProperty(#P, V); \ } @@ -208,7 +236,7 @@ inline ScriptValue convertScriptValue(ScriptEngine* e, const AACube& v) { return #define COPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(p, P, X, G) \ if (((!returnNothingOnEmptyPropertyFlags && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(p)) && \ (!skipDefaults || defaultEntityProperties._##P != _##P)) { \ - ScriptValue V = convertScriptValue(engine, G); \ + ScriptValue V = convertScriptValue(engine, G()); \ properties.setProperty(#X, V); \ } @@ -254,6 +282,8 @@ typedef QVector qVectorQuat; typedef QVector qVectorBool; typedef QVector qVectorFloat; typedef QVector qVectorQUuid; +typedef QVector qVectorQString; +typedef QSet qSetQString; inline float float_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toFloat(&isValid); } inline quint64 quint64_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toULongLong(&isValid); } inline quint32 quint32_convertFromScriptValue(const ScriptValue& v, bool& isValid) { @@ -336,6 +366,11 @@ inline qVectorQUuid qVectorQUuid_convertFromScriptValue(const ScriptValue& v, bo return qVectorQUuidFromScriptValue(v); } +inline qVectorQString qVectorQString_convertFromScriptValue(const ScriptValue& v, bool& isValid) { + isValid = true; + return qVectorQStringFromScriptValue(v); +} + inline glm::quat quat_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = false; /// assume it can't be converted ScriptValue x = v.property("x"); @@ -373,8 +408,6 @@ inline QRect QRect_convertFromScriptValue(const ScriptValue& v, bool& isValid) { } \ } - - #define COPY_PROPERTY_FROM_QSCRIPTVALUE(P, T, S) \ { \ if (namesSet.contains(#P)) { \ @@ -472,21 +505,21 @@ inline QRect QRect_convertFromScriptValue(const ScriptValue& v, bool& isValid) { static T _static##N; -#define ADD_PROPERTY_TO_MAP(P, N, n, T) \ +#define ADD_PROPERTY_TO_MAP(P, n, T) \ { \ EntityPropertyInfo propertyInfo { makePropertyInfo(P) }; \ _propertyInfos[#n] = propertyInfo; \ _enumsToPropertyStrings[P] = #n; \ } -#define ADD_PROPERTY_TO_MAP_WITH_RANGE(P, N, n, T, M, X) \ +#define ADD_PROPERTY_TO_MAP_WITH_RANGE(P, n, M, X) \ { \ EntityPropertyInfo propertyInfo = EntityPropertyInfo(P, M, X); \ _propertyInfos[#n] = propertyInfo; \ _enumsToPropertyStrings[P] = #n; \ } -#define ADD_GROUP_PROPERTY_TO_MAP(P, G, g, N, n) \ +#define ADD_GROUP_PROPERTY_TO_MAP(P, g, n) \ { \ EntityPropertyInfo propertyInfo = EntityPropertyInfo(P); \ _propertyInfos[#g "." #n] = propertyInfo; \ @@ -494,7 +527,7 @@ inline QRect QRect_convertFromScriptValue(const ScriptValue& v, bool& isValid) { _enumsToPropertyStrings[P] = #g "." #n; \ } -#define ADD_GROUP_PROPERTY_TO_MAP_WITH_RANGE(P, G, g, N, n, M, X) \ +#define ADD_GROUP_PROPERTY_TO_MAP_WITH_RANGE(P, g, n, M, X) \ { \ EntityPropertyInfo propertyInfo = EntityPropertyInfo(P, M, X); \ _propertyInfos[#g "." #n] = propertyInfo; \ @@ -510,31 +543,31 @@ inline QRect QRect_convertFromScriptValue(const ScriptValue& v, bool& isValid) { T _##n = V; \ bool _##n##Changed { false }; -#define DEFINE_PROPERTY(P, N, n, T, V) \ +#define DEFINE_PROPERTY(N, n, T, V) \ public: \ T get##N() const { return _##n; } \ void set##N(T value) { _##n = value; _##n##Changed = true; } \ DEFINE_CORE(N, n, T, V) -#define DEFINE_PROPERTY_REF(P, N, n, T, V) \ +#define DEFINE_PROPERTY_REF(N, n, T, V) \ public: \ const T& get##N() const { return _##n; } \ void set##N(const T& value) { _##n = value; _##n##Changed = true; } \ DEFINE_CORE(N, n, T, V) -#define DEFINE_PROPERTY_REF_WITH_SETTER(P, N, n, T, V) \ +#define DEFINE_PROPERTY_REF_WITH_SETTER(N, n, T, V) \ public: \ const T& get##N() const { return _##n; } \ void set##N(const T& value); \ DEFINE_CORE(N, n, T, V) -#define DEFINE_PROPERTY_REF_WITH_SETTER_AND_GETTER(P, N, n, T, V) \ +#define DEFINE_PROPERTY_REF_WITH_SETTER_AND_GETTER(N, n, T, V) \ public: \ T get##N() const; \ void set##N(const T& value); \ DEFINE_CORE(N, n, T, V) -#define DEFINE_PROPERTY_REF_ENUM(P, N, n, T, V) \ +#define DEFINE_PROPERTY_REF_ENUM(N, n, T, V) \ public: \ const T& get##N() const { return _##n; } \ void set##N(const T& value) { _##n = value; _##n##Changed = true; } \ @@ -550,4 +583,134 @@ inline QRect QRect_convertFromScriptValue(const ScriptValue& v, bool& isValid) { D << " " << #n << ":" << P.get##N() << x << "\n"; \ } +// EntityItem helpers +#define DEFINE_VARIABLE_NO_GETTER_SETTER(N, n, T, V) \ + protected: \ + T _##n = V; + +#define DEFINE_VARIABLE(N, n, T, V) \ + public: \ + T get##N() const; \ + void set##N(T value); \ + protected: \ + T _##n = V; + +#define DEFINE_VARIABLE_REF(N, n, T, V) \ + public: \ + T get##N() const; \ + void set##N(const T& value); \ + protected: \ + T _##n = V; + +#define DEFINE_VARIABLE_BASIC(N, n, T, V) \ + public: \ + T get##N() const { \ + return resultWithReadLock([&] { \ + return _##n; \ + }); \ + } \ + void set##N(T value) { \ + withWriteLock([&] { \ + _##n = value; \ + }); \ + } \ + protected: \ + T _##n = V; + +#define DEFINE_VARIABLE_BASIC_REF(N, n, T, V) \ + public: \ + T get##N() const { \ + return resultWithReadLock([&] { \ + return _##n; \ + }); \ + } \ + void set##N(const T& value) { \ + withWriteLock([&] { \ + _##n = value; \ + }); \ + } \ + protected: \ + T _##n = V; + +#define DEFINE_VARIABLE_RENDER(N, n, T, V) \ + public: \ + T get##N() const { \ + return resultWithReadLock([&] { \ + return _##n; \ + }); \ + } \ + void set##N(T value) { \ + withWriteLock([&] { \ + _needsRenderUpdate |= _##n != value; \ + _##n = value; \ + }); \ + } \ + protected: \ + T _##n = V; + +#define DEFINE_VARIABLE_RENDER_REF(N, n, T, V) \ + public: \ + T get##N() const { \ + return resultWithReadLock([&] { \ + return _##n; \ + }); \ + } \ + void set##N(const T& value) { \ + withWriteLock([&] { \ + _needsRenderUpdate |= _##n != value; \ + _##n = value; \ + }); \ + } \ + protected: \ + T _##n = V; + +#define ENTITY_PROPERTY_SUBCLASS_METHODS \ + EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, \ + bool allowEmptyDesiredProperties) const override; \ + bool setSubClassProperties(const EntityItemProperties& properties) override; \ + EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; \ + void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, \ + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, \ + EntityPropertyFlags& requestedProperties, \ + EntityPropertyFlags& propertyFlags, \ + EntityPropertyFlags& propertiesDidntFit, \ + int& propertyCount, \ + OctreeElement::AppendState& appendState) const override; \ + int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, \ + ReadBitstreamToTreeParams& args, \ + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, \ + bool& somethingChanged) override; \ + virtual void debugDump() const override; + +#define ENTITY_PROPERTY_GROUP_METHODS(P) \ + virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, \ + ScriptEngine* engine, bool skipDefaults, \ + EntityItemProperties& defaultEntityProperties, \ + bool returnNothingOnEmptyPropertyFlags, \ + bool isMyOwnAvatarEntity) const override; \ + virtual void copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, \ + bool& _defaultSettings) override; \ + void merge(const P& other); \ + virtual void debugDump() const override; \ + virtual void listChangedProperties(QList& 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; \ + virtual void getProperties(EntityItemProperties& propertiesOut) const override; \ + virtual bool setProperties(const EntityItemProperties& properties) override; \ + virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; \ + virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, \ + ReadBitstreamToTreeParams& args, \ + EntityPropertyFlags& propertyFlags, \ + bool overwriteLocalData, bool& somethingChanged) override; \ + static void addPropertyMap(QHash& _propertyInfos, \ + QHash& _enumsToPropertyStrings); + #endif // hifi_EntityItemPropertiesMacros_h diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h deleted file mode 100644 index e0b5a040948..00000000000 --- a/libraries/entities/src/EntityPropertyFlags.h +++ /dev/null @@ -1,391 +0,0 @@ -// -// EntityPropertyFlags.h -// libraries/entities/src -// -// Created by Brad Hefta-Gaub on 12/4/13. -// Copyright 2013 High Fidelity, Inc. -// Copyright 2020 Vircadia contributors. -// -// 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_EntityPropertyFlags_h -#define hifi_EntityPropertyFlags_h - -#include - -enum EntityPropertyList { - PROP_PAGED_PROPERTY, - PROP_CUSTOM_PROPERTIES_INCLUDED, - - // Core properties - PROP_SIMULATION_OWNER, - PROP_PARENT_ID, - PROP_PARENT_JOINT_INDEX, - PROP_VISIBLE, - PROP_NAME, - PROP_LOCKED, - PROP_USER_DATA, - PROP_PRIVATE_USER_DATA, - PROP_HREF, - PROP_DESCRIPTION, - PROP_POSITION, - PROP_DIMENSIONS, - PROP_ROTATION, - PROP_REGISTRATION_POINT, - PROP_CREATED, - PROP_LAST_EDITED_BY, - PROP_ENTITY_HOST_TYPE, // not sent over the wire - PROP_OWNING_AVATAR_ID, // not sent over the wire - PROP_QUERY_AA_CUBE, - PROP_CAN_CAST_SHADOW, - PROP_VISIBLE_IN_SECONDARY_CAMERA, // not sent over the wire - PROP_RENDER_LAYER, - PROP_PRIMITIVE_MODE, - PROP_IGNORE_PICK_INTERSECTION, - PROP_RENDER_WITH_ZONES, - PROP_BILLBOARD_MODE, - // Grab - PROP_GRAB_GRABBABLE, - PROP_GRAB_KINEMATIC, - PROP_GRAB_FOLLOWS_CONTROLLER, - PROP_GRAB_TRIGGERABLE, - PROP_GRAB_EQUIPPABLE, - PROP_GRAB_DELEGATE_TO_PARENT, - PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, - PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, - PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, - PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, - PROP_GRAB_EQUIPPABLE_INDICATOR_URL, - PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, - PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, - - // Physics - PROP_DENSITY, - PROP_VELOCITY, - PROP_ANGULAR_VELOCITY, - PROP_GRAVITY, - PROP_ACCELERATION, - PROP_DAMPING, - PROP_ANGULAR_DAMPING, - PROP_RESTITUTION, - PROP_FRICTION, - PROP_LIFETIME, - PROP_COLLISIONLESS, - PROP_COLLISION_MASK, - PROP_DYNAMIC, - PROP_COLLISION_SOUND_URL, - PROP_ACTION_DATA, - - // Cloning - PROP_CLONEABLE, - PROP_CLONE_LIFETIME, - PROP_CLONE_LIMIT, - PROP_CLONE_DYNAMIC, - PROP_CLONE_AVATAR_ENTITY, - PROP_CLONE_ORIGIN_ID, - - // Scripts - PROP_SCRIPT, - PROP_SCRIPT_TIMESTAMP, - PROP_SERVER_SCRIPTS, - - // Certifiable Properties - PROP_ITEM_NAME, - PROP_ITEM_DESCRIPTION, - PROP_ITEM_CATEGORIES, - PROP_ITEM_ARTIST, - PROP_ITEM_LICENSE, - PROP_LIMITED_RUN, - PROP_MARKETPLACE_ID, - PROP_EDITION_NUMBER, - PROP_ENTITY_INSTANCE_NUMBER, - PROP_CERTIFICATE_ID, - PROP_CERTIFICATE_TYPE, - PROP_STATIC_CERTIFICATE_VERSION, - - // Used to convert values to and from scripts - PROP_LOCAL_POSITION, - PROP_LOCAL_ROTATION, - PROP_LOCAL_VELOCITY, - PROP_LOCAL_ANGULAR_VELOCITY, - PROP_LOCAL_DIMENSIONS, - - // These properties are used by multiple subtypes but aren't in the base EntityItem - PROP_SHAPE_TYPE, - PROP_COMPOUND_SHAPE_URL, - PROP_COLOR, - PROP_ALPHA, - PROP_PULSE_MIN, - PROP_PULSE_MAX, - PROP_PULSE_PERIOD, - PROP_PULSE_COLOR_MODE, - PROP_PULSE_ALPHA_MODE, - PROP_TEXTURES, - - //////////////////////////////////////////////////////////////////////////////////////////////////// - // ATTENTION: add new shared EntityItem properties to the list ABOVE this line - //////////////////////////////////////////////////////////////////////////////////////////////////// - - // We need as many of these as the number of unique properties of a derived EntityItem class - PROP_DERIVED_0, - PROP_DERIVED_1, - PROP_DERIVED_2, - PROP_DERIVED_3, - PROP_DERIVED_4, - PROP_DERIVED_5, - PROP_DERIVED_6, - PROP_DERIVED_7, - PROP_DERIVED_8, - PROP_DERIVED_9, - PROP_DERIVED_10, - PROP_DERIVED_11, - PROP_DERIVED_12, - PROP_DERIVED_13, - PROP_DERIVED_14, - PROP_DERIVED_15, - PROP_DERIVED_16, - PROP_DERIVED_17, - PROP_DERIVED_18, - PROP_DERIVED_19, - PROP_DERIVED_20, - PROP_DERIVED_21, - PROP_DERIVED_22, - PROP_DERIVED_23, - PROP_DERIVED_24, - PROP_DERIVED_25, - PROP_DERIVED_26, - PROP_DERIVED_27, - PROP_DERIVED_28, - PROP_DERIVED_29, - PROP_DERIVED_30, - PROP_DERIVED_31, - PROP_DERIVED_32, - PROP_DERIVED_33, - PROP_DERIVED_34, - - PROP_AFTER_LAST_ITEM, - - //////////////////////////////////////////////////////////////////////////////////////////////////// - // WARNING! Do not add props here unless you intentionally mean to reuse PROP_DERIVED_X indexes - // - // These properties intentionally reuse the enum values for other properties which will never overlap with each other. We do this so that we don't have to expand - // the size of the properties bitflags mask - // - // Only add properties here that are only used by one subclass. Otherwise, they should go above to prevent collisions - - // Particles - PROP_MAX_PARTICLES = PROP_DERIVED_0, - PROP_LIFESPAN = PROP_DERIVED_1, - PROP_EMITTING_PARTICLES = PROP_DERIVED_2, - PROP_EMIT_RATE = PROP_DERIVED_3, - PROP_EMIT_SPEED = PROP_DERIVED_4, - PROP_SPEED_SPREAD = PROP_DERIVED_5, - PROP_EMIT_ORIENTATION = PROP_DERIVED_6, - PROP_EMIT_DIMENSIONS = PROP_DERIVED_7, - PROP_ACCELERATION_SPREAD = PROP_DERIVED_8, - PROP_POLAR_START = PROP_DERIVED_9, - PROP_POLAR_FINISH = PROP_DERIVED_10, - PROP_AZIMUTH_START = PROP_DERIVED_11, - PROP_AZIMUTH_FINISH = PROP_DERIVED_12, - PROP_EMIT_RADIUS_START = PROP_DERIVED_13, - PROP_EMIT_ACCELERATION = PROP_DERIVED_14, - PROP_PARTICLE_RADIUS = PROP_DERIVED_15, - PROP_RADIUS_SPREAD = PROP_DERIVED_16, - PROP_RADIUS_START = PROP_DERIVED_17, - PROP_RADIUS_FINISH = PROP_DERIVED_18, - PROP_COLOR_SPREAD = PROP_DERIVED_19, - PROP_COLOR_START = PROP_DERIVED_20, - PROP_COLOR_FINISH = PROP_DERIVED_21, - PROP_ALPHA_SPREAD = PROP_DERIVED_22, - PROP_ALPHA_START = PROP_DERIVED_23, - PROP_ALPHA_FINISH = PROP_DERIVED_24, - PROP_EMITTER_SHOULD_TRAIL = PROP_DERIVED_25, - PROP_PARTICLE_SPIN = PROP_DERIVED_26, - PROP_SPIN_START = PROP_DERIVED_27, - PROP_SPIN_FINISH = PROP_DERIVED_28, - PROP_SPIN_SPREAD = PROP_DERIVED_29, - PROP_PARTICLE_ROTATE_WITH_ENTITY = PROP_DERIVED_30, - - // Model - PROP_MODEL_URL = PROP_DERIVED_0, - PROP_MODEL_SCALE = PROP_DERIVED_1, - PROP_JOINT_ROTATIONS_SET = PROP_DERIVED_2, - PROP_JOINT_ROTATIONS = PROP_DERIVED_3, - PROP_JOINT_TRANSLATIONS_SET = PROP_DERIVED_4, - PROP_JOINT_TRANSLATIONS = PROP_DERIVED_5, - PROP_RELAY_PARENT_JOINTS = PROP_DERIVED_6, - PROP_GROUP_CULLED = PROP_DERIVED_7, - PROP_BLENDSHAPE_COEFFICIENTS = PROP_DERIVED_8, - PROP_USE_ORIGINAL_PIVOT = PROP_DERIVED_9, - // Animation - PROP_ANIMATION_URL = PROP_DERIVED_10, - PROP_ANIMATION_ALLOW_TRANSLATION = PROP_DERIVED_11, - PROP_ANIMATION_FPS = PROP_DERIVED_12, - PROP_ANIMATION_FRAME_INDEX = PROP_DERIVED_13, - PROP_ANIMATION_PLAYING = PROP_DERIVED_14, - PROP_ANIMATION_LOOP = PROP_DERIVED_15, - PROP_ANIMATION_FIRST_FRAME = PROP_DERIVED_16, - PROP_ANIMATION_LAST_FRAME = PROP_DERIVED_17, - PROP_ANIMATION_HOLD = PROP_DERIVED_18, - - // Light - PROP_IS_SPOTLIGHT = PROP_DERIVED_0, - PROP_INTENSITY = PROP_DERIVED_1, - PROP_EXPONENT = PROP_DERIVED_2, - PROP_CUTOFF = PROP_DERIVED_3, - PROP_FALLOFF_RADIUS = PROP_DERIVED_4, - - // Text - PROP_TEXT = PROP_DERIVED_0, - PROP_LINE_HEIGHT = PROP_DERIVED_1, - PROP_TEXT_COLOR = PROP_DERIVED_2, - PROP_TEXT_ALPHA = PROP_DERIVED_3, - PROP_BACKGROUND_COLOR = PROP_DERIVED_4, - PROP_BACKGROUND_ALPHA = PROP_DERIVED_5, - PROP_LEFT_MARGIN = PROP_DERIVED_6, - PROP_RIGHT_MARGIN = PROP_DERIVED_7, - PROP_TOP_MARGIN = PROP_DERIVED_8, - PROP_BOTTOM_MARGIN = PROP_DERIVED_9, - PROP_UNLIT = PROP_DERIVED_10, - PROP_FONT = PROP_DERIVED_11, - PROP_TEXT_EFFECT = PROP_DERIVED_12, - PROP_TEXT_EFFECT_COLOR = PROP_DERIVED_13, - PROP_TEXT_EFFECT_THICKNESS = PROP_DERIVED_14, - PROP_TEXT_ALIGNMENT = PROP_DERIVED_15, - - // Zone - // Keylight - PROP_KEYLIGHT_COLOR = PROP_DERIVED_0, - PROP_KEYLIGHT_INTENSITY = PROP_DERIVED_1, - PROP_KEYLIGHT_DIRECTION = PROP_DERIVED_2, - PROP_KEYLIGHT_CAST_SHADOW = PROP_DERIVED_3, - PROP_KEYLIGHT_SHADOW_BIAS = PROP_DERIVED_4, - PROP_KEYLIGHT_SHADOW_MAX_DISTANCE = PROP_DERIVED_5, - // Ambient light - PROP_AMBIENT_LIGHT_INTENSITY = PROP_DERIVED_6, - PROP_AMBIENT_LIGHT_URL = PROP_DERIVED_7, - // Skybox - PROP_SKYBOX_COLOR = PROP_DERIVED_8, - PROP_SKYBOX_URL = PROP_DERIVED_9, - // Haze - PROP_HAZE_RANGE = PROP_DERIVED_10, - PROP_HAZE_COLOR = PROP_DERIVED_11, - PROP_HAZE_GLARE_COLOR = PROP_DERIVED_12, - PROP_HAZE_ENABLE_GLARE = PROP_DERIVED_13, - PROP_HAZE_GLARE_ANGLE = PROP_DERIVED_14, - PROP_HAZE_ALTITUDE_EFFECT = PROP_DERIVED_15, - PROP_HAZE_CEILING = PROP_DERIVED_16, - PROP_HAZE_BASE_REF = PROP_DERIVED_17, - PROP_HAZE_BACKGROUND_BLEND = PROP_DERIVED_18, - PROP_HAZE_ATTENUATE_KEYLIGHT = PROP_DERIVED_19, - PROP_HAZE_KEYLIGHT_RANGE = PROP_DERIVED_20, - PROP_HAZE_KEYLIGHT_ALTITUDE = PROP_DERIVED_21, - // Bloom - PROP_BLOOM_INTENSITY = PROP_DERIVED_22, - PROP_BLOOM_THRESHOLD = PROP_DERIVED_23, - PROP_BLOOM_SIZE = PROP_DERIVED_24, - PROP_FLYING_ALLOWED = PROP_DERIVED_25, - PROP_GHOSTING_ALLOWED = PROP_DERIVED_26, - PROP_FILTER_URL = PROP_DERIVED_27, - PROP_KEY_LIGHT_MODE = PROP_DERIVED_28, - PROP_AMBIENT_LIGHT_MODE = PROP_DERIVED_29, - PROP_SKYBOX_MODE = PROP_DERIVED_30, - PROP_HAZE_MODE = PROP_DERIVED_31, - PROP_BLOOM_MODE = PROP_DERIVED_32, - // Avatar priority - PROP_AVATAR_PRIORITY = PROP_DERIVED_33, - // Screen-sharing - PROP_SCREENSHARE = PROP_DERIVED_34, - - // Polyvox - PROP_VOXEL_VOLUME_SIZE = PROP_DERIVED_0, - PROP_VOXEL_DATA = PROP_DERIVED_1, - PROP_VOXEL_SURFACE_STYLE = PROP_DERIVED_2, - PROP_X_TEXTURE_URL = PROP_DERIVED_3, - PROP_Y_TEXTURE_URL = PROP_DERIVED_4, - PROP_Z_TEXTURE_URL = PROP_DERIVED_5, - PROP_X_N_NEIGHBOR_ID = PROP_DERIVED_6, - PROP_Y_N_NEIGHBOR_ID = PROP_DERIVED_7, - PROP_Z_N_NEIGHBOR_ID = PROP_DERIVED_8, - PROP_X_P_NEIGHBOR_ID = PROP_DERIVED_9, - PROP_Y_P_NEIGHBOR_ID = PROP_DERIVED_10, - PROP_Z_P_NEIGHBOR_ID = PROP_DERIVED_11, - - // Web - PROP_SOURCE_URL = PROP_DERIVED_0, - PROP_DPI = PROP_DERIVED_1, - PROP_SCRIPT_URL = PROP_DERIVED_2, - PROP_MAX_FPS = PROP_DERIVED_3, - PROP_INPUT_MODE = PROP_DERIVED_4, - PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT = PROP_DERIVED_5, - PROP_WEB_USE_BACKGROUND = PROP_DERIVED_6, - PROP_USER_AGENT = PROP_DERIVED_7, - - // Polyline - PROP_LINE_POINTS = PROP_DERIVED_0, - PROP_STROKE_WIDTHS = PROP_DERIVED_1, - PROP_STROKE_NORMALS = PROP_DERIVED_2, - PROP_STROKE_COLORS = PROP_DERIVED_3, - PROP_IS_UV_MODE_STRETCH = PROP_DERIVED_4, - PROP_LINE_GLOW = PROP_DERIVED_5, - PROP_LINE_FACE_CAMERA = PROP_DERIVED_6, - - // Shape - PROP_SHAPE = PROP_DERIVED_0, - - // Material - PROP_MATERIAL_URL = PROP_DERIVED_0, - PROP_MATERIAL_MAPPING_MODE = PROP_DERIVED_1, - PROP_MATERIAL_PRIORITY = PROP_DERIVED_2, - PROP_PARENT_MATERIAL_NAME = PROP_DERIVED_3, - PROP_MATERIAL_MAPPING_POS = PROP_DERIVED_4, - PROP_MATERIAL_MAPPING_SCALE = PROP_DERIVED_5, - PROP_MATERIAL_MAPPING_ROT = PROP_DERIVED_6, - PROP_MATERIAL_DATA = PROP_DERIVED_7, - PROP_MATERIAL_REPEAT = PROP_DERIVED_8, - - // Image - PROP_IMAGE_URL = PROP_DERIVED_0, - PROP_EMISSIVE = PROP_DERIVED_1, - PROP_KEEP_ASPECT_RATIO = PROP_DERIVED_2, - PROP_SUB_IMAGE = PROP_DERIVED_3, - - // Grid - PROP_GRID_FOLLOW_CAMERA = PROP_DERIVED_0, - PROP_MAJOR_GRID_EVERY = PROP_DERIVED_1, - PROP_MINOR_GRID_EVERY = PROP_DERIVED_2, - - // Gizmo - PROP_GIZMO_TYPE = PROP_DERIVED_0, - // Ring - PROP_START_ANGLE = PROP_DERIVED_1, - PROP_END_ANGLE = PROP_DERIVED_2, - PROP_INNER_RADIUS = PROP_DERIVED_3, - PROP_INNER_START_COLOR = PROP_DERIVED_4, - PROP_INNER_END_COLOR = PROP_DERIVED_5, - PROP_OUTER_START_COLOR = PROP_DERIVED_6, - PROP_OUTER_END_COLOR = PROP_DERIVED_7, - PROP_INNER_START_ALPHA = PROP_DERIVED_8, - PROP_INNER_END_ALPHA = PROP_DERIVED_9, - PROP_OUTER_START_ALPHA = PROP_DERIVED_10, - PROP_OUTER_END_ALPHA = PROP_DERIVED_11, - PROP_HAS_TICK_MARKS = PROP_DERIVED_12, - PROP_MAJOR_TICK_MARKS_ANGLE = PROP_DERIVED_13, - PROP_MINOR_TICK_MARKS_ANGLE = PROP_DERIVED_14, - PROP_MAJOR_TICK_MARKS_LENGTH = PROP_DERIVED_15, - PROP_MINOR_TICK_MARKS_LENGTH = PROP_DERIVED_16, - PROP_MAJOR_TICK_MARKS_COLOR = PROP_DERIVED_17, - PROP_MINOR_TICK_MARKS_COLOR = PROP_DERIVED_18, - - // WARNING!!! DO NOT ADD PROPS_xxx here unless you really really meant to.... Add them UP above -}; - -typedef PropertyFlags EntityPropertyFlags; - -// this is set at the top of EntityItemProperties.cpp to PROP_AFTER_LAST_ITEM - 1. PROP_AFTER_LAST_ITEM is always -// one greater than the last item property due to the enum's auto-incrementing. -extern EntityPropertyList PROP_LAST_ITEM; - -#endif // hifi_EntityPropertyFlags_h diff --git a/libraries/entities/src/EntityPropertyFlags.h.in b/libraries/entities/src/EntityPropertyFlags.h.in new file mode 100644 index 00000000000..c087ae5c578 --- /dev/null +++ b/libraries/entities/src/EntityPropertyFlags.h.in @@ -0,0 +1,107 @@ +// +// EntityPropertyFlags.h +// libraries/entities/src +// +// Created by Brad Hefta-Gaub on 12/4/13. +// Copyright 2013 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. +// Copyright 2023 Overte e.V. +// +// 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_EntityPropertyFlags_h +#define hifi_EntityPropertyFlags_h + +#include + +enum EntityPropertyList : uint16_t { + PROP_PAGED_PROPERTY, + PROP_CUSTOM_PROPERTIES_INCLUDED, + +@ENTITY_PROPERTY_FLAGS_COMMON@ + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // ATTENTION: add new shared EntityItem properties to the list ABOVE this line + //////////////////////////////////////////////////////////////////////////////////////////////////// + + // We need as many of these as the number of unique properties of a derived EntityItem class + PROP_DERIVED_0, + PROP_DERIVED_1, + PROP_DERIVED_2, + PROP_DERIVED_3, + PROP_DERIVED_4, + PROP_DERIVED_5, + PROP_DERIVED_6, + PROP_DERIVED_7, + PROP_DERIVED_8, + PROP_DERIVED_9, + PROP_DERIVED_10, + PROP_DERIVED_11, + PROP_DERIVED_12, + PROP_DERIVED_13, + PROP_DERIVED_14, + PROP_DERIVED_15, + PROP_DERIVED_16, + PROP_DERIVED_17, + PROP_DERIVED_18, + PROP_DERIVED_19, + PROP_DERIVED_20, + PROP_DERIVED_21, + PROP_DERIVED_22, + PROP_DERIVED_23, + PROP_DERIVED_24, + PROP_DERIVED_25, + PROP_DERIVED_26, + PROP_DERIVED_27, + PROP_DERIVED_28, + PROP_DERIVED_29, + PROP_DERIVED_30, + PROP_DERIVED_31, + PROP_DERIVED_32, + PROP_DERIVED_33, + PROP_DERIVED_34, + PROP_DERIVED_35, + PROP_DERIVED_36, + PROP_DERIVED_37, + PROP_DERIVED_38, + PROP_DERIVED_39, + PROP_DERIVED_40, + PROP_DERIVED_41, + PROP_DERIVED_42, + PROP_DERIVED_43, + PROP_DERIVED_44, + PROP_DERIVED_45, + PROP_DERIVED_46, + PROP_DERIVED_47, + PROP_DERIVED_48, + PROP_DERIVED_49, + PROP_DERIVED_50, + PROP_DERIVED_51, + PROP_DERIVED_52, + PROP_DERIVED_53, + PROP_DERIVED_54, + + PROP_AFTER_LAST_ITEM, + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // WARNING! Do not add props here unless you intentionally mean to reuse PROP_DERIVED_X indexes + // + // These properties intentionally reuse the enum values for other properties which will never overlap with each other. We do this so that we don't have to expand + // the size of the properties bitflags mask + // + // Only add properties here that are only used by one subclass. Otherwise, they should go above to prevent collisions + +@ENTITY_PROPERTY_FLAGS_DERIVED@ + + // WARNING!!! DO NOT ADD PROPS_xxx here unless you really really meant to.... Add them UP above +}; + +typedef PropertyFlags EntityPropertyFlags; + +// this is set at the top of EntityItemProperties.cpp to PROP_AFTER_LAST_ITEM - 1. PROP_AFTER_LAST_ITEM is always +// one greater than the last item property due to the enum's auto-incrementing. +extern EntityPropertyList PROP_LAST_ITEM; + +#endif // hifi_EntityPropertyFlags_h diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 0d2a5738a2b..6bb0c0b69f9 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -1465,6 +1465,17 @@ QVector EntityScriptingInterface::findEntitiesByName(const QString entity return result; } +QVector EntityScriptingInterface::findEntitiesByTags(const QVector entityTags, const glm::vec3& center, float radius, bool caseSensitiveSearch) const { + QVector result; + if (_entityTree) { + _entityTree->withReadLock([&] { + unsigned int searchFilter = PickFilter::getBitMask(PickFilter::FlagBit::DOMAIN_ENTITIES) | PickFilter::getBitMask(PickFilter::FlagBit::AVATAR_ENTITIES); + _entityTree->evalEntitiesInSphereWithTags(center, radius, entityTags, caseSensitiveSearch, PickFilter(searchFilter), result); + }); + } + return result; +} + RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray, bool precisionPicking, const ScriptValue& entityIdsToInclude, const ScriptValue& entityIdsToDiscard, bool visibleOnly, bool collidableOnly) const { PROFILE_RANGE(script_entities, __FUNCTION__); @@ -1868,6 +1879,7 @@ bool EntityScriptingInterface::setAllPoints(const QUuid& entityID, const QVector EntityItemPointer entity = static_cast(_entityTree->findEntityByEntityItemID(entityID)); if (!entity) { qCDebug(entities) << "EntityScriptingInterface::setPoints no entity with ID" << entityID; + return false; } EntityTypes::EntityType entityType = entity->getType(); @@ -1875,7 +1887,7 @@ bool EntityScriptingInterface::setAllPoints(const QUuid& entityID, const QVector if (entityType == EntityTypes::Line) { return setPoints(entityID, [points](LineEntityItem& lineEntity) -> bool { - return (LineEntityItem*)lineEntity.setLinePoints(points); + return lineEntity.setLinePoints(points); }); } @@ -1904,6 +1916,29 @@ bool EntityScriptingInterface::appendPoint(const QUuid& entityID, const glm::vec return false; } +bool EntityScriptingInterface::restartSound(const QUuid& entityID) { + PROFILE_RANGE(script_entities, __FUNCTION__); + + EntityItemPointer entity = static_cast(_entityTree->findEntityByEntityItemID(entityID)); + if (!entity) { + qCDebug(entities) << "EntityScriptingInterface::restartSound no entity with ID" << entityID; + // There is no entity + return false; + } + + EntityTypes::EntityType entityType = entity->getType(); + + if (entityType == EntityTypes::Sound) { + auto soundEntity = std::dynamic_pointer_cast(entity); + bool isPlaying = soundEntity->getPlaying(); + if (isPlaying) { + soundEntity->restartSound(true); + } + return isPlaying; + } + + return false; +} bool EntityScriptingInterface::actionWorker(const QUuid& entityID, std::function actor) { diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 8d74e6821c2..6fe4a96d759 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -815,6 +815,25 @@ public slots: Q_INVOKABLE QVector findEntitiesByName(const QString entityName, const glm::vec3& center, float radius, bool caseSensitiveSearch = false) const; + /*@jsdoc + * Finds all domain and avatar entities with particular tags that intersect a sphere. + *

Note: Server entity scripts only find entities that have a server entity script + * running in them or a parent entity. You can apply a dummy script to entities that you want found in a search.

+ * @function Entities.findEntitiesByTags + * @param {string[]} entityTags - The tags of the entity to search for. + * @param {Vec3} center - The point about which to search. + * @param {number} radius - The radius within which to search. + * @param {boolean} [caseSensitive=false] - true if the search is case-sensitive, false if it is + * case-insensitive. + * @returns {Uuid[]} An array of entity IDs that have the specified name and intersect the search sphere. The array is + * empty if no entities could be found. + * @example Report the number of entities with the tag, "Light-Target". + * var entityIDs = Entities.findEntitiesByTags(["Light-Target"], MyAvatar.position, 10, false); + * print("Number of entities with the tag Light-Target: " + entityIDs.length); + */ + Q_INVOKABLE QVector findEntitiesByTags(const QVector entityTags, const glm::vec3& center, float radius, + bool caseSensitiveSearch = false) const; + /*@jsdoc * Finds the first avatar or domain entity intersected by a {@link PickRay}. Light and Zone * entities are not intersected unless they've been configured as pickable using @@ -1244,6 +1263,27 @@ public slots: */ Q_INVOKABLE bool appendPoint(const QUuid& entityID, const glm::vec3& point); + /*@jsdoc + * Restart a {@link Entities.EntityProperties-Sound|Sound} entity, locally only. It must also be localOnly. + * @function Entities.restartSound + * @param {Uuid} entityID - The ID of the {@link Entities.EntityProperties-Sound|Sound} entity. + * @example Play a sound once and repeat it every 3 seconds. + * var position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.5, z: -8 })); + * var sound = Entities.addEntity({ + * type: "Sound", + * position: position, + * soundURL: "https://themushroomkingdom.net/sounds/wav/lm/lm_gold_mouse.wav", + * positional: false, + * localOnly: true, + * loop: false, + * lifetime: 300 // Delete after 5 minutes. + * }); + * Script.setInterval(() => { + * Entities.restartSound(sound); + * }, 3000); + */ + Q_INVOKABLE bool restartSound(const QUuid& entityID); + /*@jsdoc * Dumps debug information about all entities in Interface's local in-memory tree of entities it knows about to the program * log. diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index f2525615010..7a70076cf85 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -368,7 +368,7 @@ bool EntityTree::updateEntity(EntityItemPointer entity, const EntityItemProperti } } } else { - if (getIsServer()) { + if (isEntityServer()) { bool simulationBlocked = !entity->getSimulatorID().isNull(); if (properties.simulationOwnerChanged()) { QUuid submittedID = properties.getSimulationOwner().getID(); @@ -674,7 +674,7 @@ void EntityTree::deleteEntitiesByID(const std::vector& ids, bool f // this method has two paths: // (a) entity-server: applies delete filter // (b) interface-client: deletes local- and my-avatar-entities immediately, submits domainEntity deletes to the entity-server - if (getIsServer()) { + if (isEntityServer()) { withWriteLock([&] { std::vector entitiesToDelete; entitiesToDelete.reserve(ids.size()); @@ -1110,6 +1110,42 @@ void EntityTree::evalEntitiesInSphereWithName(const glm::vec3& center, float rad foundEntities.swap(args.entities); } +class FindEntitiesInSphereWithTagsArgs { +public: + // Inputs + glm::vec3 position; + float targetRadius; + QVector tags; + bool caseSensitive; + PickFilter searchFilter; + + // Outputs + QVector entities; +}; + +bool evalInSphereWithTagsOperation(const OctreeElementPointer& element, void* extraData) { + FindEntitiesInSphereWithTagsArgs* args = static_cast(extraData); + glm::vec3 penetration; + bool sphereIntersection = element->getAACube().findSpherePenetration(args->position, args->targetRadius, penetration); + + // If this element contains the point, then search it... + if (sphereIntersection) { + EntityTreeElementPointer entityTreeElement = std::static_pointer_cast(element); + entityTreeElement->evalEntitiesInSphereWithTags(args->position, args->targetRadius, args->tags, args->caseSensitive, args->searchFilter, args->entities); + return true; // keep searching in case children have closer entities + } + + // if this element doesn't contain the point, then none of it's children can contain the point, so stop searching + return false; +} + +// NOTE: assumes caller has handled locking +void EntityTree::evalEntitiesInSphereWithTags(const glm::vec3& center, float radius, const QVector& tags, bool caseSensitive, PickFilter searchFilter, QVector& foundEntities) { + FindEntitiesInSphereWithTagsArgs args = { center, radius, tags, caseSensitive, searchFilter, QVector() }; + recurseTreeWithOperation(evalInSphereWithTagsOperation, &args); + foundEntities.swap(args.entities); +} + class FindEntitiesInCubeArgs { public: // Inputs @@ -1432,7 +1468,7 @@ bool EntityTree::isScriptInAllowlist(const QString& scriptProperty) { // NOTE: Caller must lock the tree before calling this. int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode) { - if (!getIsServer()) { + if (!isEntityServer()) { qCWarning(entities) << "EntityTree::processEditPacketData() should only be called on a server tree."; return 0; } @@ -2035,7 +2071,7 @@ int EntityTree::processEraseMessage(ReceivedMessage& message, const SharedNodePo // Which means this is a state synchronization message from the the entity-server. It is saying // "The following domain-entities have already been deleted". While need to perform sanity checking // (e.g. verify these are domain entities) permissions need NOT checked for the domain-entities. - assert(!getIsServer()); + assert(!isEntityServer()); // TODO: remove this stuff out of EntityTree:: and into interface-client code. #ifdef EXTRA_ERASE_DEBUGGING qCDebug(entities) << "EntityTree::processEraseMessage()"; @@ -2105,7 +2141,7 @@ int EntityTree::processEraseMessage(ReceivedMessage& message, const SharedNodePo int EntityTree::processEraseMessageDetails(const QByteArray& dataByteArray, const SharedNodePointer& sourceNode) { // NOTE: this is called on entity-server when receiving a delete request from an interface-client or agent //TODO: assert(treeIsLocked); - assert(getIsServer()); + assert(isEntityServer()); #ifdef EXTRA_ERASE_DEBUGGING qCDebug(entities) << "EntityTree::processEraseMessageDetails()"; #endif @@ -2768,8 +2804,8 @@ bool EntityTree::readFromMap(QVariantMap& map, const bool isImport) { // Use skybox value only if it is not empty, else set ambientMode to inherit (to use default URL) properties.setAmbientLightMode(COMPONENT_MODE_ENABLED); if (properties.getAmbientLight().getAmbientURL() == "") { - if (properties.getSkybox().getURL() != "") { - properties.getAmbientLight().setAmbientURL(properties.getSkybox().getURL()); + if (properties.getSkybox().getUrl() != "") { + properties.getAmbientLight().setAmbientURL(properties.getSkybox().getUrl()); } else { properties.setAmbientLightMode(COMPONENT_MODE_INHERIT); } @@ -2854,6 +2890,11 @@ bool EntityTree::readFromMap(QVariantMap& map, const bool isImport) { } } + // Before, animations weren't smoothed + if (contentVersion < (int)EntityVersion::AnimationSmoothFrames && properties.getType() == EntityTypes::EntityType::Model) { + properties.getAnimation().setSmoothFrames(false); + } + EntityItemPointer entity = addEntity(entityItemID, properties, isImport); if (!entity) { qCDebug(entities) << "adding Entity failed:" << entityItemID << properties.getType(); diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index ec209b37ad4..99028adfb7a 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -139,6 +139,7 @@ class EntityTree : public Octree, public SpatialParentTree { void evalEntitiesInSphere(const glm::vec3& center, float radius, PickFilter searchFilter, QVector& foundEntities); void evalEntitiesInSphereWithType(const glm::vec3& center, float radius, EntityTypes::EntityType type, PickFilter searchFilter, QVector& foundEntities); void evalEntitiesInSphereWithName(const glm::vec3& center, float radius, const QString& name, bool caseSensitive, PickFilter searchFilter, QVector& foundEntities); + void evalEntitiesInSphereWithTags(const glm::vec3& center, float radius, const QVector& tags, bool caseSensitive, PickFilter searchFilter, QVector& foundEntities); void evalEntitiesInCube(const AACube& cube, PickFilter searchFilter, QVector& foundEntities); void evalEntitiesInBox(const AABox& box, PickFilter searchFilter, QVector& foundEntities); void evalEntitiesInFrustum(const ViewFrustum& frustum, PickFilter searchFilter, QVector& foundEntities); @@ -257,6 +258,9 @@ class EntityTree : public Octree, public SpatialParentTree { void setIsServerlessMode(bool value) { _serverlessDomain = value; } bool isServerlessMode() const { return _serverlessDomain; } + void setIsEntityServer(bool value) { _entityServer = value; } + bool isEntityServer() const { return _entityServer; } + static void setGetEntityObjectOperator(std::function getEntityObjectOperator) { _getEntityObjectOperator = getEntityObjectOperator; } static QObject* getEntityObject(const QUuid& id); @@ -380,6 +384,7 @@ class EntityTree : public Octree, public SpatialParentTree { std::vector _staleProxies; bool _serverlessDomain { false }; + bool _entityServer { false }; std::map _namedPaths; diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index f330058a787..6b38a17d821 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -257,8 +257,8 @@ EntityItemID EntityTreeElement::evalDetailedRayIntersection(const glm::vec3& ori } } else { // if the entity type doesn't support a detailed intersection, then just return the non-AABox results - // Never intersect with particle entities - if (localDistance < distance && entity->getType() != EntityTypes::ParticleEffect) { + // Never intersect with particle or sound entities + if (localDistance < distance && (entity->getType() != EntityTypes::ParticleEffect && entity->getType() != EntityTypes::ProceduralParticleEffect && entity->getType() != EntityTypes::Sound)) { distance = localDistance; face = localFace; surfaceNormal = glm::vec3(rotation * glm::vec4(localSurfaceNormal, 0.0f)); @@ -409,8 +409,8 @@ EntityItemID EntityTreeElement::evalDetailedParabolaIntersection(const glm::vec3 } } else { // if the entity type doesn't support a detailed intersection, then just return the non-AABox results - // Never intersect with particle entities - if (localDistance < parabolicDistance && entity->getType() != EntityTypes::ParticleEffect) { + // Never intersect with particle or sound entities + if (localDistance < parabolicDistance && (entity->getType() != EntityTypes::ParticleEffect && entity->getType() != EntityTypes::ProceduralParticleEffect && entity->getType() != EntityTypes::Sound)) { parabolicDistance = localDistance; face = localFace; surfaceNormal = glm::vec3(rotation * glm::vec4(localSurfaceNormal, 0.0f)); @@ -602,6 +602,78 @@ void EntityTreeElement::evalEntitiesInSphereWithName(const glm::vec3& position, }); } +void EntityTreeElement::evalEntitiesInSphereWithTags(const glm::vec3& position, float radius, const QVector& tags, bool caseSensitive, PickFilter searchFilter, QVector& foundEntities) const { + forEachEntity([&](EntityItemPointer entity) { + if (!checkFilterSettings(entity, searchFilter)) { + return; + } + + QSet entityTags = entity->getTags(); + for (const QString& tag : tags) { + if (caseSensitive && !entityTags.contains(tag)) { + return; + } else { + const QString lowerTag = tag.toLower(); + bool found = false; + for (const QString& entityTag : entityTags) { + if (lowerTag == entityTag.toLower()) { + found = true; + break; + } + } + if (!found) { + return; + } + } + } + + bool success; + AABox entityBox = entity->getAABox(success); + + // if the sphere doesn't intersect with our world frame AABox, we don't need to consider the more complex case + glm::vec3 penetration; + if (success && entityBox.findSpherePenetration(position, radius, penetration)) { + + glm::vec3 dimensions = entity->getScaledDimensions(); + + // FIXME - consider allowing the entity to determine penetration so that + // entities could presumably do actual hull testing if they wanted to + // FIXME - handle entity->getShapeType() == SHAPE_TYPE_SPHERE case better in particular + // can we handle the ellipsoid case better? We only currently handle perfect spheres + // with centered registration points + if (entity->getShapeType() == SHAPE_TYPE_SPHERE && (dimensions.x == dimensions.y && dimensions.y == dimensions.z)) { + + // NOTE: entity->getRadius() doesn't return the true radius, it returns the radius of the + // maximum bounding sphere, which is actually larger than our actual radius + float entityTrueRadius = dimensions.x / 2.0f; + bool success; + glm::vec3 center = entity->getCenterPosition(success); + + if (success && findSphereSpherePenetration(position, radius, center, entityTrueRadius, penetration)) { + foundEntities.push_back(entity->getID()); + } + } else { + // determine the worldToEntityMatrix that doesn't include scale because + // we're going to use the registration aware aa box in the entity frame + glm::mat4 translation = glm::translate(entity->getWorldPosition()); + glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation()); + glm::mat4 entityToWorldMatrix = translation * rotation; + glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix); + + glm::vec3 registrationPoint = entity->getRegistrationPoint(); + glm::vec3 corner = -(dimensions * registrationPoint) + entity->getPivot(); + + AABox entityFrameBox(corner, dimensions); + + glm::vec3 entityFrameSearchPosition = glm::vec3(worldToEntityMatrix * glm::vec4(position, 1.0f)); + if (entityFrameBox.findSpherePenetration(entityFrameSearchPosition, radius, penetration)) { + foundEntities.push_back(entity->getID()); + } + } + } + }); +} + void EntityTreeElement::evalEntitiesInCube(const AACube& cube, PickFilter searchFilter, QVector& foundEntities) const { forEachEntity([&](EntityItemPointer entity) { if (!checkFilterSettings(entity, searchFilter)) { diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index dab56132c99..951481fcb90 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -177,6 +177,7 @@ class EntityTreeElement : public OctreeElement, ReadWriteLockable { void evalEntitiesInSphere(const glm::vec3& position, float radius, PickFilter searchFilter, QVector& foundEntities) const; void evalEntitiesInSphereWithType(const glm::vec3& position, float radius, EntityTypes::EntityType type, PickFilter searchFilter, QVector& foundEntities) const; void evalEntitiesInSphereWithName(const glm::vec3& position, float radius, const QString& name, bool caseSensitive, PickFilter searchFilter, QVector& foundEntities) const; + void evalEntitiesInSphereWithTags(const glm::vec3& position, float radius, const QVector& tags, bool caseSensitive, PickFilter searchFilter, QVector& foundEntities) const; void evalEntitiesInCube(const AACube& cube, PickFilter searchFilter, QVector& foundEntities) const; void evalEntitiesInBox(const AABox& box, PickFilter searchFilter, QVector& foundEntities) const; void evalEntitiesInFrustum(const ViewFrustum& frustum, PickFilter searchFilter, QVector& foundEntities) const; diff --git a/libraries/entities/src/EntityTypes.cpp b/libraries/entities/src/EntityTypes.cpp index 95057bedbc2..2873920793f 100644 --- a/libraries/entities/src/EntityTypes.cpp +++ b/libraries/entities/src/EntityTypes.cpp @@ -4,6 +4,7 @@ // // Created by Brad Hefta-Gaub on 12/4/13. // Copyright 2013 High Fidelity, Inc. +// Copyright 2023 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -23,6 +24,7 @@ #include "ShapeEntityItem.h" #include "ModelEntityItem.h" #include "ParticleEffectEntityItem.h" +#include "ProceduralParticleEffectEntityItem.h" #include "TextEntityItem.h" #include "ImageEntityItem.h" #include "WebEntityItem.h" @@ -34,6 +36,7 @@ #include "LightEntityItem.h" #include "ZoneEntityItem.h" #include "MaterialEntityItem.h" +#include "SoundEntityItem.h" QMap EntityTypes::_typeToNameMap; QMap EntityTypes::_nameToTypeMap; @@ -51,6 +54,7 @@ REGISTER_ENTITY_TYPE(Text) REGISTER_ENTITY_TYPE(Image) REGISTER_ENTITY_TYPE(Web) REGISTER_ENTITY_TYPE(ParticleEffect) +REGISTER_ENTITY_TYPE(ProceduralParticleEffect) REGISTER_ENTITY_TYPE(Line) REGISTER_ENTITY_TYPE(PolyLine) REGISTER_ENTITY_TYPE(PolyVox) @@ -59,6 +63,7 @@ REGISTER_ENTITY_TYPE(Gizmo) REGISTER_ENTITY_TYPE(Light) REGISTER_ENTITY_TYPE(Zone) REGISTER_ENTITY_TYPE(Material) +REGISTER_ENTITY_TYPE(Sound) bool EntityTypes::typeIsValid(EntityType type) { return type > EntityType::Unknown && type <= EntityType::NUM_TYPES; diff --git a/libraries/entities/src/EntityTypes.h b/libraries/entities/src/EntityTypes.h index 441e77fccd7..ab3233e639c 100644 --- a/libraries/entities/src/EntityTypes.h +++ b/libraries/entities/src/EntityTypes.h @@ -4,6 +4,7 @@ // // Created by Brad Hefta-Gaub on 12/4/13. // Copyright 2013 High Fidelity, Inc. +// Copyright 2023 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -70,6 +71,9 @@ class EntityTypes { * "ParticleEffect"A particle system that can be used to simulate things such as fire, * smoke, snow, magic spells, etc. * {@link Entities.EntityProperties-ParticleEffect|EntityProperties-ParticleEffect} + * "ProceduralParticleEffect"A GPU particle system with custom update and rendering that can + * be used to simulate things such as fire, smoke, snow, magic spells, etc. + * {@link Entities.EntityProperties-ProceduralParticleEffect|EntityProperties-ProceduralParticleEffect} * "Line"A sequence of one or more simple straight lines. * {@link Entities.EntityProperties-Line|EntityProperties-Line} * "PolyLine"A sequence of one or more textured straight lines. @@ -86,6 +90,8 @@ class EntityTypes { * {@link Entities.EntityProperties-Zone|EntityProperties-Zone} * "Material"Modifies the existing materials on entities and avatars. * {@link Entities.EntityProperties-Material|EntityProperties-Material} + * "Sound"Plays a sound. + * {@link Entities.EntityProperties-Material|EntityProperties-Sound} * * * @typedef {string} Entities.EntityType @@ -100,6 +106,7 @@ class EntityTypes { Image, Web, ParticleEffect, + ProceduralParticleEffect, Line, PolyLine, PolyVox, @@ -108,6 +115,7 @@ class EntityTypes { Light, Zone, Material, + Sound, NUM_TYPES } EntityType; diff --git a/libraries/entities/src/GizmoEntityItem.cpp b/libraries/entities/src/GizmoEntityItem.cpp.in similarity index 77% rename from libraries/entities/src/GizmoEntityItem.cpp rename to libraries/entities/src/GizmoEntityItem.cpp.in index c53f2293fb2..ea48d9bcffe 100644 --- a/libraries/entities/src/GizmoEntityItem.cpp +++ b/libraries/entities/src/GizmoEntityItem.cpp.in @@ -34,10 +34,7 @@ void GizmoEntityItem::setUnscaledDimensions(const glm::vec3& value) { EntityItemProperties GizmoEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class - COPY_ENTITY_PROPERTY_TO_PROPERTIES(gizmoType, getGizmoType); - withReadLock([&] { - _ringProperties.getProperties(properties); - }); +@Gizmo_ENTITY_COPY_TO@ return properties; } @@ -45,16 +42,33 @@ EntityItemProperties GizmoEntityItem::getProperties(const EntityPropertyFlags& d bool GizmoEntityItem::setSubClassProperties(const EntityItemProperties& properties) { bool somethingChanged = false; - SET_ENTITY_PROPERTY_FROM_PROPERTIES(gizmoType, setGizmoType); - withWriteLock([&] { - bool ringPropertiesChanged = _ringProperties.setProperties(properties); - somethingChanged |= ringPropertiesChanged; - _needsRenderUpdate |= ringPropertiesChanged; - }); +@Gizmo_ENTITY_SET_FROM@ return somethingChanged; } +EntityPropertyFlags GizmoEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + +@Gizmo_REQUESTED_PROPS@ + + return requestedProperties; +} + +void GizmoEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@Gizmo_ENTITY_APPEND@ + +} + int GizmoEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData, @@ -63,42 +77,21 @@ int GizmoEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesRead = 0; const unsigned char* dataAt = data; - READ_ENTITY_PROPERTY(PROP_GIZMO_TYPE, GizmoType, setGizmoType); - withWriteLock([&] { - int bytesFromRing = _ringProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, - somethingChanged); - bytesRead += bytesFromRing; - dataAt += bytesFromRing; - }); +@Gizmo_ENTITY_READ@ return bytesRead; } -EntityPropertyFlags GizmoEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { - EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); - - requestedProperties += PROP_GIZMO_TYPE; - requestedProperties += _ringProperties.getEntityProperties(params); - - return requestedProperties; -} - -void GizmoEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const { +void GizmoEntityItem::debugDump() const { + qCDebug(entities) << "GizmoEntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " editedAgo:" << debugTime(getLastEdited(), usecTimestampNow()); + qCDebug(entities) << " pointer:" << this; - bool successPropertyFits = true; +@Gizmo_ENTITY_DEBUG@ - APPEND_ENTITY_PROPERTY(PROP_GIZMO_TYPE, (uint32_t)getGizmoType()); - withReadLock([&] { - _ringProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, - propertyFlags, propertiesDidntFit, propertyCount, appendState); - }); } bool GizmoEntityItem::supportsDetailedIntersection() const { @@ -181,19 +174,6 @@ bool GizmoEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, return false; } -void GizmoEntityItem::setGizmoType(GizmoType value) { - withWriteLock([&] { - _needsRenderUpdate |= _gizmoType != value; - _gizmoType = value; - }); -} - -GizmoType GizmoEntityItem::getGizmoType() const { - return resultWithReadLock([&] { - return _gizmoType; - }); -} - RingGizmoPropertyGroup GizmoEntityItem::getRingProperties() const { return resultWithReadLock([&] { return _ringProperties; diff --git a/libraries/entities/src/GizmoEntityItem.h b/libraries/entities/src/GizmoEntityItem.h.in similarity index 54% rename from libraries/entities/src/GizmoEntityItem.h rename to libraries/entities/src/GizmoEntityItem.h.in index a05c2945237..9396bcc91ef 100644 --- a/libraries/entities/src/GizmoEntityItem.h +++ b/libraries/entities/src/GizmoEntityItem.h.in @@ -21,28 +21,10 @@ class GizmoEntityItem : public EntityItem { GizmoEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated + ENTITY_PROPERTY_SUBCLASS_METHODS virtual void setUnscaledDimensions(const glm::vec3& value) override; - // methods for getting/setting all properties of an entity - EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - bool setSubClassProperties(const EntityItemProperties& properties) override; - - EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; - - void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const override; - - int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, - ReadBitstreamToTreeParams& args, - EntityPropertyFlags& propertyFlags, bool overwriteLocalData, - bool& somethingChanged) override; - bool supportsDetailedIntersection() const override; bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance, @@ -54,14 +36,11 @@ class GizmoEntityItem : public EntityItem { QVariantMap& extraInfo, bool precisionPicking) const override; bool getRotateForPicking() const override { return getBillboardMode() != BillboardMode::NONE; } - GizmoType getGizmoType() const; - void setGizmoType(GizmoType value); - RingGizmoPropertyGroup getRingProperties() const; protected: - GizmoType _gizmoType; - RingGizmoPropertyGroup _ringProperties; + +@Gizmo_ENTITY_PROPS@ }; diff --git a/libraries/entities/src/GrabPropertyGroup.cpp b/libraries/entities/src/GrabPropertyGroup.cpp deleted file mode 100644 index a4037ff98fb..00000000000 --- a/libraries/entities/src/GrabPropertyGroup.cpp +++ /dev/null @@ -1,354 +0,0 @@ -// -// GrabPropertyGroup.h -// libraries/entities/src -// -// Created by Seth Alves on 2018-8-8. -// Copyright 2018 High Fidelity, Inc. -// Copyright 2023 Overte e.V. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// SPDX-License-Identifier: Apache-2.0 -// - -#include "GrabPropertyGroup.h" - -#include - -#include "EntityItemProperties.h" -#include "EntityItemPropertiesMacros.h" - -void GrabPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, - ScriptEngine* engine, bool skipDefaults, - EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, - bool isMyOwnAvatarEntity) const { - auto nodeList = DependencyManager::get(); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_GRABBABLE, Grab, grab, Grabbable, grabbable); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_KINEMATIC, Grab, grab, GrabKinematic, grabKinematic); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_FOLLOWS_CONTROLLER, Grab, grab, GrabFollowsController, grabFollowsController); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_TRIGGERABLE, Grab, grab, Triggerable, triggerable); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_EQUIPPABLE, Grab, grab, Equippable, equippable); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_DELEGATE_TO_PARENT, Grab, grab, - GrabDelegateToParent, grabDelegateToParent); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, Grab, grab, - EquippableLeftPosition, equippableLeftPosition); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, Grab, grab, - EquippableLeftRotation, equippableLeftRotation); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, Grab, grab, - EquippableRightPosition, equippableRightPosition); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, Grab, grab, - EquippableRightRotation, equippableRightRotation); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, Grab, grab, - EquippableIndicatorURL, equippableIndicatorURL); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, Grab, grab, - EquippableIndicatorScale, equippableIndicatorScale); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, Grab, grab, - EquippableIndicatorOffset, equippableIndicatorOffset); - -} - -void GrabPropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) { - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, grabbable, bool, setGrabbable); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, grabKinematic, bool, setGrabKinematic); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, grabFollowsController, bool, setGrabFollowsController); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, triggerable, bool, setTriggerable); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, equippable, bool, setEquippable); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, grabDelegateToParent, bool, setGrabDelegateToParent); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, equippableLeftPosition, vec3, setEquippableLeftPosition); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, equippableLeftRotation, quat, setEquippableLeftRotation); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, equippableRightPosition, vec3, setEquippableRightPosition); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, equippableRightRotation, quat, setEquippableRightRotation); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, equippableIndicatorURL, QString, setEquippableIndicatorURL); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, equippableIndicatorScale, vec3, setEquippableIndicatorScale); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(grab, equippableIndicatorOffset, vec3, setEquippableIndicatorOffset); -} - -void GrabPropertyGroup::merge(const GrabPropertyGroup& other) { - COPY_PROPERTY_IF_CHANGED(grabbable); - COPY_PROPERTY_IF_CHANGED(grabKinematic); - COPY_PROPERTY_IF_CHANGED(grabFollowsController); - COPY_PROPERTY_IF_CHANGED(triggerable); - COPY_PROPERTY_IF_CHANGED(equippable); - COPY_PROPERTY_IF_CHANGED(grabDelegateToParent); - COPY_PROPERTY_IF_CHANGED(equippableLeftPosition); - COPY_PROPERTY_IF_CHANGED(equippableLeftRotation); - COPY_PROPERTY_IF_CHANGED(equippableRightPosition); - COPY_PROPERTY_IF_CHANGED(equippableRightRotation); - COPY_PROPERTY_IF_CHANGED(equippableIndicatorURL); - COPY_PROPERTY_IF_CHANGED(equippableIndicatorScale); - COPY_PROPERTY_IF_CHANGED(equippableIndicatorOffset); -} - -void GrabPropertyGroup::debugDump() const { - qCDebug(entities) << " GrabPropertyGroup: ---------------------------------------------"; - - qCDebug(entities) << " _grabbable:" << _grabbable; - qCDebug(entities) << " _grabKinematic:" << _grabKinematic; - qCDebug(entities) << " _grabFollowsController:" << _grabFollowsController; - qCDebug(entities) << " _triggerable:" << _triggerable; - qCDebug(entities) << " _equippable:" << _equippable; - qCDebug(entities) << " _equippableLeftPosition:" << _equippableLeftPosition; - qCDebug(entities) << " _equippableLeftRotation:" << _equippableLeftRotation; - qCDebug(entities) << " _equippableRightPosition:" << _equippableRightPosition; - qCDebug(entities) << " _equippableRightRotation:" << _equippableRightRotation; - qCDebug(entities) << " _equippableIndicatorURL:" << _equippableIndicatorURL; - qCDebug(entities) << " _equippableIndicatorScale:" << _equippableIndicatorScale; - qCDebug(entities) << " _equippableIndicatorOffset:" << _equippableIndicatorOffset; -} - -void GrabPropertyGroup::listChangedProperties(QList& out) { - if (grabbableChanged()) { - out << "grab-grabbable"; - } - if (grabKinematicChanged()) { - out << "grab-grabKinematic"; - } - if (grabFollowsControllerChanged()) { - out << "grab-followsController"; - } - if (triggerableChanged()) { - out << "grab-triggerable"; - } - if (equippableChanged()) { - out << "grab-equippable"; - } - if (grabDelegateToParentChanged()) { - out << "grab-grabDelegateToParent"; - } - if (equippableLeftPositionChanged()) { - out << "grab-equippableLeftPosition"; - } - if (equippableLeftRotationChanged()) { - out << "grab-equippableLeftRotation"; - } - if (equippableRightPositionChanged()) { - out << "grab-equippableRightPosition"; - } - if (equippableRightRotationChanged()) { - out << "grab-equippableRightRotation"; - } - if (equippableIndicatorURLChanged()) { - out << "grab-equippableIndicatorURL"; - } - if (equippableIndicatorScaleChanged()) { - out << "grab-equippableIndicatorScale"; - } - if (equippableIndicatorOffsetChanged()) { - out << "grab-equippableIndicatorOffset"; - } -} - -bool GrabPropertyGroup::appendToEditPacket(OctreePacketData* packetData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const { - - bool successPropertyFits = true; - - APPEND_ENTITY_PROPERTY(PROP_GRAB_GRABBABLE, getGrabbable()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_KINEMATIC, getGrabKinematic()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_FOLLOWS_CONTROLLER, getGrabFollowsController()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_TRIGGERABLE, getTriggerable()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE, getEquippable()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_DELEGATE_TO_PARENT, getGrabDelegateToParent()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, getEquippableLeftPosition()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, getEquippableLeftRotation()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, getEquippableRightPosition()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, getEquippableRightRotation()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, getEquippableIndicatorURL()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, getEquippableIndicatorScale()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, getEquippableIndicatorOffset()); - - return true; -} - -bool GrabPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, - const unsigned char*& dataAt , int& processedBytes) { - - int bytesRead = 0; - bool overwriteLocalData = true; - bool somethingChanged = false; - - READ_ENTITY_PROPERTY(PROP_GRAB_GRABBABLE, bool, setGrabbable); - READ_ENTITY_PROPERTY(PROP_GRAB_KINEMATIC, bool, setGrabKinematic); - READ_ENTITY_PROPERTY(PROP_GRAB_FOLLOWS_CONTROLLER, bool, setGrabFollowsController); - READ_ENTITY_PROPERTY(PROP_GRAB_TRIGGERABLE, bool, setTriggerable); - READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE, bool, setEquippable); - READ_ENTITY_PROPERTY(PROP_GRAB_DELEGATE_TO_PARENT, bool, setGrabDelegateToParent); - READ_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, glm::vec3, setEquippableLeftPosition); - READ_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, glm::quat, setEquippableLeftRotation); - READ_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, glm::vec3, setEquippableRightPosition); - READ_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, glm::quat, setEquippableRightRotation); - READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, QString, setEquippableIndicatorURL); - READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, glm::vec3, setEquippableIndicatorScale); - READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, glm::vec3, setEquippableIndicatorOffset); - - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_GRABBABLE, Grabbable); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_KINEMATIC, GrabKinematic); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_FOLLOWS_CONTROLLER, GrabFollowsController); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_TRIGGERABLE, Triggerable); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_EQUIPPABLE, Equippable); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_DELEGATE_TO_PARENT, GrabDelegateToParent); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, EquippableLeftPosition); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, EquippableLeftRotation); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, EquippableRightPosition); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, EquippableRightRotation); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, EquippableIndicatorURL); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, EquippableIndicatorScale); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, EquippableIndicatorOffset); - - processedBytes += bytesRead; - - Q_UNUSED(somethingChanged); - - return true; -} - -void GrabPropertyGroup::markAllChanged() { - _grabbableChanged = true; - _grabKinematicChanged = true; - _grabFollowsControllerChanged = true; - _triggerableChanged = true; - _equippableChanged = true; - _grabDelegateToParentChanged = true; - _equippableLeftPositionChanged = true; - _equippableLeftRotationChanged = true; - _equippableRightPositionChanged = true; - _equippableRightRotationChanged = true; - _equippableIndicatorURLChanged = true; - _equippableIndicatorScaleChanged = true; - _equippableIndicatorOffsetChanged = true; -} - -EntityPropertyFlags GrabPropertyGroup::getChangedProperties() const { - EntityPropertyFlags changedProperties; - - CHECK_PROPERTY_CHANGE(PROP_GRAB_GRABBABLE, grabbable); - CHECK_PROPERTY_CHANGE(PROP_GRAB_KINEMATIC, grabKinematic); - CHECK_PROPERTY_CHANGE(PROP_GRAB_FOLLOWS_CONTROLLER, grabFollowsController); - CHECK_PROPERTY_CHANGE(PROP_GRAB_TRIGGERABLE, triggerable); - CHECK_PROPERTY_CHANGE(PROP_GRAB_EQUIPPABLE, equippable); - CHECK_PROPERTY_CHANGE(PROP_GRAB_DELEGATE_TO_PARENT, grabDelegateToParent); - CHECK_PROPERTY_CHANGE(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, equippableLeftPosition); - CHECK_PROPERTY_CHANGE(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, equippableLeftRotation); - CHECK_PROPERTY_CHANGE(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, equippableRightPosition); - CHECK_PROPERTY_CHANGE(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, equippableRightRotation); - CHECK_PROPERTY_CHANGE(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, equippableIndicatorURL); - CHECK_PROPERTY_CHANGE(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, equippableIndicatorScale); - CHECK_PROPERTY_CHANGE(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, equippableIndicatorOffset); - - return changedProperties; -} - -void GrabPropertyGroup::getProperties(EntityItemProperties& properties) const { - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, Grabbable, getGrabbable); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, GrabKinematic, getGrabKinematic); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, GrabFollowsController, getGrabFollowsController); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, Triggerable, getTriggerable); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, Equippable, getEquippable); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, GrabDelegateToParent, getGrabDelegateToParent); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, EquippableLeftPosition, getEquippableLeftPosition); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, EquippableLeftRotation, getEquippableLeftRotation); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, EquippableRightPosition, getEquippableRightPosition); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, EquippableRightRotation, getEquippableRightRotation); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, EquippableIndicatorURL, getEquippableIndicatorURL); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, EquippableIndicatorScale, getEquippableIndicatorScale); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Grab, EquippableIndicatorOffset, getEquippableIndicatorOffset); -} - -bool GrabPropertyGroup::setProperties(const EntityItemProperties& properties) { - bool somethingChanged = false; - - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, Grabbable, grabbable, setGrabbable); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, GrabKinematic, grabKinematic, setGrabKinematic); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, GrabFollowsController, grabFollowsController, setGrabFollowsController); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, Triggerable, triggerable, setTriggerable); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, Equippable, equippable, setEquippable); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, GrabDelegateToParent, grabDelegateToParent, setGrabDelegateToParent); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, EquippableLeftPosition, equippableLeftPosition, setEquippableLeftPosition); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, EquippableLeftRotation, equippableLeftRotation, setEquippableLeftRotation); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, EquippableRightPosition, equippableRightPosition, - setEquippableRightPosition); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, EquippableRightRotation, equippableRightRotation, - setEquippableRightRotation); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, EquippableIndicatorURL, equippableIndicatorURL, - setEquippableIndicatorURL); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, EquippableIndicatorScale, equippableIndicatorScale, - setEquippableIndicatorScale); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Grab, EquippableIndicatorOffset, equippableIndicatorOffset, - setEquippableIndicatorOffset); - - return somethingChanged; -} - -EntityPropertyFlags GrabPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { - EntityPropertyFlags requestedProperties; - - requestedProperties += PROP_GRAB_GRABBABLE; - requestedProperties += PROP_GRAB_KINEMATIC; - requestedProperties += PROP_GRAB_FOLLOWS_CONTROLLER; - requestedProperties += PROP_GRAB_TRIGGERABLE; - requestedProperties += PROP_GRAB_EQUIPPABLE; - requestedProperties += PROP_GRAB_DELEGATE_TO_PARENT; - requestedProperties += PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET; - requestedProperties += PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET; - requestedProperties += PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET; - requestedProperties += PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET; - requestedProperties += PROP_GRAB_EQUIPPABLE_INDICATOR_URL; - requestedProperties += PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE; - requestedProperties += PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET; - - return requestedProperties; -} - -void GrabPropertyGroup::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_GRAB_GRABBABLE, getGrabbable()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_KINEMATIC, getGrabKinematic()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_FOLLOWS_CONTROLLER, getGrabFollowsController()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_TRIGGERABLE, getTriggerable()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE, getEquippable()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_DELEGATE_TO_PARENT, getGrabDelegateToParent()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, getEquippableLeftPosition()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, getEquippableLeftRotation()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, getEquippableRightPosition()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, getEquippableRightRotation()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, getEquippableIndicatorURL()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, getEquippableIndicatorScale()); - APPEND_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, getEquippableIndicatorOffset()); -} - -int GrabPropertyGroup::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_GRAB_GRABBABLE, bool, setGrabbable); - READ_ENTITY_PROPERTY(PROP_GRAB_KINEMATIC, bool, setGrabKinematic); - READ_ENTITY_PROPERTY(PROP_GRAB_FOLLOWS_CONTROLLER, bool, setGrabFollowsController); - READ_ENTITY_PROPERTY(PROP_GRAB_TRIGGERABLE, bool, setTriggerable); - READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE, bool, setEquippable); - READ_ENTITY_PROPERTY(PROP_GRAB_DELEGATE_TO_PARENT, bool, setGrabDelegateToParent); - READ_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, glm::vec3, setEquippableLeftPosition); - READ_ENTITY_PROPERTY(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, glm::quat, setEquippableLeftRotation); - READ_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, glm::vec3, setEquippableRightPosition); - READ_ENTITY_PROPERTY(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, glm::quat, setEquippableRightRotation); - READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, QString, setEquippableIndicatorURL); - READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, glm::vec3, setEquippableIndicatorScale); - READ_ENTITY_PROPERTY(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, glm::vec3, setEquippableIndicatorOffset); - - return bytesRead; -} diff --git a/libraries/entities/src/GrabPropertyGroup.cpp.in b/libraries/entities/src/GrabPropertyGroup.cpp.in new file mode 100644 index 00000000000..290e70cd142 --- /dev/null +++ b/libraries/entities/src/GrabPropertyGroup.cpp.in @@ -0,0 +1,140 @@ +// +// GrabPropertyGroup.h +// libraries/entities/src +// +// Created by Seth Alves on 2018-8-8. +// Copyright 2018 High Fidelity, Inc. +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#include "GrabPropertyGroup.h" + +#include + +#include "EntityItemProperties.h" +#include "EntityItemPropertiesMacros.h" + +void GrabPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, + ScriptEngine* engine, bool skipDefaults, + EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, + bool isMyOwnAvatarEntity) const { + auto nodeList = DependencyManager::get(); + +@Grab_GROUP_COPY_TO_SCRIPT@ + +} + +void GrabPropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet& namesSet, bool& _defaultSettings) { + +@Grab_GROUP_COPY_FROM_SCRIPT@ + +} + +void GrabPropertyGroup::merge(const GrabPropertyGroup& other) { + +@Grab_GROUP_MERGE@ + +} + +void GrabPropertyGroup::debugDump() const { + +@Grab_GROUP_DEBUG_DUMP@ + +} + +void GrabPropertyGroup::listChangedProperties(QList& out) { + +@Grab_GROUP_LIST_CHANGED@ + +} + +bool GrabPropertyGroup::appendToEditPacket(OctreePacketData* packetData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@Grab_GROUP_APPEND@ + + return successPropertyFits; +} + +bool GrabPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, + const unsigned char*& dataAt , int& processedBytes) { + + int bytesRead = 0; + bool overwriteLocalData = true; + bool somethingChanged = false; + +@Grab_GROUP_READ@ + +@Grab_GROUP_DECODE_CHANGED@ + + processedBytes += bytesRead; + + return somethingChanged; +} + +void GrabPropertyGroup::markAllChanged() { + +@Grab_GROUP_MARK_CHANGED@ + +} + +EntityPropertyFlags GrabPropertyGroup::getChangedProperties() const { + EntityPropertyFlags changedProperties; + +@Grab_GROUP_CHANGED_PROPERTIES@ + + return changedProperties; +} + +void GrabPropertyGroup::getProperties(EntityItemProperties& properties) const { + +@Grab_GROUP_COPY_TO@ + +} + +bool GrabPropertyGroup::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + +@Grab_GROUP_SET_FROM@ + + return somethingChanged; +} + +EntityPropertyFlags GrabPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties; + +@Grab_REQUESTED_PROPS@ + + return requestedProperties; +} + +int GrabPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + +@Grab_GROUP_READ@ + + return bytesRead; +} + + +void GrabPropertyGroup::addPropertyMap(QHash& _propertyInfos, + QHash& _enumsToPropertyStrings) { + +@Grab_GROUP_ADD_TO_MAP@ + +} diff --git a/libraries/entities/src/GrabPropertyGroup.h b/libraries/entities/src/GrabPropertyGroup.h deleted file mode 100644 index 23211bde213..00000000000 --- a/libraries/entities/src/GrabPropertyGroup.h +++ /dev/null @@ -1,145 +0,0 @@ -// -// GrabPropertyGroup.h -// libraries/entities/src -// -// Created by Seth Alves on 2018-8-8. -// Copyright 2018 High Fidelity, Inc. -// Copyright 2023 Overte e.V. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// SPDX-License-Identifier: Apache-2.0 -// - -#ifndef hifi_GrabPropertyGroup_h -#define hifi_GrabPropertyGroup_h - -#include - -#include - -#include "PropertyGroup.h" -#include "EntityItemPropertiesMacros.h" - -class EntityItemProperties; -class EncodeBitstreamParams; -class OctreePacketData; -class ReadBitstreamToTreeParams; -class ScriptValue; - -static const bool INITIAL_GRABBABLE { true }; -static const bool INITIAL_KINEMATIC { true }; -static const bool INITIAL_FOLLOWS_CONTROLLER { true }; -static const bool INITIAL_TRIGGERABLE { false }; -static const bool INITIAL_EQUIPPABLE { false }; -static const bool INITIAL_GRAB_DELEGATE_TO_PARENT { true }; -static const glm::vec3 INITIAL_LEFT_EQUIPPABLE_POSITION { glm::vec3(0.0f) }; -static const glm::quat INITIAL_LEFT_EQUIPPABLE_ROTATION { glm::quat() }; -static const glm::vec3 INITIAL_RIGHT_EQUIPPABLE_POSITION { glm::vec3(0.0f) }; -static const glm::quat INITIAL_RIGHT_EQUIPPABLE_ROTATION { glm::quat() }; -static const glm::vec3 INITIAL_EQUIPPABLE_INDICATOR_SCALE { glm::vec3(1.0f) }; -static const glm::vec3 INITIAL_EQUIPPABLE_INDICATOR_OFFSET { glm::vec3(0.0f) }; - - -/*@jsdoc - * Grabbing behavior is defined by the following properties: - * - * @typedef {object} Entities.Grab - * @property {boolean} grabbable=true - true if the entity can be grabbed, false if it can't be. - * @property {boolean} grabKinematic=true - true if the entity will be updated in a kinematic manner when - * grabbed; false if it will be grabbed using a tractor action. A kinematic grab will make the item appear - * more tightly held but will cause it to behave poorly when interacting with dynamic entities. - * @property {boolean} grabFollowsController=true - true if the entity will follow the motions of the hand - * controller even if the avatar's hand can't get to the implied position, false if it will follow the motions - * of the avatar's hand. This should be set true for tools, pens, etc. and false for things meant -* to decorate the hand. - * @property {boolean} triggerable=false - true if the entity will receive calls to trigger - * {@link Controller|Controller entity methods}, false if it won't. - * @property {boolean} grabDelegateToParent=true - true if when the entity is grabbed, the grab will be - * transferred to its parent entity if there is one; false if the grab won't be transferred, so a child entity - * can be grabbed and moved relative to its parent. - * @property {boolean} equippable=true - true if the entity can be equipped, false if it cannot. - * @property {Vec3} equippableLeftPosition=0,0,0 - Positional offset from the left hand, when equipped. - * @property {Quat} equippableLeftRotation=0,0,0,1 - Rotational offset from the left hand, when equipped. - * @property {Vec3} equippableRightPosition=0,0,0 - Positional offset from the right hand, when equipped. - * @property {Quat} equippableRightRotation=0,0,0,1 - Rotational offset from the right hand, when equipped. - * @property {string} equippableIndicatorURL="" - If non-empty, this model will be used to indicate that an - * entity is equippable, rather than the default. - * @property {Vec3} equippableIndicatorScale=1,1,1 - If equippableIndicatorURL is non-empty, this controls the - scale of the displayed indicator. - * @property {Vec3} equippableIndicatorOffset=0,0,0 - If equippableIndicatorURL is non-empty, this controls the - relative offset of the displayed object from the equippable entity. - */ -class GrabPropertyGroup : public PropertyGroup { -public: - // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, - ScriptEngine* engine, bool skipDefaults, - EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, - bool isMyOwnAvatarEntity) const override; - virtual void copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) override; - - void merge(const GrabPropertyGroup& other); - - virtual void debugDump() const override; - virtual void listChangedProperties(QList& 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; - - // grab properties - DEFINE_PROPERTY(PROP_GRAB_GRABBABLE, Grabbable, grabbable, bool, INITIAL_GRABBABLE); - DEFINE_PROPERTY(PROP_GRAB_KINEMATIC, GrabKinematic, grabKinematic, bool, INITIAL_KINEMATIC); - DEFINE_PROPERTY(PROP_GRAB_FOLLOWS_CONTROLLER, GrabFollowsController, grabFollowsController, bool, - INITIAL_FOLLOWS_CONTROLLER); - DEFINE_PROPERTY(PROP_GRAB_TRIGGERABLE, Triggerable, triggerable, bool, INITIAL_TRIGGERABLE); - DEFINE_PROPERTY(PROP_GRAB_EQUIPPABLE, Equippable, equippable, bool, INITIAL_EQUIPPABLE); - DEFINE_PROPERTY(PROP_GRAB_DELEGATE_TO_PARENT, GrabDelegateToParent, grabDelegateToParent, bool, - INITIAL_GRAB_DELEGATE_TO_PARENT); - DEFINE_PROPERTY_REF(PROP_GRAB_LEFT_EQUIPPABLE_POSITION_OFFSET, EquippableLeftPosition, equippableLeftPosition, - glm::vec3, INITIAL_LEFT_EQUIPPABLE_POSITION); - DEFINE_PROPERTY_REF(PROP_GRAB_LEFT_EQUIPPABLE_ROTATION_OFFSET, EquippableLeftRotation, equippableLeftRotation, - glm::quat, INITIAL_LEFT_EQUIPPABLE_ROTATION); - DEFINE_PROPERTY_REF(PROP_GRAB_RIGHT_EQUIPPABLE_POSITION_OFFSET, EquippableRightPosition, equippableRightPosition, - glm::vec3, INITIAL_RIGHT_EQUIPPABLE_POSITION); - DEFINE_PROPERTY_REF(PROP_GRAB_RIGHT_EQUIPPABLE_ROTATION_OFFSET, EquippableRightRotation, equippableRightRotation, - glm::quat, INITIAL_RIGHT_EQUIPPABLE_ROTATION); - DEFINE_PROPERTY_REF(PROP_GRAB_EQUIPPABLE_INDICATOR_URL, EquippableIndicatorURL, equippableIndicatorURL, QString, ""); - DEFINE_PROPERTY_REF(PROP_GRAB_EQUIPPABLE_INDICATOR_SCALE, EquippableIndicatorScale, equippableIndicatorScale, - glm::vec3, INITIAL_EQUIPPABLE_INDICATOR_SCALE); - DEFINE_PROPERTY_REF(PROP_GRAB_EQUIPPABLE_INDICATOR_OFFSET, EquippableIndicatorOffset, equippableIndicatorOffset, - glm::vec3, INITIAL_EQUIPPABLE_INDICATOR_OFFSET); -}; - -#endif // hifi_GrabPropertyGroup_h diff --git a/libraries/entities/src/GrabPropertyGroup.h.in b/libraries/entities/src/GrabPropertyGroup.h.in new file mode 100644 index 00000000000..1a0382da26f --- /dev/null +++ b/libraries/entities/src/GrabPropertyGroup.h.in @@ -0,0 +1,83 @@ +// +// GrabPropertyGroup.h +// libraries/entities/src +// +// Created by Seth Alves on 2018-8-8. +// Copyright 2018 High Fidelity, Inc. +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef hifi_GrabPropertyGroup_h +#define hifi_GrabPropertyGroup_h + +#include + +#include + +#include "PropertyGroup.h" +#include "EntityItemPropertiesMacros.h" + +class EntityItemProperties; +class EncodeBitstreamParams; +class OctreePacketData; +class ReadBitstreamToTreeParams; +class ScriptValue; + +static const bool INITIAL_GRABBABLE { true }; +static const bool INITIAL_KINEMATIC { true }; +static const bool INITIAL_FOLLOWS_CONTROLLER { true }; +static const bool INITIAL_TRIGGERABLE { false }; +static const bool INITIAL_EQUIPPABLE { false }; +static const bool INITIAL_GRAB_DELEGATE_TO_PARENT { true }; +static const glm::vec3 INITIAL_LEFT_EQUIPPABLE_POSITION { glm::vec3(0.0f) }; +static const glm::quat INITIAL_LEFT_EQUIPPABLE_ROTATION { glm::quat() }; +static const glm::vec3 INITIAL_RIGHT_EQUIPPABLE_POSITION { glm::vec3(0.0f) }; +static const glm::quat INITIAL_RIGHT_EQUIPPABLE_ROTATION { glm::quat() }; +static const glm::vec3 INITIAL_EQUIPPABLE_INDICATOR_SCALE { glm::vec3(1.0f) }; +static const glm::vec3 INITIAL_EQUIPPABLE_INDICATOR_OFFSET { glm::vec3(0.0f) }; + + +/*@jsdoc + * Grabbing behavior is defined by the following properties: + * + * @typedef {object} Entities.Grab + * @property {boolean} grabbable=true - true if the entity can be grabbed, false if it can't be. + * @property {boolean} grabKinematic=true - true if the entity will be updated in a kinematic manner when + * grabbed; false if it will be grabbed using a tractor action. A kinematic grab will make the item appear + * more tightly held but will cause it to behave poorly when interacting with dynamic entities. + * @property {boolean} grabFollowsController=true - true if the entity will follow the motions of the hand + * controller even if the avatar's hand can't get to the implied position, false if it will follow the motions + * of the avatar's hand. This should be set true for tools, pens, etc. and false for things meant +* to decorate the hand. + * @property {boolean} triggerable=false - true if the entity will receive calls to trigger + * {@link Controller|Controller entity methods}, false if it won't. + * @property {boolean} grabDelegateToParent=true - true if when the entity is grabbed, the grab will be + * transferred to its parent entity if there is one; false if the grab won't be transferred, so a child entity + * can be grabbed and moved relative to its parent. + * @property {boolean} equippable=true - true if the entity can be equipped, false if it cannot. + * @property {Vec3} equippableLeftPosition=0,0,0 - Positional offset from the left hand, when equipped. + * @property {Quat} equippableLeftRotation=0,0,0,1 - Rotational offset from the left hand, when equipped. + * @property {Vec3} equippableRightPosition=0,0,0 - Positional offset from the right hand, when equipped. + * @property {Quat} equippableRightRotation=0,0,0,1 - Rotational offset from the right hand, when equipped. + * @property {string} equippableIndicatorURL="" - If non-empty, this model will be used to indicate that an + * entity is equippable, rather than the default. + * @property {Vec3} equippableIndicatorScale=1,1,1 - If equippableIndicatorURL is non-empty, this controls the + scale of the displayed indicator. + * @property {Vec3} equippableIndicatorOffset=0,0,0 - If equippableIndicatorURL is non-empty, this controls the + relative offset of the displayed object from the equippable entity. + */ +class GrabPropertyGroup : public PropertyGroup { +public: + ENTITY_PROPERTY_GROUP_METHODS(GrabPropertyGroup) + +protected: + +@Grab_GROUP_PROPS@ + +}; + +#endif // hifi_GrabPropertyGroup_h diff --git a/libraries/entities/src/GridEntityItem.cpp b/libraries/entities/src/GridEntityItem.cpp deleted file mode 100644 index 5e749652cc0..00000000000 --- a/libraries/entities/src/GridEntityItem.cpp +++ /dev/null @@ -1,203 +0,0 @@ -// -// Created by Sam Gondelman on 11/29/18 -// 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 "GridEntityItem.h" - -#include "EntityItemProperties.h" - -const uint32_t GridEntityItem::DEFAULT_MAJOR_GRID_EVERY = 5; -const float GridEntityItem::DEFAULT_MINOR_GRID_EVERY = 1.0f; - -EntityItemPointer GridEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - Pointer entity(new GridEntityItem(entityID), [](GridEntityItem* ptr) { ptr->deleteLater(); }); - entity->setProperties(properties); - return entity; -} - -// our non-pure virtual subclass for now... -GridEntityItem::GridEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { - _type = EntityTypes::Grid; -} - -void GridEntityItem::setUnscaledDimensions(const glm::vec3& value) { - const float GRID_ENTITY_ITEM_FIXED_DEPTH = 0.01f; - // NOTE: Grid Entities always have a "depth" of 1cm. - EntityItem::setUnscaledDimensions(glm::vec3(value.x, value.y, GRID_ENTITY_ITEM_FIXED_DEPTH)); -} - -EntityItemProperties GridEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { - EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class - - COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getColor); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha); - withReadLock([&] { - _pulseProperties.getProperties(properties); - }); - - COPY_ENTITY_PROPERTY_TO_PROPERTIES(followCamera, getFollowCamera); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(majorGridEvery, getMajorGridEvery); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(minorGridEvery, getMinorGridEvery); - - return properties; -} - -bool GridEntityItem::setSubClassProperties(const EntityItemProperties& properties) { - bool somethingChanged = false; - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha); - withWriteLock([&] { - bool pulsePropertiesChanged = _pulseProperties.setProperties(properties); - somethingChanged |= pulsePropertiesChanged; - _needsRenderUpdate |= pulsePropertiesChanged; - }); - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(followCamera, setFollowCamera); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(majorGridEvery, setMajorGridEvery); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(minorGridEvery, setMinorGridEvery); - - return somethingChanged; -} - -int GridEntityItem::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_COLOR, u8vec3Color, setColor); - READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha); - withWriteLock([&] { - int bytesFromPulse = _pulseProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, - somethingChanged); - bytesRead += bytesFromPulse; - dataAt += bytesFromPulse; - }); - - READ_ENTITY_PROPERTY(PROP_GRID_FOLLOW_CAMERA, bool, setFollowCamera); - READ_ENTITY_PROPERTY(PROP_MAJOR_GRID_EVERY, uint32_t, setMajorGridEvery); - READ_ENTITY_PROPERTY(PROP_MINOR_GRID_EVERY, float, setMinorGridEvery); - - return bytesRead; -} - -EntityPropertyFlags GridEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { - EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); - - requestedProperties += PROP_COLOR; - requestedProperties += PROP_ALPHA; - requestedProperties += _pulseProperties.getEntityProperties(params); - - requestedProperties += PROP_GRID_FOLLOW_CAMERA; - requestedProperties += PROP_MAJOR_GRID_EVERY; - requestedProperties += PROP_MINOR_GRID_EVERY; - - return requestedProperties; -} - -void GridEntityItem::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_COLOR, getColor()); - APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha()); - withReadLock([&] { - _pulseProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, - propertyFlags, propertiesDidntFit, propertyCount, appendState); - }); - - APPEND_ENTITY_PROPERTY(PROP_GRID_FOLLOW_CAMERA, getFollowCamera()); - APPEND_ENTITY_PROPERTY(PROP_MAJOR_GRID_EVERY, getMajorGridEvery()); - APPEND_ENTITY_PROPERTY(PROP_MINOR_GRID_EVERY, getMinorGridEvery()); -} - -void GridEntityItem::setColor(const glm::u8vec3& color) { - withWriteLock([&] { - _needsRenderUpdate |= _color != color; - _color = color; - }); -} - -glm::u8vec3 GridEntityItem::getColor() const { - return resultWithReadLock([&] { - return _color; - }); -} - -void GridEntityItem::setAlpha(float alpha) { - withWriteLock([&] { - _needsRenderUpdate |= _alpha != alpha; - _alpha = alpha; - }); -} - -float GridEntityItem::getAlpha() const { - return resultWithReadLock([&] { - return _alpha; - }); -} - -void GridEntityItem::setFollowCamera(bool followCamera) { - withWriteLock([&] { - _needsRenderUpdate |= _followCamera != followCamera; - _followCamera = followCamera; - }); -} - -bool GridEntityItem::getFollowCamera() const { - return resultWithReadLock([&] { - return _followCamera; - }); -} - -void GridEntityItem::setMajorGridEvery(uint32_t majorGridEvery) { - const uint32_t MAJOR_GRID_EVERY_MIN = 1; - majorGridEvery = std::max(majorGridEvery, MAJOR_GRID_EVERY_MIN); - - withWriteLock([&] { - _needsRenderUpdate |= _majorGridEvery != majorGridEvery; - _majorGridEvery = majorGridEvery; - }); -} - -uint32_t GridEntityItem::getMajorGridEvery() const { - return resultWithReadLock([&] { - return _majorGridEvery; - }); -} - -void GridEntityItem::setMinorGridEvery(float minorGridEvery) { - const float MINOR_GRID_EVERY_MIN = 0.01f; - minorGridEvery = std::max(minorGridEvery, MINOR_GRID_EVERY_MIN); - - withWriteLock([&] { - _needsRenderUpdate |= _minorGridEvery != minorGridEvery; - _minorGridEvery = minorGridEvery; - }); -} - -float GridEntityItem::getMinorGridEvery() const { - return resultWithReadLock([&] { - return _minorGridEvery; - }); -} - -PulsePropertyGroup GridEntityItem::getPulseProperties() const { - return resultWithReadLock([&] { - return _pulseProperties; - }); -} \ No newline at end of file diff --git a/libraries/entities/src/GridEntityItem.cpp.in b/libraries/entities/src/GridEntityItem.cpp.in new file mode 100644 index 00000000000..a1e83092fa9 --- /dev/null +++ b/libraries/entities/src/GridEntityItem.cpp.in @@ -0,0 +1,132 @@ +// +// Created by Sam Gondelman on 11/29/18 +// 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 "GridEntityItem.h" + +#include "EntityItemProperties.h" + +const uint32_t GridEntityItem::DEFAULT_MAJOR_GRID_EVERY = 5; +const float GridEntityItem::DEFAULT_MINOR_GRID_EVERY = 1.0f; + +EntityItemPointer GridEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + Pointer entity(new GridEntityItem(entityID), [](GridEntityItem* ptr) { ptr->deleteLater(); }); + entity->setProperties(properties); + return entity; +} + +// our non-pure virtual subclass for now... +GridEntityItem::GridEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { + _type = EntityTypes::Grid; +} + +void GridEntityItem::setUnscaledDimensions(const glm::vec3& value) { + const float GRID_ENTITY_ITEM_FIXED_DEPTH = 0.01f; + // NOTE: Grid Entities always have a "depth" of 1cm. + EntityItem::setUnscaledDimensions(glm::vec3(value.x, value.y, GRID_ENTITY_ITEM_FIXED_DEPTH)); +} + +EntityItemProperties GridEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class + +@Grid_ENTITY_COPY_TO@ + + return properties; +} + +bool GridEntityItem::setSubClassProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + +@Grid_ENTITY_SET_FROM@ + + return somethingChanged; +} + +EntityPropertyFlags GridEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + +@Grid_REQUESTED_PROPS@ + + return requestedProperties; +} + +void GridEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@Grid_ENTITY_APPEND@ + +} + +int GridEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + +@Grid_ENTITY_READ@ + + return bytesRead; +} + +void GridEntityItem::debugDump() const { + qCDebug(entities) << "GridEntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " editedAgo:" << debugTime(getLastEdited(), usecTimestampNow()); + qCDebug(entities) << " pointer:" << this; + +@Grid_ENTITY_DEBUG@ + +} + +void GridEntityItem::setMajorGridEvery(uint32_t majorGridEvery) { + const uint32_t MAJOR_GRID_EVERY_MIN = 1; + majorGridEvery = std::max(majorGridEvery, MAJOR_GRID_EVERY_MIN); + + withWriteLock([&] { + _needsRenderUpdate |= _majorGridEvery != majorGridEvery; + _majorGridEvery = majorGridEvery; + }); +} + +uint32_t GridEntityItem::getMajorGridEvery() const { + return resultWithReadLock([&] { + return _majorGridEvery; + }); +} + +void GridEntityItem::setMinorGridEvery(float minorGridEvery) { + const float MINOR_GRID_EVERY_MIN = 0.01f; + minorGridEvery = std::max(minorGridEvery, MINOR_GRID_EVERY_MIN); + + withWriteLock([&] { + _needsRenderUpdate |= _minorGridEvery != minorGridEvery; + _minorGridEvery = minorGridEvery; + }); +} + +float GridEntityItem::getMinorGridEvery() const { + return resultWithReadLock([&] { + return _minorGridEvery; + }); +} + +PulsePropertyGroup GridEntityItem::getPulseProperties() const { + return resultWithReadLock([&] { + return _pulseProperties; + }); +} \ No newline at end of file diff --git a/libraries/entities/src/GridEntityItem.h b/libraries/entities/src/GridEntityItem.h deleted file mode 100644 index 7dc7a475b29..00000000000 --- a/libraries/entities/src/GridEntityItem.h +++ /dev/null @@ -1,77 +0,0 @@ -// -// Created by Sam Gondelman on 11/29/18 -// 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_GridEntityItem_h -#define hifi_GridEntityItem_h - -#include "EntityItem.h" - -#include "PulsePropertyGroup.h" - -class GridEntityItem : public EntityItem { - using Pointer = std::shared_ptr; -public: - static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - - GridEntityItem(const EntityItemID& entityItemID); - - ALLOW_INSTANTIATION // This class can be instantiated - - virtual void setUnscaledDimensions(const glm::vec3& value) override; - - // methods for getting/setting all properties of an entity - EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - bool setSubClassProperties(const EntityItemProperties& properties) override; - - EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; - - void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const override; - - int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, - ReadBitstreamToTreeParams& args, - EntityPropertyFlags& propertyFlags, bool overwriteLocalData, - bool& somethingChanged) override; - - static const uint32_t DEFAULT_MAJOR_GRID_EVERY; - static const float DEFAULT_MINOR_GRID_EVERY; - - void setColor(const glm::u8vec3& color); - glm::u8vec3 getColor() const; - - void setAlpha(float alpha); - float getAlpha() const; - - void setFollowCamera(bool followCamera); - bool getFollowCamera() const; - - void setMajorGridEvery(uint32_t majorGridEvery); - uint32_t getMajorGridEvery() const; - - void setMinorGridEvery(float minorGridEvery); - float getMinorGridEvery() const; - - PulsePropertyGroup getPulseProperties() const; - -protected: - glm::u8vec3 _color; - float _alpha; - PulsePropertyGroup _pulseProperties; - - bool _followCamera { true }; - uint32_t _majorGridEvery { DEFAULT_MAJOR_GRID_EVERY }; - float _minorGridEvery { DEFAULT_MINOR_GRID_EVERY }; - -}; - -#endif // hifi_GridEntityItem_h diff --git a/libraries/entities/src/GridEntityItem.h.in b/libraries/entities/src/GridEntityItem.h.in new file mode 100644 index 00000000000..bbd7b2a6ff8 --- /dev/null +++ b/libraries/entities/src/GridEntityItem.h.in @@ -0,0 +1,39 @@ +// +// Created by Sam Gondelman on 11/29/18 +// 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_GridEntityItem_h +#define hifi_GridEntityItem_h + +#include "EntityItem.h" + +#include "PulsePropertyGroup.h" + +class GridEntityItem : public EntityItem { + using Pointer = std::shared_ptr; +public: + static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); + + GridEntityItem(const EntityItemID& entityItemID); + + ALLOW_INSTANTIATION // This class can be instantiated + ENTITY_PROPERTY_SUBCLASS_METHODS + + virtual void setUnscaledDimensions(const glm::vec3& value) override; + + static const uint32_t DEFAULT_MAJOR_GRID_EVERY; + static const float DEFAULT_MINOR_GRID_EVERY; + + PulsePropertyGroup getPulseProperties() const; + +protected: + +@Grid_ENTITY_PROPS@ + +}; + +#endif // hifi_GridEntityItem_h diff --git a/libraries/entities/src/HazePropertyGroup.cpp b/libraries/entities/src/HazePropertyGroup.cpp deleted file mode 100644 index fd091de8aca..00000000000 --- a/libraries/entities/src/HazePropertyGroup.cpp +++ /dev/null @@ -1,366 +0,0 @@ -// -// HazePropertyGroup.h -// libraries/entities/src -// -// Created by Nissim hadar on 9/21/17. -// Copyright 2013 High Fidelity, Inc. -// Copyright 2023 Overte e.V. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// SPDX-License-Identifier: Apache-2.0 -// - -#include "HazePropertyGroup.h" - -#include - -#include "EntityItemProperties.h" -#include "EntityItemPropertiesMacros.h" - -void HazePropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, - bool skipDefaults, EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, - bool isMyOwnAvatarEntity) const { - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_HAZE_RANGE, Haze, haze, HazeRange, hazeRange); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_HAZE_COLOR, Haze, haze, HazeColor, hazeColor, u8vec3Color); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_HAZE_GLARE_COLOR, Haze, haze, HazeGlareColor, hazeGlareColor, u8vec3Color); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_HAZE_ENABLE_GLARE, Haze, haze, HazeEnableGlare, hazeEnableGlare); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_HAZE_GLARE_ANGLE, Haze, haze, HazeGlareAngle, hazeGlareAngle); - - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_HAZE_ALTITUDE_EFFECT, Haze, haze, HazeAltitudeEffect, hazeAltitudeEffect); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_HAZE_CEILING, Haze, haze, HazeCeiling, hazeCeiling); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_HAZE_BASE_REF, Haze, haze, HazeBaseRef, hazeBaseRef); - - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_HAZE_BACKGROUND_BLEND, Haze, haze, HazeBackgroundBlend, hazeBackgroundBlend); - - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_HAZE_ATTENUATE_KEYLIGHT, Haze, haze, HazeAttenuateKeyLight, hazeAttenuateKeyLight); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_HAZE_KEYLIGHT_RANGE, Haze, haze, HazeKeyLightRange, hazeKeyLightRange); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_HAZE_KEYLIGHT_ALTITUDE, Haze, haze, HazeKeyLightAltitude, hazeKeyLightAltitude); -} - -void HazePropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) { - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(haze, hazeRange, float, setHazeRange); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(haze, hazeColor, u8vec3Color, setHazeColor); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(haze, hazeGlareColor, u8vec3Color, setHazeGlareColor); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(haze, hazeEnableGlare, bool, setHazeEnableGlare); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(haze, hazeGlareAngle, float, setHazeGlareAngle); - - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(haze, hazeAltitudeEffect, bool, setHazeAltitudeEffect); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(haze, hazeCeiling, float, setHazeCeiling); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(haze, hazeBaseRef, float, setHazeBaseRef); - - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(haze, hazeBackgroundBlend, float, setHazeBackgroundBlend); - - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(haze, hazeAttenuateKeyLight, bool, setHazeAttenuateKeyLight); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(haze, hazeKeyLightRange, float, setHazeKeyLightRange); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(haze, hazeKeyLightAltitude, float, setHazeKeyLightAltitude); -} - -void HazePropertyGroup::merge(const HazePropertyGroup& other) { - COPY_PROPERTY_IF_CHANGED(hazeRange); - COPY_PROPERTY_IF_CHANGED(hazeColor); - COPY_PROPERTY_IF_CHANGED(hazeGlareColor); - COPY_PROPERTY_IF_CHANGED(hazeEnableGlare); - COPY_PROPERTY_IF_CHANGED(hazeGlareAngle); - - COPY_PROPERTY_IF_CHANGED(hazeAltitudeEffect); - COPY_PROPERTY_IF_CHANGED(hazeCeiling); - COPY_PROPERTY_IF_CHANGED(hazeBaseRef); - - COPY_PROPERTY_IF_CHANGED(hazeBackgroundBlend); - - COPY_PROPERTY_IF_CHANGED(hazeAttenuateKeyLight); - COPY_PROPERTY_IF_CHANGED(hazeKeyLightRange); - COPY_PROPERTY_IF_CHANGED(hazeKeyLightAltitude); -} - -void HazePropertyGroup::debugDump() const { - qCDebug(entities) << " HazePropertyGroup: ---------------------------------------------"; - - qCDebug(entities) << " _hazeRange:" << _hazeRange; - qCDebug(entities) << " _hazeColor:" << _hazeColor; - qCDebug(entities) << " _hazeGlareColor:" << _hazeGlareColor; - qCDebug(entities) << " _hazeEnableGlare:" << _hazeEnableGlare; - qCDebug(entities) << " _hazeGlareAngle:" << _hazeGlareAngle; - - qCDebug(entities) << " _hazeAltitudeEffect:" << _hazeAltitudeEffect; - qCDebug(entities) << " _hazeCeiling:" << _hazeCeiling; - qCDebug(entities) << " _hazeBaseRef:" << _hazeBaseRef; - - qCDebug(entities) << " _hazeBackgroundBlend:" << _hazeBackgroundBlend; - - qCDebug(entities) << " _hazeAttenuateKeyLight:" << _hazeAttenuateKeyLight; - qCDebug(entities) << " _hazeKeyLightRange:" << _hazeKeyLightRange; - qCDebug(entities) << " _hazeKeyLightAltitude:" << _hazeKeyLightAltitude; -} - -void HazePropertyGroup::listChangedProperties(QList& out) { - if (hazeRangeChanged()) { - out << "haze-hazeRange"; - } - if (hazeColorChanged()) { - out << "haze-hazeColor"; - } - if (hazeGlareColorChanged()) { - out << "haze-hazeGlareColor"; - } - if (hazeEnableGlareChanged()) { - out << "haze-hazeEnableGlare"; - } - if (hazeGlareAngleChanged()) { - out << "haze-hazeGlareAngle"; - } - - if (hazeAltitudeEffectChanged()) { - out << "haze-hazeAltitudeEffect"; - } - if (hazeCeilingChanged()) { - out << "haze-hazeCeiling"; - } - if (hazeBaseRefChanged()) { - out << "haze-hazeBaseRef"; - } - - if (hazeBackgroundBlendChanged()) { - out << "haze-hazeBackgroundBlend"; - } - - if (hazeAttenuateKeyLightChanged()) { - out << "haze-hazeAttenuateKeyLight"; - } - if (hazeKeyLightRangeChanged()) { - out << "haze-hazeKeyLightRange"; - } - if (hazeKeyLightAltitudeChanged()) { - out << "haze-hazeKeyLightAltitude"; - } -} - -bool HazePropertyGroup::appendToEditPacket(OctreePacketData* packetData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const { - - bool successPropertyFits = true; - - APPEND_ENTITY_PROPERTY(PROP_HAZE_RANGE, getHazeRange()); - APPEND_ENTITY_PROPERTY(PROP_HAZE_COLOR, getHazeColor()); - APPEND_ENTITY_PROPERTY(PROP_HAZE_GLARE_COLOR, getHazeGlareColor()); - APPEND_ENTITY_PROPERTY(PROP_HAZE_ENABLE_GLARE, getHazeEnableGlare()); - APPEND_ENTITY_PROPERTY(PROP_HAZE_GLARE_ANGLE, getHazeGlareAngle()); - - APPEND_ENTITY_PROPERTY(PROP_HAZE_ALTITUDE_EFFECT, getHazeAltitudeEffect()); - APPEND_ENTITY_PROPERTY(PROP_HAZE_CEILING, getHazeCeiling()); - APPEND_ENTITY_PROPERTY(PROP_HAZE_BASE_REF, getHazeBaseRef()); - - APPEND_ENTITY_PROPERTY(PROP_HAZE_BACKGROUND_BLEND, getHazeBackgroundBlend()); - - APPEND_ENTITY_PROPERTY(PROP_HAZE_ATTENUATE_KEYLIGHT, getHazeAttenuateKeyLight()); - APPEND_ENTITY_PROPERTY(PROP_HAZE_KEYLIGHT_RANGE, getHazeKeyLightRange()); - APPEND_ENTITY_PROPERTY(PROP_HAZE_KEYLIGHT_ALTITUDE, getHazeKeyLightAltitude()); - - return true; -} - -bool HazePropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) { - - int bytesRead = 0; - bool overwriteLocalData = true; - bool somethingChanged = false; - - READ_ENTITY_PROPERTY(PROP_HAZE_RANGE, float, setHazeRange); - READ_ENTITY_PROPERTY(PROP_HAZE_COLOR, u8vec3Color, setHazeColor); - READ_ENTITY_PROPERTY(PROP_HAZE_GLARE_COLOR, u8vec3Color, setHazeGlareColor); - READ_ENTITY_PROPERTY(PROP_HAZE_ENABLE_GLARE, bool, setHazeEnableGlare); - READ_ENTITY_PROPERTY(PROP_HAZE_GLARE_ANGLE, float, setHazeGlareAngle); - - READ_ENTITY_PROPERTY(PROP_HAZE_ALTITUDE_EFFECT, bool, setHazeAltitudeEffect); - READ_ENTITY_PROPERTY(PROP_HAZE_CEILING, float, setHazeCeiling); - READ_ENTITY_PROPERTY(PROP_HAZE_BASE_REF, float, setHazeBaseRef); - - READ_ENTITY_PROPERTY(PROP_HAZE_BACKGROUND_BLEND, float, setHazeBackgroundBlend); - - READ_ENTITY_PROPERTY(PROP_HAZE_ATTENUATE_KEYLIGHT, bool, setHazeAttenuateKeyLight); - READ_ENTITY_PROPERTY(PROP_HAZE_KEYLIGHT_RANGE, float, setHazeKeyLightRange); - READ_ENTITY_PROPERTY(PROP_HAZE_KEYLIGHT_ALTITUDE, float, setHazeKeyLightAltitude); - - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_HAZE_RANGE, HazeRange); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_HAZE_COLOR, HazeColor); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_HAZE_GLARE_COLOR, HazeGlareColor); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_HAZE_ENABLE_GLARE, HazeEnableGlare); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_HAZE_GLARE_ANGLE, HazeGlareAngle); - - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_HAZE_ALTITUDE_EFFECT, HazeAltitudeEffect); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_HAZE_CEILING, HazeCeiling); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_HAZE_BASE_REF, HazeBaseRef); - - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_HAZE_BACKGROUND_BLEND, HazeBackgroundBlend); - - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_HAZE_ATTENUATE_KEYLIGHT, HazeAttenuateKeyLight); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_HAZE_KEYLIGHT_RANGE, HazeKeyLightRange); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_HAZE_KEYLIGHT_ALTITUDE, HazeKeyLightAltitude); - - processedBytes += bytesRead; - - Q_UNUSED(somethingChanged); - - return true; -} - -void HazePropertyGroup::markAllChanged() { - _hazeRangeChanged = true; - _hazeColorChanged = true; - _hazeGlareColorChanged = true; - _hazeEnableGlareChanged = true; - _hazeGlareAngleChanged = true; - - _hazeAltitudeEffectChanged = true; - _hazeCeilingChanged = true; - _hazeBaseRefChanged = true; - - _hazeBackgroundBlendChanged = true; - - _hazeAttenuateKeyLightChanged = true; - _hazeKeyLightRangeChanged = true; - _hazeKeyLightAltitudeChanged = true; -} - -EntityPropertyFlags HazePropertyGroup::getChangedProperties() const { - EntityPropertyFlags changedProperties; - - CHECK_PROPERTY_CHANGE(PROP_HAZE_RANGE, hazeRange); - CHECK_PROPERTY_CHANGE(PROP_HAZE_COLOR, hazeColor); - CHECK_PROPERTY_CHANGE(PROP_HAZE_GLARE_COLOR, hazeGlareColor); - CHECK_PROPERTY_CHANGE(PROP_HAZE_ENABLE_GLARE, hazeEnableGlare); - CHECK_PROPERTY_CHANGE(PROP_HAZE_GLARE_ANGLE, hazeGlareAngle); - - CHECK_PROPERTY_CHANGE(PROP_HAZE_ALTITUDE_EFFECT, hazeAltitudeEffect); - CHECK_PROPERTY_CHANGE(PROP_HAZE_CEILING, hazeCeiling); - CHECK_PROPERTY_CHANGE(PROP_HAZE_BASE_REF, hazeBaseRef); - - CHECK_PROPERTY_CHANGE(PROP_HAZE_BACKGROUND_BLEND, hazeBackgroundBlend); - - CHECK_PROPERTY_CHANGE(PROP_HAZE_ATTENUATE_KEYLIGHT, hazeAttenuateKeyLight); - CHECK_PROPERTY_CHANGE(PROP_HAZE_KEYLIGHT_RANGE, hazeKeyLightRange); - CHECK_PROPERTY_CHANGE(PROP_HAZE_KEYLIGHT_ALTITUDE, hazeKeyLightAltitude); - - return changedProperties; -} - -void HazePropertyGroup::getProperties(EntityItemProperties& properties) const { - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Haze, HazeRange, getHazeRange); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Haze, HazeColor, getHazeColor); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Haze, HazeGlareColor, getHazeGlareColor); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Haze, HazeEnableGlare, getHazeEnableGlare); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Haze, HazeGlareAngle, getHazeGlareAngle); - - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Haze, HazeAltitudeEffect, getHazeAltitudeEffect); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Haze, HazeCeiling, getHazeCeiling); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Haze, HazeBaseRef, getHazeBaseRef); - - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Haze, HazeBackgroundBlend, getHazeBackgroundBlend); - - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Haze, HazeAttenuateKeyLight, getHazeAttenuateKeyLight); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Haze, HazeKeyLightRange, getHazeKeyLightRange); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Haze, HazeKeyLightAltitude, getHazeKeyLightAltitude); -} - -bool HazePropertyGroup::setProperties(const EntityItemProperties& properties) { - bool somethingChanged = false; - - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Haze, HazeRange, hazeRange, setHazeRange); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Haze, HazeColor, hazeColor, setHazeColor); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Haze, HazeGlareColor, hazeGlareColor, setHazeGlareColor); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Haze, HazeEnableGlare, hazeEnableGlare, setHazeEnableGlare); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Haze, HazeGlareAngle, hazeGlareAngle, setHazeGlareAngle); - - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Haze, HazeAltitudeEffect, hazeAltitudeEffect, setHazeAltitudeEffect); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Haze, HazeCeiling, hazeCeiling, setHazeCeiling); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Haze, HazeBaseRef, hazeBaseRef, setHazeBaseRef); - - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Haze, HazeBackgroundBlend, hazeBackgroundBlend, setHazeBackgroundBlend); - - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Haze, HazeAttenuateKeyLight, hazeAttenuateKeyLight, setHazeAttenuateKeyLight); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Haze, HazeKeyLightRange, hazeKeyLightRange, setHazeKeyLightRange); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Haze, HazeKeyLightAltitude, hazeKeyLightAltitude, setHazeKeyLightAltitude); - - return somethingChanged; -} - -EntityPropertyFlags HazePropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { - EntityPropertyFlags requestedProperties; - - requestedProperties += PROP_HAZE_RANGE; - requestedProperties += PROP_HAZE_COLOR; - requestedProperties += PROP_HAZE_GLARE_COLOR; - requestedProperties += PROP_HAZE_ENABLE_GLARE; - requestedProperties += PROP_HAZE_GLARE_ANGLE; - - requestedProperties += PROP_HAZE_ALTITUDE_EFFECT; - requestedProperties += PROP_HAZE_CEILING; - requestedProperties += PROP_HAZE_BASE_REF; - - requestedProperties += PROP_HAZE_BACKGROUND_BLEND; - - requestedProperties += PROP_HAZE_ATTENUATE_KEYLIGHT; - requestedProperties += PROP_HAZE_KEYLIGHT_RANGE; - requestedProperties += PROP_HAZE_KEYLIGHT_ALTITUDE; - - return requestedProperties; -} - -void HazePropertyGroup::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_HAZE_RANGE, getHazeRange()); - APPEND_ENTITY_PROPERTY(PROP_HAZE_COLOR, getHazeColor()); - APPEND_ENTITY_PROPERTY(PROP_HAZE_GLARE_COLOR, getHazeGlareColor()); - APPEND_ENTITY_PROPERTY(PROP_HAZE_ENABLE_GLARE, getHazeEnableGlare()); - APPEND_ENTITY_PROPERTY(PROP_HAZE_GLARE_ANGLE, getHazeGlareAngle()); - - APPEND_ENTITY_PROPERTY(PROP_HAZE_ALTITUDE_EFFECT, getHazeAltitudeEffect()); - APPEND_ENTITY_PROPERTY(PROP_HAZE_CEILING, getHazeCeiling()); - APPEND_ENTITY_PROPERTY(PROP_HAZE_BASE_REF, getHazeBaseRef()); - - APPEND_ENTITY_PROPERTY(PROP_HAZE_BACKGROUND_BLEND, getHazeBackgroundBlend()); - - APPEND_ENTITY_PROPERTY(PROP_HAZE_ATTENUATE_KEYLIGHT, getHazeAttenuateKeyLight()); - APPEND_ENTITY_PROPERTY(PROP_HAZE_KEYLIGHT_RANGE, getHazeKeyLightRange()); - APPEND_ENTITY_PROPERTY(PROP_HAZE_KEYLIGHT_ALTITUDE, getHazeKeyLightAltitude()); -} - -int HazePropertyGroup::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_HAZE_RANGE, float, setHazeRange); - READ_ENTITY_PROPERTY(PROP_HAZE_COLOR, u8vec3Color, setHazeColor); - READ_ENTITY_PROPERTY(PROP_HAZE_GLARE_COLOR, u8vec3Color, setHazeGlareColor); - READ_ENTITY_PROPERTY(PROP_HAZE_ENABLE_GLARE, bool, setHazeEnableGlare); - READ_ENTITY_PROPERTY(PROP_HAZE_GLARE_ANGLE, float, setHazeGlareAngle); - - READ_ENTITY_PROPERTY(PROP_HAZE_ALTITUDE_EFFECT, bool, setHazeAltitudeEffect); - READ_ENTITY_PROPERTY(PROP_HAZE_CEILING, float, setHazeCeiling); - READ_ENTITY_PROPERTY(PROP_HAZE_BASE_REF, float, setHazeBaseRef); - - READ_ENTITY_PROPERTY(PROP_HAZE_BACKGROUND_BLEND, float, setHazeBackgroundBlend); - - READ_ENTITY_PROPERTY(PROP_HAZE_ATTENUATE_KEYLIGHT, bool, setHazeAttenuateKeyLight); - READ_ENTITY_PROPERTY(PROP_HAZE_KEYLIGHT_RANGE, float, setHazeKeyLightRange); - READ_ENTITY_PROPERTY(PROP_HAZE_KEYLIGHT_ALTITUDE, float, setHazeKeyLightAltitude); - - return bytesRead; -} diff --git a/libraries/entities/src/HazePropertyGroup.cpp.in b/libraries/entities/src/HazePropertyGroup.cpp.in new file mode 100644 index 00000000000..882af32a2ec --- /dev/null +++ b/libraries/entities/src/HazePropertyGroup.cpp.in @@ -0,0 +1,134 @@ +// +// HazePropertyGroup.h +// libraries/entities/src +// +// Created by Nissim hadar on 9/21/17. +// Copyright 2013 High Fidelity, Inc. +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#include "HazePropertyGroup.h" + +#include + +#include "EntityItemProperties.h" + +void HazePropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, + bool skipDefaults, EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, bool isMyOwnAvatarEntity) const { + +@Haze_GROUP_COPY_TO_SCRIPT@ + +} + +void HazePropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) { + +@Haze_GROUP_COPY_FROM_SCRIPT@ + +} + +void HazePropertyGroup::merge(const HazePropertyGroup& other) { + +@Haze_GROUP_MERGE@ + +} + +void HazePropertyGroup::debugDump() const { + +@Haze_GROUP_DEBUG_DUMP@ + +} + +void HazePropertyGroup::listChangedProperties(QList& out) { + +@Haze_GROUP_LIST_CHANGED@ + +} + +bool HazePropertyGroup::appendToEditPacket(OctreePacketData* packetData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@Haze_GROUP_APPEND@ + + return successPropertyFits; +} + +bool HazePropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) { + + int bytesRead = 0; + bool overwriteLocalData = true; + bool somethingChanged = false; + +@Haze_GROUP_READ@ + +@Haze_GROUP_DECODE_CHANGED@ + + processedBytes += bytesRead; + + return somethingChanged; +} + +void HazePropertyGroup::markAllChanged() { + +@Haze_GROUP_MARK_CHANGED@ + +} + +EntityPropertyFlags HazePropertyGroup::getChangedProperties() const { + EntityPropertyFlags changedProperties; + +@Haze_GROUP_CHANGED_PROPERTIES@ + + return changedProperties; +} + +void HazePropertyGroup::getProperties(EntityItemProperties& properties) const { + +@Haze_GROUP_COPY_TO@ + +} + +bool HazePropertyGroup::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + +@Haze_GROUP_SET_FROM@ + + return somethingChanged; +} + +EntityPropertyFlags HazePropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties; + +@Haze_REQUESTED_PROPS@ + + return requestedProperties; +} + +int HazePropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + +@Haze_GROUP_READ@ + + return bytesRead; +} + +void HazePropertyGroup::addPropertyMap(QHash& _propertyInfos, + QHash& _enumsToPropertyStrings) { + +@Haze_GROUP_ADD_TO_MAP@ + +} diff --git a/libraries/entities/src/HazePropertyGroup.h b/libraries/entities/src/HazePropertyGroup.h deleted file mode 100644 index a84ec207132..00000000000 --- a/libraries/entities/src/HazePropertyGroup.h +++ /dev/null @@ -1,147 +0,0 @@ -// -// HazePropertyGroup.h -// libraries/entities/src -// -// Created by Nissim hadar on 9/21/17. -// Copyright 2013 High Fidelity, Inc. -// Copyright 2023 Overte e.V. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// SPDX-License-Identifier: Apache-2.0 -// - -#ifndef hifi_HazePropertyGroup_h -#define hifi_HazePropertyGroup_h - -#include - -#include - -#include "PropertyGroup.h" -#include "EntityItemPropertiesMacros.h" - -class EntityItemProperties; -class EncodeBitstreamParams; -class OctreePacketData; -class EntityTreeElementExtraEncodeData; -class ReadBitstreamToTreeParams; -class ScriptEngine; -class ScriptValue; - -static const float INITIAL_HAZE_RANGE{ 1000.0f }; -static const glm::u8vec3 initialHazeGlareColor { 255, 229, 179 }; -static const glm::u8vec3 initialHazeColor { 128, 154, 179 }; -static const float INITIAL_HAZE_GLARE_ANGLE{ 20.0f }; - -static const float INITIAL_HAZE_BASE_REFERENCE{ 0.0f }; -static const float INITIAL_HAZE_HEIGHT{ 200.0f }; - -static const float INITIAL_HAZE_BACKGROUND_BLEND{ 0.0f }; - -static const float INITIAL_KEY_LIGHT_RANGE{ 1000.0f }; -static const float INITIAL_KEY_LIGHT_ALTITUDE{ 200.0f }; - -// FIXME: Document hazeAttenuationKeyLight, hazeKeyLightRange, and hazeKeyLightAltitude once they're working and are provided -// in the Create app's UI. -/*@jsdoc - * Haze is defined by the following properties: - * @typedef {object} Entities.Haze - * - * @property {number} hazeRange=1000 - The horizontal distance at which visibility is reduced to 95%; i.e., 95% of each pixel's - * color is haze. - * @property {Color} hazeColor=128,154,179 - The color of the haze when looking away from the key light. - * @property {boolean} hazeEnableGlare=false - true if the haze is colored with glare from the key light, - * false if it isn't. If true, then hazeGlareColor and hazeGlareAngle - * are used. - * @property {Color} hazeGlareColor=255,299,179 - The color of the haze when looking towards the key light. - * @property {number} hazeGlareAngle=20 - The angle in degrees across the circle around the key light that the glare color and - * haze color are blended 50/50. - * - * @property {boolean} hazeAltitudeEffect=false - true if haze decreases with altitude as defined by the - * entity's local coordinate system, false if it doesn't. If true, then hazeBaseRef - * and hazeCeiling are used. - * @property {number} hazeBaseRef=0 - The y-axis value in the entity's local coordinate system at which the haze density starts - * reducing with altitude. - * @property {number} hazeCeiling=200 - The y-axis value in the entity's local coordinate system at which the haze density has - * reduced to 5%. - * - * @property {number} hazeBackgroundBlend=0 - The proportion of the skybox image to show through the haze: 0.0 - * displays no skybox image; 1.0 displays no haze. - * - * @property {boolean} hazeAttenuateKeyLight=false - true if the haze attenuates the key light, false - * if it doesn't. If true, then hazeKeyLightRange and hazeKeyLightAltitude are used. - * @property {number} hazeKeyLightRange=1000 - The distance at which the haze attenuates the key light by 95%. - * @property {number} hazeKeyLightAltitude=200 - The altitude at which the haze starts attenuating the key light (i.e., the - * altitude at which the distance starts being calculated). - */ -class HazePropertyGroup : public PropertyGroup { -public: - // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, - ScriptEngine* engine, bool skipDefaults, - EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, - bool isMyOwnAvatarEntity) const override; - virtual void copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) override; - - void merge(const HazePropertyGroup& other); - - virtual void debugDump() const override; - virtual void listChangedProperties(QList& 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; - - // Range only parameters - DEFINE_PROPERTY(PROP_HAZE_RANGE, HazeRange, hazeRange, float, INITIAL_HAZE_RANGE); - DEFINE_PROPERTY_REF(PROP_HAZE_COLOR, HazeColor, hazeColor, glm::u8vec3, initialHazeColor); - DEFINE_PROPERTY_REF(PROP_HAZE_GLARE_COLOR, HazeGlareColor, hazeGlareColor, glm::u8vec3, initialHazeGlareColor); - DEFINE_PROPERTY(PROP_HAZE_ENABLE_GLARE, HazeEnableGlare, hazeEnableGlare, bool, false); - DEFINE_PROPERTY_REF(PROP_HAZE_GLARE_ANGLE, HazeGlareAngle, hazeGlareAngle, float, INITIAL_HAZE_GLARE_ANGLE); - - // Altitude parameters - DEFINE_PROPERTY(PROP_HAZE_ALTITUDE_EFFECT, HazeAltitudeEffect, hazeAltitudeEffect, bool, false); - DEFINE_PROPERTY_REF(PROP_HAZE_CEILING, HazeCeiling, hazeCeiling, float, INITIAL_HAZE_BASE_REFERENCE + INITIAL_HAZE_HEIGHT); - DEFINE_PROPERTY_REF(PROP_HAZE_BASE_REF, HazeBaseRef, hazeBaseRef, float, INITIAL_HAZE_BASE_REFERENCE); - - // Background (skybox) blend value - DEFINE_PROPERTY_REF(PROP_HAZE_BACKGROUND_BLEND, HazeBackgroundBlend, hazeBackgroundBlend, float, INITIAL_HAZE_BACKGROUND_BLEND); - - // hazeDirectional light attenuation - DEFINE_PROPERTY(PROP_HAZE_ATTENUATE_KEYLIGHT, HazeAttenuateKeyLight, hazeAttenuateKeyLight, bool, false); - DEFINE_PROPERTY_REF(PROP_HAZE_KEYLIGHT_RANGE, HazeKeyLightRange, hazeKeyLightRange, float, INITIAL_KEY_LIGHT_RANGE); - DEFINE_PROPERTY_REF(PROP_HAZE_KEYLIGHT_ALTITUDE, HazeKeyLightAltitude, hazeKeyLightAltitude, float, INITIAL_KEY_LIGHT_ALTITUDE); -}; - -#endif // hifi_HazePropertyGroup_h diff --git a/libraries/entities/src/HazePropertyGroup.h.in b/libraries/entities/src/HazePropertyGroup.h.in new file mode 100644 index 00000000000..88496ba6558 --- /dev/null +++ b/libraries/entities/src/HazePropertyGroup.h.in @@ -0,0 +1,88 @@ +// +// HazePropertyGroup.h +// libraries/entities/src +// +// Created by Nissim hadar on 9/21/17. +// Copyright 2013 High Fidelity, Inc. +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef hifi_HazePropertyGroup_h +#define hifi_HazePropertyGroup_h + +#include + +#include + +#include "PropertyGroup.h" +#include "EntityItemPropertiesMacros.h" + +class EntityItemProperties; +class EncodeBitstreamParams; +class OctreePacketData; +class EntityTreeElementExtraEncodeData; +class ReadBitstreamToTreeParams; +class ScriptEngine; +class ScriptValue; + +static const float INITIAL_HAZE_RANGE{ 1000.0f }; +static const glm::u8vec3 initialHazeGlareColor { 255, 229, 179 }; +static const glm::u8vec3 initialHazeColor { 128, 154, 179 }; +static const float INITIAL_HAZE_GLARE_ANGLE{ 20.0f }; + +static const float INITIAL_HAZE_BASE_REFERENCE{ 0.0f }; +static const float INITIAL_HAZE_HEIGHT{ 200.0f }; + +static const float INITIAL_HAZE_BACKGROUND_BLEND{ 0.0f }; + +static const float INITIAL_KEY_LIGHT_RANGE{ 1000.0f }; +static const float INITIAL_KEY_LIGHT_ALTITUDE{ 200.0f }; + +// FIXME: Document hazeAttenuationKeyLight, hazeKeyLightRange, and hazeKeyLightAltitude once they're working and are provided +// in the Create app's UI. +/*@jsdoc + * Haze is defined by the following properties: + * @typedef {object} Entities.Haze + * + * @property {number} hazeRange=1000 - The horizontal distance at which visibility is reduced to 95%; i.e., 95% of each pixel's + * color is haze. + * @property {Color} hazeColor=128,154,179 - The color of the haze when looking away from the key light. + * @property {boolean} hazeEnableGlare=false - true if the haze is colored with glare from the key light, + * false if it isn't. If true, then hazeGlareColor and hazeGlareAngle + * are used. + * @property {Color} hazeGlareColor=255,299,179 - The color of the haze when looking towards the key light. + * @property {number} hazeGlareAngle=20 - The angle in degrees across the circle around the key light that the glare color and + * haze color are blended 50/50. + * + * @property {boolean} hazeAltitudeEffect=false - true if haze decreases with altitude as defined by the + * entity's local coordinate system, false if it doesn't. If true, then hazeBaseRef + * and hazeCeiling are used. + * @property {number} hazeBaseRef=0 - The y-axis value in the entity's local coordinate system at which the haze density starts + * reducing with altitude. + * @property {number} hazeCeiling=200 - The y-axis value in the entity's local coordinate system at which the haze density has + * reduced to 5%. + * + * @property {number} hazeBackgroundBlend=0 - The proportion of the skybox image to show through the haze: 0.0 + * displays no skybox image; 1.0 displays no haze. + * + * @property {boolean} hazeAttenuateKeyLight=false - true if the haze attenuates the key light, false + * if it doesn't. If true, then hazeKeyLightRange and hazeKeyLightAltitude are used. + * @property {number} hazeKeyLightRange=1000 - The distance at which the haze attenuates the key light by 95%. + * @property {number} hazeKeyLightAltitude=200 - The altitude at which the haze starts attenuating the key light (i.e., the + * altitude at which the distance starts being calculated). + */ +class HazePropertyGroup : public PropertyGroup { +public: + ENTITY_PROPERTY_GROUP_METHODS(HazePropertyGroup) + +protected: + +@Haze_GROUP_PROPS@ + +}; + +#endif // hifi_HazePropertyGroup_h diff --git a/libraries/entities/src/ImageEntityItem.cpp b/libraries/entities/src/ImageEntityItem.cpp deleted file mode 100644 index 3a796160c8c..00000000000 --- a/libraries/entities/src/ImageEntityItem.cpp +++ /dev/null @@ -1,227 +0,0 @@ -// -// Created by Sam Gondelman on 11/29/18 -// 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 "ImageEntityItem.h" - -#include "EntityItemProperties.h" - -EntityItemPointer ImageEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - Pointer entity(new ImageEntityItem(entityID), [](ImageEntityItem* ptr) { ptr->deleteLater(); }); - entity->setProperties(properties); - return entity; -} - -// our non-pure virtual subclass for now... -ImageEntityItem::ImageEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { - _type = EntityTypes::Image; -} - -void ImageEntityItem::setUnscaledDimensions(const glm::vec3& value) { - const float IMAGE_ENTITY_ITEM_FIXED_DEPTH = 0.01f; - // NOTE: Image Entities always have a "depth" of 1cm. - EntityItem::setUnscaledDimensions(glm::vec3(value.x, value.y, IMAGE_ENTITY_ITEM_FIXED_DEPTH)); -} - -EntityItemProperties ImageEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { - EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class - - COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getColor); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha); - withReadLock([&] { - _pulseProperties.getProperties(properties); - properties.setNaturalDimensions(_naturalDimensions); - }); - - COPY_ENTITY_PROPERTY_TO_PROPERTIES(imageURL, getImageURL); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(emissive, getEmissive); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(keepAspectRatio, getKeepAspectRatio); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(subImage, getSubImage); - - return properties; -} - -bool ImageEntityItem::setSubClassProperties(const EntityItemProperties& properties) { - bool somethingChanged = false; - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha); - withWriteLock([&] { - bool pulsePropertiesChanged = _pulseProperties.setProperties(properties); - somethingChanged |= pulsePropertiesChanged; - _needsRenderUpdate |= pulsePropertiesChanged; - }); - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(imageURL, setImageURL); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(emissive, setEmissive); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(keepAspectRatio, setKeepAspectRatio); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(subImage, setSubImage); - - return somethingChanged; -} - -int ImageEntityItem::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_COLOR, u8vec3Color, setColor); - READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha); - withWriteLock([&] { - int bytesFromPulse = _pulseProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, - somethingChanged); - bytesRead += bytesFromPulse; - dataAt += bytesFromPulse; - }); - - READ_ENTITY_PROPERTY(PROP_IMAGE_URL, QString, setImageURL); - READ_ENTITY_PROPERTY(PROP_EMISSIVE, bool, setEmissive); - READ_ENTITY_PROPERTY(PROP_KEEP_ASPECT_RATIO, bool, setKeepAspectRatio); - READ_ENTITY_PROPERTY(PROP_SUB_IMAGE, QRect, setSubImage); - - return bytesRead; -} - -EntityPropertyFlags ImageEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { - EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); - - requestedProperties += PROP_COLOR; - requestedProperties += PROP_ALPHA; - requestedProperties += _pulseProperties.getEntityProperties(params); - - requestedProperties += PROP_IMAGE_URL; - requestedProperties += PROP_EMISSIVE; - requestedProperties += PROP_KEEP_ASPECT_RATIO; - requestedProperties += PROP_SUB_IMAGE; - - return requestedProperties; -} - -void ImageEntityItem::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_COLOR, getColor()); - APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha()); - withReadLock([&] { - _pulseProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, - propertyFlags, propertiesDidntFit, propertyCount, appendState); - }); - - APPEND_ENTITY_PROPERTY(PROP_IMAGE_URL, getImageURL()); - APPEND_ENTITY_PROPERTY(PROP_EMISSIVE, getEmissive()); - APPEND_ENTITY_PROPERTY(PROP_KEEP_ASPECT_RATIO, getKeepAspectRatio()); - APPEND_ENTITY_PROPERTY(PROP_SUB_IMAGE, getSubImage()); -} - -QString ImageEntityItem::getImageURL() const { - QString result; - withReadLock([&] { - result = _imageURL; - }); - return result; -} - -void ImageEntityItem::setImageURL(const QString& url) { - withWriteLock([&] { - _needsRenderUpdate |= _imageURL != url; - _imageURL = url; - }); -} - -bool ImageEntityItem::getEmissive() const { - bool result; - withReadLock([&] { - result = _emissive; - }); - return result; -} - -void ImageEntityItem::setEmissive(bool emissive) { - withWriteLock([&] { - _needsRenderUpdate |= _emissive != emissive; - _emissive = emissive; - }); -} - -bool ImageEntityItem::getKeepAspectRatio() const { - bool result; - withReadLock([&] { - result = _keepAspectRatio; - }); - return result; -} - -void ImageEntityItem::setKeepAspectRatio(bool keepAspectRatio) { - withWriteLock([&] { - _needsRenderUpdate |= _keepAspectRatio != keepAspectRatio; - _keepAspectRatio = keepAspectRatio; - }); -} - -QRect ImageEntityItem::getSubImage() const { - QRect result; - withReadLock([&] { - result = _subImage; - }); - return result; -} - -void ImageEntityItem::setSubImage(const QRect& subImage) { - withWriteLock([&] { - _needsRenderUpdate |= _subImage != subImage; - _subImage = subImage; - }); -} - -void ImageEntityItem::setColor(const glm::u8vec3& color) { - withWriteLock([&] { - _needsRenderUpdate |= _color != color; - _color = color; - }); -} - -glm::u8vec3 ImageEntityItem::getColor() const { - return resultWithReadLock([&] { - return _color; - }); -} - -void ImageEntityItem::setAlpha(float alpha) { - withWriteLock([&] { - _needsRenderUpdate |= _alpha != alpha; - _alpha = alpha; - }); -} - -float ImageEntityItem::getAlpha() const { - return resultWithReadLock([&] { - return _alpha; - }); -} - -PulsePropertyGroup ImageEntityItem::getPulseProperties() const { - return resultWithReadLock([&] { - return _pulseProperties; - }); -} - -void ImageEntityItem::setNaturalDimension(const glm::vec3& naturalDimensions) const { - withWriteLock([&] { - _naturalDimensions = naturalDimensions; - }); -} diff --git a/libraries/entities/src/ImageEntityItem.cpp.in b/libraries/entities/src/ImageEntityItem.cpp.in new file mode 100644 index 00000000000..fcbd1022843 --- /dev/null +++ b/libraries/entities/src/ImageEntityItem.cpp.in @@ -0,0 +1,107 @@ +// +// Created by Sam Gondelman on 11/29/18 +// 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 "ImageEntityItem.h" + +#include "EntityItemProperties.h" + +EntityItemPointer ImageEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + Pointer entity(new ImageEntityItem(entityID), [](ImageEntityItem* ptr) { ptr->deleteLater(); }); + entity->setProperties(properties); + return entity; +} + +// our non-pure virtual subclass for now... +ImageEntityItem::ImageEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { + _type = EntityTypes::Image; +} + +void ImageEntityItem::setUnscaledDimensions(const glm::vec3& value) { + const float IMAGE_ENTITY_ITEM_FIXED_DEPTH = 0.01f; + // NOTE: Image Entities always have a "depth" of 1cm. + EntityItem::setUnscaledDimensions(glm::vec3(value.x, value.y, IMAGE_ENTITY_ITEM_FIXED_DEPTH)); +} + +EntityItemProperties ImageEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class + +@Image_ENTITY_COPY_TO@ + + withReadLock([&] { + properties.setNaturalDimensions(_naturalDimensions); + }); + + return properties; +} + +bool ImageEntityItem::setSubClassProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + +@Image_ENTITY_SET_FROM@ + + return somethingChanged; +} + +EntityPropertyFlags ImageEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + +@Image_REQUESTED_PROPS@ + + return requestedProperties; +} + +void ImageEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@Image_ENTITY_APPEND@ + +} + +int ImageEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + +@Image_ENTITY_READ@ + + return bytesRead; +} + +void ImageEntityItem::debugDump() const { + qCDebug(entities) << "ImageEntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " editedAgo:" << debugTime(getLastEdited(), usecTimestampNow()); + qCDebug(entities) << " pointer:" << this; + +@Image_ENTITY_DEBUG@ + +} + +PulsePropertyGroup ImageEntityItem::getPulseProperties() const { + return resultWithReadLock([&] { + return _pulseProperties; + }); +} + +void ImageEntityItem::setNaturalDimension(const glm::vec3& naturalDimensions) const { + withWriteLock([&] { + _naturalDimensions = naturalDimensions; + }); +} diff --git a/libraries/entities/src/ImageEntityItem.h b/libraries/entities/src/ImageEntityItem.h deleted file mode 100644 index 0cc4eae05aa..00000000000 --- a/libraries/entities/src/ImageEntityItem.h +++ /dev/null @@ -1,81 +0,0 @@ -// -// Created by Sam Gondelman on 11/29/18 -// 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_ImageEntityItem_h -#define hifi_ImageEntityItem_h - -#include "EntityItem.h" - -#include "PulsePropertyGroup.h" - -class ImageEntityItem : public EntityItem { - using Pointer = std::shared_ptr; -public: - static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - - ImageEntityItem(const EntityItemID& entityItemID); - - ALLOW_INSTANTIATION // This class can be instantiated - - virtual void setUnscaledDimensions(const glm::vec3& value) override; - - // methods for getting/setting all properties of an entity - EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - bool setSubClassProperties(const EntityItemProperties& properties) override; - - EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; - - void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const override; - - int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, - ReadBitstreamToTreeParams& args, - EntityPropertyFlags& propertyFlags, bool overwriteLocalData, - bool& somethingChanged) override; - - void setImageURL(const QString& imageUrl); - QString getImageURL() const; - - void setEmissive(bool emissive); - bool getEmissive() const; - - void setKeepAspectRatio(bool keepAspectRatio); - bool getKeepAspectRatio() const; - - void setSubImage(const QRect& subImage); - QRect getSubImage() const; - - void setColor(const glm::u8vec3& color); - glm::u8vec3 getColor() const; - - void setAlpha(float alpha); - float getAlpha() const; - - PulsePropertyGroup getPulseProperties() const; - - void setNaturalDimension(const glm::vec3& naturalDimensions) const; - -protected: - glm::u8vec3 _color; - float _alpha; - PulsePropertyGroup _pulseProperties; - - QString _imageURL; - bool _emissive { false }; - bool _keepAspectRatio { true }; - QRect _subImage; - - mutable glm::vec3 _naturalDimensions; -}; - -#endif // hifi_ImageEntityItem_h diff --git a/libraries/entities/src/ImageEntityItem.h.in b/libraries/entities/src/ImageEntityItem.h.in new file mode 100644 index 00000000000..13989306f51 --- /dev/null +++ b/libraries/entities/src/ImageEntityItem.h.in @@ -0,0 +1,38 @@ +// +// Created by Sam Gondelman on 11/29/18 +// 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_ImageEntityItem_h +#define hifi_ImageEntityItem_h + +#include "EntityItem.h" + +#include "PulsePropertyGroup.h" + +class ImageEntityItem : public EntityItem { + using Pointer = std::shared_ptr; +public: + static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); + + ImageEntityItem(const EntityItemID& entityItemID); + + ALLOW_INSTANTIATION // This class can be instantiated + ENTITY_PROPERTY_SUBCLASS_METHODS + + void setNaturalDimension(const glm::vec3& naturalDimensions) const; + virtual void setUnscaledDimensions(const glm::vec3& value) override; + + PulsePropertyGroup getPulseProperties() const; + +protected: + +@Image_ENTITY_PROPS@ + + mutable glm::vec3 _naturalDimensions; +}; + +#endif // hifi_ImageEntityItem_h diff --git a/libraries/entities/src/KeyLightPropertyGroup.cpp b/libraries/entities/src/KeyLightPropertyGroup.cpp deleted file mode 100644 index f431aa55cce..00000000000 --- a/libraries/entities/src/KeyLightPropertyGroup.cpp +++ /dev/null @@ -1,235 +0,0 @@ -// -// KeyLightPropertyGroup.cpp -// libraries/entities/src -// -// Created by Sam Gateau on 2015/10/23. -// Copyright 2013 High Fidelity, Inc. -// Copyright 2023 Overte e.V. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// SPDX-License-Identifier: Apache-2.0 -// - -#include "KeyLightPropertyGroup.h" - -#include -#include - -#include "EntityItemProperties.h" -#include "EntityItemPropertiesMacros.h" - -const glm::u8vec3 KeyLightPropertyGroup::DEFAULT_KEYLIGHT_COLOR = { 255, 255, 255 }; -const float KeyLightPropertyGroup::DEFAULT_KEYLIGHT_INTENSITY = 1.0f; -const float KeyLightPropertyGroup::DEFAULT_KEYLIGHT_AMBIENT_INTENSITY = 0.5f; -const glm::vec3 KeyLightPropertyGroup::DEFAULT_KEYLIGHT_DIRECTION = { 0.0f, -1.0f, 0.0f }; -const bool KeyLightPropertyGroup::DEFAULT_KEYLIGHT_CAST_SHADOWS { false }; -const float KeyLightPropertyGroup::DEFAULT_KEYLIGHT_SHADOW_BIAS { 0.5f }; -const float KeyLightPropertyGroup::DEFAULT_KEYLIGHT_SHADOW_MAX_DISTANCE { 40.0f }; - -void KeyLightPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, - ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, - bool isMyOwnAvatarEntity) const { - - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_KEYLIGHT_COLOR, KeyLight, keyLight, Color, color, u8vec3Color); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_INTENSITY, KeyLight, keyLight, Intensity, intensity); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_DIRECTION, KeyLight, keyLight, Direction, direction); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_CAST_SHADOW, KeyLight, keyLight, CastShadows, castShadows); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_SHADOW_BIAS, KeyLight, keyLight, ShadowBias, shadowBias); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_KEYLIGHT_SHADOW_MAX_DISTANCE, KeyLight, keyLight, ShadowMaxDistance, shadowMaxDistance); -} - -void KeyLightPropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) { - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, color, u8vec3Color, setColor); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, intensity, float, setIntensity); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, direction, vec3, setDirection); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, castShadows, bool, setCastShadows); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, shadowBias, float, setShadowBias); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(keyLight, shadowMaxDistance, float, setShadowMaxDistance); - - // legacy property support - COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(keyLightColor, u8vec3Color, setColor, getColor); - COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(keyLightIntensity, float, setIntensity, getIntensity); - COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(keyLightDirection, vec3, setDirection, getDirection); - COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(keyLightCastShadows, bool, setCastShadows, getCastShadows); -} - -void KeyLightPropertyGroup::merge(const KeyLightPropertyGroup& other) { - COPY_PROPERTY_IF_CHANGED(color); - COPY_PROPERTY_IF_CHANGED(intensity); - COPY_PROPERTY_IF_CHANGED(direction); - COPY_PROPERTY_IF_CHANGED(castShadows); - COPY_PROPERTY_IF_CHANGED(shadowBias); - COPY_PROPERTY_IF_CHANGED(shadowMaxDistance); -} - -void KeyLightPropertyGroup::debugDump() const { - qCDebug(entities) << " KeyLightPropertyGroup: ---------------------------------------------"; - qCDebug(entities) << " color:" << getColor(); - qCDebug(entities) << " intensity:" << getIntensity(); - qCDebug(entities) << " direction:" << getDirection(); - qCDebug(entities) << " castShadows:" << getCastShadows(); - qCDebug(entities) << " shadowBias:" << getShadowBias(); - qCDebug(entities) << " shadowMaxDistance:" << getShadowMaxDistance(); -} - -void KeyLightPropertyGroup::listChangedProperties(QList& out) { - if (colorChanged()) { - out << "keyLight-color"; - } - if (intensityChanged()) { - out << "keyLight-intensity"; - } - if (directionChanged()) { - out << "keyLight-direction"; - } - if (castShadowsChanged()) { - out << "keyLight-castShadows"; - } - if (shadowBiasChanged()) { - out << "keyLight-shadowBias"; - } - if (shadowMaxDistanceChanged()) { - out << "keyLight-shadowMaxDistance"; - } -} - -bool KeyLightPropertyGroup::appendToEditPacket(OctreePacketData* packetData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const { - - bool successPropertyFits = true; - - APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_COLOR, getColor()); - APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, getIntensity()); - APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, getDirection()); - APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_CAST_SHADOW, getCastShadows()); - APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_SHADOW_BIAS, getShadowBias()); - APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_SHADOW_MAX_DISTANCE, getShadowMaxDistance()); - - return true; -} - -bool KeyLightPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt, - int& processedBytes) { - - int bytesRead = 0; - bool overwriteLocalData = true; - bool somethingChanged = false; - - READ_ENTITY_PROPERTY(PROP_KEYLIGHT_COLOR, u8vec3Color, setColor); - READ_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, float, setIntensity); - READ_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, glm::vec3, setDirection); - READ_ENTITY_PROPERTY(PROP_KEYLIGHT_CAST_SHADOW, bool, setCastShadows); - READ_ENTITY_PROPERTY(PROP_KEYLIGHT_SHADOW_BIAS, float, setShadowBias); - READ_ENTITY_PROPERTY(PROP_KEYLIGHT_SHADOW_MAX_DISTANCE, float, setShadowMaxDistance); - - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_KEYLIGHT_COLOR, Color); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_KEYLIGHT_INTENSITY, Intensity); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_KEYLIGHT_DIRECTION, Direction); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_KEYLIGHT_CAST_SHADOW, CastShadows); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_KEYLIGHT_SHADOW_BIAS, ShadowBias); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_KEYLIGHT_SHADOW_MAX_DISTANCE, ShadowMaxDistance); - - processedBytes += bytesRead; - - Q_UNUSED(somethingChanged); - - return true; -} - -void KeyLightPropertyGroup::markAllChanged() { - _colorChanged = true; - _intensityChanged = true; - _directionChanged = true; - _castShadowsChanged = true; - _shadowBiasChanged = true; - _shadowMaxDistanceChanged = true; -} - -EntityPropertyFlags KeyLightPropertyGroup::getChangedProperties() const { - EntityPropertyFlags changedProperties; - - CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_COLOR, color); - CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_INTENSITY, intensity); - CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_DIRECTION, direction); - CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_CAST_SHADOW, castShadows); - CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_SHADOW_BIAS, shadowBias); - CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_SHADOW_MAX_DISTANCE, shadowMaxDistance); - - return changedProperties; -} - -void KeyLightPropertyGroup::getProperties(EntityItemProperties& properties) const { - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(KeyLight, Color, getColor); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(KeyLight, Intensity, getIntensity); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(KeyLight, Direction, getDirection); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(KeyLight, CastShadows, getCastShadows); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(KeyLight, ShadowBias, getShadowBias); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(KeyLight, ShadowMaxDistance, getShadowMaxDistance); -} - -bool KeyLightPropertyGroup::setProperties(const EntityItemProperties& properties) { - bool somethingChanged = false; - - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(KeyLight, Color, color, setColor); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(KeyLight, Intensity, intensity, setIntensity); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(KeyLight, Direction, direction, setDirection); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(KeyLight, CastShadows, castShadows, setCastShadows); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(KeyLight, ShadowBias, shadowBias, setShadowBias); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(KeyLight, ShadowMaxDistance, shadowMaxDistance, setShadowMaxDistance); - - return somethingChanged; -} - -EntityPropertyFlags KeyLightPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { - EntityPropertyFlags requestedProperties; - - requestedProperties += PROP_KEYLIGHT_COLOR; - requestedProperties += PROP_KEYLIGHT_INTENSITY; - requestedProperties += PROP_KEYLIGHT_DIRECTION; - requestedProperties += PROP_KEYLIGHT_CAST_SHADOW; - requestedProperties += PROP_KEYLIGHT_SHADOW_BIAS; - requestedProperties += PROP_KEYLIGHT_SHADOW_MAX_DISTANCE; - - return requestedProperties; -} - -void KeyLightPropertyGroup::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_KEYLIGHT_COLOR, getColor()); - APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, getIntensity()); - APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, getDirection()); - APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_CAST_SHADOW, getCastShadows()); - APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_SHADOW_BIAS, getShadowBias()); - APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_SHADOW_MAX_DISTANCE, getShadowMaxDistance()); -} - -int KeyLightPropertyGroup::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_KEYLIGHT_COLOR, u8vec3Color, setColor); - READ_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, float, setIntensity); - READ_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, glm::vec3, setDirection); - READ_ENTITY_PROPERTY(PROP_KEYLIGHT_CAST_SHADOW, bool, setCastShadows); - READ_ENTITY_PROPERTY(PROP_KEYLIGHT_SHADOW_BIAS, float, setShadowBias); - READ_ENTITY_PROPERTY(PROP_KEYLIGHT_SHADOW_MAX_DISTANCE, float, setShadowMaxDistance); - - return bytesRead; -} diff --git a/libraries/entities/src/KeyLightPropertyGroup.cpp.in b/libraries/entities/src/KeyLightPropertyGroup.cpp.in new file mode 100644 index 00000000000..782fe9be814 --- /dev/null +++ b/libraries/entities/src/KeyLightPropertyGroup.cpp.in @@ -0,0 +1,148 @@ +// +// KeyLightPropertyGroup.cpp +// libraries/entities/src +// +// Created by Sam Gateau on 2015/10/23. +// Copyright 2013 High Fidelity, Inc. +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#include "KeyLightPropertyGroup.h" + +#include +#include + +#include "EntityItemProperties.h" + +const glm::u8vec3 KeyLightPropertyGroup::DEFAULT_KEYLIGHT_COLOR = { 255, 255, 255 }; +const float KeyLightPropertyGroup::DEFAULT_KEYLIGHT_INTENSITY = 1.0f; +const float KeyLightPropertyGroup::DEFAULT_KEYLIGHT_AMBIENT_INTENSITY = 0.5f; +const glm::vec3 KeyLightPropertyGroup::DEFAULT_KEYLIGHT_DIRECTION = { 0.0f, -1.0f, 0.0f }; +const bool KeyLightPropertyGroup::DEFAULT_KEYLIGHT_CAST_SHADOWS { false }; +const float KeyLightPropertyGroup::DEFAULT_KEYLIGHT_SHADOW_BIAS { 0.5f }; +const float KeyLightPropertyGroup::DEFAULT_KEYLIGHT_SHADOW_MAX_DISTANCE { 40.0f }; + +void KeyLightPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, + bool skipDefaults, EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, bool isMyOwnAvatarEntity) const { + +@KeyLight_GROUP_COPY_TO_SCRIPT@ + +} + +void KeyLightPropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) { + +@KeyLight_GROUP_COPY_FROM_SCRIPT@ + + // legacy property support + COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(keyLightColor, u8vec3Color, setColor, getColor); + COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(keyLightIntensity, float, setIntensity, getIntensity); + COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(keyLightDirection, vec3, setDirection, getDirection); + COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(keyLightCastShadows, bool, setCastShadows, getCastShadows); +} + +void KeyLightPropertyGroup::merge(const KeyLightPropertyGroup& other) { + +@KeyLight_GROUP_MERGE@ + +} + +void KeyLightPropertyGroup::debugDump() const { + +@KeyLight_GROUP_DEBUG_DUMP@ + +} + +void KeyLightPropertyGroup::listChangedProperties(QList& out) { + +@KeyLight_GROUP_LIST_CHANGED@ + +} + +bool KeyLightPropertyGroup::appendToEditPacket(OctreePacketData* packetData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@KeyLight_GROUP_APPEND@ + + return successPropertyFits; +} + +bool KeyLightPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) { + + int bytesRead = 0; + bool overwriteLocalData = true; + bool somethingChanged = false; + +@KeyLight_GROUP_READ@ + +@KeyLight_GROUP_DECODE_CHANGED@ + + processedBytes += bytesRead; + + return somethingChanged; +} + +void KeyLightPropertyGroup::markAllChanged() { + +@KeyLight_GROUP_MARK_CHANGED@ + +} + +EntityPropertyFlags KeyLightPropertyGroup::getChangedProperties() const { + EntityPropertyFlags changedProperties; + +@KeyLight_GROUP_CHANGED_PROPERTIES@ + + return changedProperties; +} + +void KeyLightPropertyGroup::getProperties(EntityItemProperties& properties) const { + +@KeyLight_GROUP_COPY_TO@ + +} + +bool KeyLightPropertyGroup::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + +@KeyLight_GROUP_SET_FROM@ + + return somethingChanged; +} + +EntityPropertyFlags KeyLightPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties; + +@KeyLight_REQUESTED_PROPS@ + + return requestedProperties; +} + +int KeyLightPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + +@KeyLight_GROUP_READ@ + + return bytesRead; +} + +void KeyLightPropertyGroup::addPropertyMap(QHash& _propertyInfos, + QHash& _enumsToPropertyStrings) { + +@KeyLight_GROUP_ADD_TO_MAP@ + +} diff --git a/libraries/entities/src/KeyLightPropertyGroup.h b/libraries/entities/src/KeyLightPropertyGroup.h deleted file mode 100644 index 4a412f9802c..00000000000 --- a/libraries/entities/src/KeyLightPropertyGroup.h +++ /dev/null @@ -1,112 +0,0 @@ -// -// KeyLightPropertyGroup.h -// libraries/entities/src -// -// Created by Sam Gateau on 2015/10/23. -// Copyright 2013 High Fidelity, Inc. -// Copyright 2023 Overte e.V. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// SPDX-License-Identifier: Apache-2.0 -// - - -#ifndef hifi_KeyLightPropertyGroup_h -#define hifi_KeyLightPropertyGroup_h - -#include - -#include - -#include "EntityItemPropertiesMacros.h" -#include "PropertyGroup.h" - -class EntityItemProperties; -class EncodeBitstreamParams; -class OctreePacketData; -class EntityTreeElementExtraEncodeData; -class ReadBitstreamToTreeParams; -class ScriptEngine; -class ScriptValue; - -/*@jsdoc - * A key light is defined by the following properties: - * @typedef {object} Entities.KeyLight - * @property {Color} color=255,255,255 - The color of the light. - * @property {number} intensity=1 - The intensity of the light. - * @property {Vec3} direction=0,-1,0 - The direction the light is shining. - * @property {boolean} castShadows=false - true if shadows are cast, false if they aren't. Shadows - * are cast by avatars, plus {@link Entities.EntityProperties-Model|Model} and - * {@link Entities.EntityProperties-Shape|Shape} entities that have their - * {@link Entities.EntityProperties|canCastShadow} property set to true. - * @property {number} shadowBias=0.5 - The bias of the shadows cast by the light, range 0.0 – - * 1.0. This fine-tunes shadows cast by the light, to prevent shadow acne and peter panning. - * @property {number} shadowMaxDistance=40.0 - The maximum distance from the camera position at which shadows will be computed, - * range 1.0250.0. Higher values cover more of the scene but with less precision. - */ -class KeyLightPropertyGroup : public PropertyGroup { -public: - // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, - ScriptEngine* engine, bool skipDefaults, - EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, - bool isMyOwnAvatarEntity) const override; - virtual void copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) override; - - void merge(const KeyLightPropertyGroup& other); - - virtual void debugDump() const override; - virtual void listChangedProperties(QList& 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; - - static const glm::u8vec3 DEFAULT_KEYLIGHT_COLOR; - static const float DEFAULT_KEYLIGHT_INTENSITY; - static const float DEFAULT_KEYLIGHT_AMBIENT_INTENSITY; - static const glm::vec3 DEFAULT_KEYLIGHT_DIRECTION; - static const bool DEFAULT_KEYLIGHT_CAST_SHADOWS; - static const float DEFAULT_KEYLIGHT_SHADOW_BIAS; - static const float DEFAULT_KEYLIGHT_SHADOW_MAX_DISTANCE; - - DEFINE_PROPERTY_REF(PROP_KEYLIGHT_COLOR, Color, color, glm::u8vec3, DEFAULT_KEYLIGHT_COLOR); - DEFINE_PROPERTY(PROP_KEYLIGHT_INTENSITY, Intensity, intensity, float, DEFAULT_KEYLIGHT_INTENSITY); - DEFINE_PROPERTY_REF(PROP_KEYLIGHT_DIRECTION, Direction, direction, glm::vec3, DEFAULT_KEYLIGHT_DIRECTION); - DEFINE_PROPERTY(PROP_KEYLIGHT_CAST_SHADOW, CastShadows, castShadows, bool, DEFAULT_KEYLIGHT_CAST_SHADOWS); - DEFINE_PROPERTY(PROP_KEYLIGHT_SHADOW_BIAS, ShadowBias, shadowBias, float, DEFAULT_KEYLIGHT_SHADOW_BIAS); - DEFINE_PROPERTY(PROP_KEYLIGHT_SHADOW_MAX_DISTANCE, ShadowMaxDistance, shadowMaxDistance, float, DEFAULT_KEYLIGHT_SHADOW_MAX_DISTANCE); -}; - -#endif // hifi_KeyLightPropertyGroup_h diff --git a/libraries/entities/src/KeyLightPropertyGroup.h.in b/libraries/entities/src/KeyLightPropertyGroup.h.in new file mode 100644 index 00000000000..03adb66a933 --- /dev/null +++ b/libraries/entities/src/KeyLightPropertyGroup.h.in @@ -0,0 +1,66 @@ +// +// KeyLightPropertyGroup.h +// libraries/entities/src +// +// Created by Sam Gateau on 2015/10/23. +// Copyright 2013 High Fidelity, Inc. +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + + +#ifndef hifi_KeyLightPropertyGroup_h +#define hifi_KeyLightPropertyGroup_h + +#include + +#include + +#include "EntityItemPropertiesMacros.h" +#include "PropertyGroup.h" + +class EntityItemProperties; +class EncodeBitstreamParams; +class OctreePacketData; +class EntityTreeElementExtraEncodeData; +class ReadBitstreamToTreeParams; +class ScriptEngine; +class ScriptValue; + +/*@jsdoc + * A key light is defined by the following properties: + * @typedef {object} Entities.KeyLight + * @property {Color} color=255,255,255 - The color of the light. + * @property {number} intensity=1 - The intensity of the light. + * @property {Vec3} direction=0,-1,0 - The direction the light is shining. + * @property {boolean} castShadows=false - true if shadows are cast, false if they aren't. Shadows + * are cast by avatars, plus {@link Entities.EntityProperties-Model|Model} and + * {@link Entities.EntityProperties-Shape|Shape} entities that have their + * {@link Entities.EntityProperties|canCastShadow} property set to true. + * @property {number} shadowBias=0.5 - The bias of the shadows cast by the light, range 0.0 – + * 1.0. This fine-tunes shadows cast by the light, to prevent shadow acne and peter panning. + * @property {number} shadowMaxDistance=40.0 - The maximum distance from the camera position at which shadows will be computed, + * range 1.0250.0. Higher values cover more of the scene but with less precision. + */ +class KeyLightPropertyGroup : public PropertyGroup { +public: + ENTITY_PROPERTY_GROUP_METHODS(KeyLightPropertyGroup) + + static const glm::u8vec3 DEFAULT_KEYLIGHT_COLOR; + static const float DEFAULT_KEYLIGHT_INTENSITY; + static const float DEFAULT_KEYLIGHT_AMBIENT_INTENSITY; + static const glm::vec3 DEFAULT_KEYLIGHT_DIRECTION; + static const bool DEFAULT_KEYLIGHT_CAST_SHADOWS; + static const float DEFAULT_KEYLIGHT_SHADOW_BIAS; + static const float DEFAULT_KEYLIGHT_SHADOW_MAX_DISTANCE; + +protected: + +@KeyLight_GROUP_PROPS@ + +}; + +#endif // hifi_KeyLightPropertyGroup_h diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp.in similarity index 65% rename from libraries/entities/src/LightEntityItem.cpp rename to libraries/entities/src/LightEntityItem.cpp.in index 4bd9eda5aca..43dfc784b1c 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp.in @@ -58,16 +58,17 @@ void LightEntityItem::setUnscaledDimensions(const glm::vec3& value) { EntityItemProperties LightEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class - COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getColor); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(isSpotlight, getIsSpotlight); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(intensity, getIntensity); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(exponent, getExponent); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(cutoff, getCutoff); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(falloffRadius, getFalloffRadius); +@Light_ENTITY_COPY_TO@ return properties; } +float LightEntityItem::getFalloffRadius() const { + return resultWithReadLock([&] { + return _falloffRadius; + }); +} + void LightEntityItem::setFalloffRadius(float value) { value = glm::max(value, 0.0f); @@ -77,6 +78,12 @@ void LightEntityItem::setFalloffRadius(float value) { }); } +bool LightEntityItem::getIsSpotlight() const { + return resultWithReadLock([&] { + return _isSpotlight; + }); +} + void LightEntityItem::setIsSpotlight(bool value) { bool needsRenderUpdate; withWriteLock([&] { @@ -102,6 +109,12 @@ void LightEntityItem::setIsSpotlight(bool value) { setScaledDimensions(newDimensions); } +float LightEntityItem::getCutoff() const { + return resultWithReadLock([&] { + return _cutoff; + }); +} + void LightEntityItem::setCutoff(float value) { value = glm::clamp(value, MIN_CUTOFF, MAX_CUTOFF); bool needsRenderUpdate; @@ -129,17 +142,20 @@ void LightEntityItem::setCutoff(float value) { bool LightEntityItem::setSubClassProperties(const EntityItemProperties& properties) { bool somethingChanged = false; - SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(isSpotlight, setIsSpotlight); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(intensity, setIntensity); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(exponent, setExponent); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(cutoff, setCutoff); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(falloffRadius, setFalloffRadius); +@Light_ENTITY_SET_FROM@ return somethingChanged; } -int LightEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, +EntityPropertyFlags LightEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + +@Light_REQUESTED_PROPS@ + + return requestedProperties; +} + +int LightEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData, bool& somethingChanged) { @@ -147,110 +163,35 @@ int LightEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesRead = 0; const unsigned char* dataAt = data; - READ_ENTITY_PROPERTY(PROP_COLOR, glm::u8vec3, setColor); - READ_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, bool, setIsSpotlight); - READ_ENTITY_PROPERTY(PROP_INTENSITY, float, setIntensity); - READ_ENTITY_PROPERTY(PROP_EXPONENT, float, setExponent); - READ_ENTITY_PROPERTY(PROP_CUTOFF, float, setCutoff); - READ_ENTITY_PROPERTY(PROP_FALLOFF_RADIUS, float, setFalloffRadius); +@Light_ENTITY_READ@ return bytesRead; } - -EntityPropertyFlags LightEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { - EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); - requestedProperties += PROP_COLOR; - requestedProperties += PROP_IS_SPOTLIGHT; - requestedProperties += PROP_INTENSITY; - requestedProperties += PROP_EXPONENT; - requestedProperties += PROP_CUTOFF; - requestedProperties += PROP_FALLOFF_RADIUS; - return requestedProperties; -} - -void LightEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const { +void LightEntityItem::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_COLOR, getColor()); - APPEND_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, getIsSpotlight()); - APPEND_ENTITY_PROPERTY(PROP_INTENSITY, getIntensity()); - APPEND_ENTITY_PROPERTY(PROP_EXPONENT, getExponent()); - APPEND_ENTITY_PROPERTY(PROP_CUTOFF, getCutoff()); - APPEND_ENTITY_PROPERTY(PROP_FALLOFF_RADIUS, getFalloffRadius()); -} -glm::u8vec3 LightEntityItem::getColor() const { - return resultWithReadLock([&] { - return _color; - }); -} - -void LightEntityItem::setColor(const glm::u8vec3& value) { - withWriteLock([&] { - _needsRenderUpdate |= _color != value; - _color = value; - }); -} - -bool LightEntityItem::getIsSpotlight() const { - bool result; - withReadLock([&] { - result = _isSpotlight; - }); - return result; -} - -float LightEntityItem::getIntensity() const { - float result; - withReadLock([&] { - result = _intensity; - }); - return result; -} - -void LightEntityItem::setIntensity(float value) { - withWriteLock([&] { - _needsRenderUpdate |= _intensity != value; - _intensity = value; - }); -} +@Light_ENTITY_APPEND@ -float LightEntityItem::getFalloffRadius() const { - float result; - withReadLock([&] { - result = _falloffRadius; - }); - return result; } -float LightEntityItem::getExponent() const { - float result; - withReadLock([&] { - result = _exponent; - }); - return result; -} +void LightEntityItem::debugDump() const { + qCDebug(entities) << "LightEntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " editedAgo:" << debugTime(getLastEdited(), usecTimestampNow()); + qCDebug(entities) << " pointer:" << this; -void LightEntityItem::setExponent(float value) { - withWriteLock([&] { - _needsRenderUpdate |= _exponent != value; - _exponent = value; - }); -} +@Light_ENTITY_DEBUG@ -float LightEntityItem::getCutoff() const { - float result; - withReadLock([&] { - result = _cutoff; - }); - return result; } bool LightEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, diff --git a/libraries/entities/src/LightEntityItem.h b/libraries/entities/src/LightEntityItem.h.in similarity index 51% rename from libraries/entities/src/LightEntityItem.h rename to libraries/entities/src/LightEntityItem.h.in index 0f21c6acd99..2ce56b9b3b5 100644 --- a/libraries/entities/src/LightEntityItem.h +++ b/libraries/entities/src/LightEntityItem.h.in @@ -29,46 +29,11 @@ class LightEntityItem : public EntityItem { LightEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated + ENTITY_PROPERTY_SUBCLASS_METHODS /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately virtual void setUnscaledDimensions(const glm::vec3& value) override; - // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - virtual bool setSubClassProperties(const EntityItemProperties& properties) override; - - virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; - - virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, - 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; - - glm::u8vec3 getColor() const; - void setColor(const glm::u8vec3& value); - - bool getIsSpotlight() const; - void setIsSpotlight(bool value); - - float getIntensity() const; - void setIntensity(float value); - float getFalloffRadius() const; - void setFalloffRadius(float value); - - float getExponent() const; - void setExponent(float value); - - float getCutoff() const; - void setCutoff(float value); - static bool getLightsArePickable() { return _lightsArePickable; } static void setLightsArePickable(bool value) { _lightsArePickable = value; } @@ -83,13 +48,8 @@ class LightEntityItem : public EntityItem { QVariantMap& extraInfo, bool precisionPicking) const override; private: - // properties of a light - glm::u8vec3 _color; - bool _isSpotlight { DEFAULT_IS_SPOTLIGHT }; - float _intensity { DEFAULT_INTENSITY }; - float _falloffRadius { DEFAULT_FALLOFF_RADIUS }; - float _exponent { DEFAULT_EXPONENT }; - float _cutoff { DEFAULT_CUTOFF }; + +@Light_ENTITY_PROPS@ static bool _lightsArePickable; }; diff --git a/libraries/entities/src/LineEntityItem.cpp b/libraries/entities/src/LineEntityItem.cpp.in similarity index 68% rename from libraries/entities/src/LineEntityItem.cpp rename to libraries/entities/src/LineEntityItem.cpp.in index efb21b881e8..d29729ded2e 100644 --- a/libraries/entities/src/LineEntityItem.cpp +++ b/libraries/entities/src/LineEntityItem.cpp.in @@ -36,11 +36,10 @@ LineEntityItem::LineEntityItem(const EntityItemID& entityItemID) : } EntityItemProperties LineEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { - + EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class - COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getColor); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(linePoints, getLinePoints); +@Line_ENTITY_COPY_TO@ return properties; } @@ -48,14 +47,60 @@ EntityItemProperties LineEntityItem::getProperties(const EntityPropertyFlags& de bool LineEntityItem::setSubClassProperties(const EntityItemProperties& properties) { bool somethingChanged = false; - SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(linePoints, setLinePoints); +@Line_ENTITY_SET_FROM@ return somethingChanged; } +EntityPropertyFlags LineEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + +@Line_REQUESTED_PROPS@ + + return requestedProperties; +} + +void LineEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@Line_ENTITY_APPEND@ + +} + +int LineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + +@Line_ENTITY_READ@ + + return bytesRead; +} + +void LineEntityItem::debugDump() const { + qCDebug(entities) << "LineEntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " editedAgo:" << debugTime(getLastEdited(), usecTimestampNow()); + qCDebug(entities) << " pointer:" << this; + +@Line_ENTITY_DEBUG@ + +} + bool LineEntityItem::appendPoint(const glm::vec3& point) { - if (_points.size() > MAX_POINTS_PER_LINE - 1) { + if (_linePoints.size() > MAX_POINTS_PER_LINE - 1) { qCDebug(entities) << "MAX POINTS REACHED!"; return false; } @@ -66,12 +111,18 @@ bool LineEntityItem::appendPoint(const glm::vec3& point) { } withWriteLock([&] { _needsRenderUpdate = true; - _points << point; + _linePoints << point; }); return true; } +QVector LineEntityItem::getLinePoints() const { + return resultWithReadLock>([&] { + return _linePoints; + }); +} + bool LineEntityItem::setLinePoints(const QVector& points) { if (points.size() > MAX_POINTS_PER_LINE) { return false; @@ -87,74 +138,8 @@ bool LineEntityItem::setLinePoints(const QVector& points) { withWriteLock([&] { _needsRenderUpdate = true; - _points = points; + _linePoints = points; }); return true; } - -int LineEntityItem::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_COLOR, glm::u8vec3, setColor); - READ_ENTITY_PROPERTY(PROP_LINE_POINTS, QVector, setLinePoints); - - return bytesRead; -} - - -EntityPropertyFlags LineEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { - EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); - requestedProperties += PROP_COLOR; - requestedProperties += PROP_LINE_POINTS; - return requestedProperties; -} - -void LineEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const { - - bool successPropertyFits = true; - - APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor()); - APPEND_ENTITY_PROPERTY(PROP_LINE_POINTS, getLinePoints()); -} - -void LineEntityItem::debugDump() const { - quint64 now = usecTimestampNow(); - qCDebug(entities) << " LINE EntityItem id:" << getEntityItemID() << "---------------------------------------------"; - qCDebug(entities) << " color:" << _color; - qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); - qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); - qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); -} - -glm::u8vec3 LineEntityItem::getColor() const { - return resultWithReadLock([&] { - return _color; - }); -} - -void LineEntityItem::setColor(const glm::u8vec3& value) { - withWriteLock([&] { - _needsRenderUpdate |= _color != value; - _color = value; - }); -} - -QVector LineEntityItem::getLinePoints() const { - QVector result; - withReadLock([&] { - result = _points; - }); - return result; -} \ No newline at end of file diff --git a/libraries/entities/src/LineEntityItem.h b/libraries/entities/src/LineEntityItem.h.in similarity index 57% rename from libraries/entities/src/LineEntityItem.h rename to libraries/entities/src/LineEntityItem.h.in index 505291cddad..63ea27d98b5 100644 --- a/libraries/entities/src/LineEntityItem.h +++ b/libraries/entities/src/LineEntityItem.h.in @@ -21,34 +21,10 @@ class LineEntityItem : public EntityItem { LineEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated + ENTITY_PROPERTY_SUBCLASS_METHODS - // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - virtual bool setSubClassProperties(const EntityItemProperties& properties) override; - - virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; - - virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, - 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; - - glm::u8vec3 getColor() const; - void setColor(const glm::u8vec3& value); - - bool setLinePoints(const QVector& points); bool appendPoint(const glm::vec3& point); - QVector getLinePoints() const; - // never have a ray intersection pick a LineEntityItem. virtual bool supportsDetailedIntersection() const override { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, @@ -62,12 +38,15 @@ class LineEntityItem : public EntityItem { QVariantMap& extraInfo, bool precisionPicking) const override { return false; } - virtual void debugDump() const override; static const int MAX_POINTS_PER_LINE; + QVector getLinePoints() const; + bool setLinePoints(const QVector& points); + private: - glm::u8vec3 _color; - QVector _points; + +@Line_ENTITY_PROPS@ + }; #endif // hifi_LineEntityItem_h diff --git a/libraries/entities/src/MaterialEntityItem.cpp b/libraries/entities/src/MaterialEntityItem.cpp deleted file mode 100644 index 2ee7ad49497..00000000000 --- a/libraries/entities/src/MaterialEntityItem.cpp +++ /dev/null @@ -1,290 +0,0 @@ -// -// Created by Sam Gondelman on 1/12/18 -// 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 "MaterialEntityItem.h" - -#include "EntityItemProperties.h" - -#include "QJsonDocument" -#include "QJsonArray" - -EntityItemPointer MaterialEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - Pointer entity(new MaterialEntityItem(entityID), [](MaterialEntityItem* ptr) { ptr->deleteLater(); }); - entity->setProperties(properties); - return entity; -} - -// our non-pure virtual subclass for now... -MaterialEntityItem::MaterialEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { - _type = EntityTypes::Material; -} - -EntityItemProperties MaterialEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { - EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class - COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialURL, getMaterialURL); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialMappingMode, getMaterialMappingMode); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(priority, getPriority); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(parentMaterialName, getParentMaterialName); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialMappingPos, getMaterialMappingPos); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialMappingScale, getMaterialMappingScale); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialMappingRot, getMaterialMappingRot); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialData, getMaterialData); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(materialRepeat, getMaterialRepeat); - return properties; -} - -bool MaterialEntityItem::setSubClassProperties(const EntityItemProperties& properties) { - bool somethingChanged = false; - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialURL, setMaterialURL); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMappingMode, setMaterialMappingMode); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(priority, setPriority); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentMaterialName, setParentMaterialName); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMappingPos, setMaterialMappingPos); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMappingScale, setMaterialMappingScale); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMappingRot, setMaterialMappingRot); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialData, setMaterialData); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialRepeat, setMaterialRepeat); - - return somethingChanged; -} - -int MaterialEntityItem::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_MATERIAL_URL, QString, setMaterialURL); - READ_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_MODE, MaterialMappingMode, setMaterialMappingMode); - READ_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, quint16, setPriority); - READ_ENTITY_PROPERTY(PROP_PARENT_MATERIAL_NAME, QString, setParentMaterialName); - READ_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_POS, glm::vec2, setMaterialMappingPos); - READ_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_SCALE, glm::vec2, setMaterialMappingScale); - READ_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_ROT, float, setMaterialMappingRot); - READ_ENTITY_PROPERTY(PROP_MATERIAL_DATA, QString, setMaterialData); - READ_ENTITY_PROPERTY(PROP_MATERIAL_REPEAT, bool, setMaterialRepeat); - - return bytesRead; -} - -EntityPropertyFlags MaterialEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { - EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); - requestedProperties += PROP_MATERIAL_URL; - requestedProperties += PROP_MATERIAL_MAPPING_MODE; - requestedProperties += PROP_MATERIAL_PRIORITY; - requestedProperties += PROP_PARENT_MATERIAL_NAME; - requestedProperties += PROP_MATERIAL_MAPPING_POS; - requestedProperties += PROP_MATERIAL_MAPPING_SCALE; - requestedProperties += PROP_MATERIAL_MAPPING_ROT; - requestedProperties += PROP_MATERIAL_DATA; - requestedProperties += PROP_MATERIAL_REPEAT; - return requestedProperties; -} - -void MaterialEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const { - - bool successPropertyFits = true; - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_URL, getMaterialURL()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_MODE, (uint32_t)getMaterialMappingMode()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, getPriority()); - APPEND_ENTITY_PROPERTY(PROP_PARENT_MATERIAL_NAME, getParentMaterialName()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_POS, getMaterialMappingPos()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_SCALE, getMaterialMappingScale()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_MAPPING_ROT, getMaterialMappingRot()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_DATA, getMaterialData()); - APPEND_ENTITY_PROPERTY(PROP_MATERIAL_REPEAT, getMaterialRepeat()); -} - -void MaterialEntityItem::debugDump() const { - quint64 now = usecTimestampNow(); - qCDebug(entities) << " MATERIAL EntityItem id:" << getEntityItemID() << "---------------------------------------------"; - qCDebug(entities) << " name:" << _name; - qCDebug(entities) << " material url:" << _materialURL; - qCDebug(entities) << " material mapping mode:" << _materialMappingMode; - qCDebug(entities) << " material repeat:" << _materialRepeat; - qCDebug(entities) << " priority:" << _priority; - qCDebug(entities) << " parent material name:" << _parentMaterialName; - qCDebug(entities) << " material mapping pos:" << _materialMappingPos; - qCDebug(entities) << " material mapping scale:" << _materialMappingRot; - qCDebug(entities) << " material mapping rot:" << _materialMappingScale; - qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); - qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); - qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); - qCDebug(entities) << "MATERIAL EntityItem Ptr:" << this; -} - -void MaterialEntityItem::setUnscaledDimensions(const glm::vec3& value) { - _desiredDimensions = value; - if (_hasVertexShader || _materialMappingMode == MaterialMappingMode::PROJECTED) { - EntityItem::setUnscaledDimensions(value); - } else if (_materialMappingMode == MaterialMappingMode::UV) { - EntityItem::setUnscaledDimensions(ENTITY_ITEM_DEFAULT_DIMENSIONS); - } -} - -QString MaterialEntityItem::getMaterialURL() const { - return resultWithReadLock([&] { - return _materialURL; - }); -} - -void MaterialEntityItem::setMaterialURL(const QString& materialURL) { - withWriteLock([&] { - _needsRenderUpdate |= _materialURL != materialURL; - _materialURL = materialURL; - }); -} - -QString MaterialEntityItem::getMaterialData() const { - return resultWithReadLock([&] { - return _materialData; - }); -} - -void MaterialEntityItem::setMaterialData(const QString& materialData) { - withWriteLock([&] { - _needsRenderUpdate |= _materialData != materialData; - _materialData = materialData; - }); -} - -MaterialMappingMode MaterialEntityItem::getMaterialMappingMode() const { - return resultWithReadLock([&] { - return _materialMappingMode; - }); -} - -void MaterialEntityItem::setMaterialMappingMode(MaterialMappingMode mode) { - withWriteLock([&] { - _needsRenderUpdate |= _materialMappingMode != mode; - _materialMappingMode = mode; - }); - setUnscaledDimensions(_desiredDimensions); -} - -quint16 MaterialEntityItem::getPriority() const { - return resultWithReadLock([&] { - return _priority; - }); -} - -void MaterialEntityItem::setPriority(quint16 priority) { - withWriteLock([&] { - _needsRenderUpdate |= _priority != priority; - _priority = priority; - }); -} - -QString MaterialEntityItem::getParentMaterialName() const { - return resultWithReadLock([&] { - return _parentMaterialName; - }); -} - -void MaterialEntityItem::setParentMaterialName(const QString& parentMaterialName) { - withWriteLock([&] { - _needsRenderUpdate |= _parentMaterialName != parentMaterialName; - _parentMaterialName = parentMaterialName; - }); -} - -glm::vec2 MaterialEntityItem::getMaterialMappingPos() const { - return resultWithReadLock([&] { - return _materialMappingPos; - }); -} - -void MaterialEntityItem::setMaterialMappingPos(const glm::vec2& materialMappingPos) { - withWriteLock([&] { - _needsRenderUpdate |= _materialMappingPos != materialMappingPos; - _materialMappingPos = materialMappingPos; - }); -} - -glm::vec2 MaterialEntityItem::getMaterialMappingScale() const { - return resultWithReadLock([&] { - return _materialMappingScale; - }); -} - -void MaterialEntityItem::setMaterialMappingScale(const glm::vec2& materialMappingScale) { - withWriteLock([&] { - _needsRenderUpdate |= _materialMappingScale != materialMappingScale; - _materialMappingScale = materialMappingScale; - }); -} - -float MaterialEntityItem::getMaterialMappingRot() const { - return resultWithReadLock([&] { - return _materialMappingRot; - }); -} - -void MaterialEntityItem::setMaterialMappingRot(float materialMappingRot) { - withWriteLock([&] { - _needsRenderUpdate |= _materialMappingRot != materialMappingRot; - _materialMappingRot = materialMappingRot; - }); -} - -bool MaterialEntityItem::getMaterialRepeat() const { - return resultWithReadLock([&] { - return _materialRepeat; - }); -} - -void MaterialEntityItem::setMaterialRepeat(bool value) { - withWriteLock([&] { - _needsRenderUpdate |= _materialRepeat != value; - _materialRepeat = value; - }); -} - -void MaterialEntityItem::setParentID(const QUuid& parentID) { - if (parentID != getParentID()) { - EntityItem::setParentID(parentID); - _hasVertexShader = false; - } -} - -AACube MaterialEntityItem::calculateInitialQueryAACube(bool& success) { - AACube aaCube = EntityItem::calculateInitialQueryAACube(success); - // A Material entity's queryAACube contains its parent's queryAACube - auto parent = getParentPointer(success); - if (success && parent) { - success = false; - AACube parentQueryAACube = parent->calculateInitialQueryAACube(success); - if (success) { - aaCube += parentQueryAACube.getMinimumPoint(); - aaCube += parentQueryAACube.getMaximumPoint(); - } - } - return aaCube; -} - -void MaterialEntityItem::setHasVertexShader(bool hasVertexShader) { - bool prevHasVertexShader = _hasVertexShader; - _hasVertexShader = hasVertexShader; - - if (hasVertexShader && !prevHasVertexShader) { - setLocalPosition(glm::vec3(0.0f)); - setLocalOrientation(glm::quat()); - setUnscaledDimensions(EntityTree::getUnscaledDimensionsForID(getParentID())); - } else if (!hasVertexShader && prevHasVertexShader) { - setUnscaledDimensions(_desiredDimensions); - } -} \ No newline at end of file diff --git a/libraries/entities/src/MaterialEntityItem.cpp.in b/libraries/entities/src/MaterialEntityItem.cpp.in new file mode 100644 index 00000000000..045c155084d --- /dev/null +++ b/libraries/entities/src/MaterialEntityItem.cpp.in @@ -0,0 +1,132 @@ +// +// Created by Sam Gondelman on 1/12/18 +// 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 "MaterialEntityItem.h" + +#include "EntityItemProperties.h" + +#include "QJsonDocument" +#include "QJsonArray" + +EntityItemPointer MaterialEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + Pointer entity(new MaterialEntityItem(entityID), [](MaterialEntityItem* ptr) { ptr->deleteLater(); }); + entity->setProperties(properties); + return entity; +} + +// our non-pure virtual subclass for now... +MaterialEntityItem::MaterialEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { + _type = EntityTypes::Material; +} + +EntityItemProperties MaterialEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class + +@Material_ENTITY_COPY_TO@ + + return properties; +} + +bool MaterialEntityItem::setSubClassProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + +@Material_ENTITY_SET_FROM@ + + return somethingChanged; +} + +EntityPropertyFlags MaterialEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + +@Material_REQUESTED_PROPS@ + + return requestedProperties; +} + +void MaterialEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@Material_ENTITY_APPEND@ + +} + +int MaterialEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + +@Material_ENTITY_READ@ + + return bytesRead; +} + +void MaterialEntityItem::debugDump() const { + qCDebug(entities) << "MaterialEntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " editedAgo:" << debugTime(getLastEdited(), usecTimestampNow()); + qCDebug(entities) << " pointer:" << this; + +@Material_ENTITY_DEBUG@ + +} + +void MaterialEntityItem::setUnscaledDimensions(const glm::vec3& value) { + _desiredDimensions = value; + if (_hasVertexShader || _materialMappingMode == MaterialMappingMode::PROJECTED) { + EntityItem::setUnscaledDimensions(value); + } else if (_materialMappingMode == MaterialMappingMode::UV) { + EntityItem::setUnscaledDimensions(ENTITY_ITEM_DEFAULT_DIMENSIONS); + } +} + +void MaterialEntityItem::setParentID(const QUuid& parentID) { + if (parentID != getParentID()) { + EntityItem::setParentID(parentID); + _hasVertexShader = false; + } +} + +AACube MaterialEntityItem::calculateInitialQueryAACube(bool& success) { + AACube aaCube = EntityItem::calculateInitialQueryAACube(success); + // A Material entity's queryAACube contains its parent's queryAACube + auto parent = getParentPointer(success); + if (success && parent) { + success = false; + AACube parentQueryAACube = parent->calculateInitialQueryAACube(success); + if (success) { + aaCube += parentQueryAACube.getMinimumPoint(); + aaCube += parentQueryAACube.getMaximumPoint(); + } + } + return aaCube; +} + +void MaterialEntityItem::setHasVertexShader(bool hasVertexShader) { + bool prevHasVertexShader = _hasVertexShader; + _hasVertexShader = hasVertexShader; + + if (hasVertexShader && !prevHasVertexShader) { + setLocalPosition(glm::vec3(0.0f)); + setLocalOrientation(glm::quat()); + setUnscaledDimensions(EntityTree::getUnscaledDimensionsForID(getParentID())); + } else if (!hasVertexShader && prevHasVertexShader) { + setUnscaledDimensions(_desiredDimensions); + } +} diff --git a/libraries/entities/src/MaterialEntityItem.h b/libraries/entities/src/MaterialEntityItem.h deleted file mode 100644 index 76cfbfa9dc5..00000000000 --- a/libraries/entities/src/MaterialEntityItem.h +++ /dev/null @@ -1,119 +0,0 @@ -// -// Created by Sam Gondelman on 1/12/18 -// 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_MaterialEntityItem_h -#define hifi_MaterialEntityItem_h - -#include "EntityItem.h" - -#include "MaterialMappingMode.h" - -class MaterialEntityItem : public EntityItem { - using Pointer = std::shared_ptr; -public: - static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - - MaterialEntityItem(const EntityItemID& entityItemID); - - ALLOW_INSTANTIATION // This class can be instantiated - - // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - virtual bool setSubClassProperties(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; - - void debugDump() const override; - - virtual void setUnscaledDimensions(const glm::vec3& value) override; - - QString getMaterialURL() const; - void setMaterialURL(const QString& materialURL); - - QString getMaterialData() const; - void setMaterialData(const QString& materialData); - - MaterialMappingMode getMaterialMappingMode() const; - void setMaterialMappingMode(MaterialMappingMode mode); - - bool getMaterialRepeat() const; - void setMaterialRepeat(bool repeat); - - quint16 getPriority() const; - void setPriority(quint16 priority); - - QString getParentMaterialName() const; - void setParentMaterialName(const QString& parentMaterialName); - - void setParentID(const QUuid& parentID) override; - - glm::vec2 getMaterialMappingPos() const; - void setMaterialMappingPos(const glm::vec2& materialMappingPos); - glm::vec2 getMaterialMappingScale() const; - void setMaterialMappingScale(const glm::vec2& materialMappingScale); - float getMaterialMappingRot() const; - void setMaterialMappingRot(float materialMappingRot); - - AACube calculateInitialQueryAACube(bool& success) override; - - void setHasVertexShader(bool hasVertexShader); - -private: - // URL for this material. Currently, only JSON format is supported. Set to "materialData" to use the material data to live edit a material. - // The following fields are supported in the JSON: - // materialVersion: a uint for the version of this network material (currently, only 1 is supported) - // materials, which is either an object or an array of objects, each with the following properties: - // strings: - // name (NOT YET USED), model (NOT YET USED, should use "hifi_pbr") - // floats: - // opacity, roughness, metallic, scattering - // bool: - // unlit - // colors (arrays of 3 floats 0-1. Optional fourth value in array can be a boolean isSRGB): - // emissive, albedo - // urls to textures: - // emissiveMap, albedoMap (set opacityMap = albedoMap for transparency), metallicMap or specularMap, roughnessMap or glossMap, - // normalMap or bumpMap, occlusionMap, lightMap (broken, FIXME), scatteringMap (only works if normal mapped) - QString _materialURL; - // Type of material. "uv" or "projected". - MaterialMappingMode _materialMappingMode { UV }; - bool _materialRepeat { true }; - glm::vec3 _desiredDimensions; - // Priority for this material when applying it to its parent. Only the highest priority material will be used. Materials with the same priority are (essentially) randomly sorted. - // Base materials that come with models always have priority 0. - quint16 _priority { 0 }; - // An identifier for choosing a submesh or submeshes within a parent. If in the format "mat::", all submeshes with material name "" will be replaced. Otherwise, - // parentMaterialName will be parsed as an unsigned int (strings not starting with "mat::" will parse to 0), representing the mesh index to modify. - QString _parentMaterialName { "0" }; - // Offset position in UV-space of top left of material, (0, 0) to (1, 1) - glm::vec2 _materialMappingPos { 0, 0 }; - // How much to scale this material within its parent's UV-space - glm::vec2 _materialMappingScale { 1, 1 }; - // How much to rotate this material within its parent's UV-space (degrees) - float _materialMappingRot { 0 }; - QString _materialData; - - bool _hasVertexShader { false }; - -}; - -#endif // hifi_MaterialEntityItem_h diff --git a/libraries/entities/src/MaterialEntityItem.h.in b/libraries/entities/src/MaterialEntityItem.h.in new file mode 100644 index 00000000000..8575936e69f --- /dev/null +++ b/libraries/entities/src/MaterialEntityItem.h.in @@ -0,0 +1,42 @@ +// +// Created by Sam Gondelman on 1/12/18 +// 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_MaterialEntityItem_h +#define hifi_MaterialEntityItem_h + +#include "EntityItem.h" + +#include "MaterialMappingMode.h" + +class MaterialEntityItem : public EntityItem { + using Pointer = std::shared_ptr; +public: + static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); + + MaterialEntityItem(const EntityItemID& entityItemID); + + ALLOW_INSTANTIATION // This class can be instantiated + ENTITY_PROPERTY_SUBCLASS_METHODS + + virtual void setUnscaledDimensions(const glm::vec3& value) override; + void setParentID(const QUuid& parentID) override; + + AACube calculateInitialQueryAACube(bool& success) override; + + void setHasVertexShader(bool hasVertexShader); + +private: + +@Material_ENTITY_PROPS@ + + glm::vec3 _desiredDimensions; + bool _hasVertexShader { false }; + +}; + +#endif // hifi_MaterialEntityItem_h diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp.in similarity index 70% rename from libraries/entities/src/ModelEntityItem.cpp rename to libraries/entities/src/ModelEntityItem.cpp.in index 45d41c3a7e9..dd28b21818e 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp.in @@ -34,70 +34,25 @@ EntityItemPointer ModelEntityItem::factory(const EntityItemID& entityID, const E } ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID), - _blendshapeCoefficientsVector((int)Blendshapes::BlendshapeCount, 0.0f) + _blendshapeCoefficientsVector((int)Blendshapes::BlendshapeCount, 0.0f), + _lastAnimated(usecTimestampNow()) { - _lastAnimated = usecTimestampNow(); - // set the last animated when interface (re)starts _type = EntityTypes::Model; - _lastKnownCurrentFrame = -1; _visuallyReady = false; } -const QString ModelEntityItem::getTextures() const { - return resultWithReadLock([&] { - return _textures; - }); -} - -void ModelEntityItem::setTextures(const QString& textures) { - withWriteLock([&] { - _needsRenderUpdate |= _textures != textures; - _textures = textures; - }); -} - EntityItemProperties ModelEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class - COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(compoundShapeURL, getCompoundShapeURL); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getColor); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures); - - COPY_ENTITY_PROPERTY_TO_PROPERTIES(modelURL, getModelURL); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(modelScale, getModelScale); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(jointRotationsSet, getJointRotationsSet); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(jointRotations, getJointRotations); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(jointTranslationsSet, getJointTranslationsSet); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(jointTranslations, getJointTranslations); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(relayParentJoints, getRelayParentJoints); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(groupCulled, getGroupCulled); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(blendshapeCoefficients, getBlendshapeCoefficients); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(useOriginalPivot, getUseOriginalPivot); - withReadLock([&] { - _animationProperties.getProperties(properties); - }); +@Model_ENTITY_COPY_TO@ + return properties; } bool ModelEntityItem::setSubClassProperties(const EntityItemProperties& properties) { bool somethingChanged = false; - SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, setShapeType); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures); - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(modelURL, setModelURL); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(modelScale, setModelScale); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointRotationsSet, setJointRotationsSet); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointRotations, setJointRotations); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointTranslationsSet, setJointTranslationsSet); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointTranslations, setJointTranslations); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(relayParentJoints, setRelayParentJoints); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(groupCulled, setGroupCulled); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(blendshapeCoefficients, setBlendshapeCoefficients); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(useOriginalPivot, setUseOriginalPivot); +@Model_ENTITY_SET_FROM@ withWriteLock([&] { AnimationPropertyGroup animationProperties = _animationProperties; @@ -109,6 +64,28 @@ bool ModelEntityItem::setSubClassProperties(const EntityItemProperties& properti return somethingChanged; } +EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + +@Model_REQUESTED_PROPS@ + + return requestedProperties; +} + +void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@Model_ENTITY_APPEND@ + +} + int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData, @@ -118,21 +95,7 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, const unsigned char* dataAt = data; bool animationPropertiesChanged = false; - READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType); - READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL); - READ_ENTITY_PROPERTY(PROP_COLOR, glm::u8vec3, setColor); - READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures); - - READ_ENTITY_PROPERTY(PROP_MODEL_URL, QString, setModelURL); - READ_ENTITY_PROPERTY(PROP_MODEL_SCALE, glm::vec3, setModelScale); - READ_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS_SET, QVector, setJointRotationsSet); - READ_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS, QVector, setJointRotations); - READ_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, QVector, setJointTranslationsSet); - READ_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS, QVector, setJointTranslations); - READ_ENTITY_PROPERTY(PROP_RELAY_PARENT_JOINTS, bool, setRelayParentJoints); - READ_ENTITY_PROPERTY(PROP_GROUP_CULLED, bool, setGroupCulled); - READ_ENTITY_PROPERTY(PROP_BLENDSHAPE_COEFFICIENTS, QString, setBlendshapeCoefficients); - READ_ENTITY_PROPERTY(PROP_USE_ORIGINAL_PIVOT, bool, setUseOriginalPivot); +@Model_ENTITY_READ@ // grab a local copy of _animationProperties to avoid multiple locks int bytesFromAnimation; @@ -155,63 +118,6 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, return bytesRead; } -EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { - EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); - - requestedProperties += PROP_SHAPE_TYPE; - requestedProperties += PROP_COMPOUND_SHAPE_URL; - requestedProperties += PROP_COLOR; - requestedProperties += PROP_TEXTURES; - - requestedProperties += PROP_MODEL_URL; - requestedProperties += PROP_MODEL_SCALE; - requestedProperties += PROP_JOINT_ROTATIONS_SET; - requestedProperties += PROP_JOINT_ROTATIONS; - requestedProperties += PROP_JOINT_TRANSLATIONS_SET; - requestedProperties += PROP_JOINT_TRANSLATIONS; - requestedProperties += PROP_RELAY_PARENT_JOINTS; - requestedProperties += PROP_GROUP_CULLED; - requestedProperties += PROP_BLENDSHAPE_COEFFICIENTS; - requestedProperties += PROP_USE_ORIGINAL_PIVOT; - requestedProperties += _animationProperties.getEntityProperties(params); - - return requestedProperties; -} - - -void ModelEntityItem::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_SHAPE_TYPE, (uint32_t)getShapeType()); - APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, getCompoundShapeURL()); - APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor()); - APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures()); - - APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, getModelURL()); - APPEND_ENTITY_PROPERTY(PROP_MODEL_SCALE, getModelScale()); - APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS_SET, getJointRotationsSet()); - APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS, getJointRotations()); - APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, getJointTranslationsSet()); - APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS, getJointTranslations()); - APPEND_ENTITY_PROPERTY(PROP_RELAY_PARENT_JOINTS, getRelayParentJoints()); - APPEND_ENTITY_PROPERTY(PROP_GROUP_CULLED, getGroupCulled()); - APPEND_ENTITY_PROPERTY(PROP_BLENDSHAPE_COEFFICIENTS, getBlendshapeCoefficients()); - APPEND_ENTITY_PROPERTY(PROP_USE_ORIGINAL_PIVOT, getUseOriginalPivot()); - - withReadLock([&] { - _animationProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, - propertyFlags, propertiesDidntFit, propertyCount, appendState); - }); -} - - - // added update function back for property fix void ModelEntityItem::update(const quint64& now) { assert(_lastAnimated > 0); @@ -229,7 +135,7 @@ void ModelEntityItem::update(const quint64& now) { } // increment animation frame - _currentFrame += (animationProperties.getFPS() * ((float)interval) / (float)USECS_PER_SECOND); + _currentFrame += (animationProperties.getFps() * ((float)interval) / (float)USECS_PER_SECOND); if (_currentFrame > animationProperties.getLastFrame() + 1.0f) { if (animationProperties.getLoop()) { _currentFrame = animationProperties.computeLoopedFrame(_currentFrame); @@ -249,14 +155,15 @@ void ModelEntityItem::update(const quint64& now) { } void ModelEntityItem::debugDump() const { - qCDebug(entities) << "ModelEntityItem id:" << getEntityItemID(); - qCDebug(entities) << " edited ago:" << getEditedAgo(); - qCDebug(entities) << " position:" << getWorldPosition(); - qCDebug(entities) << " dimensions:" << getScaledDimensions(); - qCDebug(entities) << " model URL:" << getModelURL(); - qCDebug(entities) << " compound shape URL:" << getCompoundShapeURL(); - qCDebug(entities) << " blendshapeCoefficients:" << getBlendshapeCoefficients(); - qCDebug(entities) << " useOrigialPivot:" << getUseOriginalPivot(); + qCDebug(entities) << "ModelEntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " editedAgo:" << debugTime(getLastEdited(), usecTimestampNow()); + qCDebug(entities) << " pointer:" << this; + +@Model_ENTITY_DEBUG@ + } void ModelEntityItem::setShapeType(ShapeType type) { @@ -296,15 +203,6 @@ ShapeType ModelEntityItem::getShapeType() const { return type; } -void ModelEntityItem::setModelURL(const QString& url) { - withWriteLock([&] { - if (_modelURL != url) { - _modelURL = url; - _needsRenderUpdate = true; - } - }); -} - glm::vec3 ModelEntityItem::getScaledDimensions() const { glm::vec3 parentScale = getTransform().getScale(); return _unscaledDimensions * parentScale; @@ -343,14 +241,6 @@ const Transform ModelEntityItem::getTransformWithOnlyLocalRotation(bool& success return worldTransform; } -void ModelEntityItem::setCompoundShapeURL(const QString& url) { - withWriteLock([&] { - if (_compoundShapeURL.get() != url) { - _compoundShapeURL.set(url); - } - }); -} - void ModelEntityItem::setAnimationSettings(const QString& value) { // NOTE: this method only called for old bitstream format @@ -367,7 +257,7 @@ void ModelEntityItem::setAnimationSettings(const QString& value) { QVariantMap settingsMap = settingsAsJsonObject.toVariantMap(); if (settingsMap.contains("fps")) { float fps = settingsMap["fps"].toFloat(); - animationProperties.setFPS(fps); + animationProperties.setFps(fps); } // old settings used frameIndex @@ -413,6 +303,19 @@ void ModelEntityItem::setAnimationSettings(const QString& value) { }); } +QString ModelEntityItem::getModelURL() const { + return resultWithReadLock([&] { + return _modelURL; + }); +} + +void ModelEntityItem::setModelURL(const QString& value) { + withWriteLock([&] { + _needsRenderUpdate |= _modelURL != value; + _modelURL = value; + }); +} + void ModelEntityItem::resizeJointArrays(int newSize) { if (newSize < 0) { return; @@ -544,78 +447,45 @@ QVector ModelEntityItem::getJointTranslationsSet() const { return result; } -bool ModelEntityItem::hasModel() const { +bool ModelEntityItem::hasModel() const { return resultWithReadLock([&] { return !_modelURL.isEmpty(); }); } bool ModelEntityItem::hasCompoundShapeURL() const { - return !_compoundShapeURL.get().isEmpty(); -} - -QString ModelEntityItem::getModelURL() const { - return resultWithReadLock([&] { - return _modelURL; - }); -} - -void ModelEntityItem::setRelayParentJoints(bool relayJoints) { - withWriteLock([&] { - _relayParentJoints = relayJoints; - }); -} - -bool ModelEntityItem::getRelayParentJoints() const { return resultWithReadLock([&] { - return _relayParentJoints; - }); -} - -void ModelEntityItem::setGroupCulled(bool value) { - withWriteLock([&] { - _needsRenderUpdate |= _groupCulled != value; - _groupCulled = value; - }); -} - -bool ModelEntityItem::getGroupCulled() const { - return resultWithReadLock([&] { - return _groupCulled; + return !_compoundShapeURL.isEmpty(); }); } QString ModelEntityItem::getCompoundShapeURL() const { - return _compoundShapeURL.get(); -} - -void ModelEntityItem::setColor(const glm::u8vec3& value) { - withWriteLock([&] { - _color = value; + return resultWithReadLock([&] { + return _compoundShapeURL; }); } -glm::u8vec3 ModelEntityItem::getColor() const { - return resultWithReadLock([&] { - return _color; +void ModelEntityItem::setCompoundShapeURL(const QString& url) { + withWriteLock([&] { + _compoundShapeURL = url; }); } // Animation related items... -AnimationPropertyGroup ModelEntityItem::getAnimationProperties() const { +AnimationPropertyGroup ModelEntityItem::getAnimationProperties() const { return resultWithReadLock([&] { return _animationProperties; }); } -bool ModelEntityItem::hasAnimation() const { - return resultWithReadLock([&] { - return !_animationProperties.getURL().isEmpty(); +bool ModelEntityItem::hasAnimation() const { + return resultWithReadLock([&] { + return !_animationProperties.getUrl().isEmpty(); }); } -QString ModelEntityItem::getAnimationURL() const { +QString ModelEntityItem::getAnimationURL() const { return resultWithReadLock([&] { - return _animationProperties.getURL(); + return _animationProperties.getUrl(); }); } @@ -631,7 +501,7 @@ bool ModelEntityItem::getAnimationAllowTranslation() const { }); } -float ModelEntityItem::getAnimationCurrentFrame() const { +float ModelEntityItem::getAnimationCurrentFrame() const { return resultWithReadLock([&] { return _animationProperties.getCurrentFrame(); }); @@ -643,6 +513,22 @@ bool ModelEntityItem::isAnimatingSomething() const { }); } +bool ModelEntityItem::getAnimationSmoothFrames() const { + return resultWithReadLock([&] { + return _animationProperties.getSmoothFrames(); + }); +} + +int ModelEntityItem::getAnimationNextFrame(int currentFrame, int frameCount) const { + return resultWithReadLock([&] { + int result = currentFrame + 1; + if (result > _animationProperties.getLastFrame() || result > (frameCount - 1)) { + result = _animationProperties.getFirstFrame(); + } + return std::max(result, 0); + }); +} + bool ModelEntityItem::applyNewAnimationProperties(AnimationPropertyGroup newProperties) { // call applyNewAnimationProperties() whenever trying to update _animationProperties // because there is some reset logic we need to do whenever the animation "config" properties change @@ -681,18 +567,6 @@ bool ModelEntityItem::applyNewAnimationProperties(AnimationPropertyGroup newProp return somethingChanged; } -glm::vec3 ModelEntityItem::getModelScale() const { - return resultWithReadLock([&] { - return _modelScale; - }); -} - -void ModelEntityItem::setModelScale(const glm::vec3& modelScale) { - withWriteLock([&] { - _modelScale = modelScale; - }); -} - QString ModelEntityItem::getBlendshapeCoefficients() const { return resultWithReadLock([&] { return QJsonDocument::fromVariant(_blendshapeCoefficientsMap).toJson(); diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h.in similarity index 58% rename from libraries/entities/src/ModelEntityItem.h rename to libraries/entities/src/ModelEntityItem.h.in index a00327251c7..7aa527f9862 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h.in @@ -26,46 +26,24 @@ class ModelEntityItem : public EntityItem { ModelEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated - - // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - virtual bool setSubClassProperties(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; - + ENTITY_PROPERTY_SUBCLASS_METHODS virtual void update(const quint64& now) override; bool needsToCallUpdate() const override { return isAnimatingSomething(); } - virtual void debugDump() const override; - void setShapeType(ShapeType type) override; virtual ShapeType getShapeType() const override; - // TODO: Move these to subclasses, or other appropriate abstraction - // getters/setters applicable to models and particles - glm::u8vec3 getColor() const; - void setColor(const glm::u8vec3& value); + virtual void setModelURL(const QString& value); + QString getModelURL() const; bool hasModel() const; virtual bool hasCompoundShapeURL() const; + virtual void setCompoundShapeURL(const QString& value); + QString getCompoundShapeURL() const; static const QString DEFAULT_MODEL_URL; - QString getModelURL() const; + static const QString DEFAULT_COMPOUND_SHAPE_URL; virtual glm::vec3 getScaledDimensions() const override; virtual void setScaledDimensions(const glm::vec3& value) override; @@ -74,13 +52,6 @@ class ModelEntityItem : public EntityItem { virtual const Transform getTransformWithOnlyLocalRotation(bool& success, int depth = 0) const override; virtual const Transform getTransform() const override; - static const QString DEFAULT_COMPOUND_SHAPE_URL; - QString getCompoundShapeURL() const; - - // model related properties - virtual void setModelURL(const QString& url); - virtual void setCompoundShapeURL(const QString& url); - // Animation related items... AnimationPropertyGroup getAnimationProperties() const; bool hasAnimation() const; @@ -89,45 +60,32 @@ class ModelEntityItem : public EntityItem { float getAnimationCurrentFrame() const; bool getAnimationAllowTranslation() const; bool isAnimatingSomething() const; - - void setRelayParentJoints(bool relayJoints); - bool getRelayParentJoints() const; - - void setGroupCulled(bool value); - bool getGroupCulled() const; + bool getAnimationSmoothFrames() const; + int getAnimationNextFrame(int currentFrame, int frameCount) const; static const QString DEFAULT_TEXTURES; - const QString getTextures() const; - void setTextures(const QString& textures); + QVector getJointRotations() const; virtual void setJointRotations(const QVector& rotations); + QVector getJointRotationsSet() const; virtual void setJointRotationsSet(const QVector& rotationsSet); + QVector getJointTranslations() const; virtual void setJointTranslations(const QVector& translations); + QVector getJointTranslationsSet() const; virtual void setJointTranslationsSet(const QVector& translationsSet); - virtual void setAnimationJointsData(const QVector& jointsData); - QVector getJointRotations() const; - QVector getJointRotationsSet() const; - QVector getJointTranslations() const; - QVector getJointTranslationsSet() const; - - glm::vec3 getModelScale() const; - void setModelScale(const glm::vec3& modelScale); - - QString getBlendshapeCoefficients() const; - void setBlendshapeCoefficients(const QString& blendshapeCoefficients); bool blendshapesChanged() const { return _blendshapesChanged; } QVector getBlendshapeCoefficientVector(); - bool getUseOriginalPivot() const; - void setUseOriginalPivot(bool useOriginalPivot); - private: void setAnimationSettings(const QString& value); // only called for old bitstream format bool applyNewAnimationProperties(AnimationPropertyGroup newProperties); protected: + +@Model_ENTITY_PROPS@ + void resizeJointArrays(int newSize); // these are used: @@ -136,11 +94,6 @@ class ModelEntityItem : public EntityItem { // - to relay between network and model/rig // they aren't currently updated from data in the model/rig, and they don't have a direct effect // on what's rendered. - ReadWriteLockable _jointDataLock; - - bool _jointRotationsExplicitlySet { false }; // were the joints set as a property or just side effect of animations - bool _jointTranslationsExplicitlySet{ false }; // were the joints set as a property or just side effect of animations - struct ModelJointData { EntityJointData joint; bool rotationDirty { false }; @@ -148,27 +101,16 @@ class ModelEntityItem : public EntityItem { }; QVector _localJointData; - int _lastKnownCurrentFrame{-1}; - - glm::u8vec3 _color; - glm::vec3 _modelScale { 1.0f }; - QString _modelURL; - bool _relayParentJoints; - bool _groupCulled { false }; - QVariantMap _blendshapeCoefficientsMap; - bool _useOriginalPivot { false }; - - ThreadSafeValueCache _compoundShapeURL; - - AnimationPropertyGroup _animationProperties; + ReadWriteLockable _jointDataLock; - QString _textures; + bool _jointRotationsExplicitlySet { false }; // were the joints set as a property or just side effect of animations + bool _jointTranslationsExplicitlySet{ false }; // were the joints set as a property or just side effect of animations - ShapeType _shapeType { SHAPE_TYPE_NONE }; + QVariantMap _blendshapeCoefficientsMap; private: - uint64_t _lastAnimated{ 0 }; - float _currentFrame{ -1.0f }; + uint64_t _lastAnimated { 0 }; + float _currentFrame { -1.0f }; QVector _blendshapeCoefficientsVector; bool _blendshapesChanged { false }; diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp.in similarity index 68% rename from libraries/entities/src/ParticleEffectEntityItem.cpp rename to libraries/entities/src/ParticleEffectEntityItem.cpp.in index b0cd6efc9dc..184ffee8cf8 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp.in @@ -73,7 +73,7 @@ bool operator!=(const RangeGradient& a, const RangeGradient& b) { } bool operator==(const EmitProperties& a, const EmitProperties& b) { - return + return (a.rate == b.rate) && (a.speed == b.speed) && (a.acceleration == b.acceleration) && @@ -142,7 +142,7 @@ bool Properties::valid() const { bool Properties::emitting() const { return emission.rate > 0.0f && lifespan > 0.0f && polar.start <= polar.finish; - + } uint64_t Properties::emitIntervalUsecs() const { @@ -644,54 +644,7 @@ void ParticleEffectEntityItem::computeAndUpdateDimensions() { EntityItemProperties ParticleEffectEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class - COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(compoundShapeURL, getCompoundShapeURL); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getColor); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha); - withReadLock([&] { - _pulseProperties.getProperties(properties); - }); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures); - - COPY_ENTITY_PROPERTY_TO_PROPERTIES(maxParticles, getMaxParticles); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(lifespan, getLifespan); - - COPY_ENTITY_PROPERTY_TO_PROPERTIES(isEmitting, getIsEmitting); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitRate, getEmitRate); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitSpeed, getEmitSpeed); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(speedSpread, getSpeedSpread); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitOrientation, getEmitOrientation); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitDimensions, getEmitDimensions); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitRadiusStart, getEmitRadiusStart); - - COPY_ENTITY_PROPERTY_TO_PROPERTIES(polarStart, getPolarStart); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(polarFinish, getPolarFinish); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(azimuthStart, getAzimuthStart); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(azimuthFinish, getAzimuthFinish); - - COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitAcceleration, getEmitAcceleration); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(accelerationSpread, getAccelerationSpread); - - COPY_ENTITY_PROPERTY_TO_PROPERTIES(particleRadius, getParticleRadius); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusSpread, getRadiusSpread); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusStart, getRadiusStart); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusFinish, getRadiusFinish); - - COPY_ENTITY_PROPERTY_TO_PROPERTIES(colorSpread, getColorSpread); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(colorStart, getColorStart); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(colorFinish, getColorFinish); - - COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaSpread, getAlphaSpread); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaStart, getAlphaStart); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaFinish, getAlphaFinish); - - COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitterShouldTrail, getEmitterShouldTrail); - - COPY_ENTITY_PROPERTY_TO_PROPERTIES(particleSpin, getParticleSpin); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(spinSpread, getSpinSpread); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(spinStart, getSpinStart); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(spinFinish, getSpinFinish); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(rotateWithEntity, getRotateWithEntity); +@ParticleEffect_ENTITY_COPY_TO@ return properties; } @@ -699,186 +652,15 @@ EntityItemProperties ParticleEffectEntityItem::getProperties(const EntityPropert bool ParticleEffectEntityItem::setSubClassProperties(const EntityItemProperties& properties) { bool somethingChanged = false; - SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, setShapeType); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha); - withWriteLock([&] { - bool pulsePropertiesChanged = _pulseProperties.setProperties(properties); - somethingChanged |= pulsePropertiesChanged; - _needsRenderUpdate |= pulsePropertiesChanged; - }); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures); - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(maxParticles, setMaxParticles); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifespan, setLifespan); - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(isEmitting, setIsEmitting); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitRate, setEmitRate); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitSpeed, setEmitSpeed); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(speedSpread, setSpeedSpread); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitOrientation, setEmitOrientation); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitDimensions, setEmitDimensions); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitRadiusStart, setEmitRadiusStart); - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(polarStart, setPolarStart); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(polarFinish, setPolarFinish); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(azimuthStart, setAzimuthStart); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(azimuthFinish, setAzimuthFinish); - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitAcceleration, setEmitAcceleration); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(accelerationSpread, setAccelerationSpread); - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(particleRadius, setParticleRadius); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusSpread, setRadiusSpread); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusStart, setRadiusStart); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusFinish, setRadiusFinish); - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(colorSpread, setColorSpread); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(colorStart, setColorStart); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(colorFinish, setColorFinish); - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaSpread, setAlphaSpread); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaStart, setAlphaStart); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaFinish, setAlphaFinish); - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitterShouldTrail, setEmitterShouldTrail); - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(particleSpin, setParticleSpin); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(spinSpread, setSpinSpread); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(spinStart, setSpinStart); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(spinFinish, setSpinFinish); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotateWithEntity, setRotateWithEntity); +@ParticleEffect_ENTITY_SET_FROM@ return somethingChanged; } -void ParticleEffectEntityItem::setColor(const glm::u8vec3& value) { - withWriteLock([&] { - _needsRenderUpdate |= _particleProperties.color.gradient.target != glm::vec3(value); - _particleProperties.color.gradient.target = value; - }); -} - -glm::u8vec3 ParticleEffectEntityItem::getColor() const { - return resultWithReadLock([&] { - return _particleProperties.color.gradient.target; - }); -} - -int ParticleEffectEntityItem::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_SHAPE_TYPE, ShapeType, setShapeType); - READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL); - READ_ENTITY_PROPERTY(PROP_COLOR, u8vec3Color, setColor); - READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha); - withWriteLock([&] { - int bytesFromPulse = _pulseProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, - somethingChanged); - bytesRead += bytesFromPulse; - dataAt += bytesFromPulse; - }); - READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures); - - READ_ENTITY_PROPERTY(PROP_MAX_PARTICLES, quint32, setMaxParticles); - READ_ENTITY_PROPERTY(PROP_LIFESPAN, float, setLifespan); - - READ_ENTITY_PROPERTY(PROP_EMITTING_PARTICLES, bool, setIsEmitting); - READ_ENTITY_PROPERTY(PROP_EMIT_RATE, float, setEmitRate); - READ_ENTITY_PROPERTY(PROP_EMIT_SPEED, float, setEmitSpeed); - READ_ENTITY_PROPERTY(PROP_SPEED_SPREAD, float, setSpeedSpread); - READ_ENTITY_PROPERTY(PROP_EMIT_ORIENTATION, quat, setEmitOrientation); - READ_ENTITY_PROPERTY(PROP_EMIT_DIMENSIONS, glm::vec3, setEmitDimensions); - READ_ENTITY_PROPERTY(PROP_EMIT_RADIUS_START, float, setEmitRadiusStart); - - READ_ENTITY_PROPERTY(PROP_POLAR_START, float, setPolarStart); - READ_ENTITY_PROPERTY(PROP_POLAR_FINISH, float, setPolarFinish); - READ_ENTITY_PROPERTY(PROP_AZIMUTH_START, float, setAzimuthStart); - READ_ENTITY_PROPERTY(PROP_AZIMUTH_FINISH, float, setAzimuthFinish); - - READ_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, glm::vec3, setEmitAcceleration); - READ_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, glm::vec3, setAccelerationSpread); - - READ_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, float, setParticleRadius); - READ_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, float, setRadiusSpread); - READ_ENTITY_PROPERTY(PROP_RADIUS_START, float, setRadiusStart); - READ_ENTITY_PROPERTY(PROP_RADIUS_FINISH, float, setRadiusFinish); - - READ_ENTITY_PROPERTY(PROP_COLOR_SPREAD, u8vec3Color, setColorSpread); - READ_ENTITY_PROPERTY(PROP_COLOR_START, vec3Color, setColorStart); - READ_ENTITY_PROPERTY(PROP_COLOR_FINISH, vec3Color, setColorFinish); - - READ_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, float, setAlphaSpread); - READ_ENTITY_PROPERTY(PROP_ALPHA_START, float, setAlphaStart); - READ_ENTITY_PROPERTY(PROP_ALPHA_FINISH, float, setAlphaFinish); - - READ_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, bool, setEmitterShouldTrail); - - READ_ENTITY_PROPERTY(PROP_PARTICLE_SPIN, float, setParticleSpin); - READ_ENTITY_PROPERTY(PROP_SPIN_SPREAD, float, setSpinSpread); - READ_ENTITY_PROPERTY(PROP_SPIN_START, float, setSpinStart); - READ_ENTITY_PROPERTY(PROP_SPIN_FINISH, float, setSpinFinish); - READ_ENTITY_PROPERTY(PROP_PARTICLE_ROTATE_WITH_ENTITY, bool, setRotateWithEntity); - - return bytesRead; -} - EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); - requestedProperties += PROP_SHAPE_TYPE; - requestedProperties += PROP_COMPOUND_SHAPE_URL; - requestedProperties += PROP_COLOR; - requestedProperties += PROP_ALPHA; - requestedProperties += _pulseProperties.getEntityProperties(params); - requestedProperties += PROP_TEXTURES; - - requestedProperties += PROP_MAX_PARTICLES; - requestedProperties += PROP_LIFESPAN; - - requestedProperties += PROP_EMITTING_PARTICLES; - requestedProperties += PROP_EMIT_RATE; - requestedProperties += PROP_EMIT_SPEED; - requestedProperties += PROP_SPEED_SPREAD; - requestedProperties += PROP_EMIT_ORIENTATION; - requestedProperties += PROP_EMIT_DIMENSIONS; - requestedProperties += PROP_EMIT_RADIUS_START; - - requestedProperties += PROP_POLAR_START; - requestedProperties += PROP_POLAR_FINISH; - requestedProperties += PROP_AZIMUTH_START; - requestedProperties += PROP_AZIMUTH_FINISH; - - requestedProperties += PROP_EMIT_ACCELERATION; - requestedProperties += PROP_ACCELERATION_SPREAD; - - requestedProperties += PROP_PARTICLE_RADIUS; - requestedProperties += PROP_RADIUS_SPREAD; - requestedProperties += PROP_RADIUS_START; - requestedProperties += PROP_RADIUS_FINISH; - - requestedProperties += PROP_COLOR_SPREAD; - requestedProperties += PROP_COLOR_START; - requestedProperties += PROP_COLOR_FINISH; - - requestedProperties += PROP_ALPHA_SPREAD; - requestedProperties += PROP_ALPHA_START; - requestedProperties += PROP_ALPHA_FINISH; - - requestedProperties += PROP_EMITTER_SHOULD_TRAIL; - - requestedProperties += PROP_PARTICLE_SPIN; - requestedProperties += PROP_SPIN_SPREAD; - requestedProperties += PROP_SPIN_START; - requestedProperties += PROP_SPIN_FINISH; - requestedProperties += PROP_PARTICLE_ROTATE_WITH_ENTITY; +@ParticleEffect_REQUESTED_PROPS@ return requestedProperties; } @@ -892,67 +674,47 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData, OctreeElement::AppendState& appendState) const { bool successPropertyFits = true; - APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType()); - APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, getCompoundShapeURL()); - APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor()); - APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha()); - withReadLock([&] { - _pulseProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, - propertyFlags, propertiesDidntFit, propertyCount, appendState); - }); - APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures()); - APPEND_ENTITY_PROPERTY(PROP_MAX_PARTICLES, getMaxParticles()); - APPEND_ENTITY_PROPERTY(PROP_LIFESPAN, getLifespan()); +@ParticleEffect_ENTITY_APPEND@ - APPEND_ENTITY_PROPERTY(PROP_EMITTING_PARTICLES, getIsEmitting()); - APPEND_ENTITY_PROPERTY(PROP_EMIT_RATE, getEmitRate()); - APPEND_ENTITY_PROPERTY(PROP_EMIT_SPEED, getEmitSpeed()); - APPEND_ENTITY_PROPERTY(PROP_SPEED_SPREAD, getSpeedSpread()); - APPEND_ENTITY_PROPERTY(PROP_EMIT_ORIENTATION, getEmitOrientation()); - APPEND_ENTITY_PROPERTY(PROP_EMIT_DIMENSIONS, getEmitDimensions()); - APPEND_ENTITY_PROPERTY(PROP_EMIT_RADIUS_START, getEmitRadiusStart()); +} - APPEND_ENTITY_PROPERTY(PROP_POLAR_START, getPolarStart()); - APPEND_ENTITY_PROPERTY(PROP_POLAR_FINISH, getPolarFinish()); - APPEND_ENTITY_PROPERTY(PROP_AZIMUTH_START, getAzimuthStart()); - APPEND_ENTITY_PROPERTY(PROP_AZIMUTH_FINISH, getAzimuthFinish()); +int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { - APPEND_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, getEmitAcceleration()); - APPEND_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, getAccelerationSpread()); + int bytesRead = 0; + const unsigned char* dataAt = data; - APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, getParticleRadius()); - APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, getRadiusSpread()); - APPEND_ENTITY_PROPERTY(PROP_RADIUS_START, getRadiusStart()); - APPEND_ENTITY_PROPERTY(PROP_RADIUS_FINISH, getRadiusFinish()); +@ParticleEffect_ENTITY_READ@ - APPEND_ENTITY_PROPERTY(PROP_COLOR_SPREAD, getColorSpread()); - APPEND_ENTITY_PROPERTY(PROP_COLOR_START, getColorStart()); - APPEND_ENTITY_PROPERTY(PROP_COLOR_FINISH, getColorFinish()); + return bytesRead; +} - APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, getAlphaSpread()); - APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, getAlphaStart()); - APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, getAlphaFinish()); +void ParticleEffectEntityItem::debugDump() const { + qCDebug(entities) << "ParticleEffectEntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " editedAgo:" << debugTime(getLastEdited(), usecTimestampNow()); + qCDebug(entities) << " pointer:" << this; - APPEND_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, getEmitterShouldTrail()); +@ParticleEffect_ENTITY_DEBUG@ - APPEND_ENTITY_PROPERTY(PROP_PARTICLE_SPIN, getParticleSpin()); - APPEND_ENTITY_PROPERTY(PROP_SPIN_SPREAD, getSpinSpread()); - APPEND_ENTITY_PROPERTY(PROP_SPIN_START, getSpinStart()); - APPEND_ENTITY_PROPERTY(PROP_SPIN_FINISH, getSpinFinish()); - APPEND_ENTITY_PROPERTY(PROP_PARTICLE_ROTATE_WITH_ENTITY, getRotateWithEntity()); } -void ParticleEffectEntityItem::debugDump() const { - quint64 now = usecTimestampNow(); - qCDebug(entities) << "PA EFFECT EntityItem id:" << getEntityItemID() << "---------------------------------------------"; - qCDebug(entities) << " color:" << - _particleProperties.color.gradient.target.r << "," << - _particleProperties.color.gradient.target.g << "," << - _particleProperties.color.gradient.target.b; - qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); - qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); - qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); +void ParticleEffectEntityItem::setColor(const glm::u8vec3& value) { + withWriteLock([&] { + _needsRenderUpdate |= _particleProperties.color.gradient.target != glm::vec3(value); + _particleProperties.color.gradient.target = value; + }); +} + +glm::u8vec3 ParticleEffectEntityItem::getColor() const { + return resultWithReadLock([&] { + return _particleProperties.color.gradient.target; + }); } void ParticleEffectEntityItem::setShapeType(ShapeType type) { @@ -984,26 +746,6 @@ ShapeType ParticleEffectEntityItem::getShapeType() const { }); } -void ParticleEffectEntityItem::setCompoundShapeURL(const QString& compoundShapeURL) { - withWriteLock([&] { - _needsRenderUpdate |= _compoundShapeURL != compoundShapeURL; - _compoundShapeURL = compoundShapeURL; - }); -} - -QString ParticleEffectEntityItem::getCompoundShapeURL() const { - return resultWithReadLock([&] { - return _compoundShapeURL; - }); -} - -void ParticleEffectEntityItem::setIsEmitting(bool isEmitting) { - withWriteLock([&] { - _needsRenderUpdate |= _isEmitting != isEmitting; - _isEmitting = isEmitting; - }); -} - void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) { maxParticles = glm::clamp(maxParticles, MINIMUM_MAX_PARTICLES, MAXIMUM_MAX_PARTICLES); @@ -1078,6 +820,14 @@ void ParticleEffectEntityItem::setEmitterShouldTrail(bool emitterShouldTrail) { }); } +bool ParticleEffectEntityItem::getEmitterShouldTrail() const { + return _particleProperties.emission.shouldTrail; +} + +bool ParticleEffectEntityItem::getRotateWithEntity() const { + return _particleProperties.rotateWithEntity; +} + void ParticleEffectEntityItem::setRotateWithEntity(bool rotateWithEntity) { withWriteLock([&] { _needsRenderUpdate |= _particleProperties.rotateWithEntity != rotateWithEntity; @@ -1086,7 +836,7 @@ void ParticleEffectEntityItem::setRotateWithEntity(bool rotateWithEntity) { } particle::Properties ParticleEffectEntityItem::getParticleProperties() const { - particle::Properties result; + particle::Properties result; withReadLock([&] { result = _particleProperties; }); @@ -1121,7 +871,7 @@ particle::Properties ParticleEffectEntityItem::getParticleProperties() const { qCWarning(entities) << "failed validation"; } - return result; + return result; } PulsePropertyGroup ParticleEffectEntityItem::getPulseProperties() const { diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h.in similarity index 67% rename from libraries/entities/src/ParticleEffectEntityItem.h rename to libraries/entities/src/ParticleEffectEntityItem.h.in index c96323fc9ab..093d0591321 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h.in @@ -175,7 +175,7 @@ namespace particle { bool valid() const; bool emitting() const; uint64_t emitIntervalUsecs() const; - + Properties& operator =(const Properties& other) { color = other.color; alpha = other.alpha; @@ -206,157 +206,30 @@ bool operator!=(const particle::Properties& a, const particle::Properties& b); class ParticleEffectEntityItem : public EntityItem { public: - ALLOW_INSTANTIATION // This class can be instantiated - static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); ParticleEffectEntityItem(const EntityItemID& entityItemID); - // methods for getting/setting all properties of this entity - virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - virtual bool setSubClassProperties(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; + ALLOW_INSTANTIATION // This class can be instantiated + ENTITY_PROPERTY_SUBCLASS_METHODS bool shouldBePhysical() const override { return false; } - virtual void debugDump() const override; - - void setColor(const glm::u8vec3& value); - glm::u8vec3 getColor() const; - - void setColorStart(const vec3& colorStart); - vec3 getColorStart() const; - - void setColorFinish(const vec3& colorFinish); - vec3 getColorFinish() const; - - void setColorSpread(const glm::u8vec3& colorSpread); - glm::u8vec3 getColorSpread() const; - - void setAlpha(float alpha); - float getAlpha() const; - - void setAlphaStart(float alphaStart); - float getAlphaStart() const; - - void setAlphaFinish(float alphaFinish); - float getAlphaFinish() const; - - void setAlphaSpread(float alphaSpread); - float getAlphaSpread() const; - - void setShapeType(ShapeType type) override; - virtual ShapeType getShapeType() const override; - - QString getCompoundShapeURL() const; - virtual void setCompoundShapeURL(const QString& url); - - bool getIsEmitting() const { return _isEmitting; } - void setIsEmitting(bool isEmitting); - - void setMaxParticles(quint32 maxParticles); - quint32 getMaxParticles() const; - - void setLifespan(float lifespan); - float getLifespan() const; - - void setEmitRate(float emitRate); - float getEmitRate() const; - - void setEmitSpeed(float emitSpeed); - float getEmitSpeed() const; - - void setSpeedSpread(float speedSpread); - float getSpeedSpread() const; - - void setEmitOrientation(const glm::quat& emitOrientation); - glm::quat getEmitOrientation() const; - - void setEmitDimensions(const glm::vec3& emitDimensions); - glm::vec3 getEmitDimensions() const; - - void setEmitRadiusStart(float emitRadiusStart); - float getEmitRadiusStart() const; - - void setPolarStart(float polarStart); - float getPolarStart() const; - - void setPolarFinish(float polarFinish); - float getPolarFinish() const; - - void setAzimuthStart(float azimuthStart); - float getAzimuthStart() const; - - void setAzimuthFinish(float azimuthFinish); - float getAzimuthFinish() const; - - void setEmitAcceleration(const glm::vec3& emitAcceleration); - glm::vec3 getEmitAcceleration() const; - - void setAccelerationSpread(const glm::vec3& accelerationSpread); - glm::vec3 getAccelerationSpread() const; - - void setParticleRadius(float particleRadius); - float getParticleRadius() const; - - void setRadiusStart(float radiusStart); - float getRadiusStart() const; - - void setRadiusFinish(float radiusFinish); - float getRadiusFinish() const; - - void setRadiusSpread(float radiusSpread); - float getRadiusSpread() const; - - void setParticleSpin(float particleSpin); - float getParticleSpin() const; - - void setSpinStart(float spinStart); - float getSpinStart() const; - - void setSpinFinish(float spinFinish); - float getSpinFinish() const; - - void setSpinSpread(float spinSpread); - float getSpinSpread() const; - - void setRotateWithEntity(bool rotateWithEntity); - bool getRotateWithEntity() const { return _particleProperties.rotateWithEntity; } - void computeAndUpdateDimensions(); - void setTextures(const QString& textures); - QString getTextures() const; - - void setEmitterShouldTrail(bool emitterShouldTrail); - bool getEmitterShouldTrail() const { return _particleProperties.emission.shouldTrail; } - virtual bool supportsDetailedIntersection() const override { return false; } + ShapeType getShapeType() const override; + void setShapeType(ShapeType type) override; + particle::Properties getParticleProperties() const; PulsePropertyGroup getPulseProperties() const; protected: - particle::Properties _particleProperties; - PulsePropertyGroup _pulseProperties; - bool _isEmitting { true }; - ShapeType _shapeType{ particle::DEFAULT_SHAPE_TYPE }; - QString _compoundShapeURL { "" }; +@ParticleEffect_ENTITY_PROPS@ + + particle::Properties _particleProperties; }; #endif // hifi_ParticleEffectEntityItem_h diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp.in similarity index 59% rename from libraries/entities/src/PolyLineEntityItem.cpp rename to libraries/entities/src/PolyLineEntityItem.cpp.in index 605a171c7ca..b8db81d7dca 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp.in @@ -38,17 +38,8 @@ PolyLineEntityItem::PolyLineEntityItem(const EntityItemID& entityItemID) : Entit EntityItemProperties PolyLineEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class - - COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getColor); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures); - - COPY_ENTITY_PROPERTY_TO_PROPERTIES(linePoints, getLinePoints); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(strokeWidths, getStrokeWidths); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(normals, getNormals); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(strokeColors, getStrokeColors); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(isUVModeStretch, getIsUVModeStretch); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(glow, getGlow); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(faceCamera, getFaceCamera); + +@PolyLine_ENTITY_COPY_TO@ return properties; } @@ -56,23 +47,60 @@ EntityItemProperties PolyLineEntityItem::getProperties(const EntityPropertyFlags bool PolyLineEntityItem::setSubClassProperties(const EntityItemProperties& properties) { bool somethingChanged = false; - SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures); - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(linePoints, setLinePoints); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(strokeWidths, setStrokeWidths); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(normals, setNormals); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(strokeColors, setStrokeColors); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(isUVModeStretch, setIsUVModeStretch); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(glow, setGlow); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(faceCamera, setFaceCamera); +@PolyLine_ENTITY_SET_FROM@ return somethingChanged; } +EntityPropertyFlags PolyLineEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + +@PolyLine_REQUESTED_PROPS@ + + return requestedProperties; +} + +void PolyLineEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@PolyLine_ENTITY_APPEND@ + +} + +int PolyLineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + int bytesRead = 0; + const unsigned char* dataAt = data; + +@PolyLine_ENTITY_READ@ + + return bytesRead; +} + +void PolyLineEntityItem::debugDump() const { + qCDebug(entities) << "PolyLineEntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " editedAgo:" << debugTime(getLastEdited(), usecTimestampNow()); + qCDebug(entities) << " pointer:" << this; + +@PolyLine_ENTITY_DEBUG@ + +} + void PolyLineEntityItem::setLinePoints(const QVector& points) { withWriteLock([&] { - _points = points; + _linePoints = points; _pointsChanged = true; }); computeAndUpdateDimensions(); @@ -80,7 +108,7 @@ void PolyLineEntityItem::setLinePoints(const QVector& points) { void PolyLineEntityItem::setStrokeWidths(const QVector& strokeWidths) { withWriteLock([&] { - _widths = strokeWidths; + _strokeWidths = strokeWidths; _widthsChanged = true; }); computeAndUpdateDimensions(); @@ -95,7 +123,7 @@ void PolyLineEntityItem::setNormals(const QVector& normals) { void PolyLineEntityItem::setStrokeColors(const QVector& strokeColors) { withWriteLock([&] { - _colors = strokeColors; + _strokeColors = strokeColors; _colorsChanged = true; }); } @@ -105,8 +133,8 @@ void PolyLineEntityItem::computeAndUpdateDimensions() { QVector widths; withReadLock([&] { - points = _points; - widths = _widths; + points = _linePoints; + widths = _strokeWidths; }); glm::vec3 maxHalfDim(0.5f * ENTITY_ITEM_DEFAULT_WIDTH); @@ -123,8 +151,8 @@ void PolyLineEntityItem::computeTightLocalBoundingBox(AABox& localBox) const { QVector points; QVector widths; withReadLock([&] { - points = _points; - widths = _widths; + points = _linePoints; + widths = _strokeWidths; }); if (points.size() > 0) { @@ -145,76 +173,9 @@ void PolyLineEntityItem::computeTightLocalBoundingBox(AABox& localBox) const { } } -int PolyLineEntityItem::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_COLOR, glm::u8vec3, setColor); - READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures); - - READ_ENTITY_PROPERTY(PROP_LINE_POINTS, QVector, setLinePoints); - READ_ENTITY_PROPERTY(PROP_STROKE_WIDTHS, QVector, setStrokeWidths); - READ_ENTITY_PROPERTY(PROP_STROKE_NORMALS, QVector, setNormals); - READ_ENTITY_PROPERTY(PROP_STROKE_COLORS, QVector, setStrokeColors); - READ_ENTITY_PROPERTY(PROP_IS_UV_MODE_STRETCH, bool, setIsUVModeStretch); - READ_ENTITY_PROPERTY(PROP_LINE_GLOW, bool, setGlow); - READ_ENTITY_PROPERTY(PROP_LINE_FACE_CAMERA, bool, setFaceCamera); - - return bytesRead; -} - -EntityPropertyFlags PolyLineEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { - EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); - requestedProperties += PROP_COLOR; - requestedProperties += PROP_TEXTURES; - - requestedProperties += PROP_LINE_POINTS; - requestedProperties += PROP_STROKE_WIDTHS; - requestedProperties += PROP_STROKE_NORMALS; - requestedProperties += PROP_STROKE_COLORS; - requestedProperties += PROP_IS_UV_MODE_STRETCH; - requestedProperties += PROP_LINE_GLOW; - requestedProperties += PROP_LINE_FACE_CAMERA; - return requestedProperties; -} - -void PolyLineEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const { - - bool successPropertyFits = true; - - APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor()); - APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures()); - - APPEND_ENTITY_PROPERTY(PROP_LINE_POINTS, getLinePoints()); - APPEND_ENTITY_PROPERTY(PROP_STROKE_WIDTHS, getStrokeWidths()); - APPEND_ENTITY_PROPERTY(PROP_STROKE_NORMALS, getNormals()); - APPEND_ENTITY_PROPERTY(PROP_STROKE_COLORS, getStrokeColors()); - APPEND_ENTITY_PROPERTY(PROP_IS_UV_MODE_STRETCH, getIsUVModeStretch()); - APPEND_ENTITY_PROPERTY(PROP_LINE_GLOW, getGlow()); - APPEND_ENTITY_PROPERTY(PROP_LINE_FACE_CAMERA, getFaceCamera()); -} - -void PolyLineEntityItem::debugDump() const { - quint64 now = usecTimestampNow(); - qCDebug(entities) << " QUAD EntityItem id:" << getEntityItemID() << "---------------------------------------------"; - qCDebug(entities) << " color:" << _color; - qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); - qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); - qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); -} - QVector PolyLineEntityItem::getLinePoints() const { return resultWithReadLock>([&] { - return _points; + return _linePoints; }); } @@ -226,17 +187,17 @@ QVector PolyLineEntityItem::getNormals() const { QVector PolyLineEntityItem::getStrokeColors() const { return resultWithReadLock>([&] { - return _colors; + return _strokeColors; }); } -QVector PolyLineEntityItem::getStrokeWidths() const { +QVector PolyLineEntityItem::getStrokeWidths() const { return resultWithReadLock>([&] { - return _widths; + return _strokeWidths; }); } -QString PolyLineEntityItem::getTextures() const { +QString PolyLineEntityItem::getTextures() const { return resultWithReadLock([&] { return _textures; }); @@ -263,24 +224,3 @@ glm::u8vec3 PolyLineEntityItem::getColor() const { return _color; }); } - -void PolyLineEntityItem::setIsUVModeStretch(bool isUVModeStretch) { - withWriteLock([&] { - _needsRenderUpdate |= _isUVModeStretch != isUVModeStretch; - _isUVModeStretch = isUVModeStretch; - }); -} - -void PolyLineEntityItem::setGlow(bool glow) { - withWriteLock([&] { - _needsRenderUpdate |= _glow != glow; - _glow = glow; - }); -} - -void PolyLineEntityItem::setFaceCamera(bool faceCamera) { - withWriteLock([&] { - _needsRenderUpdate |= _faceCamera != faceCamera; - _faceCamera = faceCamera; - }); -} diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h.in similarity index 50% rename from libraries/entities/src/PolyLineEntityItem.h rename to libraries/entities/src/PolyLineEntityItem.h.in index 4f3810b9006..dd1fa87e1f1 100644 --- a/libraries/entities/src/PolyLineEntityItem.h +++ b/libraries/entities/src/PolyLineEntityItem.h.in @@ -23,56 +23,12 @@ class PolyLineEntityItem : public EntityItem { PolyLineEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated - - // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - virtual bool setSubClassProperties(const EntityItemProperties& properties) override; - - virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; - - virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, - 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; - - glm::u8vec3 getColor() const; - void setColor(const glm::u8vec3& value); + ENTITY_PROPERTY_SUBCLASS_METHODS static const int MAX_POINTS_PER_LINE; - void setLinePoints(const QVector& points); - QVector getLinePoints() const; - static const float DEFAULT_LINE_WIDTH; - void setStrokeWidths(const QVector& strokeWidths); - QVector getStrokeWidths() const; - - void setNormals(const QVector& normals); - QVector getNormals() const; - void setStrokeColors(const QVector& strokeColors); - QVector getStrokeColors() const; - - void setIsUVModeStretch(bool isUVModeStretch); - bool getIsUVModeStretch() const{ return _isUVModeStretch; } - - QString getTextures() const; - void setTextures(const QString& textures); - - void setGlow(bool glow); - bool getGlow() const { return _glow; } - - void setFaceCamera(bool faceCamera); - bool getFaceCamera() const { return _faceCamera; } - - bool pointsChanged() const { return _pointsChanged; } + bool pointsChanged() const { return _pointsChanged; } bool normalsChanged() const { return _normalsChanged; } bool colorsChanged() const { return _colorsChanged; } bool widthsChanged() const { return _widthsChanged; } @@ -93,21 +49,12 @@ class PolyLineEntityItem : public EntityItem { QVariantMap& extraInfo, bool precisionPicking) const override { return false; } void computeTightLocalBoundingBox(AABox& box) const; - - virtual void debugDump() const override; private: void computeAndUpdateDimensions(); - protected: - glm::u8vec3 _color; - QVector _points; - QVector _normals; - QVector _colors; - QVector _widths; - QString _textures; - bool _isUVModeStretch { false }; - bool _glow { false }; - bool _faceCamera { false }; +protected: + +@PolyLine_ENTITY_PROPS@ bool _pointsChanged { false }; bool _normalsChanged { false }; diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp.in similarity index 61% rename from libraries/entities/src/PolyVoxEntityItem.cpp rename to libraries/entities/src/PolyVoxEntityItem.cpp.in index dcbcd72d1f1..d35111d35c0 100644 --- a/libraries/entities/src/PolyVoxEntityItem.cpp +++ b/libraries/entities/src/PolyVoxEntityItem.cpp.in @@ -80,28 +80,16 @@ void PolyVoxEntityItem::setVoxelVolumeSize(const glm::vec3& voxelVolumeSize_) { } glm::vec3 PolyVoxEntityItem::getVoxelVolumeSize() const { - glm::vec3 voxelVolumeSize; - withReadLock([&] { - voxelVolumeSize = _voxelVolumeSize; + return resultWithReadLock([&] { + return _voxelVolumeSize; }); - return voxelVolumeSize; } EntityItemProperties PolyVoxEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class - COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelVolumeSize, getVoxelVolumeSize); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelData, getVoxelData); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelSurfaceStyle, getVoxelSurfaceStyle); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(xTextureURL, getXTextureURL); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(yTextureURL, getYTextureURL); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(zTextureURL, getZTextureURL); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(xNNeighborID, getXNNeighborID); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(yNNeighborID, getYNNeighborID); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(zNNeighborID, getZNNeighborID); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(xPNeighborID, getXPNeighborID); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(yPNeighborID, getYPNeighborID); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(zPNeighborID, getZPNeighborID); + +@PolyVox_ENTITY_COPY_TO@ return properties; } @@ -109,152 +97,81 @@ EntityItemProperties PolyVoxEntityItem::getProperties(const EntityPropertyFlags& bool PolyVoxEntityItem::setSubClassProperties(const EntityItemProperties& properties) { bool somethingChanged = false; - SET_ENTITY_PROPERTY_FROM_PROPERTIES(voxelVolumeSize, setVoxelVolumeSize); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(voxelData, setVoxelData); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(voxelSurfaceStyle, setVoxelSurfaceStyle); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(xTextureURL, setXTextureURL); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(yTextureURL, setYTextureURL); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(zTextureURL, setZTextureURL); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(xNNeighborID, setXNNeighborID); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(yNNeighborID, setYNNeighborID); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(zNNeighborID, setZNNeighborID); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(xPNeighborID, setXPNeighborID); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(yPNeighborID, setYPNeighborID); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(zPNeighborID, setZPNeighborID); +@PolyVox_ENTITY_SET_FROM@ return somethingChanged; } -int PolyVoxEntityItem::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_VOXEL_VOLUME_SIZE, glm::vec3, setVoxelVolumeSize); - READ_ENTITY_PROPERTY(PROP_VOXEL_DATA, QByteArray, setVoxelData); - READ_ENTITY_PROPERTY(PROP_VOXEL_SURFACE_STYLE, uint16_t, setVoxelSurfaceStyle); - READ_ENTITY_PROPERTY(PROP_X_TEXTURE_URL, QString, setXTextureURL); - READ_ENTITY_PROPERTY(PROP_Y_TEXTURE_URL, QString, setYTextureURL); - READ_ENTITY_PROPERTY(PROP_Z_TEXTURE_URL, QString, setZTextureURL); - READ_ENTITY_PROPERTY(PROP_X_N_NEIGHBOR_ID, EntityItemID, setXNNeighborID); - READ_ENTITY_PROPERTY(PROP_Y_N_NEIGHBOR_ID, EntityItemID, setYNNeighborID); - READ_ENTITY_PROPERTY(PROP_Z_N_NEIGHBOR_ID, EntityItemID, setZNNeighborID); - READ_ENTITY_PROPERTY(PROP_X_P_NEIGHBOR_ID, EntityItemID, setXPNeighborID); - READ_ENTITY_PROPERTY(PROP_Y_P_NEIGHBOR_ID, EntityItemID, setYPNeighborID); - READ_ENTITY_PROPERTY(PROP_Z_P_NEIGHBOR_ID, EntityItemID, setZPNeighborID); - - return bytesRead; -} - EntityPropertyFlags PolyVoxEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); - requestedProperties += PROP_VOXEL_VOLUME_SIZE; - requestedProperties += PROP_VOXEL_DATA; - requestedProperties += PROP_VOXEL_SURFACE_STYLE; - requestedProperties += PROP_X_TEXTURE_URL; - requestedProperties += PROP_Y_TEXTURE_URL; - requestedProperties += PROP_Z_TEXTURE_URL; - requestedProperties += PROP_X_N_NEIGHBOR_ID; - requestedProperties += PROP_Y_N_NEIGHBOR_ID; - requestedProperties += PROP_Z_N_NEIGHBOR_ID; - requestedProperties += PROP_X_P_NEIGHBOR_ID; - requestedProperties += PROP_Y_P_NEIGHBOR_ID; - requestedProperties += PROP_Z_P_NEIGHBOR_ID; + +@PolyVox_REQUESTED_PROPS@ + return requestedProperties; } void PolyVoxEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, EntityPropertyFlags& requestedProperties, EntityPropertyFlags& propertyFlags, EntityPropertyFlags& propertiesDidntFit, int& propertyCount, OctreeElement::AppendState& appendState) const { + bool successPropertyFits = true; - APPEND_ENTITY_PROPERTY(PROP_VOXEL_VOLUME_SIZE, getVoxelVolumeSize()); - APPEND_ENTITY_PROPERTY(PROP_VOXEL_DATA, getVoxelData()); - APPEND_ENTITY_PROPERTY(PROP_VOXEL_SURFACE_STYLE, (uint16_t) getVoxelSurfaceStyle()); - APPEND_ENTITY_PROPERTY(PROP_X_TEXTURE_URL, getXTextureURL()); - APPEND_ENTITY_PROPERTY(PROP_Y_TEXTURE_URL, getYTextureURL()); - APPEND_ENTITY_PROPERTY(PROP_Z_TEXTURE_URL, getZTextureURL()); - APPEND_ENTITY_PROPERTY(PROP_X_N_NEIGHBOR_ID, getXNNeighborID()); - APPEND_ENTITY_PROPERTY(PROP_Y_N_NEIGHBOR_ID, getYNNeighborID()); - APPEND_ENTITY_PROPERTY(PROP_Z_N_NEIGHBOR_ID, getZNNeighborID()); - APPEND_ENTITY_PROPERTY(PROP_X_P_NEIGHBOR_ID, getXPNeighborID()); - APPEND_ENTITY_PROPERTY(PROP_Y_P_NEIGHBOR_ID, getYPNeighborID()); - APPEND_ENTITY_PROPERTY(PROP_Z_P_NEIGHBOR_ID, getZPNeighborID()); -} +@PolyVox_ENTITY_APPEND@ -void PolyVoxEntityItem::debugDump() const { - quint64 now = usecTimestampNow(); - qCDebug(entities) << " POLYVOX EntityItem id:" << getEntityItemID() << "---------------------------------------------"; - qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); - qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); - qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); } -void PolyVoxEntityItem::setVoxelData(const QByteArray& voxelData) { - withWriteLock([&] { - _voxelData = voxelData; - _voxelDataDirty = true; - }); -} +int PolyVoxEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { -QByteArray PolyVoxEntityItem::getVoxelData() const { - QByteArray voxelDataCopy; - withReadLock([&] { - voxelDataCopy = _voxelData; - }); - return voxelDataCopy; -} + int bytesRead = 0; + const unsigned char* dataAt = data; +@PolyVox_ENTITY_READ@ -void PolyVoxEntityItem::setXTextureURL(const QString& xTextureURL) { - withWriteLock([&] { - _needsRenderUpdate |= _xTextureURL != xTextureURL; - _xTextureURL = xTextureURL; - }); + return bytesRead; } -QString PolyVoxEntityItem::getXTextureURL() const { - QString result; - withReadLock([&] { - result = _xTextureURL; - }); - return result; +void PolyVoxEntityItem::debugDump() const { + qCDebug(entities) << "PolyVoxEntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " editedAgo:" << debugTime(getLastEdited(), usecTimestampNow()); + qCDebug(entities) << " pointer:" << this; + +@PolyVox_ENTITY_DEBUG@ + } -void PolyVoxEntityItem::setYTextureURL(const QString& yTextureURL) { +void PolyVoxEntityItem::setVoxelData(const QByteArray& voxelData) { withWriteLock([&] { - _needsRenderUpdate |= _yTextureURL != yTextureURL; - _yTextureURL = yTextureURL; + _voxelData = voxelData; + _voxelDataDirty = true; }); } -QString PolyVoxEntityItem::getYTextureURL() const { - QString result; - withReadLock([&] { - result = _yTextureURL; +QByteArray PolyVoxEntityItem::getVoxelData() const { + return resultWithReadLock([&] { + return _voxelData; }); - return result; } -void PolyVoxEntityItem::setZTextureURL(const QString& zTextureURL) { +void PolyVoxEntityItem::setVoxelSurfaceStyle(uint16_t voxelSurfaceStyle) { withWriteLock([&] { - _needsRenderUpdate |= _zTextureURL != zTextureURL; - _zTextureURL = zTextureURL; + _voxelSurfaceStyle = voxelSurfaceStyle; }); } -QString PolyVoxEntityItem::getZTextureURL() const { - QString result; - withReadLock([&] { - result = _zTextureURL; + +uint16_t PolyVoxEntityItem::getVoxelSurfaceStyle() const { + return resultWithReadLock([&] { + return _voxelSurfaceStyle; }); - return result; } void PolyVoxEntityItem::setXNNeighborID(const EntityItemID& xNNeighborID) { @@ -264,11 +181,9 @@ void PolyVoxEntityItem::setXNNeighborID(const EntityItemID& xNNeighborID) { } EntityItemID PolyVoxEntityItem::getXNNeighborID() const { - EntityItemID result; - withReadLock([&] { - result = _xNNeighborID; + return resultWithReadLock([&] { + return _xNNeighborID; }); - return result; } void PolyVoxEntityItem::setYNNeighborID(const EntityItemID& yNNeighborID) { @@ -278,11 +193,9 @@ void PolyVoxEntityItem::setYNNeighborID(const EntityItemID& yNNeighborID) { } EntityItemID PolyVoxEntityItem::getYNNeighborID() const { - EntityItemID result; - withReadLock([&] { - result = _yNNeighborID; + return resultWithReadLock([&] { + return _yNNeighborID; }); - return result; } void PolyVoxEntityItem::setZNNeighborID(const EntityItemID& zNNeighborID) { @@ -292,11 +205,9 @@ void PolyVoxEntityItem::setZNNeighborID(const EntityItemID& zNNeighborID) { } EntityItemID PolyVoxEntityItem::getZNNeighborID() const { - EntityItemID result; - withReadLock([&] { - result = _zNNeighborID; + return resultWithReadLock([&] { + return _zNNeighborID; }); - return result; } void PolyVoxEntityItem::setXPNeighborID(const EntityItemID& xPNeighborID) { @@ -306,11 +217,9 @@ void PolyVoxEntityItem::setXPNeighborID(const EntityItemID& xPNeighborID) { } EntityItemID PolyVoxEntityItem::getXPNeighborID() const { - EntityItemID result; - withReadLock([&] { - result = _xPNeighborID; + return resultWithReadLock([&] { + return _xPNeighborID; }); - return result; } void PolyVoxEntityItem::setYPNeighborID(const EntityItemID& yPNeighborID) { @@ -320,11 +229,9 @@ void PolyVoxEntityItem::setYPNeighborID(const EntityItemID& yPNeighborID) { } EntityItemID PolyVoxEntityItem::getYPNeighborID() const { - EntityItemID result; - withReadLock([&] { - result = _yPNeighborID; + return resultWithReadLock([&] { + return _yPNeighborID; }); - return result; } void PolyVoxEntityItem::setZPNeighborID(const EntityItemID& zPNeighborID) { @@ -334,11 +241,9 @@ void PolyVoxEntityItem::setZPNeighborID(const EntityItemID& zPNeighborID) { } EntityItemID PolyVoxEntityItem::getZPNeighborID() const { - EntityItemID result; - withReadLock([&] { - result = _zPNeighborID; + return resultWithReadLock([&] { + return _zPNeighborID; }); - return result; } glm::vec3 PolyVoxEntityItem::getSurfacePositionAdjustment() const { @@ -429,7 +334,7 @@ ShapeType PolyVoxEntityItem::getShapeType() const { } bool PolyVoxEntityItem::isEdged() const { - return isEdged(_voxelSurfaceStyle); + return isEdged((PolyVoxSurfaceStyle)_voxelSurfaceStyle); } std::array PolyVoxEntityItem::getNNeigborIDs() const { diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h.in similarity index 51% rename from libraries/entities/src/PolyVoxEntityItem.h rename to libraries/entities/src/PolyVoxEntityItem.h.in index 163e03cd55a..15bfceaec2d 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h.in @@ -15,31 +15,13 @@ #include "EntityItem.h" class PolyVoxEntityItem : public EntityItem { - public: +public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); PolyVoxEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated - - // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - virtual bool setSubClassProperties(const EntityItemProperties& properties) override; - - virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; - - virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, - 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; + ENTITY_PROPERTY_SUBCLASS_METHODS // never have a ray intersection pick a PolyVoxEntityItem. virtual bool supportsDetailedIntersection() const override { return true; } @@ -52,48 +34,35 @@ class PolyVoxEntityItem : public EntityItem { float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const override { return false; } - virtual void debugDump() const override; - - virtual void setVoxelVolumeSize(const glm::vec3& voxelVolumeSize); - virtual glm::vec3 getVoxelVolumeSize() const; - - virtual void setVoxelData(const QByteArray& voxelData); - virtual QByteArray getVoxelData() const; - virtual int getOnCount() const { return 0; } /*@jsdoc - *

The surface of a {@link Entities.EntityProperties-PolyVox|PolyVox} entity may be one of the following styles:

- * - * - * - * - * - * - * - * - * - * - *
ValueTypeDescription
0Marching cubes.Chamfered edges. Open volume. - * Joins neighboring PolyVox entities reasonably well.
1Cubic.Square edges. Open volume. - * Joins neighboring PolyVox entities cleanly.
2Edged cubic.Square edges. Enclosed volume. - * Joins neighboring PolyVox entities cleanly.
3Edged marching cubes.Chamfered edges. Enclosed volume. - * Doesn't join neighboring PolyVox entities.
- * @typedef {number} Entities.PolyVoxSurfaceStyle - */ + *

The surface of a {@link Entities.EntityProperties-PolyVox|PolyVox} entity may be one of the following styles:

+ * + * + * + * + * + * + * + * + * + * + *
ValueTypeDescription
0Marching cubes.Chamfered edges. Open volume. + * Joins neighboring PolyVox entities reasonably well.
1Cubic.Square edges. Open volume. + * Joins neighboring PolyVox entities cleanly.
2Edged cubic.Square edges. Enclosed volume. + * Joins neighboring PolyVox entities cleanly.
3Edged marching cubes.Chamfered edges. Enclosed volume. + * Doesn't join neighboring PolyVox entities.
+ * @typedef {number} Entities.PolyVoxSurfaceStyle + */ enum PolyVoxSurfaceStyle { SURFACE_MARCHING_CUBES, SURFACE_CUBIC, SURFACE_EDGED_CUBIC, SURFACE_EDGED_MARCHING_CUBES }; - static bool isEdged(PolyVoxSurfaceStyle surfaceStyle); - - virtual void setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxelSurfaceStyle) { _voxelSurfaceStyle = voxelSurfaceStyle; } - // this other version of setVoxelSurfaceStyle is needed for SET_ENTITY_PROPERTY_FROM_PROPERTIES - void setVoxelSurfaceStyle(uint16_t voxelSurfaceStyle) { setVoxelSurfaceStyle((PolyVoxSurfaceStyle) voxelSurfaceStyle); } - virtual PolyVoxSurfaceStyle getVoxelSurfaceStyle() const { return _voxelSurfaceStyle; } + static bool isEdged(PolyVoxSurfaceStyle surfaceStyle); static const glm::vec3 DEFAULT_VOXEL_VOLUME_SIZE; static const float MAX_VOXEL_DIMENSION; @@ -101,6 +70,26 @@ class PolyVoxEntityItem : public EntityItem { static const QByteArray DEFAULT_VOXEL_DATA; static const PolyVoxSurfaceStyle DEFAULT_VOXEL_SURFACE_STYLE; + QByteArray getVoxelData() const; + virtual void setVoxelData(const QByteArray& voxelData); + glm::vec3 getVoxelVolumeSize() const; + virtual void setVoxelVolumeSize(const glm::vec3& voxelVolumeSize); + uint16_t getVoxelSurfaceStyle() const; + virtual void setVoxelSurfaceStyle(uint16_t voxelSurfaceStyle); + + EntityItemID getXNNeighborID() const; + virtual void setXNNeighborID(const EntityItemID& value); + EntityItemID getYNNeighborID() const; + virtual void setYNNeighborID(const EntityItemID& value); + EntityItemID getZNNeighborID() const; + virtual void setZNNeighborID(const EntityItemID& value); + EntityItemID getXPNeighborID() const; + virtual void setXPNeighborID(const EntityItemID& value); + EntityItemID getYPNeighborID() const; + virtual void setYPNeighborID(const EntityItemID& value); + EntityItemID getZPNeighborID() const; + virtual void setZPNeighborID(const EntityItemID& value); + glm::vec3 voxelCoordsToWorldCoords(const glm::vec3& voxelCoords) const; glm::vec3 worldCoordsToVoxelCoords(const glm::vec3& worldCoords) const; glm::vec3 voxelCoordsToLocalCoords(const glm::vec3& voxelCoords) const; @@ -125,40 +114,10 @@ class PolyVoxEntityItem : public EntityItem { static QByteArray makeEmptyVoxelData(quint16 voxelXSize = 16, quint16 voxelYSize = 16, quint16 voxelZSize = 16); static const QString DEFAULT_X_TEXTURE_URL; - void setXTextureURL(const QString& xTextureURL); - QString getXTextureURL() const; - static const QString DEFAULT_Y_TEXTURE_URL; - void setYTextureURL(const QString& yTextureURL); - QString getYTextureURL() const; - static const QString DEFAULT_Z_TEXTURE_URL; - void setZTextureURL(const QString& zTextureURL); - QString getZTextureURL() const; - - virtual void setXNNeighborID(const EntityItemID& xNNeighborID); - void setXNNeighborID(const QString& xNNeighborID); - EntityItemID getXNNeighborID() const; - virtual void setYNNeighborID(const EntityItemID& yNNeighborID); - void setYNNeighborID(const QString& yNNeighborID); - EntityItemID getYNNeighborID() const; - virtual void setZNNeighborID(const EntityItemID& zNNeighborID); - void setZNNeighborID(const QString& zNNeighborID); - EntityItemID getZNNeighborID() const; std::array getNNeigborIDs() const; - - - virtual void setXPNeighborID(const EntityItemID& xPNeighborID); - void setXPNeighborID(const QString& xPNeighborID); - EntityItemID getXPNeighborID() const; - virtual void setYPNeighborID(const EntityItemID& yPNeighborID); - void setYPNeighborID(const QString& yPNeighborID); - EntityItemID getYPNeighborID() const; - virtual void setZPNeighborID(const EntityItemID& zPNeighborID); - void setZPNeighborID(const QString& zPNeighborID); - EntityItemID getZPNeighborID() const; - std::array getPNeigborIDs() const; glm::vec3 getSurfacePositionAdjustment() const; @@ -173,27 +132,11 @@ class PolyVoxEntityItem : public EntityItem { glm::mat4 localToVoxelMatrix() const; protected: - void setVoxelDataDirty(bool value) { withWriteLock([&] { _voxelDataDirty = value; }); } - glm::vec3 _voxelVolumeSize { DEFAULT_VOXEL_VOLUME_SIZE }; // this is always 3 bytes +@PolyVox_ENTITY_PROPS@ - QByteArray _voxelData { DEFAULT_VOXEL_DATA }; + void setVoxelDataDirty(bool value) { withWriteLock([&] { _voxelDataDirty = value; }); } bool _voxelDataDirty { true }; // _voxelData has changed, things that depend on it should be updated - - PolyVoxSurfaceStyle _voxelSurfaceStyle { DEFAULT_VOXEL_SURFACE_STYLE }; - - QString _xTextureURL { DEFAULT_X_TEXTURE_URL }; - QString _yTextureURL { DEFAULT_Y_TEXTURE_URL }; - QString _zTextureURL { DEFAULT_Z_TEXTURE_URL }; - - // for non-edged surface styles, these are used to compute the high-axis edges - EntityItemID _xNNeighborID{UNKNOWN_ENTITY_ID}; - EntityItemID _yNNeighborID{UNKNOWN_ENTITY_ID}; - EntityItemID _zNNeighborID{UNKNOWN_ENTITY_ID}; - - EntityItemID _xPNeighborID{UNKNOWN_ENTITY_ID}; - EntityItemID _yPNeighborID{UNKNOWN_ENTITY_ID}; - EntityItemID _zPNeighborID{UNKNOWN_ENTITY_ID}; }; #endif // hifi_PolyVoxEntityItem_h diff --git a/libraries/entities/src/ProceduralParticleEffectEntityItem.cpp.in b/libraries/entities/src/ProceduralParticleEffectEntityItem.cpp.in new file mode 100644 index 00000000000..d6bbbf4b685 --- /dev/null +++ b/libraries/entities/src/ProceduralParticleEffectEntityItem.cpp.in @@ -0,0 +1,93 @@ +// +// ProceduralParticleEffectEntityItem.cpp +// libraries/entities/src +// +// Created by HifiExperiements on 11/19/23 +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ProceduralParticleEffectEntityItem.h" + +#include "EntityTree.h" +#include "EntityTreeElement.h" +#include "EntitiesLogging.h" +#include "EntityScriptingInterface.h" + +EntityItemPointer ProceduralParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + std::shared_ptr entity(new ProceduralParticleEffectEntityItem(entityID), [](ProceduralParticleEffectEntityItem* ptr) { ptr->deleteLater(); }); + entity->setProperties(properties); + return entity; +} + +// our non-pure virtual subclass for now... +ProceduralParticleEffectEntityItem::ProceduralParticleEffectEntityItem(const EntityItemID& entityItemID) : + EntityItem(entityItemID) +{ + _type = EntityTypes::ProceduralParticleEffect; +} + +EntityItemProperties ProceduralParticleEffectEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class + +@ProceduralParticleEffect_ENTITY_COPY_TO@ + + return properties; +} + +bool ProceduralParticleEffectEntityItem::setSubClassProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + +@ProceduralParticleEffect_ENTITY_SET_FROM@ + + return somethingChanged; +} + +EntityPropertyFlags ProceduralParticleEffectEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + +@ProceduralParticleEffect_REQUESTED_PROPS@ + + return requestedProperties; +} + +void ProceduralParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@ProceduralParticleEffect_ENTITY_APPEND@ + +} + +int ProceduralParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + +@ProceduralParticleEffect_ENTITY_READ@ + + return bytesRead; +} + +void ProceduralParticleEffectEntityItem::debugDump() const { + qCDebug(entities) << "ProceduralParticleEffectEntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " editedAgo:" << debugTime(getLastEdited(), usecTimestampNow()); + qCDebug(entities) << " pointer:" << this; + +@ProceduralParticleEffect_ENTITY_DEBUG@ + +} diff --git a/libraries/entities/src/ProceduralParticleEffectEntityItem.h.in b/libraries/entities/src/ProceduralParticleEffectEntityItem.h.in new file mode 100644 index 00000000000..996bc832334 --- /dev/null +++ b/libraries/entities/src/ProceduralParticleEffectEntityItem.h.in @@ -0,0 +1,47 @@ +// +// ProceduralParticleEffectEntityItem.h +// libraries/entities/src +// +// Created by HifiExperiements on 11/19/23 +// Copyright 2023 Overte e.V. +// +// 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_ProceduralParticleEffectEntityItem_h +#define hifi_ProceduralParticleEffectEntityItem_h + +#include "EntityItem.h" + +namespace particle { + static const uint32_t DEFAULT_NUM_PROCEDURAL_PARTICLES = 10000; + static const uint32_t MAXIMUM_NUM_PROCEDURAL_PARTICLES = 1024 * 1024; + static const uint8_t DEFAULT_NUM_TRIS_PER = 1; + static const uint8_t MINIMUM_TRIS_PER = 1; + static const uint8_t MAXIMUM_TRIS_PER = 15; + static const uint8_t DEFAULT_NUM_UPDATE_PROPS = 0; + static const uint8_t MINIMUM_NUM_UPDATE_PROPS = 0; + static const uint8_t MAXIMUM_NUM_UPDATE_PROPS = 5; +} + +class ProceduralParticleEffectEntityItem : public EntityItem { +public: + static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); + + ProceduralParticleEffectEntityItem(const EntityItemID& entityItemID);\ + + ALLOW_INSTANTIATION // This class can be instantiated + ENTITY_PROPERTY_SUBCLASS_METHODS + + bool shouldBePhysical() const override { return false; } + + virtual bool supportsDetailedIntersection() const override { return false; } + +protected: + +@ProceduralParticleEffect_ENTITY_PROPS@ + +}; + +#endif // hifi_ProceduralParticleEffectEntityItem_h diff --git a/libraries/entities/src/PropertyGroup.h b/libraries/entities/src/PropertyGroup.h index b73c2dad2a0..57f6ef567cf 100644 --- a/libraries/entities/src/PropertyGroup.h +++ b/libraries/entities/src/PropertyGroup.h @@ -59,14 +59,6 @@ class PropertyGroup { virtual bool setProperties(const EntityItemProperties& properties) = 0; virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const = 0; - - virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const = 0; virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, diff --git a/libraries/entities/src/PulsePropertyGroup.cpp b/libraries/entities/src/PulsePropertyGroup.cpp deleted file mode 100644 index ab61a1f8ad9..00000000000 --- a/libraries/entities/src/PulsePropertyGroup.cpp +++ /dev/null @@ -1,252 +0,0 @@ -// -// PulsePropertyGroup.cpp -// -// Created by Sam Gondelman on 1/15/19 -// Copyright 2019 High Fidelity, Inc. -// Copyright 2023 Overte e.V. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// SPDX-License-Identifier: Apache-2.0 -// - -#include "PulsePropertyGroup.h" - -#include - -#include "EntityItemProperties.h" -#include "EntityItemPropertiesMacros.h" - -QHash stringToPulseModeLookup; - -void addPulseMode(PulseMode mode) { - stringToPulseModeLookup[PulseModeHelpers::getNameForPulseMode(mode)] = mode; -} - -void buildStringToPulseModeLookup() { - addPulseMode(PulseMode::NONE); - addPulseMode(PulseMode::IN_PHASE); - addPulseMode(PulseMode::OUT_PHASE); -} - -QString PulsePropertyGroup::getColorModeAsString() const { - return PulseModeHelpers::getNameForPulseMode(_colorMode); -} - -void PulsePropertyGroup::setColorModeFromString(const QString& pulseMode) { - if (stringToPulseModeLookup.empty()) { - buildStringToPulseModeLookup(); - } - auto pulseModeItr = stringToPulseModeLookup.find(pulseMode.toLower()); - if (pulseModeItr != stringToPulseModeLookup.end()) { - _colorMode = pulseModeItr.value(); - _colorModeChanged = true; - } -} - -QString PulsePropertyGroup::getAlphaModeAsString() const { - return PulseModeHelpers::getNameForPulseMode(_alphaMode); -} - -void PulsePropertyGroup::setAlphaModeFromString(const QString& pulseMode) { - if (stringToPulseModeLookup.empty()) { - buildStringToPulseModeLookup(); - } - auto pulseModeItr = stringToPulseModeLookup.find(pulseMode.toLower()); - if (pulseModeItr != stringToPulseModeLookup.end()) { - _alphaMode = pulseModeItr.value(); - _alphaModeChanged = true; - } -} - -void PulsePropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, - ScriptEngine* engine, bool skipDefaults, - EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, - bool isMyOwnAvatarEntity) const { - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_PULSE_MIN, Pulse, pulse, Min, min); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_PULSE_MAX, Pulse, pulse, Max, max); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_PULSE_PERIOD, Pulse, pulse, Period, period); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_PULSE_COLOR_MODE, Pulse, pulse, ColorMode, colorMode, getColorModeAsString); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_PULSE_ALPHA_MODE, Pulse, pulse, AlphaMode, alphaMode, getAlphaModeAsString); -} - -void PulsePropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) { - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(pulse, min, float, setMin); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(pulse, max, float, setMax); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(pulse, period, float, setPeriod); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_ENUM(pulse, colorMode, ColorMode); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_ENUM(pulse, alphaMode, AlphaMode); -} - -void PulsePropertyGroup::merge(const PulsePropertyGroup& other) { - COPY_PROPERTY_IF_CHANGED(min); - COPY_PROPERTY_IF_CHANGED(max); - COPY_PROPERTY_IF_CHANGED(period); - COPY_PROPERTY_IF_CHANGED(colorMode); - COPY_PROPERTY_IF_CHANGED(alphaMode); -} - -void PulsePropertyGroup::debugDump() const { - qCDebug(entities) << " PulsePropertyGroup: ---------------------------------------------"; - qCDebug(entities) << " _min:" << _min; - qCDebug(entities) << " _max:" << _max; - qCDebug(entities) << " _period:" << _period; - qCDebug(entities) << " _colorMode:" << getColorModeAsString(); - qCDebug(entities) << " _alphaMode:" << getAlphaModeAsString(); -} - -void PulsePropertyGroup::listChangedProperties(QList& out) { - if (minChanged()) { - out << "pulse-min"; - } - if (maxChanged()) { - out << "pulse-max"; - } - if (periodChanged()) { - out << "pulse-period"; - } - if (colorModeChanged()) { - out << "pulse-colorMode"; - } - if (alphaModeChanged()) { - out << "pulse-alphaMode"; - } -} - -bool PulsePropertyGroup::appendToEditPacket(OctreePacketData* packetData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const { - - bool successPropertyFits = true; - - APPEND_ENTITY_PROPERTY(PROP_PULSE_MIN, getMin()); - APPEND_ENTITY_PROPERTY(PROP_PULSE_MAX, getMax()); - APPEND_ENTITY_PROPERTY(PROP_PULSE_PERIOD, getPeriod()); - APPEND_ENTITY_PROPERTY(PROP_PULSE_COLOR_MODE, (uint32_t)getColorMode()); - APPEND_ENTITY_PROPERTY(PROP_PULSE_ALPHA_MODE, (uint32_t)getAlphaMode()); - - return true; -} - -bool PulsePropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, - const unsigned char*& dataAt , int& processedBytes) { - - int bytesRead = 0; - bool overwriteLocalData = true; - bool somethingChanged = false; - - READ_ENTITY_PROPERTY(PROP_PULSE_MIN, float, setMin); - READ_ENTITY_PROPERTY(PROP_PULSE_MAX, float, setMax); - READ_ENTITY_PROPERTY(PROP_PULSE_PERIOD, float, setPeriod); - READ_ENTITY_PROPERTY(PROP_PULSE_COLOR_MODE, PulseMode, setColorMode); - READ_ENTITY_PROPERTY(PROP_PULSE_ALPHA_MODE, PulseMode, setAlphaMode); - - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_PULSE_MIN, Min); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_PULSE_MAX, Max); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_PULSE_PERIOD, Period); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_PULSE_COLOR_MODE, ColorMode); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_PULSE_ALPHA_MODE, AlphaMode); - - processedBytes += bytesRead; - - Q_UNUSED(somethingChanged); - - return true; -} - -void PulsePropertyGroup::markAllChanged() { - _minChanged = true; - _maxChanged = true; - _periodChanged = true; - _colorModeChanged = true; - _alphaModeChanged = true; -} - -EntityPropertyFlags PulsePropertyGroup::getChangedProperties() const { - EntityPropertyFlags changedProperties; - - CHECK_PROPERTY_CHANGE(PROP_PULSE_MIN, min); - CHECK_PROPERTY_CHANGE(PROP_PULSE_MAX, max); - CHECK_PROPERTY_CHANGE(PROP_PULSE_PERIOD, period); - CHECK_PROPERTY_CHANGE(PROP_PULSE_COLOR_MODE, colorMode); - CHECK_PROPERTY_CHANGE(PROP_PULSE_ALPHA_MODE, alphaMode); - - return changedProperties; -} - -void PulsePropertyGroup::getProperties(EntityItemProperties& properties) const { - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Pulse, Min, getMin); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Pulse, Max, getMax); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Pulse, Period, getPeriod); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Pulse, ColorMode, getColorMode); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Pulse, AlphaMode, getAlphaMode); -} - -bool PulsePropertyGroup::setProperties(const EntityItemProperties& properties) { - bool somethingChanged = false; - - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Pulse, Min, min, setMin); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Pulse, Max, max, setMax); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Pulse, Period, period, setPeriod); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Pulse, ColorMode, colorMode, setColorMode); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Pulse, AlphaMode, alphaMode, setAlphaMode); - - return somethingChanged; -} - -EntityPropertyFlags PulsePropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { - EntityPropertyFlags requestedProperties; - - requestedProperties += PROP_PULSE_MIN; - requestedProperties += PROP_PULSE_MAX; - requestedProperties += PROP_PULSE_PERIOD; - requestedProperties += PROP_PULSE_COLOR_MODE; - requestedProperties += PROP_PULSE_ALPHA_MODE; - - return requestedProperties; -} - -void PulsePropertyGroup::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_PULSE_MIN, getMin()); - APPEND_ENTITY_PROPERTY(PROP_PULSE_MAX, getMax()); - APPEND_ENTITY_PROPERTY(PROP_PULSE_PERIOD, getPeriod()); - APPEND_ENTITY_PROPERTY(PROP_PULSE_COLOR_MODE, (uint32_t)getColorMode()); - APPEND_ENTITY_PROPERTY(PROP_PULSE_ALPHA_MODE, (uint32_t)getAlphaMode()); -} - -int PulsePropertyGroup::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_PULSE_MIN, float, setMin); - READ_ENTITY_PROPERTY(PROP_PULSE_MAX, float, setMax); - READ_ENTITY_PROPERTY(PROP_PULSE_PERIOD, float, setPeriod); - READ_ENTITY_PROPERTY(PROP_PULSE_COLOR_MODE, PulseMode, setColorMode); - READ_ENTITY_PROPERTY(PROP_PULSE_ALPHA_MODE, PulseMode, setAlphaMode); - - return bytesRead; -} - -bool PulsePropertyGroup::operator==(const PulsePropertyGroup& a) const { - return (a._min == _min) && - (a._max == _max) && - (a._period == _period) && - (a._colorMode == _colorMode) && - (a._alphaMode == _alphaMode); -} \ No newline at end of file diff --git a/libraries/entities/src/PulsePropertyGroup.cpp.in b/libraries/entities/src/PulsePropertyGroup.cpp.in new file mode 100644 index 00000000000..ddd4cb71d0a --- /dev/null +++ b/libraries/entities/src/PulsePropertyGroup.cpp.in @@ -0,0 +1,183 @@ +// +// PulsePropertyGroup.cpp +// +// Created by Sam Gondelman on 1/15/19 +// Copyright 2019 High Fidelity, Inc. +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#include "PulsePropertyGroup.h" + +#include + +#include "EntityItemProperties.h" + +QHash stringToPulseModeLookup; + +void addPulseMode(PulseMode mode) { + stringToPulseModeLookup[PulseModeHelpers::getNameForPulseMode(mode)] = mode; +} + +void buildStringToPulseModeLookup() { + addPulseMode(PulseMode::NONE); + addPulseMode(PulseMode::IN_PHASE); + addPulseMode(PulseMode::OUT_PHASE); +} + +QString PulsePropertyGroup::getColorModeAsString() const { + return PulseModeHelpers::getNameForPulseMode(_colorMode); +} + +void PulsePropertyGroup::setColorModeFromString(const QString& pulseMode) { + if (stringToPulseModeLookup.empty()) { + buildStringToPulseModeLookup(); + } + auto pulseModeItr = stringToPulseModeLookup.find(pulseMode.toLower()); + if (pulseModeItr != stringToPulseModeLookup.end()) { + _colorMode = pulseModeItr.value(); + _colorModeChanged = true; + } +} + +QString PulsePropertyGroup::getAlphaModeAsString() const { + return PulseModeHelpers::getNameForPulseMode(_alphaMode); +} + +void PulsePropertyGroup::setAlphaModeFromString(const QString& pulseMode) { + if (stringToPulseModeLookup.empty()) { + buildStringToPulseModeLookup(); + } + auto pulseModeItr = stringToPulseModeLookup.find(pulseMode.toLower()); + if (pulseModeItr != stringToPulseModeLookup.end()) { + _alphaMode = pulseModeItr.value(); + _alphaModeChanged = true; + } +} + +void PulsePropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, + bool skipDefaults, EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, bool isMyOwnAvatarEntity) const { + +@Pulse_GROUP_COPY_TO_SCRIPT@ + +} + +void PulsePropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) { + +@Pulse_GROUP_COPY_FROM_SCRIPT@ + +} + +void PulsePropertyGroup::merge(const PulsePropertyGroup& other) { + +@Pulse_GROUP_MERGE@ + +} + +void PulsePropertyGroup::debugDump() const { + +@Pulse_GROUP_DEBUG_DUMP@ + +} + +void PulsePropertyGroup::listChangedProperties(QList& out) { + +@Pulse_GROUP_LIST_CHANGED@ + +} + +bool PulsePropertyGroup::appendToEditPacket(OctreePacketData* packetData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@Pulse_GROUP_APPEND@ + + return successPropertyFits; +} + +bool PulsePropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) { + + int bytesRead = 0; + bool overwriteLocalData = true; + bool somethingChanged = false; + +@Pulse_GROUP_READ@ + +@Pulse_GROUP_DECODE_CHANGED@ + + processedBytes += bytesRead; + + return somethingChanged; +} + +void PulsePropertyGroup::markAllChanged() { + +@Pulse_GROUP_MARK_CHANGED@ + +} + +EntityPropertyFlags PulsePropertyGroup::getChangedProperties() const { + EntityPropertyFlags changedProperties; + +@Pulse_GROUP_CHANGED_PROPERTIES@ + + return changedProperties; +} + +void PulsePropertyGroup::getProperties(EntityItemProperties& properties) const { + +@Pulse_GROUP_COPY_TO@ + +} + +bool PulsePropertyGroup::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + +@Pulse_GROUP_SET_FROM@ + + return somethingChanged; +} + +EntityPropertyFlags PulsePropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties; + +@Pulse_REQUESTED_PROPS@ + + return requestedProperties; +} + +int PulsePropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + +@Pulse_GROUP_READ@ + + return bytesRead; +} + +void PulsePropertyGroup::addPropertyMap(QHash& _propertyInfos, + QHash& _enumsToPropertyStrings) { + +@Pulse_GROUP_ADD_TO_MAP@ + +} + +bool PulsePropertyGroup::operator==(const PulsePropertyGroup& a) const { + return (a._min == _min) && + (a._max == _max) && + (a._period == _period) && + (a._colorMode == _colorMode) && + (a._alphaMode == _alphaMode); +} diff --git a/libraries/entities/src/PulsePropertyGroup.h b/libraries/entities/src/PulsePropertyGroup.h deleted file mode 100644 index 649005b970a..00000000000 --- a/libraries/entities/src/PulsePropertyGroup.h +++ /dev/null @@ -1,100 +0,0 @@ -// -// PulsePropertyGroup.h -// -// Created by Sam Gondelman on 1/15/19 -// Copyright 2019 High Fidelity, Inc. -// Copyright 2023 Overte e.V. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// SPDX-License-Identifier: Apache-2.0 -// - -#ifndef hifi_PulsePropertyGroup_h -#define hifi_PulsePropertyGroup_h - -#include - -#include - -#include "PropertyGroup.h" -#include "EntityItemPropertiesMacros.h" - -class EntityItemProperties; -class EncodeBitstreamParams; -class OctreePacketData; -class ReadBitstreamToTreeParams; -class ScriptEngine; -class ScriptValue; - -/*@jsdoc - * A color and alpha pulse that an entity may have. - * @typedef {object} Entities.Pulse - * @property {number} min=0 - The minimum value of the pulse multiplier. - * @property {number} max=1 - The maximum value of the pulse multiplier. - * @property {number} period=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from - * min to max, then max to min in one period. - * @property {Entities.PulseMode} colorMode="none" - If "in", the color is pulsed in phase with the pulse period; if "out" - * the color is pulsed out of phase with the pulse period. - * @property {Entities.PulseMode} alphaMode="none" - If "in", the alpha is pulsed in phase with the pulse period; if "out" - * the alpha is pulsed out of phase with the pulse period. - */ -class PulsePropertyGroup : public PropertyGroup { -public: - // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, - ScriptEngine* engine, bool skipDefaults, - EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, - bool isMyOwnAvatarEntity) const override; - virtual void copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) override; - - void merge(const PulsePropertyGroup& other); - - virtual void debugDump() const override; - virtual void listChangedProperties(QList& 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; - - bool operator==(const PulsePropertyGroup& a) const; - bool operator!=(const PulsePropertyGroup& a) const { return !(*this == a); } - - DEFINE_PROPERTY(PROP_PULSE_MIN, Min, min, float, 0.0f); - DEFINE_PROPERTY(PROP_PULSE_MAX, Max, max, float, 1.0f); - DEFINE_PROPERTY(PROP_PULSE_PERIOD, Period, period, float, 1.0f); - DEFINE_PROPERTY_REF_ENUM(PROP_PULSE_COLOR_MODE, ColorMode, colorMode, PulseMode, PulseMode::NONE); - DEFINE_PROPERTY_REF_ENUM(PROP_PULSE_ALPHA_MODE, AlphaMode, alphaMode, PulseMode, PulseMode::NONE); -}; - -#endif // hifi_PulsePropertyGroup_h diff --git a/libraries/entities/src/PulsePropertyGroup.h.in b/libraries/entities/src/PulsePropertyGroup.h.in new file mode 100644 index 00000000000..59fc84143f5 --- /dev/null +++ b/libraries/entities/src/PulsePropertyGroup.h.in @@ -0,0 +1,55 @@ +// +// PulsePropertyGroup.h +// +// Created by Sam Gondelman on 1/15/19 +// Copyright 2019 High Fidelity, Inc. +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef hifi_PulsePropertyGroup_h +#define hifi_PulsePropertyGroup_h + +#include + +#include + +#include "PropertyGroup.h" +#include "EntityItemPropertiesMacros.h" + +class EntityItemProperties; +class EncodeBitstreamParams; +class OctreePacketData; +class ReadBitstreamToTreeParams; +class ScriptEngine; +class ScriptValue; + +/*@jsdoc + * A color and alpha pulse that an entity may have. + * @typedef {object} Entities.Pulse + * @property {number} min=0 - The minimum value of the pulse multiplier. + * @property {number} max=1 - The maximum value of the pulse multiplier. + * @property {number} period=1 - The duration of the color and alpha pulse, in seconds. A pulse multiplier value goes from + * min to max, then max to min in one period. + * @property {Entities.PulseMode} colorMode="none" - If "in", the color is pulsed in phase with the pulse period; if "out" + * the color is pulsed out of phase with the pulse period. + * @property {Entities.PulseMode} alphaMode="none" - If "in", the alpha is pulsed in phase with the pulse period; if "out" + * the alpha is pulsed out of phase with the pulse period. + */ +class PulsePropertyGroup : public PropertyGroup { +public: + ENTITY_PROPERTY_GROUP_METHODS(PulsePropertyGroup) + + bool operator==(const PulsePropertyGroup& a) const; + bool operator!=(const PulsePropertyGroup& a) const { return !(*this == a); } + +protected: + +@Pulse_GROUP_PROPS@ + +}; + +#endif // hifi_PulsePropertyGroup_h diff --git a/libraries/entities/src/RingGizmoPropertyGroup.cpp b/libraries/entities/src/RingGizmoPropertyGroup.cpp deleted file mode 100644 index 68021f44a28..00000000000 --- a/libraries/entities/src/RingGizmoPropertyGroup.cpp +++ /dev/null @@ -1,492 +0,0 @@ -// -// Created by Sam Gondelman on 1/22/19 -// Copyright 2019 High Fidelity, Inc. -// Copyright 2023 Overte e.V. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// SPDX-License-Identifier: Apache-2.0 -// - -#include "RingGizmoPropertyGroup.h" - -#include - -#include "EntityItemProperties.h" -#include "EntityItemPropertiesMacros.h" - -const float RingGizmoPropertyGroup::MIN_ANGLE = 0.0f; -const float RingGizmoPropertyGroup::MAX_ANGLE = 360.0f; -const float RingGizmoPropertyGroup::MIN_ALPHA = 0.0f; -const float RingGizmoPropertyGroup::MAX_ALPHA = 1.0f; -const float RingGizmoPropertyGroup::MIN_RADIUS = 0.0f; -const float RingGizmoPropertyGroup::MAX_RADIUS = 0.5f; - -void RingGizmoPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, - ScriptEngine* engine, bool skipDefaults, - EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, - bool isMyOwnAvatarEntity) const { - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_START_ANGLE, Ring, ring, StartAngle, startAngle); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_END_ANGLE, Ring, ring, EndAngle, endAngle); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_INNER_RADIUS, Ring, ring, InnerRadius, innerRadius); - - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_INNER_START_COLOR, Ring, ring, InnerStartColor, innerStartColor, u8vec3Color); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_INNER_END_COLOR, Ring, ring, InnerEndColor, innerEndColor, u8vec3Color); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_OUTER_START_COLOR, Ring, ring, OuterStartColor, outerStartColor, u8vec3Color); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_OUTER_END_COLOR, Ring, ring, OuterEndColor, outerEndColor, u8vec3Color); - - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_INNER_START_ALPHA, Ring, ring, InnerStartAlpha, innerStartAlpha); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_INNER_END_ALPHA, Ring, ring, InnerEndAlpha, innerEndAlpha); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_OUTER_START_ALPHA, Ring, ring, OuterStartAlpha, outerStartAlpha); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_OUTER_END_ALPHA, Ring, ring, OuterEndAlpha, outerEndAlpha); - - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_HAS_TICK_MARKS, Ring, ring, HasTickMarks, hasTickMarks); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_MAJOR_TICK_MARKS_ANGLE, Ring, ring, MajorTickMarksAngle, majorTickMarksAngle); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_MINOR_TICK_MARKS_ANGLE, Ring, ring, MinorTickMarksAngle, minorTickMarksAngle); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_MAJOR_TICK_MARKS_LENGTH, Ring, ring, MajorTickMarksLength, majorTickMarksLength); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_MINOR_TICK_MARKS_LENGTH, Ring, ring, MinorTickMarksLength, minorTickMarksLength); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_MAJOR_TICK_MARKS_COLOR, Ring, ring, MajorTickMarksColor, majorTickMarksColor, u8vec3Color); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_MINOR_TICK_MARKS_COLOR, Ring, ring, MinorTickMarksColor, minorTickMarksColor, u8vec3Color); -} - -void RingGizmoPropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) { - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, startAngle, float, setStartAngle); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, endAngle, float, setEndAngle); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, innerRadius, float, setInnerRadius); - - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, innerStartColor, u8vec3Color, setInnerStartColor); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, innerEndColor, u8vec3Color, setInnerEndColor); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, outerStartColor, u8vec3Color, setOuterStartColor); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, outerEndColor, u8vec3Color, setOuterEndColor); - - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, innerStartAlpha, float, setInnerStartAlpha); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, innerEndAlpha, float, setInnerEndAlpha); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, outerStartAlpha, float, setOuterStartAlpha); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, outerEndAlpha, float, setOuterEndAlpha); - - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, hasTickMarks, bool, setHasTickMarks); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, majorTickMarksAngle, float, setMajorTickMarksAngle); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, minorTickMarksAngle, float, setMinorTickMarksAngle); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, majorTickMarksLength, float, setMajorTickMarksLength); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, minorTickMarksLength, float, setMinorTickMarksLength); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, majorTickMarksColor, u8vec3Color, setMajorTickMarksColor); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(ring, minorTickMarksColor, u8vec3Color, setMinorTickMarksColor); -} - -void RingGizmoPropertyGroup::merge(const RingGizmoPropertyGroup& other) { - COPY_PROPERTY_IF_CHANGED(startAngle); - COPY_PROPERTY_IF_CHANGED(endAngle); - COPY_PROPERTY_IF_CHANGED(innerRadius); - - COPY_PROPERTY_IF_CHANGED(innerStartColor); - COPY_PROPERTY_IF_CHANGED(innerEndColor); - COPY_PROPERTY_IF_CHANGED(outerStartColor); - COPY_PROPERTY_IF_CHANGED(outerEndColor); - - COPY_PROPERTY_IF_CHANGED(innerStartAlpha); - COPY_PROPERTY_IF_CHANGED(innerEndAlpha); - COPY_PROPERTY_IF_CHANGED(outerStartAlpha); - COPY_PROPERTY_IF_CHANGED(outerEndAlpha); - - COPY_PROPERTY_IF_CHANGED(hasTickMarks); - COPY_PROPERTY_IF_CHANGED(majorTickMarksAngle); - COPY_PROPERTY_IF_CHANGED(minorTickMarksAngle); - COPY_PROPERTY_IF_CHANGED(majorTickMarksLength); - COPY_PROPERTY_IF_CHANGED(minorTickMarksLength); - COPY_PROPERTY_IF_CHANGED(majorTickMarksColor); - COPY_PROPERTY_IF_CHANGED(minorTickMarksColor); -} - -void RingGizmoPropertyGroup::debugDump() const { - qCDebug(entities) << " RingGizmoPropertyGroup: ---------------------------------------------"; - qCDebug(entities) << " _startAngle:" << _startAngle; - qCDebug(entities) << " _endAngle:" << _endAngle; - qCDebug(entities) << " _innerRadius:" << _innerRadius; - qCDebug(entities) << " _innerStartColor:" << _innerStartColor; - qCDebug(entities) << " _innerEndColor:" << _innerEndColor; - qCDebug(entities) << " _outerStartColor:" << _outerStartColor; - qCDebug(entities) << " _outerEndColor:" << _outerEndColor; - qCDebug(entities) << " _innerStartAlpha:" << _innerStartAlpha; - qCDebug(entities) << " _innerEndAlpha:" << _innerEndAlpha; - qCDebug(entities) << " _outerStartAlpha:" << _outerStartAlpha; - qCDebug(entities) << " _outerEndAlpha:" << _outerEndAlpha; - qCDebug(entities) << " _hasTickMarks:" << _hasTickMarks; - qCDebug(entities) << " _majorTickMarksAngle:" << _majorTickMarksAngle; - qCDebug(entities) << " _minorTickMarksAngle:" << _minorTickMarksAngle; - qCDebug(entities) << " _majorTickMarksLength:" << _majorTickMarksLength; - qCDebug(entities) << " _minorTickMarksLength:" << _minorTickMarksLength; - qCDebug(entities) << " _majorTickMarksColor:" << _majorTickMarksColor; - qCDebug(entities) << " _minorTickMarksColor:" << _minorTickMarksColor; -} - -void RingGizmoPropertyGroup::listChangedProperties(QList& out) { - if (startAngleChanged()) { - out << "ring-startAngle"; - } - if (endAngleChanged()) { - out << "ring-endAngle"; - } - if (innerRadiusChanged()) { - out << "ring-innerRadius"; - } - - if (innerStartColorChanged()) { - out << "ring-innerStartColor"; - } - if (innerEndColorChanged()) { - out << "ring-innerEndColor"; - } - if (outerStartColorChanged()) { - out << "ring-outerStartColor"; - } - if (outerEndColorChanged()) { - out << "ring-outerEndColor"; - } - - if (innerStartAlphaChanged()) { - out << "ring-innerStartAlpha"; - } - if (innerEndAlphaChanged()) { - out << "ring-innerEndAlpha"; - } - if (outerStartAlphaChanged()) { - out << "ring-outerStartAlpha"; - } - if (outerEndAlphaChanged()) { - out << "ring-outerEndAlpha"; - } - - if (hasTickMarksChanged()) { - out << "ring-hasTickMarks"; - } - if (majorTickMarksAngleChanged()) { - out << "ring-majorTickMarksAngle"; - } - if (minorTickMarksAngleChanged()) { - out << "ring-minorTickMarksAngle"; - } - if (majorTickMarksLengthChanged()) { - out << "ring-majorTickMarksLength"; - } - if (minorTickMarksLengthChanged()) { - out << "ring-minorTickMarksLength"; - } - if (majorTickMarksColorChanged()) { - out << "ring-majorTickMarksColor"; - } - if (minorTickMarksColorChanged()) { - out << "ring-minorTickMarksColor"; - } -} - -bool RingGizmoPropertyGroup::appendToEditPacket(OctreePacketData* packetData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const { - - bool successPropertyFits = true; - - APPEND_ENTITY_PROPERTY(PROP_START_ANGLE, getStartAngle()); - APPEND_ENTITY_PROPERTY(PROP_END_ANGLE, getEndAngle()); - APPEND_ENTITY_PROPERTY(PROP_INNER_RADIUS, getInnerRadius()); - - APPEND_ENTITY_PROPERTY(PROP_INNER_START_COLOR, getInnerStartColor()); - APPEND_ENTITY_PROPERTY(PROP_INNER_END_COLOR, getInnerEndColor()); - APPEND_ENTITY_PROPERTY(PROP_OUTER_START_COLOR, getOuterStartColor()); - APPEND_ENTITY_PROPERTY(PROP_OUTER_END_COLOR, getOuterEndColor()); - - APPEND_ENTITY_PROPERTY(PROP_INNER_START_ALPHA, getInnerStartAlpha()); - APPEND_ENTITY_PROPERTY(PROP_INNER_END_ALPHA, getInnerEndAlpha()); - APPEND_ENTITY_PROPERTY(PROP_OUTER_START_ALPHA, getOuterStartAlpha()); - APPEND_ENTITY_PROPERTY(PROP_OUTER_END_ALPHA, getOuterEndAlpha()); - - APPEND_ENTITY_PROPERTY(PROP_HAS_TICK_MARKS, getHasTickMarks()); - APPEND_ENTITY_PROPERTY(PROP_MAJOR_TICK_MARKS_ANGLE, getMajorTickMarksAngle()); - APPEND_ENTITY_PROPERTY(PROP_MINOR_TICK_MARKS_ANGLE, getMinorTickMarksAngle()); - APPEND_ENTITY_PROPERTY(PROP_MAJOR_TICK_MARKS_LENGTH, getMajorTickMarksLength()); - APPEND_ENTITY_PROPERTY(PROP_MINOR_TICK_MARKS_LENGTH, getMinorTickMarksLength()); - APPEND_ENTITY_PROPERTY(PROP_MAJOR_TICK_MARKS_COLOR, getMajorTickMarksColor()); - APPEND_ENTITY_PROPERTY(PROP_MINOR_TICK_MARKS_COLOR, getMinorTickMarksColor()); - - return true; -} - -bool RingGizmoPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, - const unsigned char*& dataAt , int& processedBytes) { - - int bytesRead = 0; - bool overwriteLocalData = true; - bool somethingChanged = false; - - READ_ENTITY_PROPERTY(PROP_START_ANGLE, float, setStartAngle); - READ_ENTITY_PROPERTY(PROP_END_ANGLE, float, setEndAngle); - READ_ENTITY_PROPERTY(PROP_INNER_RADIUS, float, setInnerRadius); - - READ_ENTITY_PROPERTY(PROP_INNER_START_COLOR, u8vec3Color, setInnerStartColor); - READ_ENTITY_PROPERTY(PROP_INNER_END_COLOR, u8vec3Color, setInnerEndColor); - READ_ENTITY_PROPERTY(PROP_OUTER_START_COLOR, u8vec3Color, setOuterStartColor); - READ_ENTITY_PROPERTY(PROP_OUTER_END_COLOR, u8vec3Color, setOuterEndColor); - - READ_ENTITY_PROPERTY(PROP_INNER_START_ALPHA, float, setInnerStartAlpha); - READ_ENTITY_PROPERTY(PROP_INNER_END_ALPHA, float, setInnerEndAlpha); - READ_ENTITY_PROPERTY(PROP_OUTER_START_ALPHA, float, setOuterStartAlpha); - READ_ENTITY_PROPERTY(PROP_OUTER_END_ALPHA, float, setOuterEndAlpha); - - READ_ENTITY_PROPERTY(PROP_HAS_TICK_MARKS, bool, setHasTickMarks); - READ_ENTITY_PROPERTY(PROP_MAJOR_TICK_MARKS_ANGLE, float, setMajorTickMarksAngle); - READ_ENTITY_PROPERTY(PROP_MINOR_TICK_MARKS_ANGLE, float, setMinorTickMarksAngle); - READ_ENTITY_PROPERTY(PROP_MAJOR_TICK_MARKS_LENGTH, float, setMajorTickMarksLength); - READ_ENTITY_PROPERTY(PROP_MINOR_TICK_MARKS_LENGTH, float, setMinorTickMarksLength); - READ_ENTITY_PROPERTY(PROP_MAJOR_TICK_MARKS_COLOR, u8vec3Color, setMajorTickMarksColor); - READ_ENTITY_PROPERTY(PROP_MINOR_TICK_MARKS_COLOR, u8vec3Color, setMinorTickMarksColor); - - - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_START_ANGLE, StartAngle); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_END_ANGLE, EndAngle); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_INNER_RADIUS, InnerRadius); - - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_INNER_START_COLOR, InnerStartColor); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_INNER_END_COLOR, InnerEndColor); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_OUTER_START_COLOR, OuterStartColor); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_OUTER_END_COLOR, OuterEndColor); - - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_INNER_START_ALPHA, InnerStartAlpha); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_INNER_END_ALPHA, InnerEndAlpha); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_OUTER_START_ALPHA, OuterStartAlpha); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_OUTER_END_ALPHA, OuterEndAlpha); - - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_HAS_TICK_MARKS, HasTickMarks); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_MAJOR_TICK_MARKS_ANGLE, MajorTickMarksAngle); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_MINOR_TICK_MARKS_ANGLE, MinorTickMarksAngle); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_MAJOR_TICK_MARKS_LENGTH, MajorTickMarksLength); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_MINOR_TICK_MARKS_LENGTH, MinorTickMarksLength); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_MAJOR_TICK_MARKS_COLOR, MajorTickMarksColor); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_MINOR_TICK_MARKS_COLOR, MinorTickMarksColor); - - processedBytes += bytesRead; - - Q_UNUSED(somethingChanged); - - return true; -} - -void RingGizmoPropertyGroup::markAllChanged() { - _startAngleChanged = true; - _endAngleChanged = true; - _innerRadiusChanged = true; - - _innerStartColorChanged = true; - _innerEndColorChanged = true; - _outerStartColorChanged = true; - _outerEndColorChanged = true; - - _innerStartAlphaChanged = true; - _innerEndAlphaChanged = true; - _outerStartAlphaChanged = true; - _outerEndAlphaChanged = true; - - _hasTickMarksChanged = true; - _majorTickMarksAngleChanged = true; - _minorTickMarksAngleChanged = true; - _majorTickMarksLengthChanged = true; - _minorTickMarksLengthChanged = true; - _majorTickMarksColorChanged = true; - _minorTickMarksColorChanged = true; -} - -EntityPropertyFlags RingGizmoPropertyGroup::getChangedProperties() const { - EntityPropertyFlags changedProperties; - - CHECK_PROPERTY_CHANGE(PROP_START_ANGLE, startAngle); - CHECK_PROPERTY_CHANGE(PROP_END_ANGLE, endAngle); - CHECK_PROPERTY_CHANGE(PROP_INNER_RADIUS, innerRadius); - - CHECK_PROPERTY_CHANGE(PROP_INNER_START_COLOR, innerStartColor); - CHECK_PROPERTY_CHANGE(PROP_INNER_END_COLOR, innerEndColor); - CHECK_PROPERTY_CHANGE(PROP_OUTER_START_COLOR, outerStartColor); - CHECK_PROPERTY_CHANGE(PROP_OUTER_END_COLOR, outerEndColor); - - CHECK_PROPERTY_CHANGE(PROP_INNER_START_ALPHA, innerStartAlpha); - CHECK_PROPERTY_CHANGE(PROP_INNER_END_ALPHA, innerEndAlpha); - CHECK_PROPERTY_CHANGE(PROP_OUTER_START_ALPHA, outerStartAlpha); - CHECK_PROPERTY_CHANGE(PROP_OUTER_END_ALPHA, outerEndAlpha); - - CHECK_PROPERTY_CHANGE(PROP_HAS_TICK_MARKS, hasTickMarks); - CHECK_PROPERTY_CHANGE(PROP_MAJOR_TICK_MARKS_ANGLE, majorTickMarksAngle); - CHECK_PROPERTY_CHANGE(PROP_MINOR_TICK_MARKS_ANGLE, minorTickMarksAngle); - CHECK_PROPERTY_CHANGE(PROP_MAJOR_TICK_MARKS_LENGTH, majorTickMarksLength); - CHECK_PROPERTY_CHANGE(PROP_MINOR_TICK_MARKS_LENGTH, minorTickMarksLength); - CHECK_PROPERTY_CHANGE(PROP_MAJOR_TICK_MARKS_COLOR, majorTickMarksColor); - CHECK_PROPERTY_CHANGE(PROP_MINOR_TICK_MARKS_COLOR, minorTickMarksColor); - - return changedProperties; -} - -void RingGizmoPropertyGroup::getProperties(EntityItemProperties& properties) const { - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Ring, StartAngle, getStartAngle); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Ring, EndAngle, getEndAngle); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Ring, InnerRadius, getInnerRadius); - - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Ring, InnerStartColor, getInnerStartColor); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Ring, InnerEndColor, getInnerEndColor); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Ring, OuterStartColor, getOuterStartColor); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Ring, OuterEndColor, getOuterEndColor); - - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Ring, InnerStartAlpha, getInnerStartAlpha); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Ring, InnerEndAlpha, getInnerEndAlpha); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Ring, OuterStartAlpha, getOuterStartAlpha); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Ring, OuterEndAlpha, getOuterEndAlpha); - - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Ring, HasTickMarks, getHasTickMarks); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Ring, MajorTickMarksAngle, getMajorTickMarksAngle); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Ring, MinorTickMarksAngle, getMinorTickMarksAngle); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Ring, MajorTickMarksLength, getMajorTickMarksLength); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Ring, MinorTickMarksLength, getMinorTickMarksLength); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Ring, MajorTickMarksColor, getMajorTickMarksColor); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Ring, MinorTickMarksColor, getMinorTickMarksColor); -} - -bool RingGizmoPropertyGroup::setProperties(const EntityItemProperties& properties) { - bool somethingChanged = false; - - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Ring, StartAngle, startAngle, setStartAngle); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Ring, EndAngle, endAngle, setEndAngle); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Ring, InnerRadius, innerRadius, setInnerRadius); - - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Ring, InnerStartColor, innerStartColor, setInnerStartColor); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Ring, InnerEndColor, innerEndColor, setInnerEndColor); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Ring, OuterStartColor, outerStartColor, setOuterStartColor); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Ring, OuterEndColor, outerEndColor, setOuterEndColor); - - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Ring, InnerStartAlpha, innerStartAlpha, setInnerStartAlpha); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Ring, InnerEndAlpha, innerEndAlpha, setInnerEndAlpha); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Ring, OuterStartAlpha, outerStartAlpha, setOuterStartAlpha); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Ring, OuterEndAlpha, outerEndAlpha, setOuterEndAlpha); - - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Ring, HasTickMarks, hasTickMarks, setHasTickMarks); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Ring, MajorTickMarksAngle, majorTickMarksAngle, setMajorTickMarksAngle); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Ring, MinorTickMarksAngle, minorTickMarksAngle, setMinorTickMarksAngle); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Ring, MajorTickMarksLength, majorTickMarksLength, setMajorTickMarksLength); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Ring, MinorTickMarksLength, minorTickMarksLength, setMinorTickMarksLength); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Ring, MajorTickMarksColor, majorTickMarksColor, setMajorTickMarksColor); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Ring, MinorTickMarksColor, minorTickMarksColor, setMinorTickMarksColor); - - return somethingChanged; -} - -EntityPropertyFlags RingGizmoPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { - EntityPropertyFlags requestedProperties; - - requestedProperties += PROP_START_ANGLE; - requestedProperties += PROP_END_ANGLE; - requestedProperties += PROP_INNER_RADIUS; - - requestedProperties += PROP_INNER_START_COLOR; - requestedProperties += PROP_INNER_END_COLOR; - requestedProperties += PROP_OUTER_START_COLOR; - requestedProperties += PROP_OUTER_END_COLOR; - - requestedProperties += PROP_INNER_START_ALPHA; - requestedProperties += PROP_INNER_END_ALPHA; - requestedProperties += PROP_OUTER_START_ALPHA; - requestedProperties += PROP_OUTER_END_ALPHA; - - requestedProperties += PROP_HAS_TICK_MARKS; - requestedProperties += PROP_MAJOR_TICK_MARKS_ANGLE; - requestedProperties += PROP_MINOR_TICK_MARKS_ANGLE; - requestedProperties += PROP_MAJOR_TICK_MARKS_LENGTH; - requestedProperties += PROP_MINOR_TICK_MARKS_LENGTH; - requestedProperties += PROP_MAJOR_TICK_MARKS_COLOR; - requestedProperties += PROP_MINOR_TICK_MARKS_COLOR; - - return requestedProperties; -} - -void RingGizmoPropertyGroup::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_START_ANGLE, getStartAngle()); - APPEND_ENTITY_PROPERTY(PROP_END_ANGLE, getEndAngle()); - APPEND_ENTITY_PROPERTY(PROP_INNER_RADIUS, getInnerRadius()); - - APPEND_ENTITY_PROPERTY(PROP_INNER_START_COLOR, getInnerStartColor()); - APPEND_ENTITY_PROPERTY(PROP_INNER_END_COLOR, getInnerEndColor()); - APPEND_ENTITY_PROPERTY(PROP_OUTER_START_COLOR, getOuterStartColor()); - APPEND_ENTITY_PROPERTY(PROP_OUTER_END_COLOR, getOuterEndColor()); - - APPEND_ENTITY_PROPERTY(PROP_INNER_START_ALPHA, getInnerStartAlpha()); - APPEND_ENTITY_PROPERTY(PROP_INNER_END_ALPHA, getInnerEndAlpha()); - APPEND_ENTITY_PROPERTY(PROP_OUTER_START_ALPHA, getOuterStartAlpha()); - APPEND_ENTITY_PROPERTY(PROP_OUTER_END_ALPHA, getOuterEndAlpha()); - - APPEND_ENTITY_PROPERTY(PROP_HAS_TICK_MARKS, getHasTickMarks()); - APPEND_ENTITY_PROPERTY(PROP_MAJOR_TICK_MARKS_ANGLE, getMajorTickMarksAngle()); - APPEND_ENTITY_PROPERTY(PROP_MINOR_TICK_MARKS_ANGLE, getMinorTickMarksAngle()); - APPEND_ENTITY_PROPERTY(PROP_MAJOR_TICK_MARKS_LENGTH, getMajorTickMarksLength()); - APPEND_ENTITY_PROPERTY(PROP_MINOR_TICK_MARKS_LENGTH, getMinorTickMarksLength()); - APPEND_ENTITY_PROPERTY(PROP_MAJOR_TICK_MARKS_COLOR, getMajorTickMarksColor()); - APPEND_ENTITY_PROPERTY(PROP_MINOR_TICK_MARKS_COLOR, getMinorTickMarksColor()); -} - -int RingGizmoPropertyGroup::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_START_ANGLE, float, setStartAngle); - READ_ENTITY_PROPERTY(PROP_END_ANGLE, float, setEndAngle); - READ_ENTITY_PROPERTY(PROP_INNER_RADIUS, float, setInnerRadius); - - READ_ENTITY_PROPERTY(PROP_INNER_START_COLOR, u8vec3Color, setInnerStartColor); - READ_ENTITY_PROPERTY(PROP_INNER_END_COLOR, u8vec3Color, setInnerEndColor); - READ_ENTITY_PROPERTY(PROP_OUTER_START_COLOR, u8vec3Color, setOuterStartColor); - READ_ENTITY_PROPERTY(PROP_OUTER_END_COLOR, u8vec3Color, setOuterEndColor); - - READ_ENTITY_PROPERTY(PROP_INNER_START_ALPHA, float, setInnerStartAlpha); - READ_ENTITY_PROPERTY(PROP_INNER_END_ALPHA, float, setInnerEndAlpha); - READ_ENTITY_PROPERTY(PROP_OUTER_START_ALPHA, float, setOuterStartAlpha); - READ_ENTITY_PROPERTY(PROP_OUTER_END_ALPHA, float, setOuterEndAlpha); - - READ_ENTITY_PROPERTY(PROP_HAS_TICK_MARKS, bool, setHasTickMarks); - READ_ENTITY_PROPERTY(PROP_MAJOR_TICK_MARKS_ANGLE, float, setMajorTickMarksAngle); - READ_ENTITY_PROPERTY(PROP_MINOR_TICK_MARKS_ANGLE, float, setMinorTickMarksAngle); - READ_ENTITY_PROPERTY(PROP_MAJOR_TICK_MARKS_LENGTH, float, setMajorTickMarksLength); - READ_ENTITY_PROPERTY(PROP_MINOR_TICK_MARKS_LENGTH, float, setMinorTickMarksLength); - READ_ENTITY_PROPERTY(PROP_MAJOR_TICK_MARKS_COLOR, u8vec3Color, setMajorTickMarksColor); - READ_ENTITY_PROPERTY(PROP_MINOR_TICK_MARKS_COLOR, u8vec3Color, setMinorTickMarksColor); - - return bytesRead; -} - -bool RingGizmoPropertyGroup::operator==(const RingGizmoPropertyGroup& a) const { - return (a._startAngle == _startAngle) && - (a._endAngle == _endAngle) && - (a._innerRadius == _innerRadius) && - (a._innerStartColor == _innerStartColor) && - (a._innerEndColor == _innerEndColor) && - (a._outerStartColor == _outerStartColor) && - (a._outerEndColor == _outerEndColor) && - (a._innerStartAlpha == _innerStartAlpha) && - (a._innerEndAlpha == _innerEndAlpha) && - (a._outerStartAlpha == _outerStartAlpha) && - (a._outerEndAlpha == _outerEndAlpha) && - (a._hasTickMarks == _hasTickMarks) && - (a._majorTickMarksAngle == _majorTickMarksAngle) && - (a._minorTickMarksAngle == _minorTickMarksAngle) && - (a._majorTickMarksLength == _majorTickMarksLength) && - (a._minorTickMarksLength == _minorTickMarksLength) && - (a._majorTickMarksColor == _majorTickMarksColor) && - (a._minorTickMarksColor == _minorTickMarksColor); -} \ No newline at end of file diff --git a/libraries/entities/src/RingGizmoPropertyGroup.cpp.in b/libraries/entities/src/RingGizmoPropertyGroup.cpp.in new file mode 100644 index 00000000000..b7e22c81876 --- /dev/null +++ b/libraries/entities/src/RingGizmoPropertyGroup.cpp.in @@ -0,0 +1,159 @@ +// +// Created by Sam Gondelman on 1/22/19 +// Copyright 2019 High Fidelity, Inc. +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#include "RingGizmoPropertyGroup.h" + +#include + +#include "EntityItemProperties.h" + +const float RingGizmoPropertyGroup::MIN_ANGLE = 0.0f; +const float RingGizmoPropertyGroup::MAX_ANGLE = 360.0f; +const float RingGizmoPropertyGroup::MIN_ALPHA = 0.0f; +const float RingGizmoPropertyGroup::MAX_ALPHA = 1.0f; +const float RingGizmoPropertyGroup::MIN_RADIUS = 0.0f; +const float RingGizmoPropertyGroup::MAX_RADIUS = 0.5f; + +void RingGizmoPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, + bool skipDefaults, EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, bool isMyOwnAvatarEntity) const { + +@Ring_GROUP_COPY_TO_SCRIPT@ + +} + +void RingGizmoPropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) { + +@Ring_GROUP_COPY_FROM_SCRIPT@ + +} + +void RingGizmoPropertyGroup::merge(const RingGizmoPropertyGroup& other) { + +@Ring_GROUP_MERGE@ + +} + +void RingGizmoPropertyGroup::debugDump() const { + +@Ring_GROUP_DEBUG_DUMP@ + +} + +void RingGizmoPropertyGroup::listChangedProperties(QList& out) { + +@Ring_GROUP_LIST_CHANGED@ + +} + +bool RingGizmoPropertyGroup::appendToEditPacket(OctreePacketData* packetData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@Ring_GROUP_APPEND@ + + return successPropertyFits; +} + +bool RingGizmoPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) { + + int bytesRead = 0; + bool overwriteLocalData = true; + bool somethingChanged = false; + +@Ring_GROUP_READ@ + +@Ring_GROUP_DECODE_CHANGED@ + + processedBytes += bytesRead; + + return somethingChanged; +} + +void RingGizmoPropertyGroup::markAllChanged() { + +@Ring_GROUP_MARK_CHANGED@ + +} + +EntityPropertyFlags RingGizmoPropertyGroup::getChangedProperties() const { + EntityPropertyFlags changedProperties; + +@Ring_GROUP_CHANGED_PROPERTIES@ + + return changedProperties; +} + +void RingGizmoPropertyGroup::getProperties(EntityItemProperties& properties) const { + +@Ring_GROUP_COPY_TO@ + +} + +bool RingGizmoPropertyGroup::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + +@Ring_GROUP_SET_FROM@ + + return somethingChanged; +} + +EntityPropertyFlags RingGizmoPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties; + +@Ring_REQUESTED_PROPS@ + + return requestedProperties; +} + +int RingGizmoPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + +@Ring_GROUP_READ@ + + return bytesRead; +} + +void RingGizmoPropertyGroup::addPropertyMap(QHash& _propertyInfos, + QHash& _enumsToPropertyStrings) { + +@Ring_GROUP_ADD_TO_MAP@ + +} + +bool RingGizmoPropertyGroup::operator==(const RingGizmoPropertyGroup& a) const { + return (a._startAngle == _startAngle) && + (a._endAngle == _endAngle) && + (a._innerRadius == _innerRadius) && + (a._innerStartColor == _innerStartColor) && + (a._innerEndColor == _innerEndColor) && + (a._outerStartColor == _outerStartColor) && + (a._outerEndColor == _outerEndColor) && + (a._innerStartAlpha == _innerStartAlpha) && + (a._innerEndAlpha == _innerEndAlpha) && + (a._outerStartAlpha == _outerStartAlpha) && + (a._outerEndAlpha == _outerEndAlpha) && + (a._hasTickMarks == _hasTickMarks) && + (a._majorTickMarksAngle == _majorTickMarksAngle) && + (a._minorTickMarksAngle == _minorTickMarksAngle) && + (a._majorTickMarksLength == _majorTickMarksLength) && + (a._minorTickMarksLength == _minorTickMarksLength) && + (a._majorTickMarksColor == _majorTickMarksColor) && + (a._minorTickMarksColor == _minorTickMarksColor); +} diff --git a/libraries/entities/src/RingGizmoPropertyGroup.h b/libraries/entities/src/RingGizmoPropertyGroup.h deleted file mode 100644 index 51ef709f5b3..00000000000 --- a/libraries/entities/src/RingGizmoPropertyGroup.h +++ /dev/null @@ -1,139 +0,0 @@ -// -// Created by Sam Gondelman on 1/22/19 -// Copyright 2019 High Fidelity, Inc. -// Copyright 2023 Overte e.V. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// SPDX-License-Identifier: Apache-2.0 -// - -#ifndef hifi_RingGizmoPropertyGroup_h -#define hifi_RingGizmoPropertyGroup_h - -#include - -#include "PropertyGroup.h" -#include "EntityItemPropertiesMacros.h" -#include "EntityItemPropertiesDefaults.h" - -class EntityItemProperties; -class EncodeBitstreamParams; -class OctreePacketData; -class ReadBitstreamToTreeParams; -class ScriptEngine; -class ScriptValue; - -using u8vec3Color = glm::u8vec3; - -/*@jsdoc - * A {@link Entities.EntityProperties-Gizmo|ring Gizmo} entity is defined by the following properties: - * @typedef {object} Entities.RingGizmo - * - * @property {number} startAngle=0 - The angle at which the ring starts, in degrees. - * @property {number} endAngle=360 - The angle at which the ring ends, in degrees. - * @property {number} innerRadius=0 - The inner radius of the ring as a fraction of the total radius, range 0.0 - * — 1.0. - - * @property {Color} innerStartColor=255,255,255 - The color at the inner start point of the ring. - * @property {Color} innerEndColor=255,255,255 - The color at the inner end point of the ring. - * @property {Color} outerStartColor=255,255,255 - The color at the outer start point of the ring. - * @property {Color} outerEndColor=255,255,255 - The color at the outer end point of the ring. - * @property {number} innerStartAlpha=1 - The opacity at the inner start point of the ring. - * @property {number} innerEndAlpha=1 - The opacity at the inner end point of the ring. - * @property {number} outerStartAlpha=1 - The opacity at the outer start point of the ring. - * @property {number} outerEndAlpha=1 - The opacity at the outer end point of the ring. - - * @property {boolean} hasTickMarks=false - true to render tick marks, otherwise false. - * @property {number} majorTickMarksAngle=0 - The angle between major tick marks, in degrees. - * @property {number} minorTickMarksAngle=0 - The angle between minor tick marks, in degrees. - * @property {number} majorTickMarksLength=0 - The length of the major tick marks as a fraction of the radius. A positive value - * draws tick marks outwards from the inner radius; a negative value draws tick marks inwards from the outer radius. - * @property {number} minorTickMarksLength=0 - The length of the minor tick marks, as a fraction of the radius. A positive - * value draws tick marks outwards from the inner radius; a negative value draws tick marks inwards from the outer radius. - * @property {Color} majorTickMarksColor=255,255,255 - The color of the major tick marks. - * @property {Color} minorTickMarksColor=255,255,255 - The color of the minor tick marks. - */ - -class RingGizmoPropertyGroup : public PropertyGroup { -public: - // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, - ScriptEngine* engine, bool skipDefaults, - EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, - bool isMyOwnAvatarEntity) const override; - virtual void copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) override; - - void merge(const RingGizmoPropertyGroup& other); - - virtual void debugDump() const override; - virtual void listChangedProperties(QList& 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; - - bool operator==(const RingGizmoPropertyGroup& a) const; - bool operator!=(const RingGizmoPropertyGroup& a) const { return !(*this == a); } - - static const float MIN_ANGLE; - static const float MAX_ANGLE; - static const float MIN_ALPHA; - static const float MAX_ALPHA; - static const float MIN_RADIUS; - static const float MAX_RADIUS; - - DEFINE_PROPERTY(PROP_START_ANGLE, StartAngle, startAngle, float, 0.0f); - DEFINE_PROPERTY(PROP_END_ANGLE, EndAngle, endAngle, float, 360.0f); - DEFINE_PROPERTY(PROP_INNER_RADIUS, InnerRadius, innerRadius, float, 0.0f); - - DEFINE_PROPERTY_REF(PROP_INNER_START_COLOR, InnerStartColor, innerStartColor, u8vec3Color, ENTITY_ITEM_DEFAULT_COLOR); - DEFINE_PROPERTY_REF(PROP_INNER_END_COLOR, InnerEndColor, innerEndColor, u8vec3Color, ENTITY_ITEM_DEFAULT_COLOR); - DEFINE_PROPERTY_REF(PROP_OUTER_START_COLOR, OuterStartColor, outerStartColor, u8vec3Color, ENTITY_ITEM_DEFAULT_COLOR); - DEFINE_PROPERTY_REF(PROP_OUTER_END_COLOR, OuterEndColor, outerEndColor, u8vec3Color, ENTITY_ITEM_DEFAULT_COLOR); - - DEFINE_PROPERTY(PROP_INNER_START_ALPHA, InnerStartAlpha, innerStartAlpha, float, ENTITY_ITEM_DEFAULT_ALPHA); - DEFINE_PROPERTY(PROP_INNER_END_ALPHA, InnerEndAlpha, innerEndAlpha, float, ENTITY_ITEM_DEFAULT_ALPHA); - DEFINE_PROPERTY(PROP_OUTER_START_ALPHA, OuterStartAlpha, outerStartAlpha, float, ENTITY_ITEM_DEFAULT_ALPHA); - DEFINE_PROPERTY(PROP_OUTER_END_ALPHA, OuterEndAlpha, outerEndAlpha, float, ENTITY_ITEM_DEFAULT_ALPHA); - - DEFINE_PROPERTY(PROP_HAS_TICK_MARKS, HasTickMarks, hasTickMarks, bool, false); - DEFINE_PROPERTY(PROP_MAJOR_TICK_MARKS_ANGLE, MajorTickMarksAngle, majorTickMarksAngle, float, 0.0f); - DEFINE_PROPERTY(PROP_MINOR_TICK_MARKS_ANGLE, MinorTickMarksAngle, minorTickMarksAngle, float, 0.0f); - DEFINE_PROPERTY(PROP_MAJOR_TICK_MARKS_LENGTH, MajorTickMarksLength, majorTickMarksLength, float, 0.0f); - DEFINE_PROPERTY(PROP_MINOR_TICK_MARKS_LENGTH, MinorTickMarksLength, minorTickMarksLength, float, 0.0f); - DEFINE_PROPERTY_REF(PROP_MAJOR_TICK_MARKS_COLOR, MajorTickMarksColor, majorTickMarksColor, u8vec3Color, ENTITY_ITEM_DEFAULT_COLOR); - DEFINE_PROPERTY_REF(PROP_MINOR_TICK_MARKS_COLOR, MinorTickMarksColor, minorTickMarksColor, u8vec3Color, ENTITY_ITEM_DEFAULT_COLOR); -}; - -#endif // hifi_RingGizmoPropertyGroup_h diff --git a/libraries/entities/src/RingGizmoPropertyGroup.h.in b/libraries/entities/src/RingGizmoPropertyGroup.h.in new file mode 100644 index 00000000000..ea422258511 --- /dev/null +++ b/libraries/entities/src/RingGizmoPropertyGroup.h.in @@ -0,0 +1,76 @@ +// +// Created by Sam Gondelman on 1/22/19 +// Copyright 2019 High Fidelity, Inc. +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef hifi_RingGizmoPropertyGroup_h +#define hifi_RingGizmoPropertyGroup_h + +#include + +#include "PropertyGroup.h" +#include "EntityItemPropertiesMacros.h" +#include "EntityItemPropertiesDefaults.h" + +class EntityItemProperties; +class EncodeBitstreamParams; +class OctreePacketData; +class ReadBitstreamToTreeParams; +class ScriptEngine; +class ScriptValue; + +/*@jsdoc + * A {@link Entities.EntityProperties-Gizmo|ring Gizmo} entity is defined by the following properties: + * @typedef {object} Entities.RingGizmo + * + * @property {number} startAngle=0 - The angle at which the ring starts, in degrees. + * @property {number} endAngle=360 - The angle at which the ring ends, in degrees. + * @property {number} innerRadius=0 - The inner radius of the ring as a fraction of the total radius, range 0.0 + * — 1.0. + + * @property {Color} innerStartColor=255,255,255 - The color at the inner start point of the ring. + * @property {Color} innerEndColor=255,255,255 - The color at the inner end point of the ring. + * @property {Color} outerStartColor=255,255,255 - The color at the outer start point of the ring. + * @property {Color} outerEndColor=255,255,255 - The color at the outer end point of the ring. + * @property {number} innerStartAlpha=1 - The opacity at the inner start point of the ring. + * @property {number} innerEndAlpha=1 - The opacity at the inner end point of the ring. + * @property {number} outerStartAlpha=1 - The opacity at the outer start point of the ring. + * @property {number} outerEndAlpha=1 - The opacity at the outer end point of the ring. + + * @property {boolean} hasTickMarks=false - true to render tick marks, otherwise false. + * @property {number} majorTickMarksAngle=0 - The angle between major tick marks, in degrees. + * @property {number} minorTickMarksAngle=0 - The angle between minor tick marks, in degrees. + * @property {number} majorTickMarksLength=0 - The length of the major tick marks as a fraction of the radius. A positive value + * draws tick marks outwards from the inner radius; a negative value draws tick marks inwards from the outer radius. + * @property {number} minorTickMarksLength=0 - The length of the minor tick marks, as a fraction of the radius. A positive + * value draws tick marks outwards from the inner radius; a negative value draws tick marks inwards from the outer radius. + * @property {Color} majorTickMarksColor=255,255,255 - The color of the major tick marks. + * @property {Color} minorTickMarksColor=255,255,255 - The color of the minor tick marks. + */ + +class RingGizmoPropertyGroup : public PropertyGroup { +public: + ENTITY_PROPERTY_GROUP_METHODS(RingGizmoPropertyGroup) + + bool operator==(const RingGizmoPropertyGroup& a) const; + bool operator!=(const RingGizmoPropertyGroup& a) const { return !(*this == a); } + + static const float MIN_ANGLE; + static const float MAX_ANGLE; + static const float MIN_ALPHA; + static const float MAX_ALPHA; + static const float MIN_RADIUS; + static const float MAX_RADIUS; + +protected: + +@Ring_GROUP_PROPS@ + +}; + +#endif // hifi_RingGizmoPropertyGroup_h diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp.in similarity index 63% rename from libraries/entities/src/ShapeEntityItem.cpp rename to libraries/entities/src/ShapeEntityItem.cpp.in index 825660bd72f..cababe7f03e 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp.in @@ -19,67 +19,8 @@ #include "EntityTree.h" #include "EntityTreeElement.h" -namespace entity { - - /*@jsdoc - *

A "Shape", "Box", or "Sphere" {@link Entities.EntityType|EntityType} may - * display as one of the following geometrical shapes:

- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
ValueDimensionsNotes
"Circle"2DA circle oriented in 3D.
"Cone"3D
"Cube"3D
"Cylinder"3D
"Dodecahedron"3D
"Hexagon"3DA hexagonal prism.
"Icosahedron"3D
"Octagon"3DAn octagonal prism.
"Octahedron"3D
"Quad"2DA square oriented in 3D.
"Sphere"3D
"Tetrahedron"3D
"Torus"3DNot implemented.
"Triangle"3DA triangular prism.
- * @typedef {string} Entities.Shape - */ - static const std::array shapeStrings { { - "Triangle", - "Quad", - "Hexagon", - "Octagon", - "Circle", - "Cube", - "Sphere", - "Tetrahedron", - "Octahedron", - "Dodecahedron", - "Icosahedron", - "Torus", // Not implemented yet. - "Cone", - "Cylinder" - } }; - - Shape shapeFromString(const ::QString& shapeString) { - for (size_t i = 0; i < shapeStrings.size(); ++i) { - if (shapeString.toLower() == shapeStrings[i].toLower()) { - return static_cast(i); - } - } - return Shape::Sphere; - } - - QString stringFromShape(Shape shape) { - return shapeStrings[shape]; - } -} - // hullShapeCalculator is a hook for external code that knows how to configure a ShapeInfo -// for given entity::Shape and dimensions +// for given EntityShape and dimensions ShapeEntityItem::ShapeInfoCalculator hullShapeCalculator = nullptr; void ShapeEntityItem::setShapeInfoCalulator(ShapeEntityItem::ShapeInfoCalculator callback) { @@ -98,13 +39,13 @@ EntityItemPointer ShapeEntityItem::factory(const EntityItemID& entityID, const E EntityItemPointer ShapeEntityItem::boxFactory(const EntityItemID& entityID, const EntityItemProperties& properties) { auto result = baseFactory(entityID, properties); - result->setShape(entity::Shape::Cube); + result->setShape(EntityShape::Cube); return result; } EntityItemPointer ShapeEntityItem::sphereFactory(const EntityItemID& entityID, const EntityItemProperties& properties) { auto result = baseFactory(entityID, properties); - result->setShape(entity::Shape::Sphere); + result->setShape(EntityShape::Sphere); return result; } @@ -117,30 +58,24 @@ ShapeEntityItem::ShapeEntityItem(const EntityItemID& entityItemID) : EntityItem( EntityItemProperties ShapeEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class - COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getColor); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha); - withReadLock([&] { - _pulseProperties.getProperties(properties); - }); - properties.setShape(entity::stringFromShape(getShape())); - properties._shapeChanged = false; +@Shape_ENTITY_COPY_TO@ return properties; } -void ShapeEntityItem::setShape(const entity::Shape& shape) { +void ShapeEntityItem::setShape(EntityShape shape) { switch (shape) { - case entity::Shape::Cube: + case EntityShape::Cube: _type = EntityTypes::Box; break; - case entity::Shape::Sphere: + case EntityShape::Sphere: _type = EntityTypes::Sphere; break; - case entity::Shape::Circle: + case EntityShape::Circle: // Circle is implicitly flat so we enforce flat dimensions setUnscaledDimensions(getUnscaledDimensions()); break; - case entity::Shape::Quad: + case EntityShape::Quad: // Quad is implicitly flat so we enforce flat dimensions setUnscaledDimensions(getUnscaledDimensions()); break; @@ -159,8 +94,8 @@ void ShapeEntityItem::setShape(const entity::Shape& shape) { } } -entity::Shape ShapeEntityItem::getShape() const { - return resultWithReadLock([&] { +EntityShape ShapeEntityItem::getShape() const { + return resultWithReadLock([&] { return _shape; }); } @@ -168,97 +103,50 @@ entity::Shape ShapeEntityItem::getShape() const { bool ShapeEntityItem::setSubClassProperties(const EntityItemProperties& properties) { bool somethingChanged = false; - SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha); - withWriteLock([&] { - bool pulsePropertiesChanged = _pulseProperties.setProperties(properties); - somethingChanged |= pulsePropertiesChanged; - _needsRenderUpdate |= pulsePropertiesChanged; - }); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(shape, setShape); +@Shape_ENTITY_SET_FROM@ return somethingChanged; } -int ShapeEntityItem::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_COLOR, glm::u8vec3, setColor); - READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha); - withWriteLock([&] { - int bytesFromPulse = _pulseProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, - somethingChanged); - bytesRead += bytesFromPulse; - dataAt += bytesFromPulse; - }); - READ_ENTITY_PROPERTY(PROP_SHAPE, QString, setShape); - - return bytesRead; -} - EntityPropertyFlags ShapeEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); - requestedProperties += PROP_COLOR; - requestedProperties += PROP_ALPHA; - requestedProperties += _pulseProperties.getEntityProperties(params); - requestedProperties += PROP_SHAPE; + +@Shape_REQUESTED_PROPS@ + return requestedProperties; } void ShapeEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const { + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { bool successPropertyFits = true; - APPEND_ENTITY_PROPERTY(PROP_COLOR, getColor()); - APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha()); - withReadLock([&] { - _pulseProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, - propertyFlags, propertiesDidntFit, propertyCount, appendState); - }); - APPEND_ENTITY_PROPERTY(PROP_SHAPE, entity::stringFromShape(getShape())); -} -void ShapeEntityItem::setColor(const glm::u8vec3& value) { - withWriteLock([&] { - _needsRenderUpdate |= _color != value; - _color = value; - }); -} +@Shape_ENTITY_APPEND@ -glm::u8vec3 ShapeEntityItem::getColor() const { - return resultWithReadLock([&] { - return _color; - }); } -void ShapeEntityItem::setAlpha(float alpha) { - withWriteLock([&] { - _needsRenderUpdate |= _alpha != alpha; - _alpha = alpha; - }); -} +int ShapeEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { -float ShapeEntityItem::getAlpha() const { - return resultWithReadLock([&] { - return _alpha; - }); + int bytesRead = 0; + const unsigned char* dataAt = data; + +@Shape_ENTITY_READ@ + + return bytesRead; } void ShapeEntityItem::setUnscaledDimensions(const glm::vec3& value) { const float MAX_FLAT_DIMENSION = 0.0001f; const auto shape = getShape(); - if ((shape == entity::Shape::Circle || shape == entity::Shape::Quad) && value.y > MAX_FLAT_DIMENSION) { + if ((shape == EntityShape::Circle || shape == EntityShape::Quad) && value.y > MAX_FLAT_DIMENSION) { // enforce flatness in Y glm::vec3 newDimensions = value; newDimensions.y = MAX_FLAT_DIMENSION; @@ -269,7 +157,7 @@ void ShapeEntityItem::setUnscaledDimensions(const glm::vec3& value) { } bool ShapeEntityItem::supportsDetailedIntersection() const { - return getShape() == entity::Sphere; + return getShape() == EntityShape::Sphere; } bool ShapeEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, @@ -339,20 +227,19 @@ bool ShapeEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, bool ShapeEntityItem::getRotateForPicking() const { auto shape = getShape(); - return getBillboardMode() != BillboardMode::NONE && (shape < entity::Shape::Cube || shape > entity::Shape::Icosahedron); + return getBillboardMode() != BillboardMode::NONE && (shape < EntityShape::Cube || shape > EntityShape::Icosahedron); } void ShapeEntityItem::debugDump() const { - quint64 now = usecTimestampNow(); - qCDebug(entities) << "SHAPE EntityItem id:" << getEntityItemID() << "---------------------------------------------"; - qCDebug(entities) << " name:" << _name; - qCDebug(entities) << " shape:" << stringFromShape(_shape) << " (EnumId: " << _shape << " )"; - qCDebug(entities) << " collisionShapeType:" << ShapeInfo::getNameForShapeType(getShapeType()); - qCDebug(entities) << " color:" << _color; - qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); - qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); - qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); - qCDebug(entities) << "SHAPE EntityItem Ptr:" << this; + qCDebug(entities) << "ShapeEntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " editedAgo:" << debugTime(getLastEdited(), usecTimestampNow()); + qCDebug(entities) << " pointer:" << this; + +@Shape_ENTITY_DEBUG@ + } void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) { @@ -364,13 +251,13 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) { const auto shape = getShape(); switch (shape){ - case entity::Shape::Quad: + case EntityShape::Quad: // Quads collide like flat Cubes - case entity::Shape::Cube: { + case EntityShape::Cube: { _collisionShapeType = SHAPE_TYPE_BOX; } break; - case entity::Shape::Sphere: { + case EntityShape::Sphere: { float diameter = entityDimensions.x; const float MIN_DIAMETER = 0.001f; const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f; @@ -384,9 +271,9 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) { } } break; - case entity::Shape::Circle: + case EntityShape::Circle: // Circles collide like flat Cylinders - case entity::Shape::Cylinder: { + case EntityShape::Cylinder: { float diameter = entityDimensions.x; const float MIN_DIAMETER = 0.001f; const float MIN_RELATIVE_SPHERICAL_ERROR = 0.001f; @@ -403,7 +290,7 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) { } } break; - case entity::Shape::Cone: { + case EntityShape::Cone: { if (hullShapeCalculator) { hullShapeCalculator(this, info); _collisionShapeType = SHAPE_TYPE_SIMPLE_HULL; @@ -413,9 +300,9 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) { } break; // gons, ones, & angles built via GeometryCache::extrudePolygon - case entity::Shape::Triangle: - case entity::Shape::Hexagon: - case entity::Shape::Octagon: { + case EntityShape::Triangle: + case EntityShape::Hexagon: + case EntityShape::Octagon: { if (hullShapeCalculator) { hullShapeCalculator(this, info); _collisionShapeType = SHAPE_TYPE_SIMPLE_HULL; @@ -425,10 +312,10 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) { } break; // hedrons built via GeometryCache::setUpFlatShapes - case entity::Shape::Tetrahedron: - case entity::Shape::Octahedron: - case entity::Shape::Dodecahedron: - case entity::Shape::Icosahedron: { + case EntityShape::Tetrahedron: + case EntityShape::Octahedron: + case EntityShape::Dodecahedron: + case EntityShape::Icosahedron: { if ( hullShapeCalculator ) { hullShapeCalculator(this, info); _collisionShapeType = SHAPE_TYPE_SIMPLE_HULL; @@ -437,7 +324,7 @@ void ShapeEntityItem::computeShapeInfo(ShapeInfo& info) { } } break; - case entity::Shape::Torus: { + case EntityShape::Torus: { // Not in GeometryCache::buildShapes, unsupported. _collisionShapeType = SHAPE_TYPE_ELLIPSOID; //TODO handle this shape more correctly @@ -468,4 +355,4 @@ void ShapeEntityItem::setUserData(const QString& value) { _needsRenderUpdate |= _userData != value; _userData = value; }); -} \ No newline at end of file +} diff --git a/libraries/entities/src/ShapeEntityItem.h b/libraries/entities/src/ShapeEntityItem.h.in similarity index 55% rename from libraries/entities/src/ShapeEntityItem.h rename to libraries/entities/src/ShapeEntityItem.h.in index d5b934153a6..151e844f596 100644 --- a/libraries/entities/src/ShapeEntityItem.h +++ b/libraries/entities/src/ShapeEntityItem.h.in @@ -13,29 +13,6 @@ #include "PulsePropertyGroup.h" -namespace entity { - enum Shape { - Triangle, - Quad, - Hexagon, - Octagon, - Circle, - Cube, - Sphere, - Tetrahedron, - Octahedron, - Dodecahedron, - Icosahedron, - Torus, - Cone, - Cylinder, - NUM_SHAPES, - }; - - Shape shapeFromString(const ::QString& shapeString); - QString stringFromShape(Shape shape); -} - class ShapeEntityItem : public EntityItem { using Pointer = std::shared_ptr; static Pointer baseFactory(const EntityItemID& entityID, const EntityItemProperties& properties); @@ -51,36 +28,9 @@ class ShapeEntityItem : public EntityItem { void pureVirtualFunctionPlaceHolder() override { }; // Triggers warnings on OSX - //ALLOW_INSTANTIATION - - // methods for getting/setting all properties of an entity - EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - bool setSubClassProperties(const EntityItemProperties& properties) override; - - EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; - - void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const override; - - int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, - ReadBitstreamToTreeParams& args, - EntityPropertyFlags& propertyFlags, bool overwriteLocalData, - bool& somethingChanged) override; + //ALLOW_INSTANTIATION - entity::Shape getShape() const; - void setShape(const entity::Shape& shape); - void setShape(const QString& shape) { setShape(entity::shapeFromString(shape)); } - - float getAlpha() const; - void setAlpha(float alpha); - - glm::u8vec3 getColor() const; - void setColor(const glm::u8vec3& value); + ENTITY_PROPERTY_SUBCLASS_METHODS void setUnscaledDimensions(const glm::vec3& value) override; @@ -95,8 +45,6 @@ class ShapeEntityItem : public EntityItem { QVariantMap& extraInfo, bool precisionPicking) const override; bool getRotateForPicking() const override; - void debugDump() const override; - virtual void computeShapeInfo(ShapeInfo& info) override; virtual ShapeType getShapeType() const override; @@ -105,10 +53,8 @@ class ShapeEntityItem : public EntityItem { void setUserData(const QString& value) override; protected: - glm::u8vec3 _color; - float _alpha { 1.0f }; - PulsePropertyGroup _pulseProperties; - entity::Shape _shape { entity::Shape::Sphere }; + +@Shape_ENTITY_PROPS@ //! This is SHAPE_TYPE_ELLIPSOID rather than SHAPE_TYPE_NONE to maintain //! prior functionality where new or unsupported shapes are treated as diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index d64efdf87f2..ecdc37ebfb4 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -62,7 +62,7 @@ void SimpleEntitySimulation::addEntityToInternalLists(EntityItemPointer entity) // we don't allow dynamic objects to move without an owner so nothing to do here } else if (entity->isMovingRelativeToParent()) { SetOfEntities::iterator itr = _simpleKinematicEntities.find(entity); - if (itr != _simpleKinematicEntities.end()) { + if (itr == _simpleKinematicEntities.end()) { _simpleKinematicEntities.insert(entity); entity->setLastSimulated(usecTimestampNow()); } @@ -73,7 +73,7 @@ void SimpleEntitySimulation::addEntityToInternalLists(EntityItemPointer entity) if (entity->isMovingRelativeToParent()) { SetOfEntities::iterator itr = _simpleKinematicEntities.find(entity); - if (itr != _simpleKinematicEntities.end()) { + if (itr == _simpleKinematicEntities.end()) { _simpleKinematicEntities.insert(entity); entity->setLastSimulated(usecTimestampNow()); } diff --git a/libraries/entities/src/SkyboxPropertyGroup.cpp b/libraries/entities/src/SkyboxPropertyGroup.cpp deleted file mode 100644 index 9c3ad46fcee..00000000000 --- a/libraries/entities/src/SkyboxPropertyGroup.cpp +++ /dev/null @@ -1,154 +0,0 @@ -// -// SkyboxPropertyGroup.cpp -// libraries/entities/src -// -// Created by Brad Hefta-Gaub on 12/4/13. -// Copyright 2013 High Fidelity, Inc. -// Copyright 2023 Overte e.V. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// SPDX-License-Identifier: Apache-2.0 -// - -#include "SkyboxPropertyGroup.h" - -#include - -#include "EntityItemProperties.h" -#include "EntityItemPropertiesMacros.h" - -const glm::u8vec3 SkyboxPropertyGroup::DEFAULT_COLOR = { 0, 0, 0 }; - -void SkyboxPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, - bool skipDefaults, EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, bool isMyOwnAvatarEntity) const { - auto nodeList = DependencyManager::get(); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(PROP_SKYBOX_COLOR, Skybox, skybox, Color, color, u8vec3Color); - COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_SKYBOX_URL, Skybox, skybox, URL, url); -} - -void SkyboxPropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) { - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(skybox, color, u8vec3Color, setColor); - COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(skybox, url, QString, setURL); -} - -void SkyboxPropertyGroup::merge(const SkyboxPropertyGroup& other) { - COPY_PROPERTY_IF_CHANGED(color); - COPY_PROPERTY_IF_CHANGED(url); -} - - -void SkyboxPropertyGroup::debugDump() const { - qCDebug(entities) << " SkyboxPropertyGroup: ---------------------------------------------"; - qCDebug(entities) << " Color:" << getColor() << " has changed:" << colorChanged(); - qCDebug(entities) << " URL:" << getURL() << " has changed:" << urlChanged(); -} - -void SkyboxPropertyGroup::listChangedProperties(QList& out) { - if (colorChanged()) { - out << "skybox-color"; - } - if (urlChanged()) { - out << "skybox-url"; - } -} - -bool SkyboxPropertyGroup::appendToEditPacket(OctreePacketData* packetData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const { - - bool successPropertyFits = true; - - APPEND_ENTITY_PROPERTY(PROP_SKYBOX_COLOR, getColor()); - APPEND_ENTITY_PROPERTY(PROP_SKYBOX_URL, getURL()); - - return true; -} - - -bool SkyboxPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) { - - int bytesRead = 0; - bool overwriteLocalData = true; - bool somethingChanged = false; - - READ_ENTITY_PROPERTY(PROP_SKYBOX_COLOR, u8vec3Color, setColor); - READ_ENTITY_PROPERTY(PROP_SKYBOX_URL, QString, setURL); - - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_SKYBOX_COLOR, Color); - DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_SKYBOX_URL, URL); - - processedBytes += bytesRead; - - Q_UNUSED(somethingChanged); - - return true; -} - -void SkyboxPropertyGroup::markAllChanged() { - _colorChanged = true; - _urlChanged = true; -} - -EntityPropertyFlags SkyboxPropertyGroup::getChangedProperties() const { - EntityPropertyFlags changedProperties; - - CHECK_PROPERTY_CHANGE(PROP_SKYBOX_COLOR, color); - CHECK_PROPERTY_CHANGE(PROP_SKYBOX_URL, url); - - return changedProperties; -} - -void SkyboxPropertyGroup::getProperties(EntityItemProperties& properties) const { - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Skybox, Color, getColor); - COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Skybox, URL, getURL); -} - -bool SkyboxPropertyGroup::setProperties(const EntityItemProperties& properties) { - bool somethingChanged = false; - - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Skybox, Color, color, setColor); - SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Skybox, URL, url, setURL); - - return somethingChanged; -} - -EntityPropertyFlags SkyboxPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { - EntityPropertyFlags requestedProperties; - - requestedProperties += PROP_SKYBOX_COLOR; - requestedProperties += PROP_SKYBOX_URL; - - return requestedProperties; -} - -void SkyboxPropertyGroup::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_SKYBOX_COLOR, getColor()); - APPEND_ENTITY_PROPERTY(PROP_SKYBOX_URL, getURL()); -} - -int SkyboxPropertyGroup::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_SKYBOX_COLOR, u8vec3Color, setColor); - READ_ENTITY_PROPERTY(PROP_SKYBOX_URL, QString, setURL); - - return bytesRead; -} diff --git a/libraries/entities/src/SkyboxPropertyGroup.cpp.in b/libraries/entities/src/SkyboxPropertyGroup.cpp.in new file mode 100644 index 00000000000..6b43ac514b0 --- /dev/null +++ b/libraries/entities/src/SkyboxPropertyGroup.cpp.in @@ -0,0 +1,138 @@ +// +// SkyboxPropertyGroup.cpp +// libraries/entities/src +// +// Created by Brad Hefta-Gaub on 12/4/13. +// Copyright 2013 High Fidelity, Inc. +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#include "SkyboxPropertyGroup.h" + +#include + +#include "EntityItemProperties.h" + +const glm::u8vec3 SkyboxPropertyGroup::DEFAULT_COLOR = { 0, 0, 0 }; + +void SkyboxPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, + bool skipDefaults, EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, bool isMyOwnAvatarEntity) const { + + auto nodeList = DependencyManager::get(); + +@Skybox_GROUP_COPY_TO_SCRIPT@ + +} + +void SkyboxPropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) { + +@Skybox_GROUP_COPY_FROM_SCRIPT@ + +} + +void SkyboxPropertyGroup::merge(const SkyboxPropertyGroup& other) { + +@Skybox_GROUP_MERGE@ + +} + +void SkyboxPropertyGroup::debugDump() const { + +@Skybox_GROUP_DEBUG_DUMP@ + +} + +void SkyboxPropertyGroup::listChangedProperties(QList& out) { + +@Skybox_GROUP_LIST_CHANGED@ + +} + +bool SkyboxPropertyGroup::appendToEditPacket(OctreePacketData* packetData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@Skybox_GROUP_APPEND@ + + return successPropertyFits; +} + +bool SkyboxPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) { + + int bytesRead = 0; + bool overwriteLocalData = true; + bool somethingChanged = false; + +@Skybox_GROUP_READ@ + +@Skybox_GROUP_DECODE_CHANGED@ + + processedBytes += bytesRead; + + return somethingChanged; +} + +void SkyboxPropertyGroup::markAllChanged() { + +@Skybox_GROUP_MARK_CHANGED@ + +} + +EntityPropertyFlags SkyboxPropertyGroup::getChangedProperties() const { + EntityPropertyFlags changedProperties; + +@Skybox_GROUP_CHANGED_PROPERTIES@ + + return changedProperties; +} + +void SkyboxPropertyGroup::getProperties(EntityItemProperties& properties) const { + +@Skybox_GROUP_COPY_TO@ + +} + +bool SkyboxPropertyGroup::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + +@Skybox_GROUP_SET_FROM@ + + return somethingChanged; +} + +EntityPropertyFlags SkyboxPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties; + +@Skybox_REQUESTED_PROPS@ + + return requestedProperties; +} + +int SkyboxPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + +@Skybox_GROUP_READ@ + + return bytesRead; +} + +void SkyboxPropertyGroup::addPropertyMap(QHash& _propertyInfos, + QHash& _enumsToPropertyStrings) { + +@Skybox_GROUP_ADD_TO_MAP@ + +} diff --git a/libraries/entities/src/SkyboxPropertyGroup.h b/libraries/entities/src/SkyboxPropertyGroup.h deleted file mode 100644 index 30c9ef1d3a1..00000000000 --- a/libraries/entities/src/SkyboxPropertyGroup.h +++ /dev/null @@ -1,94 +0,0 @@ -// -// SkyboxPropertyGroup.h -// libraries/entities/src -// -// Created by Brad Hefta-Gaub on 12/4/13. -// Copyright 2013 High Fidelity, Inc. -// Copyright 2023 Overte e.V. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// SPDX-License-Identifier: Apache-2.0 -// - -#ifndef hifi_SkyboxPropertyGroup_h -#define hifi_SkyboxPropertyGroup_h - -#include - -#include - -#include - -#include "PropertyGroup.h" -#include "EntityItemPropertiesMacros.h" - -class EntityItemProperties; -class EncodeBitstreamParams; -class OctreePacketData; -class EntityTreeElementExtraEncodeData; -class ReadBitstreamToTreeParams; -class ScriptEngine; -class ScriptValue; - -/*@jsdoc - * A skybox is defined by the following properties: - * @typedef {object} Entities.Skybox - * @property {Color} color=0,0,0 - Sets the color of the sky if url is "", otherwise modifies the - * color of the cube map image. - * @property {string} url="" - A cube map image that is used to render the sky. - */ -class SkyboxPropertyGroup : public PropertyGroup { -public: - // EntityItemProperty related helpers - virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, - ScriptEngine* engine, bool skipDefaults, - EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, - bool isMyOwnAvatarEntity) const override; - virtual void copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) override; - - void merge(const SkyboxPropertyGroup& other); - - virtual void debugDump() const override; - virtual void listChangedProperties(QList& 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; - - static const glm::u8vec3 DEFAULT_COLOR; - DEFINE_PROPERTY_REF(PROP_SKYBOX_COLOR, Color, color, glm::u8vec3, DEFAULT_COLOR); - DEFINE_PROPERTY_REF(PROP_SKYBOX_URL, URL, url, QString, ""); -}; - -#endif // hifi_SkyboxPropertyGroup_h diff --git a/libraries/entities/src/SkyboxPropertyGroup.h.in b/libraries/entities/src/SkyboxPropertyGroup.h.in new file mode 100644 index 00000000000..3961f25badb --- /dev/null +++ b/libraries/entities/src/SkyboxPropertyGroup.h.in @@ -0,0 +1,53 @@ +// +// SkyboxPropertyGroup.h +// libraries/entities/src +// +// Created by Brad Hefta-Gaub on 12/4/13. +// Copyright 2013 High Fidelity, Inc. +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef hifi_SkyboxPropertyGroup_h +#define hifi_SkyboxPropertyGroup_h + +#include + +#include + +#include + +#include "PropertyGroup.h" +#include "EntityItemPropertiesMacros.h" + +class EntityItemProperties; +class EncodeBitstreamParams; +class OctreePacketData; +class EntityTreeElementExtraEncodeData; +class ReadBitstreamToTreeParams; +class ScriptEngine; +class ScriptValue; + +/*@jsdoc + * A skybox is defined by the following properties: + * @typedef {object} Entities.Skybox + * @property {Color} color=0,0,0 - Sets the color of the sky if url is "", otherwise modifies the + * color of the cube map image. + * @property {string} url="" - A cube map image that is used to render the sky. + */ +class SkyboxPropertyGroup : public PropertyGroup { +public: + ENTITY_PROPERTY_GROUP_METHODS(SkyboxPropertyGroup) + + static const glm::u8vec3 DEFAULT_COLOR; + +protected: + +@Skybox_GROUP_PROPS@ + +}; + +#endif // hifi_SkyboxPropertyGroup_h diff --git a/libraries/entities/src/SoundEntityItem.cpp.in b/libraries/entities/src/SoundEntityItem.cpp.in new file mode 100644 index 00000000000..a308747bffe --- /dev/null +++ b/libraries/entities/src/SoundEntityItem.cpp.in @@ -0,0 +1,413 @@ +// +// Created by HifiExperiments on 12/30/2023 +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "SoundEntityItem.h" + +#include + +#include "EntitiesLogging.h" +#include "EntityItemProperties.h" +#include "EntityTree.h" +#include "EntityTreeElement.h" + +EntityItemPointer SoundEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + std::shared_ptr entity(new SoundEntityItem(entityID), [](SoundEntityItem* ptr) { ptr->deleteLater(); }); + entity->setProperties(properties); + return entity; +} + +// our non-pure virtual subclass for now... +SoundEntityItem::SoundEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { + _type = EntityTypes::Sound; +} + +SoundEntityItem::~SoundEntityItem() { + auto manager = DependencyManager::get(); + if (manager && _injector) { + manager->stop(_injector); + } +} + +EntityItemProperties SoundEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class + +@Sound_ENTITY_COPY_TO@ + + return properties; +} + +bool SoundEntityItem::setSubClassProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + +@Sound_ENTITY_SET_FROM@ + + return somethingChanged; +} + +EntityPropertyFlags SoundEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + +@Sound_REQUESTED_PROPS@ + + return requestedProperties; +} + +void SoundEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@Sound_ENTITY_APPEND@ + +} + +int SoundEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + +@Sound_ENTITY_READ@ + + return bytesRead; +} + +void SoundEntityItem::debugDump() const { + qCDebug(entities) << "SoundEntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " editedAgo:" << debugTime(getLastEdited(), usecTimestampNow()); + qCDebug(entities) << " pointer:" << this; + +@Sound_ENTITY_DEBUG@ + +} + +bool SoundEntityItem::shouldCreateSound(const EntityTreePointer& tree) const { + bool clientShouldMakeSound = _localOnly || isMyAvatarEntity() || tree->isServerlessMode(); + bool serverShouldMakeSound = !_localOnly; + return (clientShouldMakeSound && tree->getIsClient()) || (serverShouldMakeSound && tree->isEntityServer()); +} + +void SoundEntityItem::update(const quint64& now) { + const auto tree = getTree(); + if (tree) { + std::lock_guard lock(_soundLock); + + _updateNeeded = false; + + withReadLock([&] { + if (shouldCreateSound(tree)) { + _sound = DependencyManager::get()->getSound(_soundURL); + } + }); + + if (_sound) { + if (_sound->isLoaded()) { + updateSound(true); + } else { + connect(_sound.data(), &Resource::finished, this, [&] { updateSound(true); }); + } + } + } +} + +void SoundEntityItem::locationChanged(bool tellPhysics, bool tellChildren) { + EntityItem::locationChanged(tellPhysics, tellChildren); + updateSound(); +} + +void SoundEntityItem::dimensionsChanged() { + EntityItem::dimensionsChanged(); + updateSound(); +} + +void SoundEntityItem::setSoundURL(const QString& value) { + bool changed = false; + withWriteLock([&] { + if (value != _soundURL) { + _soundURL = value; + changed = true; + } + }); + + if (changed) { + const auto tree = getTree(); + if (!tree) { + _updateNeeded = true; + return; + } + + std::lock_guard lock(_soundLock); + + withReadLock([&] { + if (shouldCreateSound(tree)) { + _sound = DependencyManager::get()->getSound(_soundURL); + } + }); + + if (_sound) { + if (_sound->isLoaded()) { + updateSound(true); + } else { + connect(_sound.data(), &Resource::finished, this, [&] { updateSound(true); }); + } + } + } +} + +QString SoundEntityItem::getSoundURL() const { + return resultWithReadLock([&] { + return _soundURL; + }); +} + +void SoundEntityItem::setVolume(float value) { + bool changed = false; + withWriteLock([&] { + if (value != _volume) { + _volume = value; + changed = true; + } + }); + + if (changed) { + updateSound(); + } +} + +float SoundEntityItem::getVolume() const { + return resultWithReadLock([&] { + return _volume; + }); +} + +void SoundEntityItem::setTimeOffset(float value) { + bool changed = false; + withWriteLock([&] { + if (value != _timeOffset) { + _timeOffset = value; + changed = true; + } + }); + + if (changed) { + updateSound(true); + } +} + +float SoundEntityItem::getTimeOffset() const { + return resultWithReadLock([&] { + return _timeOffset; + }); +} + +void SoundEntityItem::setPitch(float value) { + bool changed = false; + withWriteLock([&] { + if (value != _pitch) { + _pitch = value; + changed = true; + } + }); + + if (changed) { + updateSound(true); + } +} + +float SoundEntityItem::getPitch() const { + return resultWithReadLock([&] { + return _pitch; + }); +} + +void SoundEntityItem::setPlaying(bool value) { + bool changed = false; + withWriteLock([&] { + if (value != _playing) { + _playing = value; + changed = true; + } + }); + + if (changed) { + updateSound(); + } +} + +bool SoundEntityItem::getPlaying() const { + return resultWithReadLock([&] { + return _playing; + }); +} + +void SoundEntityItem::setLoop(bool value) { + bool changed = false; + withWriteLock([&] { + if (value != _loop) { + _loop = value; + changed = true; + } + }); + + if (changed) { + updateSound(true); + } +} + +bool SoundEntityItem::getLoop() const { + return resultWithReadLock([&] { + return _loop; + }); +} + +void SoundEntityItem::setPositional(bool value) { + bool changed = false; + withWriteLock([&] { + if (value != _positional) { + _positional = value; + changed = true; + } + }); + + if (changed) { + updateSound(); + } +} + +bool SoundEntityItem::getPositional() const { + return resultWithReadLock([&] { + return _positional; + }); +} + +void SoundEntityItem::setLocalOnly(bool value) { + bool changed = false; + withWriteLock([&] { + if (value != _localOnly) { + _localOnly = value; + changed = true; + } + }); + + if (changed) { + const auto tree = getTree(); + if (!tree) { + _updateNeeded = true; + return; + } + + std::lock_guard lock(_soundLock); + + bool createdSound = false; + withReadLock([&] { + if (shouldCreateSound(tree)) { + _sound = DependencyManager::get()->getSound(_soundURL); + createdSound = true; + } + }); + + if (!createdSound) { + _sound = nullptr; + + if (_injector) { + DependencyManager::get()->stop(_injector); + _injector = nullptr; + } + } + + if (_sound) { + if (_sound->isLoaded()) { + updateSound(true); + } else { + connect(_sound.data(), &Resource::finished, this, [&] { updateSound(true); }); + } + } + } +} + +bool SoundEntityItem::getLocalOnly() const { + return resultWithReadLock([&] { + return _localOnly; + }); +} + +bool SoundEntityItem::restartSound(bool lock) { + if (lock) { + _soundLock.lock(); + } + + if (!_sound) { + if (lock) { + _soundLock.unlock(); + } + return false; + } + + AudioInjectorOptions options; + withReadLock([&] { + const glm::quat orientation = getWorldOrientation(); + options.position = getWorldPosition() + orientation * (getScaledDimensions() * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())); + options.positionSet = _positional; + options.volume = _volume; + options.loop = _loop; + options.orientation = orientation; + options.localOnly = _localOnly || _sound->isAmbisonic(); // force localOnly when ambisonic + options.secondOffset = _timeOffset; + options.pitch = _pitch; + }); + + // stereo option isn't set from script, this comes from sound metadata or filename + options.stereo = _sound->isStereo(); + options.ambisonic = _sound->isAmbisonic(); + + if (_injector) { + DependencyManager::get()->setOptions(_injector, options); + } else { + _injector = DependencyManager::get()->playSound(_sound, options); + } + + if (lock) { + _soundLock.unlock(); + } + + return true; +} + +void SoundEntityItem::updateSound(bool restart) { + std::lock_guard lock(_soundLock); + + if (!_sound) { + return; + } + + if (restart) { + if (_injector) { + DependencyManager::get()->stop(_injector); + _injector = nullptr; + } + } + + if (_playing) { + restartSound(); + } else { + if (_injector) { + DependencyManager::get()->stop(_injector); + _injector = nullptr; + } + } +} diff --git a/libraries/entities/src/SoundEntityItem.h.in b/libraries/entities/src/SoundEntityItem.h.in new file mode 100644 index 00000000000..c88345640a3 --- /dev/null +++ b/libraries/entities/src/SoundEntityItem.h.in @@ -0,0 +1,52 @@ +// +// Created by HifiExperiments on 12/30/2023 +// Copyright 2023 Overte e.V. +// +// 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_SoundEntityItem_h +#define hifi_SoundEntityItem_h + +#include "EntityItem.h" + +#include +#include + +class SoundEntityItem : public EntityItem { +public: + static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); + + SoundEntityItem(const EntityItemID& entityItemID); + ~SoundEntityItem(); + + ALLOW_INSTANTIATION // This class can be instantiated + ENTITY_PROPERTY_SUBCLASS_METHODS + + bool shouldBePhysical() const override { return false; } + + virtual bool supportsDetailedIntersection() const override { return false; } + + virtual void update(const quint64& now) override; + bool needsToCallUpdate() const override { return _updateNeeded; } + + void locationChanged(bool tellPhysics = true, bool tellChildren = true) override; + void dimensionsChanged() override; + + bool restartSound(bool lock = false); + +protected: + +@Sound_ENTITY_PROPS@ + + bool shouldCreateSound(const EntityTreePointer& tree) const; + void updateSound(bool restart = false); + + std::recursive_mutex _soundLock; + SharedSoundPointer _sound; + AudioInjectorPointer _injector; + bool _updateNeeded { false }; +}; + +#endif // hifi_SoundEntityItem_h diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp deleted file mode 100644 index 160a608c23a..00000000000 --- a/libraries/entities/src/TextEntityItem.cpp +++ /dev/null @@ -1,413 +0,0 @@ -// -// TextEntityItem.cpp -// libraries/entities/src -// -// Created by Brad Hefta-Gaub on 12/4/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "TextEntityItem.h" - -#include - -#include - -#include -#include - -#include "EntityItemProperties.h" -#include "EntitiesLogging.h" -#include "EntityTree.h" -#include "EntityTreeElement.h" - -const QString TextEntityItem::DEFAULT_TEXT(""); -const float TextEntityItem::DEFAULT_LINE_HEIGHT = 0.1f; -const glm::u8vec3 TextEntityItem::DEFAULT_TEXT_COLOR = { 255, 255, 255 }; -const float TextEntityItem::DEFAULT_TEXT_ALPHA = 1.0f; -const glm::u8vec3 TextEntityItem::DEFAULT_BACKGROUND_COLOR = { 0, 0, 0}; -const float TextEntityItem::DEFAULT_MARGIN = 0.0f; -const float TextEntityItem::DEFAULT_TEXT_EFFECT_THICKNESS = 0.2f; - -EntityItemPointer TextEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - std::shared_ptr entity(new TextEntityItem(entityID), [](TextEntityItem* ptr) { ptr->deleteLater(); }); - entity->setProperties(properties); - return entity; -} - -TextEntityItem::TextEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { - _type = EntityTypes::Text; -} - -void TextEntityItem::setUnscaledDimensions(const glm::vec3& value) { - const float TEXT_ENTITY_ITEM_FIXED_DEPTH = 0.01f; - // NOTE: Text Entities always have a "depth" of 1cm. - EntityItem::setUnscaledDimensions(glm::vec3(value.x, value.y, TEXT_ENTITY_ITEM_FIXED_DEPTH)); -} - -EntityItemProperties TextEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { - EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class - - withReadLock([&] { - _pulseProperties.getProperties(properties); - }); - - COPY_ENTITY_PROPERTY_TO_PROPERTIES(text, getText); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(lineHeight, getLineHeight); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(textColor, getTextColor); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(textAlpha, getTextAlpha); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(backgroundColor, getBackgroundColor); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(backgroundAlpha, getBackgroundAlpha); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(leftMargin, getLeftMargin); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(rightMargin, getRightMargin); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(topMargin, getTopMargin); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(bottomMargin, getBottomMargin); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(unlit, getUnlit); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(font, getFont); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(textEffect, getTextEffect); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(textEffectColor, getTextEffectColor); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(textEffectThickness, getTextEffectThickness); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(alignment, getAlignment); - return properties; -} - -bool TextEntityItem::setSubClassProperties(const EntityItemProperties& properties) { - bool somethingChanged = false; - - withWriteLock([&] { - bool pulsePropertiesChanged = _pulseProperties.setProperties(properties); - somethingChanged |= pulsePropertiesChanged; - _needsRenderUpdate |= pulsePropertiesChanged; - }); - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(text, setText); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(lineHeight, setLineHeight); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(textColor, setTextColor); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(textAlpha, setTextAlpha); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(backgroundColor, setBackgroundColor); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(backgroundAlpha, setBackgroundAlpha); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(leftMargin, setLeftMargin); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(rightMargin, setRightMargin); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(topMargin, setTopMargin); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(bottomMargin, setBottomMargin); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(unlit, setUnlit); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(font, setFont); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(textEffect, setTextEffect); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(textEffectColor, setTextEffectColor); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(textEffectThickness, setTextEffectThickness); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(alignment, setAlignment); - - return somethingChanged; -} - -int TextEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, - ReadBitstreamToTreeParams& args, - EntityPropertyFlags& propertyFlags, bool overwriteLocalData, - bool& somethingChanged) { - - int bytesRead = 0; - const unsigned char* dataAt = data; - - withWriteLock([&] { - int bytesFromPulse = _pulseProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, - somethingChanged); - bytesRead += bytesFromPulse; - dataAt += bytesFromPulse; - }); - - READ_ENTITY_PROPERTY(PROP_TEXT, QString, setText); - READ_ENTITY_PROPERTY(PROP_LINE_HEIGHT, float, setLineHeight); - READ_ENTITY_PROPERTY(PROP_TEXT_COLOR, glm::u8vec3, setTextColor); - READ_ENTITY_PROPERTY(PROP_TEXT_ALPHA, float, setTextAlpha); - READ_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, glm::u8vec3, setBackgroundColor); - READ_ENTITY_PROPERTY(PROP_BACKGROUND_ALPHA, float, setBackgroundAlpha); - READ_ENTITY_PROPERTY(PROP_LEFT_MARGIN, float, setLeftMargin); - READ_ENTITY_PROPERTY(PROP_RIGHT_MARGIN, float, setRightMargin); - READ_ENTITY_PROPERTY(PROP_TOP_MARGIN, float, setTopMargin); - READ_ENTITY_PROPERTY(PROP_BOTTOM_MARGIN, float, setBottomMargin); - READ_ENTITY_PROPERTY(PROP_UNLIT, bool, setUnlit); - READ_ENTITY_PROPERTY(PROP_FONT, QString, setFont); - READ_ENTITY_PROPERTY(PROP_TEXT_EFFECT, TextEffect, setTextEffect); - READ_ENTITY_PROPERTY(PROP_TEXT_EFFECT_COLOR, glm::u8vec3, setTextEffectColor); - READ_ENTITY_PROPERTY(PROP_TEXT_EFFECT_THICKNESS, float, setTextEffectThickness); - READ_ENTITY_PROPERTY(PROP_TEXT_ALIGNMENT, TextAlignment, setAlignment); - - return bytesRead; -} - -EntityPropertyFlags TextEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { - EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); - - requestedProperties += _pulseProperties.getEntityProperties(params); - - requestedProperties += PROP_TEXT; - requestedProperties += PROP_LINE_HEIGHT; - requestedProperties += PROP_TEXT_COLOR; - requestedProperties += PROP_TEXT_ALPHA; - requestedProperties += PROP_BACKGROUND_COLOR; - requestedProperties += PROP_BACKGROUND_ALPHA; - requestedProperties += PROP_LEFT_MARGIN; - requestedProperties += PROP_RIGHT_MARGIN; - requestedProperties += PROP_TOP_MARGIN; - requestedProperties += PROP_BOTTOM_MARGIN; - requestedProperties += PROP_UNLIT; - requestedProperties += PROP_FONT; - requestedProperties += PROP_TEXT_EFFECT; - requestedProperties += PROP_TEXT_EFFECT_COLOR; - requestedProperties += PROP_TEXT_EFFECT_THICKNESS; - requestedProperties += PROP_TEXT_ALIGNMENT; - - return requestedProperties; -} - -void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const { - - bool successPropertyFits = true; - - withReadLock([&] { - _pulseProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, - propertyFlags, propertiesDidntFit, propertyCount, appendState); - }); - - APPEND_ENTITY_PROPERTY(PROP_TEXT, getText()); - APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, getLineHeight()); - APPEND_ENTITY_PROPERTY(PROP_TEXT_COLOR, getTextColor()); - APPEND_ENTITY_PROPERTY(PROP_TEXT_ALPHA, getTextAlpha()); - APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_COLOR, getBackgroundColor()); - APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_ALPHA, getBackgroundAlpha()); - APPEND_ENTITY_PROPERTY(PROP_LEFT_MARGIN, getLeftMargin()); - APPEND_ENTITY_PROPERTY(PROP_RIGHT_MARGIN, getRightMargin()); - APPEND_ENTITY_PROPERTY(PROP_TOP_MARGIN, getTopMargin()); - APPEND_ENTITY_PROPERTY(PROP_BOTTOM_MARGIN, getBottomMargin()); - APPEND_ENTITY_PROPERTY(PROP_UNLIT, getUnlit()); - APPEND_ENTITY_PROPERTY(PROP_FONT, getFont()); - APPEND_ENTITY_PROPERTY(PROP_TEXT_EFFECT, (uint32_t)getTextEffect()); - APPEND_ENTITY_PROPERTY(PROP_TEXT_EFFECT_COLOR, getTextEffectColor()); - APPEND_ENTITY_PROPERTY(PROP_TEXT_EFFECT_THICKNESS, getTextEffectThickness()); - APPEND_ENTITY_PROPERTY(PROP_TEXT_ALIGNMENT, (uint32_t)getAlignment()); -} - -void TextEntityItem::setText(const QString& value) { - withWriteLock([&] { - _needsRenderUpdate |= _text != value; - _text = value; - }); -} - -QString TextEntityItem::getText() const { - return resultWithReadLock([&] { - return _text; - }); -} - -void TextEntityItem::setLineHeight(float value) { - withWriteLock([&] { - _needsRenderUpdate |= _lineHeight != value; - _lineHeight = value; - }); -} - -float TextEntityItem::getLineHeight() const { - float result; - withReadLock([&] { - result = _lineHeight; - }); - return result; -} - -void TextEntityItem::setTextColor(const glm::u8vec3& value) { - withWriteLock([&] { - _needsRenderUpdate |= _textColor != value; - _textColor = value; - }); -} - -glm::u8vec3 TextEntityItem::getTextColor() const { - return resultWithReadLock([&] { - return _textColor; - }); -} - -void TextEntityItem::setTextAlpha(float value) { - withWriteLock([&] { - _needsRenderUpdate |= _textAlpha != value; - _textAlpha = value; - }); -} - -float TextEntityItem::getTextAlpha() const { - return resultWithReadLock([&] { - return _textAlpha; - }); -} - -void TextEntityItem::setBackgroundColor(const glm::u8vec3& value) { - withWriteLock([&] { - _needsRenderUpdate |= _backgroundColor != value; - _backgroundColor = value; - }); -} - -glm::u8vec3 TextEntityItem::getBackgroundColor() const { - return resultWithReadLock([&] { - return _backgroundColor; - }); -} - -void TextEntityItem::setBackgroundAlpha(float value) { - withWriteLock([&] { - _needsRenderUpdate |= _backgroundAlpha != value; - _backgroundAlpha = value; - }); -} - -float TextEntityItem::getBackgroundAlpha() const { - return resultWithReadLock([&] { - return _backgroundAlpha; - }); -} - -void TextEntityItem::setLeftMargin(float value) { - withWriteLock([&] { - _needsRenderUpdate |= _leftMargin != value; - _leftMargin = value; - }); -} - -float TextEntityItem::getLeftMargin() const { - return resultWithReadLock([&] { - return _leftMargin; - }); -} - -void TextEntityItem::setRightMargin(float value) { - withWriteLock([&] { - _needsRenderUpdate |= _rightMargin != value; - _rightMargin = value; - }); -} - -float TextEntityItem::getRightMargin() const { - return resultWithReadLock([&] { - return _rightMargin; - }); -} - -void TextEntityItem::setTopMargin(float value) { - withWriteLock([&] { - _needsRenderUpdate |= _topMargin != value; - _topMargin = value; - }); -} - -float TextEntityItem::getTopMargin() const { - return resultWithReadLock([&] { - return _topMargin; - }); -} - -void TextEntityItem::setBottomMargin(float value) { - withWriteLock([&] { - _needsRenderUpdate |= _bottomMargin != value; - _bottomMargin = value; - }); -} - -float TextEntityItem::getBottomMargin() const { - return resultWithReadLock([&] { - return _bottomMargin; - }); -} - -void TextEntityItem::setUnlit(bool value) { - withWriteLock([&] { - _needsRenderUpdate |= _unlit != value; - _unlit = value; - }); -} - -bool TextEntityItem::getUnlit() const { - return resultWithReadLock([&] { - return _unlit; - }); -} - -void TextEntityItem::setFont(const QString& value) { - withWriteLock([&] { - _needsRenderUpdate |= _font != value; - _font = value; - }); -} - -QString TextEntityItem::getFont() const { - return resultWithReadLock([&] { - return _font; - }); -} - -void TextEntityItem::setTextEffect(TextEffect value) { - withWriteLock([&] { - _needsRenderUpdate |= _effect != value; - _effect = value; - }); -} - -TextEffect TextEntityItem::getTextEffect() const { - return resultWithReadLock([&] { - return _effect; - }); -} - -void TextEntityItem::setTextEffectColor(const glm::u8vec3& value) { - withWriteLock([&] { - _needsRenderUpdate |= _effectColor != value; - _effectColor = value; - }); -} - -glm::u8vec3 TextEntityItem::getTextEffectColor() const { - return resultWithReadLock([&] { - return _effectColor; - }); -} - -void TextEntityItem::setTextEffectThickness(float value) { - withWriteLock([&] { - _needsRenderUpdate |= _effectThickness != value; - _effectThickness = value; - }); -} - -float TextEntityItem::getTextEffectThickness() const { - return resultWithReadLock([&] { - return _effectThickness; - }); -} - -void TextEntityItem::setAlignment(TextAlignment value) { - withWriteLock([&] { - _needsRenderUpdate |= _alignment != value; - _alignment = value; - }); -} - -TextAlignment TextEntityItem::getAlignment() const { - return resultWithReadLock([&] { - return _alignment; - }); -} - -PulsePropertyGroup TextEntityItem::getPulseProperties() const { - return resultWithReadLock([&] { - return _pulseProperties; - }); -} diff --git a/libraries/entities/src/TextEntityItem.cpp.in b/libraries/entities/src/TextEntityItem.cpp.in new file mode 100644 index 00000000000..b5927e350a8 --- /dev/null +++ b/libraries/entities/src/TextEntityItem.cpp.in @@ -0,0 +1,117 @@ +// +// TextEntityItem.cpp +// libraries/entities/src +// +// Created by Brad Hefta-Gaub on 12/4/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "TextEntityItem.h" + +#include + +#include + +#include +#include + +#include "EntityItemProperties.h" +#include "EntitiesLogging.h" +#include "EntityTree.h" +#include "EntityTreeElement.h" + +const QString TextEntityItem::DEFAULT_TEXT(""); +const float TextEntityItem::DEFAULT_LINE_HEIGHT = 0.1f; +const glm::u8vec3 TextEntityItem::DEFAULT_TEXT_COLOR = { 255, 255, 255 }; +const float TextEntityItem::DEFAULT_TEXT_ALPHA = 1.0f; +const glm::u8vec3 TextEntityItem::DEFAULT_BACKGROUND_COLOR = { 0, 0, 0}; +const float TextEntityItem::DEFAULT_MARGIN = 0.0f; +const float TextEntityItem::DEFAULT_TEXT_EFFECT_THICKNESS = 0.2f; + +EntityItemPointer TextEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + std::shared_ptr entity(new TextEntityItem(entityID), [](TextEntityItem* ptr) { ptr->deleteLater(); }); + entity->setProperties(properties); + return entity; +} + +TextEntityItem::TextEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { + _type = EntityTypes::Text; +} + +void TextEntityItem::setUnscaledDimensions(const glm::vec3& value) { + const float TEXT_ENTITY_ITEM_FIXED_DEPTH = 0.01f; + // NOTE: Text Entities always have a "depth" of 1cm. + EntityItem::setUnscaledDimensions(glm::vec3(value.x, value.y, TEXT_ENTITY_ITEM_FIXED_DEPTH)); +} + +EntityItemProperties TextEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class + +@Text_ENTITY_COPY_TO@ + + return properties; +} + +bool TextEntityItem::setSubClassProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + +@Text_ENTITY_SET_FROM@ + + return somethingChanged; +} + +EntityPropertyFlags TextEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + +@Text_REQUESTED_PROPS@ + + return requestedProperties; +} + +void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@Text_ENTITY_APPEND@ + +} + +int TextEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + +@Text_ENTITY_READ@ + + return bytesRead; +} + +void TextEntityItem::debugDump() const { + qCDebug(entities) << "TextEntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " editedAgo:" << debugTime(getLastEdited(), usecTimestampNow()); + qCDebug(entities) << " pointer:" << this; + +@Text_ENTITY_DEBUG@ + +} + +PulsePropertyGroup TextEntityItem::getPulseProperties() const { + return resultWithReadLock([&] { + return _pulseProperties; + }); +} diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h deleted file mode 100644 index e39625060a0..00000000000 --- a/libraries/entities/src/TextEntityItem.h +++ /dev/null @@ -1,128 +0,0 @@ -// -// TextEntityItem.h -// libraries/entities/src -// -// Created by Brad Hefta-Gaub on 12/4/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_TextEntityItem_h -#define hifi_TextEntityItem_h - -#include "EntityItem.h" - -#include "PulsePropertyGroup.h" - -class TextEntityItem : public EntityItem { -public: - static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - - TextEntityItem(const EntityItemID& entityItemID); - - ALLOW_INSTANTIATION // This class can be instantiated - - /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately - virtual void setUnscaledDimensions(const glm::vec3& value) override; - virtual ShapeType getShapeType() const override { return SHAPE_TYPE_BOX; } - - // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - virtual bool setSubClassProperties(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; - - static const QString DEFAULT_TEXT; - void setText(const QString& value); - QString getText() const; - - static const float DEFAULT_LINE_HEIGHT; - void setLineHeight(float value); - float getLineHeight() const; - - static const glm::u8vec3 DEFAULT_TEXT_COLOR; - glm::u8vec3 getTextColor() const; - void setTextColor(const glm::u8vec3& value); - - static const float DEFAULT_TEXT_ALPHA; - float getTextAlpha() const; - void setTextAlpha(float value); - - static const glm::u8vec3 DEFAULT_BACKGROUND_COLOR; - glm::u8vec3 getBackgroundColor() const; - void setBackgroundColor(const glm::u8vec3& value); - - float getBackgroundAlpha() const; - void setBackgroundAlpha(float value); - - static const float DEFAULT_MARGIN; - float getLeftMargin() const; - void setLeftMargin(float value); - - float getRightMargin() const; - void setRightMargin(float value); - - float getTopMargin() const; - void setTopMargin(float value); - - float getBottomMargin() const; - void setBottomMargin(float value); - - bool getUnlit() const; - void setUnlit(bool value); - - void setFont(const QString& value); - QString getFont() const; - - TextEffect getTextEffect() const; - void setTextEffect(TextEffect value); - - glm::u8vec3 getTextEffectColor() const; - void setTextEffectColor(const glm::u8vec3& value); - - static const float DEFAULT_TEXT_EFFECT_THICKNESS; - float getTextEffectThickness() const; - void setTextEffectThickness(float value); - - TextAlignment getAlignment() const; - void setAlignment(TextAlignment value); - - PulsePropertyGroup getPulseProperties() const; - -private: - QString _text; - float _lineHeight; - glm::u8vec3 _textColor; - float _textAlpha; - glm::u8vec3 _backgroundColor; - float _backgroundAlpha; - PulsePropertyGroup _pulseProperties; - float _leftMargin; - float _rightMargin; - float _topMargin; - float _bottomMargin; - bool _unlit { false }; - - QString _font; - TextAlignment _alignment; - TextEffect _effect; - glm::u8vec3 _effectColor; - float _effectThickness; -}; - -#endif // hifi_TextEntityItem_h diff --git a/libraries/entities/src/TextEntityItem.h.in b/libraries/entities/src/TextEntityItem.h.in new file mode 100644 index 00000000000..ec236449f55 --- /dev/null +++ b/libraries/entities/src/TextEntityItem.h.in @@ -0,0 +1,48 @@ +// +// TextEntityItem.h +// libraries/entities/src +// +// Created by Brad Hefta-Gaub on 12/4/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_TextEntityItem_h +#define hifi_TextEntityItem_h + +#include "EntityItem.h" + +#include "PulsePropertyGroup.h" + +class TextEntityItem : public EntityItem { +public: + static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); + + TextEntityItem(const EntityItemID& entityItemID); + + ALLOW_INSTANTIATION // This class can be instantiated + ENTITY_PROPERTY_SUBCLASS_METHODS + + /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately + virtual void setUnscaledDimensions(const glm::vec3& value) override; + virtual ShapeType getShapeType() const override { return SHAPE_TYPE_BOX; } + + static const QString DEFAULT_TEXT; + static const float DEFAULT_LINE_HEIGHT; + static const glm::u8vec3 DEFAULT_TEXT_COLOR; + static const float DEFAULT_TEXT_ALPHA; + static const glm::u8vec3 DEFAULT_BACKGROUND_COLOR; + static const float DEFAULT_MARGIN; + static const float DEFAULT_TEXT_EFFECT_THICKNESS; + + PulsePropertyGroup getPulseProperties() const; + +private: + +@Text_ENTITY_PROPS@ + +}; + +#endif // hifi_TextEntityItem_h diff --git a/libraries/entities/src/TonemappingPropertyGroup.cpp.in b/libraries/entities/src/TonemappingPropertyGroup.cpp.in new file mode 100644 index 00000000000..95319ae87a9 --- /dev/null +++ b/libraries/entities/src/TonemappingPropertyGroup.cpp.in @@ -0,0 +1,151 @@ +// +// TonemappingPropertyGroup.cpp +// libraries/entities/src +// +// Created by HifiExperiments on 6/23/24 +// Copyright 2024 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#include "TonemappingPropertyGroup.h" + +#include + +#include "EntityItemProperties.h" + +inline void addTonemappingCurve(QHash& lookup, TonemappingCurve curve) { lookup[TonemappingCurveHelpers::getNameForTonemappingCurve(curve)] = curve; } +const QHash stringToTonemappingCurveLookup = [] { + QHash toReturn; + addTonemappingCurve(toReturn, TonemappingCurve::RGB); + addTonemappingCurve(toReturn, TonemappingCurve::SRGB); + addTonemappingCurve(toReturn, TonemappingCurve::FILMIC); + addTonemappingCurve(toReturn, TonemappingCurve::REINHARD); + return toReturn; +}(); +QString TonemappingPropertyGroup::getCurveAsString() const { return TonemappingCurveHelpers::getNameForTonemappingCurve(_curve); } +void TonemappingPropertyGroup::setCurveFromString(const QString& curve) { + auto curveItr = stringToTonemappingCurveLookup.find(curve.toLower()); + if (curveItr != stringToTonemappingCurveLookup.end()) { + _curve = curveItr.value(); + _curveChanged = true; + } +} + +void TonemappingPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, + bool skipDefaults, EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, bool isMyOwnAvatarEntity) const { + +@Tonemapping_GROUP_COPY_TO_SCRIPT@ + +} + +void TonemappingPropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) { + +@Tonemapping_GROUP_COPY_FROM_SCRIPT@ + +} + +void TonemappingPropertyGroup::merge(const TonemappingPropertyGroup& other) { + +@Tonemapping_GROUP_MERGE@ + +} + +void TonemappingPropertyGroup::debugDump() const { + +@Tonemapping_GROUP_DEBUG_DUMP@ + +} + +void TonemappingPropertyGroup::listChangedProperties(QList& out) { + +@Tonemapping_GROUP_LIST_CHANGED@ + +} + +bool TonemappingPropertyGroup::appendToEditPacket(OctreePacketData* packetData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@Tonemapping_GROUP_APPEND@ + + return successPropertyFits; +} + +bool TonemappingPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) { + + int bytesRead = 0; + bool overwriteLocalData = true; + bool somethingChanged = false; + +@Tonemapping_GROUP_READ@ + +@Tonemapping_GROUP_DECODE_CHANGED@ + + processedBytes += bytesRead; + + return somethingChanged; +} + +void TonemappingPropertyGroup::markAllChanged() { + +@Tonemapping_GROUP_MARK_CHANGED@ + +} + +EntityPropertyFlags TonemappingPropertyGroup::getChangedProperties() const { + EntityPropertyFlags changedProperties; + +@Tonemapping_GROUP_CHANGED_PROPERTIES@ + + return changedProperties; +} + +void TonemappingPropertyGroup::getProperties(EntityItemProperties& properties) const { + +@Tonemapping_GROUP_COPY_TO@ + +} + +bool TonemappingPropertyGroup::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + +@Tonemapping_GROUP_SET_FROM@ + + return somethingChanged; +} + +EntityPropertyFlags TonemappingPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties; + +@Tonemapping_REQUESTED_PROPS@ + + return requestedProperties; +} + +int TonemappingPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + +@Tonemapping_GROUP_READ@ + + return bytesRead; +} + +void TonemappingPropertyGroup::addPropertyMap(QHash& _propertyInfos, + QHash& _enumsToPropertyStrings) { + +@Tonemapping_GROUP_ADD_TO_MAP@ + +} diff --git a/libraries/entities/src/TonemappingPropertyGroup.h.in b/libraries/entities/src/TonemappingPropertyGroup.h.in new file mode 100644 index 00000000000..5b3c437dae6 --- /dev/null +++ b/libraries/entities/src/TonemappingPropertyGroup.h.in @@ -0,0 +1,45 @@ +// +// TonemappingPropertyGroup.h +// libraries/entities/src +// +// Created by HifiExperiments on 6/23/24 +// Copyright 2024 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef hifi_TonemappingPropertyGroup_h +#define hifi_TonemappingPropertyGroup_h + +#include + +#include "PropertyGroup.h" +#include "EntityItemPropertiesMacros.h" + +class EntityItemProperties; +class EncodeBitstreamParams; +class OctreePacketData; +class EntityTreeElementExtraEncodeData; +class ReadBitstreamToTreeParams; +class ScriptEngine; +class ScriptValue; + +/*@jsdoc + * Tonemapping is defined by the following properties: + * @typedef {object} Entities.Tonemapping + * @property {TonemappingCurve} curve="srgb" - The tonemapping curve used. + * @property {number} exposure=0.0 - The applied exposure. + */ +class TonemappingPropertyGroup : public PropertyGroup { +public: + ENTITY_PROPERTY_GROUP_METHODS(TonemappingPropertyGroup) + +protected: + +@Tonemapping_GROUP_PROPS@ + +}; + +#endif // hifi_TonemappingPropertyGroup_h diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp deleted file mode 100644 index e090ec25ae9..00000000000 --- a/libraries/entities/src/WebEntityItem.cpp +++ /dev/null @@ -1,306 +0,0 @@ -// -// Created by Bradley Austin Davis on 2015/05/12 -// Copyright 2013 High Fidelity, Inc. -// Copyright 2020 Vircadia contributors. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "WebEntityItem.h" - -#include - -#include -#include - -#include -#include -#include -#include - -#include "EntitiesLogging.h" -#include "EntityItemProperties.h" -#include "EntityTree.h" -#include "EntityTreeElement.h" - -const QString WebEntityItem::DEFAULT_SOURCE_URL = NetworkingConstants::WEB_ENTITY_DEFAULT_SOURCE_URL; -const QString WebEntityItem::DEFAULT_USER_AGENT = NetworkingConstants::WEB_ENTITY_DEFAULT_USER_AGENT; -const uint8_t WebEntityItem::DEFAULT_MAX_FPS = 10; - -EntityItemPointer WebEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - std::shared_ptr entity(new WebEntityItem(entityID), [](WebEntityItem* ptr) { ptr->deleteLater(); }); - entity->setProperties(properties); - return entity; -} - -WebEntityItem::WebEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { - // this initialzation of localSafeContext is reading a thread-local variable and that is depends on - // the ctor being executed on the same thread as the script, assuming it's being create by a script - _localSafeContext = hifi::scripting::isLocalAccessSafeThread(); - _type = EntityTypes::Web; -} - -void WebEntityItem::setUnscaledDimensions(const glm::vec3& value) { - // NOTE: Web Entities always have a "depth" of 1cm. - const float WEB_ENTITY_ITEM_FIXED_DEPTH = 0.01f; - EntityItem::setUnscaledDimensions(glm::vec3(value.x, value.y, WEB_ENTITY_ITEM_FIXED_DEPTH)); -} - -EntityItemProperties WebEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { - EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class - - COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getColor); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha); - withReadLock([&] { - _pulseProperties.getProperties(properties); - }); - - COPY_ENTITY_PROPERTY_TO_PROPERTIES(sourceUrl, getSourceUrl); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(dpi, getDPI); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(scriptURL, getScriptURL); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(maxFPS, getMaxFPS); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(inputMode, getInputMode); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(showKeyboardFocusHighlight, getShowKeyboardFocusHighlight); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(useBackground, getUseBackground); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(userAgent, getUserAgent); - return properties; -} - -bool WebEntityItem::setSubClassProperties(const EntityItemProperties& properties) { - bool somethingChanged = false; - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha); - withWriteLock([&] { - bool pulsePropertiesChanged = _pulseProperties.setProperties(properties); - somethingChanged |= pulsePropertiesChanged; - _needsRenderUpdate |= pulsePropertiesChanged; - }); - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(sourceUrl, setSourceUrl); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(dpi, setDPI); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(scriptURL, setScriptURL); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(maxFPS, setMaxFPS); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(inputMode, setInputMode); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(showKeyboardFocusHighlight, setShowKeyboardFocusHighlight); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(useBackground, setUseBackground); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(userAgent, setUserAgent); - - return somethingChanged; -} - -int WebEntityItem::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_COLOR, glm::u8vec3, setColor); - READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha); - withWriteLock([&] { - int bytesFromPulse = _pulseProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, - somethingChanged); - bytesRead += bytesFromPulse; - dataAt += bytesFromPulse; - }); - - READ_ENTITY_PROPERTY(PROP_SOURCE_URL, QString, setSourceUrl); - READ_ENTITY_PROPERTY(PROP_DPI, uint16_t, setDPI); - READ_ENTITY_PROPERTY(PROP_SCRIPT_URL, QString, setScriptURL); - READ_ENTITY_PROPERTY(PROP_MAX_FPS, uint8_t, setMaxFPS); - READ_ENTITY_PROPERTY(PROP_INPUT_MODE, WebInputMode, setInputMode); - READ_ENTITY_PROPERTY(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, bool, setShowKeyboardFocusHighlight); - READ_ENTITY_PROPERTY(PROP_WEB_USE_BACKGROUND, bool, setUseBackground); - READ_ENTITY_PROPERTY(PROP_USER_AGENT, QString, setUserAgent); - - return bytesRead; -} - -EntityPropertyFlags WebEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { - EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); - requestedProperties += PROP_COLOR; - requestedProperties += PROP_ALPHA; - requestedProperties += _pulseProperties.getEntityProperties(params); - - requestedProperties += PROP_SOURCE_URL; - requestedProperties += PROP_DPI; - requestedProperties += PROP_SCRIPT_URL; - requestedProperties += PROP_MAX_FPS; - requestedProperties += PROP_INPUT_MODE; - requestedProperties += PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT; - requestedProperties += PROP_WEB_USE_BACKGROUND; - requestedProperties += PROP_USER_AGENT; - return requestedProperties; -} - -void WebEntityItem::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_COLOR, getColor()); - APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha()); - withReadLock([&] { - _pulseProperties.appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, - propertyFlags, propertiesDidntFit, propertyCount, appendState); - }); - - APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, getSourceUrl()); - APPEND_ENTITY_PROPERTY(PROP_DPI, getDPI()); - APPEND_ENTITY_PROPERTY(PROP_SCRIPT_URL, getScriptURL()); - APPEND_ENTITY_PROPERTY(PROP_MAX_FPS, getMaxFPS()); - APPEND_ENTITY_PROPERTY(PROP_INPUT_MODE, (uint32_t)getInputMode()); - APPEND_ENTITY_PROPERTY(PROP_SHOW_KEYBOARD_FOCUS_HIGHLIGHT, getShowKeyboardFocusHighlight()); - APPEND_ENTITY_PROPERTY(PROP_WEB_USE_BACKGROUND, getUseBackground()); - APPEND_ENTITY_PROPERTY(PROP_USER_AGENT, getUserAgent()); -} - -void WebEntityItem::setColor(const glm::u8vec3& value) { - withWriteLock([&] { - _needsRenderUpdate |= _color != value; - _color = value; - }); -} - -glm::u8vec3 WebEntityItem::getColor() const { - return resultWithReadLock([&] { - return _color; - }); -} - -bool WebEntityItem::getLocalSafeContext() const { - return resultWithReadLock([&] { - return _localSafeContext; - }); -} - -void WebEntityItem::setAlpha(float alpha) { - withWriteLock([&] { - _needsRenderUpdate |= _alpha != alpha; - _alpha = alpha; - }); -} - -float WebEntityItem::getAlpha() const { - return resultWithReadLock([&] { - return _alpha; - }); -} - -void WebEntityItem::setSourceUrl(const QString& value) { - withWriteLock([&] { - _needsRenderUpdate |= _sourceUrl != value; - _sourceUrl = value; - }); -} - -QString WebEntityItem::getSourceUrl() const { - return resultWithReadLock([&] { - return _sourceUrl; - }); -} - -void WebEntityItem::setDPI(uint16_t value) { - withWriteLock([&] { - _needsRenderUpdate |= _dpi != value; - _dpi = value; - }); -} - -uint16_t WebEntityItem::getDPI() const { - return resultWithReadLock([&] { - return _dpi; - }); -} - -void WebEntityItem::setScriptURL(const QString& value) { - auto newURL = QUrl::fromUserInput(value); - - if (!newURL.isValid()) { - qCDebug(entities) << "Not setting web entity script URL since" << value << "cannot be parsed to a valid URL."; - return; - } - - auto urlString = newURL.toDisplayString(); - - withWriteLock([&] { - _needsRenderUpdate |= _scriptURL != urlString; - _scriptURL = urlString; - }); -} - -QString WebEntityItem::getScriptURL() const { - return resultWithReadLock([&] { - return _scriptURL; - }); -} - -void WebEntityItem::setMaxFPS(uint8_t value) { - withWriteLock([&] { - _needsRenderUpdate |= _maxFPS != value; - _maxFPS = value; - }); -} - -uint8_t WebEntityItem::getMaxFPS() const { - return resultWithReadLock([&] { - return _maxFPS; - }); -} - -void WebEntityItem::setInputMode(const WebInputMode& value) { - withWriteLock([&] { - _needsRenderUpdate |= _inputMode != value; - _inputMode = value; - }); -} - -WebInputMode WebEntityItem::getInputMode() const { - return resultWithReadLock([&] { - return _inputMode; - }); -} - -void WebEntityItem::setShowKeyboardFocusHighlight(bool value) { - _showKeyboardFocusHighlight = value; -} - -bool WebEntityItem::getShowKeyboardFocusHighlight() const { - return _showKeyboardFocusHighlight; -} - -void WebEntityItem::setUseBackground(bool value) { - withWriteLock([&] { - _needsRenderUpdate |= _useBackground != value; - _useBackground = value; - }); -} - -bool WebEntityItem::getUseBackground() const { - return resultWithReadLock([&] { return _useBackground; }); -} - -void WebEntityItem::setUserAgent(const QString& value) { - withWriteLock([&] { - _needsRenderUpdate |= _userAgent != value; - _userAgent = value; - }); -} - -QString WebEntityItem::getUserAgent() const { - return resultWithReadLock([&] { return _userAgent; }); -} - -PulsePropertyGroup WebEntityItem::getPulseProperties() const { - return resultWithReadLock([&] { - return _pulseProperties; - }); -} diff --git a/libraries/entities/src/WebEntityItem.cpp.in b/libraries/entities/src/WebEntityItem.cpp.in new file mode 100644 index 00000000000..c6e1129dcd6 --- /dev/null +++ b/libraries/entities/src/WebEntityItem.cpp.in @@ -0,0 +1,145 @@ +// +// Created by Bradley Austin Davis on 2015/05/12 +// Copyright 2013 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "WebEntityItem.h" + +#include + +#include +#include + +#include +#include +#include +#include + +#include "EntitiesLogging.h" +#include "EntityItemProperties.h" +#include "EntityTree.h" +#include "EntityTreeElement.h" + +const QString WebEntityItem::DEFAULT_SOURCE_URL = NetworkingConstants::WEB_ENTITY_DEFAULT_SOURCE_URL; +const QString WebEntityItem::DEFAULT_USER_AGENT = NetworkingConstants::WEB_ENTITY_DEFAULT_USER_AGENT; +const uint8_t WebEntityItem::DEFAULT_MAX_FPS = 10; + +EntityItemPointer WebEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + std::shared_ptr entity(new WebEntityItem(entityID), [](WebEntityItem* ptr) { ptr->deleteLater(); }); + entity->setProperties(properties); + return entity; +} + +WebEntityItem::WebEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { + // this initialzation of localSafeContext is reading a thread-local variable and that is depends on + // the ctor being executed on the same thread as the script, assuming it's being create by a script + _localSafeContext = hifi::scripting::isLocalAccessSafeThread(); + _type = EntityTypes::Web; +} + +void WebEntityItem::setUnscaledDimensions(const glm::vec3& value) { + // NOTE: Web Entities always have a "depth" of 1cm. + const float WEB_ENTITY_ITEM_FIXED_DEPTH = 0.01f; + EntityItem::setUnscaledDimensions(glm::vec3(value.x, value.y, WEB_ENTITY_ITEM_FIXED_DEPTH)); +} + +EntityItemProperties WebEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class + +@Web_ENTITY_COPY_TO@ + + return properties; +} + +bool WebEntityItem::setSubClassProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + +@Web_ENTITY_SET_FROM@ + + return somethingChanged; +} + +EntityPropertyFlags WebEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + +@Web_REQUESTED_PROPS@ + + return requestedProperties; +} + +void WebEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@Web_ENTITY_APPEND@ + +} + +int WebEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + +@Web_ENTITY_READ@ + + return bytesRead; +} + +void WebEntityItem::debugDump() const { + qCDebug(entities) << "WebEntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " editedAgo:" << debugTime(getLastEdited(), usecTimestampNow()); + qCDebug(entities) << " pointer:" << this; + +@Web_ENTITY_DEBUG@ + +} + +bool WebEntityItem::getLocalSafeContext() const { + return resultWithReadLock([&] { + return _localSafeContext; + }); +} + +void WebEntityItem::setScriptURL(const QString& value) { + auto newURL = QUrl::fromUserInput(value); + + if (!newURL.isValid()) { + qCDebug(entities) << "Not setting web entity script URL since" << value << "cannot be parsed to a valid URL."; + return; + } + + auto urlString = newURL.toDisplayString(); + + withWriteLock([&] { + _needsRenderUpdate |= _scriptURL != urlString; + _scriptURL = urlString; + }); +} + +QString WebEntityItem::getScriptURL() const { + return resultWithReadLock([&] { + return _scriptURL; + }); +} + +PulsePropertyGroup WebEntityItem::getPulseProperties() const { + return resultWithReadLock([&] { + return _pulseProperties; + }); +} diff --git a/libraries/entities/src/WebEntityItem.h b/libraries/entities/src/WebEntityItem.h deleted file mode 100644 index d607bbc99d9..00000000000 --- a/libraries/entities/src/WebEntityItem.h +++ /dev/null @@ -1,103 +0,0 @@ -// -// Created by Bradley Austin Davis on 2015/05/12 -// Copyright 2013 High Fidelity, Inc. -// Copyright 2020 Vircadia contributors. -// Copyright 2023 Overte e.V. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// SPDX-License-Identifier: Apache-2.0 -// - -#ifndef hifi_WebEntityItem_h -#define hifi_WebEntityItem_h - -#include "EntityItem.h" - -#include "PulsePropertyGroup.h" - -class WebEntityItem : public EntityItem { -public: - static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - - WebEntityItem(const EntityItemID& entityItemID); - - ALLOW_INSTANTIATION // This class can be instantiated - - /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately - virtual void setUnscaledDimensions(const glm::vec3& value) override; - virtual ShapeType getShapeType() const override { return SHAPE_TYPE_BOX; } - - // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - virtual bool setSubClassProperties(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; - - glm::u8vec3 getColor() const; - void setColor(const glm::u8vec3& value); - - float getAlpha() const; - void setAlpha(float alpha); - - static const QString DEFAULT_SOURCE_URL; - void setSourceUrl(const QString& value); - QString getSourceUrl() const; - - void setDPI(uint16_t value); - uint16_t getDPI() const; - - void setScriptURL(const QString& value); - QString getScriptURL() const; - - bool getLocalSafeContext() const; - - static const uint8_t DEFAULT_MAX_FPS; - void setMaxFPS(uint8_t value); - uint8_t getMaxFPS() const; - - void setInputMode(const WebInputMode& value); - WebInputMode getInputMode() const; - - bool getShowKeyboardFocusHighlight() const; - void setShowKeyboardFocusHighlight(bool value); - - bool getUseBackground() const; - void setUseBackground(bool value); - - static const QString DEFAULT_USER_AGENT; - QString getUserAgent() const; - void setUserAgent(const QString& value); - - PulsePropertyGroup getPulseProperties() const; - -protected: - glm::u8vec3 _color; - float _alpha { 1.0f }; - PulsePropertyGroup _pulseProperties; - - QString _sourceUrl; - uint16_t _dpi; - QString _scriptURL; - uint8_t _maxFPS; - WebInputMode _inputMode; - bool _showKeyboardFocusHighlight { false }; - bool _useBackground { false }; - QString _userAgent; - bool _localSafeContext { false }; -}; - -#endif // hifi_WebEntityItem_h diff --git a/libraries/entities/src/WebEntityItem.h.in b/libraries/entities/src/WebEntityItem.h.in new file mode 100644 index 00000000000..df28f893f4d --- /dev/null +++ b/libraries/entities/src/WebEntityItem.h.in @@ -0,0 +1,50 @@ +// +// Created by Bradley Austin Davis on 2015/05/12 +// Copyright 2013 High Fidelity, Inc. +// Copyright 2020 Vircadia contributors. +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef hifi_WebEntityItem_h +#define hifi_WebEntityItem_h + +#include "EntityItem.h" + +#include "PulsePropertyGroup.h" + +class WebEntityItem : public EntityItem { +public: + static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); + + WebEntityItem(const EntityItemID& entityItemID); + + ALLOW_INSTANTIATION // This class can be instantiated + ENTITY_PROPERTY_SUBCLASS_METHODS + + /// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately + virtual void setUnscaledDimensions(const glm::vec3& value) override; + virtual ShapeType getShapeType() const override { return SHAPE_TYPE_BOX; } + + void setScriptURL(const QString& value); + QString getScriptURL() const; + + bool getLocalSafeContext() const; + + static const QString DEFAULT_SOURCE_URL; + static const uint8_t DEFAULT_MAX_FPS; + static const QString DEFAULT_USER_AGENT; + + PulsePropertyGroup getPulseProperties() const; + +protected: + +@Web_ENTITY_PROPS@ + + bool _localSafeContext { false }; +}; + +#endif // hifi_WebEntityItem_h diff --git a/libraries/entities/src/ZoneAudioPropertyGroup.cpp.in b/libraries/entities/src/ZoneAudioPropertyGroup.cpp.in new file mode 100644 index 00000000000..9d9226eff46 --- /dev/null +++ b/libraries/entities/src/ZoneAudioPropertyGroup.cpp.in @@ -0,0 +1,132 @@ +// +// ZoneAudioPropertyGroup.cpp +// libraries/entities/src +// +// Created by HifiExperiments on 11/28/23 +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#include "ZoneAudioPropertyGroup.h" + +#include + +#include "EntityItemProperties.h" +void ZoneAudioPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, ScriptEngine* engine, + bool skipDefaults, EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags, bool isMyOwnAvatarEntity) const { + +@Audio_GROUP_COPY_TO_SCRIPT@ + +} + +void ZoneAudioPropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) { + +@Audio_GROUP_COPY_FROM_SCRIPT@ + +} + +void ZoneAudioPropertyGroup::merge(const ZoneAudioPropertyGroup& other) { + +@Audio_GROUP_MERGE@ + +} + +void ZoneAudioPropertyGroup::debugDump() const { + +@Audio_GROUP_DEBUG_DUMP@ + +} + +void ZoneAudioPropertyGroup::listChangedProperties(QList& out) { + +@Audio_GROUP_LIST_CHANGED@ + +} + +bool ZoneAudioPropertyGroup::appendToEditPacket(OctreePacketData* packetData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@Audio_GROUP_APPEND@ + + return successPropertyFits; +} + +bool ZoneAudioPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) { + + int bytesRead = 0; + bool overwriteLocalData = true; + bool somethingChanged = false; + +@Audio_GROUP_READ@ + +@Audio_GROUP_DECODE_CHANGED@ + + processedBytes += bytesRead; + + return somethingChanged; +} + +void ZoneAudioPropertyGroup::markAllChanged() { + +@Audio_GROUP_MARK_CHANGED@ + +} + +EntityPropertyFlags ZoneAudioPropertyGroup::getChangedProperties() const { + EntityPropertyFlags changedProperties; + +@Audio_GROUP_CHANGED_PROPERTIES@ + + return changedProperties; +} + +void ZoneAudioPropertyGroup::getProperties(EntityItemProperties& properties) const { + +@Audio_GROUP_COPY_TO@ + +} + +bool ZoneAudioPropertyGroup::setProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + +@Audio_GROUP_SET_FROM@ + + return somethingChanged; +} + +EntityPropertyFlags ZoneAudioPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties; + +@Audio_REQUESTED_PROPS@ + + return requestedProperties; +} + +int ZoneAudioPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + + int bytesRead = 0; + const unsigned char* dataAt = data; + +@Audio_GROUP_READ@ + + return bytesRead; +} + +void ZoneAudioPropertyGroup::addPropertyMap(QHash& _propertyInfos, + QHash& _enumsToPropertyStrings) { + +@Audio_GROUP_ADD_TO_MAP@ + +} diff --git a/libraries/entities/src/ZoneAudioPropertyGroup.h.in b/libraries/entities/src/ZoneAudioPropertyGroup.h.in new file mode 100644 index 00000000000..62067b9a259 --- /dev/null +++ b/libraries/entities/src/ZoneAudioPropertyGroup.h.in @@ -0,0 +1,52 @@ +// +// ZoneAudioPropertyGroup.h +// libraries/entities/src +// +// Created by HifiExperiments on 11/28/23 +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// SPDX-License-Identifier: Apache-2.0 +// + +#ifndef hifi_ZoneAudioPropertyGroup_h +#define hifi_ZoneAudioPropertyGroup_h + +#include +#include + +#include "PropertyGroup.h" +#include "EntityItemPropertiesMacros.h" + +class EntityItemProperties; +class EncodeBitstreamParams; +class OctreePacketData; +class EntityTreeElementExtraEncodeData; +class ReadBitstreamToTreeParams; +class ScriptEngine; +class ScriptValue; + +/*@jsdoc + * Zone audio is defined by the following properties: + * @typedef {object} Entities.ZoneAudio + * @property {boolean} reverbEnabled=false - If reverb should be enabled for listeners in this zone. + * @property {number} reverbTime=1.0 - The time (seconds) for the reverb tail to decay by 60dB, also known as RT60. + * @property {number} reverbWetLevel=50 - Adjusts the wet/dry percentage, from completely dry (0%) to completely wet (100%). + * @property {Uuid[]} listenerZones=[] - A list of entity IDs representing listener zones with this zone as a source. + * Sounds from this zone being heard by a listener in a listener zone will be attenuated by the corresponding + * listenerAttenuationCoefficient. + * @property {number[]} listenerAttenuationCoefficients=[] - A list of attenuation coefficients. Each coefficient will be + * applied to sounds coming from this zone and being heard by a listener in the corresponding listenerZone. + */ +class ZoneAudioPropertyGroup : public PropertyGroup { +public: + ENTITY_PROPERTY_GROUP_METHODS(ZoneAudioPropertyGroup) + +protected: + +@Audio_GROUP_PROPS@ + +}; + +#endif // hifi_ZoneAudioPropertyGroup_h diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp deleted file mode 100644 index 8ac5a4329c5..00000000000 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ /dev/null @@ -1,485 +0,0 @@ -// -// ZoneEntityItem.cpp -// libraries/entities/src -// -// Created by Brad Hefta-Gaub on 12/4/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "ZoneEntityItem.h" - -#include -#include - -#include - -#include "EntitiesLogging.h" -#include "EntityItemProperties.h" -#include "EntityTree.h" -#include "EntityTreeElement.h" -#include "EntityEditFilters.h" - -bool ZoneEntityItem::_zonesArePickable = false; -bool ZoneEntityItem::_drawZoneBoundaries = false; - - -const ShapeType ZoneEntityItem::DEFAULT_SHAPE_TYPE = SHAPE_TYPE_BOX; -const QString ZoneEntityItem::DEFAULT_COMPOUND_SHAPE_URL = ""; -const bool ZoneEntityItem::DEFAULT_FLYING_ALLOWED = true; -const bool ZoneEntityItem::DEFAULT_GHOSTING_ALLOWED = true; -const QString ZoneEntityItem::DEFAULT_FILTER_URL = ""; - -EntityItemPointer ZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { - std::shared_ptr entity(new ZoneEntityItem(entityID), [](ZoneEntityItem* ptr) { ptr->deleteLater(); }); - entity->setProperties(properties); - return entity; -} - -ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { - _type = EntityTypes::Zone; - - _shapeType = DEFAULT_SHAPE_TYPE; - _compoundShapeURL = DEFAULT_COMPOUND_SHAPE_URL; - _visuallyReady = false; -} - -EntityItemProperties ZoneEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { - EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class - - COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(compoundShapeURL, getCompoundShapeURL); - - // Contain QString properties, must be synchronized - withReadLock([&] { - _keyLightProperties.getProperties(properties); - _ambientLightProperties.getProperties(properties); - _skyboxProperties.getProperties(properties); - }); - _hazeProperties.getProperties(properties); - _bloomProperties.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(keyLightMode, getKeyLightMode); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(ambientLightMode, getAmbientLightMode); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(skyboxMode, getSkyboxMode); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(hazeMode, getHazeMode); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(bloomMode, getBloomMode); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(avatarPriority, getAvatarPriority); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(screenshare, getScreenshare); - - return properties; -} - -bool ZoneEntityItem::setSubClassProperties(const EntityItemProperties& properties) { - bool somethingChanged = false; - - SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, setShapeType); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL); - - // Contains a QString property, must be synchronized - withWriteLock([&] { - _keyLightPropertiesChanged |= _keyLightProperties.setProperties(properties); - _ambientLightPropertiesChanged |= _ambientLightProperties.setProperties(properties); - _skyboxPropertiesChanged |= _skyboxProperties.setProperties(properties); - }); - _hazePropertiesChanged |= _hazeProperties.setProperties(properties); - _bloomPropertiesChanged |= _bloomProperties.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(keyLightMode, setKeyLightMode); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(ambientLightMode, setAmbientLightMode); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(skyboxMode, setSkyboxMode); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(hazeMode, setHazeMode); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(bloomMode, setBloomMode); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(avatarPriority, setAvatarPriority); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(screenshare, setScreenshare); - - somethingChanged |= _keyLightPropertiesChanged || _ambientLightPropertiesChanged || - _skyboxPropertiesChanged || _hazePropertiesChanged || _bloomPropertiesChanged; - - return somethingChanged; -} - -int ZoneEntityItem::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_SHAPE_TYPE, ShapeType, setShapeType); - READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL); - - { - int bytesFromKeylight; - withWriteLock([&] { - bytesFromKeylight = _keyLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, _keyLightPropertiesChanged); - }); - somethingChanged |= _keyLightPropertiesChanged; - bytesRead += bytesFromKeylight; - dataAt += bytesFromKeylight; - } - - { - int bytesFromAmbientlight; - withWriteLock([&] { - bytesFromAmbientlight = _ambientLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, _ambientLightPropertiesChanged); - }); - somethingChanged |= _ambientLightPropertiesChanged; - bytesRead += bytesFromAmbientlight; - dataAt += bytesFromAmbientlight; - } - - { - int bytesFromSkybox; - withWriteLock([&] { - bytesFromSkybox = _skyboxProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, _skyboxPropertiesChanged); - }); - somethingChanged |= _skyboxPropertiesChanged; - bytesRead += bytesFromSkybox; - dataAt += bytesFromSkybox; - } - - { - int bytesFromHaze = _hazeProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, _hazePropertiesChanged); - somethingChanged |= _hazePropertiesChanged; - bytesRead += bytesFromHaze; - dataAt += bytesFromHaze; - } - - { - int bytesFromBloom = _bloomProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, - propertyFlags, overwriteLocalData, _bloomPropertiesChanged); - somethingChanged |= _bloomPropertiesChanged; - bytesRead += bytesFromBloom; - dataAt += bytesFromBloom; - } - - 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_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_HAZE_MODE, uint32_t, setHazeMode); - READ_ENTITY_PROPERTY(PROP_BLOOM_MODE, uint32_t, setBloomMode); - READ_ENTITY_PROPERTY(PROP_AVATAR_PRIORITY, uint32_t, setAvatarPriority); - READ_ENTITY_PROPERTY(PROP_SCREENSHARE, uint32_t, setScreenshare); - - return bytesRead; -} - -EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { - EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); - - requestedProperties += PROP_SHAPE_TYPE; - requestedProperties += PROP_COMPOUND_SHAPE_URL; - - requestedProperties += _keyLightProperties.getEntityProperties(params); - requestedProperties += _ambientLightProperties.getEntityProperties(params); - requestedProperties += _skyboxProperties.getEntityProperties(params); - requestedProperties += _hazeProperties.getEntityProperties(params); - requestedProperties += _bloomProperties.getEntityProperties(params); - - requestedProperties += PROP_FLYING_ALLOWED; - requestedProperties += PROP_GHOSTING_ALLOWED; - requestedProperties += PROP_FILTER_URL; - requestedProperties += PROP_AVATAR_PRIORITY; - requestedProperties += PROP_SCREENSHARE; - - requestedProperties += PROP_KEY_LIGHT_MODE; - requestedProperties += PROP_AMBIENT_LIGHT_MODE; - requestedProperties += PROP_SKYBOX_MODE; - requestedProperties += PROP_HAZE_MODE; - requestedProperties += PROP_BLOOM_MODE; - - return requestedProperties; -} - -void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, - EntityPropertyFlags& requestedProperties, - EntityPropertyFlags& propertyFlags, - EntityPropertyFlags& propertiesDidntFit, - int& propertyCount, - OctreeElement::AppendState& appendState) const { - - bool successPropertyFits = true; - - APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType()); - APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, getCompoundShapeURL()); - - withReadLock([&] { - _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_FLYING_ALLOWED, getFlyingAllowed()); - APPEND_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, getGhostingAllowed()); - APPEND_ENTITY_PROPERTY(PROP_FILTER_URL, getFilterURL()); - - 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_HAZE_MODE, (uint32_t)getHazeMode()); - APPEND_ENTITY_PROPERTY(PROP_BLOOM_MODE, (uint32_t)getBloomMode()); - APPEND_ENTITY_PROPERTY(PROP_AVATAR_PRIORITY, getAvatarPriority()); - APPEND_ENTITY_PROPERTY(PROP_SCREENSHARE, getScreenshare()); -} - -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::getComponentModeAsString(_hazeMode); - qCDebug(entities) << " _keyLightMode:" << EntityItemProperties::getComponentModeAsString(_keyLightMode); - qCDebug(entities) << " _ambientLightMode:" << EntityItemProperties::getComponentModeAsString(_ambientLightMode); - qCDebug(entities) << " _skyboxMode:" << EntityItemProperties::getComponentModeAsString(_skyboxMode); - qCDebug(entities) << " _bloomMode:" << EntityItemProperties::getComponentModeAsString(_bloomMode); - qCDebug(entities) << " _avatarPriority:" << getAvatarPriority(); - - _keyLightProperties.debugDump(); - _ambientLightProperties.debugDump(); - _skyboxProperties.debugDump(); - _hazeProperties.debugDump(); - _bloomProperties.debugDump(); -} - -void ZoneEntityItem::setShapeType(ShapeType type) { - switch(type) { - case SHAPE_TYPE_NONE: - case SHAPE_TYPE_CAPSULE_X: - case SHAPE_TYPE_CAPSULE_Y: - case SHAPE_TYPE_CAPSULE_Z: - case SHAPE_TYPE_HULL: - case SHAPE_TYPE_PLANE: - case SHAPE_TYPE_SIMPLE_HULL: - case SHAPE_TYPE_SIMPLE_COMPOUND: - case SHAPE_TYPE_STATIC_MESH: - case SHAPE_TYPE_CIRCLE: - // these types are unsupported for ZoneEntity - type = DEFAULT_SHAPE_TYPE; - break; - default: - break; - } - - ShapeType oldShapeType; - withWriteLock([&] { - oldShapeType = _shapeType; - _shapeType = type; - }); - - if (type == SHAPE_TYPE_COMPOUND) { - if (type != oldShapeType) { - fetchCollisionGeometryResource(); - } - } else { - _shapeResource.reset(); - } -} - -ShapeType ZoneEntityItem::getShapeType() const { - return resultWithReadLock([&] { - return _shapeType; - }); -} - -void ZoneEntityItem::setCompoundShapeURL(const QString& url) { - QString oldCompoundShapeURL; - ShapeType shapeType; - withWriteLock([&] { - oldCompoundShapeURL = _compoundShapeURL; - _compoundShapeURL = url; - shapeType = _shapeType; - }); - if (oldCompoundShapeURL != url) { - if (shapeType == SHAPE_TYPE_COMPOUND) { - fetchCollisionGeometryResource(); - } else { - _shapeResource.reset(); - } - } -} - -bool ZoneEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance, - BoxFace& face, glm::vec3& surfaceNormal, - QVariantMap& extraInfo, bool precisionPicking) const { - return _zonesArePickable; -} - -bool ZoneEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, - const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element, - float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, - QVariantMap& extraInfo, bool precisionPicking) const { - return _zonesArePickable; -} - -bool ZoneEntityItem::contains(const glm::vec3& point) const { - GeometryResource::Pointer resource = _shapeResource; - if (getShapeType() == SHAPE_TYPE_COMPOUND && resource) { - if (resource->isLoaded()) { - const HFMModel& hfmModel = resource->getHFMModel(); - - Extents meshExtents = hfmModel.getMeshExtents(); - glm::vec3 meshExtentsDiagonal = meshExtents.maximum - meshExtents.minimum; - glm::vec3 offset = -meshExtents.minimum - (meshExtentsDiagonal * getRegistrationPoint()); - glm::vec3 scale(getScaledDimensions() / meshExtentsDiagonal); - - glm::mat4 hfmToEntityMatrix = glm::scale(scale) * glm::translate(offset); - glm::mat4 entityToWorldMatrix = getTransform().getMatrix(); - glm::mat4 worldToHFMMatrix = glm::inverse(entityToWorldMatrix * hfmToEntityMatrix); - - return hfmModel.convexHullContains(glm::vec3(worldToHFMMatrix * glm::vec4(point, 1.0f))); - } - } - return EntityItem::contains(point); -} - -void ZoneEntityItem::setFilterURL(QString url) { - withWriteLock([&] { - _filterURL = url; - }); - if (DependencyManager::isSet()) { - auto entityEditFilters = DependencyManager::get(); - qCDebug(entities) << "adding filter " << url << "for zone" << getEntityItemID(); - entityEditFilters->addFilter(getEntityItemID(), url); - } -} - -QString ZoneEntityItem::getFilterURL() const { - QString result; - withReadLock([&] { - result = _filterURL; - }); - return result; -} - -QString ZoneEntityItem::getCompoundShapeURL() const { - QString result; - withReadLock([&] { - result = _compoundShapeURL; - }); - return result; -} - -void ZoneEntityItem::resetRenderingPropertiesChanged() { - withWriteLock([&] { - _keyLightPropertiesChanged = false; - _ambientLightPropertiesChanged = false; - _skyboxPropertiesChanged = false; - _hazePropertiesChanged = false; - _bloomPropertiesChanged = false; - }); -} - -void ZoneEntityItem::setHazeMode(const uint32_t value) { - if (value < COMPONENT_MODE_ITEM_COUNT && value != _hazeMode) { - _hazeMode = value; - _hazePropertiesChanged = true; - } -} - -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; - _keyLightPropertiesChanged = true; - } -} - -uint32_t ZoneEntityItem::getKeyLightMode() const { - return _keyLightMode; -} - -void ZoneEntityItem::setAmbientLightMode(const uint32_t value) { - if (value < COMPONENT_MODE_ITEM_COUNT && value != _ambientLightMode) { - _ambientLightMode = value; - _ambientLightPropertiesChanged = true; - } -} - -uint32_t ZoneEntityItem::getAmbientLightMode() const { - return _ambientLightMode; -} - -void ZoneEntityItem::setSkyboxMode(const uint32_t value) { - if (value < COMPONENT_MODE_ITEM_COUNT && value != _skyboxMode) { - _skyboxMode = value; - _skyboxPropertiesChanged = true; - } -} - -uint32_t ZoneEntityItem::getSkyboxMode() const { - return _skyboxMode; -} - -void ZoneEntityItem::setUserData(const QString& value) { - withWriteLock([&] { - _needsRenderUpdate |= _userData != value; - _userData = value; - }); -} - -void ZoneEntityItem::fetchCollisionGeometryResource() { - QUrl hullURL(getCompoundShapeURL()); - if (hullURL.isEmpty()) { - _shapeResource.reset(); - } else { - _shapeResource = DependencyManager::get()->getCollisionGeometryResource(hullURL); - } -} - -bool ZoneEntityItem::matchesJSONFilters(const QJsonObject& jsonFilters) const { - // currently the only property filter we handle in ZoneEntityItem is value of avatarPriority - - static const QString AVATAR_PRIORITY_PROPERTY = "avatarPriority"; - - // If set match zones of interest to avatar mixer: - if (jsonFilters.contains(AVATAR_PRIORITY_PROPERTY) && jsonFilters[AVATAR_PRIORITY_PROPERTY].toBool() - && (_avatarPriority != COMPONENT_MODE_INHERIT || _screenshare != COMPONENT_MODE_INHERIT)) { - return true; - } - - // Chain to base: - return EntityItem::matchesJSONFilters(jsonFilters); -} diff --git a/libraries/entities/src/ZoneEntityItem.cpp.in b/libraries/entities/src/ZoneEntityItem.cpp.in new file mode 100644 index 00000000000..e926f678cef --- /dev/null +++ b/libraries/entities/src/ZoneEntityItem.cpp.in @@ -0,0 +1,348 @@ +// +// ZoneEntityItem.cpp +// libraries/entities/src +// +// Created by Brad Hefta-Gaub on 12/4/13. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ZoneEntityItem.h" + +#include +#include + +#include + +#include "EntitiesLogging.h" +#include "EntityItemProperties.h" +#include "EntityTree.h" +#include "EntityTreeElement.h" +#include "EntityEditFilters.h" + +bool ZoneEntityItem::_zonesArePickable = false; +bool ZoneEntityItem::_drawZoneBoundaries = false; + + +const ShapeType ZoneEntityItem::DEFAULT_SHAPE_TYPE = SHAPE_TYPE_BOX; +const QString ZoneEntityItem::DEFAULT_COMPOUND_SHAPE_URL = ""; +const bool ZoneEntityItem::DEFAULT_FLYING_ALLOWED = true; +const bool ZoneEntityItem::DEFAULT_GHOSTING_ALLOWED = true; +const QString ZoneEntityItem::DEFAULT_FILTER_URL = ""; + +EntityItemPointer ZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { + std::shared_ptr entity(new ZoneEntityItem(entityID), [](ZoneEntityItem* ptr) { ptr->deleteLater(); }); + entity->setProperties(properties); + return entity; +} + +ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID) { + _type = EntityTypes::Zone; + + _shapeType = DEFAULT_SHAPE_TYPE; + _compoundShapeURL = DEFAULT_COMPOUND_SHAPE_URL; + _visuallyReady = false; +} + +EntityItemProperties ZoneEntityItem::getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const { + EntityItemProperties properties = EntityItem::getProperties(desiredProperties, allowEmptyDesiredProperties); // get the properties from our base class + +@Zone_ENTITY_COPY_TO@ + + return properties; +} + +bool ZoneEntityItem::setSubClassProperties(const EntityItemProperties& properties) { + bool somethingChanged = false; + +@Zone_ENTITY_SET_FROM@ + + somethingChanged |= _keyLightPropertiesChanged || _ambientLightPropertiesChanged || _skyboxPropertiesChanged || + _hazePropertiesChanged || _bloomPropertiesChanged || _tonemappingPropertiesChanged || + _ambientOcclusionPropertiesChanged; + + return somethingChanged; +} + +EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& params) const { + EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params); + +@Zone_REQUESTED_PROPS@ + + return requestedProperties; +} + +void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, + EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, + EntityPropertyFlags& requestedProperties, + EntityPropertyFlags& propertyFlags, + EntityPropertyFlags& propertiesDidntFit, + int& propertyCount, + OctreeElement::AppendState& appendState) const { + + bool successPropertyFits = true; + +@Zone_ENTITY_APPEND@ + +} + +int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, + ReadBitstreamToTreeParams& args, + EntityPropertyFlags& propertyFlags, bool overwriteLocalData, + bool& somethingChanged) { + int bytesRead = 0; + const unsigned char* dataAt = data; + +@Zone_ENTITY_READ@ + + return bytesRead; +} + +void ZoneEntityItem::debugDump() const { + qCDebug(entities) << "ZoneEntityItem id:" << getEntityItemID() << "---------------------------------------------"; + qCDebug(entities) << " name:" << _name; + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); + qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions()); + qCDebug(entities) << " editedAgo:" << debugTime(getLastEdited(), usecTimestampNow()); + qCDebug(entities) << " pointer:" << this; + +@Zone_ENTITY_DEBUG@ + +} + +void ZoneEntityItem::setShapeType(ShapeType type) { + switch(type) { + case SHAPE_TYPE_NONE: + case SHAPE_TYPE_CAPSULE_X: + case SHAPE_TYPE_CAPSULE_Y: + case SHAPE_TYPE_CAPSULE_Z: + case SHAPE_TYPE_HULL: + case SHAPE_TYPE_PLANE: + case SHAPE_TYPE_SIMPLE_HULL: + case SHAPE_TYPE_SIMPLE_COMPOUND: + case SHAPE_TYPE_STATIC_MESH: + case SHAPE_TYPE_CIRCLE: + // these types are unsupported for ZoneEntity + type = DEFAULT_SHAPE_TYPE; + break; + default: + break; + } + + ShapeType oldShapeType; + withWriteLock([&] { + oldShapeType = _shapeType; + _shapeType = type; + }); + + if (type == SHAPE_TYPE_COMPOUND) { + if (type != oldShapeType) { + fetchCollisionGeometryResource(); + } + } else { + _shapeResource.reset(); + } +} + +ShapeType ZoneEntityItem::getShapeType() const { + return resultWithReadLock([&] { + return _shapeType; + }); +} + +void ZoneEntityItem::setCompoundShapeURL(const QString& url) { + QString oldCompoundShapeURL; + ShapeType shapeType; + withWriteLock([&] { + oldCompoundShapeURL = _compoundShapeURL; + _compoundShapeURL = url; + shapeType = _shapeType; + }); + if (oldCompoundShapeURL != url) { + if (shapeType == SHAPE_TYPE_COMPOUND) { + fetchCollisionGeometryResource(); + } else { + _shapeResource.reset(); + } + } +} + +bool ZoneEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + const glm::vec3& viewFrustumPos, OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, + QVariantMap& extraInfo, bool precisionPicking) const { + return _zonesArePickable; +} + +bool ZoneEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, + const glm::vec3& acceleration, const glm::vec3& viewFrustumPos, OctreeElementPointer& element, + float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, + QVariantMap& extraInfo, bool precisionPicking) const { + return _zonesArePickable; +} + +bool ZoneEntityItem::contains(const glm::vec3& point) const { + GeometryResource::Pointer resource = _shapeResource; + if (getShapeType() == SHAPE_TYPE_COMPOUND && resource) { + if (resource->isLoaded()) { + const HFMModel& hfmModel = resource->getHFMModel(); + + Extents meshExtents = hfmModel.getMeshExtents(); + glm::vec3 meshExtentsDiagonal = meshExtents.maximum - meshExtents.minimum; + glm::vec3 offset = -meshExtents.minimum - (meshExtentsDiagonal * getRegistrationPoint()); + glm::vec3 scale(getScaledDimensions() / meshExtentsDiagonal); + + glm::mat4 hfmToEntityMatrix = glm::scale(scale) * glm::translate(offset); + glm::mat4 entityToWorldMatrix = getTransform().getMatrix(); + glm::mat4 worldToHFMMatrix = glm::inverse(entityToWorldMatrix * hfmToEntityMatrix); + + return hfmModel.convexHullContains(glm::vec3(worldToHFMMatrix * glm::vec4(point, 1.0f))); + } + } + return EntityItem::contains(point); +} + +void ZoneEntityItem::setFilterURL(const QString& url) { + withWriteLock([&] { + _filterURL = url; + }); + if (DependencyManager::isSet()) { + auto entityEditFilters = DependencyManager::get(); + qCDebug(entities) << "adding filter " << url << "for zone" << getEntityItemID(); + entityEditFilters->addFilter(getEntityItemID(), url); + } +} + +QString ZoneEntityItem::getFilterURL() const { + return resultWithReadLock([&] { + return _filterURL; + }); +} + +QString ZoneEntityItem::getCompoundShapeURL() const { + return resultWithReadLock([&] { + return _compoundShapeURL; + }); +} + +void ZoneEntityItem::resetRenderingPropertiesChanged() { + withWriteLock([&] { + _keyLightPropertiesChanged = false; + _ambientLightPropertiesChanged = false; + _skyboxPropertiesChanged = false; + _hazePropertiesChanged = false; + _bloomPropertiesChanged = false; + _tonemappingPropertiesChanged = false; + _ambientOcclusionPropertiesChanged = false; + }); +} + +void ZoneEntityItem::setSkyboxMode(const uint8_t value) { + if (value < COMPONENT_MODE_ITEM_COUNT && value != _skyboxMode) { + _skyboxMode = value; + _skyboxPropertiesChanged = true; + } +} + +uint8_t ZoneEntityItem::getSkyboxMode() const { + return _skyboxMode; +} + +void ZoneEntityItem::setKeyLightMode(const uint8_t value) { + if (value < COMPONENT_MODE_ITEM_COUNT && value != _keyLightMode) { + _keyLightMode = value; + _keyLightPropertiesChanged = true; + } +} + +uint8_t ZoneEntityItem::getKeyLightMode() const { + return _keyLightMode; +} + +void ZoneEntityItem::setAmbientLightMode(const uint8_t value) { + if (value < COMPONENT_MODE_ITEM_COUNT && value != _ambientLightMode) { + _ambientLightMode = value; + _ambientLightPropertiesChanged = true; + } +} + +uint8_t ZoneEntityItem::getAmbientLightMode() const { + return _ambientLightMode; +} + +void ZoneEntityItem::setHazeMode(const uint8_t value) { + if (value < COMPONENT_MODE_ITEM_COUNT && value != _hazeMode) { + _hazeMode = value; + _hazePropertiesChanged = true; + } +} + +uint8_t ZoneEntityItem::getHazeMode() const { + return _hazeMode; +} + +void ZoneEntityItem::setBloomMode(const uint8_t value) { + if (value < COMPONENT_MODE_ITEM_COUNT && value != _bloomMode) { + _bloomMode = value; + _bloomPropertiesChanged = true; + } +} + +uint8_t ZoneEntityItem::getBloomMode() const { + return _bloomMode; +} + +void ZoneEntityItem::setTonemappingMode(const uint8_t value) { + if (value < COMPONENT_MODE_ITEM_COUNT && value != _tonemappingMode) { + _tonemappingMode = value; + _tonemappingPropertiesChanged = true; + } +} + +uint8_t ZoneEntityItem::getTonemappingMode() const { + return _tonemappingMode; +} + +void ZoneEntityItem::setAmbientOcclusionMode(const uint8_t value) { + if (value < COMPONENT_MODE_ITEM_COUNT && value != _ambientOcclusionMode) { + _ambientOcclusionMode = value; + _ambientOcclusionPropertiesChanged = true; + } +} + +uint8_t ZoneEntityItem::getAmbientOcclusionMode() const { + return _ambientOcclusionMode; +} + +void ZoneEntityItem::setUserData(const QString& value) { + withWriteLock([&] { + _needsRenderUpdate |= _userData != value; + _userData = value; + }); +} + +void ZoneEntityItem::fetchCollisionGeometryResource() { + QUrl hullURL(getCompoundShapeURL()); + if (hullURL.isEmpty()) { + _shapeResource.reset(); + } else { + _shapeResource = DependencyManager::get()->getCollisionGeometryResource(hullURL); + } +} + +bool ZoneEntityItem::matchesJSONFilters(const QJsonObject& jsonFilters) const { + // currently the only property filter we handle in ZoneEntityItem is value of avatarPriority + + static const QString AVATAR_PRIORITY_PROPERTY = "avatarPriority"; + + // If set match zones of interest to avatar mixer: + if (jsonFilters.contains(AVATAR_PRIORITY_PROPERTY) && jsonFilters[AVATAR_PRIORITY_PROPERTY].toBool() + && (_avatarPriority != COMPONENT_MODE_INHERIT || _screenshare != COMPONENT_MODE_INHERIT)) { + return true; + } + + // Chain to base: + return EntityItem::matchesJSONFilters(jsonFilters); +} diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h.in similarity index 54% rename from libraries/entities/src/ZoneEntityItem.h rename to libraries/entities/src/ZoneEntityItem.h.in index 2b61bbd346e..7da10c3c2a6 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h.in @@ -22,6 +22,9 @@ #include "SkyboxPropertyGroup.h" #include "HazePropertyGroup.h" #include "BloomPropertyGroup.h" +#include "ZoneAudioPropertyGroup.h" +#include "TonemappingPropertyGroup.h" +#include "AmbientOcclusionPropertyGroup.h" class ZoneEntityItem : public EntityItem { public: @@ -30,27 +33,7 @@ class ZoneEntityItem : public EntityItem { ZoneEntityItem(const EntityItemID& entityItemID); ALLOW_INSTANTIATION // This class can be instantiated - - // methods for getting/setting all properties of an entity - virtual EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, bool allowEmptyDesiredProperties) const override; - virtual bool setSubClassProperties(const EntityItemProperties& properties) override; - - virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; - - virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, - EntityTreeElementExtraEncodeDataPointer modelTreeElementExtraEncodeData, - 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; - - + ENTITY_PROPERTY_SUBCLASS_METHODS static bool getZonesArePickable() { return _zonesArePickable; } static void setZonesArePickable(bool value) { _zonesArePickable = value; } @@ -63,46 +46,16 @@ class ZoneEntityItem : public EntityItem { virtual ShapeType getShapeType() const override; bool shouldBePhysical() const override { return false; } - QString getCompoundShapeURL() const; - virtual void setCompoundShapeURL(const QString& url); - virtual bool matchesJSONFilters(const QJsonObject& jsonFilters) const override; + SkyboxPropertyGroup getSkyboxProperties() const { return resultWithReadLock([&] { return _skyboxProperties; }); } KeyLightPropertyGroup getKeyLightProperties() const { return resultWithReadLock([&] { return _keyLightProperties; }); } AmbientLightPropertyGroup getAmbientLightProperties() const { return resultWithReadLock([&] { return _ambientLightProperties; }); } - - void setHazeMode(const uint32_t value); - uint32_t getHazeMode() const; - - void setKeyLightMode(uint32_t value); - uint32_t getKeyLightMode() const; - - void setAmbientLightMode(uint32_t value); - uint32_t getAmbientLightMode() const; - - void setSkyboxMode(uint32_t value); - uint32_t getSkyboxMode() const; - - void setBloomMode(const uint32_t value); - uint32_t getBloomMode() const; - - SkyboxPropertyGroup getSkyboxProperties() const { return resultWithReadLock([&] { 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; } - bool getGhostingAllowed() const { return _ghostingAllowed; } - void setGhostingAllowed(bool value) { _ghostingAllowed = value; } - QString getFilterURL() const; - void setFilterURL(const QString url); - - uint32_t getAvatarPriority() const { return _avatarPriority; } - void setAvatarPriority(uint32_t value) { _avatarPriority = value; } - - uint32_t getScreenshare() const { return _screenshare; } - void setScreenshare(uint32_t value) { _screenshare = value; } + const ZoneAudioPropertyGroup& getAudioProperties() const { return _audioProperties; } + const TonemappingPropertyGroup& getTonemappingProperties() const { return _tonemappingProperties; } + const AmbientOcclusionPropertyGroup& getAmbientOcclusionProperties() const { return _ambientOcclusionProperties; } void setUserData(const QString& value) override; @@ -111,6 +64,8 @@ class ZoneEntityItem : public EntityItem { bool skyboxPropertiesChanged() const { return _skyboxPropertiesChanged; } bool hazePropertiesChanged() const { return _hazePropertiesChanged; } bool bloomPropertiesChanged() const { return _bloomPropertiesChanged; } + bool tonemappingPropertiesChanged() const { return _tonemappingPropertiesChanged; } + bool ambientOcclusionPropertiesChanged() const { return _ambientOcclusionPropertiesChanged; } void resetRenderingPropertiesChanged(); @@ -126,8 +81,6 @@ class ZoneEntityItem : public EntityItem { bool contains(const glm::vec3& point) const override; - virtual void debugDump() const override; - static const ShapeType DEFAULT_SHAPE_TYPE; static const QString DEFAULT_COMPOUND_SHAPE_URL; static const bool DEFAULT_FLYING_ALLOWED; @@ -135,40 +88,17 @@ class ZoneEntityItem : public EntityItem { static const QString DEFAULT_FILTER_URL; protected: - KeyLightPropertyGroup _keyLightProperties; - AmbientLightPropertyGroup _ambientLightProperties; - - ShapeType _shapeType { DEFAULT_SHAPE_TYPE }; - QString _compoundShapeURL; - - // The following 3 values are the defaults for zone creation - uint32_t _keyLightMode { COMPONENT_MODE_INHERIT }; - uint32_t _skyboxMode { COMPONENT_MODE_INHERIT }; - 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 }; - QString _filterURL { DEFAULT_FILTER_URL }; - - // Avatar-updates priority - uint32_t _avatarPriority { COMPONENT_MODE_INHERIT }; - // Screen-sharing zone - uint32_t _screenshare { COMPONENT_MODE_INHERIT }; +@Zone_ENTITY_PROPS@ // Dirty flags turn true when either keylight properties is changing values. bool _keyLightPropertiesChanged { false }; bool _ambientLightPropertiesChanged { false }; bool _skyboxPropertiesChanged { false }; - bool _hazePropertiesChanged{ false }; + bool _hazePropertiesChanged { false }; bool _bloomPropertiesChanged { false }; + bool _tonemappingPropertiesChanged { false }; + bool _ambientOcclusionPropertiesChanged { false }; static bool _drawZoneBoundaries; static bool _zonesArePickable; diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp index 47861d4f808..86b0df982ae 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp @@ -81,6 +81,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::gl::GLBackend::do_disableContextViewCorrection), (&::gpu::gl::GLBackend::do_restoreContextViewCorrection), + (&::gpu::gl::GLBackend::do_setContextMirrorViewCorrection), (&::gpu::gl::GLBackend::do_disableContextStereo), (&::gpu::gl::GLBackend::do_restoreContextStereo), @@ -346,6 +347,7 @@ void GLBackend::renderPassTransfer(const Batch& batch) { case Batch::COMMAND_setViewTransform: case Batch::COMMAND_setProjectionTransform: case Batch::COMMAND_setProjectionJitter: + case Batch::COMMAND_setContextMirrorViewCorrection: { CommandCall call = _commandCalls[(*command)]; (this->*(call))(batch, *offset); @@ -411,6 +413,7 @@ void GLBackend::renderPassDraw(const Batch& batch) { case Batch::COMMAND_setProjectionJitter: case Batch::COMMAND_setViewportTransform: case Batch::COMMAND_setDepthRangeTransform: + case Batch::COMMAND_setContextMirrorViewCorrection: { PROFILE_RANGE(render_gpu_gl_detail, "transform"); CommandCall call = _commandCalls[(*command)]; @@ -617,6 +620,16 @@ void GLBackend::do_restoreContextViewCorrection(const Batch& batch, size_t param _transform._viewCorrectionEnabled = true; } +void GLBackend::do_setContextMirrorViewCorrection(const Batch& batch, size_t paramOffset) { + bool prevMirrorViewCorrection = _transform._mirrorViewCorrection; + _transform._mirrorViewCorrection = batch._params[paramOffset]._uint != 0; + + if (_transform._correction.correction != glm::mat4()) { + setCameraCorrection(_transform._mirrorViewCorrection ? _transform._flippedCorrection : _transform._unflippedCorrection, _transform._correction.prevView, false); + _transform._invalidView = true; + } +} + void GLBackend::do_disableContextStereo(const Batch& batch, size_t paramOffset) { } @@ -979,15 +992,29 @@ void GLBackend::recycle() const { _textureManagement._transferEngine->manageMemory(); } -void GLBackend::setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset) { +void GLBackend::setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool primary, bool reset) { auto invCorrection = glm::inverse(correction); auto invPrevView = glm::inverse(prevRenderView); _transform._correction.prevView = (reset ? Mat4() : prevRenderView); _transform._correction.prevViewInverse = (reset ? Mat4() : invPrevView); _transform._correction.correction = correction; _transform._correction.correctionInverse = invCorrection; - _pipeline._cameraCorrectionBuffer._buffer->setSubData(0, _transform._correction); - _pipeline._cameraCorrectionBuffer._buffer->flush(); + + if (!_inRenderTransferPass) { + _pipeline._cameraCorrectionBuffer._buffer->setSubData(0, _transform._correction); + _pipeline._cameraCorrectionBuffer._buffer->flush(); + } + + if (primary) { + _transform._unflippedCorrection = _transform._correction.correction; + quat flippedRotation = glm::quat_cast(_transform._unflippedCorrection); + flippedRotation.y *= -1.0f; + flippedRotation.z *= -1.0f; + vec3 flippedTranslation = _transform._unflippedCorrection[3]; + flippedTranslation.x *= -1.0f; + _transform._flippedCorrection = glm::translate(glm::mat4_cast(flippedRotation), flippedTranslation); + _transform._mirrorViewCorrection = false; + } } void GLBackend::syncProgram(const gpu::ShaderPointer& program) { diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h index 73e99ce1acd..8a1648a01b5 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h @@ -121,7 +121,7 @@ class GLBackend : public Backend, public std::enable_shared_from_this // Shutdown rendering and persist any required resources void shutdown() override; - void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset = false) override; + void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool primary, bool reset = false) override; void render(const Batch& batch) final override; // This call synchronize the Full Backend cache with the current GLState @@ -211,6 +211,7 @@ class GLBackend : public Backend, public std::enable_shared_from_this virtual void do_disableContextViewCorrection(const Batch& batch, size_t paramOffset) final; virtual void do_restoreContextViewCorrection(const Batch& batch, size_t paramOffset) final; + virtual void do_setContextMirrorViewCorrection(const Batch& batch, size_t paramOffset) final; virtual void do_disableContextStereo(const Batch& batch, size_t paramOffset) final; virtual void do_restoreContextStereo(const Batch& batch, size_t paramOffset) final; @@ -427,6 +428,9 @@ class GLBackend : public Backend, public std::enable_shared_from_this Transform _view; CameraCorrection _correction; bool _viewCorrectionEnabled{ true }; + mat4 _unflippedCorrection; + mat4 _flippedCorrection; + bool _mirrorViewCorrection{ false }; Mat4 _projection; Vec4i _viewport{ 0, 0, 1, 1 }; diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index 3654dfca5d0..bd4aef97689 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -464,6 +464,12 @@ void Batch::restoreContextViewCorrection() { ADD_COMMAND(restoreContextViewCorrection); } +void Batch::setContextMirrorViewCorrection(bool shouldMirror) { + ADD_COMMAND(setContextMirrorViewCorrection); + uint mirrorFlag = shouldMirror ? 1 : 0; + _params.emplace_back(mirrorFlag); +} + void Batch::disableContextStereo() { ADD_COMMAND(disableContextStereo); } diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 0b43cfe927d..3cf8184913a 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -239,6 +239,7 @@ class Batch { void disableContextViewCorrection(); void restoreContextViewCorrection(); + void setContextMirrorViewCorrection(bool shouldMirror); void disableContextStereo(); void restoreContextStereo(); @@ -338,6 +339,7 @@ class Batch { COMMAND_disableContextViewCorrection, COMMAND_restoreContextViewCorrection, + COMMAND_setContextMirrorViewCorrection, COMMAND_disableContextStereo, COMMAND_restoreContextStereo, diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h index 1946f447f8f..ebc81f14e9e 100644 --- a/libraries/gpu/src/gpu/Context.h +++ b/libraries/gpu/src/gpu/Context.h @@ -66,7 +66,7 @@ class Backend { virtual void syncProgram(const gpu::ShaderPointer& program) = 0; virtual void recycle() const = 0; virtual void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) = 0; - virtual void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool reset = false) {} + virtual void setCameraCorrection(const Mat4& correction, const Mat4& prevRenderView, bool primary, bool reset = false) {} virtual bool supportedTextureFormat(const gpu::Element& format) = 0; diff --git a/libraries/gpu/src/gpu/FrameIOKeys.h b/libraries/gpu/src/gpu/FrameIOKeys.h index 4cb7c6085d2..5a5cfdf2b14 100644 --- a/libraries/gpu/src/gpu/FrameIOKeys.h +++ b/libraries/gpu/src/gpu/FrameIOKeys.h @@ -181,6 +181,7 @@ constexpr const char* COMMAND_NAMES[] = { "disableContextViewCorrection", "restoreContextViewCorrection", + "setContextMirrorViewCorrection", "disableContextStereo", "restoreContextStereo", diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index 3015de7e0e8..767db13595c 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -246,6 +246,16 @@ TransformObject getTransformObject() { } <@endfunc@> +<@func transformWorldToEyeAndClipPos(cameraTransform, worldPos, eyePos, clipPos)@> + { // transformWorldToEyeAndClipPos + vec4 eyeWAPos = <$worldPos$> - vec4(<$cameraTransform$>._viewInverse[3].xyz, 0.0); + <$eyePos$> = vec4((<$cameraTransform$>._view * vec4(eyeWAPos.xyz, 0.0)).xyz, 1.0); + <$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * eyeWAPos; + + <$transformStereoClipsSpace($cameraTransform$, $clipPos$)$> + } +<@endfunc@> + <@func transformModelToWorldPos(objectTransform, modelPos, worldPos)@> { // transformModelToWorldPos <$worldPos$> = (<$objectTransform$>._model * <$modelPos$>); diff --git a/libraries/graphics/src/graphics/AmbientOcclusion.h b/libraries/graphics/src/graphics/AmbientOcclusion.h new file mode 100644 index 00000000000..66a1ad0ea7a --- /dev/null +++ b/libraries/graphics/src/graphics/AmbientOcclusion.h @@ -0,0 +1,59 @@ +// +// AmbientOcclusion.h +// libraries/graphics/src/graphics +// +// Created by HifiExperiments 6/24/24 +// Copyright 2024 Overte e.V. +// +// 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_AmbientOcclusion_h +#define hifi_model_AmbientOcclusion_h + +#include + +#include + +namespace graphics { + class AmbientOcclusion { + public: + AmbientOcclusion() {} + + void setTechnique(const AmbientOcclusionTechnique technique) { _technique = technique; } + void setJitter(const bool jitter) { _jitter = jitter; } + void setResolutionLevel(const uint8_t resolutionLevel) { _resolutionLevel = resolutionLevel; } + void setEdgeSharpness(const float edgeSharpness) { _edgeSharpness = edgeSharpness; } + void setBlurRadius(const uint8_t blurRadius) { _blurRadius = blurRadius; } + void setAORadius(const float aoRadius) { _aoRadius = aoRadius; } + void setAOObscuranceLevel(const float aoObscuranceLevel) { _aoObscuranceLevel = aoObscuranceLevel; } + void setAOFalloffAngle(const float aoFalloffAngle) { _aoFalloffAngle = aoFalloffAngle; } + void setAOSamplingAmount(const float aoSamplingAmount) { _aoSamplingAmount = aoSamplingAmount; } + void setSSAONumSpiralTurns(const float ssaoNumSpiralTurns) { _ssaoNumSpiralTurns = ssaoNumSpiralTurns; } + + AmbientOcclusionTechnique getTechnique() const { return _technique; } + bool getJitter() const { return _jitter; } + uint8_t getResolutionLevel() const { return _resolutionLevel; } + float getEdgeSharpness() const { return _edgeSharpness; } + uint8_t getBlurRadius() const { return _blurRadius; } + float getAORadius() const { return _aoRadius; } + float getAOObscuranceLevel() const { return _aoObscuranceLevel; } + float getAOFalloffAngle() const { return _aoFalloffAngle; } + float getAOSamplingAmount() const { return _aoSamplingAmount; } + float getSSAONumSpiralTurns() const { return _ssaoNumSpiralTurns; } + + private: + AmbientOcclusionTechnique _technique { AmbientOcclusionTechnique::SSAO }; + bool _jitter { false }; + uint8_t _resolutionLevel { 2 }; + float _edgeSharpness { 1.0f }; + uint8_t _blurRadius { 4 }; + float _aoRadius { 1.0f }; + float _aoObscuranceLevel { 0.5f }; + float _aoFalloffAngle { 0.25f }; + float _aoSamplingAmount { 0.5f }; + float _ssaoNumSpiralTurns { 7.0f }; + }; + using AmbientOcclusionPointer = std::shared_ptr; +} +#endif // hifi_model_AmbientOcclusion_h diff --git a/libraries/graphics/src/graphics/Light.cpp b/libraries/graphics/src/graphics/Light.cpp index fb14783b4e9..abdfd526176 100644 --- a/libraries/graphics/src/graphics/Light.cpp +++ b/libraries/graphics/src/graphics/Light.cpp @@ -4,6 +4,7 @@ // // Created by Sam Gateau on 1/26/2014. // Copyright 2014 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -156,6 +157,10 @@ void Light::setSpotExponent(float exponent) { _lightSchemaBuffer.edit().irradiance.falloffSpot = exponent; } +void Light::setAmbientColor(vec3 color) { + _ambientSchemaBuffer.edit().color = color; +} + void Light::setAmbientIntensity(float intensity) { _ambientSchemaBuffer.edit().intensity = intensity; } @@ -187,3 +192,18 @@ void Light::setTransform(const glm::mat4& transform) { } } +const Light::AmbientSchemaBuffer& Light::getAmbientSchemaBuffer() { + auto blend = 0.0f; + if (getAmbientMap() && getAmbientMap()->isDefined()) { + blend = 0.5f; + + // If pitch black neutralize the color + if (glm::all(glm::equal(getAmbientColor(), glm::vec3(0.0f)))) { + blend = 1.0f; + } + } + + _ambientSchemaBuffer.edit().blend = blend; + + return _ambientSchemaBuffer; +} diff --git a/libraries/graphics/src/graphics/Light.h b/libraries/graphics/src/graphics/Light.h index 81a6fddbd35..cb09e17786b 100644 --- a/libraries/graphics/src/graphics/Light.h +++ b/libraries/graphics/src/graphics/Light.h @@ -4,6 +4,7 @@ // // Created by Sam Gateau on 12/10/2014. // Copyright 2014 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -143,7 +144,9 @@ class Light { void setSpotExponent(float exponent); float getSpotExponent() const { return _lightSchemaBuffer->irradiance.falloffSpot; } - // If the light has an ambient (Indirect) component, then the Ambientintensity can be used to control its contribution to the lighting + // If the light has an ambient (Indirect) component, then the AmbientColor and AmbientIntensity can be used to control its contribution to the lighting + void setAmbientColor(vec3 color); + vec3 getAmbientColor() const { return _ambientSchemaBuffer->color; } void setAmbientIntensity(float intensity); float getAmbientIntensity() const { return _ambientSchemaBuffer->intensity; } @@ -169,6 +172,9 @@ class Light { class AmbientSchema { public: + vec3 color { 0.0f }; + float blend { 0.0f }; + float intensity { 0.0f }; float mapNumMips { 0.0f }; float spare1; @@ -182,7 +188,7 @@ class Light { using AmbientSchemaBuffer = gpu::StructBuffer; const LightSchemaBuffer& getLightSchemaBuffer() const { return _lightSchemaBuffer; } - const AmbientSchemaBuffer& getAmbientSchemaBuffer() const { return _ambientSchemaBuffer; } + const AmbientSchemaBuffer& getAmbientSchemaBuffer(); // This also updates the blend factor to make sure it's current protected: diff --git a/libraries/graphics/src/graphics/Light.slh b/libraries/graphics/src/graphics/Light.slh index c00bfea6a26..d8ce697b981 100644 --- a/libraries/graphics/src/graphics/Light.slh +++ b/libraries/graphics/src/graphics/Light.slh @@ -4,6 +4,7 @@ // // Created by Sam Gateau on 1/25/14. // Copyright 2013 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -15,7 +16,16 @@ <@include graphics/LightVolume.shared.slh@> <@include graphics/LightIrradiance.shared.slh@> -// NOw lets define Light +// FIXME: For legacy reasons, when blend is 0.5, this is equivalent to: +// color * texel +// It should actually be: +// mix(color, texel, blend) +// and the blend factor should be user controlled +vec3 applySkyboxColorMix(vec3 texel, vec3 color, float blend) { + return mix(vec3(1.0), texel, float(blend > 0.0)) * mix(vec3(1.0), color, float(blend < 1.0)); +} + +// Now let's define Light struct Light { LightVolume volume; LightIrradiance irradiance; @@ -35,17 +45,19 @@ vec3 getLightIrradiance(Light l) { return lightIrradiance_getIrradiance(l.irradi // Light Ambient struct LightAmbient { - vec4 _ambient; + vec4 _ambientColor; + vec4 _ambientInfo; SphericalHarmonics _ambientSphere; mat4 transform; }; SphericalHarmonics getLightAmbientSphere(LightAmbient l) { return l._ambientSphere; } - -float getLightAmbientIntensity(LightAmbient l) { return l._ambient.x; } -bool getLightHasAmbientMap(LightAmbient l) { return l._ambient.y > 0.0; } -float getLightAmbientMapNumMips(LightAmbient l) { return l._ambient.y; } +vec3 getLightAmbientColor(LightAmbient l) { return l._ambientColor.xyz; } +float getLightAmbientBlend(LightAmbient l) { return l._ambientColor.w; } +float getLightAmbientIntensity(LightAmbient l) { return l._ambientInfo.x; } +bool getLightHasAmbientMap(LightAmbient l) { return l._ambientInfo.y > 0.0; } +float getLightAmbientMapNumMips(LightAmbient l) { return l._ambientInfo.y; } <@func declareLightBuffer(N)@> @@ -71,10 +83,6 @@ Light getKeyLight() { <@endfunc@> - - - - <@func declareLightAmbientBuffer(N)@> <@if N@> diff --git a/libraries/graphics/src/graphics/ShaderConstants.h b/libraries/graphics/src/graphics/ShaderConstants.h index 237c780a601..75eb4d00ccf 100644 --- a/libraries/graphics/src/graphics/ShaderConstants.h +++ b/libraries/graphics/src/graphics/ShaderConstants.h @@ -28,6 +28,7 @@ #define GRAPHICS_TEXTURE_MATERIAL_ROUGHNESS 4 #define GRAPHICS_TEXTURE_MATERIAL_OCCLUSION 5 #define GRAPHICS_TEXTURE_MATERIAL_SCATTERING 6 +#define GRAPHICS_TEXTURE_MATERIAL_MIRROR 1 // Mirrors use albedo textures, but nothing else // Keep aligned with procedural/ProceduralMaterialCache.h #define GRAPHICS_TEXTURE_MATERIAL_SHADE GRAPHICS_TEXTURE_MATERIAL_METALLIC @@ -67,6 +68,7 @@ enum Texture { MaterialRoughness = GRAPHICS_TEXTURE_MATERIAL_ROUGHNESS, MaterialOcclusion = GRAPHICS_TEXTURE_MATERIAL_OCCLUSION, MaterialScattering = GRAPHICS_TEXTURE_MATERIAL_SCATTERING, + MaterialMirror = GRAPHICS_TEXTURE_MATERIAL_MIRROR, Skybox = GRAPHICS_TEXTURE_SKYBOX, MaterialShade = GRAPHICS_TEXTURE_MATERIAL_SHADE, diff --git a/libraries/graphics/src/graphics/Tonemapping.h b/libraries/graphics/src/graphics/Tonemapping.h new file mode 100644 index 00000000000..ad7467d1319 --- /dev/null +++ b/libraries/graphics/src/graphics/Tonemapping.h @@ -0,0 +1,35 @@ +// +// Tonemapping.h +// libraries/graphics/src/graphics +// +// Created by HifiExperiments on 6/24/24 +// Copyright 2024 Overte e.V. +// +// 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_Tonemapping_h +#define hifi_model_Tonemapping_h + +#include + +#include + +namespace graphics { + class Tonemapping { + public: + Tonemapping() {} + + void setCurve(const TonemappingCurve curve) { _curve = curve; } + void setExposure(const float exposure) { _exposure = exposure; } + + TonemappingCurve getCurve() const { return _curve; } + float getExposure() const { return _exposure; } + + private: + TonemappingCurve _curve { TonemappingCurve::SRGB }; + float _exposure { 0.0f }; + }; + using TonemappingPointer = std::shared_ptr; +} +#endif // hifi_model_Tonemapping_h diff --git a/libraries/graphics/src/graphics/skybox.slf b/libraries/graphics/src/graphics/skybox.slf index 4ae53a657f6..2d5ba4d26b2 100755 --- a/libraries/graphics/src/graphics/skybox.slf +++ b/libraries/graphics/src/graphics/skybox.slf @@ -5,17 +5,18 @@ // // Created by Sam Gateau on 5/5/2015. // Copyright 2015 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // <@include graphics/ShaderConstants.h@> +<@include graphics/Light.slh@> <@if HIFI_USE_FORWARD@> <@include gpu/Transform.slh@> <$declareStandardCameraTransform()$> - <@include graphics/Light.slh@> <$declareLightBuffer()$> <@include graphics/Haze.slh@> @@ -35,17 +36,10 @@ layout(location=0) in vec3 _normal; layout(location=0) out vec4 _fragColor; void main(void) { - // FIXME: For legacy reasons, when skybox.color.a is 0.5, this is equivalent to: - // skyboxColor * skyboxTexel - // It should actually be: - // mix(skyboxColor, skyboxTexel, skybox.color.a) - // and the blend factor should be user controlled - vec3 normal = normalize(_normal); vec3 skyboxTexel = texture(cubeMap, normal).rgb; vec3 skyboxColor = skybox.color.rgb; - _fragColor = vec4(mix(vec3(1.0), skyboxTexel, float(skybox.color.a > 0.0)) * - mix(vec3(1.0), skyboxColor, float(skybox.color.a < 1.0)), 1.0); + _fragColor = vec4(applySkyboxColorMix(skyboxTexel, skyboxColor, skybox.color.a), 1.0); <@if HIFI_USE_FORWARD@> // FIXME: either move this elsewhere or give it access to isHazeEnabled() (which is in render-utils/LightingModel.slh) diff --git a/libraries/material-networking/src/material-networking/TextureCache.cpp b/libraries/material-networking/src/material-networking/TextureCache.cpp index 496b00ae2cb..840fa50a0a9 100644 --- a/libraries/material-networking/src/material-networking/TextureCache.cpp +++ b/libraries/material-networking/src/material-networking/TextureCache.cpp @@ -448,9 +448,9 @@ void NetworkTexture::setExtra(void* extra) { _shouldFailOnRedirect = _currentlyLoadingResourceType != ResourceType::KTX; if (_type == image::TextureUsage::SKY_TEXTURE) { - setLoadPriority(this, SKYBOX_LOAD_PRIORITY); + setLoadPriorityOperator(this, []() { return SKYBOX_LOAD_PRIORITY; }); } else if (_currentlyLoadingResourceType == ResourceType::KTX) { - setLoadPriority(this, HIGH_MIPS_LOAD_PRIORITY); + setLoadPriorityOperator(this, []() { return HIGH_MIPS_LOAD_PRIORITY; }); } if (!_url.isValid()) { @@ -704,7 +704,7 @@ void NetworkTexture::startRequestForNextMipLevel() { init(false); float priority = -(float)_originalKtxDescriptor->header.numberOfMipmapLevels + (float)_lowestKnownPopulatedMip; - setLoadPriority(this, priority); + setLoadPriorityOperator(this, [priority]() { return priority; }); _url.setFragment(QString::number(_lowestKnownPopulatedMip - 1)); TextureCache::attemptRequest(self); } diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index ddfdeb79d10..264c6b98019 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -252,7 +252,6 @@ void GeometryResource::downloadFinished(const QByteArray& data) { } auto animGraphVariant = _mapping.value("animGraphUrl"); - if (animGraphVariant.isValid()) { QUrl fstUrl(animGraphVariant.toString()); if (fstUrl.isValid()) { @@ -264,6 +263,8 @@ void GeometryResource::downloadFinished(const QByteArray& data) { _animGraphOverrideUrl = QUrl(); } + _waitForWearables = _mapping.value(WAIT_FOR_WEARABLES_FIELD).toBool(); + auto modelCache = DependencyManager::get(); GeometryExtra extra { GeometryMappingPair(base, _mapping), _textureBaseURL, false }; @@ -452,6 +453,7 @@ Geometry::Geometry(const Geometry& geometry) { } _animGraphOverrideUrl = geometry._animGraphOverrideUrl; + _waitForWearables = geometry._waitForWearables; _mapping = geometry._mapping; } diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 236c6262bf3..79021087095 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -58,6 +58,7 @@ class Geometry { virtual bool areTexturesLoaded() const; const QUrl& getAnimGraphOverrideUrl() const { return _animGraphOverrideUrl; } + bool shouldWaitForWearables() const { return _waitForWearables; } const QVariantHash& getMapping() const { return _mapping; } protected: @@ -72,6 +73,7 @@ class Geometry { QUrl _animGraphOverrideUrl; QVariantHash _mapping; // parsed contents of FST file. + bool _waitForWearables { false }; private: mutable bool _areTexturesLoaded { false }; diff --git a/libraries/model-serializers/src/FSTReader.cpp b/libraries/model-serializers/src/FSTReader.cpp index d7c4b730487..9c1ff5a431d 100644 --- a/libraries/model-serializers/src/FSTReader.cpp +++ b/libraries/model-serializers/src/FSTReader.cpp @@ -22,7 +22,7 @@ #include -const QStringList SINGLE_VALUE_PROPERTIES{"name", "filename", "texdir", "script", "comment"}; +const QStringList SINGLE_VALUE_PROPERTIES { NAME_FIELD, FILENAME_FIELD, TEXDIR_FIELD, SCRIPT_FIELD, WAIT_FOR_WEARABLES_FIELD, COMMENT_FIELD }; hifi::VariantMultiHash FSTReader::parseMapping(QIODevice* device) { hifi::VariantMultiHash properties; @@ -183,7 +183,6 @@ QString FSTReader::getNameFromType(ModelType modelType) { _typesToNames[HEAD_MODEL] = "head"; _typesToNames[BODY_ONLY_MODEL] = "body"; _typesToNames[HEAD_AND_BODY_MODEL] = "body+head"; - _typesToNames[ATTACHMENT_MODEL] = "attachment"; } return _typesToNames[modelType]; } @@ -195,9 +194,6 @@ FSTReader::ModelType FSTReader::getTypeFromName(const QString& name) { _namesToTypes["head"] = HEAD_MODEL ; _namesToTypes["body"] = BODY_ONLY_MODEL; _namesToTypes["body+head"] = HEAD_AND_BODY_MODEL; - - // NOTE: this is not yet implemented, but will be used to allow you to attach fully independent models to your avatar - _namesToTypes["attachment"] = ATTACHMENT_MODEL; } return _namesToTypes[name]; } diff --git a/libraries/model-serializers/src/FSTReader.h b/libraries/model-serializers/src/FSTReader.h index 4ba0428e83e..5557df67c69 100644 --- a/libraries/model-serializers/src/FSTReader.h +++ b/libraries/model-serializers/src/FSTReader.h @@ -33,6 +33,7 @@ static const QString BLENDSHAPE_FIELD = "bs"; static const QString SCRIPT_FIELD = "script"; static const QString JOINT_NAME_MAPPING_FIELD = "jointMap"; static const QString MATERIAL_MAPPING_FIELD = "materialMap"; +static const QString WAIT_FOR_WEARABLES_FIELD = "waitForWearables"; static const QString COMMENT_FIELD = "comment"; class FSTReader { @@ -42,8 +43,7 @@ class FSTReader { ENTITY_MODEL, HEAD_MODEL, BODY_ONLY_MODEL, - HEAD_AND_BODY_MODEL, - ATTACHMENT_MODEL + HEAD_AND_BODY_MODEL }; /// Reads an FST mapping from the supplied data. diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 4e36fb46463..782c40609de 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -30,10 +30,10 @@ #include "NetworkLogging.h" #include "NodeList.h" -bool ResourceCacheSharedItems::appendRequest(QWeakPointer resource) { +bool ResourceCacheSharedItems::appendRequest(QWeakPointer resource, float priority) { Lock lock(_mutex); if ((uint32_t)_loadingRequests.size() < _requestLimit) { - _loadingRequests.append(resource); + _loadingRequests.append({ resource, priority }); return true; } else { _pendingRequests.append(resource); @@ -70,14 +70,14 @@ uint32_t ResourceCacheSharedItems::getPendingRequestsCount() const { return _pendingRequests.size(); } -QList> ResourceCacheSharedItems::getLoadingRequests() const { - QList> result; +QList, float>> ResourceCacheSharedItems::getLoadingRequests() const { + QList, float>> result; Lock lock(_mutex); - foreach(QWeakPointer resource, _loadingRequests) { - auto locked = resource.lock(); + foreach(auto resourcePair, _loadingRequests) { + auto locked = resourcePair.first.lock(); if (locked) { - result.append(locked); + result.append({ locked, resourcePair.second }); } } @@ -96,7 +96,7 @@ void ResourceCacheSharedItems::removeRequest(QWeakPointer resource) { // QWeakPointer has no operator== implementation for two weak ptrs, so // manually loop in case resource has been freed. for (int i = 0; i < _loadingRequests.size();) { - auto request = _loadingRequests.at(i); + auto request = _loadingRequests.at(i).first; // Clear our resource and any freed resources if (!request || request.toStrongRef().data() == resource.toStrongRef().data()) { _loadingRequests.removeAt(i); @@ -106,7 +106,7 @@ void ResourceCacheSharedItems::removeRequest(QWeakPointer resource) { } } -QSharedPointer ResourceCacheSharedItems::getHighestPendingRequest() { +std::pair, float> ResourceCacheSharedItems::getHighestPendingRequest() { // look for the highest priority pending request int highestIndex = -1; float highestPriority = -FLT_MAX; @@ -139,7 +139,7 @@ QSharedPointer ResourceCacheSharedItems::getHighestPendingRequest() { _pendingRequests.takeAt(highestIndex); } - return highestResource; + return { highestResource, highestPriority }; } void ResourceCacheSharedItems::clear() { @@ -519,7 +519,7 @@ void ResourceCache::updateTotalSize(const qint64& deltaSize) { emit dirty(); } -QList> ResourceCache::getLoadingRequests() { +QList, float>> ResourceCache::getLoadingRequests() { return DependencyManager::get()->getLoadingRequests(); } @@ -531,11 +531,11 @@ uint32_t ResourceCache::getLoadingRequestCount() { return DependencyManager::get()->getLoadingRequestsCount(); } -bool ResourceCache::attemptRequest(QSharedPointer resource) { +bool ResourceCache::attemptRequest(QSharedPointer resource, float priority) { Q_ASSERT(!resource.isNull()); auto sharedItems = DependencyManager::get(); - if (sharedItems->appendRequest(resource)) { + if (sharedItems->appendRequest(resource, priority)) { resource->makeRequest(); return true; } @@ -555,8 +555,8 @@ void ResourceCache::requestCompleted(QWeakPointer resource) { bool ResourceCache::attemptHighestPriorityRequest() { auto sharedItems = DependencyManager::get(); - auto resource = sharedItems->getHighestPendingRequest(); - return (resource && attemptRequest(resource)); + auto resourcePair = sharedItems->getHighestPendingRequest(); + return (resourcePair.first && attemptRequest(resourcePair.first, resourcePair.second)); } static int requestID = 0; @@ -571,7 +571,7 @@ Resource::Resource(const Resource& other) : _startedLoading(other._startedLoading), _failedToLoad(other._failedToLoad), _loaded(other._loaded), - _loadPriorities(other._loadPriorities), + _loadPriorityOperators(other._loadPriorityOperators), _bytesReceived(other._bytesReceived), _bytesTotal(other._bytesTotal), _bytes(other._bytes), @@ -605,40 +605,24 @@ void Resource::ensureLoading() { } } -void Resource::setLoadPriority(const QPointer& owner, float priority) { - if (!_failedToLoad) { - _loadPriorities.insert(owner, priority); - } -} - -void Resource::setLoadPriorities(const QHash, float>& priorities) { - if (_failedToLoad) { - return; - } - for (QHash, float>::const_iterator it = priorities.constBegin(); - it != priorities.constEnd(); it++) { - _loadPriorities.insert(it.key(), it.value()); - } -} - -void Resource::clearLoadPriority(const QPointer& owner) { +void Resource::setLoadPriorityOperator(const QPointer& owner, std::function priorityOperator) { if (!_failedToLoad) { - _loadPriorities.remove(owner); + _loadPriorityOperators.insert(owner, priorityOperator); } } float Resource::getLoadPriority() { - if (_loadPriorities.size() == 0) { + if (_loadPriorityOperators.size() == 0) { return 0; } float highestPriority = -FLT_MAX; - for (QHash, float>::iterator it = _loadPriorities.begin(); it != _loadPriorities.end(); ) { - if (it.key().isNull()) { - it = _loadPriorities.erase(it); + for (QHash, std::function>::iterator it = _loadPriorityOperators.begin(); it != _loadPriorityOperators.end();) { + if (it.key().isNull() || !it.value()) { + it = _loadPriorityOperators.erase(it); continue; } - highestPriority = qMax(highestPriority, it.value()); + highestPriority = qMax(highestPriority, it.value()()); it++; } return highestPriority; @@ -742,7 +726,7 @@ void Resource::attemptRequest() { void Resource::finishedLoading(bool success) { if (success) { - _loadPriorities.clear(); + _loadPriorityOperators.clear(); _loaded = true; } else { _failedToLoad = true; diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 0eafd1f900a..d2687f0964d 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -66,14 +67,14 @@ class ResourceCacheSharedItems : public Dependency { using Lock = std::unique_lock; public: - bool appendRequest(QWeakPointer newRequest); + bool appendRequest(QWeakPointer newRequest, float priority); void removeRequest(QWeakPointer doneRequest); void setRequestLimit(uint32_t limit); uint32_t getRequestLimit() const; QList> getPendingRequests() const; - QSharedPointer getHighestPendingRequest(); + std::pair, float> getHighestPendingRequest(); uint32_t getPendingRequestsCount() const; - QList> getLoadingRequests() const; + QList, float>> getLoadingRequests() const; uint32_t getLoadingRequestsCount() const; void clear(); @@ -82,7 +83,7 @@ class ResourceCacheSharedItems : public Dependency { mutable Mutex _mutex; QList> _pendingRequests; - QList> _loadingRequests; + QList, float>> _loadingRequests; const uint32_t DEFAULT_REQUEST_LIMIT = 10; uint32_t _requestLimit { DEFAULT_REQUEST_LIMIT }; }; @@ -216,7 +217,7 @@ class ResourceCache : public QObject { void setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize); qint64 getUnusedResourceCacheSize() const { return _unusedResourcesMaxSize; } - static QList> getLoadingRequests(); + static QList, float>> getLoadingRequests(); static uint32_t getPendingRequestCount(); static uint32_t getLoadingRequestCount(); @@ -268,7 +269,7 @@ private slots: /// Attempt to load a resource if requests are below the limit, otherwise queue the resource for loading /// \return true if the resource began loading, otherwise false if the resource is in the pending queue - static bool attemptRequest(QSharedPointer resource); + static bool attemptRequest(QSharedPointer resource, float priority = NAN); static void requestCompleted(QWeakPointer resource); static bool attemptHighestPriorityRequest(); @@ -424,13 +425,7 @@ class Resource : public QObject { void ensureLoading(); /// Sets the load priority for one owner. - virtual void setLoadPriority(const QPointer& owner, float priority); - - /// Sets a set of priorities at once. - virtual void setLoadPriorities(const QHash, float>& priorities); - - /// Clears the load priority for one owner. - virtual void clearLoadPriority(const QPointer& owner); + virtual void setLoadPriorityOperator(const QPointer& owner, std::function priorityOperator); /// Returns the highest load priority across all owners. float getLoadPriority(); @@ -451,7 +446,7 @@ class Resource : public QObject { qint64 getBytes() const { return _bytes; } /// For loading resources, returns the load progress. - float getProgress() const { return (_bytesTotal <= 0) ? 0.0f : (float)_bytesReceived / _bytesTotal; } + float getProgress() const { return (_bytesTotal <= 0) ? 0.0f : ((float)_bytesReceived / _bytesTotal); } /// Refreshes the resource. virtual void refresh(); @@ -537,7 +532,7 @@ protected slots: bool _failedToLoad = false; bool _loaded = false; - QHash, float> _loadPriorities; + QHash, std::function> _loadPriorityOperators; QWeakPointer _self; QPointer _cache; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 2aafc5501e7..ee5495a6226 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -38,10 +38,10 @@ PacketVersion versionForPacketType(PacketType packetType) { return static_cast(EntityQueryPacketVersion::ConicalFrustums); case PacketType::AvatarIdentity: case PacketType::AvatarData: - return static_cast(AvatarMixerPacketVersion::ARKitBlendshapes); + return static_cast(AvatarMixerPacketVersion::RemoveAttachments); case PacketType::BulkAvatarData: case PacketType::KillAvatar: - return static_cast(AvatarMixerPacketVersion::ARKitBlendshapes); + return static_cast(AvatarMixerPacketVersion::RemoveAttachments); case PacketType::MessagesData: return static_cast(MessageDataVersion::TextOrBinaryData); // ICE packets diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index bc36d9444ac..923913e896c 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -349,6 +349,19 @@ enum class EntityVersion : PacketVersion { UserAgent, AllBillboardMode, TextAlignment, + Mirror, + EntityTags, + WantsKeyboardFocus, + AudioZones, + AnimationSmoothFrames, + ProceduralParticles, + ShapeUnlit, + AmbientColor, + SoundEntities, + TonemappingAndAmbientOcclusion, + ModelLoadPriority, + PropertyCleanup, + TextVerticalAlignment, // Add new versions above here NUM_PACKET_TYPE, @@ -414,7 +427,8 @@ enum class AvatarMixerPacketVersion : PacketVersion { FBXJointOrderChange, HandControllerSection, SendVerificationFailed, - ARKitBlendshapes + ARKitBlendshapes, + RemoveAttachments, }; enum class DomainConnectRequestVersion : PacketVersion { diff --git a/libraries/octree/src/OctreePacketData.cpp b/libraries/octree/src/OctreePacketData.cpp index 3966fcf86fc..c13d58226b4 100644 --- a/libraries/octree/src/OctreePacketData.cpp +++ b/libraries/octree/src/OctreePacketData.cpp @@ -496,6 +496,24 @@ bool OctreePacketData::appendValue(const QVector& value) { return success; } +bool OctreePacketData::appendValue(const QSet& value) { + QVector valueVector; + for (const QString& valueString : value) { + valueVector.push_back(valueString); + } + + uint16_t qVecSize = value.size(); + bool success = appendValue(qVecSize); + if (success) { + success = append((const unsigned char*)valueVector.constData(), qVecSize * sizeof(QString)); + if (success) { + _bytesOfValues += qVecSize * sizeof(QString); + _totalBytesOfValues += qVecSize * sizeof(QString); + } + } + return success; +} + bool OctreePacketData::appendValue(const glm::quat& value) { const size_t VALUES_PER_QUAT = 4; const size_t PACKED_QUAT_SIZE = sizeof(uint16_t) * VALUES_PER_QUAT; @@ -802,6 +820,23 @@ int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QVecto return sizeof(uint16_t) + length * sizeof(QUuid); } +int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QSet& result) { + QVector resultVector; + + uint16_t length; + memcpy(&length, dataBytes, sizeof(uint16_t)); + dataBytes += sizeof(length); + resultVector.resize(length); + memcpy(resultVector.data(), dataBytes, length * sizeof(QString)); + + result.clear(); + for (const QString& resultString : resultVector) { + result.insert(resultString); + } + + return sizeof(uint16_t) + length * sizeof(QString); +} + int OctreePacketData::unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result) { uint16_t length; memcpy(&length, dataBytes, sizeof(length)); diff --git a/libraries/octree/src/OctreePacketData.h b/libraries/octree/src/OctreePacketData.h index 583f090942c..cf4d259a4c3 100644 --- a/libraries/octree/src/OctreePacketData.h +++ b/libraries/octree/src/OctreePacketData.h @@ -33,6 +33,7 @@ #include #include +#include "EntityShape.h" #include "MaterialMappingMode.h" #include "BillboardMode.h" #include "RenderLayer.h" @@ -42,6 +43,10 @@ #include "GizmoType.h" #include "TextEffect.h" #include "TextAlignment.h" +#include "TextVerticalAlignment.h" +#include "MirrorMode.h" +#include "TonemappingCurve.h" +#include "AmbientOcclusionTechnique.h" #include "OctreeConstants.h" #include "OctreeElement.h" @@ -190,6 +195,9 @@ class OctreePacketData { /// appends a QVector of QUuids to the end of the stream, may fail if new data stream is too long to fit in packet bool appendValue(const QVector& value); + /// appends a QSet of QStrings to the end of the stream, may fail if new data stream is too long to fit in packet + bool appendValue(const QSet& value); + /// appends a packed quat to the end of the stream, may fail if new data stream is too long to fit in packet bool appendValue(const glm::quat& value); @@ -270,6 +278,7 @@ class OctreePacketData { static int unpackDataFromBytes(const unsigned char* dataBytes, uint16_t& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, uint8_t& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, glm::quat& result) { int bytes = unpackOrientationQuatFromBytes(dataBytes, result); return bytes; } + static int unpackDataFromBytes(const unsigned char* dataBytes, EntityShape& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, ShapeType& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, MaterialMappingMode& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, BillboardMode& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } @@ -280,6 +289,10 @@ class OctreePacketData { static int unpackDataFromBytes(const unsigned char* dataBytes, GizmoType& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, TextEffect& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, TextAlignment& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } + static int unpackDataFromBytes(const unsigned char* dataBytes, TextVerticalAlignment& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } + static int unpackDataFromBytes(const unsigned char* dataBytes, MirrorMode& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } + static int unpackDataFromBytes(const unsigned char* dataBytes, TonemappingCurve& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } + static int unpackDataFromBytes(const unsigned char* dataBytes, AmbientOcclusionTechnique& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); } static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec2& result); static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec3& result); static int unpackDataFromBytes(const unsigned char* dataBytes, glm::u8vec3& result); @@ -290,6 +303,7 @@ class OctreePacketData { static int unpackDataFromBytes(const unsigned char* dataBytes, QVector& result); static int unpackDataFromBytes(const unsigned char* dataBytes, QVector& result); static int unpackDataFromBytes(const unsigned char* dataBytes, QVector& result); + static int unpackDataFromBytes(const unsigned char* dataBytes, QSet& result); static int unpackDataFromBytes(const unsigned char* dataBytes, QByteArray& result); static int unpackDataFromBytes(const unsigned char* dataBytes, AACube& result); static int unpackDataFromBytes(const unsigned char* dataBytes, QRect& result); diff --git a/libraries/physics/CMakeLists.txt b/libraries/physics/CMakeLists.txt index 3237e712f98..001c9923208 100644 --- a/libraries/physics/CMakeLists.txt +++ b/libraries/physics/CMakeLists.txt @@ -5,6 +5,7 @@ set(TARGET_NAME physics) setup_hifi_library() link_hifi_libraries(shared workload entities shaders) +include_hifi_library_headers(audio) include_hifi_library_headers(networking) include_hifi_library_headers(gpu) include_hifi_library_headers(avatars) @@ -19,5 +20,6 @@ include_hifi_library_headers(hfm) include_hifi_library_headers(model-serializers) include_hifi_library_headers(graphics) include_hifi_library_headers(script-engine) +include_hifi_library_headers(entities) target_bullet() diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index 49d05d8059d..3162ab95e69 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -329,12 +329,12 @@ void Procedural::prepare(gpu::Batch& batch, // Build the fragment and vertex shaders auto versionDefine = "#define PROCEDURAL_V" + std::to_string(_data.version); - fragmentSource.replacements.clear(); + fragmentSource.replacements = _fragmentReplacements; fragmentSource.replacements[PROCEDURAL_VERSION] = versionDefine; if (!_fragmentShaderSource.isEmpty()) { fragmentSource.replacements[PROCEDURAL_BLOCK] = _fragmentShaderSource.toStdString(); } - vertexSource.replacements.clear(); + vertexSource.replacements = _vertexReplacements; vertexSource.replacements[PROCEDURAL_VERSION] = versionDefine; if (!_vertexShaderSource.isEmpty()) { vertexSource.replacements[PROCEDURAL_BLOCK] = _vertexShaderSource.toStdString(); @@ -555,6 +555,19 @@ bool Procedural::hasVertexShader() const { return !_data.vertexShaderUrl.isEmpty(); } + +void Procedural::setVertexReplacements(const std::unordered_map& replacements) { + std::lock_guard lock(_mutex); + _vertexReplacements = replacements; + _shaderDirty = true; +} + +void Procedural::setFragmentReplacements(const std::unordered_map& replacements) { + std::lock_guard lock(_mutex); + _fragmentReplacements = replacements; + _shaderDirty = true; +} + void graphics::ProceduralMaterial::initializeProcedural() { _procedural._vertexSource = gpu::Shader::getVertexShaderSource(shader::render_utils::vertex::simple_procedural); _procedural._vertexSourceSkinned = gpu::Shader::getVertexShaderSource(shader::render_utils::vertex::simple_procedural_deformed); diff --git a/libraries/procedural/src/procedural/Procedural.h b/libraries/procedural/src/procedural/Procedural.h index 9e6f102e362..3ca2f41f0bb 100644 --- a/libraries/procedural/src/procedural/Procedural.h +++ b/libraries/procedural/src/procedural/Procedural.h @@ -118,6 +118,9 @@ struct Procedural { bool hasBoundOperator() const { return (bool)_boundOperator; } AABox getBound(RenderArgs* args) { return _boundOperator(args); } + void setVertexReplacements(const std::unordered_map& replacements); + void setFragmentReplacements(const std::unordered_map& replacements); + gpu::Shader::Source _vertexSource; gpu::Shader::Source _vertexSourceSkinned; gpu::Shader::Source _vertexSourceSkinnedDQ; @@ -185,6 +188,8 @@ struct Procedural { // Rendering objects UniformLambdas _uniforms; NetworkTexturePointer _channels[MAX_PROCEDURAL_TEXTURE_CHANNELS]; + std::unordered_map _vertexReplacements; + std::unordered_map _fragmentReplacements; std::unordered_map _proceduralPipelines; std::unordered_map _errorPipelines; diff --git a/libraries/procedural/src/procedural/ProceduralParticleCommon.slh b/libraries/procedural/src/procedural/ProceduralParticleCommon.slh new file mode 100644 index 00000000000..363cdeae014 --- /dev/null +++ b/libraries/procedural/src/procedural/ProceduralParticleCommon.slh @@ -0,0 +1,82 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// <$_SCRIBE_FILENAME$> +// Generated on <$_SCRIBE_DATE$> +// +// Created by HifiExperiements on 11/21/23 +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include procedural/ShaderConstants.h@> + +#define NUM_PARTICLES 1 +//PROCEDURAL_PARTICLE_NUM_PARTICLES + +#define NUM_TRIS_PER_PARTICLE 3 +//PROCEDURAL_PARTICLE_NUM_TRIS_PER_PARTICLE + +#define NUM_UPDATE_PROPS 0 +//PROCEDURAL_PARTICLE_NUM_UPDATE_PROPS + + +#if NUM_UPDATE_PROPS > 0 +LAYOUT(binding=PROCEDURAL_PARTICLE_TEXTURE_PROP0) uniform sampler2D _prop0Texture; +#endif +#if NUM_UPDATE_PROPS > 1 +LAYOUT(binding=PROCEDURAL_PARTICLE_TEXTURE_PROP1) uniform sampler2D _prop1Texture; +#endif +#if NUM_UPDATE_PROPS > 2 +LAYOUT(binding=PROCEDURAL_PARTICLE_TEXTURE_PROP2) uniform sampler2D _prop2Texture; +#endif +#if NUM_UPDATE_PROPS > 3 +LAYOUT(binding=PROCEDURAL_PARTICLE_TEXTURE_PROP3) uniform sampler2D _prop3Texture; +#endif +#if NUM_UPDATE_PROPS > 4 +LAYOUT(binding=PROCEDURAL_PARTICLE_TEXTURE_PROP4) uniform sampler2D _prop4Texture; +#endif + +<@func declareProceduralParticleRender()@> + +vec4 getParticleProperty(const int propIndex, const int particleID) { + if (propIndex < 0 || propIndex >= NUM_UPDATE_PROPS || particleID < 0 || particleID >= NUM_PARTICLES) { + return vec4(0.0); + } + +#if NUM_UPDATE_PROPS > 0 + const ivec2 textureDims = textureSize(_prop0Texture, 0); + const ivec2 uv = ivec2(particleID % textureDims.x, particleID / textureDims.x); + if (propIndex == 0) { + return texelFetch(_prop0Texture, uv, 0); + } +#endif +#if NUM_UPDATE_PROPS > 1 + else if (propIndex == 1) { + return texelFetch(_prop1Texture, uv, 0); + } +#endif +#if NUM_UPDATE_PROPS > 2 + else if (propIndex == 2) { + return texelFetch(_prop2Texture, uv, 0); + } +#endif +#if NUM_UPDATE_PROPS > 3 + else if (propIndex == 3) { + return texelFetch(_prop3Texture, uv, 0); + } +#endif +#if NUM_UPDATE_PROPS > 4 + else if (propIndex == 4) { + return texelFetch(_prop4Texture, uv, 0); + } +#endif + + return vec4(0.0); +} + +<@endfunc@> + +// hack comment for extra whitespace + diff --git a/libraries/procedural/src/procedural/ShaderConstants.h b/libraries/procedural/src/procedural/ShaderConstants.h index f1336b6479e..a70538359fc 100644 --- a/libraries/procedural/src/procedural/ShaderConstants.h +++ b/libraries/procedural/src/procedural/ShaderConstants.h @@ -1,6 +1,7 @@ // Not used.

- * @function Recording.setPlayerUseAttachments - * @param {boolean} useAttachments - Use attachments. - * @deprecated This method is deprecated and will be removed. - */ - void setPlayerUseAttachments(bool useAttachments); - /*@jsdoc *

Not used.

* @function Recording.setPlayerUseHeadModel @@ -203,14 +195,6 @@ public slots: */ bool getPlayerUseDisplayName() { return _useDisplayName; } - /*@jsdoc - *

Not used.

- * @function Recording.getPlayerUseAttachments - * @returns {boolean} Use attachments. - * @deprecated This method is deprecated and will be removed. - */ - bool getPlayerUseAttachments() { return _useAttachments; } - /*@jsdoc *

Not used.

* @function Recording.getPlayerUseHeadModel @@ -365,7 +349,6 @@ public slots: Flag _playFromCurrentLocation { true }; Flag _useDisplayName { false }; Flag _useHeadModel { false }; - Flag _useAttachments { false }; Flag _useSkeletonModel { false }; recording::ClipPointer _lastClip; diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 68eb1b5a066..5e7c584e330 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -37,6 +37,9 @@ gpu::PipelinePointer AmbientOcclusionEffect::_mipCreationPipeline; gpu::PipelinePointer AmbientOcclusionEffect::_gatherPipeline; gpu::PipelinePointer AmbientOcclusionEffect::_buildNormalsPipeline; +#define MAX_SSAO_SAMPLES 64.0f +#define MAX_HBAO_SAMPLES 6.0f + AmbientOcclusionFramebuffer::AmbientOcclusionFramebuffer() { } @@ -205,29 +208,7 @@ gpu::TexturePointer AmbientOcclusionFramebuffer::getNormalTexture() { } AmbientOcclusionEffectConfig::AmbientOcclusionEffectConfig() : - render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion"), - perspectiveScale{ 1.0f }, - edgeSharpness{ 1.0f }, - blurRadius{ 4 }, - resolutionLevel{ 2 }, - - ssaoRadius{ 1.0f }, - ssaoObscuranceLevel{ 0.4f }, - ssaoFalloffAngle{ 0.15f }, - ssaoNumSpiralTurns{ 7.0f }, - ssaoNumSamples{ 32 }, - - hbaoRadius{ 0.7f }, - hbaoObscuranceLevel{ 0.75f }, - hbaoFalloffAngle{ 0.3f }, - hbaoNumSamples{ 1 }, - - horizonBased{ false }, - ditheringEnabled{ true }, - borderingEnabled{ true }, - fetchMipsEnabled{ true }, - jitterEnabled{ false }{ -} + render::GPUJobConfig::Persistent(QStringList() << "Render" << "Engine" << "Ambient Occlusion") {} void AmbientOcclusionEffectConfig::setSSAORadius(float newRadius) { ssaoRadius = std::max(0.01f, newRadius); emit dirty(); @@ -288,89 +269,105 @@ void AmbientOcclusionEffectConfig::setBlurRadius(int radius) { } AmbientOcclusionEffect::AOParameters::AOParameters() { - _resolutionInfo = glm::vec4{ 0.0f }; - _radiusInfo = glm::vec4{ 0.0f }; - _ditheringInfo = glm::vec4{ 0.0f }; - _sampleInfo = glm::vec4{ 0.0f }; - _falloffInfo = glm::vec4{ 0.0f }; + _resolutionInfo = glm::vec4(0.0f); + _radiusInfo = glm::vec4(0.0f); + _ditheringInfo = glm::vec4(0.0f); + _sampleInfo = glm::vec4(0.0f); + _falloffInfo = glm::vec4(0.0f); } AmbientOcclusionEffect::BlurParameters::BlurParameters() { _blurInfo = { 1.0f, 2.0f, 0.0f, 3.0f }; } -AmbientOcclusionEffect::AmbientOcclusionEffect() { -} - void AmbientOcclusionEffect::configure(const Config& config) { + _debug = config.debug; + _debugAmbientOcclusion->setTechnique(config.horizonBased ? AmbientOcclusionTechnique::HBAO : AmbientOcclusionTechnique::SSAO); + _debugAmbientOcclusion->setJitter(config.jitterEnabled); + _debugAmbientOcclusion->setResolutionLevel(config.resolutionLevel); + _debugAmbientOcclusion->setEdgeSharpness(config.edgeSharpness); + _debugAmbientOcclusion->setBlurRadius(config.blurRadius); + _debugAmbientOcclusion->setAORadius(config.horizonBased ? config.hbaoRadius : config.ssaoRadius); + _debugAmbientOcclusion->setAOObscuranceLevel(config.horizonBased ? config.hbaoObscuranceLevel : config.ssaoObscuranceLevel); + _debugAmbientOcclusion->setAOFalloffAngle(config.horizonBased ? config.hbaoFalloffAngle : config.ssaoFalloffAngle); + _debugAmbientOcclusion->setAOSamplingAmount(config.horizonBased ? (config.hbaoNumSamples / MAX_HBAO_SAMPLES) : + (config.ssaoNumSamples / MAX_SSAO_SAMPLES)); + _debugAmbientOcclusion->setSSAONumSpiralTurns(config.ssaoNumSpiralTurns); + + _perspectiveScale = config.perspectiveScale; + _ditheringEnabled = config.ditheringEnabled; + _borderingEnabled = config.borderingEnabled; + _fetchMipsEnabled = config.fetchMipsEnabled; +} + +void AmbientOcclusionEffect::updateParameters(const graphics::AmbientOcclusionPointer ambientOcclusion) { bool shouldUpdateBlurs = false; bool shouldUpdateTechnique = false; - _isJitterEnabled = config.jitterEnabled; - if (!_framebuffer) { _framebuffer = std::make_shared(); shouldUpdateBlurs = true; } // Update bilateral blur - if (config.blurRadius != _hblurParametersBuffer->getBlurRadius() || _blurEdgeSharpness != config.edgeSharpness) { + if (ambientOcclusion->getBlurRadius() != _hblurParametersBuffer->getBlurRadius() || _blurEdgeSharpness != ambientOcclusion->getEdgeSharpness()) { const float BLUR_EDGE_DISTANCE_SCALE = float(10000 * SSAO_DEPTH_KEY_SCALE); const float BLUR_EDGE_NORMAL_SCALE = 2.0f; auto& hblur = _hblurParametersBuffer.edit()._blurInfo; auto& vblur = _vblurParametersBuffer.edit()._blurInfo; - float blurRadialSigma = float(config.blurRadius) * 0.5f; + float blurRadialSigma = float(ambientOcclusion->getBlurRadius()) * 0.5f; float blurRadialScale = 1.0f / (2.0f*blurRadialSigma*blurRadialSigma); - glm::vec3 blurScales = -glm::vec3(blurRadialScale, glm::vec2(BLUR_EDGE_DISTANCE_SCALE, BLUR_EDGE_NORMAL_SCALE) * config.edgeSharpness); + glm::vec3 blurScales = -glm::vec3(blurRadialScale, glm::vec2(BLUR_EDGE_DISTANCE_SCALE, BLUR_EDGE_NORMAL_SCALE) * ambientOcclusion->getEdgeSharpness()); - _blurEdgeSharpness = config.edgeSharpness; + _blurEdgeSharpness = ambientOcclusion->getEdgeSharpness(); hblur.x = blurScales.x; hblur.y = blurScales.y; hblur.z = blurScales.z; - hblur.w = (float)config.blurRadius; + hblur.w = (float)ambientOcclusion->getBlurRadius(); vblur.x = blurScales.x; vblur.y = blurScales.y; vblur.z = blurScales.z; - vblur.w = (float)config.blurRadius; + vblur.w = (float)ambientOcclusion->getBlurRadius(); } - if (_aoParametersBuffer->isHorizonBased() != config.horizonBased) { - auto& current = _aoParametersBuffer.edit()._resolutionInfo; - current.y = config.horizonBased & 1; - shouldUpdateTechnique = true; + if (_perspectiveScale != _aoParametersBuffer->getPerspectiveScale()) { + _aoParametersBuffer.edit()._resolutionInfo.z = _perspectiveScale; } - if (config.fetchMipsEnabled != _aoParametersBuffer->isFetchMipsEnabled()) { - auto& current = _aoParametersBuffer.edit()._sampleInfo; - current.w = (float)config.fetchMipsEnabled; + if (_ditheringEnabled != _aoParametersBuffer->isDitheringEnabled()) { + auto& current = _aoParametersBuffer.edit()._ditheringInfo; + current.x = (float)_ditheringEnabled; } - if (config.perspectiveScale != _aoParametersBuffer->getPerspectiveScale()) { - _aoParametersBuffer.edit()._resolutionInfo.z = config.perspectiveScale; + if (_borderingEnabled != _aoParametersBuffer->isBorderingEnabled()) { + auto& current = _aoParametersBuffer.edit()._ditheringInfo; + current.w = (float)_borderingEnabled; } - if (config.resolutionLevel != _aoParametersBuffer->getResolutionLevel()) { - auto& current = _aoParametersBuffer.edit()._resolutionInfo; - current.x = (float)config.resolutionLevel; - shouldUpdateBlurs = true; + if (_fetchMipsEnabled != _aoParametersBuffer->isFetchMipsEnabled()) { + auto& current = _aoParametersBuffer.edit()._sampleInfo; + current.w = (float)_fetchMipsEnabled; } - if (config.ditheringEnabled != _aoParametersBuffer->isDitheringEnabled()) { - auto& current = _aoParametersBuffer.edit()._ditheringInfo; - current.x = (float)config.ditheringEnabled; + bool horizonBased = ambientOcclusion->getTechnique() == AmbientOcclusionTechnique::HBAO; + if (_aoParametersBuffer->isHorizonBased() != horizonBased) { + auto& current = _aoParametersBuffer.edit()._resolutionInfo; + current.y = horizonBased & 1; + shouldUpdateTechnique = true; } - if (config.borderingEnabled != _aoParametersBuffer->isBorderingEnabled()) { - auto& current = _aoParametersBuffer.edit()._ditheringInfo; - current.w = (float)config.borderingEnabled; + if (ambientOcclusion->getResolutionLevel() != _aoParametersBuffer->getResolutionLevel()) { + auto& current = _aoParametersBuffer.edit()._resolutionInfo; + current.x = (float)ambientOcclusion->getResolutionLevel(); + shouldUpdateBlurs = true; } - if (config.horizonBased) { + if (horizonBased) { // Configure for HBAO - const auto& radius = config.hbaoRadius; + const auto& radius = ambientOcclusion->getAORadius(); if (shouldUpdateTechnique || radius != _aoParametersBuffer->getRadius()) { auto& current = _aoParametersBuffer.edit()._radiusInfo; current.x = radius; @@ -378,31 +375,33 @@ void AmbientOcclusionEffect::configure(const Config& config) { current.z = 1.0f / current.y; } - if (shouldUpdateTechnique || config.hbaoObscuranceLevel != _aoParametersBuffer->getObscuranceLevel()) { + if (shouldUpdateTechnique || ambientOcclusion->getAOObscuranceLevel() != _aoParametersBuffer->getObscuranceLevel()) { auto& current = _aoParametersBuffer.edit()._radiusInfo; - current.w = config.hbaoObscuranceLevel; + current.w = ambientOcclusion->getAOObscuranceLevel(); } - if (shouldUpdateTechnique || config.hbaoFalloffAngle != _aoParametersBuffer->getFalloffAngle()) { + const float falloffAngle = std::min(1.0f - EPSILON, ambientOcclusion->getAOFalloffAngle()); + if (shouldUpdateTechnique || falloffAngle != _aoParametersBuffer->getFalloffAngle()) { auto& current = _aoParametersBuffer.edit()._falloffInfo; - current.x = config.hbaoFalloffAngle; + current.x = falloffAngle; current.y = 1.0f / (1.0f - current.x); // Compute sin from cos - current.z = sqrtf(1.0f - config.hbaoFalloffAngle * config.hbaoFalloffAngle); + current.z = sqrtf(1.0f - current.x * current.x); current.w = 1.0f / current.z; } - if (shouldUpdateTechnique || config.hbaoNumSamples != _aoParametersBuffer->getNumSamples()) { + const int numSamples = std::max(1, (int)(ambientOcclusion->getAOSamplingAmount() * MAX_HBAO_SAMPLES)); + if (shouldUpdateTechnique || numSamples != _aoParametersBuffer->getNumSamples()) { auto& current = _aoParametersBuffer.edit()._sampleInfo; - current.x = config.hbaoNumSamples; - current.y = 1.0f / config.hbaoNumSamples; + current.x = numSamples; + current.y = 1.0f / numSamples; updateRandomSamples(); updateJitterSamples(); } } else { // Configure for SSAO const double RADIUS_POWER = 6.0; - const auto& radius = config.ssaoRadius; + const auto& radius = ambientOcclusion->getAORadius(); if (shouldUpdateTechnique || radius != _aoParametersBuffer->getRadius()) { auto& current = _aoParametersBuffer.edit()._radiusInfo; current.x = radius; @@ -410,25 +409,26 @@ void AmbientOcclusionEffect::configure(const Config& config) { current.z = (float)(10.0 / pow((double)radius, RADIUS_POWER)); } - if (shouldUpdateTechnique || config.ssaoObscuranceLevel != _aoParametersBuffer->getObscuranceLevel()) { + if (shouldUpdateTechnique || ambientOcclusion->getAOObscuranceLevel() != _aoParametersBuffer->getObscuranceLevel()) { auto& current = _aoParametersBuffer.edit()._radiusInfo; - current.w = config.ssaoObscuranceLevel; + current.w = ambientOcclusion->getAOObscuranceLevel(); } - if (shouldUpdateTechnique || config.ssaoFalloffAngle != _aoParametersBuffer->getFalloffAngle()) { + if (shouldUpdateTechnique || ambientOcclusion->getAOFalloffAngle() != _aoParametersBuffer->getFalloffAngle()) { auto& current = _aoParametersBuffer.edit()._falloffInfo; - current.x = config.ssaoFalloffAngle; + current.x = ambientOcclusion->getAOFalloffAngle(); } - if (shouldUpdateTechnique || config.ssaoNumSpiralTurns != _aoParametersBuffer->getNumSpiralTurns()) { + if (shouldUpdateTechnique || ambientOcclusion->getSSAONumSpiralTurns() != _aoParametersBuffer->getNumSpiralTurns()) { auto& current = _aoParametersBuffer.edit()._sampleInfo; - current.z = config.ssaoNumSpiralTurns; + current.z = ambientOcclusion->getSSAONumSpiralTurns(); } - if (shouldUpdateTechnique || config.ssaoNumSamples != _aoParametersBuffer->getNumSamples()) { + const int numSamples = std::max(1, (int)(ambientOcclusion->getAOSamplingAmount() * MAX_SSAO_SAMPLES)); + if (shouldUpdateTechnique || numSamples != _aoParametersBuffer->getNumSamples()) { auto& current = _aoParametersBuffer.edit()._sampleInfo; - current.x = config.ssaoNumSamples; - current.y = 1.0f / config.ssaoNumSamples; + current.x = numSamples; + current.y = 1.0f / numSamples; updateRandomSamples(); updateJitterSamples(); } @@ -600,12 +600,23 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte RenderArgs* args = renderContext->args; const auto& lightingModel = input.get0(); + const auto ambientOcclusionFrame = input.get4(); + + const auto& ambientOcclusionStage = renderContext->_scene->getStage(); + graphics::AmbientOcclusionPointer ambientOcclusion; + if (_debug) { + ambientOcclusion = _debugAmbientOcclusion; + } else if (ambientOcclusionStage && ambientOcclusionFrame->_ambientOcclusions.size()) { + ambientOcclusion = ambientOcclusionStage->getAmbientOcclusion(ambientOcclusionFrame->_ambientOcclusions.front()); + } - if (!lightingModel->isAmbientOcclusionEnabled()) { + if (!ambientOcclusion || !lightingModel->isAmbientOcclusionEnabled()) { output.edit0().reset(); return; } + updateParameters(ambientOcclusion); + const auto& frameTransform = input.get1(); const auto& linearDepthFramebuffer = input.get3(); @@ -657,7 +668,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte #endif // Update sample rotation - if (_isJitterEnabled) { + if (ambientOcclusion->getJitter()) { updateJitterSamples(); _frameId = (_frameId + 1) % (SSAO_RANDOM_SAMPLE_COUNT); } @@ -831,11 +842,7 @@ void AmbientOcclusionEffect::run(const render::RenderContextPointer& renderConte config->setGPUBatchRunTime(_gpuTimer->getGPUAverage(), _gpuTimer->getBatchAverage()); } -DebugAmbientOcclusion::DebugAmbientOcclusion() { -} - void DebugAmbientOcclusion::configure(const Config& config) { - _showCursorPixel = config.showCursorPixel; auto cursorPos = glm::vec2(_parametersBuffer->pixelInfo); @@ -916,9 +923,6 @@ void DebugAmbientOcclusion::run(const render::RenderContextPointer& renderContex batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, fullResDepthTexture); batch.draw(gpu::TRIANGLE_STRIP, 4); - batch.setResourceTexture(render_utils::slot::texture::SsaoDepth, nullptr); }); - } - diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.h b/libraries/render-utils/src/AmbientOcclusionEffect.h index 65fc09a8140..3c49dba3d46 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.h +++ b/libraries/render-utils/src/AmbientOcclusionEffect.h @@ -21,6 +21,7 @@ #include "DeferredFrameTransform.h" #include "DeferredFramebuffer.h" #include "SurfaceGeometryPass.h" +#include "AmbientOcclusionStage.h" #include "ssao_shared.h" @@ -70,15 +71,16 @@ class AmbientOcclusionFramebuffer { #endif glm::ivec2 _frameSize; - int _resolutionLevel{ 0 }; - int _depthResolutionLevel{ 0 }; - bool _isStereo{ false }; + int _resolutionLevel { 0 }; + int _depthResolutionLevel { 0 }; + bool _isStereo { false }; }; using AmbientOcclusionFramebufferPointer = std::shared_ptr; class AmbientOcclusionEffectConfig : public render::GPUJobConfig::Persistent { Q_OBJECT + Q_PROPERTY(bool debug MEMBER debug NOTIFY dirty) Q_PROPERTY(bool horizonBased MEMBER horizonBased NOTIFY dirty) Q_PROPERTY(bool ditheringEnabled MEMBER ditheringEnabled NOTIFY dirty) Q_PROPERTY(bool borderingEnabled MEMBER borderingEnabled NOTIFY dirty) @@ -108,42 +110,44 @@ class AmbientOcclusionEffectConfig : public render::GPUJobConfig::Persistent { const int MAX_RESOLUTION_LEVEL = 4; const int MAX_BLUR_RADIUS = 15; - void setEdgeSharpness(float sharpness); void setResolutionLevel(int level); + void setEdgeSharpness(float sharpness); void setBlurRadius(int radius); void setSSAORadius(float newRadius); void setSSAOObscuranceLevel(float level); void setSSAOFalloffAngle(float bias); - void setSSAONumSpiralTurns(float turns); void setSSAONumSamples(int samples); + void setSSAONumSpiralTurns(float turns); void setHBAORadius(float newRadius); void setHBAOObscuranceLevel(float level); void setHBAOFalloffAngle(float bias); void setHBAONumSamples(int samples); - float perspectiveScale; - float edgeSharpness; - int blurRadius; // 0 means no blurring - int resolutionLevel; + bool debug { false }; + + bool jitterEnabled { false }; // Add small jittering to AO samples at each frame + bool horizonBased { false }; // Use horizon based AO + int resolutionLevel { 2 }; + float edgeSharpness { 1.0f }; + int blurRadius { 4 }; // 0 means no blurring - float ssaoRadius; - float ssaoObscuranceLevel; // intensify or dim down the obscurance effect - float ssaoFalloffAngle; - float ssaoNumSpiralTurns; // defining an angle span to distribute the samples ray directions - int ssaoNumSamples; + float ssaoRadius { 1.0f }; + float ssaoObscuranceLevel { 0.4f }; // intensify or dim down the obscurance effect + float ssaoFalloffAngle { 0.15f }; + int ssaoNumSamples { 32 }; + float ssaoNumSpiralTurns { 7.0f }; // defining an angle span to distribute the samples ray directions - float hbaoRadius; - float hbaoObscuranceLevel; // intensify or dim down the obscurance effect - float hbaoFalloffAngle; - int hbaoNumSamples; + float hbaoRadius { 0.7f }; + float hbaoObscuranceLevel { 0.75f }; // intensify or dim down the obscurance effect + float hbaoFalloffAngle { 0.3f }; + int hbaoNumSamples { 1 }; - bool horizonBased; // Use horizon based AO - bool ditheringEnabled; // randomize the distribution of taps per pixel, should always be true - bool borderingEnabled; // avoid evaluating information from non existing pixels out of the frame, should always be true - bool fetchMipsEnabled; // fetch taps in sub mips to otpimize cache, should always be true - bool jitterEnabled; // Add small jittering to AO samples at each frame + float perspectiveScale { 1.0f }; + bool ditheringEnabled { true }; // randomize the distribution of taps per pixel, should always be true + bool borderingEnabled { true }; // avoid evaluating information from non existing pixels out of the frame, should always be true + bool fetchMipsEnabled { true }; // fetch taps in sub mips to otpimize cache, should always be true signals: void dirty(); @@ -153,12 +157,13 @@ class AmbientOcclusionEffectConfig : public render::GPUJobConfig::Persistent { class AmbientOcclusionEffect { public: - using Input = render::VaryingSet4; + using Input = render::VaryingSet5; using Output = render::VaryingSet2; using Config = AmbientOcclusionEffectConfig; using JobModel = render::Job::ModelIO; - AmbientOcclusionEffect(); + AmbientOcclusionEffect() {} void configure(const Config& config); void run(const render::RenderContextPointer& renderContext, const Input& input, Output& output); @@ -166,7 +171,6 @@ class AmbientOcclusionEffect { // Class describing the uniform buffer with all the parameters common to the AO shaders class AOParameters : public AmbientOcclusionParams { public: - AOParameters(); int getResolutionLevel() const { return _resolutionInfo.x; } @@ -182,7 +186,6 @@ class AmbientOcclusionEffect { bool isDitheringEnabled() const { return _ditheringInfo.x != 0.0f; } bool isBorderingEnabled() const { return _ditheringInfo.w != 0.0f; } bool isHorizonBased() const { return _resolutionInfo.y != 0.0f; } - }; using AOParametersBuffer = gpu::StructBuffer; @@ -191,17 +194,15 @@ class AmbientOcclusionEffect { // Class describing the uniform buffer with all the parameters common to the bilateral blur shaders class BlurParameters : public AmbientOcclusionBlurParams { public: - BlurParameters(); float getEdgeSharpness() const { return (float)_blurInfo.x; } int getBlurRadius() const { return (int)_blurInfo.w; } - }; using BlurParametersBuffer = gpu::StructBuffer; - using FrameParametersBuffer = gpu::StructBuffer< AmbientOcclusionFrameParams>; + void updateParameters(const graphics::AmbientOcclusionPointer ambientOcclusion); void updateBlurParameters(); void updateFramebufferSizes(); void updateRandomSamples(); @@ -213,7 +214,7 @@ class AmbientOcclusionEffect { FrameParametersBuffer _aoFrameParametersBuffer[SSAO_SPLIT_COUNT*SSAO_SPLIT_COUNT]; BlurParametersBuffer _vblurParametersBuffer; BlurParametersBuffer _hblurParametersBuffer; - float _blurEdgeSharpness{ 0.0f }; + float _blurEdgeSharpness { 0.0f }; static const gpu::PipelinePointer& getOcclusionPipeline(); static const gpu::PipelinePointer& getBilateralBlurPipeline(); @@ -229,9 +230,14 @@ class AmbientOcclusionEffect { AmbientOcclusionFramebufferPointer _framebuffer; std::array _randomSamples; - int _frameId{ 0 }; - bool _isJitterEnabled{ true }; - + int _frameId { 0 }; + bool _debug { false }; + float _perspectiveScale { 1.0f }; + bool _ditheringEnabled { true }; + bool _borderingEnabled { true }; + bool _fetchMipsEnabled { true }; + graphics::AmbientOcclusionPointer _debugAmbientOcclusion { std::make_shared() }; + gpu::RangeTimerPointer _gpuTimer; friend class DebugAmbientOcclusion; @@ -246,8 +252,8 @@ class DebugAmbientOcclusionConfig : public render::Job::Config { public: DebugAmbientOcclusionConfig() : render::Job::Config(false) {} - bool showCursorPixel{ false }; - glm::vec2 debugCursorTexcoord{ 0.5f, 0.5f }; + bool showCursorPixel { false }; + glm::vec2 debugCursorTexcoord { 0.5f, 0.5f }; signals: void dirty(); @@ -260,7 +266,7 @@ class DebugAmbientOcclusion { using Config = DebugAmbientOcclusionConfig; using JobModel = render::Job::ModelI; - DebugAmbientOcclusion(); + DebugAmbientOcclusion() {} void configure(const Config& config); void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); @@ -281,7 +287,7 @@ class DebugAmbientOcclusion { gpu::PipelinePointer _debugPipeline; - bool _showCursorPixel{ false }; + bool _showCursorPixel { false }; }; #endif // hifi_AmbientOcclusionEffect_h diff --git a/libraries/render-utils/src/AmbientOcclusionStage.cpp b/libraries/render-utils/src/AmbientOcclusionStage.cpp new file mode 100644 index 00000000000..6b3763a39c9 --- /dev/null +++ b/libraries/render-utils/src/AmbientOcclusionStage.cpp @@ -0,0 +1,56 @@ +// +// AmbientOcclusionStage.cpp +// +// Created by HifiExperiments on 6/24/24 +// Copyright 2024 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "AmbientOcclusionStage.h" + +#include + +std::string AmbientOcclusionStage::_stageName { "AMBIENT_OCCLUSION_STAGE" }; +const AmbientOcclusionStage::Index AmbientOcclusionStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX }; + +AmbientOcclusionStage::Index AmbientOcclusionStage::findAmbientOcclusion(const AmbientOcclusionPointer& ambientOcclusion) const { + auto found = _ambientOcclusionMap.find(ambientOcclusion); + if (found != _ambientOcclusionMap.end()) { + return INVALID_INDEX; + } else { + return (*found).second; + } +} + +AmbientOcclusionStage::Index AmbientOcclusionStage::addAmbientOcclusion(const AmbientOcclusionPointer& ambientOcclusion) { + auto found = _ambientOcclusionMap.find(ambientOcclusion); + if (found == _ambientOcclusionMap.end()) { + auto ambientOcclusionId = _ambientOcclusions.newElement(ambientOcclusion); + // Avoid failing to allocate a ambientOcclusion, just pass + if (ambientOcclusionId != INVALID_INDEX) { + // Insert the ambientOcclusion and its index in the reverse map + _ambientOcclusionMap.insert(AmbientOcclusionMap::value_type(ambientOcclusion, ambientOcclusionId)); + } + return ambientOcclusionId; + } else { + return (*found).second; + } +} + +AmbientOcclusionStage::AmbientOcclusionPointer AmbientOcclusionStage::removeAmbientOcclusion(Index index) { + AmbientOcclusionPointer removed = _ambientOcclusions.freeElement(index); + if (removed) { + _ambientOcclusionMap.erase(removed); + } + return removed; +} + +AmbientOcclusionStageSetup::AmbientOcclusionStageSetup() {} + +void AmbientOcclusionStageSetup::run(const render::RenderContextPointer& renderContext) { + auto stage = renderContext->_scene->getStage(AmbientOcclusionStage::getName()); + if (!stage) { + renderContext->_scene->resetStage(AmbientOcclusionStage::getName(), std::make_shared()); + } +} diff --git a/libraries/render-utils/src/AmbientOcclusionStage.h b/libraries/render-utils/src/AmbientOcclusionStage.h new file mode 100644 index 00000000000..d5dee344ba1 --- /dev/null +++ b/libraries/render-utils/src/AmbientOcclusionStage.h @@ -0,0 +1,84 @@ +// +// AmbientOcclusionStage.h +// +// Created by HifiExperiments on 6/24/24 +// Copyright 2024 Overte e.V. +// +// 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_AmbientOcclusionStage_h +#define hifi_render_utils_AmbientOcclusionStage_h + +#include +#include +#include +#include +#include + +#include +#include +#include + +// AmbientOcclusion stage to set up ambientOcclusion-related rendering tasks +class AmbientOcclusionStage : 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 AmbientOcclusionPointer = graphics::AmbientOcclusionPointer; + using AmbientOcclusions = render::indexed_container::IndexedPointerVector; + using AmbientOcclusionMap = std::unordered_map; + + using AmbientOcclusionIndices = std::vector; + + Index findAmbientOcclusion(const AmbientOcclusionPointer& ambientOcclusion) const; + Index addAmbientOcclusion(const AmbientOcclusionPointer& ambientOcclusion); + + AmbientOcclusionPointer removeAmbientOcclusion(Index index); + + bool checkAmbientOcclusionId(Index index) const { return _ambientOcclusions.checkIndex(index); } + + Index getNumAmbientOcclusions() const { return _ambientOcclusions.getNumElements(); } + Index getNumFreeAmbientOcclusions() const { return _ambientOcclusions.getNumFreeIndices(); } + Index getNumAllocatedAmbientOcclusions() const { return _ambientOcclusions.getNumAllocatedIndices(); } + + AmbientOcclusionPointer getAmbientOcclusion(Index ambientOcclusionId) const { + return _ambientOcclusions.get(ambientOcclusionId); + } + + AmbientOcclusions _ambientOcclusions; + AmbientOcclusionMap _ambientOcclusionMap; + + class Frame { + public: + Frame() {} + + void clear() { _ambientOcclusions.clear(); } + + void pushAmbientOcclusion(AmbientOcclusionStage::Index index) { _ambientOcclusions.emplace_back(index); } + + AmbientOcclusionStage::AmbientOcclusionIndices _ambientOcclusions; + }; + using FramePointer = std::shared_ptr; + + Frame _currentFrame; +}; +using AmbientOcclusionStagePointer = std::shared_ptr; + +class AmbientOcclusionStageSetup { +public: + using JobModel = render::Job::Model; + + AmbientOcclusionStageSetup(); + void run(const render::RenderContextPointer& renderContext); + +protected: +}; + +#endif diff --git a/libraries/render-utils/src/AssembleLightingStageTask.cpp b/libraries/render-utils/src/AssembleLightingStageTask.cpp index 589cdb31ea9..bc040582bd2 100644 --- a/libraries/render-utils/src/AssembleLightingStageTask.cpp +++ b/libraries/render-utils/src/AssembleLightingStageTask.cpp @@ -25,6 +25,14 @@ void FetchCurrentFrames::run(const render::RenderContextPointer& renderContext, auto bloomStage = renderContext->_scene->getStage(); assert(bloomStage); output.edit3() = std::make_shared(bloomStage->_currentFrame); + + auto tonemappingStage = renderContext->_scene->getStage(); + assert(tonemappingStage); + output.edit4() = std::make_shared(tonemappingStage->_currentFrame); + + auto ambientOcclusionStage = renderContext->_scene->getStage(); + assert(ambientOcclusionStage); + output.edit5() = std::make_shared(ambientOcclusionStage->_currentFrame); } @@ -47,4 +55,3 @@ void AssembleLightingStageTask::build(JobModel& task, const render::Varying& inp output = Output(currentStageFrames, zones); } - diff --git a/libraries/render-utils/src/AssembleLightingStageTask.h b/libraries/render-utils/src/AssembleLightingStageTask.h index 9770af473ca..17add988ef5 100644 --- a/libraries/render-utils/src/AssembleLightingStageTask.h +++ b/libraries/render-utils/src/AssembleLightingStageTask.h @@ -16,13 +16,16 @@ #include "BackgroundStage.h" #include "HazeStage.h" #include "BloomStage.h" +#include "TonemappingStage.h" +#include "AmbientOcclusionStage.h" #include "ZoneRenderer.h" class FetchCurrentFrames { public: - using Output = render::VaryingSet4; + using Output = render::VaryingSet6; using JobModel = render::Job::ModelO; FetchCurrentFrames() {} diff --git a/libraries/render-utils/src/BackgroundStage.cpp b/libraries/render-utils/src/BackgroundStage.cpp index 91b766d90be..455f356a456 100644 --- a/libraries/render-utils/src/BackgroundStage.cpp +++ b/libraries/render-utils/src/BackgroundStage.cpp @@ -15,7 +15,7 @@ #include -std::string BackgroundStage::_stageName { "BACKGROUND_STAGE"}; +std::string BackgroundStage::_stageName { "BACKGROUND_STAGE" }; const BackgroundStage::Index BackgroundStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX }; BackgroundStage::Index BackgroundStage::findBackground(const BackgroundPointer& background) const { diff --git a/libraries/render-utils/src/BloomStage.cpp b/libraries/render-utils/src/BloomStage.cpp index b3ba5f9565f..2bedfeea963 100644 --- a/libraries/render-utils/src/BloomStage.cpp +++ b/libraries/render-utils/src/BloomStage.cpp @@ -13,7 +13,7 @@ #include -std::string BloomStage::_stageName { "BLOOM_STAGE"}; +std::string BloomStage::_stageName { "BLOOM_STAGE" }; const BloomStage::Index BloomStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX }; BloomStage::Index BloomStage::findBloom(const BloomPointer& bloom) const { diff --git a/libraries/render-utils/src/BloomStage.h b/libraries/render-utils/src/BloomStage.h index 7ba7e560356..bb03e181af6 100644 --- a/libraries/render-utils/src/BloomStage.h +++ b/libraries/render-utils/src/BloomStage.h @@ -81,26 +81,4 @@ class BloomStageSetup { 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(); -}; - #endif diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp index dc1ffb7b671..78652bfb09b 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.cpp +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.cpp @@ -71,14 +71,15 @@ void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform _cauterizedTransform = renderTransform; } -void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const { - bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) && _enableCauterization; +void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode, size_t mirrorDepth) const { + bool useCauterizedMesh = _enableCauterization && (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) && + mirrorDepth == 0; if (useCauterizedMesh) { if (_cauterizedClusterBuffer) { batch.setUniformBuffer(graphics::slot::buffer::Skinning, _cauterizedClusterBuffer); } batch.setModelTransform(_cauterizedTransform); } else { - ModelMeshPartPayload::bindTransform(batch, transform, renderMode); + ModelMeshPartPayload::bindTransform(batch, transform, renderMode, mirrorDepth); } } diff --git a/libraries/render-utils/src/CauterizedMeshPartPayload.h b/libraries/render-utils/src/CauterizedMeshPartPayload.h index 430f41fc080..cef7b6d9b56 100644 --- a/libraries/render-utils/src/CauterizedMeshPartPayload.h +++ b/libraries/render-utils/src/CauterizedMeshPartPayload.h @@ -25,7 +25,7 @@ class CauterizedMeshPartPayload : public ModelMeshPartPayload { void updateTransformForCauterizedMesh(const Transform& modelTransform, const Model::MeshState& meshState, bool useDualQuaternionSkinning); - void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const override; + void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode, size_t mirrorDepth) const override; void setEnableCauterization(bool enableCauterization) { _enableCauterization = enableCauterization; } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 8d7fc345ac9..0ff1c435e17 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -286,6 +286,7 @@ void PrepareDeferred::run(const RenderContextPointer& renderContext, const Input outputs.edit0() = _deferredFramebuffer; outputs.edit1() = _deferredFramebuffer->getLightingFramebuffer(); + outputs.edit2() = _deferredFramebuffer->getDeferredFramebuffer(); gpu::doInBatch("PrepareDeferred::run", args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); @@ -661,5 +662,14 @@ void DefaultLightingSetup::run(const RenderContextPointer& renderContext) { _defaultHazeID = hazeStage->addHaze(_defaultHaze); } } -} + if (!_defaultTonemapping) { + auto tonemappingStage = renderContext->_scene->getStage(); + if (tonemappingStage) { + auto tonemapping = std::make_shared(); + + _defaultTonemapping = tonemapping; + _defaultTonemappingID = tonemappingStage->addTonemapping(_defaultTonemapping); + } + } +} diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 47793764106..73c43c52a3c 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -32,6 +32,7 @@ #include "LightClusters.h" #include "BackgroundStage.h" #include "HazeStage.h" +#include "TonemappingStage.h" #include "SurfaceGeometryPass.h" #include "SubsurfaceScattering.h" @@ -78,8 +79,8 @@ class PrepareDeferred { public: // Inputs: primaryFramebuffer and lightingModel using Inputs = render::VaryingSet2 ; - // Output: DeferredFramebuffer, LightingFramebuffer - using Outputs = render::VaryingSet2; + // Output: DeferredFramebuffer, LightingFramebuffer, the framebuffer to be used for mirrors (same as DeferredFramebuffer) + using Outputs = render::VaryingSet3; using JobModel = render::Job::ModelIO; @@ -162,11 +163,13 @@ class DefaultLightingSetup { protected: graphics::LightPointer _defaultLight; - LightStage::Index _defaultLightID{ LightStage::INVALID_INDEX }; + LightStage::Index _defaultLightID { LightStage::INVALID_INDEX }; graphics::SunSkyStagePointer _defaultBackground; - BackgroundStage::Index _defaultBackgroundID{ BackgroundStage::INVALID_INDEX }; - graphics::HazePointer _defaultHaze{ nullptr }; - HazeStage::Index _defaultHazeID{ HazeStage::INVALID_INDEX }; + BackgroundStage::Index _defaultBackgroundID { BackgroundStage::INVALID_INDEX }; + graphics::HazePointer _defaultHaze { nullptr }; + HazeStage::Index _defaultHazeID { HazeStage::INVALID_INDEX }; + graphics::TonemappingPointer _defaultTonemapping { nullptr }; + TonemappingStage::Index _defaultTonemappingID { TonemappingStage::INVALID_INDEX }; graphics::SkyboxPointer _defaultSkybox { new ProceduralSkybox() }; NetworkTexturePointer _defaultSkyboxNetworkTexture; NetworkTexturePointer _defaultAmbientNetworkTexture; diff --git a/libraries/render-utils/src/DrawHaze.cpp b/libraries/render-utils/src/DrawHaze.cpp index 012161ec033..71845be7313 100644 --- a/libraries/render-utils/src/DrawHaze.cpp +++ b/libraries/render-utils/src/DrawHaze.cpp @@ -31,6 +31,10 @@ namespace gr { using graphics::slot::buffer::Buffer; } +gpu::PipelinePointer DrawHaze::_hazePipeline = nullptr; +gpu::PipelinePointer DrawHaze::_separateHazePipeline = nullptr; +gpu::PipelinePointer DrawHaze::_separateHazeBackgroundPipeline = nullptr; + void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { const auto hazeFrame = inputs.get0(); const auto& hazeStage = renderContext->args->_scene->getStage(); @@ -55,15 +59,29 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu if (!_hazePipeline) { gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::haze); - gpu::StatePointer state = std::make_shared(); - state->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + auto createState = []() { + gpu::StatePointer state = std::make_shared(); + state->setBlendFunction(true, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + return state; + }; // Mask out haze on the tablet - PrepareStencil::testMask(*state); - _hazePipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + auto hazeState = createState(); + PrepareStencil::testMask(*hazeState); + _hazePipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, hazeState)); + + // For our separated passes, we perform one pass on anything marked shape, and one on just the background + auto hazeSeparatedState = createState(); + PrepareStencil::testShape(*hazeSeparatedState); + _separateHazePipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, hazeSeparatedState)); + + gpu::ShaderPointer backgroundProgram = gpu::Shader::createProgram(shader::render_utils::program::haze_background); + auto hazeBackgroundSeparatedState = createState(); + PrepareStencil::testBackground(*hazeBackgroundSeparatedState); + _separateHazeBackgroundPipeline = gpu::PipelinePointer(gpu::Pipeline::create(backgroundProgram, hazeBackgroundSeparatedState)); } auto outputFramebufferSize = glm::ivec2(outputBuffer->getSize()); @@ -77,7 +95,6 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu batch.resetViewTransform(); batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(outputFramebufferSize, args->_viewport)); - batch.setPipeline(_hazePipeline); batch.setUniformBuffer(graphics::slot::buffer::Buffer::HazeParams, haze->getHazeParametersBuffer()); batch.setUniformBuffer(ru::Buffer::DeferredFrameTransform, transformBuffer->getFrameTransformBuffer()); @@ -92,6 +109,15 @@ void DrawHaze::run(const render::RenderContextPointer& renderContext, const Inpu } } - batch.draw(gpu::TRIANGLE_STRIP, 4); + if (!_separateBackgroundPass) { + batch.setPipeline(_hazePipeline); + batch.draw(gpu::TRIANGLE_STRIP, 4); + } else { + batch.setPipeline(_separateHazePipeline); + batch.draw(gpu::TRIANGLE_STRIP, 4); + + batch.setPipeline(_separateHazeBackgroundPipeline); + batch.draw(gpu::TRIANGLE_STRIP, 4); + } }); } diff --git a/libraries/render-utils/src/DrawHaze.h b/libraries/render-utils/src/DrawHaze.h index 92365430687..82e8beaa9b8 100644 --- a/libraries/render-utils/src/DrawHaze.h +++ b/libraries/render-utils/src/DrawHaze.h @@ -33,10 +33,16 @@ class DrawHaze { using Inputs = render::VaryingSet6; using JobModel = render::Job::ModelI; + DrawHaze(bool separateBackgroundPass) : _separateBackgroundPass(separateBackgroundPass) {} + void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); private: - gpu::PipelinePointer _hazePipeline; + bool _separateBackgroundPass { false }; + + static gpu::PipelinePointer _hazePipeline; + static gpu::PipelinePointer _separateHazePipeline; + static gpu::PipelinePointer _separateHazeBackgroundPipeline; }; #endif // hifi_render_utils_DrawHaze_h diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 3f06a6b1a35..0265b5e35b4 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -147,7 +147,7 @@ class GeometryCache : public Dependency { NUM_SHAPES, }; - /// @param entityShapeEnum: The entity::Shape enumeration for the shape + /// @param entityShapeEnum: The EntityShape enumeration for the shape /// whose GeometryCache::Shape is desired. /// @return GeometryCache::NUM_SHAPES in the event of an error; otherwise, /// the GeometryCache::Shape enum which aligns with the diff --git a/libraries/render-utils/src/GlobalLight.slh b/libraries/render-utils/src/GlobalLight.slh index de8702ea8c3..0593abe375a 100644 --- a/libraries/render-utils/src/GlobalLight.slh +++ b/libraries/render-utils/src/GlobalLight.slh @@ -44,14 +44,6 @@ <@endfunc@> -<@func declareEvalAmbientGlobalColor()@> -vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, vec3 fresnel, float metallic, float roughness) { - <$prepareGlobalLight(position, normal)$> - color += albedo * getLightColor(light) * obscurance * getLightAmbientIntensity(lightAmbient); - return color; -} -<@endfunc@> - <@func declareEvalAmbientSphereGlobalColor(supportScattering)@> <$declareLightingAmbient(1, _SCRIBE_NULL, _SCRIBE_NULL, $supportScattering$)$> diff --git a/libraries/render-utils/src/Haze.slf b/libraries/render-utils/src/Haze.slf index 899f36b8ebf..9be64e76953 100644 --- a/libraries/render-utils/src/Haze.slf +++ b/libraries/render-utils/src/Haze.slf @@ -21,10 +21,16 @@ <@include graphics/Haze.slh@> +<@if not HIFI_USE_BACKGROUND@> LAYOUT(binding=RENDER_UTILS_TEXTURE_HAZE_LINEAR_DEPTH) uniform sampler2D linearDepthMap; +<@endif@> vec4 unpackPositionFromZeye(vec2 texcoord) { +<@if not HIFI_USE_BACKGROUND@> float Zeye = -texture(linearDepthMap, texcoord).x; +<@else@> + float Zeye = 1.0; // We just want to get the direction first +<@endif@> float check = float(isStereo()); float check2 = check * float(texcoord.x > 0.5); @@ -44,8 +50,14 @@ void main(void) { } vec4 fragPositionES = unpackPositionFromZeye(varTexCoord0); - mat4 viewInverse = getViewInverse(); + +<@if HIFI_USE_BACKGROUND@> + // We choose an arbitrary large number > BLEND_DISTANCE in Haze.slh + const float SKYBOX_DISTANCE = 32000.0; + fragPositionES = vec4(-SKYBOX_DISTANCE * normalize(fragPositionES.xyz), 1.0); +<@endif@> + vec4 fragPositionWS = viewInverse * fragPositionES; vec4 eyePositionWS = viewInverse[3]; diff --git a/libraries/render-utils/src/HazeStage.cpp b/libraries/render-utils/src/HazeStage.cpp index c850828be5c..9251e1e2f90 100644 --- a/libraries/render-utils/src/HazeStage.cpp +++ b/libraries/render-utils/src/HazeStage.cpp @@ -13,7 +13,7 @@ #include -std::string HazeStage::_stageName { "HAZE_STAGE"}; +std::string HazeStage::_stageName { "HAZE_STAGE" }; const HazeStage::Index HazeStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX }; HazeStage::Index HazeStage::findHaze(const HazePointer& haze) const { diff --git a/libraries/render-utils/src/HighlightEffect.cpp b/libraries/render-utils/src/HighlightEffect.cpp index baf3877e817..754c99c425c 100644 --- a/libraries/render-utils/src/HighlightEffect.cpp +++ b/libraries/render-utils/src/HighlightEffect.cpp @@ -474,13 +474,14 @@ void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, ren const auto jitter = inputs.getN(4); // Prepare the ShapePipeline - auto shapePlumber = std::make_shared(); - { + static ShapePlumberPointer shapePlumber = std::make_shared(); + static std::once_flag once; + std::call_once(once, [] { auto state = std::make_shared(); state->setColorWriteMask(false, false, false, false); auto fadeEffect = DependencyManager::get(); initZPassPipelines(*shapePlumber, state, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); - } + }); auto sharedParameters = std::make_shared(); const auto selectionToHighlightInputs = SelectionToHighlight::Inputs(outlines, primaryFramebuffer).asVarying(); diff --git a/libraries/render-utils/src/LightAmbient.slh b/libraries/render-utils/src/LightAmbient.slh index cb76a8e5454..81c672292ab 100644 --- a/libraries/render-utils/src/LightAmbient.slh +++ b/libraries/render-utils/src/LightAmbient.slh @@ -2,6 +2,7 @@ // // Created by Sam Gateau on 7/5/16. // Copyright 2016 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -74,7 +75,7 @@ vec3 evalAmbientSpecularIrradiance(LightAmbient ambient, SurfaceData surface, ve } <@endif@> - return specularLight; + return applySkyboxColorMix(specularLight, getLightAmbientColor(ambient), getLightAmbientBlend(ambient)); } <@endfunc@> @@ -104,8 +105,9 @@ void evalLightingAmbient(out vec3 diffuse, out vec3 specular, LightAmbient ambie vec3 ambientFresnel = fresnelSchlickAmbient(fresnelF0, surface.ndotv, surface.roughness); - diffuse = (1.0 - metallic) * (vec3(1.0) - ambientFresnel) * - sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(ambient), ambientSpaceSurfaceNormal).xyz; + diffuse = (1.0 - metallic) * (vec3(1.0) - ambientFresnel) * + applySkyboxColorMix(sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(ambient), ambientSpaceSurfaceNormal).xyz, + getLightAmbientColor(ambient), getLightAmbientBlend(ambient)); // Specular highlight from ambient vec3 ambientSpaceLightDir = -reflect(ambientSpaceSurfaceEyeDir, ambientSpaceSurfaceNormal); @@ -120,7 +122,8 @@ void evalLightingAmbient(out vec3 diffuse, out vec3 specular, LightAmbient ambie obscurance = min(obscurance, ambientOcclusion); // Diffuse from ambient - diffuse = sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(ambient), ambientSpaceLowNormal).xyz; + diffuse = applySkyboxColorMix(sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(ambient), ambientSpaceLowNormal).xyz, + getLightAmbientColor(ambient), getLightAmbientBlend(ambient)); // Scattering ambient specular is the same as non scattering for now // TODO: we should use the same specular answer as for direct lighting diff --git a/libraries/render-utils/src/LightStage.cpp b/libraries/render-utils/src/LightStage.cpp index ccdf45cedcc..58f32cdc4e5 100644 --- a/libraries/render-utils/src/LightStage.cpp +++ b/libraries/render-utils/src/LightStage.cpp @@ -15,7 +15,7 @@ #include "ViewFrustum.h" -std::string LightStage::_stageName { "LIGHT_STAGE"}; +std::string LightStage::_stageName { "LIGHT_STAGE" }; // The bias matrix goes from homogeneous coordinates to UV coords (see http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-16-shadow-mapping/#basic-shader) const glm::mat4 LightStage::Shadow::_biasMatrix { 0.5, 0.0, 0.0, 0.0, diff --git a/libraries/render-utils/src/LightingModel.h b/libraries/render-utils/src/LightingModel.h index a488abcb09a..c5811b11109 100644 --- a/libraries/render-utils/src/LightingModel.h +++ b/libraries/render-utils/src/LightingModel.h @@ -4,6 +4,7 @@ // // Created by Sam Gateau 7/1/2016. // Copyright 2016 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -17,14 +18,13 @@ #include #include -// LightingModel is a helper class gathering in one place the flags to enable the lighting contributions +// LightingModel is a helper class gathering in one place the flags to enable the lighting contributions class LightingModel { public: using UniformBufferView = gpu::BufferView; LightingModel(); - void setUnlit(bool enable); bool isUnlitEnabled() const; @@ -76,7 +76,6 @@ class LightingModel { void setBlendshape(bool enable); bool isBlendshapeEnabled() const; - void setAmbientOcclusion(bool enable); bool isAmbientOcclusionEnabled() const; void setShadow(bool enable); @@ -86,55 +85,49 @@ class LightingModel { gpu::TexturePointer getAmbientFresnelLUT() const { return _ambientFresnelLUT; } protected: - - // Class describing the uniform buffer with the transform info common to the AO shaders // It s changing every frame class Parameters { public: - float enableUnlit{ 1.0f }; - float enableEmissive{ 1.0f }; - float enableLightmap{ 1.0f }; - float enableBackground{ 1.0f }; + float enableUnlit { 1.0f }; + float enableEmissive { 1.0f }; + float enableLightmap { 1.0f }; + float enableBackground { 1.0f }; - float enableScattering{ 1.0f }; - float enableDiffuse{ 1.0f }; - float enableSpecular{ 1.0f }; - float enableAlbedo{ 1.0f }; + float enableScattering { 1.0f }; + float enableDiffuse { 1.0f }; + float enableSpecular { 1.0f }; + float enableAlbedo { 1.0f }; - float enableAmbientLight{ 1.0f }; - float enableDirectionalLight{ 1.0f }; - float enablePointLight{ 1.0f }; - float enableSpotLight{ 1.0f }; + float enableAmbientLight { 1.0f }; + float enableDirectionalLight { 1.0f }; + float enablePointLight { 1.0f }; + float enableSpotLight { 1.0f }; float showLightContour { 0.0f }; // false by default - float enableObscurance{ 1.0f }; + float enableObscurance { 1.0f }; float enableMaterialTexturing { 1.0f }; float enableWireframe { 0.0f }; // false by default - float enableHaze{ 1.0f }; - float enableBloom{ 1.0f }; - float enableSkinning{ 1.0f }; - float enableBlendshape{ 1.0f }; + float enableHaze { 1.0f }; + float enableBloom { 1.0f }; + float enableSkinning { 1.0f }; + float enableBlendshape { 1.0f }; - float enableAmbientOcclusion{ 0.0f }; // false by default - float enableShadow{ 1.0f }; - float spare1{ 1.0f }; - float spare2{ 1.0f }; + float enableAmbientOcclusion { 1.0f }; + float enableShadow { 1.0f }; + float spare1 { 1.0f }; + float spare2 { 1.0f }; Parameters() {} }; UniformBufferView _parametersBuffer; static gpu::TexturePointer _ambientFresnelLUT; }; - using LightingModelPointer = std::shared_ptr; - - - class MakeLightingModelConfig : public render::Job::Config { Q_OBJECT @@ -168,44 +161,44 @@ class MakeLightingModelConfig : public render::Job::Config { Q_PROPERTY(bool enableAmbientOcclusion READ isAmbientOcclusionEnabled WRITE setAmbientOcclusion NOTIFY dirty) Q_PROPERTY(bool enableShadow READ isShadowEnabled WRITE setShadow NOTIFY dirty) - public: MakeLightingModelConfig() : render::Job::Config() {} // Make Lighting Model is always on - bool enableUnlit{ true }; - bool enableEmissive{ true }; - bool enableLightmap{ true }; - bool enableBackground{ true }; - bool enableObscurance{ true }; + bool enableUnlit { true }; + bool enableEmissive { true }; + bool enableLightmap { true }; + bool enableBackground { true }; + bool enableObscurance { true }; - bool enableScattering{ true }; - bool enableDiffuse{ true }; - bool enableSpecular{ true }; + bool enableScattering { true }; + bool enableDiffuse { true }; + bool enableSpecular { true }; - bool enableAlbedo{ true }; + bool enableAlbedo { true }; bool enableMaterialTexturing { true }; - bool enableAmbientLight{ true }; - bool enableDirectionalLight{ true }; - bool enablePointLight{ true }; - bool enableSpotLight{ true }; + bool enableAmbientLight { true }; + bool enableDirectionalLight { true }; + bool enablePointLight { true }; + bool enableSpotLight { true }; bool showLightContour { false }; // false by default bool enableWireframe { false }; // false by default - bool enableHaze{ true }; - bool enableBloom{ true }; - bool enableSkinning{ true }; - bool enableBlendshape{ true }; - - bool enableAmbientOcclusion{ false }; // false by default - bool enableShadow{ true }; + bool enableHaze { true }; + bool enableBloom { true }; + bool enableSkinning { true }; + bool enableBlendshape { true }; + bool enableAmbientOcclusion { true }; + bool enableShadow { true }; void setAmbientOcclusion(bool enable) { enableAmbientOcclusion = enable; emit dirty();} bool isAmbientOcclusionEnabled() const { return enableAmbientOcclusion; } void setShadow(bool enable) { enableShadow = enable; emit dirty(); } bool isShadowEnabled() const { return enableShadow; } + void setHaze(bool enable) { enableHaze = enable; emit dirty(); } + void setBloom(bool enable) { enableBloom = enable; emit dirty(); } signals: void dirty(); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index a77dc6b1604..0ea4f147677 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -13,6 +13,7 @@ #include "MeshPartPayload.h" #include +#include #include #include #include @@ -187,7 +188,7 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) { batch.setInputStream(0, _drawMesh->getVertexStream()); } -void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const { +void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode, size_t mirrorDepth) const { if (_clusterBuffer) { batch.setUniformBuffer(graphics::slot::buffer::Skinning, _clusterBuffer); } @@ -219,6 +220,10 @@ void ModelMeshPartPayload::updateKey(const render::ItemKey& key) { builder.withSubMetaCulled(); } + if (_mirrorMode == MirrorMode::MIRROR || (_mirrorMode == MirrorMode::PORTAL && !_portalExitID.isNull())) { + builder.withMirror(); + } + if (_drawMaterials.hasOutline()) { builder.withOutline(); } @@ -306,8 +311,9 @@ Item::Bound ModelMeshPartPayload::getBound(RenderArgs* args) const { auto worldBound = _adjustedLocalBound; auto parentTransform = _parentTransform; if (args) { + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; parentTransform.setRotation(BillboardModeHelpers::getBillboardRotation(parentTransform.getTranslation(), parentTransform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); } worldBound.transform(parentTransform); return worldBound; @@ -320,18 +326,19 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { void ModelMeshPartPayload::render(RenderArgs* args) { PerformanceTimer perfTimer("ModelMeshPartPayload::render"); - if (!args || (args->_renderMode == RenderArgs::RenderMode::DEFAULT_RENDER_MODE && _cauterized)) { + if (!args || (_cauterized && args->_renderMode == RenderArgs::RenderMode::DEFAULT_RENDER_MODE && args->_mirrorDepth == 0)) { return; } gpu::Batch& batch = *(args->_batch); Transform transform = _parentTransform; + bool usePrimaryFrustum = args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE || args->_mirrorDepth > 0; transform.setRotation(BillboardModeHelpers::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, - args->_renderMode == RenderArgs::RenderMode::SHADOW_RENDER_MODE ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); + usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition())); Transform modelTransform = transform.worldTransform(_localTransform); - bindTransform(batch, modelTransform, args->_renderMode); + bindTransform(batch, modelTransform, args->_renderMode, args->_mirrorDepth); //Bind the index buffer and vertex buffer and Blend shapes if needed bindMesh(batch); @@ -352,7 +359,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) { const uint32_t compactColor = GeometryCache::toCompactColor(glm::vec4(outColor)); _drawMesh->getColorBuffer()->setData(sizeof(compactColor), (const gpu::Byte*) &compactColor); - } else { + } else if (!_itemKey.isMirror()) { // apply material properties if (RenderPipelines::bindMaterials(_drawMaterials, batch, args->_renderMode, args->_enableTexturing)) { args->_details._materialSwitches++; @@ -386,6 +393,12 @@ bool ModelMeshPartPayload::passesZoneOcclusionTest(const std::unordered_set bool payloadPassesZoneOcclusionTest(const ModelMeshPartPayload::Poin return false; } +template <> ItemID payloadComputeMirrorView(const ModelMeshPartPayload::Pointer& payload, ViewFrustum& viewFrustum) { + if (payload) { + return payload->computeMirrorView(viewFrustum); + } + return Item::INVALID_ITEM_ID; +} + template <> HighlightStyle payloadGetOutlineStyle(const ModelMeshPartPayload::Pointer& payload, const ViewFrustum& viewFrustum, const size_t height) { if (payload) { return payload->getOutlineStyle(viewFrustum, height); diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 08183409815..ecc9e997f0e 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -39,7 +39,7 @@ class ModelMeshPartPayload { // ModelMeshPartPayload functions to perform render void bindMesh(gpu::Batch& batch); - virtual void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode) const; + virtual void bindTransform(gpu::Batch& batch, const Transform& transform, RenderArgs::RenderMode renderMode, size_t mirrorDepth) const; void drawCall(gpu::Batch& batch) const; void updateKey(const render::ItemKey& key); @@ -60,7 +60,10 @@ class ModelMeshPartPayload { void setCullWithParent(bool value) { _cullWithParent = value; } void setRenderWithZones(const QVector& renderWithZones) { _renderWithZones = renderWithZones; } void setBillboardMode(BillboardMode billboardMode) { _billboardMode = billboardMode; } + void setMirrorMode(MirrorMode mirrorMode) { _mirrorMode = mirrorMode; } + void setPortalExitID(const QUuid& portalExitID) { _portalExitID = portalExitID; } bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const; + render::ItemID computeMirrorView(ViewFrustum& viewFrustum) const; render::HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const; void addMaterial(graphics::MaterialLayer material) { _drawMaterials.push(material); } @@ -94,6 +97,8 @@ class ModelMeshPartPayload { bool _cullWithParent { false }; QVector _renderWithZones; BillboardMode _billboardMode { BillboardMode::NONE }; + MirrorMode _mirrorMode { MirrorMode::NONE }; + QUuid _portalExitID; uint64_t _created; Transform _localTransform; @@ -108,6 +113,7 @@ namespace render { template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload); template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args); template <> bool payloadPassesZoneOcclusionTest(const ModelMeshPartPayload::Pointer& payload, const std::unordered_set& containingZones); + template <> ItemID payloadComputeMirrorView(const ModelMeshPartPayload::Pointer& payload, ViewFrustum& viewFrustum); template <> HighlightStyle payloadGetOutlineStyle(const ModelMeshPartPayload::Pointer& payload, const ViewFrustum& viewFrustum, const size_t height); } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 71947f918a4..69a593ed097 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -232,6 +232,8 @@ void Model::updateRenderItems() { auto renderWithZones = self->getRenderWithZones(); auto renderItemKeyGlobalFlags = self->getRenderItemKeyGlobalFlags(); bool cauterized = self->isCauterized(); + auto mirrorMode = self->getMirrorMode(); + const QUuid& portalExitID = self->getPortalExitID(); render::Transaction transaction; for (int i = 0; i < (int) self->_modelMeshRenderItemIDs.size(); i++) { @@ -246,7 +248,7 @@ void Model::updateRenderItems() { transaction.updateItem(itemID, [modelTransform, meshState, useDualQuaternionSkinning, invalidatePayloadShapeKey, primitiveMode, billboardMode, renderItemKeyGlobalFlags, - cauterized, renderWithZones](ModelMeshPartPayload& data) { + cauterized, renderWithZones, mirrorMode, portalExitID](ModelMeshPartPayload& data) { if (useDualQuaternionSkinning) { data.updateClusterBuffer(meshState.clusterDualQuaternions); data.computeAdjustedLocalBound(meshState.clusterDualQuaternions); @@ -260,6 +262,8 @@ void Model::updateRenderItems() { data.setCauterized(cauterized); data.setRenderWithZones(renderWithZones); data.setBillboardMode(billboardMode); + data.setMirrorMode(mirrorMode); + data.setPortalExitID(portalExitID); data.updateKey(renderItemKeyGlobalFlags); data.setShapeKey(invalidatePayloadShapeKey, primitiveMode, useDualQuaternionSkinning); }); @@ -1065,6 +1069,46 @@ void Model::setRenderWithZones(const QVector& renderWithZones, const rend } } +void Model::setMirrorMode(MirrorMode mirrorMode, const render::ScenePointer& scene) { + if (_mirrorMode != mirrorMode) { + _mirrorMode = mirrorMode; + if (!scene) { + _needsFixupInScene = true; + return; + } + + render::Transaction transaction; + auto renderItemsKey = _renderItemKeyGlobalFlags; + for (auto item : _modelMeshRenderItemIDs) { + transaction.updateItem(item, [mirrorMode, renderItemsKey](ModelMeshPartPayload& data) { + data.setMirrorMode(mirrorMode); + data.updateKey(renderItemsKey); + }); + } + scene->enqueueTransaction(transaction); + } +} + +void Model::setPortalExitID(const QUuid& portalExitID, const render::ScenePointer& scene) { + if (_portalExitID != portalExitID) { + _portalExitID = portalExitID; + if (!scene) { + _needsFixupInScene = true; + return; + } + + render::Transaction transaction; + auto renderItemsKey = _renderItemKeyGlobalFlags; + for (auto item : _modelMeshRenderItemIDs) { + transaction.updateItem(item, [portalExitID, renderItemsKey](ModelMeshPartPayload& data) { + data.setPortalExitID(portalExitID); + data.updateKey(renderItemsKey); + }); + } + scene->enqueueTransaction(transaction); + } +} + const render::ItemKey Model::getRenderItemKeyGlobalFlags() const { return _renderItemKeyGlobalFlags; } @@ -1299,7 +1343,7 @@ void Model::setURL(const QUrl& url) { auto resource = DependencyManager::get()->getGeometryResource(url); if (resource) { - resource->setLoadPriority(this, _loadingPriority); + resource->setLoadPriorityOperator(this, _loadingPriorityOperator); _renderWatcher.setResource(resource); } _rig.initFlow(false); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 17b7df9b233..bc9b8fcfff0 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -41,6 +41,7 @@ #include "Rig.h" #include "PrimitiveMode.h" #include "BillboardMode.h" +#include "MirrorMode.h" // Use dual quaternion skinning! // Must match define in Skinning.slh @@ -131,6 +132,12 @@ class Model : public QObject, public std::enable_shared_from_this, public void setRenderWithZones(const QVector& renderWithZones, const render::ScenePointer& scene = nullptr); const QVector& getRenderWithZones() const { return _renderWithZones; } + void setMirrorMode(MirrorMode mirrorMode, const render::ScenePointer& scene = nullptr); + MirrorMode getMirrorMode() const { return _mirrorMode; } + + void setPortalExitID(const QUuid& portalExitID, const render::ScenePointer& scene = nullptr); + const QUuid& getPortalExitID() const { return _portalExitID; } + // Access the current RenderItemKey Global Flags used by the model and applied to the render items representing the parts of the model. const render::ItemKey getRenderItemKeyGlobalFlags() const; @@ -288,7 +295,7 @@ class Model : public QObject, public std::enable_shared_from_this, public // returns 'true' if needs fullUpdate after geometry change virtual bool updateGeometry(); - void setLoadingPriority(float priority) { _loadingPriority = priority; } + void setLoadingPriorityOperator(std::function priorityOperator) { _loadingPriorityOperator = priorityOperator; } size_t getRenderInfoVertexCount() const { return _renderInfoVertexCount; } size_t getRenderInfoTextureSize(); @@ -503,13 +510,15 @@ public slots: bool _cauterized { false }; bool _cullWithParent { false }; QVector _renderWithZones; + MirrorMode _mirrorMode { MirrorMode::NONE }; + QUuid _portalExitID; bool shouldInvalidatePayloadShapeKey(int meshIndex); uint64_t _created; private: - float _loadingPriority { 0.0f }; + std::function _loadingPriorityOperator { []() { return 0.0f; } }; void calculateTextureInfo(); diff --git a/libraries/render-utils/src/RenderCommonTask.cpp b/libraries/render-utils/src/RenderCommonTask.cpp index 3853d06d31b..1055a4256d0 100644 --- a/libraries/render-utils/src/RenderCommonTask.cpp +++ b/libraries/render-utils/src/RenderCommonTask.cpp @@ -13,7 +13,10 @@ #include "render-utils/ShaderConstants.h" #include "DeferredLightingEffect.h" +#include "FadeEffect.h" #include "RenderUtilsLogging.h" +#include "RenderViewTask.h" +#include "StencilMaskPass.h" namespace ru { using render_utils::slot::texture::Texture; @@ -25,9 +28,11 @@ namespace gr { using graphics::slot::buffer::Buffer; } +using RenderArgsPointer = std::shared_ptr; using namespace render; extern void initForwardPipelines(ShapePlumber& plumber); +extern void initMirrorPipelines(ShapePlumber& plumber, gpu::StatePointer state, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter, bool forward); void BeginGPURangeTimer::run(const render::RenderContextPointer& renderContext, gpu::RangeTimerPointer& timer) { timer = _gpuTimer; @@ -45,10 +50,14 @@ void EndGPURangeTimer::run(const render::RenderContextPointer& renderContext, co config->setGPUBatchRunTime(timer->getGPUAverage(), timer->getBatchAverage()); } +render::ShapePlumberPointer DrawLayered3D::_shapePlumber = std::make_shared(); + DrawLayered3D::DrawLayered3D(bool opaque) : - _shapePlumber(std::make_shared()), _opaquePass(opaque) { - initForwardPipelines(*_shapePlumber); + static std::once_flag once; + std::call_once(once, [] { + initForwardPipelines(*_shapePlumber); + }); } void DrawLayered3D::run(const RenderContextPointer& renderContext, const Inputs& inputs) { @@ -273,3 +282,170 @@ void ResolveFramebuffer::run(const render::RenderContextPointer& renderContext, } } +class SetupMirrorTask { +public: + using Input = RenderMirrorTask::Inputs; + using Outputs = render::VaryingSet4; + using JobModel = render::Job::ModelIO; + + SetupMirrorTask(size_t mirrorIndex, size_t depth) : _mirrorIndex(mirrorIndex), _depth(depth) {} + + void run(const render::RenderContextPointer& renderContext, const Input& inputs, Outputs& outputs) { + auto args = renderContext->args; + auto items = inputs.get0(); + + if (items.empty() || _mirrorIndex > items.size() - 1) { + renderContext->taskFlow.abortTask(); + return; + } + + auto inputFramebuffer = inputs.get1(); + if (!_mirrorFramebuffer || _mirrorFramebuffer->getWidth() != inputFramebuffer->getWidth() || _mirrorFramebuffer->getHeight() != inputFramebuffer->getHeight()) { + _mirrorFramebuffer.reset(gpu::Framebuffer::create("mirror" + _mirrorIndex, gpu::Element::COLOR_SRGBA_32, inputFramebuffer->getWidth(), inputFramebuffer->getHeight())); + } + + render::ItemBound mirror = items[_mirrorIndex]; + + _cachedArgsPointer->_renderMode = args->_renderMode; + _cachedArgsPointer->_blitFramebuffer = args->_blitFramebuffer; + _cachedArgsPointer->_ignoreItem = args->_ignoreItem; + _cachedArgsPointer->_mirrorDepth = args->_mirrorDepth; + _cachedArgsPointer->_numMirrorFlips = args->_numMirrorFlips; + + ViewFrustum srcViewFrustum = args->getViewFrustum(); + ItemID portalExitID = args->_scene->getItem(mirror.id).computeMirrorView(srcViewFrustum); + + args->_blitFramebuffer = _mirrorFramebuffer; + args->_ignoreItem = portalExitID != Item::INVALID_ITEM_ID ? portalExitID : mirror.id; + args->_mirrorDepth = _depth; + args->_numMirrorFlips += portalExitID != Item::INVALID_ITEM_ID ? 0 : 1; + + gpu::doInBatch("SetupMirrorTask::run", args->_context, [&](gpu::Batch& batch) { + bool shouldMirror = args->_numMirrorFlips % 2 == (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); + batch.setContextMirrorViewCorrection(shouldMirror); + }); + + // Without calculating the bound planes, the mirror will use the same culling frustum as the main camera, + // which is not what we want here. + srcViewFrustum.calculate(); + args->pushViewFrustum(srcViewFrustum); + + outputs.edit0() = mirror; + outputs.edit1() = inputFramebuffer; + outputs.edit2() = _cachedArgsPointer; + outputs.edit3() = inputs.get2(); + } + +protected: + gpu::FramebufferPointer _mirrorFramebuffer { nullptr }; + RenderArgsPointer _cachedArgsPointer { std::make_shared() }; + size_t _mirrorIndex; + size_t _depth; + +}; + +class DrawMirrorTask { +public: + using Inputs = SetupMirrorTask::Outputs; + using JobModel = render::Job::ModelI; + + DrawMirrorTask() { + static std::once_flag once; + std::call_once(once, [this] { + auto state = std::make_shared(); + state->setCullMode(gpu::State::CULL_BACK); + state->setDepthTest(true, true, gpu::LESS_EQUAL); + PrepareStencil::testMaskDrawShape(*state); + + auto fadeEffect = DependencyManager::get(); + initMirrorPipelines(*_forwardPipelines, state, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter(), true); + initMirrorPipelines(*_deferredPipelines, state, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter(), false); + }); + } + + void run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { + auto args = renderContext->args; + auto mirror = inputs.get0(); + auto framebuffer = inputs.get1(); + auto cachedArgs = inputs.get2(); + auto jitter = inputs.get3(); + + if (cachedArgs) { + args->_renderMode = cachedArgs->_renderMode; + } + args->popViewFrustum(); + + gpu::doInBatch("DrawMirrorTask::run", args->_context, [&](gpu::Batch& batch) { + args->_batch = &batch; + + if (cachedArgs) { + bool shouldMirror = cachedArgs->_numMirrorFlips % 2 == (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); + batch.setContextMirrorViewCorrection(shouldMirror); + } + + batch.setFramebuffer(framebuffer); + batch.setViewportTransform(args->_viewport); + batch.setStateScissorRect(args->_viewport); + + glm::mat4 projMat; + Transform viewMat; + args->getViewFrustum().evalProjectionMatrix(projMat); + args->getViewFrustum().evalViewTransform(viewMat); + + batch.setProjectionTransform(projMat); + batch.setProjectionJitter(jitter.x, jitter.y); + batch.setViewTransform(viewMat); + + batch.setResourceTexture(gr::Texture::MaterialMirror, args->_blitFramebuffer->getRenderBuffer(0)); + + renderShapes(renderContext, args->_renderMethod == render::Args::RenderMethod::FORWARD ? _forwardPipelines : _deferredPipelines, { mirror }); + + args->_batch = nullptr; + }); + + if (cachedArgs) { + // Restore the blit framebuffer after we've sampled from it + args->_blitFramebuffer = cachedArgs->_blitFramebuffer; + args->_ignoreItem = cachedArgs->_ignoreItem; + args->_mirrorDepth = cachedArgs->_mirrorDepth; + args->_numMirrorFlips = cachedArgs->_numMirrorFlips; + } + } + +private: + static ShapePlumberPointer _forwardPipelines; + static ShapePlumberPointer _deferredPipelines; +}; + +ShapePlumberPointer DrawMirrorTask::_forwardPipelines = std::make_shared(); +ShapePlumberPointer DrawMirrorTask::_deferredPipelines = std::make_shared(); + + void RenderMirrorTask::build(JobModel& task, const render::Varying& inputs, render::Varying& output, size_t mirrorIndex, render::CullFunctor cullFunctor, size_t depth) { + size_t nextDepth = depth + 1; + const auto setupOutput = task.addJob("SetupMirror" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), inputs, mirrorIndex, nextDepth); + + task.addJob("RenderMirrorView" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), cullFunctor, render::ItemKey::TAG_BITS_1, render::ItemKey::TAG_BITS_1, nextDepth); + + task.addJob("DrawMirrorTask" + std::to_string(mirrorIndex) + "Depth" + std::to_string(depth), setupOutput); + } + +void RenderSimulateTask::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { + auto args = renderContext->args; + auto items = inputs.get0(); + auto framebuffer = inputs.get1(); + + gpu::doInBatch("RenderSimulateTask::run", args->_context, [&](gpu::Batch& batch) { + args->_batch = &batch; + + for (ItemBound& item : items) { + args->_scene->simulate(item.id, args); + } + + // Reset render state after each simulate + batch.setFramebuffer(framebuffer); + batch.setViewportTransform(args->_viewport); + batch.setStateScissorRect(args->_viewport); + + args->_batch = nullptr; + }); +} \ No newline at end of file diff --git a/libraries/render-utils/src/RenderCommonTask.h b/libraries/render-utils/src/RenderCommonTask.h index 15d6ff98955..255fcb63921 100644 --- a/libraries/render-utils/src/RenderCommonTask.h +++ b/libraries/render-utils/src/RenderCommonTask.h @@ -10,6 +10,8 @@ #define hifi_RenderCommonTask_h #include +#include + #include "LightStage.h" #include "HazeStage.h" #include "LightingModel.h" @@ -71,7 +73,7 @@ class DrawLayered3D { void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); protected: - render::ShapePlumberPointer _shapePlumber; + static render::ShapePlumberPointer _shapePlumber; int _maxDrawn; // initialized by Config bool _opaquePass { true }; }; @@ -152,4 +154,27 @@ class SetRenderMethod { render::Args::RenderMethod _method; }; +class RenderMirrorTask { +public: + using Inputs = render::VaryingSet3; + using JobModel = render::Task::ModelI; + + RenderMirrorTask() {} + + void build(JobModel& task, const render::Varying& inputs, render::Varying& output, size_t mirrorIndex, render::CullFunctor cullFunctor, size_t depth); + + static const size_t MAX_MIRROR_DEPTH { 3 }; + static const size_t MAX_MIRRORS_PER_LEVEL { 3 }; +}; + +class RenderSimulateTask { +public: + using Inputs = render::VaryingSet2; + using JobModel = render::Job::ModelI; + + RenderSimulateTask() {} + + void run(const render::RenderContextPointer& renderContext, const Inputs& inputs); +}; + #endif // hifi_RenderDeferredTask_h diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index c506f22bc71..b8bc9a542b8 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -100,11 +100,14 @@ void RenderDeferredTask::configure(const Config& config) { preparePrimaryBufferConfig->setResolutionScale(config.resolutionScale); } -void RenderDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { - auto fadeEffect = DependencyManager::get(); +void RenderDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, size_t depth) { + static auto fadeEffect = DependencyManager::get(); // Prepare the ShapePipelines - ShapePlumberPointer shapePlumber = std::make_shared(); - initDeferredPipelines(*shapePlumber, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); + static ShapePlumberPointer shapePlumber = std::make_shared(); + static std::once_flag once; + std::call_once(once, [] { + initDeferredPipelines(*shapePlumber, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); + }); const auto& inputs = input.get(); @@ -116,6 +119,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Extract opaques / transparents / lights / metas / layered / background const auto& opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE]; const auto& transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE]; + const auto& mirrors = items[RenderFetchCullSortTask::MIRROR]; + const auto& simulateItems = items[RenderFetchCullSortTask::SIMULATE]; const auto& inFrontOpaque = items[RenderFetchCullSortTask::LAYER_FRONT_OPAQUE_SHAPE]; const auto& inFrontTransparent = items[RenderFetchCullSortTask::LAYER_FRONT_TRANSPARENT_SHAPE]; const auto& hudOpaque = items[RenderFetchCullSortTask::LAYER_HUD_OPAQUE_SHAPE]; @@ -132,6 +137,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto backgroundFrame = currentStageFrames[1]; const auto& hazeFrame = currentStageFrames[2]; const auto& bloomFrame = currentStageFrames[3]; + const auto& tonemappingFrame = currentStageFrames[4]; + const auto& ambientOcclusionFrame = currentStageFrames[5]; // Shadow Task Outputs const auto& shadowTaskOutputs = inputs.get3(); @@ -139,7 +146,6 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren // Shadow Stage Frame const auto shadowFrame = shadowTaskOutputs[1]; - fadeEffect->build(task, opaques); const auto jitter = task.addJob("JitterCam"); @@ -154,6 +160,12 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto prepareDeferredOutputs = task.addJob("PrepareDeferred", prepareDeferredInputs); const auto deferredFramebuffer = prepareDeferredOutputs.getN(0); const auto lightingFramebuffer = prepareDeferredOutputs.getN(1); + const auto mainTargetFramebuffer = prepareDeferredOutputs.getN(2); + + if (depth == 0) { + const auto simulateInputs = RenderSimulateTask::Inputs(simulateItems, mainTargetFramebuffer).asVarying(); + task.addJob("RenderSimulation", simulateInputs); + } // draw a stencil mask in hidden regions of the framebuffer. task.addJob("PrepareStencil", scaledPrimaryFramebuffer); @@ -162,6 +174,13 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel, jitter).asVarying(); task.addJob("DrawOpaqueDeferred", opaqueInputs, shapePlumber); + if (depth < RenderMirrorTask::MAX_MIRROR_DEPTH) { + const auto mirrorInputs = RenderMirrorTask::Inputs(mirrors, mainTargetFramebuffer, jitter).asVarying(); + for (size_t i = 0; i < RenderMirrorTask::MAX_MIRRORS_PER_LEVEL; i++) { + task.addJob("RenderMirrorTask" + std::to_string(i) + "Depth" + std::to_string(depth), mirrorInputs, i, cullFunctor, depth); + } + } + // Opaque all rendered // Linear Depth Pass @@ -181,7 +200,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto scatteringResource = task.addJob("Scattering"); // AO job - const auto ambientOcclusionInputs = AmbientOcclusionEffect::Input(lightingModel, deferredFrameTransform, deferredFramebuffer, linearDepthTarget).asVarying(); + const auto ambientOcclusionInputs = AmbientOcclusionEffect::Input(lightingModel, deferredFrameTransform, deferredFramebuffer, linearDepthTarget, ambientOcclusionFrame).asVarying(); const auto ambientOcclusionOutputs = task.addJob("AmbientOcclusion", ambientOcclusionInputs); const auto ambientOcclusionFramebuffer = ambientOcclusionOutputs.getN(0); const auto ambientOcclusionUniforms = ambientOcclusionOutputs.getN(1); @@ -206,7 +225,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren task.addJob("DrawBackgroundDeferred", backgroundInputs); const auto drawHazeInputs = render::Varying(DrawHaze::Inputs(hazeFrame, lightingFramebuffer, linearDepthTarget, deferredFrameTransform, lightingModel, lightFrame)); - task.addJob("DrawHazeDeferred", drawHazeInputs); + task.addJob("DrawHazeDeferred", drawHazeInputs, depth > 0); // Render transparent objects forward in LightingBuffer const auto transparentsInputs = RenderTransparentDeferred::Inputs(transparents, hazeFrame, lightFrame, lightingModel, lightClusters, shadowFrame, jitter).asVarying(); @@ -233,7 +252,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto destFramebuffer = static_cast(nullptr); // Lighting Buffer ready for tone mapping - const auto toneMappingInputs = ToneMapAndResample::Input(lightingFramebuffer, destFramebuffer).asVarying(); + const auto toneMappingInputs = ToneMapAndResample::Input(lightingFramebuffer, destFramebuffer, tonemappingFrame).asVarying(); const auto toneMappedBuffer = task.addJob("ToneMapping", toneMappingInputs); // Debugging task is happening in the "over" layer after tone mapping and just before HUD @@ -398,8 +417,12 @@ void RenderDeferredTaskDebug::build(JobModel& task, const render::Varying& input // Status icon rendering job { // Grab a texture map representing the different status icons and assign that to the drawStatusJob - auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg"; - auto statusIconMap = DependencyManager::get()->getImageTexture(iconMapPath, image::TextureUsage::STRICT_TEXTURE); + static gpu::TexturePointer statusIconMap; + static std::once_flag once; + std::call_once(once, [] { + auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg"; + statusIconMap = DependencyManager::get()->getImageTexture(iconMapPath, image::TextureUsage::STRICT_TEXTURE); + }); const auto drawStatusInputs = DrawStatus::Input(opaques, jitter).asVarying(); task.addJob("DrawStatus", drawStatusInputs, DrawStatus(statusIconMap)); } @@ -407,8 +430,6 @@ void RenderDeferredTaskDebug::build(JobModel& task, const render::Varying& input const auto debugZoneInputs = DebugZoneLighting::Inputs(deferredFrameTransform, lightFrame, backgroundFrame).asVarying(); task.addJob("DrawZoneStack", debugZoneInputs); } - - } gpu::FramebufferPointer PreparePrimaryFramebuffer::createFramebuffer(const char* name, const glm::uvec2& frameSize) { diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 969094488e8..5fc9580981c 100644 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -144,7 +144,7 @@ class RenderDeferredTask { RenderDeferredTask(); void configure(const Config& config); - void build(JobModel& task, const render::Varying& input, render::Varying& output); + void build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, size_t depth); private: }; diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index e34db755b70..cba6f4920f9 100644 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -34,6 +34,8 @@ #include "RenderCommonTask.h" #include "RenderHUDLayerTask.h" +#include "RenderViewTask.h" + namespace ru { using render_utils::slot::texture::Texture; using render_utils::slot::buffer::Buffer; @@ -66,13 +68,16 @@ void RenderForwardTask::configure(const Config& config) { preparePrimaryBufferConfig->setResolutionScale(config.resolutionScale); } -void RenderForwardTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { +void RenderForwardTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, size_t depth) { task.addJob("SetRenderMethodTask", render::Args::FORWARD); // Prepare the ShapePipelines auto fadeEffect = DependencyManager::get(); - ShapePlumberPointer shapePlumber = std::make_shared(); - initForwardPipelines(*shapePlumber); + static ShapePlumberPointer shapePlumber = std::make_shared(); + static std::once_flag once; + std::call_once(once, [] { + initForwardPipelines(*shapePlumber); + }); // Unpack inputs const auto& inputs = input.get(); @@ -86,6 +91,8 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend const auto& opaques = items[RenderFetchCullSortTask::OPAQUE_SHAPE]; const auto& transparents = items[RenderFetchCullSortTask::TRANSPARENT_SHAPE]; const auto& metas = items[RenderFetchCullSortTask::META]; + const auto& mirrors = items[RenderFetchCullSortTask::MIRROR]; + const auto& simulateItems = items[RenderFetchCullSortTask::SIMULATE]; const auto& inFrontOpaque = items[RenderFetchCullSortTask::LAYER_FRONT_OPAQUE_SHAPE]; const auto& inFrontTransparent = items[RenderFetchCullSortTask::LAYER_FRONT_TRANSPARENT_SHAPE]; const auto& hudOpaque = items[RenderFetchCullSortTask::LAYER_HUD_OPAQUE_SHAPE]; @@ -101,13 +108,13 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend const auto lightFrame = currentStageFrames[0]; const auto backgroundFrame = currentStageFrames[1]; const auto hazeFrame = currentStageFrames[2]; + const auto tonemappingFrame = currentStageFrames[4]; const auto& zones = lightingStageInputs[1]; // First job, alter faded fadeEffect->build(task, opaques); - // GPU jobs: Start preparing the main framebuffer const auto scaledPrimaryFramebuffer = task.addJob("PreparePrimaryBufferForward"); @@ -118,6 +125,11 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend const auto prepareForwardInputs = PrepareForward::Inputs(scaledPrimaryFramebuffer, lightFrame).asVarying(); task.addJob("PrepareForward", prepareForwardInputs); + if (depth == 0) { + const auto simulateInputs = RenderSimulateTask::Inputs(simulateItems, scaledPrimaryFramebuffer).asVarying(); + task.addJob("RenderSimulation", simulateInputs); + } + // draw a stencil mask in hidden regions of the framebuffer. task.addJob("PrepareStencil", scaledPrimaryFramebuffer); @@ -125,6 +137,16 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend const auto opaqueInputs = DrawForward::Inputs(opaques, lightingModel, hazeFrame).asVarying(); task.addJob("DrawOpaques", opaqueInputs, shapePlumber, true); + const auto nullJitter = Varying(glm::vec2(0.0f, 0.0f)); +#ifndef Q_OS_ANDROID + if (depth < RenderMirrorTask::MAX_MIRROR_DEPTH) { + const auto mirrorInputs = RenderMirrorTask::Inputs(mirrors, scaledPrimaryFramebuffer, nullJitter).asVarying(); + for (size_t i = 0; i < RenderMirrorTask::MAX_MIRRORS_PER_LEVEL; i++) { + task.addJob("RenderMirrorTask" + std::to_string(i) + "Depth" + std::to_string(depth), mirrorInputs, i, cullFunctor, depth); + } + } +#endif + // Similar to light stage, background stage has been filled by several potential render items and resolved for the frame in this job const auto backgroundInputs = DrawBackgroundStage::Inputs(lightingModel, backgroundFrame, hazeFrame).asVarying(); task.addJob("DrawBackgroundForward", backgroundInputs); @@ -134,7 +156,6 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend task.addJob("DrawTransparents", transparentInputs, shapePlumber, false); // Layered - const auto nullJitter = Varying(glm::vec2(0.0f, 0.0f)); const auto inFrontOpaquesInputs = DrawLayered3D::Inputs(inFrontOpaque, lightingModel, hazeFrame, nullJitter).asVarying(); const auto inFrontTransparentsInputs = DrawLayered3D::Inputs(inFrontTransparent, lightingModel, hazeFrame, nullJitter).asVarying(); task.addJob("DrawInFrontOpaque", inFrontOpaquesInputs, true); @@ -158,7 +179,7 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend const auto destFramebuffer = static_cast(nullptr); - const auto toneMappingInputs = ToneMapAndResample::Input(resolvedFramebuffer, destFramebuffer).asVarying(); + const auto toneMappingInputs = ToneMapAndResample::Input(resolvedFramebuffer, destFramebuffer, tonemappingFrame).asVarying(); const auto toneMappedBuffer = task.addJob("ToneMapping", toneMappingInputs); // HUD Layer const auto renderHUDLayerInputs = RenderHUDLayerTask::Input(toneMappedBuffer, lightingModel, hudOpaque, hudTransparent, hazeFrame).asVarying(); diff --git a/libraries/render-utils/src/RenderForwardTask.h b/libraries/render-utils/src/RenderForwardTask.h index 6833e424496..de3a6dd2052 100644 --- a/libraries/render-utils/src/RenderForwardTask.h +++ b/libraries/render-utils/src/RenderForwardTask.h @@ -36,7 +36,7 @@ class RenderForwardTask { RenderForwardTask() {} void configure(const Config& config); - void build(JobModel& task, const render::Varying& input, render::Varying& output); + void build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, size_t depth); }; diff --git a/libraries/render-utils/src/RenderHUDLayerTask.cpp b/libraries/render-utils/src/RenderHUDLayerTask.cpp index 743e59eebc5..8fee3d57bcf 100644 --- a/libraries/render-utils/src/RenderHUDLayerTask.cpp +++ b/libraries/render-utils/src/RenderHUDLayerTask.cpp @@ -16,8 +16,8 @@ void CompositeHUD::run(const RenderContextPointer& renderContext, const gpu::Fra assert(renderContext->args); assert(renderContext->args->_context); - // We do not want to render HUD elements in secondary camera - if (nsightActive() || renderContext->args->_renderMode == RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) { + // We do not want to render HUD elements in secondary camera or mirrors + if (nsightActive() || renderContext->args->_renderMode == RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE || renderContext->args->_mirrorDepth > 0) { return; } diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 879b48ce111..e7253f6adc8 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -45,6 +45,7 @@ namespace gr { void initDeferredPipelines(ShapePlumber& plumber, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter); void initForwardPipelines(ShapePlumber& plumber); void initZPassPipelines(ShapePlumber& plumber, gpu::StatePointer state, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter); +void initMirrorPipelines(ShapePlumber& plumber, gpu::StatePointer state, const render::ShapePipeline::BatchSetter& batchSetter, const render::ShapePipeline::ItemSetter& itemSetter, bool forward); void sortAndRenderZPassShapes(const ShapePlumberPointer& shapePlumber, const render::RenderContextPointer& renderContext, const render::ShapeBounds& inShapes, render::ItemBounds &itemBounds); void addPlumberPipeline(ShapePlumber& plumber, @@ -481,6 +482,45 @@ void sortAndRenderZPassShapes(const ShapePlumberPointer& shapePlumber, const ren renderContext->args->_batch = nullptr; } +void initMirrorPipelines(ShapePlumber& shapePlumber, gpu::StatePointer state, const render::ShapePipeline::BatchSetter& extraBatchSetter, const render::ShapePipeline::ItemSetter& itemSetter, bool forward) { + using namespace shader::render_utils::program; + + if (forward) { + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withoutDeformed().withoutFade(), + gpu::Shader::createProgram(model_shadow_mirror_forward), state); + + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withDeformed().withoutDualQuatSkinned().withoutFade(), + gpu::Shader::createProgram(model_shadow_mirror_forward_deformed), state); + + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withDeformed().withDualQuatSkinned().withoutFade(), + gpu::Shader::createProgram(model_shadow_mirror_forward_deformeddq), state); + } else { + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withoutDeformed().withoutFade(), + gpu::Shader::createProgram(model_shadow_mirror), state); + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withoutDeformed().withFade(), + gpu::Shader::createProgram(model_shadow_mirror_fade), state, extraBatchSetter, itemSetter); + + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withDeformed().withoutDualQuatSkinned().withoutFade(), + gpu::Shader::createProgram(model_shadow_mirror_deformed), state); + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withDeformed().withoutDualQuatSkinned().withFade(), + gpu::Shader::createProgram(model_shadow_mirror_fade_deformed), state, extraBatchSetter, itemSetter); + + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withDeformed().withDualQuatSkinned().withoutFade(), + gpu::Shader::createProgram(model_shadow_mirror_deformeddq), state); + shapePlumber.addPipeline( + ShapeKey::Filter::Builder().withDeformed().withDualQuatSkinned().withFade(), + gpu::Shader::createProgram(model_shadow_mirror_fade_deformeddq), state, extraBatchSetter, itemSetter); + } +} + bool RenderPipelines::bindMaterial(graphics::MaterialPointer& material, gpu::Batch& batch, render::Args::RenderMode renderMode, bool enableTextures) { graphics::MultiMaterial multiMaterial; multiMaterial.push(graphics::MaterialLayer(material, 0)); diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 817d5b7d8e6..d6c50bc6fb2 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -47,11 +47,13 @@ void RenderShadowTask::configure(const Config& configuration) { void RenderShadowTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cameraCullFunctor, uint8_t tagBits, uint8_t tagMask) { // Prepare the ShapePipeline - ShapePlumberPointer shapePlumber = std::make_shared(); - { + static ShapePlumberPointer shapePlumber = std::make_shared(); + static std::once_flag once; + std::call_once(once, [] { auto fadeEffect = DependencyManager::get(); initZPassPipelines(*shapePlumber, std::make_shared(), fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); - } + }); + const auto setupOutput = task.addJob("ShadowSetup", input); const auto queryResolution = setupOutput.getN(1); const auto shadowFrame = setupOutput.getN(3); diff --git a/libraries/render-utils/src/RenderViewTask.cpp b/libraries/render-utils/src/RenderViewTask.cpp index 93a3ff2d670..b9320b6ad39 100644 --- a/libraries/render-utils/src/RenderViewTask.cpp +++ b/libraries/render-utils/src/RenderViewTask.cpp @@ -15,7 +15,7 @@ #include "RenderDeferredTask.h" #include "RenderForwardTask.h" -void RenderShadowsAndDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) { +void RenderShadowsAndDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask, size_t depth) { task.addJob("SetRenderMethodTask", render::Args::DEFERRED); const auto items = input.getN(0); @@ -28,16 +28,16 @@ void RenderShadowsAndDeferredTask::build(JobModel& task, const render::Varying& const auto shadowTaskOut = task.addJob("RenderShadowTask", shadowTaskIn, cullFunctor, tagBits, tagMask); const auto renderDeferredInput = RenderDeferredTask::Input(items, lightingModel, lightingStageFramesAndZones, shadowTaskOut).asVarying(); - task.addJob("RenderDeferredTask", renderDeferredInput); + task.addJob("RenderDeferredTask", renderDeferredInput, cullFunctor, depth); } -void DeferredForwardSwitchJob::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) { - task.addBranch("RenderShadowsAndDeferredTask", 0, input, cullFunctor, tagBits, tagMask); +void DeferredForwardSwitchJob::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask, size_t depth) { + task.addBranch("RenderShadowsAndDeferredTask", 0, input, cullFunctor, tagBits, tagMask, depth); - task.addBranch("RenderForwardTask", 1, input); + task.addBranch("RenderForwardTask", 1, input, cullFunctor, depth); } -void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask) { +void RenderViewTask::build(JobModel& task, const render::Varying& input, render::Varying& output, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask, size_t depth) { const auto items = task.addJob("FetchCullSort", cullFunctor, tagBits, tagMask); // Issue the lighting model, aka the big global settings for the view @@ -48,7 +48,7 @@ void RenderViewTask::build(JobModel& task, const render::Varying& input, render: #ifndef Q_OS_ANDROID const auto deferredForwardIn = DeferredForwardSwitchJob::Input(items, lightingModel, lightingStageFramesAndZones).asVarying(); - task.addJob("DeferredForwardSwitch", deferredForwardIn, cullFunctor, tagBits, tagMask); + task.addJob("DeferredForwardSwitch", deferredForwardIn, cullFunctor, tagBits, tagMask, depth); #else const auto renderInput = RenderForwardTask::Input(items, lightingModel, lightingStageFramesAndZones).asVarying(); task.addJob("RenderForwardTask", renderInput); diff --git a/libraries/render-utils/src/RenderViewTask.h b/libraries/render-utils/src/RenderViewTask.h index cdb56a21893..139d00125ef 100644 --- a/libraries/render-utils/src/RenderViewTask.h +++ b/libraries/render-utils/src/RenderViewTask.h @@ -24,7 +24,7 @@ class RenderShadowsAndDeferredTask { RenderShadowsAndDeferredTask() {} - void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask, size_t depth); }; @@ -36,7 +36,7 @@ class DeferredForwardSwitchJob { DeferredForwardSwitchJob() {} void configure(const render::SwitchConfig& config) {} - void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits, uint8_t tagMask, size_t depth); }; @@ -47,7 +47,7 @@ class RenderViewTask { RenderViewTask() {} - void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, uint8_t tagBits = 0x00, uint8_t tagMask = 0x00, size_t depth = 0); }; diff --git a/libraries/render-utils/src/SoftAttachmentModel.cpp b/libraries/render-utils/src/SoftAttachmentModel.cpp deleted file mode 100644 index 24d60817438..00000000000 --- a/libraries/render-utils/src/SoftAttachmentModel.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// -// Created by Anthony J. Thibault on 12/17/15. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "SoftAttachmentModel.h" - -SoftAttachmentModel::SoftAttachmentModel(QObject* parent, const Rig& rigOverride) : - CauterizedModel(parent), - _rigOverride(rigOverride) { -} - -SoftAttachmentModel::~SoftAttachmentModel() { -} - -// virtual -void SoftAttachmentModel::updateRig(float deltaTime, glm::mat4 parentTransform) { - _needsUpdateClusterMatrices = true; -} - -int SoftAttachmentModel::getJointIndexOverride(int i) const { - QString name = _rig.nameOfJoint(i); - if (name.isEmpty()) { - return -1; - } - return _rigOverride.indexOfJoint(name); -} - -// virtual -// use the _rigOverride matrices instead of the Model::_rig -void SoftAttachmentModel::updateClusterMatrices() { - if (!_needsUpdateClusterMatrices) { - return; - } - if (!isLoaded()) { - return; - } - - _needsUpdateClusterMatrices = false; - - const HFMModel& hfmModel = getHFMModel(); - - for (int i = 0; i < (int) _meshStates.size(); i++) { - MeshState& state = _meshStates[i]; - const HFMMesh& mesh = hfmModel.meshes.at(i); - int meshIndex = i; - for (int j = 0; j < mesh.clusters.size(); j++) { - const HFMCluster& cluster = mesh.clusters.at(j); - - int clusterIndex = j; - // TODO: cache these look-ups as an optimization - int jointIndexOverride = getJointIndexOverride(cluster.jointIndex); - glm::mat4 jointMatrix; - if (jointIndexOverride >= 0 && jointIndexOverride < _rigOverride.getJointStateCount()) { - jointMatrix = _rigOverride.getJointTransform(jointIndexOverride); - } else { - jointMatrix = _rig.getJointTransform(cluster.jointIndex); - } - if (_useDualQuaternionSkinning) { - glm::mat4 m; - glm_mat4u_mul(jointMatrix, _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex).inverseBindMatrix, m); - state.clusterDualQuaternions[j] = Model::TransformDualQuaternion(m); - } else { - glm_mat4u_mul(jointMatrix, _rig.getAnimSkeleton()->getClusterBindMatricesOriginalValues(meshIndex, clusterIndex).inverseBindMatrix, state.clusterMatrices[j]); - } - } - } - - updateBlendshapes(); -} diff --git a/libraries/render-utils/src/SoftAttachmentModel.h b/libraries/render-utils/src/SoftAttachmentModel.h deleted file mode 100644 index 4335c1634e2..00000000000 --- a/libraries/render-utils/src/SoftAttachmentModel.h +++ /dev/null @@ -1,38 +0,0 @@ -// -// Created by Anthony J. Thibault on 12/17/15. -// Copyright 2015 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_SoftAttachmentModel_h -#define hifi_SoftAttachmentModel_h - -#include "CauterizedModel.h" - -// A model that allows the creator to specify a secondary rig instance. -// When the cluster matrices are created for rendering, the -// cluster matrices will use the secondary rig for the joint poses -// instead of the primary rig. -// -// This is used by Avatar instances to wear clothing that follows the same -// animated pose as the SkeletonModel. - -class SoftAttachmentModel : public CauterizedModel { - Q_OBJECT - -public: - SoftAttachmentModel(QObject* parent, const Rig& rigOverride); - ~SoftAttachmentModel(); - - void updateRig(float deltaTime, glm::mat4 parentTransform) override; - void updateClusterMatrices() override; - -protected: - int getJointIndexOverride(int i) const; - - const Rig& _rigOverride; -}; - -#endif // hifi_SoftAttachmentModel_h diff --git a/libraries/render-utils/src/TextRenderer3D.cpp b/libraries/render-utils/src/TextRenderer3D.cpp index 76d8374fb77..a4680805e6f 100644 --- a/libraries/render-utils/src/TextRenderer3D.cpp +++ b/libraries/render-utils/src/TextRenderer3D.cpp @@ -33,28 +33,25 @@ glm::vec2 TextRenderer3D::computeExtent(const QString& str) const { return glm::vec2(0.0f, 0.0f); } -float TextRenderer3D::getFontSize() const { +float TextRenderer3D::getFontHeight() const { if (_font) { - return _font->getFontSize(); + return _font->getFontHeight(); } return 0.0f; } -void TextRenderer3D::draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds, - const QString& str, const glm::vec4& color, bool unlit, bool forward) { +void TextRenderer3D::draw(gpu::Batch& batch, const Font::DrawProps& props) { if (_font) { - _font->drawString(batch, _drawInfo, str, color, glm::vec3(0.0f), 0, TextEffect::NO_EFFECT, TextAlignment::LEFT, { x, y }, bounds, 1.0f, unlit, forward); + _font->drawString(batch, _drawInfo, props); } } -void TextRenderer3D::draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds, float scale, - const QString& str, const QString& font, const glm::vec4& color, const glm::vec3& effectColor, - float effectThickness, TextEffect effect, TextAlignment alignment, bool unlit, bool forward) { +void TextRenderer3D::draw(gpu::Batch& batch, const QString& font, const Font::DrawProps& props) { if (font != _family) { _family = font; _font = Font::load(_family); } if (_font) { - _font->drawString(batch, _drawInfo, str, color, effectColor, effectThickness, effect, alignment, { x, y }, bounds, scale, unlit, forward); + _font->drawString(batch, _drawInfo, props); } } \ No newline at end of file diff --git a/libraries/render-utils/src/TextRenderer3D.h b/libraries/render-utils/src/TextRenderer3D.h index edccf1429c9..1a0a1343f85 100644 --- a/libraries/render-utils/src/TextRenderer3D.h +++ b/libraries/render-utils/src/TextRenderer3D.h @@ -25,13 +25,10 @@ class TextRenderer3D { static TextRenderer3D* getInstance(const char* family); glm::vec2 computeExtent(const QString& str) const; - float getFontSize() const; // Pixel size - - void draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds, - const QString& str, const glm::vec4& color, bool unlit, bool forward); - void draw(gpu::Batch& batch, float x, float y, const glm::vec2& bounds, float scale, - const QString& str, const QString& font, const glm::vec4& color, const glm::vec3& effectColor, - float effectThickness, TextEffect effect, TextAlignment alignment, bool unlit, bool forward); + float getFontHeight() const; + + void draw(gpu::Batch& batch, const Font::DrawProps& props); + void draw(gpu::Batch& batch, const QString& font, const Font::DrawProps& props); private: TextRenderer3D(const char* family); diff --git a/libraries/render-utils/src/ToneMapAndResampleTask.cpp b/libraries/render-utils/src/ToneMapAndResampleTask.cpp index 10312f7f2e5..d906d82aa72 100644 --- a/libraries/render-utils/src/ToneMapAndResampleTask.cpp +++ b/libraries/render-utils/src/ToneMapAndResampleTask.cpp @@ -43,13 +43,13 @@ void ToneMapAndResample::init() { void ToneMapAndResample::setExposure(float exposure) { auto& params = _parametersBuffer.get(); - if (params._exposure != exposure) { - _parametersBuffer.edit()._exposure = exposure; + if (_exposure != exposure) { + _exposure = exposure; _parametersBuffer.edit()._twoPowExposure = pow(2.0, exposure); } } -void ToneMapAndResample::setToneCurve(ToneCurve curve) { +void ToneMapAndResample::setCurve(TonemappingCurve curve) { auto& params = _parametersBuffer.get(); if (params._toneCurve != (int)curve) { _parametersBuffer.edit()._toneCurve = (int)curve; @@ -57,8 +57,9 @@ void ToneMapAndResample::setToneCurve(ToneCurve curve) { } void ToneMapAndResample::configure(const Config& config) { - setExposure(config.exposure); - setToneCurve((ToneCurve)config.curve); + _debug = config.debug; + _debugExposure = config.exposure; + _debugCurve = (TonemappingCurve)config.curve; } void ToneMapAndResample::run(const RenderContextPointer& renderContext, const Input& input, Output& output) { @@ -69,6 +70,21 @@ void ToneMapAndResample::run(const RenderContextPointer& renderContext, const In auto lightingBuffer = input.get0()->getRenderBuffer(0); auto destinationFramebuffer = input.get1(); + const auto tonemappingFrame = input.get2(); + + const auto& tonemappingStage = renderContext->_scene->getStage(); + graphics::TonemappingPointer tonemapping; + if (tonemappingStage && tonemappingFrame->_tonemappings.size()) { + tonemapping = tonemappingStage->getTonemapping(tonemappingFrame->_tonemappings.front()); + } + + if (_debug) { + setCurve(_debugCurve); + setExposure(_debugExposure); + } else if (tonemapping) { + setCurve(tonemapping->getCurve()); + setExposure(tonemapping->getExposure()); + } if (!destinationFramebuffer) { destinationFramebuffer = args->_blitFramebuffer; @@ -95,7 +111,8 @@ void ToneMapAndResample::run(const RenderContextPointer& renderContext, const In batch.setViewportTransform(destViewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); - batch.setPipeline(args->_renderMode == RenderArgs::MIRROR_RENDER_MODE ? _mirrorPipeline : _pipeline); + bool shouldMirror = args->_numMirrorFlips >= (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); + batch.setPipeline(shouldMirror ? _mirrorPipeline : _pipeline); batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(srcBufferSize, args->_viewport)); batch.setUniformBuffer(render_utils::slot::buffer::ToneMappingParams, _parametersBuffer); diff --git a/libraries/render-utils/src/ToneMapAndResampleTask.h b/libraries/render-utils/src/ToneMapAndResampleTask.h index 1c7ef2cf48e..50a35b2fe4f 100644 --- a/libraries/render-utils/src/ToneMapAndResampleTask.h +++ b/libraries/render-utils/src/ToneMapAndResampleTask.h @@ -20,28 +20,24 @@ #include #include -enum class ToneCurve { - // Different tone curve available - None, - Gamma22, - Reinhard, - Filmic, -}; +#include "TonemappingStage.h" class ToneMappingConfig : public render::Job::Config { Q_OBJECT - Q_PROPERTY(float exposure MEMBER exposure WRITE setExposure); - Q_PROPERTY(int curve MEMBER curve WRITE setCurve); + Q_PROPERTY(bool debug MEMBER debug WRITE setDebug NOTIFY dirty); + Q_PROPERTY(int curve MEMBER curve WRITE setCurve NOTIFY dirty); + Q_PROPERTY(float exposure MEMBER exposure WRITE setExposure NOTIFY dirty); public: ToneMappingConfig() : render::Job::Config(true) {} + void setDebug(bool newDebug) { debug = newDebug; emit dirty(); } + void setCurve(int newCurve) { curve = std::max(0, std::min((int)TonemappingCurve::FILMIC, newCurve)); emit dirty(); } void setExposure(float newExposure) { exposure = newExposure; emit dirty(); } - void setCurve(int newCurve) { curve = std::max((int)ToneCurve::None, std::min((int)ToneCurve::Filmic, newCurve)); emit dirty(); } - - float exposure{ 0.0f }; - int curve{ (int)ToneCurve::Gamma22 }; + bool debug { false }; + int curve { (int)TonemappingCurve::SRGB }; + float exposure { 0.0f }; signals: void dirty(); @@ -52,16 +48,11 @@ class ToneMapAndResample { ToneMapAndResample(); virtual ~ToneMapAndResample() {} - void render(RenderArgs* args, const gpu::TexturePointer& lightingBuffer, gpu::FramebufferPointer& destinationBuffer); - + void setCurve(TonemappingCurve curve); void setExposure(float exposure); - float getExposure() const { return _parametersBuffer.get()._exposure; } - - void setToneCurve(ToneCurve curve); - ToneCurve getToneCurve() const { return (ToneCurve)_parametersBuffer.get()._toneCurve; } - // Inputs: lightingFramebuffer, destinationFramebuffer - using Input = render::VaryingSet2; + // Inputs: lightingFramebuffer, destinationFramebuffer, tonemappingFrame + using Input = render::VaryingSet3; using Output = gpu::FramebufferPointer; using Config = ToneMappingConfig; using JobModel = render::Job::ModelIO; @@ -75,21 +66,19 @@ class ToneMapAndResample { gpu::FramebufferPointer _destinationFrameBuffer; - float _factor{ 2.0f }; - - gpu::FramebufferPointer getResampledFrameBuffer(const gpu::FramebufferPointer& sourceFramebuffer); - private: gpu::PipelinePointer _blitLightBuffer; + float _exposure { 0.0f }; + + bool _debug { false }; + TonemappingCurve _debugCurve { TonemappingCurve::SRGB }; + float _debugExposure { 0.0f }; // Class describing the uniform buffer with all the parameters common to the tone mapping shaders class Parameters { public: - float _exposure = 0.0f; float _twoPowExposure = 1.0f; - glm::vec2 spareA; - int _toneCurve = (int)ToneCurve::Gamma22; - glm::vec3 spareB; + int _toneCurve = (int)TonemappingCurve::SRGB; Parameters() {} }; diff --git a/libraries/render-utils/src/TonemappingStage.cpp b/libraries/render-utils/src/TonemappingStage.cpp new file mode 100644 index 00000000000..9b6029ca1b9 --- /dev/null +++ b/libraries/render-utils/src/TonemappingStage.cpp @@ -0,0 +1,56 @@ +// +// TonemappingStage.cpp +// +// Created by HifiExperiments on 6/24/24 +// Copyright 2024 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "TonemappingStage.h" + +#include + +std::string TonemappingStage::_stageName { "TONEMAPPING_STAGE" }; +const TonemappingStage::Index TonemappingStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX }; + +TonemappingStage::Index TonemappingStage::findTonemapping(const TonemappingPointer& tonemapping) const { + auto found = _tonemappingMap.find(tonemapping); + if (found != _tonemappingMap.end()) { + return INVALID_INDEX; + } else { + return (*found).second; + } +} + +TonemappingStage::Index TonemappingStage::addTonemapping(const TonemappingPointer& tonemapping) { + auto found = _tonemappingMap.find(tonemapping); + if (found == _tonemappingMap.end()) { + auto tonemappingId = _tonemappings.newElement(tonemapping); + // Avoid failing to allocate a tonemapping, just pass + if (tonemappingId != INVALID_INDEX) { + // Insert the tonemapping and its index in the reverse map + _tonemappingMap.insert(TonemappingMap::value_type(tonemapping, tonemappingId)); + } + return tonemappingId; + } else { + return (*found).second; + } +} + +TonemappingStage::TonemappingPointer TonemappingStage::removeTonemapping(Index index) { + TonemappingPointer removed = _tonemappings.freeElement(index); + if (removed) { + _tonemappingMap.erase(removed); + } + return removed; +} + +TonemappingStageSetup::TonemappingStageSetup() {} + +void TonemappingStageSetup::run(const render::RenderContextPointer& renderContext) { + auto stage = renderContext->_scene->getStage(TonemappingStage::getName()); + if (!stage) { + renderContext->_scene->resetStage(TonemappingStage::getName(), std::make_shared()); + } +} diff --git a/libraries/render-utils/src/TonemappingStage.h b/libraries/render-utils/src/TonemappingStage.h new file mode 100644 index 00000000000..15161094a2a --- /dev/null +++ b/libraries/render-utils/src/TonemappingStage.h @@ -0,0 +1,84 @@ +// +// TonemappingStage.h +// +// Created by HifiExperiments on 6/24/24 +// Copyright 2024 Overte e.V. +// +// 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_TonemappingStage_h +#define hifi_render_utils_TonemappingStage_h + +#include +#include +#include +#include +#include + +#include +#include +#include + +// Tonemapping stage to set up tonemapping-related rendering tasks +class TonemappingStage : 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 TonemappingPointer = graphics::TonemappingPointer; + using Tonemappings = render::indexed_container::IndexedPointerVector; + using TonemappingMap = std::unordered_map; + + using TonemappingIndices = std::vector; + + Index findTonemapping(const TonemappingPointer& tonemapping) const; + Index addTonemapping(const TonemappingPointer& tonemapping); + + TonemappingPointer removeTonemapping(Index index); + + bool checkTonemappingId(Index index) const { return _tonemappings.checkIndex(index); } + + Index getNumTonemappings() const { return _tonemappings.getNumElements(); } + Index getNumFreeTonemappings() const { return _tonemappings.getNumFreeIndices(); } + Index getNumAllocatedTonemappings() const { return _tonemappings.getNumAllocatedIndices(); } + + TonemappingPointer getTonemapping(Index tonemappingId) const { + return _tonemappings.get(tonemappingId); + } + + Tonemappings _tonemappings; + TonemappingMap _tonemappingMap; + + class Frame { + public: + Frame() {} + + void clear() { _tonemappings.clear(); } + + void pushTonemapping(TonemappingStage::Index index) { _tonemappings.emplace_back(index); } + + TonemappingStage::TonemappingIndices _tonemappings; + }; + using FramePointer = std::shared_ptr; + + Frame _currentFrame; +}; +using TonemappingStagePointer = std::shared_ptr; + +class TonemappingStageSetup { +public: + using JobModel = render::Job::Model; + + TonemappingStageSetup(); + void run(const render::RenderContextPointer& renderContext); + +protected: +}; + +#endif diff --git a/libraries/render-utils/src/UpdateSceneTask.cpp b/libraries/render-utils/src/UpdateSceneTask.cpp index be61953073a..3fca91ccb96 100644 --- a/libraries/render-utils/src/UpdateSceneTask.cpp +++ b/libraries/render-utils/src/UpdateSceneTask.cpp @@ -15,6 +15,8 @@ #include "BackgroundStage.h" #include "HazeStage.h" #include "BloomStage.h" +#include "TonemappingStage.h" +#include "AmbientOcclusionStage.h" #include #include #include "DeferredLightingEffect.h" @@ -24,6 +26,8 @@ void UpdateSceneTask::build(JobModel& task, const render::Varying& input, render task.addJob("BackgroundStageSetup"); task.addJob("HazeStageSetup"); task.addJob("BloomStageSetup"); + task.addJob("TonemappingStageSetup"); + task.addJob("AmbientOcclusionStageSetup"); task.addJob("TransitionStageSetup"); task.addJob("HighlightStageSetup"); diff --git a/libraries/render-utils/src/ZoneRenderer.cpp b/libraries/render-utils/src/ZoneRenderer.cpp index 5332e138162..d9c0de99347 100644 --- a/libraries/render-utils/src/ZoneRenderer.cpp +++ b/libraries/render-utils/src/ZoneRenderer.cpp @@ -26,6 +26,7 @@ #include "DeferredLightingEffect.h" #include "BloomStage.h" +#include "TonemappingStage.h" namespace ru { using render_utils::slot::texture::Texture; @@ -71,6 +72,14 @@ void SetupZones::run(const RenderContextPointer& context, const Input& input) { assert(bloomStage); bloomStage->_currentFrame.clear(); + auto tonemappingStage = context->_scene->getStage(); + assert(tonemappingStage); + tonemappingStage->_currentFrame.clear(); + + auto ambientOcclusionStage = context->_scene->getStage(); + assert(ambientOcclusionStage); + ambientOcclusionStage->_currentFrame.clear(); + // call render over the zones to grab their components in the correct order first... render::renderItems(context, input); @@ -80,6 +89,8 @@ void SetupZones::run(const RenderContextPointer& context, const Input& input) { backgroundStage->_currentFrame.pushBackground(0); hazeStage->_currentFrame.pushHaze(0); bloomStage->_currentFrame.pushBloom(INVALID_INDEX); + tonemappingStage->_currentFrame.pushTonemapping(0); + ambientOcclusionStage->_currentFrame.pushAmbientOcclusion(INVALID_INDEX); } const gpu::PipelinePointer& DebugZoneLighting::getKeyLightPipeline() { @@ -105,6 +116,7 @@ const gpu::PipelinePointer& DebugZoneLighting::getAmbientPipeline() { } return _ambientPipeline; } + const gpu::PipelinePointer& DebugZoneLighting::getBackgroundPipeline() { if (!_backgroundPipeline) { gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::zone_drawSkybox); diff --git a/libraries/render-utils/src/model.slf b/libraries/render-utils/src/model.slf index 4b40aa171c1..48e483edf73 100644 --- a/libraries/render-utils/src/model.slf +++ b/libraries/render-utils/src/model.slf @@ -19,12 +19,18 @@ <@if HIFI_USE_MTOON@> <@if HIFI_USE_SHADOW@> <$declareMToonMaterialTextures(ALBEDO)$> + <@if HIFI_USE_MIRROR@> + LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_MIRROR) uniform sampler2D mirrorMap; + <@endif@> <@else@> <$declareMToonMaterialTextures(ALBEDO, HIFI_USE_NORMALMAP, SHADE, EMISSIVE, SHADING_SHIFT, MATCAP, RIM, UV_ANIMATION_MASK)$> <@endif@> <@else@> <@if HIFI_USE_SHADOW or HIFI_USE_UNLIT@> <$declareMaterialTextures(ALBEDO)$> + <@if HIFI_USE_MIRROR@> + LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_MIRROR) uniform sampler2D mirrorMap; + <@endif@> <@else@> <@if not HIFI_USE_LIGHTMAP@> <@if HIFI_USE_TRANSLUCENT@> @@ -75,7 +81,15 @@ <@include DeferredBufferWrite.slh@> <@endif@> <@else@> - layout(location=0) out vec4 _fragColor0; + <@if HIFI_USE_MIRROR@> + <@if HIFI_USE_FORWARD@> + layout(location=0) out vec4 _fragColor0; + <@else@> + <@include DeferredBufferWrite.slh@> + <@endif@> + <@else@> + layout(location=0) out vec4 _fragColor0; + <@endif@> <@endif@> <@if HIFI_USE_UNLIT@> @@ -150,7 +164,14 @@ void main(void) { <@endif@> <@endif@> - <@if HIFI_USE_SHADOW@> + <@if HIFI_USE_MIRROR@> + vec3 mirrorColor = texelFetch(mirrorMap, ivec2(gl_FragCoord.xy), 0).rgb; + <@if HIFI_USE_FORWARD@> + _fragColor0 = vec4(mirrorColor, 1.0); + <@else@> + packDeferredFragmentUnlit(vec3(1.0, 0.0, 0.0), 1.0, mirrorColor); + <@endif@> + <@elif HIFI_USE_SHADOW@> _fragColor0 = vec4(1.0); <@elif HIFI_USE_TRANSLUCENT or HIFI_USE_FORWARD@> _fragColor0 = vec4(albedo * isUnlitEnabled(), opacity); diff --git a/libraries/render-utils/src/render-utils/haze.slp b/libraries/render-utils/src/render-utils/haze.slp index 805b855c8d0..7cfd358e3de 100644 --- a/libraries/render-utils/src/render-utils/haze.slp +++ b/libraries/render-utils/src/render-utils/haze.slp @@ -1,2 +1,3 @@ VERTEX gpu::vertex::DrawViewportQuadTransformTexcoord FRAGMENT Haze +DEFINES background:f diff --git a/libraries/render-utils/src/render-utils/model.slp b/libraries/render-utils/src/render-utils/model.slp index e69518f8fda..f2b1a0d588e 100644 --- a/libraries/render-utils/src/render-utils/model.slp +++ b/libraries/render-utils/src/render-utils/model.slp @@ -1 +1 @@ -DEFINES (normalmap translucent:f unlit:f/lightmap:f)/shadow mtoon fade:f/forward:f deformed:v/deformeddq:v \ No newline at end of file +DEFINES (normalmap translucent:f unlit:f/lightmap:f)/(shadow mirror:f) mtoon fade:f/forward:f deformed:v/deformeddq:v diff --git a/libraries/render-utils/src/render-utils/sdf_text3D.slp b/libraries/render-utils/src/render-utils/sdf_text3D.slp index 118135d099b..f3f9af59aa2 100644 --- a/libraries/render-utils/src/render-utils/sdf_text3D.slp +++ b/libraries/render-utils/src/render-utils/sdf_text3D.slp @@ -1 +1 @@ -DEFINES (translucent unlit:f)/forward \ No newline at end of file +DEFINES (translucent unlit:f)/forward mirror:f \ No newline at end of file diff --git a/libraries/render-utils/src/sdf_text3D.slf b/libraries/render-utils/src/sdf_text3D.slf index 27debc521e7..f606c1be812 100644 --- a/libraries/render-utils/src/sdf_text3D.slf +++ b/libraries/render-utils/src/sdf_text3D.slf @@ -42,6 +42,12 @@ layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01; #define _texCoord1 _texCoord01.zw layout(location=RENDER_UTILS_ATTR_FADE1) flat in vec4 _glyphBounds; // we're reusing the fade texcoord locations here +<@if HIFI_USE_MIRROR@> + <@include graphics/ShaderConstants.h@> + + LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_MIRROR) uniform sampler2D mirrorMap; +<@endif@> + void main() { vec4 color = evalSDFSuperSampled(_texCoord0, _positionMS, _glyphBounds); @@ -52,6 +58,11 @@ void main() { } <@endif@> +<@if HIFI_USE_MIRROR@> + color.rgb = texelFetch(mirrorMap, ivec2(gl_FragCoord.xy), 0).rgb; + color.a = 1.0; +<@endif@> + <@if HIFI_USE_UNLIT@> <@if HIFI_USE_TRANSLUCENT or HIFI_USE_FORWARD@> _fragColor0 = vec4(color.rgb * isUnlitEnabled(), color.a); diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp index 1a92ccf8ec5..81badb84406 100644 --- a/libraries/render-utils/src/text/Font.cpp +++ b/libraries/render-utils/src/text/Font.cpp @@ -33,7 +33,7 @@ static std::mutex fontMutex; -std::map, gpu::PipelinePointer> Font::_pipelines; +std::map, gpu::PipelinePointer> Font::_pipelines; gpu::Stream::FormatPointer Font::_format; struct TextureVertex { @@ -129,7 +129,7 @@ void Font::read(QIODevice& in) { } _distanceRange = glm::vec2(arteryFont.variants[0].metrics.distanceRange); - _fontSize = arteryFont.variants[0].metrics.ascender + fabs(arteryFont.variants[0].metrics.descender); + _fontHeight = arteryFont.variants[0].metrics.ascender + fabs(arteryFont.variants[0].metrics.descender); _leading = arteryFont.variants[0].metrics.lineHeight; _spaceWidth = 0.5f * arteryFont.variants[0].metrics.emSize; // We use half the emSize as a first guess for _spaceWidth @@ -303,11 +303,11 @@ QStringList Font::tokenizeForWrapping(const QString& str) const { return tokens; } -glm::vec2 Font::computeTokenExtent(const QString& token) const { - glm::vec2 advance(0, _fontSize); +float Font::computeTokenWidth(const QString& token) const { + float advance = 0.0f; foreach(QChar c, token) { Q_ASSERT(c != '\n'); - advance.x += (c == ' ') ? _spaceWidth : getGlyph(c).d; + advance += (c == ' ') ? _spaceWidth : getGlyph(c).d; } return advance; } @@ -318,10 +318,10 @@ glm::vec2 Font::computeExtent(const QString& str) const { QStringList lines = splitLines(str); if (!lines.empty()) { for(const auto& line : lines) { - glm::vec2 tokenExtent = computeTokenExtent(line); - extent.x = std::max(tokenExtent.x, extent.x); + float tokenWidth = computeTokenWidth(line); + extent.x = std::max(tokenWidth, extent.x); } - extent.y = lines.count() * _fontSize; + extent.y = lines.count() * _fontHeight; } return extent; } @@ -330,6 +330,7 @@ void Font::setupGPU() { if (_pipelines.empty()) { using namespace shader::render_utils::program; + // transparent, unlit, forward static const std::vector> keys = { std::make_tuple(false, false, false, sdf_text3D), std::make_tuple(true, false, false, sdf_text3D_translucent), std::make_tuple(false, true, false, sdf_text3D_unlit), std::make_tuple(true, true, false, sdf_text3D_translucent_unlit), @@ -337,18 +338,23 @@ void Font::setupGPU() { std::make_tuple(false, true, true, sdf_text3D_translucent_unlit/*sdf_text3D_unlit_forward*/), std::make_tuple(true, true, true, sdf_text3D_translucent_unlit/*sdf_text3D_translucent_unlit_forward*/) }; for (auto& key : keys) { + bool transparent = std::get<0>(key); + bool unlit = std::get<1>(key); + bool forward = std::get<2>(key); + auto state = std::make_shared(); state->setCullMode(gpu::State::CULL_BACK); - state->setDepthTest(true, !std::get<0>(key), gpu::LESS_EQUAL); - state->setBlendFunction(std::get<0>(key), + state->setDepthTest(true, !transparent, gpu::LESS_EQUAL); + state->setBlendFunction(transparent, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - if (std::get<0>(key)) { + if (transparent) { PrepareStencil::testMask(*state); } else { PrepareStencil::testMaskDrawShape(*state); } - _pipelines[std::make_tuple(std::get<0>(key), std::get<1>(key), std::get<2>(key))] = gpu::Pipeline::create(gpu::Shader::createProgram(std::get<3>(key)), state); + _pipelines[std::make_tuple(transparent, unlit, forward, false)] = gpu::Pipeline::create(gpu::Shader::createProgram(std::get<3>(key)), state); + _pipelines[std::make_tuple(transparent, unlit, forward, true)] = gpu::Pipeline::create(gpu::Shader::createProgram(forward ? sdf_text3D_forward_mirror : sdf_text3D_mirror), state); } // Sanity checks @@ -367,17 +373,22 @@ void Font::setupGPU() { } inline QuadBuilder adjustedQuadBuilderForAlignmentMode(const Glyph& glyph, glm::vec2 advance, float scale, float enlargeForShadows, - TextAlignment alignment, float rightSpacing) { + TextAlignment alignment, float rightSpacing, TextVerticalAlignment verticalAlignment, float bottomSpacing) { if (alignment == TextAlignment::RIGHT) { advance.x += rightSpacing; } else if (alignment == TextAlignment::CENTER) { advance.x += 0.5f * rightSpacing; } + if (verticalAlignment == TextVerticalAlignment::BOTTOM) { + advance.y += bottomSpacing; + } else if (verticalAlignment == TextVerticalAlignment::CENTER) { + advance.y += 0.5f * bottomSpacing; + } return QuadBuilder(glyph, advance, scale, enlargeForShadows); } void Font::buildVertices(Font::DrawInfo& drawInfo, const QString& str, const glm::vec2& origin, const glm::vec2& bounds, float scale, bool enlargeForShadows, - TextAlignment alignment) { + TextAlignment alignment, TextVerticalAlignment verticalAlignment) { drawInfo.verticesBuffer = std::make_shared(); drawInfo.indicesBuffer = std::make_shared(); drawInfo.indexCount = 0; @@ -388,6 +399,7 @@ void Font::buildVertices(Font::DrawInfo& drawInfo, const QString& str, const glm drawInfo.origin = origin; float rightEdge = origin.x + bounds.x; + float bottomEdge = origin.y - bounds.y; // Top left of text bool firstTokenOfLine = true; @@ -397,7 +409,7 @@ void Font::buildVertices(Font::DrawInfo& drawInfo, const QString& str, const glm for (int i = 0; i < tokens.length(); i++) { const QString& token = tokens[i]; - if ((bounds.y != -1) && (advance.y < origin.y - bounds.y)) { + if ((bounds.y != -1) && (advance.y < bottomEdge)) { // We are out of the y bound, stop drawing break; } @@ -453,25 +465,47 @@ void Font::buildVertices(Font::DrawInfo& drawInfo, const QString& str, const glm std::vector quadBuilders; quadBuilders.reserve(glyphsAndCorners.size()); { + float bottomSpacing = -FLT_MAX; + bool foundBottomSpacing = false; + if (verticalAlignment != TextVerticalAlignment::TOP) { + int i = (int)glyphsAndCorners.size() - 1; + while (!foundBottomSpacing && i >= 0) { + auto* nextGlyphAndCorner = &glyphsAndCorners[i]; + bottomSpacing = std::max(bottomSpacing, bottomEdge - (nextGlyphAndCorner->second.y + (nextGlyphAndCorner->first.offset.y - nextGlyphAndCorner->first.size.y))); + i--; + while (i >= 0) { + auto& prevGlyphAndCorner = glyphsAndCorners[i]; + // We're to the right of the last character we checked, which means we're on a previous line, so we can stop + if (prevGlyphAndCorner.second.x >= nextGlyphAndCorner->second.x) { + foundBottomSpacing = true; + break; + } + nextGlyphAndCorner = &prevGlyphAndCorner; + bottomSpacing = std::max(bottomSpacing, bottomEdge - (nextGlyphAndCorner->second.y + (nextGlyphAndCorner->first.offset.y - nextGlyphAndCorner->first.size.y))); + i--; + } + } + } + int i = (int)glyphsAndCorners.size() - 1; while (i >= 0) { - auto nextGlyphAndCorner = glyphsAndCorners[i]; - float rightSpacing = rightEdge - (nextGlyphAndCorner.second.x + nextGlyphAndCorner.first.d); - quadBuilders.push_back(adjustedQuadBuilderForAlignmentMode(nextGlyphAndCorner.first, nextGlyphAndCorner.second, scale, enlargeForShadows, - alignment, rightSpacing)); + auto* nextGlyphAndCorner = &glyphsAndCorners[i]; + float rightSpacing = rightEdge - (nextGlyphAndCorner->second.x + nextGlyphAndCorner->first.d); + quadBuilders.push_back(adjustedQuadBuilderForAlignmentMode(nextGlyphAndCorner->first, nextGlyphAndCorner->second, scale, enlargeForShadows, + alignment, rightSpacing, verticalAlignment, bottomSpacing)); i--; while (i >= 0) { - const auto& prevGlyphAndCorner = glyphsAndCorners[i]; + auto& prevGlyphAndCorner = glyphsAndCorners[i]; // We're to the right of the last character we checked, which means we're on a previous line, so we need to // recalculate the spacing, so we exit this loop - if (prevGlyphAndCorner.second.x >= nextGlyphAndCorner.second.x) { + if (prevGlyphAndCorner.second.x >= nextGlyphAndCorner->second.x) { break; } quadBuilders.push_back(adjustedQuadBuilderForAlignmentMode(prevGlyphAndCorner.first, prevGlyphAndCorner.second, scale, enlargeForShadows, - alignment, rightSpacing)); + alignment, rightSpacing, verticalAlignment, bottomSpacing)); - nextGlyphAndCorner = prevGlyphAndCorner; + nextGlyphAndCorner = &prevGlyphAndCorner; i--; } } @@ -512,40 +546,39 @@ void Font::buildVertices(Font::DrawInfo& drawInfo, const QString& str, const glm } } -void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const QString& str, const glm::vec4& color, - const glm::vec3& effectColor, float effectThickness, TextEffect effect, TextAlignment alignment, - const glm::vec2& origin, const glm::vec2& bounds, float scale, bool unlit, bool forward) { - if (!_loaded || str == "") { +void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const DrawProps& props) { + if (!_loaded || props.str == "") { return; } - int textEffect = (int)effect; + int textEffect = (int)props.effect; const int SHADOW_EFFECT = (int)TextEffect::SHADOW_EFFECT; - const bool boundsChanged = bounds != drawInfo.bounds || origin != drawInfo.origin; + const bool boundsChanged = props.bounds != drawInfo.bounds || props.origin != drawInfo.origin; // If we're switching to or from shadow effect mode, we need to rebuild the vertices - if (str != drawInfo.string || boundsChanged || alignment != _alignment || + if (props.str != drawInfo.string || boundsChanged || props.alignment != drawInfo.alignment || props.verticalAlignment != drawInfo.verticalAlignment || (drawInfo.params.effect != textEffect && (textEffect == SHADOW_EFFECT || drawInfo.params.effect == SHADOW_EFFECT)) || - (textEffect == SHADOW_EFFECT && scale != _scale)) { - _scale = scale; - _alignment = alignment; - buildVertices(drawInfo, str, origin, bounds, scale, textEffect == SHADOW_EFFECT, alignment); + (textEffect == SHADOW_EFFECT && props.scale != drawInfo.scale)) { + drawInfo.scale = props.scale; + drawInfo.alignment = props.alignment; + drawInfo.verticalAlignment = props.verticalAlignment; + buildVertices(drawInfo, props.str, props.origin, props.bounds, props.scale, textEffect == SHADOW_EFFECT, drawInfo.alignment, drawInfo.verticalAlignment); } setupGPU(); - if (!drawInfo.paramsBuffer || boundsChanged || _needsParamsUpdate || drawInfo.params.color != color || - drawInfo.params.effectColor != effectColor || drawInfo.params.effectThickness != effectThickness || + if (!drawInfo.paramsBuffer || boundsChanged || _needsParamsUpdate || drawInfo.params.color != props.color || + drawInfo.params.effectColor != props.effectColor || drawInfo.params.effectThickness != props.effectThickness || drawInfo.params.effect != textEffect) { - drawInfo.params.color = color; - drawInfo.params.effectColor = effectColor; - drawInfo.params.effectThickness = effectThickness; + drawInfo.params.color = props.color; + drawInfo.params.effectColor = props.effectColor; + drawInfo.params.effectThickness = props.effectThickness; drawInfo.params.effect = textEffect; // need the gamma corrected color here DrawParams gpuDrawParams; - gpuDrawParams.bounds = glm::vec4(origin, bounds); + gpuDrawParams.bounds = glm::vec4(props.origin, props.bounds); gpuDrawParams.color = ColorUtils::sRGBToLinearVec4(drawInfo.params.color); gpuDrawParams.unitRange = _distanceRange; gpuDrawParams.effect = drawInfo.params.effect; @@ -559,7 +592,7 @@ void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const QString _needsParamsUpdate = false; } - batch.setPipeline(_pipelines[std::make_tuple(color.a < 1.0f, unlit, forward)]); + batch.setPipeline(_pipelines[std::make_tuple(props.color.a < 1.0f, props.unlit, props.forward, props.mirror)]); batch.setInputFormat(_format); batch.setInputBuffer(0, drawInfo.verticesBuffer, 0, _format->getChannels().at(0)._stride); batch.setResourceTexture(render_utils::slot::texture::TextFont, _texture); diff --git a/libraries/render-utils/src/text/Font.h b/libraries/render-utils/src/text/Font.h index 523d58e0fdb..8112e279e57 100644 --- a/libraries/render-utils/src/text/Font.h +++ b/libraries/render-utils/src/text/Font.h @@ -15,6 +15,7 @@ #include "Glyph.h" #include "TextEffect.h" #include "TextAlignment.h" +#include "TextVerticalAlignment.h" #include #include @@ -55,15 +56,41 @@ class Font : public QObject { glm::vec2 origin; glm::vec2 bounds; DrawParams params; + + float scale { 0.0f }; + TextAlignment alignment { TextAlignment::LEFT }; + TextVerticalAlignment verticalAlignment { TextVerticalAlignment::TOP }; }; glm::vec2 computeExtent(const QString& str) const; - float getFontSize() const { return _fontSize; } + float getFontHeight() const { return _fontHeight; } + + struct DrawProps { + DrawProps(const QString& str, const glm::vec4& color, const glm::vec3& effectColor, const glm::vec2& origin, const glm::vec2& bounds, + float scale, float effectThickness, TextEffect effect, TextAlignment alignment, TextVerticalAlignment verticalAlignment, bool unlit, + bool forward, bool mirror) : + str(str), color(color), effectColor(effectColor), origin(origin), bounds(bounds), scale(scale), effectThickness(effectThickness), + effect(effect), alignment(alignment), verticalAlignment(verticalAlignment), unlit(unlit), forward(forward), mirror(mirror) {} + DrawProps(const QString& str, const glm::vec4& color, const glm::vec2& origin, const glm::vec2& bounds, bool forward) : + str(str), color(color), origin(origin), bounds(bounds), forward(forward) {} + + const QString& str; + const glm::vec4& color; + const glm::vec3& effectColor { glm::vec3(0.0f) }; + const glm::vec2& origin; + const glm::vec2& bounds; + float scale { 1.0f }; + float effectThickness { 0.0f }; + TextEffect effect { TextEffect::NO_EFFECT }; + TextAlignment alignment { TextAlignment::LEFT }; + TextVerticalAlignment verticalAlignment { TextVerticalAlignment::TOP }; + bool unlit = true; + bool forward; + bool mirror = false; + }; // Render string to batch - void drawString(gpu::Batch& batch, DrawInfo& drawInfo, const QString& str, const glm::vec4& color, - const glm::vec3& effectColor, float effectThickness, TextEffect effect, TextAlignment alignment, - const glm::vec2& origin, const glm::vec2& bound, float scale, bool unlit, bool forward); + void drawString(gpu::Batch& batch, DrawInfo& drawInfo, const DrawProps& props); static Pointer load(const QString& family); @@ -76,11 +103,11 @@ public slots: static Pointer load(const QString& family, QIODevice& fontFile); QStringList tokenizeForWrapping(const QString& str) const; QStringList splitLines(const QString& str) const; - glm::vec2 computeTokenExtent(const QString& str) const; + float computeTokenWidth(const QString& str) const; const Glyph& getGlyph(const QChar& c) const; void buildVertices(DrawInfo& drawInfo, const QString& str, const glm::vec2& origin, const glm::vec2& bounds, float scale, bool enlargeForShadows, - TextAlignment alignment); + TextAlignment alignment, TextVerticalAlignment verticalAlignment); void setupGPU(); @@ -94,20 +121,17 @@ public slots: // Font characteristics QString _family; glm::vec2 _distanceRange { 1.0f }; - float _fontSize { 0.0f }; + float _fontHeight { 0.0f }; float _leading { 0.0f }; float _spaceWidth { 0.0f }; - float _scale { 0.0f }; - TextAlignment _alignment { TextAlignment::LEFT }; - bool _loaded { false }; bool _needsParamsUpdate { false }; gpu::TexturePointer _texture; gpu::BufferStreamPointer _stream; - static std::map, gpu::PipelinePointer> _pipelines; + static std::map, gpu::PipelinePointer> _pipelines; static gpu::Stream::FormatPointer _format; }; diff --git a/libraries/render-utils/src/toneMapping.slf b/libraries/render-utils/src/toneMapping.slf index 32aa2b0788f..0c336c8563a 100644 --- a/libraries/render-utils/src/toneMapping.slf +++ b/libraries/render-utils/src/toneMapping.slf @@ -16,8 +16,8 @@ <@include render-utils/ShaderConstants.h@> struct ToneMappingParams { - vec4 _exp_2powExp_s0_s1; - ivec4 _toneCurve_s0_s1_s2; + float _2powExp; + int _toneCurve; }; const float GAMMA_22 = 2.2; @@ -31,17 +31,17 @@ LAYOUT(binding=RENDER_UTILS_BUFFER_TM_PARAMS) uniform toneMappingParamsBuffer { ToneMappingParams params; }; float getTwoPowExposure() { - return params._exp_2powExp_s0_s1.y; + return params._2powExp; } int getToneCurve() { - return params._toneCurve_s0_s1_s2.x; + return params._toneCurve; } LAYOUT(binding=RENDER_UTILS_TEXTURE_TM_COLOR) uniform sampler2D colorMap; layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; - + void main(void) { <@if HIFI_USE_MIRRORED@> vec4 fragColorRaw = texture(colorMap, vec2(1.0 - varTexCoord0.x, varTexCoord0.y)); diff --git a/libraries/render-utils/src/zone_drawAmbient.slf b/libraries/render-utils/src/zone_drawAmbient.slf index d780fd0de21..07eab08a352 100644 --- a/libraries/render-utils/src/zone_drawAmbient.slf +++ b/libraries/render-utils/src/zone_drawAmbient.slf @@ -4,6 +4,7 @@ // // Created by Sam Gateau on 5/16/17. // Copyright 2017 High Fidelity, Inc. +// Copyright 2024 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html @@ -41,10 +42,10 @@ void main(void) { vec3 ambientMap = evalSkyboxLight(fragNormal, lod).xyz; vec3 ambientSH = sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(lightAmbient), fragNormal).xyz; - // vec3 ambient = sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(lightAmbient), fragNormal).xyz; - // _fragColor = vec4( 0.5 * (fragNormal + vec3(1.0)), 1.0); + // _fragColor = vec4( 0.5 * (fragNormal + vec3(1.0)), 1.0); vec3 color = mix(ambientSH, ambientMap, float(sphereUV.x > 0.0)); + color = applySkyboxColorMix(color, getLightAmbientColor(lightAmbient), getLightAmbientBlend(lightAmbient)); color = color * 1.0 - base.w + base.xyz * base.w; const float INV_GAMMA_22 = 1.0 / 2.2; diff --git a/libraries/render/src/render/Args.h b/libraries/render/src/render/Args.h index d09b0d2f2fb..fb7d698672d 100644 --- a/libraries/render/src/render/Args.h +++ b/libraries/render/src/render/Args.h @@ -159,6 +159,10 @@ namespace render { bool _takingSnapshot { false }; StencilMaskMode _stencilMaskMode { StencilMaskMode::NONE }; std::function _stencilMaskOperator; + + ItemID _ignoreItem { 0 }; + size_t _mirrorDepth { 0 }; + size_t _numMirrorFlips { 0 }; }; } diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index 039cf01c861..cd69114bbf0 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -82,7 +82,7 @@ void FetchNonspatialItems::run(const RenderContextPointer& renderContext, const outItems.reserve(items.size()); for (auto& id : items) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && item.passesZoneOcclusionTest(CullTest::_containingZones)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && item.passesZoneOcclusionTest(CullTest::_containingZones)) { outItems.emplace_back(ItemBound(id, item.getBound(renderContext->args))); } } @@ -190,7 +190,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("insideFitItems"); for (auto id : inSelection.insideItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -205,7 +205,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("insideSmallItems"); for (auto id : inSelection.insideSubcellItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -220,7 +220,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("partialFitItems"); for (auto id : inSelection.partialItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -235,7 +235,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("partialSmallItems"); for (auto id : inSelection.partialSubcellItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -252,7 +252,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("insideFitItems"); for (auto id : inSelection.insideItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); outItems.emplace_back(itemBound); if (item.getKey().isMetaCullGroup()) { @@ -267,7 +267,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("insideSmallItems"); for (auto id : inSelection.insideSubcellItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); if (test.solidAngleTest(itemBound.bound)) { outItems.emplace_back(itemBound); @@ -284,7 +284,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("partialFitItems"); for (auto id : inSelection.partialItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); if (test.frustumTest(itemBound.bound)) { outItems.emplace_back(itemBound); @@ -301,7 +301,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, PerformanceTimer perfTimer("partialSmallItems"); for (auto id : inSelection.partialSubcellItems) { auto& item = scene->getItem(id); - if (filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { + if (id != renderContext->args->_ignoreItem && filter.test(item.getKey()) && test.zoneOcclusionTest(item)) { ItemBound itemBound(id, item.getBound(args)); if (test.frustumTest(itemBound.bound) && test.solidAngleTest(itemBound.bound)) { outItems.emplace_back(itemBound); @@ -325,73 +325,6 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, std::static_pointer_cast(renderContext->jobConfig)->numItems = (int)outItems.size(); } -void CullShapeBounds::run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { - assert(renderContext->args); - assert(renderContext->args->hasViewFrustum()); - RenderArgs* args = renderContext->args; - - const auto& inShapes = inputs.get0(); - const auto& cullFilter = inputs.get1(); - const auto& boundsFilter = inputs.get2(); - ViewFrustumPointer antiFrustum; - auto& outShapes = outputs.edit0(); - auto& outBounds = outputs.edit1(); - - if (!inputs[3].isNull()) { - antiFrustum = inputs.get3(); - } - outShapes.clear(); - outBounds = AABox(); - - if (!cullFilter.selectsNothing() || !boundsFilter.selectsNothing()) { - auto& details = args->_details.edit(_detailType); - CullTest test(_cullFunctor, args, details, antiFrustum); - auto scene = args->_scene; - - for (auto& inItems : inShapes) { - auto key = inItems.first; - auto outItems = outShapes.find(key); - if (outItems == outShapes.end()) { - outItems = outShapes.insert(std::make_pair(key, ItemBounds{})).first; - outItems->second.reserve(inItems.second.size()); - } - - details._considered += (int)inItems.second.size(); - - if (antiFrustum == nullptr) { - for (auto& item : inItems.second) { - if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound)) { - const auto shapeKey = scene->getItem(item.id).getKey(); - if (cullFilter.test(shapeKey)) { - outItems->second.emplace_back(item); - } - if (boundsFilter.test(shapeKey)) { - outBounds += item.bound; - } - } - } - } else { - for (auto& item : inItems.second) { - if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound) && test.antiFrustumTest(item.bound)) { - const auto shapeKey = scene->getItem(item.id).getKey(); - if (cullFilter.test(shapeKey)) { - outItems->second.emplace_back(item); - } - if (boundsFilter.test(shapeKey)) { - outBounds += item.bound; - } - } - } - } - details._rendered += (int)outItems->second.size(); - } - - for (auto& items : outShapes) { - items.second.shrink_to_fit(); - } - } -} - void ApplyCullFunctorOnItemBounds::run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); diff --git a/libraries/render/src/render/CullTask.h b/libraries/render/src/render/CullTask.h index 9a7466223d7..9e214fd9889 100644 --- a/libraries/render/src/render/CullTask.h +++ b/libraries/render/src/render/CullTask.h @@ -121,29 +121,6 @@ namespace render { void run(const RenderContextPointer& renderContext, const Inputs& inputs, ItemBounds& outItems); }; - class CullShapeBounds { - public: - using Inputs = render::VaryingSet4; - using Outputs = render::VaryingSet2; - using JobModel = Job::ModelIO; - - CullShapeBounds(CullFunctor cullFunctor, RenderDetails::Type type) : - _cullFunctor{ cullFunctor }, - _detailType(type) {} - - CullShapeBounds(CullFunctor cullFunctor) : - _cullFunctor{ cullFunctor } { - } - - void run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); - - private: - - CullFunctor _cullFunctor; - RenderDetails::Type _detailType{ RenderDetails::OTHER }; - - }; - class ApplyCullFunctorOnItemBounds { public: using Inputs = render::VaryingSet2; diff --git a/libraries/render/src/render/FilterTask.cpp b/libraries/render/src/render/FilterTask.cpp index 3771d7f743e..22f61a42fe7 100644 --- a/libraries/render/src/render/FilterTask.cpp +++ b/libraries/render/src/render/FilterTask.cpp @@ -148,3 +148,11 @@ void IDsToBounds::run(const RenderContextPointer& renderContext, const ItemIDs& } } } + +void MergeItems::run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { + const auto& array1 = inputs.get0(); + const auto& array2 = inputs.get1(); + + outputs = array1; + outputs.insert(outputs.end(), array2.begin(), array2.end()); +} diff --git a/libraries/render/src/render/FilterTask.h b/libraries/render/src/render/FilterTask.h index c2244e5f57f..1a8f8f2e150 100644 --- a/libraries/render/src/render/FilterTask.h +++ b/libraries/render/src/render/FilterTask.h @@ -158,6 +158,18 @@ namespace render { bool _disableAABBs{ false }; }; + // Concatenate two arrays of items + class MergeItems { + public: + using Inputs = VaryingSet2; + using Outputs = ItemBounds; + using JobModel = Job::ModelIO; + + MergeItems() {} + + void run(const RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); + }; + } #endif // hifi_render_FilterTask_h; \ No newline at end of file diff --git a/libraries/render/src/render/Item.cpp b/libraries/render/src/render/Item.cpp index 62b3b205230..b5a6befdcb4 100644 --- a/libraries/render/src/render/Item.cpp +++ b/libraries/render/src/render/Item.cpp @@ -148,6 +148,13 @@ namespace render { payload->render(args); } + template <> void payloadRenderSimulate(const PayloadProxyInterface::Pointer& payload, RenderArgs* args) { + if (!args || !payload) { + return; + } + payload->renderSimulate(args); + } + template <> uint32_t metaFetchMetaSubItems(const PayloadProxyInterface::Pointer& payload, ItemIDs& subItems) { if (!payload) { return 0; @@ -162,10 +169,17 @@ namespace render { return payload->passesZoneOcclusionTest(containingZones); } + template <> ItemID payloadComputeMirrorView(const PayloadProxyInterface::Pointer& payload, ViewFrustum& viewFrustum) { + if (!payload) { + return Item::INVALID_ITEM_ID; + } + return payload->computeMirrorView(viewFrustum); + } + template <> HighlightStyle payloadGetOutlineStyle(const PayloadProxyInterface::Pointer& payload, const ViewFrustum& viewFrustum, const size_t height) { if (!payload) { return HighlightStyle(); } return payload->getOutlineStyle(viewFrustum, height); } -} \ No newline at end of file +} diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index a5a4b5e32f6..791b180e04e 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -112,6 +112,8 @@ class ItemKey { FIRST_LAYER_BIT, // 8 Exclusive Layers (encoded in 3 bits) available to organize the items in layers, an item can only belong to ONE layer LAST_LAYER_BIT = FIRST_LAYER_BIT + NUM_LAYER_BITS, + MIRROR, // Item is a mirror + SIMULATE, // Item requires simulation OUTLINE, // Item has an outline __SMALLER, // Reserved bit for spatialized item to indicate that it is smaller than expected in the cell in which it belongs (probably because it overlaps over several smaller cells) @@ -166,6 +168,8 @@ class ItemKey { Builder& withoutMetaCullGroup() { _flags.reset(META_CULL_GROUP); return (*this); } Builder& withSubMetaCulled() { _flags.set(SUB_META_CULLED); return (*this); } Builder& withoutSubMetaCulled() { _flags.reset(SUB_META_CULLED); return (*this); } + Builder& withMirror() { _flags.set(MIRROR); return (*this); } + Builder& withSimulate() { _flags.set(SIMULATE); return (*this); } Builder& withTag(Tag tag) { _flags.set(FIRST_TAG_BIT + tag); return (*this); } // Set ALL the tags in one call using the Tag bits @@ -212,6 +216,12 @@ class ItemKey { bool isSubMetaCulled() const { return _flags[SUB_META_CULLED]; } void setSubMetaCulled(bool metaCulled) { (metaCulled ? _flags.set(SUB_META_CULLED) : _flags.reset(SUB_META_CULLED)); } + bool isNotMirror() const { return !_flags[MIRROR]; } + bool isMirror() const { return _flags[MIRROR]; } + + bool isNotSimulate() const { return !_flags[SIMULATE]; } + bool isSimulate() const { return _flags[SIMULATE]; } + bool isTag(Tag tag) const { return _flags[FIRST_TAG_BIT + tag]; } uint8_t getTagBits() const { return ((_flags.to_ulong() & KEY_TAG_BITS_MASK) >> FIRST_TAG_BIT); } @@ -283,7 +293,13 @@ class ItemFilter { Builder& withMetaCullGroup() { _value.set(ItemKey::META_CULL_GROUP); _mask.set(ItemKey::META_CULL_GROUP); return (*this); } Builder& withoutSubMetaCulled() { _value.reset(ItemKey::SUB_META_CULLED); _mask.set(ItemKey::SUB_META_CULLED); return (*this); } - Builder& withSubMetaCulled() { _value.set(ItemKey::SUB_META_CULLED); _mask.set(ItemKey::SUB_META_CULLED); return (*this); } + Builder& withSubMetaCulled() { _value.set(ItemKey::SUB_META_CULLED); _mask.set(ItemKey::SUB_META_CULLED); return (*this); } + + Builder& withoutMirror() { _value.reset(ItemKey::MIRROR); _mask.set(ItemKey::MIRROR); return (*this); } + Builder& withMirror() { _value.set(ItemKey::MIRROR); _mask.set(ItemKey::MIRROR); return (*this); } + + Builder& withoutSimulate() { _value.reset(ItemKey::SIMULATE); _mask.set(ItemKey::SIMULATE); return (*this); } + Builder& withSimulate() { _value.set(ItemKey::SIMULATE); _mask.set(ItemKey::SIMULATE); return (*this); } Builder& withoutTag(ItemKey::Tag tagIndex) { _value.reset(ItemKey::FIRST_TAG_BIT + tagIndex); _mask.set(ItemKey::FIRST_TAG_BIT + tagIndex); return (*this); } Builder& withTag(ItemKey::Tag tagIndex) { _value.set(ItemKey::FIRST_TAG_BIT + tagIndex); _mask.set(ItemKey::FIRST_TAG_BIT + tagIndex); return (*this); } @@ -304,6 +320,7 @@ class ItemFilter { static Builder transparentShape() { return Builder().withTypeShape().withTransparent().withWorldSpace(); } static Builder light() { return Builder().withTypeLight(); } static Builder meta() { return Builder().withTypeMeta(); } + static Builder mirror() { return Builder().withMirror(); } static Builder background() { return Builder().withViewSpace().withLayer(ItemKey::LAYER_BACKGROUND); } static Builder nothing() { return Builder().withNothing(); } }; @@ -445,6 +462,7 @@ class Item { virtual const ItemKey getKey() const = 0; virtual const Bound getBound(RenderArgs* args) const = 0; virtual void render(RenderArgs* args) = 0; + virtual void renderSimulate(RenderArgs* args) = 0; virtual const ShapeKey getShapeKey() const = 0; @@ -452,6 +470,8 @@ class Item { virtual bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const = 0; + virtual ItemID computeMirrorView(ViewFrustum& viewFrustum) const = 0; + virtual HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const = 0; ~PayloadInterface() {} @@ -498,6 +518,9 @@ class Item { // Render call for the item void render(RenderArgs* args) const { _payload->render(args); } + // Render-side simulate call for the item + void renderSimulate(RenderArgs* args) { _payload->renderSimulate(args); } + // Shape Type Interface const ShapeKey getShapeKey() const; @@ -507,6 +530,8 @@ class Item { bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const { return _payload->passesZoneOcclusionTest(containingZones); } + ItemID computeMirrorView(ViewFrustum& viewFrustum) const { return _payload->computeMirrorView(viewFrustum); } + HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const { return _payload->getOutlineStyle(viewFrustum, height); } // Access the status @@ -548,6 +573,7 @@ inline QDebug operator<<(QDebug debug, const Item& item) { template const ItemKey payloadGetKey(const std::shared_ptr& payloadData) { return ItemKey(); } template const Item::Bound payloadGetBound(const std::shared_ptr& payloadData, RenderArgs* args) { return Item::Bound(); } template void payloadRender(const std::shared_ptr& payloadData, RenderArgs* args) { } +template void payloadRenderSimulate(const std::shared_ptr& payloadData, RenderArgs* args) { } // Shape type interface // This allows shapes to characterize their pipeline via a ShapeKey, to be picked with a subclass of Shape. @@ -563,6 +589,9 @@ template uint32_t metaFetchMetaSubItems(const std::shared_ptr& payl // Allows payloads to determine if they should render or not, based on the zones that contain the current camera template bool payloadPassesZoneOcclusionTest(const std::shared_ptr& payloadData, const std::unordered_set& containingZones) { return true; } +// Mirror Interface +template ItemID payloadComputeMirrorView(const std::shared_ptr& payloadData, ViewFrustum& viewFrustum) { return Item::INVALID_ITEM_ID; } + // Outline Interface // Allows payloads to specify an outline style template HighlightStyle payloadGetOutlineStyle(const std::shared_ptr& payloadData, const ViewFrustum& viewFrustum, const size_t height) { @@ -586,6 +615,7 @@ template class Payload : public Item::PayloadInterface { virtual const Item::Bound getBound(RenderArgs* args) const override { return payloadGetBound(_data, args); } virtual void render(RenderArgs* args) override { payloadRender(_data, args); } + virtual void renderSimulate(RenderArgs* args) override { payloadRenderSimulate(_data, args); } // Shape Type interface virtual const ShapeKey getShapeKey() const override { return shapeGetShapeKey(_data); } @@ -595,6 +625,8 @@ template class Payload : public Item::PayloadInterface { virtual bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const override { return payloadPassesZoneOcclusionTest(_data, containingZones); } + virtual ItemID computeMirrorView(ViewFrustum& viewFrustum) const override { return payloadComputeMirrorView(_data, viewFrustum); } + virtual HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const override { return payloadGetOutlineStyle(_data, viewFrustum, height); } protected: @@ -650,8 +682,10 @@ class PayloadProxyInterface { virtual ShapeKey getShapeKey() = 0; virtual Item::Bound getBound(RenderArgs* args) = 0; virtual void render(RenderArgs* args) = 0; + virtual void renderSimulate(RenderArgs* args) = 0; virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const = 0; virtual bool passesZoneOcclusionTest(const std::unordered_set& containingZones) const = 0; + virtual ItemID computeMirrorView(ViewFrustum& viewFrustum) const = 0; virtual HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const = 0; // FIXME: this isn't the best place for this since it's only used for ModelEntities, but currently all Entities use PayloadProxyInterface @@ -662,9 +696,11 @@ class PayloadProxyInterface { template <> const ItemKey payloadGetKey(const PayloadProxyInterface::Pointer& payload); template <> const Item::Bound payloadGetBound(const PayloadProxyInterface::Pointer& payload, RenderArgs* args); template <> void payloadRender(const PayloadProxyInterface::Pointer& payload, RenderArgs* args); +template <> void payloadRenderSimulate(const PayloadProxyInterface::Pointer& payload, RenderArgs* args); template <> uint32_t metaFetchMetaSubItems(const PayloadProxyInterface::Pointer& payload, ItemIDs& subItems); template <> const ShapeKey shapeGetShapeKey(const PayloadProxyInterface::Pointer& payload); template <> bool payloadPassesZoneOcclusionTest(const PayloadProxyInterface::Pointer& payload, const std::unordered_set& containingZones); +template <> ItemID payloadComputeMirrorView(const PayloadProxyInterface::Pointer& payload, ViewFrustum& viewFrustum); template <> HighlightStyle payloadGetOutlineStyle(const PayloadProxyInterface::Pointer& payload, const ViewFrustum& viewFrustum, const size_t height); typedef Item::PayloadPointer PayloadPointer; diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp index f30fbc155eb..e8954f4161b 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.cpp +++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp @@ -36,24 +36,29 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin const auto nonspatialSelection = task.addJob("FetchLayeredSelection", nonspatialFilter); // Multi filter visible items into different buckets - const int NUM_SPATIAL_FILTERS = 5; - const int NUM_NON_SPATIAL_FILTERS = 3; + const int NUM_SPATIAL_FILTERS = 7; + const int NUM_NON_SPATIAL_FILTERS = 4; const int OPAQUE_SHAPE_BUCKET = 0; const int TRANSPARENT_SHAPE_BUCKET = 1; - const int LIGHT_BUCKET = 2; - const int META_BUCKET = 3; - const int OUTLINE_BUCKET = 4; - const int BACKGROUND_BUCKET = 2; + const int SIMULATE_BUCKET = 2; + const int LIGHT_BUCKET = 3; + const int META_BUCKET = 4; + const int MIRROR_BUCKET = 5; + const int OUTLINE_BUCKET = 6; + const int BACKGROUND_BUCKET = 3; MultiFilterItems::ItemFilterArray spatialFilters = { { - ItemFilter::Builder::opaqueShape(), + ItemFilter::Builder::opaqueShape().withoutMirror(), ItemFilter::Builder::transparentShape(), + ItemFilter::Builder().withSimulate(), ItemFilter::Builder::light(), - ItemFilter::Builder::meta(), + ItemFilter::Builder::meta().withoutMirror(), + ItemFilter::Builder::mirror(), ItemFilter::Builder().withVisible().withOutline() } }; MultiFilterItems::ItemFilterArray nonspatialFilters = { { ItemFilter::Builder::opaqueShape(), ItemFilter::Builder::transparentShape(), + ItemFilter::Builder().withSimulate(), ItemFilter::Builder::background() } }; const auto filteredSpatialBuckets = @@ -68,6 +73,7 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin const auto transparents = task.addJob("DepthSortTransparent", filteredSpatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false)); const auto lights = filteredSpatialBuckets[LIGHT_BUCKET]; const auto metas = filteredSpatialBuckets[META_BUCKET]; + const auto mirrors = task.addJob("DepthSortMirrors", filteredSpatialBuckets[MIRROR_BUCKET]); const auto background = filteredNonspatialBuckets[BACKGROUND_BUCKET]; @@ -77,9 +83,13 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin const auto filteredLayeredOpaque = task.addJob("FilterLayeredOpaque", layeredOpaques, ItemKey::Layer::LAYER_1); const auto filteredLayeredTransparent = task.addJob("FilterLayeredTransparent", layeredTransparents, ItemKey::Layer::LAYER_1); + // collect our simulate objects from both buckets + const auto mergeInputs = MergeItems::Inputs(filteredSpatialBuckets[SIMULATE_BUCKET], filteredNonspatialBuckets[SIMULATE_BUCKET]).asVarying(); + const auto simulate = task.addJob("MergeSimulateItems", mergeInputs); + task.addJob("ClearContainingZones"); - output = Output(BucketList{ opaques, transparents, lights, metas, filteredSpatialBuckets[OUTLINE_BUCKET], + output = Output(BucketList{ opaques, transparents, lights, metas, mirrors, simulate, filteredSpatialBuckets[OUTLINE_BUCKET], filteredLayeredOpaque.getN(0), filteredLayeredTransparent.getN(0), filteredLayeredOpaque.getN(1), filteredLayeredTransparent.getN(1), background }, spatialSelection); diff --git a/libraries/render/src/render/RenderFetchCullSortTask.h b/libraries/render/src/render/RenderFetchCullSortTask.h index bb01a81d81d..5802245b90b 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.h +++ b/libraries/render/src/render/RenderFetchCullSortTask.h @@ -24,6 +24,8 @@ class RenderFetchCullSortTask { TRANSPARENT_SHAPE, LIGHT, META, + MIRROR, + SIMULATE, OUTLINE, LAYER_FRONT_OPAQUE_SHAPE, LAYER_FRONT_TRANSPARENT_SHAPE, diff --git a/libraries/render/src/render/ResampleTask.cpp b/libraries/render/src/render/ResampleTask.cpp index b868c535425..e77dda600c3 100644 --- a/libraries/render/src/render/ResampleTask.cpp +++ b/libraries/render/src/render/ResampleTask.cpp @@ -167,7 +167,8 @@ void UpsampleToBlitFramebuffer::run(const RenderContextPointer& renderContext, c batch.setViewportTransform(viewport); batch.setProjectionTransform(glm::mat4()); batch.resetViewTransform(); - batch.setPipeline(args->_renderMode == RenderArgs::MIRROR_RENDER_MODE ? _mirrorPipeline : _pipeline); + bool shouldMirror = args->_numMirrorFlips >= (args->_renderMode != RenderArgs::MIRROR_RENDER_MODE); + batch.setPipeline(shouldMirror ? _mirrorPipeline : _pipeline); batch.setModelTransform(gpu::Framebuffer::evalSubregionTexcoordTransform(bufferSize, viewport)); batch.setResourceTexture(0, sourceFramebuffer->getRenderBuffer(0)); diff --git a/libraries/render/src/render/ResampleTask.h b/libraries/render/src/render/ResampleTask.h index 92f720c8434..bf1e5359494 100644 --- a/libraries/render/src/render/ResampleTask.h +++ b/libraries/render/src/render/ResampleTask.h @@ -73,7 +73,7 @@ namespace render { using Input = gpu::FramebufferPointer; using JobModel = Job::ModelIO; - UpsampleToBlitFramebuffer() {} + UpsampleToBlitFramebuffer(size_t depth) : _depth(depth) {} void run(const RenderContextPointer& renderContext, const Input& input, gpu::FramebufferPointer& resampledFrameBuffer); @@ -81,6 +81,8 @@ namespace render { static gpu::PipelinePointer _pipeline; static gpu::PipelinePointer _mirrorPipeline; + + size_t _depth; }; } diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index 988b04cc3ff..49b23a04e4c 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -203,6 +203,8 @@ class Scene { void setItemTransition(ItemID id, Index transitionId); void removeItemTransition(ItemID id); + void simulate(ItemID id, RenderArgs* args) { _items[id].renderSimulate(args); } + HighlightStyle getOutlineStyle(ItemID id, const ViewFrustum& viewFrustum, uint16_t height) { return _items[id].getOutlineStyle(viewFrustum, height); } protected: diff --git a/libraries/script-engine/src/ScriptValueUtils.cpp b/libraries/script-engine/src/ScriptValueUtils.cpp index ea0c40bfc40..77ee38de8c9 100644 --- a/libraries/script-engine/src/ScriptValueUtils.cpp +++ b/libraries/script-engine/src/ScriptValueUtils.cpp @@ -863,6 +863,14 @@ bool quuidFromScriptValue(const ScriptValue& object, QUuid& uuid) { return true; } +ScriptValue qStringToScriptValue(ScriptEngine* engine, const QString& string) { + if (string.isNull()) { + return engine->nullValue(); + } + ScriptValue obj(engine->newValue(string)); + return obj; +} + /*@jsdoc * A 2D size value. * @typedef {object} Size @@ -1030,3 +1038,25 @@ QVector qVectorEntityItemIDFromScriptValue(const ScriptValue& arra } return newVector; } + +ScriptValue qVectorQStringToScriptValue(ScriptEngine* engine, const QVector& vector) { + ScriptValue array = engine->newArray(); + for (int i = 0; i < vector.size(); i++) { + array.setProperty(i, qStringToScriptValue(engine, vector.at(i))); + } + return array; +} + +QVector qVectorQStringFromScriptValue(const ScriptValue& array) { + if (!array.isArray()) { + return QVector(); + } + QVector newVector; + int length = array.property("length").toInteger(); + newVector.reserve(length); + for (int i = 0; i < length; i++) { + QString string = array.property(i).toString(); + newVector << string; + } + return newVector; +} \ No newline at end of file diff --git a/libraries/script-engine/src/ScriptValueUtils.h b/libraries/script-engine/src/ScriptValueUtils.h index 45fee61cc45..0a206d1aa56 100644 --- a/libraries/script-engine/src/ScriptValueUtils.h +++ b/libraries/script-engine/src/ScriptValueUtils.h @@ -224,6 +224,9 @@ ScriptValue qVectorQUuidToScriptValue(ScriptEngine* engine, const QVector bool qVectorQUuidFromScriptValue(const ScriptValue& array, QVector& vector); QVector qVectorQUuidFromScriptValue(const ScriptValue& array); +ScriptValue qVectorQStringToScriptValue(ScriptEngine* engine, const QVector& vector); +QVector qVectorQStringFromScriptValue(const ScriptValue& array); + class AACube; ScriptValue aaCubeToScriptValue(ScriptEngine* engine, const AACube& aaCube); bool aaCubeFromScriptValue(const ScriptValue& object, AACube& aaCube); diff --git a/libraries/shared/src/AmbientOcclusionTechnique.cpp b/libraries/shared/src/AmbientOcclusionTechnique.cpp new file mode 100644 index 00000000000..d34f1e247e3 --- /dev/null +++ b/libraries/shared/src/AmbientOcclusionTechnique.cpp @@ -0,0 +1,24 @@ +// +// Created by HifiExperiments on 6/23/24 +// Copyright 2024 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "AmbientOcclusionTechnique.h" + +const char* ambientOcclusionTechniqueNames[] = { + "ssao", + "hbao" +}; + +static const size_t AO_TECHNIQUE_NAMES = (sizeof(ambientOcclusionTechniqueNames) / sizeof(ambientOcclusionTechniqueNames[0])); + +QString AmbientOcclusionTechniqueHelpers::getNameForAmbientOcclusionTechnique(AmbientOcclusionTechnique technique) { + if (((int)technique <= 0) || ((int)technique >= (int)AO_TECHNIQUE_NAMES)) { + technique = (AmbientOcclusionTechnique)0; + } + + return ambientOcclusionTechniqueNames[(int)technique]; +} diff --git a/libraries/shared/src/AmbientOcclusionTechnique.h b/libraries/shared/src/AmbientOcclusionTechnique.h new file mode 100644 index 00000000000..3295149e4d5 --- /dev/null +++ b/libraries/shared/src/AmbientOcclusionTechnique.h @@ -0,0 +1,38 @@ +// +// Created by HifiExperiments on 6/23/24 +// Copyright 2024 Overte e.V. +// +// 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_AmbientOcclusionTechnique_h +#define hifi_AmbientOcclusionTechnique_h + +#include "QString" + +/*@jsdoc + *

The technique used for calculating ambient occlusion. Different techniques have different tradeoffs.

+ * + * + * + * + * + * + * + * + *
ValueDescription
"ssao"A basic screen-space AO effect.
"hbao"A form of SSAO that uses the depth buffer for better AO detail, sometimes at the expense of performance.
+ * @typedef {string} AmbientOcclusionTechnique + */ + +enum class AmbientOcclusionTechnique : uint8_t { + SSAO = 0, + HBAO, +}; + +class AmbientOcclusionTechniqueHelpers { +public: + static QString getNameForAmbientOcclusionTechnique(AmbientOcclusionTechnique curve); +}; + +#endif // hifi_AmbientOcclusionTechnique_h diff --git a/libraries/shared/src/BillboardMode.h b/libraries/shared/src/BillboardMode.h index dd377cab31e..7c7ab981fb3 100644 --- a/libraries/shared/src/BillboardMode.h +++ b/libraries/shared/src/BillboardMode.h @@ -33,7 +33,7 @@ * @typedef {string} BillboardMode */ -enum class BillboardMode { +enum class BillboardMode : uint8_t { NONE = 0, YAW, FULL diff --git a/libraries/shared/src/ComponentMode.h b/libraries/shared/src/ComponentMode.h index f1d030cefd6..9cf773e9971 100644 --- a/libraries/shared/src/ComponentMode.h +++ b/libraries/shared/src/ComponentMode.h @@ -14,7 +14,7 @@ #include -enum ComponentMode { +enum ComponentMode : uint8_t { COMPONENT_MODE_INHERIT, COMPONENT_MODE_DISABLED, COMPONENT_MODE_ENABLED, @@ -22,7 +22,7 @@ enum ComponentMode { COMPONENT_MODE_ITEM_COUNT }; -enum AvatarPriorityMode { +enum AvatarPriorityMode : uint8_t { AVATAR_PRIORITY_INHERIT, AVATAR_PRIORITY_CROWD, AVATAR_PRIORITY_HERO, diff --git a/libraries/shared/src/EntityShape.cpp b/libraries/shared/src/EntityShape.cpp new file mode 100644 index 00000000000..a9c266904b9 --- /dev/null +++ b/libraries/shared/src/EntityShape.cpp @@ -0,0 +1,36 @@ +// +// Created by HifiExperiments on 8/4/24 +// Copyright 2024 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "EntityShape.h" + +const char* shapeNames[] = { + "Triangle", + "Quad", + "Hexagon", + "Octagon", + "Circle", + "Cube", + "Sphere", + "Tetrahedron", + "Octahedron", + "Dodecahedron", + "Icosahedron", + "Torus", // Not implemented yet. + "Cone", + "Cylinder" +}; + +static const size_t ENTITY_SHAPE_NAMES = (sizeof(shapeNames) / sizeof(shapeNames[0])); + +QString EntityShapeHelpers::getNameForEntityShape(EntityShape shape) { + if (((int)shape <= 0) || ((int)shape >= (int)ENTITY_SHAPE_NAMES)) { + shape = (EntityShape)0; + } + + return shapeNames[(int)shape]; +} diff --git a/libraries/shared/src/EntityShape.h b/libraries/shared/src/EntityShape.h new file mode 100644 index 00000000000..baa3eb77386 --- /dev/null +++ b/libraries/shared/src/EntityShape.h @@ -0,0 +1,63 @@ +// +// Created by HifiExperiments on 8/4/24 +// Copyright 2024 Overte e.V. +// +// 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_EntityShape_h +#define hifi_EntityShape_h + +#include + +/*@jsdoc + *

A "Shape", "Box", or "Sphere" {@link Entities.EntityType|EntityType} may + * display as one of the following geometrical shapes:

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
ValueDimensionsNotes
"Circle"2DA circle oriented in 3D.
"Cone"3D
"Cube"3D
"Cylinder"3D
"Dodecahedron"3D
"Hexagon"3DA hexagonal prism.
"Icosahedron"3D
"Octagon"3DAn octagonal prism.
"Octahedron"3D
"Quad"2DA square oriented in 3D.
"Sphere"3D
"Tetrahedron"3D
"Torus"3DNot implemented.
"Triangle"3DA triangular prism.
+ * @typedef {string} Entities.Shape + */ +enum class EntityShape : uint8_t { + Triangle, + Quad, + Hexagon, + Octagon, + Circle, + Cube, + Sphere, + Tetrahedron, + Octahedron, + Dodecahedron, + Icosahedron, + Torus, + Cone, + Cylinder, + NUM_SHAPES, +}; + +class EntityShapeHelpers { +public: + static QString getNameForEntityShape(EntityShape shape); +}; + +#endif // hifi_EntityShape_h diff --git a/libraries/shared/src/GizmoType.h b/libraries/shared/src/GizmoType.h index ca091e63fe5..edee96698a7 100644 --- a/libraries/shared/src/GizmoType.h +++ b/libraries/shared/src/GizmoType.h @@ -24,7 +24,7 @@ * @typedef {string} Entities.GizmoType */ -enum GizmoType { +enum GizmoType : uint8_t { RING = 0, // put new gizmo-types before this line. UNSET_GIZMO_TYPE diff --git a/libraries/shared/src/MaterialMappingMode.h b/libraries/shared/src/MaterialMappingMode.h index d95fbb339eb..d48739562a1 100644 --- a/libraries/shared/src/MaterialMappingMode.h +++ b/libraries/shared/src/MaterialMappingMode.h @@ -11,7 +11,7 @@ #include "QString" -enum MaterialMappingMode { +enum MaterialMappingMode : uint8_t { UV = 0, PROJECTED, // put new mapping-modes before this line. diff --git a/libraries/shared/src/MirrorMode.cpp b/libraries/shared/src/MirrorMode.cpp new file mode 100644 index 00000000000..272eb5d7c03 --- /dev/null +++ b/libraries/shared/src/MirrorMode.cpp @@ -0,0 +1,36 @@ +// +// Created by HifiExperiments on 3/14/22. +// Copyright 2022 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "MirrorMode.h" + +const char* MirrorModeNames[] = { + "none", + "mirror", + "portal" +}; + +static const size_t MIRROR_MODE_NAMES = (sizeof(MirrorModeNames) / sizeof(MirrorModeNames[0])); +std::function MirrorModeHelpers::_computeMirrorViewOperator = + [](ViewFrustum&, const glm::vec3&, const glm::quat&, MirrorMode, const QUuid&) { return 0; }; + +QString MirrorModeHelpers::getNameForMirrorMode(MirrorMode mode) { + if (((int)mode <= 0) || ((int)mode >= (int)MIRROR_MODE_NAMES)) { + mode = (MirrorMode)0; + } + + return MirrorModeNames[(int)mode]; +} + +void MirrorModeHelpers::setComputeMirrorViewOperator(std::function computeMirrorViewOperator) { + _computeMirrorViewOperator = computeMirrorViewOperator; +} + +uint32_t MirrorModeHelpers::computeMirrorView(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, + MirrorMode mirrorMode, const QUuid& portalExitID) { + return _computeMirrorViewOperator(viewFrustum, inPropertiesPosition, inPropertiesRotation, mirrorMode, portalExitID); +} \ No newline at end of file diff --git a/libraries/shared/src/MirrorMode.h b/libraries/shared/src/MirrorMode.h new file mode 100644 index 00000000000..cfcef790f21 --- /dev/null +++ b/libraries/shared/src/MirrorMode.h @@ -0,0 +1,51 @@ +// +// Created by HifiExperiments on 3/14/22. +// Copyright 2022 Overte e.V. +// +// 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_MirrorMode_h +#define hifi_MirrorMode_h + +#include + +#include "QString" + +#include "ViewFrustum.h" + +/*@jsdoc + *

If an entity is rendered as a mirror, a portal, or normally.

+ * + * + * + * + * + * + * + * + * + *
ValueDescription
"none"The entity will render normally.
"mirror"The entity will render as a mirror.
"portal"The entity will render as a portal.
+ * @typedef {string} MirrorMode + */ + +enum class MirrorMode : uint8_t { + NONE = 0, + MIRROR, + PORTAL +}; + +class MirrorModeHelpers { +public: + static QString getNameForMirrorMode(MirrorMode mode); + + static void setComputeMirrorViewOperator(std::function computeMirrorViewOperator); + static uint32_t computeMirrorView(ViewFrustum& viewFrustum, const glm::vec3& inPropertiesPosition, const glm::quat& inPropertiesRotation, + MirrorMode mirrorMode, const QUuid& portalExitID); + +private: + static std::function _computeMirrorViewOperator; +}; + +#endif // hifi_MirrorMode_h diff --git a/libraries/shared/src/PrimitiveMode.h b/libraries/shared/src/PrimitiveMode.h index 6dd65ec0c71..f52d21ca59e 100644 --- a/libraries/shared/src/PrimitiveMode.h +++ b/libraries/shared/src/PrimitiveMode.h @@ -25,7 +25,7 @@ * @typedef {string} Entities.PrimitiveMode */ -enum class PrimitiveMode { +enum class PrimitiveMode : uint8_t { SOLID = 0, LINES }; diff --git a/libraries/shared/src/PulseMode.h b/libraries/shared/src/PulseMode.h index 8d4c24b4bea..fb6bfc434fa 100644 --- a/libraries/shared/src/PulseMode.h +++ b/libraries/shared/src/PulseMode.h @@ -26,7 +26,7 @@ * @typedef {string} Entities.PulseMode */ -enum class PulseMode { +enum class PulseMode : uint8_t { NONE = 0, IN_PHASE, OUT_PHASE diff --git a/libraries/shared/src/RenderLayer.h b/libraries/shared/src/RenderLayer.h index e0c249a001c..d3fb97a2568 100644 --- a/libraries/shared/src/RenderLayer.h +++ b/libraries/shared/src/RenderLayer.h @@ -26,7 +26,7 @@ * @typedef {string} Entities.RenderLayer */ -enum class RenderLayer { +enum class RenderLayer : uint8_t { WORLD = 0, FRONT, HUD diff --git a/libraries/shared/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h index 6b0f981b243..7af28e86841 100644 --- a/libraries/shared/src/ShapeInfo.h +++ b/libraries/shared/src/ShapeInfo.h @@ -28,7 +28,7 @@ const int MAX_HULL_POINTS = 42; const int32_t END_OF_MESH_PART = -1; // bogus vertex index at end of mesh part const int32_t END_OF_MESH = -2; // bogus vertex index at end of mesh -enum ShapeType { +enum ShapeType : uint8_t { SHAPE_TYPE_NONE, SHAPE_TYPE_BOX, SHAPE_TYPE_SPHERE, diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 7a02c2dbbb4..d8395c8739e 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -69,7 +69,6 @@ const QUuid SpatiallyNestable::getParentID() const { } void SpatiallyNestable::setParentID(const QUuid& parentID) { - bumpAncestorChainRenderableVersion(); bool success = false; auto parent = getParentPointer(success); bool parentChanged = false; @@ -89,7 +88,6 @@ void SpatiallyNestable::setParentID(const QUuid& parentID) { success = false; parent = getParentPointer(success); if (success && parent) { - bumpAncestorChainRenderableVersion(); parent->updateQueryAACube(); parent->recalculateChildCauterization(); } @@ -1509,17 +1507,3 @@ QUuid SpatiallyNestable::getEditSenderID() { }); return editSenderID; } - -void SpatiallyNestable::bumpAncestorChainRenderableVersion(int depth) const { - if (depth > MAX_PARENTING_CHAIN_SIZE) { - // can't break the parent chain here, because it will call setParentID, which calls this - return; - } - - _ancestorChainRenderableVersion++; - bool success = false; - auto parent = getParentPointer(success); - if (success && parent) { - parent->bumpAncestorChainRenderableVersion(depth + 1); - } -} diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 29f23afdfbc..a04ad62a3a4 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -224,8 +224,6 @@ class SpatiallyNestable : public std::enable_shared_from_this bool hasGrabs(); virtual QUuid getEditSenderID(); - void bumpAncestorChainRenderableVersion(int depth = 0) const; - protected: QUuid _id; mutable SpatiallyNestableWeakPointer _parent; @@ -248,8 +246,6 @@ class SpatiallyNestable : public std::enable_shared_from_this mutable ReadWriteLockable _grabsLock; QSet _grabs; // upon this thing - mutable std::atomic _ancestorChainRenderableVersion { 0 }; - private: SpatiallyNestable() = delete; const NestableType _nestableType; // EntityItem or an AvatarData diff --git a/libraries/shared/src/TextAlignment.h b/libraries/shared/src/TextAlignment.h index b82d8e8c57a..643b501b310 100644 --- a/libraries/shared/src/TextAlignment.h +++ b/libraries/shared/src/TextAlignment.h @@ -12,21 +12,21 @@ #include "QString" /*@jsdoc - *

A {@link Entities.EntityProperties-Text|Text} entity may use one of the following alignments:

+ *

A {@link Entities.EntityProperties-Text|Text} entity may use one of the following horizontal alignments:

* * * * * * - * + * * * *
ValueDescription
"left"Text is aligned to the left side.
"center"Text is centered.
"center"Text is centered horizontally.
"right"Text is aligned to the right side.
* @typedef {string} Entities.TextAlignment */ -enum class TextAlignment { +enum class TextAlignment : uint8_t { LEFT = 0, CENTER, RIGHT diff --git a/libraries/shared/src/TextEffect.h b/libraries/shared/src/TextEffect.h index 09affc1f4ea..f0bbf22209c 100644 --- a/libraries/shared/src/TextEffect.h +++ b/libraries/shared/src/TextEffect.h @@ -27,7 +27,7 @@ * @typedef {string} Entities.TextEffect */ -enum class TextEffect { +enum class TextEffect : uint8_t { NO_EFFECT = 0, OUTLINE_EFFECT, OUTLINE_WITH_FILL_EFFECT, diff --git a/libraries/shared/src/TextVerticalAlignment.cpp b/libraries/shared/src/TextVerticalAlignment.cpp new file mode 100644 index 00000000000..a42b4c7e32d --- /dev/null +++ b/libraries/shared/src/TextVerticalAlignment.cpp @@ -0,0 +1,25 @@ +// +// Created by HifiExperiments on 8/17/24 +// Copyright 2024 Overte e.V contributors. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "TextVerticalAlignment.h" + +const char* textVerticalAlignmentNames[] = { + "top", + "bottom", + "center" +}; + +static const size_t TEXT_VERTICAL_ALIGNMENT_NAMES = (sizeof(textVerticalAlignmentNames) / sizeof(textVerticalAlignmentNames[0])); + +QString TextVerticalAlignmentHelpers::getNameForTextVerticalAlignment(TextVerticalAlignment verticalAlignment) { + if (((int)verticalAlignment <= 0) || ((int)verticalAlignment >= (int)TEXT_VERTICAL_ALIGNMENT_NAMES)) { + verticalAlignment = (TextVerticalAlignment)0; + } + + return textVerticalAlignmentNames[(int)verticalAlignment]; +} \ No newline at end of file diff --git a/libraries/shared/src/TextVerticalAlignment.h b/libraries/shared/src/TextVerticalAlignment.h new file mode 100644 index 00000000000..938bb93abe9 --- /dev/null +++ b/libraries/shared/src/TextVerticalAlignment.h @@ -0,0 +1,40 @@ +// +// Created by HifiExperiments on 8/17/24 +// Copyright 2024 Overte e.V contributors. +// +// 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_TextVerticalAlignment_h +#define hifi_TextVerticalAlignment_h + +#include "QString" + +/*@jsdoc + *

A {@link Entities.EntityProperties-Text|Text} entity may use one of the following vertical alignments:

+ * + * + * + * + * + * + * + * + * + *
ValueDescription
"top"Text is aligned to the top.
"bottom"Text is aligned to the bottom.
"center"Text is centered vertically.
+ * @typedef {string} Entities.TextVerticalAlignment + */ + +enum class TextVerticalAlignment : uint8_t { + TOP = 0, + BOTTOM, + CENTER, +}; + +class TextVerticalAlignmentHelpers { +public: + static QString getNameForTextVerticalAlignment(TextVerticalAlignment alignment); +}; + +#endif // hifi_TextVerticalAlignment_h \ No newline at end of file diff --git a/libraries/shared/src/TonemappingCurve.cpp b/libraries/shared/src/TonemappingCurve.cpp new file mode 100644 index 00000000000..e65415af04f --- /dev/null +++ b/libraries/shared/src/TonemappingCurve.cpp @@ -0,0 +1,26 @@ +// +// Created by HifiExperiments on 6/23/24 +// Copyright 2024 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "TonemappingCurve.h" + +const char* tonemappingCurveNames[] = { + "rgb", + "srgb", + "reinhard", + "filmic" +}; + +static const size_t TONEMAPPING_CURVE_NAMES = (sizeof(tonemappingCurveNames) / sizeof(tonemappingCurveNames[0])); + +QString TonemappingCurveHelpers::getNameForTonemappingCurve(TonemappingCurve curve) { + if (((int)curve <= 0) || ((int)curve >= (int)TONEMAPPING_CURVE_NAMES)) { + curve = (TonemappingCurve)0; + } + + return tonemappingCurveNames[(int)curve]; +} diff --git a/libraries/shared/src/TonemappingCurve.h b/libraries/shared/src/TonemappingCurve.h new file mode 100644 index 00000000000..f5f4d3fbb52 --- /dev/null +++ b/libraries/shared/src/TonemappingCurve.h @@ -0,0 +1,42 @@ +// +// Created by HifiExperiments on 6/23/24 +// Copyright 2024 Overte e.V. +// +// 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_TonemappingCurve_h +#define hifi_TonemappingCurve_h + +#include "QString" + +/*@jsdoc + *

The tonemapping curve applied to the final rendering.

+ * + * + * + * + * + * + * + * + * + * + *
ValueDescription
"rgb"No tonemapping, colors are kept in RGB.
"srgb"Colors are converted to sRGB.
"reinhard"Reinhard tonemapping is applied.
"filmic"Filmic tonemapping is applied.
+ * @typedef {string} TonemappingCurve + */ + +enum class TonemappingCurve : uint8_t { + RGB = 0, + SRGB, + REINHARD, + FILMIC +}; + +class TonemappingCurveHelpers { +public: + static QString getNameForTonemappingCurve(TonemappingCurve curve); +}; + +#endif // hifi_TonemappingCurve_h diff --git a/libraries/shared/src/ViewFrustum.cpp b/libraries/shared/src/ViewFrustum.cpp index e925ef960d5..daa08b5dbc8 100644 --- a/libraries/shared/src/ViewFrustum.cpp +++ b/libraries/shared/src/ViewFrustum.cpp @@ -53,7 +53,7 @@ static const glm::vec4 NDC_VALUES[NUM_FRUSTUM_CORNERS] = { glm::vec4(-1.0f, 1.0f, 1.0f, 1.0f), }; -void ViewFrustum::setProjection(const glm::mat4& projection) { +void ViewFrustum::setProjection(const glm::mat4& projection, bool isOblique) { _projection = projection; glm::mat4 inverseProjection = glm::inverse(projection); @@ -63,16 +63,21 @@ void ViewFrustum::setProjection(const glm::mat4& projection) { _corners[i] /= _corners[i].w; } - // compute frustum properties - _nearClip = -_corners[BOTTOM_LEFT_NEAR].z; - _farClip = -_corners[BOTTOM_LEFT_FAR].z; - _aspectRatio = (_corners[TOP_RIGHT_NEAR].x - _corners[BOTTOM_LEFT_NEAR].x) / - (_corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_LEFT_NEAR].y); - glm::vec4 top = inverseProjection * vec4(0.0f, 1.0f, -1.0f, 1.0f); - top /= top.w; - _fieldOfView = abs(glm::degrees(2.0f * abs(glm::angle(vec3(0.0f, 0.0f, -1.0f), glm::normalize(vec3(top)))))); - _height = _corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_RIGHT_NEAR].y; - _width = _corners[TOP_RIGHT_NEAR].x - _corners[TOP_LEFT_NEAR].x; + // HACK: these calculations aren't correct for our oblique mirror frustums, but we can just reuse the values from the original + // frustum since these values are only used on the CPU. + if (!isOblique) { + // compute frustum properties + _nearClip = -_corners[BOTTOM_LEFT_NEAR].z; + _farClip = -_corners[BOTTOM_LEFT_FAR].z; + _aspectRatio = (_corners[TOP_RIGHT_NEAR].x - _corners[BOTTOM_LEFT_NEAR].x) / + (_corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_LEFT_NEAR].y); + glm::vec4 top = inverseProjection * vec4(0.0f, 1.0f, -1.0f, 1.0f); + top /= top.w; + _fieldOfView = abs(glm::degrees(2.0f * abs(glm::angle(vec3(0.0f, 0.0f, -1.0f), glm::normalize(vec3(top)))))); + _height = _corners[TOP_RIGHT_NEAR].y - _corners[BOTTOM_RIGHT_NEAR].y; + _width = _corners[TOP_RIGHT_NEAR].x - _corners[TOP_LEFT_NEAR].x; + } + _isOblique = isOblique; } void ViewFrustum::setProjection(float cameraFov, float cameraAspectRatio, float cameraNearClip, float cameraFarClip) { @@ -109,12 +114,24 @@ void ViewFrustum::calculate() { // the function set3Points assumes that the points are given in counter clockwise order, assume you // are inside the frustum, facing the plane. Start with any point, and go counter clockwise for // three consecutive points - _planes[TOP_PLANE].set3Points(_cornersWorld[TOP_RIGHT_NEAR], _cornersWorld[TOP_LEFT_NEAR], _cornersWorld[TOP_LEFT_FAR]); - _planes[BOTTOM_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[BOTTOM_RIGHT_FAR]); - _planes[LEFT_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[BOTTOM_LEFT_FAR], _cornersWorld[TOP_LEFT_FAR]); - _planes[RIGHT_PLANE].set3Points(_cornersWorld[BOTTOM_RIGHT_FAR], _cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[TOP_RIGHT_FAR]); - _planes[NEAR_PLANE].set3Points(_cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[TOP_LEFT_NEAR]); - _planes[FAR_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_FAR], _cornersWorld[BOTTOM_RIGHT_FAR], _cornersWorld[TOP_RIGHT_FAR]); + if (!_isOblique) { + _planes[TOP_PLANE].set3Points(_cornersWorld[TOP_RIGHT_NEAR], _cornersWorld[TOP_LEFT_NEAR], _cornersWorld[TOP_LEFT_FAR]); + _planes[BOTTOM_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[BOTTOM_RIGHT_FAR]); + _planes[LEFT_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[BOTTOM_LEFT_FAR], _cornersWorld[TOP_LEFT_FAR]); + _planes[RIGHT_PLANE].set3Points(_cornersWorld[BOTTOM_RIGHT_FAR], _cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[TOP_RIGHT_FAR]); + _planes[NEAR_PLANE].set3Points(_cornersWorld[BOTTOM_RIGHT_NEAR], _cornersWorld[BOTTOM_LEFT_NEAR], _cornersWorld[TOP_LEFT_NEAR]); + _planes[FAR_PLANE].set3Points(_cornersWorld[BOTTOM_LEFT_FAR], _cornersWorld[BOTTOM_RIGHT_FAR], _cornersWorld[TOP_RIGHT_FAR]); + } else { + Corners near = getCorners(_nearClip); + Corners far = getCorners(_farClip); + + _planes[TOP_PLANE].set3Points(near.topRight, near.topLeft, far.topLeft); + _planes[BOTTOM_PLANE].set3Points(near.bottomLeft, near.bottomRight, far.bottomRight); + _planes[LEFT_PLANE].set3Points(near.bottomLeft, far.bottomLeft, far.topLeft); + _planes[RIGHT_PLANE].set3Points(far.bottomRight, near.bottomRight, far.topRight); + _planes[NEAR_PLANE].set3Points(near.bottomRight, near.bottomLeft, near.topLeft); + _planes[FAR_PLANE].set3Points(far.bottomLeft, far.bottomRight, far.topRight); + } // Also calculate our projection matrix in case people want to project points... // Projection matrix : Field of View, ratio, display range : near to far diff --git a/libraries/shared/src/ViewFrustum.h b/libraries/shared/src/ViewFrustum.h index 672ad74d368..47768b09ff4 100644 --- a/libraries/shared/src/ViewFrustum.h +++ b/libraries/shared/src/ViewFrustum.h @@ -47,7 +47,7 @@ class ViewFrustum { const glm::vec3& getRight() const { return _right; } // setters for lens attributes - void setProjection(const glm::mat4 & projection); + void setProjection(const glm::mat4& projection, bool isOblique = false); void setProjection(float cameraFov, float cameraAspectRatio, float cameraNearClip, float cameraFarClip); void setFocalLength(float focalLength) { _focalLength = focalLength; } bool isPerspective() const; @@ -103,7 +103,6 @@ class ViewFrustum { bool pointIntersectsFrustum(const glm::vec3& point) const; bool sphereIntersectsFrustum(const glm::vec3& center, float radius) const; - bool cubeIntersectsFrustum(const AACube& box) const; bool boxIntersectsFrustum(const AABox& box) const; bool boxInsideFrustum(const AABox& box) const; @@ -175,6 +174,8 @@ class ViewFrustum { float _nearClip { DEFAULT_NEAR_CLIP }; float _farClip { DEFAULT_FAR_CLIP }; + bool _isOblique { false }; + const char* debugPlaneName (int plane) const; // Used to project points diff --git a/libraries/shared/src/WebInputMode.h b/libraries/shared/src/WebInputMode.h index a65ae1341c1..e1bd7b7984b 100644 --- a/libraries/shared/src/WebInputMode.h +++ b/libraries/shared/src/WebInputMode.h @@ -25,7 +25,7 @@ * @typedef {string} WebInputMode */ -enum class WebInputMode { +enum class WebInputMode : uint8_t { TOUCH = 0, MOUSE, }; diff --git a/scripts/developer/utilities/render/ambientOcclusionPass.qml b/scripts/developer/utilities/render/ambientOcclusionPass.qml index 5c20d643459..75b927a2c95 100644 --- a/scripts/developer/utilities/render/ambientOcclusionPass.qml +++ b/scripts/developer/utilities/render/ambientOcclusionPass.qml @@ -55,6 +55,7 @@ Rectangle { Column { Repeater { model: [ + "debugEnabled:debug", "horizonBased:horizonBased", "jitterEnabled:jitterEnabled", "ditheringEnabled:ditheringEnabled", @@ -72,7 +73,7 @@ Rectangle { Column { Repeater { model: [ - "debugEnabled:showCursorPixel" + "showCursorPixel:showCursorPixel" ] HifiControls.CheckBox { boxSize: 20 @@ -100,8 +101,6 @@ Rectangle { ] } - - TabView { anchors.left: parent.left anchors.right: parent.right diff --git a/scripts/developer/utilities/render/luci/ToneMapping.qml b/scripts/developer/utilities/render/luci/ToneMapping.qml index a76990e37c4..39954039179 100644 --- a/scripts/developer/utilities/render/luci/ToneMapping.qml +++ b/scripts/developer/utilities/render/luci/ToneMapping.qml @@ -14,15 +14,11 @@ import "../../lib/prop" as Prop Column { anchors.left: parent.left - anchors.right: parent.right - Prop.PropScalar { - label: "Exposure" + anchors.right: parent.right + Prop.PropBool { + label: "Debug" object: Render.getConfig("RenderMainView.ToneMapping") - property: "exposure" - min: -4 - max: 4 - anchors.left: parent.left - anchors.right: parent.right + property: "debug" } Prop.PropEnum { label: "Tone Curve" @@ -35,6 +31,15 @@ Column { "Filmic", ] anchors.left: parent.left - anchors.right: parent.right - } + anchors.right: parent.right + } + Prop.PropScalar { + label: "Exposure" + object: Render.getConfig("RenderMainView.ToneMapping") + property: "exposure" + min: -4 + max: 4 + anchors.left: parent.left + anchors.right: parent.right + } } diff --git a/scripts/system/assets/images/tools/sound.svg b/scripts/system/assets/images/tools/sound.svg new file mode 100644 index 00000000000..a71b4490450 --- /dev/null +++ b/scripts/system/assets/images/tools/sound.svg @@ -0,0 +1,258 @@ + + + +SOUNDSOUNDSOUND + + + + + + + + + + + + + + + + + + + diff --git a/scripts/system/create/assets/data/createAppTooltips.json b/scripts/system/create/assets/data/createAppTooltips.json index eaefd08a0d1..fcbad7b3201 100644 --- a/scripts/system/create/assets/data/createAppTooltips.json +++ b/scripts/system/create/assets/data/createAppTooltips.json @@ -8,6 +8,10 @@ "shapeAlpha": { "tooltip": "The opacity of the entity between 0.0 fully transparent and 1.0 completely opaque." }, + "shapeUnlit": { + "tooltip": "If enabled, the entity will not be lit by the keylight or local lights.", + "jsPropertyName": "unlit" + }, "text": { "tooltip": "The text to display on the entity." }, @@ -41,6 +45,9 @@ "textAlignment": { "tooltip": "How the text is aligned within its left and right bounds." }, + "textVerticalAlignment": { + "tooltip": "How the text is aligned within its top and bottom bounds." + }, "topMargin": { "tooltip": "The top margin, in meters." }, @@ -116,6 +123,9 @@ "ambientLight.ambientURL": { "tooltip": "A cube map image that defines the color of the light coming from each direction." }, + "ambientLight.ambientColor": { + "tooltip": "If the URL is blank, this changes the color of the ambient light, otherwise it modifies the color of the ambient map." + }, "hazeMode": { "tooltip": "Configures the haze in the scene." }, @@ -158,6 +168,63 @@ "bloom.bloomSize": { "tooltip": "The radius of bloom. The higher the value, the larger the bloom." }, + "tonemappingMode": { + "tooltip": "Configures the tonemapping applied to the final render." + }, + "tonemapping.curve": { + "tooltip": "The tonemapping curve used." + }, + "tonemapping.exposure": { + "tooltip": "The exposure used during tonemapping." + }, + "ambientOcclusionMode": { + "tooltip": "Configures the ambient occlusion in this zone." + }, + "ambientOcclusion.technique": { + "tooltip": "The ambient occlusion technique used. Different techniques have different tradeoffs." + }, + "ambientOcclusion.jitter": { + "tooltip": "Whether or not the ambient occlusion sampling is jittered." + }, + "ambientOcclusion.resolutionLevel": { + "tooltip": "How high the resolution of the ambient occlusion buffer should be. Higher levels mean lower resolution buffers." + }, + "ambientOcclusion.edgeSharpness": { + "tooltip": "How much to sharpen the edges during the ambient occlusion blurring." + }, + "ambientOcclusion.blurRadius": { + "tooltip": "The radius used for blurring, in pixels." + }, + "ambientOcclusion.aoRadius": { + "tooltip": "The radius used for ambient occlusion." + }, + "ambientOcclusion.aoObscuranceLevel": { + "tooltip": "Intensify or dim ambient occlusion." + }, + "ambientOcclusion.aoFalloffAngle": { + "tooltip": "The falloff angle for the AO calculation." + }, + "ambientOcclusion.aoSamplingAmount": { + "tooltip": "The fraction of AO samples to use, out of the maximum for each technique." + }, + "ambientOcclusion.ssaoNumSpiralTurns": { + "tooltip": "The angle span used to distribute the AO samples ray directions. SSAO only." + }, + "audio.reverbEnabled": { + "tooltip": "If reverb should be enabled for listeners in this zone." + }, + "audio.reverbTime": { + "tooltip": "The time (seconds) for the reverb tail to decay by 60dB." + }, + "audio.reverbWetLevel": { + "tooltip": "Adjusts the wet/dry percentage, from completely dry (0%) to completely wet (100%)." + }, + "audio.listenerZones": { + "tooltip": "A list of entity IDs representing listener zones with this zone as a source." + }, + "audio.listenerAttenuationCoefficients": { + "tooltip": "A list of attenuation coefficients." + }, "avatarPriority": { "tooltip": "Alter Avatars' update priorities." }, @@ -200,6 +267,9 @@ "animation.fps": { "tooltip": "The speed of the animation." }, + "animation.smoothFrames": { + "tooltip": "If enabled, the frames of the animation will be linearly interpolated to create smoother movement." + }, "textures": { "tooltip": "A JSON string containing a texture. Use a name from the Original Texture property to override it." }, @@ -215,7 +285,7 @@ }, "imageAlpha": { "tooltip": "The opacity of the image between 0.0 fully transparent and 1.0 completely opaque." - }, + }, "emissive": { "tooltip": "If enabled, the image will display at full brightness." }, @@ -236,7 +306,10 @@ }, "showKeyboardFocusHighlight": { "tooltip": "If enabled, highlights when it has keyboard focus." - }, + }, + "wantsKeyboardFocus": { + "tooltip": "If enabled, this web entity will capture keyboard focus once clicked." + }, "isEmitting": { "tooltip": "If enabled, then particles are emitted." }, @@ -503,6 +576,12 @@ "grab.triggerable": { "tooltip": "If enabled, the collider on this entity is used for triggering events." }, + "mirrorMode": { + "tooltip": "If this entity should render normally, or as a \"Mirror\" or \"Portal\"" + }, + "portalExitID": { + "tooltip": "If this entity is a portal, what entity it should use as its exit." + }, "cloneable": { "tooltip": "If enabled, this entity can be duplicated." }, @@ -606,7 +685,7 @@ }, "useBackground": { "tooltip": "If disabled, this web entity will support a transparent background for the webpage and its elements if the CSS property of 'background-color' on the 'body' is set with transparency." - }, + }, "maxFPS": { "tooltip": "The FPS at which to render the web entity. Higher values will have a performance impact." }, @@ -682,5 +761,47 @@ }, "zTextureURL": { "tooltip": "The URL of the texture to map to surfaces perpendicular to the entity's local z-axis. JPG or PNG format." + }, + "numParticles": { + "tooltip": "The maximum number of particles to render at one time." + }, + "numTrianglesPerParticle": { + "tooltip": "The number of triangles to render per particle." + }, + "numUpdateProps": { + "tooltip": "The number of persistent Vec4 per-particle properties to use during simulation and rendering." + }, + "particleTransparent": { + "tooltip": "If the particles should render as transparent (with additive blending) or as opaque." + }, + "particleUpdateData": { + "tooltip": "A JSON description of the shaders, textures, and uniforms to use during particle updating." + }, + "particleRenderData": { + "tooltip": "A JSON description of the shaders, textures, and uniforms to use during particle rendering." + }, + "soundURL": { + "tooltip": "The URL of the sound, as a wav, mp3, or raw file." + }, + "playing": { + "tooltip": "Whether or not the sound should play." + }, + "volume": { + "tooltip": "The volume of the sound." + }, + "pitch": { + "tooltip": "Alter the pitch of the sound, within +/- 2 octaves. The value is the relative sample rate at which to resample the sound." + }, + "timeOffset": { + "tooltip": "Starts playback from a specified time (seconds) within the sound file." + }, + "loop": { + "tooltip": "Whether or not the sound is played repeatedly." + }, + "positional": { + "tooltip": "Whether or not the sound volume drops off with distance." + }, + "localOnly": { + "tooltip": "Whether the sound should play locally for everyone separately, or globally via the audio mixer." } } diff --git a/scripts/system/create/assets/images/icon-sound.svg b/scripts/system/create/assets/images/icon-sound.svg new file mode 100644 index 00000000000..cf89956c412 --- /dev/null +++ b/scripts/system/create/assets/images/icon-sound.svg @@ -0,0 +1,84 @@ + +image/svg+xml diff --git a/scripts/system/create/edit.js b/scripts/system/create/edit.js index 624886e4545..12e86291342 100644 --- a/scripts/system/create/edit.js +++ b/scripts/system/create/edit.js @@ -95,8 +95,9 @@ var SPOT_LIGHT_URL = Script.resolvePath("assets/images/icon-spot-light.svg"); var ZONE_URL = Script.resolvePath("assets/images/icon-zone.svg"); var MATERIAL_URL = Script.resolvePath("assets/images/icon-material.svg"); + var SOUND_URL = Script.resolvePath("assets/images/icon-sound.svg"); - var entityIconOverlayManager = new EntityIconOverlayManager(["Light", "ParticleEffect", "Zone", "Material"], function(entityID) { + var entityIconOverlayManager = new EntityIconOverlayManager(["Light", "ParticleEffect", "ProceduralParticleEffect", "Zone", "Material", "Sound"], function(entityID) { var properties = Entities.getEntityProperties(entityID, ["type", "isSpotlight", "parentID", "name"]); if (properties.type === "Light") { return { @@ -110,6 +111,8 @@ } else { return { imageURL: "" }; } + } else if (properties.type === "Sound") { + return { imageURL: SOUND_URL, rotation: Quat.fromPitchYawRollDegrees(0, 0, 0) }; } else { return { imageURL: PARTICLE_SYSTEM_URL }; } @@ -496,6 +499,31 @@ azimuthStart: -Math.PI, azimuthFinish: Math.PI }, + ProceduralParticleEffect: { + dimensions: 3, + numParticles: 10000, + numTrianglesPerParticle: 6, + numUpdateProps: 3, + particleUpdateData: JSON.stringify({ + version: 1.0, + fragmentShaderURL: "qrc:///shaders/proceduralParticleSwarmUpdate.frag", + uniforms: { + lifespan: 3.0, + speed: 2.0, + speedSpread: 0.25, + mass: 50000000000 + } + }), + particleRenderData: JSON.stringify({ + version: 3.0, + vertexShaderURL: "qrc:///shaders/proceduralParticleSwarmRender.vert", + fragmentShaderURL: "qrc:///shaders/proceduralParticleSwarmRender.frag", + uniforms: { + radius: 0.03, + lifespan: 3.0 + } + }) + }, Light: { color: { red: 255, green: 255, blue: 255 }, intensity: 5.0, @@ -505,6 +533,13 @@ exponent: 1.0, cutoff: 75.0, }, + Sound: { + volume: 1.0, + playing: true, + loop: true, + positional: true, + localOnly: false + }, }; var toolBar = (function () { @@ -583,8 +618,9 @@ if (!properties.grab) { properties.grab = {}; if (Menu.isOptionChecked(MENU_CREATE_ENTITIES_GRABBABLE) && - !(properties.type === "Zone" || properties.type === "Light" - || properties.type === "ParticleEffect" || properties.type === "Web")) { + !(properties.type === "Zone" || properties.type === "Light" || properties.type === "Sound" + || properties.type === "ParticleEffect" || properties.type == "ProceduralParticleEffect" + || properties.type === "Web")) { properties.grab.grabbable = true; } else { properties.grab.grabbable = false; @@ -872,6 +908,26 @@ } } + function handleNewParticleDialogResult(result) { + if (result) { + createNewEntity({ + type: result.procedural ? "ProceduralParticleEffect" : "ParticleEffect" + }); + } + } + + function handleNewSoundDialogResult(result) { + if (result) { + var soundURL = result.textInput; + if (soundURL) { + createNewEntity({ + type: "Sound", + soundURL: soundURL + }); + } + } + } + function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml. var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); tablet.popFromStack(); @@ -893,6 +949,13 @@ case "newMaterialDialogCancel": closeExistingDialogWindow(); break; + case "newParticleDialogAdd": + handleNewParticleDialogResult(message.params); + closeExistingDialogWindow(); + break; + case "newParticleDialogCancel": + closeExistingDialogWindow(); + break; case "newPolyVoxDialogAdd": handleNewPolyVoxDialogResult(message.params); closeExistingDialogWindow(); @@ -900,6 +963,13 @@ case "newPolyVoxDialogCancel": closeExistingDialogWindow(); break; + case "newSoundDialogAdd": + handleNewSoundDialogResult(message.params); + closeExistingDialogWindow(); + break; + case "newSoundDialogCancel": + closeExistingDialogWindow(); + break; } } @@ -1059,16 +1129,14 @@ }); }); - addButton("newParticleButton", function () { - createNewEntity({ - type: "ParticleEffect", - }); - }); + addButton("newParticleButton", createNewEntityDialogButtonCallback("Particle")); addButton("newMaterialButton", createNewEntityDialogButtonCallback("Material")); addButton("newPolyVoxButton", createNewEntityDialogButtonCallback("PolyVox")); + addButton("newSoundButton", createNewEntityDialogButtonCallback("Sound")); + var deactivateCreateIfDesktopWindowsHidden = function() { if (!shouldUseEditTabletApp() && !entityListTool.isVisible() && !createToolsWindow.isVisible()) { that.setActive(false); @@ -2055,7 +2123,7 @@ var entityParentIDs = []; var propType = Entities.getEntityProperties(pastedEntityIDs[0], ["type"]).type; - var NO_ADJUST_ENTITY_TYPES = ["Zone", "Light", "ParticleEffect"]; + var NO_ADJUST_ENTITY_TYPES = ["Zone", "Light", "ParticleEffect", "ProceduralParticleEffect", "Sound"]; if (NO_ADJUST_ENTITY_TYPES.indexOf(propType) === -1) { var targetDirection; if (Camera.mode === "entity" || Camera.mode === "independent") { @@ -2621,7 +2689,7 @@ if (data.snapToGrid !== undefined) { entityListTool.setListMenuSnapToGrid(data.snapToGrid); } - } else if (data.type === 'saveUserData' || data.type === 'saveMaterialData') { + } else if (data.type === 'saveUserData' || data.type === 'saveMaterialData' || data.type === 'saveParticleUpdateData' || data.type === 'saveParticleRenderData') { data.ids.forEach(function(entityID) { Entities.editEntity(entityID, data.properties); }); diff --git a/scripts/system/create/entityList/entityList.js b/scripts/system/create/entityList/entityList.js index 01196c61fe4..9a1df1f76fc 100644 --- a/scripts/system/create/entityList/entityList.js +++ b/scripts/system/create/entityList/entityList.js @@ -210,8 +210,8 @@ var EntityListTool = function(shouldUseEditTabletApp, selectionManager) { var cameraPosition = Camera.position; PROFILE("getMultipleProperties", function () { var multipleProperties = Entities.getMultipleEntityProperties(ids, ['position', 'name', 'type', 'locked', - 'visible', 'renderInfo', 'modelURL', 'materialURL', 'imageURL', 'script', 'serverScripts', - 'skybox.url', 'ambientLight.url', 'created', 'lastEdited', 'entityHostType']); + 'visible', 'renderInfo', 'modelURL', 'materialURL', 'imageURL', 'script', 'serverScripts', + 'skybox.url', 'ambientLight.url', 'soundURL', 'created', 'lastEdited', 'entityHostType']); for (var i = 0; i < multipleProperties.length; i++) { var properties = multipleProperties[i]; @@ -223,6 +223,8 @@ var EntityListTool = function(shouldUseEditTabletApp, selectionManager) { url = properties.materialURL; } else if (properties.type === "Image") { url = properties.imageURL; + } else if (properties.type === "Sound") { + url = properties.soundURL; } //print("Global object before getParentState call: " + JSON.stringify(globalThis)); var parentStatus = that.createApp.getParentState(ids[i]); diff --git a/scripts/system/create/entityList/html/js/entityList.js b/scripts/system/create/entityList/html/js/entityList.js index 06425cde66b..a642c9e722a 100644 --- a/scripts/system/create/entityList/html/js/entityList.js +++ b/scripts/system/create/entityList/html/js/entityList.js @@ -175,10 +175,12 @@ const FILTER_TYPES = [ "Web", "Material", "ParticleEffect", + "ProceduralParticleEffect", "PolyLine", "PolyVox", "Text", "Grid", + "Sound", ]; const DOUBLE_CLICK_TIMEOUT = 300; // ms diff --git a/scripts/system/create/entityProperties/html/js/entityProperties.js b/scripts/system/create/entityProperties/html/js/entityProperties.js index ab7c7ba54a8..8eab673e31d 100644 --- a/scripts/system/create/entityProperties/html/js/entityProperties.js +++ b/scripts/system/create/entityProperties/html/js/entityProperties.js @@ -131,6 +131,22 @@ const GROUPS = [ }, propertyID: "billboardMode", }, + { + label: "Mirror Mode", + type: "dropdown", + options: { + none: "None", + mirror: "Mirror", + portal: "Portal" + }, + propertyID: "mirrorMode", + }, + { + label: "Portal Exit", + type: "string", + propertyID: "portalExitID", + showPropertyRule: { "mirrorMode": "portal" }, + }, { label: "Render With Zones", type: "multipleZonesSelection", @@ -166,6 +182,12 @@ const GROUPS = [ propertyID: "shapeAlpha", propertyName: "alpha", }, + { + label: "Unlit", + type: "bool", + propertyID: "shapeUnlit", + propertyName: "unlit" + } ] }, { @@ -255,6 +277,17 @@ const GROUPS = [ propertyID: "textAlignment", propertyName: "alignment", // actual entity property name }, + { + label: "Vertical Alignment", + type: "dropdown", + options: { + top: "Top", + center: "Center", + bottom: "Bottom" + }, + propertyID: "textVerticalAlignment", + propertyName: "verticalAlignment", // actual entity property name + }, { label: "Top Margin", type: "number-draggable", @@ -437,6 +470,12 @@ const GROUPS = [ options: { inherit: "Inherit", disabled: "Off", enabled: "On" }, propertyID: "ambientLightMode", }, + { + label: "Ambient Color", + type: "color", + propertyID: "ambientLight.ambientColor", + showPropertyRule: { "ambientLightMode": "enabled" }, + }, { label: "Ambient Intensity", type: "number-draggable", @@ -594,6 +633,124 @@ const GROUPS = [ } ] }, + { + id: "zone_tonemapping", + label: "ZONE TONEMAPPING", + properties: [ + { + label: "Tonemapping", + type: "dropdown", + options: { inherit: "Inherit", disabled: "Off", enabled: "On" }, + propertyID: "tonemappingMode", + }, + { + label: "Curve", + type: "dropdown", + options: { rgb: "RGB", srgb: "sRGB", reinhard: "Reinhard", filmic: "Filmic" }, + propertyID: "tonemapping.curve", + showPropertyRule: { "tonemappingMode": "enabled" }, + }, + { + label: "Exposure", + type: "number-draggable", + min: -4.0, + max: 4.0, + step: 0.1, + decimals: 1, + propertyID: "tonemapping.exposure", + showPropertyRule: { "tonemappingMode": "enabled" }, + } + ] + }, + { + id: "zone_ambient_occlusion", + label: "ZONE AMBIENT OCCLUSION", + properties: [ + { + label: "Ambient Occlusion", + type: "dropdown", + options: { inherit: "Inherit", disabled: "Off", enabled: "On" }, + propertyID: "ambientOcclusionMode", + }, + //{ + // label: "Technique", + // type: "dropdown", + // options: { ssao: "SSAO", hbao: "HBAO" }, + // propertyID: "ambientOcclusion.technique", + // showPropertyRule: { "ambientOcclusionMode": "enabled" }, + //}, + { + label: "Jitter", + type: "bool", + propertyID: "ambientOcclusion.jitter", + showPropertyRule: { "ambientOcclusionMode": "enabled" }, + }, + { + label: "Resolution Level", + type: "number-draggable", + step: 1, + decimals: 0, + propertyID: "ambientOcclusion.resolutionLevel", + showPropertyRule: { "ambientOcclusionMode": "enabled" }, + }, + { + label: "Edge Sharpness", + type: "number-draggable", + step: 0.01, + decimals: 2, + propertyID: "ambientOcclusion.edgeSharpness", + showPropertyRule: { "ambientOcclusionMode": "enabled" }, + }, + { + label: "Blur Radius (pixels)", + type: "number-draggable", + step: 1, + decimals: 0, + propertyID: "ambientOcclusion.blurRadius", + showPropertyRule: { "ambientOcclusionMode": "enabled" }, + }, + { + label: "AO Radius", + type: "number-draggable", + step: 0.01, + decimals: 2, + propertyID: "ambientOcclusion.aoRadius", + showPropertyRule: { "ambientOcclusionMode": "enabled" }, + }, + { + label: "Intensity", + type: "number-draggable", + step: 0.01, + decimals: 2, + propertyID: "ambientOcclusion.aoObscuranceLevel", + showPropertyRule: { "ambientOcclusionMode": "enabled" }, + }, + { + label: "Falloff Angle", + type: "number-draggable", + step: 0.01, + decimals: 2, + propertyID: "ambientOcclusion.aoFalloffAngle", + showPropertyRule: { "ambientOcclusionMode": "enabled" }, + }, + { + label: "Sampling Amount", + type: "number-draggable", + step: 0.01, + decimals: 2, + propertyID: "ambientOcclusion.aoSamplingAmount", + showPropertyRule: { "ambientOcclusionMode": "enabled" }, + }, + { + label: "Num Spiral Turns", + type: "number-draggable", + step: 0.01, + decimals: 2, + propertyID: "ambientOcclusion.ssaoNumSpiralTurns", + showPropertyRule: { "ambientOcclusionMode": "enabled" }, + } + ] + }, { id: "zone_avatar_priority", label: "ZONE AVATAR PRIORITY", @@ -612,6 +769,42 @@ const GROUPS = [ } ] }, + { + id: "zone_audio", + label: "ZONE AUDIO", + properties: [ + { + label: "Enable Reverb", + type: "bool", + propertyID: "audio.reverbEnabled" + }, + { + label: "Reverb Time", + type: "number-draggable", + min: 0, + max: 10, + step: 0.1, + decimals: 2, + propertyID: "audio.reverbTime", + showPropertyRule: { "audio.reverbEnabled": "true" }, + }, + { + label: "Reverb Wet Level", + type: "number-draggable", + min: 0, + max: 100, + step: 1, + decimals: 1, + propertyID: "audio.reverbWetLevel", + showPropertyRule: { "audio.reverbEnabled": "true" }, + }, + { + label: "Listener Zones", + type: "multipleZonesSelection", + propertyID: "audio.listenerZones", + } + ] + }, { id: "model", label: "MODEL", @@ -687,6 +880,11 @@ const GROUPS = [ type: "number-draggable", propertyID: "animation.fps", }, + { + label: "Smooth Animation", + type: "bool", + propertyID: "animation.smoothFrames", + }, { label: "Texture", type: "textarea", @@ -803,6 +1001,11 @@ const GROUPS = [ }, propertyID: "inputMode", }, + { + label: "Wants Keyboard Focus", + type: "bool", + propertyID: "wantsKeyboardFocus", + }, { label: "Focus Highlight", type: "bool", @@ -1337,6 +1540,54 @@ const GROUPS = [ } ] }, + { + id: "particles_procedural", + label: "PROCEDURAL PARTICLES", + properties: [ + { + label: "Particles", + type: "number-draggable", + propertyID: "numParticles", + min: 1, + max: 1000000 + }, + { + label: "Triangles Per Particle", + type: "number-draggable", + propertyID: "numTrianglesPerParticle", + min: 1, + max: 15 + }, + { + label: "Update Props", + type: "number-draggable", + propertyID: "numUpdateProps", + min: 0, + max: 5 + }, + { + label: "Transparent", + type: "bool", + propertyID: "particleTransparent", + }, + { + label: "Particle Update Data", + type: "textarea", + buttons: [{ id: "clear", label: "Clear Update Data", className: "secondary_red red", onClick: clearParticleUpdateData }, + { id: "edit", label: "Edit as JSON", className: "secondary", onClick: newJSONParticleUpdateEditor }, + { id: "save", label: "Save Update Data", className: "secondary", onClick: saveParticleUpdateData }], + propertyID: "particleUpdateData", + }, + { + label: "Particle Render Data", + type: "textarea", + buttons: [{ id: "clear", label: "Clear Render Data", className: "secondary_red red", onClick: clearParticleRenderData }, + { id: "edit", label: "Edit as JSON", className: "secondary", onClick: newJSONParticleRenderEditor }, + { id: "save", label: "Save Render Data", className: "secondary", onClick: saveParticleRenderData }], + propertyID: "particleRenderData", + } + ] + }, { id: "polyvox", label: "POLYVOX", @@ -1391,6 +1642,62 @@ const GROUPS = [ }, ] }, + { + id: "sound", + label: "SOUND", + properties: [ + { + label: "Sound", + type: "string", + propertyID: "soundURL", + placeholder: "URL", + }, + { + label: "Playing", + type: "bool", + propertyID: "playing", + }, + { + label: "Loop", + type: "bool", + propertyID: "loop", + }, + { + label: "Volume", + type: "number-draggable", + min: 0, + max: 1, + step: 0.01, + decimals: 2, + propertyID: "volume", + }, + { + label: "Positional", + type: "bool", + propertyID: "positional", + }, + { + label: "Pitch", + type: "number-draggable", + min: 0.0625, + max: 16, + step: 0.1, + decimals: 2, + propertyID: "pitch", + }, + { + label: "Time Offset", + type: "number-draggable", + step: 0.1, + propertyID: "timeOffset", + }, + { + label: "Local Only", + type: "bool", + propertyID: "localOnly", + } + ] + }, { id: "spatial", label: "SPATIAL", @@ -1764,8 +2071,9 @@ const GROUPS_PER_TYPE = { None: [ 'base', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ], Shape: [ 'base', 'shape', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ], Text: [ 'base', 'text', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ], - Zone: [ 'base', 'zone', 'zone_key_light', 'zone_skybox', 'zone_ambient_light', 'zone_haze', - 'zone_bloom', 'zone_avatar_priority', 'spatial', 'behavior', 'scripts', 'physics' ], + Zone: [ 'base', 'zone', 'zone_key_light', 'zone_skybox', 'zone_ambient_light', 'zone_haze', + 'zone_bloom', 'zone_tonemapping', 'zone_ambient_occlusion', 'zone_avatar_priority', + 'zone_audio', 'spatial', 'behavior', 'scripts', 'physics' ], Model: [ 'base', 'model', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ], Image: [ 'base', 'image', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ], Web: [ 'base', 'web', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ], @@ -1773,9 +2081,11 @@ const GROUPS_PER_TYPE = { Material: [ 'base', 'material', 'spatial', 'behavior', 'scripts', 'physics' ], ParticleEffect: [ 'base', 'particles', 'particles_emit', 'particles_size', 'particles_color', 'particles_behavior', 'particles_constraints', 'spatial', 'behavior', 'scripts', 'physics' ], + ProceduralParticleEffect: [ 'base', 'particles_procedural', 'spatial', 'behavior', 'scripts', 'physics' ], PolyLine: [ 'base', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ], PolyVox: [ 'base', 'polyvox', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ], Grid: [ 'base', 'grid', 'spatial', 'behavior', 'scripts', 'physics' ], + Sound: [ 'base', 'sound', 'spatial', 'behavior', 'scripts', 'physics' ], Multiple: [ 'base', 'spatial', 'behavior', 'scripts', 'collision', 'physics' ], }; @@ -2859,10 +3169,18 @@ function createVec2Property(property, elProperty) { function updateVectorMinMax(property) { let min = property.data.min; let max = property.data.max; - property.elNumberX.updateMinMax(min, max); - property.elNumberY.updateMinMax(min, max); - if (property.elNumberZ) { - property.elNumberZ.updateMinMax(min, max); + if (property.elNumberX) { + property.elNumberX.updateMinMax(min, max); + property.elNumberY.updateMinMax(min, max); + if (property.elNumberZ) { + property.elNumberZ.updateMinMax(min, max); + } + } else if (property.elNumberR) { + property.elNumberR.updateMinMax(min, max); + property.elNumberG.updateMinMax(min, max); + if (property.elNumberB) { + property.elNumberB.updateMinMax(min, max); + } } } @@ -3767,6 +4085,327 @@ function saveJSONMaterialData(noUpdate, entityIDsToUpdate) { }, EDITOR_TIMEOUT_DURATION); } + +/** + * PROCEDURAL PARTICLE DATA FUNCTIONS + */ + +function clearParticleUpdateData() { + let elParticleUpdateData = getPropertyInputElement("particleUpdateData"); + deleteJSONParticleUpdateEditor(); + elParticleUpdateData.value = ""; + showParticleUpdateDataTextArea(); + showNewJSONParticleUpdateEditorButton(); + hideSaveParticleUpdateDataButton(); + updateProperty('particleUpdateData', elParticleUpdateData.value, false); +} + +function newJSONParticleUpdateEditor() { + getPropertyInputElement("particleUpdateData").classList.remove('multi-diff'); + deleteJSONParticleUpdateEditor(); + createJSONParticleUpdateEditor(); + let data = {}; + setParticleUpdateEditorJSON(data); + hideParticleUpdateDataTextArea(); + hideNewJSONParticleUpdateEditorButton(); + showSaveParticleUpdateDataButton(); +} + +/** + * @param {Set.} [entityIDsToUpdate] Entity IDs to update particleUpdateData for. + */ +function saveParticleUpdateData(entityIDsToUpdate) { + saveJSONParticleUpdateData(true, entityIDsToUpdate); +} + +function setJSONError(property, isError) { + $("#property-"+ property + "-editor").toggleClass('error', isError); + let $propertyParticleUpdateDataEditorStatus = $("#property-"+ property + "-editorStatus"); + $propertyParticleUpdateDataEditorStatus.css('display', isError ? 'block' : 'none'); + $propertyParticleUpdateDataEditorStatus.text(isError ? 'Invalid JSON code - look for red X in your code' : ''); +} + +/** + * @param {boolean} noUpdate - don't update the UI, but do send a property update. + * @param {Set.} [entityIDsToUpdate] - Entity IDs to update particleUpdateData for. + */ +function setParticleUpdateDataFromEditor(noUpdate, entityIDsToUpdate) { + let errorFound = false; + try { + particleUpdateEditor.get(); + } catch (e) { + errorFound = true; + } + + setJSONError('particleUpdateData', errorFound); + + if (errorFound) { + return; + } + + let text = particleUpdateEditor.getText(); + if (noUpdate) { + EventBridge.emitWebEvent( + JSON.stringify({ + ids: [...entityIDsToUpdate], + type: "saveParticleUpdateData", + properties: { + particleUpdateData: text + } + }) + ); + } else { + updateProperty('particleUpdateData', text, false); + } +} + +let particleUpdateEditor = null; + +function createJSONParticleUpdateEditor() { + let container = document.getElementById("property-particleUpdateData-editor"); + let options = { + search: false, + mode: 'tree', + modes: ['code', 'tree'], + name: 'particleUpdateData', + onError: function(e) { + alert('JSON editor:' + e); + }, + onChange: function() { + let currentJSONString = particleUpdateEditor.getText(); + + if (currentJSONString === '{"":""}') { + return; + } + $('#property-particleUpdateData-button-save').attr('disabled', false); + } + }; + particleUpdateEditor = new JSONEditor(container, options); +} + +function showSaveParticleUpdateDataButton() { + $('#property-particleUpdateData-button-save').show(); +} + +function hideSaveParticleUpdateDataButton() { + $('#property-particleUpdateData-button-save').hide(); +} + +function disableSaveParticleUpdateDataButton() { + $('#property-particleUpdateData-button-save').attr('disabled', true); +} + +function showNewJSONParticleUpdateEditorButton() { + $('#property-particleUpdateData-button-edit').show(); +} + +function hideNewJSONParticleUpdateEditorButton() { + $('#property-particleUpdateData-button-edit').hide(); +} + +function showParticleUpdateDataTextArea() { + $('#property-particleUpdateData').show(); +} + +function hideParticleUpdateDataTextArea() { + $('#property-particleUpdateData').hide(); +} + +function hideParticleUpdateDataSaved() { + $('#property-particleUpdateData-saved').hide(); +} + +function setParticleUpdateEditorJSON(json) { + particleUpdateEditor.set(json); + if (particleUpdateEditor.hasOwnProperty('expandAll')) { + particleUpdateEditor.expandAll(); + } +} + +function deleteJSONParticleUpdateEditor() { + if (particleUpdateEditor !== null) { + setJSONError('particleUpdateData', false); + particleUpdateEditor.destroy(); + particleUpdateEditor = null; + } +} + +let savedParticleUpdateJSONTimer = null; + +/** + * @param {boolean} noUpdate - don't update the UI, but do send a property update. + * @param {Set.} [entityIDsToUpdate] Entity IDs to update particleUpdateData for + */ +function saveJSONParticleUpdateData(noUpdate, entityIDsToUpdate) { + setParticleUpdateDataFromEditor(noUpdate, entityIDsToUpdate ? entityIDsToUpdate : selectedEntityIDs); + $('#property-particleUpdateData-saved').show(); + $('#property-particleUpdateData-button-save').attr('disabled', true); + if (savedJSONTimer !== null) { + clearTimeout(savedJSONTimer); + } + savedJSONTimer = setTimeout(function() { + hideParticleUpdateDataSaved(); + }, EDITOR_TIMEOUT_DURATION); +} + +function clearParticleRenderData() { + let elParticleRenderData = getPropertyInputElement("particleRenderData"); + deleteJSONParticleRenderEditor(); + elParticleRenderData.value = ""; + showParticleRenderDataTextArea(); + showNewJSONParticleRenderEditorButton(); + hideSaveParticleRenderDataButton(); + updateProperty('particleRenderData', elParticleRenderData.value, false); +} + +function newJSONParticleRenderEditor() { + getPropertyInputElement("particleRenderData").classList.remove('multi-diff'); + deleteJSONParticleRenderEditor(); + createJSONParticleRenderEditor(); + let data = {}; + setParticleRenderEditorJSON(data); + hideParticleRenderDataTextArea(); + hideNewJSONParticleRenderEditorButton(); + showSaveParticleRenderDataButton(); +} + +/** + * @param {Set.} [entityIDsToUpdate] Entity IDs to update particleRenderData for. + */ +function saveParticleRenderData(entityIDsToUpdate) { + saveJSONParticleRenderData(true, entityIDsToUpdate); +} + +function setJSONError(property, isError) { + $("#property-"+ property + "-editor").toggleClass('error', isError); + let $propertyParticleRenderDataEditorStatus = $("#property-"+ property + "-editorStatus"); + $propertyParticleRenderDataEditorStatus.css('display', isError ? 'block' : 'none'); + $propertyParticleRenderDataEditorStatus.text(isError ? 'Invalid JSON code - look for red X in your code' : ''); +} + +/** + * @param {boolean} noUpdate - don't update the UI, but do send a property update. + * @param {Set.} [entityIDsToUpdate] - Entity IDs to update particleRenderData for. + */ +function setParticleRenderDataFromEditor(noUpdate, entityIDsToUpdate) { + let errorFound = false; + try { + particleRenderEditor.get(); + } catch (e) { + errorFound = true; + } + + setJSONError('particleRenderData', errorFound); + + if (errorFound) { + return; + } + + let text = particleRenderEditor.getText(); + if (noUpdate) { + EventBridge.emitWebEvent( + JSON.stringify({ + ids: [...entityIDsToUpdate], + type: "saveParticleRenderData", + properties: { + particleRenderData: text + } + }) + ); + } else { + updateProperty('particleRenderData', text, false); + } +} + +let particleRenderEditor = null; + +function createJSONParticleRenderEditor() { + let container = document.getElementById("property-particleRenderData-editor"); + let options = { + search: false, + mode: 'tree', + modes: ['code', 'tree'], + name: 'particleRenderData', + onError: function(e) { + alert('JSON editor:' + e); + }, + onChange: function() { + let currentJSONString = particleRenderEditor.getText(); + + if (currentJSONString === '{"":""}') { + return; + } + $('#property-particleRenderData-button-save').attr('disabled', false); + } + }; + particleRenderEditor = new JSONEditor(container, options); +} + +function showSaveParticleRenderDataButton() { + $('#property-particleRenderData-button-save').show(); +} + +function hideSaveParticleRenderDataButton() { + $('#property-particleRenderData-button-save').hide(); +} + +function disableSaveParticleRenderDataButton() { + $('#property-particleRenderData-button-save').attr('disabled', true); +} + +function showNewJSONParticleRenderEditorButton() { + $('#property-particleRenderData-button-edit').show(); +} + +function hideNewJSONParticleRenderEditorButton() { + $('#property-particleRenderData-button-edit').hide(); +} + +function showParticleRenderDataTextArea() { + $('#property-particleRenderData').show(); +} + +function hideParticleRenderDataTextArea() { + $('#property-particleRenderData').hide(); +} + +function hideParticleRenderDataSaved() { + $('#property-particleRenderData-saved').hide(); +} + +function setParticleRenderEditorJSON(json) { + particleRenderEditor.set(json); + if (particleRenderEditor.hasOwnProperty('expandAll')) { + particleRenderEditor.expandAll(); + } +} + +function deleteJSONParticleRenderEditor() { + if (particleRenderEditor !== null) { + setJSONError('particleRenderData', false); + particleRenderEditor.destroy(); + particleRenderEditor = null; + } +} + +let savedParticleRenderJSONTimer = null; + +/** + * @param {boolean} noUpdate - don't update the UI, but do send a property update. + * @param {Set.} [entityIDsToUpdate] Entity IDs to update particleRenderData for + */ +function saveJSONParticleRenderData(noUpdate, entityIDsToUpdate) { + setParticleRenderDataFromEditor(noUpdate, entityIDsToUpdate ? entityIDsToUpdate : selectedEntityIDs); + $('#property-particleRenderData-saved').show(); + $('#property-particleRenderData-button-save').attr('disabled', true); + if (savedJSONTimer !== null) { + clearTimeout(savedJSONTimer); + } + savedJSONTimer = setTimeout(function() { + hideParticleRenderDataSaved(); + }, EDITOR_TIMEOUT_DURATION); +} + function bindAllNonJSONEditorElements() { let inputs = $('input'); let i; @@ -3777,7 +4416,9 @@ function bindAllNonJSONEditorElements() { // an outer scoped variable may lead to confusing semantics. field.on('focus', function(e) { if (e.target.id === "property-userData-button-edit" || e.target.id === "property-userData-button-clear" || - e.target.id === "property-materialData-button-edit" || e.target.id === "property-materialData-button-clear") { + e.target.id === "property-materialData-button-edit" || e.target.id === "property-materialData-button-clear" || + e.target.id === "property-particleUpdateData-button-edit" || e.target.id === "property-particleUpdateData-button-clear" || + e.target.id === "property-particleRenderData-button-edit" || e.target.id === "property-particleRenderData-button-clear") { return; } if ($('#property-userData-editor').css('height') !== "0px") { @@ -3786,6 +4427,12 @@ function bindAllNonJSONEditorElements() { if ($('#property-materialData-editor').css('height') !== "0px") { saveMaterialData(); } + if ($('#property-particleUpdateData-editor').css('height') !== "0px") { + saveParticleUpdateData(); + } + if ($('#property-particleRenderData-editor').css('height') !== "0px") { + saveParticleRenderData(); + } }); } } @@ -3893,6 +4540,7 @@ function addZoneToZonesSelection(propertyId, id) { hiddenField.value = JSON.stringify(selectedZones); displaySelectedZones(propertyId, true); let propertyName = propertyId.replace("property-", ""); + propertyName = propertyName.replace("-", "."); updateProperty(propertyName, selectedZones, false); document.getElementById("zones-select-selector-list-panel-" + propertyId).style.display = "none"; } @@ -3910,6 +4558,7 @@ function removeZoneFromZonesSelection(propertyId, zoneId) { hiddenField.value = JSON.stringify(selectedZones); displaySelectedZones(propertyId, true); let propertyName = propertyId.replace("property-", ""); + propertyName = propertyName.replace("-", "."); updateProperty(propertyName, selectedZones, false); } @@ -4201,6 +4850,8 @@ function handleEntitySelectionUpdate(selections, isPropertiesToolUpdate) { if (selections.length === 0) { deleteJSONEditor(); deleteJSONMaterialEditor(); + deleteJSONParticleUpdateEditor(); + deleteJSONParticleRenderEditor(); resetProperties(); showGroupsForType("None"); @@ -4219,6 +4870,16 @@ function handleEntitySelectionUpdate(selections, isPropertiesToolUpdate) { showSaveMaterialDataButton(); showNewJSONMaterialEditorButton(); + getPropertyInputElement("particleUpdateData").value = ""; + showParticleUpdateDataTextArea(); + showSaveParticleUpdateDataButton(); + showNewJSONParticleUpdateEditorButton(); + + getPropertyInputElement("particleRenderData").value = ""; + showParticleRenderDataTextArea(); + showSaveParticleRenderDataButton(); + showNewJSONParticleRenderEditorButton(); + setCopyPastePositionAndRotationAvailability (selections.length, true); disableProperties(); @@ -4258,6 +4919,8 @@ function handleEntitySelectionUpdate(selections, isPropertiesToolUpdate) { enableProperties(); disableSaveUserDataButton(); disableSaveMaterialDataButton(); + disableSaveParticleUpdateDataButton(); + disableSaveParticleRenderDataButton(); setCopyPastePositionAndRotationAvailability (selections.length, false); } @@ -4548,6 +5211,70 @@ function handleEntitySelectionUpdate(selections, isPropertiesToolUpdate) { requestMaterialTarget(); } + let particleUpdateDataMultiValue = getMultiplePropertyValue("particleUpdateData"); + let particleUpdateDataTextArea = getPropertyInputElement("particleUpdateData"); + let particleUpdateJSON = null; + if (!particleUpdateDataMultiValue.isMultiDiffValue) { + try { + particleUpdateJSON = JSON.parse(particleUpdateDataMultiValue.value); + } catch (e) { + + } + } + if (particleUpdateJSON !== null && !lockedMultiValue.isMultiDiffValue && !lockedMultiValue.value) { + if (particleUpdateEditor === null) { + createJSONParticleUpdateEditor(); + } + particleUpdateDataTextArea.classList.remove('multi-diff'); + setParticleUpdateEditorJSON(particleUpdateJSON); + showSaveParticleUpdateDataButton(); + hideParticleUpdateDataTextArea(); + hideNewJSONParticleUpdateEditorButton(); + hideParticleUpdateDataSaved(); + } else { + // normal text + deleteJSONParticleUpdateEditor(); + particleUpdateDataTextArea.classList.toggle('multi-diff', particleUpdateDataMultiValue.isMultiDiffValue); + particleUpdateDataTextArea.value = particleUpdateDataMultiValue.isMultiDiffValue ? "" : particleUpdateDataMultiValue.value; + + showParticleUpdateDataTextArea(); + showNewJSONParticleUpdateEditorButton(); + hideSaveParticleUpdateDataButton(); + hideParticleUpdateDataSaved(); + } + + let particleRenderDataMultiValue = getMultiplePropertyValue("particleRenderData"); + let particleRenderDataTextArea = getPropertyInputElement("particleRenderData"); + let particleRenderJSON = null; + if (!particleRenderDataMultiValue.isMultiDiffValue) { + try { + particleRenderJSON = JSON.parse(particleRenderDataMultiValue.value); + } catch (e) { + + } + } + if (particleRenderJSON !== null && !lockedMultiValue.isMultiDiffValue && !lockedMultiValue.value) { + if (particleRenderEditor === null) { + createJSONParticleRenderEditor(); + } + particleRenderDataTextArea.classList.remove('multi-diff'); + setParticleRenderEditorJSON(particleRenderJSON); + showSaveParticleRenderDataButton(); + hideParticleRenderDataTextArea(); + hideNewJSONParticleRenderEditorButton(); + hideParticleRenderDataSaved(); + } else { + // normal text + deleteJSONParticleRenderEditor(); + particleRenderDataTextArea.classList.toggle('multi-diff', particleRenderDataMultiValue.isMultiDiffValue); + particleRenderDataTextArea.value = particleRenderDataMultiValue.isMultiDiffValue ? "" : particleRenderDataMultiValue.value; + + showParticleRenderDataTextArea(); + showNewJSONParticleRenderEditorButton(); + hideSaveParticleRenderDataButton(); + hideParticleRenderDataSaved(); + } + let activeElement = document.activeElement; if (doSelectElement && typeof activeElement.select !== "undefined") { activeElement.select(); @@ -4855,6 +5582,37 @@ function loaded() { elDiv.insertBefore(elMaterialDataEditor, elMaterialData); elDiv.insertBefore(elMaterialDataEditorStatus, elMaterialData); + // Particle Update + Render Data + let particleUpdateDataProperty = properties["particleUpdateData"]; + let elParticleUpdateData = particleUpdateDataProperty.elInput; + let particleUpdateDataElementID = particleUpdateDataProperty.elementID; + elDiv = elParticleUpdateData.parentNode; + let elParticleUpdateDataEditor = document.createElement('div'); + elParticleUpdateDataEditor.setAttribute("id", particleUpdateDataElementID + "-editor"); + let elParticleUpdateDataEditorStatus = document.createElement('div'); + elParticleUpdateDataEditorStatus.setAttribute("id", particleUpdateDataElementID + "-editorStatus"); + let elParticleUpdateDataSaved = document.createElement('span'); + elParticleUpdateDataSaved.setAttribute("id", particleUpdateDataElementID + "-saved"); + elParticleUpdateDataSaved.innerText = "Saved!"; + elDiv.childNodes[JSON_EDITOR_ROW_DIV_INDEX].appendChild(elParticleUpdateDataSaved); + elDiv.insertBefore(elParticleUpdateDataEditor, elParticleUpdateData); + elDiv.insertBefore(elParticleUpdateDataEditorStatus, elParticleUpdateData); + + let particleRenderDataProperty = properties["particleRenderData"]; + let elParticleRenderData = particleRenderDataProperty.elInput; + let particleRenderDataElementID = particleRenderDataProperty.elementID; + elDiv = elParticleRenderData.parentNode; + let elParticleRenderDataEditor = document.createElement('div'); + elParticleRenderDataEditor.setAttribute("id", particleRenderDataElementID + "-editor"); + let elParticleRenderDataEditorStatus = document.createElement('div'); + elParticleRenderDataEditorStatus.setAttribute("id", particleRenderDataElementID + "-editorStatus"); + let elParticleRenderDataSaved = document.createElement('span'); + elParticleRenderDataSaved.setAttribute("id", particleRenderDataElementID + "-saved"); + elParticleRenderDataSaved.innerText = "Saved!"; + elDiv.childNodes[JSON_EDITOR_ROW_DIV_INDEX].appendChild(elParticleRenderDataSaved); + elDiv.insertBefore(elParticleRenderDataEditor, elParticleRenderData); + elDiv.insertBefore(elParticleRenderDataEditorStatus, elParticleRenderData); + // Textarea scrollbars let elTextareas = document.getElementsByTagName("TEXTAREA"); @@ -4968,7 +5726,8 @@ function loaded() { return; } - if (elUserDataEditor.contains(keyUpEvent.target) || elMaterialDataEditor.contains(keyUpEvent.target)) { + if (elUserDataEditor.contains(keyUpEvent.target) || elMaterialDataEditor.contains(keyUpEvent.target) || elParticleUpdateDataEditor.contains(keyUpEvent.target) + || elParticleRenderDataEditor.contains(keyUpEvent.target)) { return; } diff --git a/scripts/system/create/entityProperties/html/tabs/particles_procedural.png b/scripts/system/create/entityProperties/html/tabs/particles_procedural.png new file mode 100644 index 00000000000..6a0d47cacb7 Binary files /dev/null and b/scripts/system/create/entityProperties/html/tabs/particles_procedural.png differ diff --git a/scripts/system/create/entityProperties/html/tabs/sound.png b/scripts/system/create/entityProperties/html/tabs/sound.png new file mode 100644 index 00000000000..218bfe7c4ff Binary files /dev/null and b/scripts/system/create/entityProperties/html/tabs/sound.png differ diff --git a/scripts/system/create/entityProperties/html/tabs/zone_ambient_occlusion.png b/scripts/system/create/entityProperties/html/tabs/zone_ambient_occlusion.png new file mode 100644 index 00000000000..ace90dbcbc8 Binary files /dev/null and b/scripts/system/create/entityProperties/html/tabs/zone_ambient_occlusion.png differ diff --git a/scripts/system/create/entityProperties/html/tabs/zone_audio.png b/scripts/system/create/entityProperties/html/tabs/zone_audio.png new file mode 100644 index 00000000000..6e7adf8fa50 Binary files /dev/null and b/scripts/system/create/entityProperties/html/tabs/zone_audio.png differ diff --git a/scripts/system/create/entityProperties/html/tabs/zone_tonemapping.png b/scripts/system/create/entityProperties/html/tabs/zone_tonemapping.png new file mode 100644 index 00000000000..06f93f57e46 Binary files /dev/null and b/scripts/system/create/entityProperties/html/tabs/zone_tonemapping.png differ diff --git a/scripts/system/create/entitySelectionTool/entitySelectionTool.js b/scripts/system/create/entitySelectionTool/entitySelectionTool.js index b3559b3a671..574f91eba75 100644 --- a/scripts/system/create/entitySelectionTool/entitySelectionTool.js +++ b/scripts/system/create/entitySelectionTool/entitySelectionTool.js @@ -2255,7 +2255,7 @@ SelectionDisplay = (function() { Entities.editEntity(selectionBox, selectionBoxGeometry); // UPDATE ICON TRANSLATE HANDLE - if (SelectionManager.entityType === "ParticleEffect" || SelectionManager.entityType === "Light") { + if (SelectionManager.entityType === "ParticleEffect" || SelectionManager.entityType === "ProceduralParticleEffect" || SelectionManager.entityType === "Light" || SelectionManager.entityType === "Sound") { var iconSelectionBoxGeometry = { position: position, rotation: rotation diff --git a/scripts/system/create/modules/brokenURLReport.js b/scripts/system/create/modules/brokenURLReport.js index c04612bb272..42248260233 100644 --- a/scripts/system/create/modules/brokenURLReport.js +++ b/scripts/system/create/modules/brokenURLReport.js @@ -352,6 +352,17 @@ function brokenURLReport(entityIDs) { }; brokenURLReportUrlList.push(brokenURLReportUrlEntry); } + if (properties.type === "Sound" && properties.soundURL.toLowerCase().startsWith("http")) { + brokenURLReportUrlEntry = { + id: entityIDs[i], + name: properties.name, + type: properties.type, + urlType: "soundURL", + url: soundURL, + validity: "NOT_TESTED" + }; + brokenURLReportUrlList.push(brokenURLReportUrlEntry); + } } if (brokenURLReportUrlList.length === 0) { audioFeedback.confirmation(); diff --git a/scripts/system/create/qml/EditTabView.qml b/scripts/system/create/qml/EditTabView.qml index 2db23ec659d..aa123894407 100644 --- a/scripts/system/create/qml/EditTabView.qml +++ b/scripts/system/create/qml/EditTabView.qml @@ -190,6 +190,18 @@ TabBar { editTabView.currentIndex = 2 } } + + NewEntityButton { + icon: "icons/sound.svg" + text: "SOUND" + onClicked: { + editRoot.sendToScript({ + method: "newEntityButtonClicked", + params: { buttonName: "newSoundButton" } + }); + editTabView.currentIndex = 2 + } + } } HifiControls.Button { diff --git a/scripts/system/create/qml/EditToolsTabView.qml b/scripts/system/create/qml/EditToolsTabView.qml index 1000724458a..87ae6f96822 100644 --- a/scripts/system/create/qml/EditToolsTabView.qml +++ b/scripts/system/create/qml/EditToolsTabView.qml @@ -196,6 +196,18 @@ TabBar { editTabView.currentIndex = tabIndex.properties } } + + NewEntityButton { + icon: "icons/sound.svg" + text: "SOUND" + onClicked: { + editRoot.sendToScript({ + method: "newEntityButtonClicked", + params: { buttonName: "newSoundButton" } + }); + editTabView.currentIndex = tabIndex.properties + } + } } HifiControls.Button { diff --git a/scripts/system/create/qml/NewMaterialDialog.qml b/scripts/system/create/qml/NewMaterialDialog.qml index 4378077ee1e..423afe4b186 100644 --- a/scripts/system/create/qml/NewMaterialDialog.qml +++ b/scripts/system/create/qml/NewMaterialDialog.qml @@ -28,7 +28,6 @@ Rectangle { signal sendToScript(var message); property bool keyboardEnabled: false property bool punctuationMode: false - property bool keyboardRasied: false function errorMessageBox(message) { try { diff --git a/scripts/system/create/qml/NewModelDialog.qml b/scripts/system/create/qml/NewModelDialog.qml index 07c46280afb..ad70f470853 100644 --- a/scripts/system/create/qml/NewModelDialog.qml +++ b/scripts/system/create/qml/NewModelDialog.qml @@ -28,7 +28,6 @@ Rectangle { property bool keyboardEnabled: false property bool keyboardRaised: false property bool punctuationMode: false - property bool keyboardRasied: false function errorMessageBox(message) { try { diff --git a/scripts/system/create/qml/NewParticleDialog.qml b/scripts/system/create/qml/NewParticleDialog.qml new file mode 100644 index 00000000000..c07843f30ad --- /dev/null +++ b/scripts/system/create/qml/NewParticleDialog.qml @@ -0,0 +1,108 @@ +// +// NewParticleDialog.qml +// qml/hifi +// +// Created by HifiExperiments on 11/22/23 +// Copyright 2023 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import QtQuick.Dialogs 1.2 as OriginalDialogs + +import stylesUit 1.0 +import controlsUit 1.0 +import hifi.dialogs 1.0 + +Rectangle { + id: newParticleDialog + // width: parent.width + // height: parent.height + HifiConstants { id: hifi } + color: hifi.colors.baseGray; + signal sendToScript(var message); + property bool keyboardEnabled: false + property bool keyboardRaised: false + property bool punctuationMode: false + + function errorMessageBox(message) { + try { + return desktop.messageBox({ + icon: hifi.icons.warning, + defaultButton: OriginalDialogs.StandardButton.Ok, + title: "Error", + text: message + }); + } catch(e) { + Window.alert(message); + } + } + + Item { + id: column1 + anchors.rightMargin: 10 + anchors.leftMargin: 10 + anchors.bottomMargin: 10 + anchors.topMargin: 10 + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: keyboard.top + + Column { + id: column2 + height: 400 + spacing: 10 + + CheckBox { + id: procedural + text: qsTr("Procedural (GPU) Particles?") + checked: false + } + + Row { + id: row1 + width: 200 + height: 400 + spacing: 5 + + Button { + id: button1 + text: qsTr("Create") + z: -1 + onClicked: { + newParticleDialog.sendToScript({ + method: "newParticleDialogAdd", + params: { + procedural: procedural.checked + } + }); + } + } + + Button { + id: button2 + z: -1 + text: qsTr("Cancel") + onClicked: { + newParticleDialog.sendToScript({method: "newParticleDialogCancel"}) + } + } + } + } + } + + Keyboard { + id: keyboard + raised: parent.keyboardEnabled && parent.keyboardRaised + numeric: parent.punctuationMode + anchors { + bottom: parent.bottom + bottomMargin: 40 + left: parent.left + right: parent.right + } + } +} diff --git a/scripts/system/create/qml/NewParticleWindow.qml b/scripts/system/create/qml/NewParticleWindow.qml new file mode 100644 index 00000000000..2b195008071 --- /dev/null +++ b/scripts/system/create/qml/NewParticleWindow.qml @@ -0,0 +1,20 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.2 + +StackView { + id: stackView + anchors.fill: parent + anchors.leftMargin: 10 + anchors.rightMargin: 10 + anchors.topMargin: 40 + + signal sendToScript(var message); + + NewParticleDialog { + id: dialog + anchors.fill: parent + Component.onCompleted:{ + dialog.sendToScript.connect(stackView.sendToScript); + } + } +} diff --git a/scripts/system/create/qml/NewPolyVoxDialog.qml b/scripts/system/create/qml/NewPolyVoxDialog.qml index 67c0a76bf77..97e3f9d3417 100644 --- a/scripts/system/create/qml/NewPolyVoxDialog.qml +++ b/scripts/system/create/qml/NewPolyVoxDialog.qml @@ -29,7 +29,6 @@ Rectangle { property bool keyboardEnabled: false property bool keyboardRaised: false property bool punctuationMode: false - property bool keyboardRasied: false function errorMessageBox(message) { try { diff --git a/scripts/system/create/qml/NewSoundDialog.qml b/scripts/system/create/qml/NewSoundDialog.qml new file mode 100644 index 00000000000..870e8bb41df --- /dev/null +++ b/scripts/system/create/qml/NewSoundDialog.qml @@ -0,0 +1,158 @@ +// +// NewSoundDialog.qml +// qml/hifi +// +// Created by HifiExperiments on 4/7/24 +// Copyright 2024 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.7 +import QtQuick.Controls 2.2 +import QtQuick.Dialogs 1.2 as OriginalDialogs + +import stylesUit 1.0 +import controlsUit 1.0 +import hifi.dialogs 1.0 + +Rectangle { + id: newSoundDialog + // width: parent.width + // height: parent.height + HifiConstants { id: hifi } + color: hifi.colors.baseGray; + signal sendToScript(var message); + property bool keyboardEnabled: false + property bool punctuationMode: false + + function errorMessageBox(message) { + try { + return desktop.messageBox({ + icon: hifi.icons.warning, + defaultButton: OriginalDialogs.StandardButton.Ok, + title: "Error", + text: message + }); + } catch(e) { + Window.alert(message); + } + } + + Item { + id: column1 + anchors.rightMargin: 10 + anchors.leftMargin: 10 + anchors.bottomMargin: 10 + anchors.topMargin: 10 + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: keyboard.top + + Text { + id: text1 + text: qsTr("Sound URL") + color: "#ffffff" + font.pixelSize: 12 + } + + TextInput { + id: soundURL + height: 20 + text: qsTr("") + color: "white" + anchors.top: text1.bottom + anchors.topMargin: 5 + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.right: parent.right + anchors.rightMargin: 0 + font.pixelSize: 12 + + onAccepted: { + newSoundDialog.keyboardEnabled = false; + } + + MouseArea { + anchors.fill: parent + onClicked: { + newSoundDialog.keyboardEnabled = HMD.active + parent.focus = true; + parent.forceActiveFocus(); + soundURL.cursorPosition = soundURL.positionAt(mouseX, mouseY, TextInput.CursorBetweenCharaters); + } + } + } + + Rectangle { + id: textInputBox + color: "white" + anchors.fill: soundURL + opacity: 0.1 + } + + Row { + id: row1 + height: 400 + spacing: 30 + anchors.top: soundURL.bottom + anchors.topMargin: 5 + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.right: parent.right + anchors.rightMargin: 0 + + Column { + id: column3 + height: 400 + spacing: 10 + + Row { + id: row3 + width: 200 + height: 400 + spacing: 5 + + anchors.horizontalCenter: column3.horizontalCenter + anchors.horizontalCenterOffset: 0 + + Button { + id: button1 + text: qsTr("Create") + z: -1 + onClicked: { + newSoundDialog.sendToScript({ + method: "newSoundDialogAdd", + params: { + textInput: soundURL.text + } + }); + } + } + + Button { + id: button2 + z: -1 + text: qsTr("Cancel") + onClicked: { + newSoundDialog.sendToScript({method: "newSoundDialogCancel"}) + } + } + } + } + } + } + + Keyboard { + id: keyboard + raised: parent.keyboardEnabled + numeric: parent.punctuationMode + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + } + } +} diff --git a/scripts/system/create/qml/NewSoundWindow.qml b/scripts/system/create/qml/NewSoundWindow.qml new file mode 100644 index 00000000000..9f78ade0b11 --- /dev/null +++ b/scripts/system/create/qml/NewSoundWindow.qml @@ -0,0 +1,31 @@ +// +// NewSoundWindow.qml +// qml/hifi +// +// Created by HifiExperiments on 4/7/24 +// Copyright 2024 Overte e.V. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.7 +import QtQuick.Controls 2.2 + +StackView { + id: stackView + anchors.fill: parent + anchors.leftMargin: 10 + anchors.rightMargin: 10 + anchors.topMargin: 40 + + signal sendToScript(var message); + + NewSoundDialog { + id: dialog + anchors.fill: parent + Component.onCompleted:{ + dialog.sendToScript.connect(stackView.sendToScript); + } + } +} diff --git a/scripts/system/create/qml/icons/sound.svg b/scripts/system/create/qml/icons/sound.svg new file mode 100644 index 00000000000..448156343dd --- /dev/null +++ b/scripts/system/create/qml/icons/sound.svg @@ -0,0 +1,59 @@ + + + + + + + diff --git a/scripts/system/html/css/edit-style.css b/scripts/system/html/css/edit-style.css index 356f75d556b..3ec78eb6cc5 100644 --- a/scripts/system/html/css/edit-style.css +++ b/scripts/system/html/css/edit-style.css @@ -1771,7 +1771,9 @@ input#property-scale-button-reset { } #property-userData-static, -#property-materialData-static { +#property-materialData-static, +#property-particleUpdateData-static, +#property-particleRenderData-static { display: none; z-index: 99; position: absolute; @@ -1783,7 +1785,9 @@ input#property-scale-button-reset { } #property-userData-saved, -#property-materialData-saved { +#property-materialData-saved, +#property-particleUpdateData-saved +#property-particleRenderData-saved { margin-top: 5px; font-size: 16px; display: none; @@ -1990,23 +1994,17 @@ input.number-slider { cursor: pointer; } -#property-userData-editor.error { +#property-userData-editor.error, +#property-materialData-editor.error, +#property-particleUpdateData-editor.error, +#property-particleRenderData-editor.error { border: 2px solid red; } -#property-userData-editorStatus { - color: white; - background-color: red; - padding: 5px; - display: none; - cursor: pointer; -} - -#property-materialData-editor.error { - border: 2px solid red; -} - -#property-materialData-editorStatus { +#property-userData-editorStatus, +#property-materialData-editorStatus, +#property-particleUpdateData-editorStatus, +#property-particleRenderData-editorStatus { color: white; background-color: red; padding: 5px; diff --git a/scripts/system/html/js/includes.js b/scripts/system/html/js/includes.js index c604115f913..e3131628311 100644 --- a/scripts/system/html/js/includes.js +++ b/scripts/system/html/js/includes.js @@ -16,10 +16,12 @@ const ENTITY_TYPE_ICON = { Material: "", Model: "", ParticleEffect: "", + ProceduralParticleEffect: "", PolyVox: "", PolyLine: "", Shape: "n", Sphere: "n", + Sound: "G", Text: "l", Web: "q", Zone: "o", diff --git a/tools/gpu-frame-player/src/RenderThread.cpp b/tools/gpu-frame-player/src/RenderThread.cpp index 0089c1577bb..de39dacdea3 100644 --- a/tools/gpu-frame-player/src/RenderThread.cpp +++ b/tools/gpu-frame-player/src/RenderThread.cpp @@ -122,7 +122,7 @@ void RenderThread::renderFrame(gpu::FramePointer& frame) { if (_correction != glm::mat4()) { std::unique_lock lock(_frameLock); if (_correction != glm::mat4()) { - _backend->setCameraCorrection(_correction, _activeFrame->view); + _backend->setCameraCorrection(_correction, _activeFrame->view, true); //_prevRenderView = _correction * _activeFrame->view; } }