Merge pull request #1096 from overte-org/protocol_changes

Protocol changes -> master
This commit is contained in:
ksuprynowicz 2024-10-21 11:41:50 +02:00 committed by GitHub
commit ce8d57b4be
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
348 changed files with 15305 additions and 17221 deletions

View file

@ -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()

View file

@ -31,6 +31,7 @@
#include <StDev.h>
#include <UUID.h>
#include <CPUDetect.h>
#include <ZoneEntityItem.h>
#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<QString, shared_ptr<CodecPlugin>> AudioMixer::_availableCodecs{ };
QStringList AudioMixer::_codecPreferenceOrder{};
vector<AudioMixer::ZoneDescription> AudioMixer::_audioZones;
vector<AudioMixer::ZoneSettings> AudioMixer::_zoneSettings;
vector<AudioMixer::ReverbSettings> AudioMixer::_zoneReverbSettings;
unordered_map<QString, AudioMixer::ZoneSettings> AudioMixer::_audioZones;
AudioMixer::AudioMixer(ReceivedMessage& message) :
ThreadedAssignment(message)
{
DependencyManager::registerInheritance<EntityDynamicFactoryInterface, AssignmentDynamicFactory>();
DependencyManager::set<AssignmentDynamicFactory>();
// Always clear settings first
// This prevents previous assignment settings from sticking around
clearDomainSettings();
@ -112,6 +116,8 @@ AudioMixer::AudioMixer(ReceivedMessage& message) :
PacketReceiver::makeSourcedListenerReference<AudioMixer>(this, &AudioMixer::handleNodeMuteRequestPacket));
packetReceiver.registerListener(PacketType::KillAvatar,
PacketReceiver::makeSourcedListenerReference<AudioMixer>(this, &AudioMixer::handleKillAvatarPacket));
packetReceiver.registerListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase },
PacketReceiver::makeSourcedListenerReference<AudioMixer>(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<SpatialParentFinder, AssignmentParentFinder>();
DependencyManager::set<AssignmentParentFinder>(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<ReceivedMessage> 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<NLPacket> for it
auto buffer = std::unique_ptr<char[]>(new char[piggyBackedSizeWithHeader]);
memcpy(buffer.get(), message->getRawMessage() + message->getPosition(), piggyBackedSizeWithHeader);
auto newPacket = NLPacket::fromReceivedPacket(std::move(buffer), piggyBackedSizeWithHeader, message->getSenderSockAddr());
auto newMessage = QSharedPointer<ReceivedMessage>::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<QString, AudioMixer::ZoneSettings>& 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();
}

View file

@ -14,7 +14,7 @@
#include <QtCore/QSharedPointer>
#include <AABox.h>
#include <Transform.h>
#include <AudioHRTF.h>
#include <AudioRingBuffer.h>
#include <ThreadedAssignment.h>
@ -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<QString> listeners;
std::vector<float> coefficients;
};
static int getStaticJitterFrames() { return _numStaticJitterFrames; }
static bool shouldMute(float quietestFrame) { return quietestFrame > _noiseMutingThreshold; }
static float getAttenuationPerDoublingInDistance() { return _attenuationPerDoublingInDistance; }
static const std::vector<ZoneDescription>& getAudioZones() { return _audioZones; }
static const std::vector<ZoneSettings>& getZoneSettings() { return _zoneSettings; }
static const std::vector<ReverbSettings>& getReverbSettings() { return _zoneReverbSettings; }
static const std::unordered_map<QString, ZoneSettings>& getAudioZones() { return _audioZones; }
static const std::pair<QString, CodecPluginPointer> negotiateCodec(std::vector<QString> 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<ReceivedMessage> packet, SharedNodePointer sendingNode);
void handleNodeMuteRequestPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode);
void handleNodeKilled(SharedNodePointer killedNode);
void handleKillAvatarPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode);
void handleOctreePacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
void queueAudioPacket(QSharedPointer<ReceivedMessage> packet, SharedNodePointer sendingNode);
void queueReplicatedAudioPacket(QSharedPointer<ReceivedMessage> packet);
@ -146,14 +147,17 @@ private:
static std::map<QString, CodecPluginPointer> _availableCodecs;
static QStringList _codecPreferenceOrder;
static std::vector<ZoneDescription> _audioZones;
static std::vector<ZoneSettings> _zoneSettings;
static std::vector<ReverbSettings> _zoneReverbSettings;
static std::unordered_map<QString, ZoneSettings> _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

View file

@ -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

View file

@ -1081,11 +1081,12 @@ void AvatarMixer::parseDomainServerSettings(const QJsonObject& domainSettings) {
void AvatarMixer::setupEntityQuery() {
_entityViewer.init();
EntityTreePointer entityTree = _entityViewer.getTree();
entityTree->setIsServer(true);
DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
DependencyManager::set<AssignmentParentFinder>(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<ResourceManager>();
DependencyManager::destroy<ResourceCacheSharedItems>();

View file

@ -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<ReceivedMessage> message, SharedNodePointer node);

View file

@ -67,8 +67,6 @@
* @property {boolean} lookAtSnappingEnabled=true - <code>true</code> 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 <code>lookAtSnappingEnabled == true</code>.
* @property {string} skeletonModelURL - The avatar's FST file.
* @property {AttachmentData[]} attachmentData - Information on the avatar's attachments.
* <p class="important">Deprecated: This property is deprecated and will be removed. Use avatar entities instead.</p>
* @property {string[]} jointNames - The list of joints in the current avatar model. <em>Read-only.</em>
* @property {Uuid} sessionUUID - Unique ID of the avatar in the domain. <em>Read-only.</em>
* @property {Mat4} sensorToWorldMatrix - The scale, rotation, and translation transform from the user's real world to the

View file

@ -16,9 +16,11 @@
#include <QJsonArray>
#include <QJsonDocument>
#include <AudioInjectorManager.h>
#include <EntityTree.h>
#include <ResourceCache.h>
#include <ScriptCache.h>
#include <SoundCache.h>
#include <plugins/PluginManager.h>
#include <EntityEditFilters.h>
#include <NetworkingConstants.h>
@ -49,6 +51,9 @@ EntityServer::EntityServer(ReceivedMessage& message) :
DependencyManager::set<ModelFormatRegistry>(); // ModelFormatRegistry must be defined before ModelCache. See the ModelCache ctor
DependencyManager::set<ModelCache>();
DependencyManager::set<SoundCache>();
DependencyManager::set<AudioInjectorManager>();
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
packetReceiver.registerListenerForTypes({ PacketType::EntityAdd,
PacketType::EntityClone,
@ -71,6 +76,8 @@ EntityServer::~EntityServer() {
void EntityServer::aboutToFinish() {
DependencyManager::get<ResourceManager>()->cleanup();
DependencyManager::destroy<AudioInjectorManager>();
DependencyManager::destroy<SoundCache>();
DependencyManager::destroy<AssignmentDynamicFactory>();
OctreeServer::aboutToFinish();
@ -90,6 +97,7 @@ OctreePointer EntityServer::createTree() {
EntityTreePointer tree = std::make_shared<EntityTree>(true);
tree->createRootElement();
tree->addNewlyCreatedHook(this);
tree->setIsEntityServer(true);
if (!_entitySimulation) {
SimpleEntitySimulationPointer simpleSimulation { new SimpleEntitySimulation() };
simpleSimulation->setEntityTree(tree);

View file

@ -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

View file

@ -316,6 +316,7 @@ void EntityScriptServer::run() {
entityScriptingInterface->setEntityTree(_entityViewer.getTree());
auto treePtr = _entityViewer.getTree();
treePtr->setIsServer(true);
DependencyManager::set<AssignmentParentFinder>(treePtr);
if (!_entitySimulation) {

View file

@ -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()

View file

@ -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)

View file

@ -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()

View file

@ -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")

View file

@ -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,

View file

@ -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")

View file

@ -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] + "%"
}
}
}

View file

@ -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] + "%"
}
}
}

View file

@ -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 {
@ -267,6 +268,45 @@ Flickable {
Render.shadowsEnabled = renderingEffectShadows.checked;
}
}
HifiControlsUit.CheckBox {
id: renderingEffectHaze
checked: Render.hazeEnabled
boxSize: 16
text: "Haze"
spacing: -1
colorScheme: hifi.colorSchemes.dark
anchors.left: parent.left
anchors.top: renderingEffectShadows.bottom
onCheckedChanged: {
Render.hazeEnabled = renderingEffectHaze.checked;
}
}
HifiControlsUit.CheckBox {
id: renderingEffectBloom
checked: Render.bloomEnabled
boxSize: 16
text: "Bloom"
spacing: -1
colorScheme: hifi.colorSchemes.dark
anchors.left: parent.left
anchors.top: renderingEffectHaze.bottom
onCheckedChanged: {
Render.bloomEnabled = renderingEffectBloom.checked;
}
}
HifiControlsUit.CheckBox {
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
@ -277,41 +317,11 @@ Flickable {
spacing: -1
colorScheme: hifi.colorSchemes.dark
anchors.left: parent.left
anchors.top: renderingEffectShadows.bottom
anchors.top: renderingEffectAO.bottom
//onCheckedChanged: {
// Render.localLightsEnabled = renderingEffectLocalLightsEnabled.checked;
//}
}
HifiControlsUit.CheckBox {
id: renderingEffectFog
enabled: false
//checked: Render.fogEnabled
checked: renderingEffectsEnabled.checked
boxSize: 16
text: "Fog"
spacing: -1
colorScheme: hifi.colorSchemes.dark
anchors.left: parent.left
anchors.top: renderingEffectLocalLights.bottom
//onCheckedChanged: {
// Render.fogEnabled = renderingEffectFogEnabled.checked;
//}
}
HifiControlsUit.CheckBox {
id: renderingEffectBloom
enabled: false
//checked: Render.bloomEnabled
checked: renderingEffectsEnabled.checked
boxSize: 16
text: "Bloom"
spacing: -1
colorScheme: hifi.colorSchemes.dark
anchors.left: parent.left
anchors.top: renderingEffectFog.bottom
//onCheckedChanged: {
// Render.bloomEnabled = renderingEffectBloomEnabled.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;
}
}
}
}
}
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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<std::pair<QString, Application::AcceptURLMethod>> 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<UsersScriptingInterface>()->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<QMessageBox::StandardButton>(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<TabletScriptingInterface>()->getTablet(SYSTEM_TABLET);
auto hmd = DependencyManager::get<HMDScriptingInterface>();
@ -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<EntityScriptingInterface>();
@ -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<EntityScriptingInterface>();

View file

@ -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:
bool _reticleClickPressed { false };
bool _keyboardFocusWaitingOnRenderable { false };
int _avatarAttachmentRequest = 0;
bool _settingsLoaded { false };
bool _captureMouse { false };

View file

@ -222,8 +222,6 @@ void AvatarBookmarks::updateAvatarEntities(const QVariantList &avatarEntities) {
* @property {number} avatarScale - The target scale of the avatar.
* @property {Array<Object<"properties",Entities.EntityProperties>>} [avatarEntites] - The avatar entities included with the
* bookmark.
* @property {AttachmentData[]} [attachments] - The attachments included with the bookmark.
* <p class="important">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<QVariant> attachments = bookmark.value(ENTRY_AVATAR_ATTACHMENTS, QList<QVariant>()).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);

View file

@ -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 @@ private:
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";

View file

@ -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<ModelBlender>().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<render::DrawStatus>("RenderMainView.DrawStatus");

View file

@ -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<LODManager>()->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<LODManager>()->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<LODManager>()->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<LODManager>()->setWorldDetailQuality(WORLD_DETAIL_LOW);
break;

View file

@ -27,7 +27,7 @@ public:
using Config = SecondaryCameraJobConfig;
using JobModel = render::Job::ModelO<SecondaryCameraJob, RenderArgsPointer, Config>;
SecondaryCameraJob() {
_cachedArgsPointer = std::make_shared<RenderArgs>(_cachedArgs);
_cachedArgsPointer = std::make_shared<RenderArgs>();
_attachedEntityPropertyFlags += PROP_POSITION;
_attachedEntityPropertyFlags += PROP_ROTATION;
}
@ -203,7 +203,6 @@ public:
}
protected:
RenderArgs _cachedArgs;
RenderArgsPointer _cachedArgsPointer;
private:

View file

@ -259,7 +259,7 @@ MyAvatar::MyAvatar(QThread* thread) :
_headData = new MyHead(this);
_skeletonModel = std::make_shared<MySkeletonModel>(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<NodeList>()->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<EntityScriptingInterface>()->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<NodeList>()->getThisNodeCanRezAvatarEntities()) {
qCDebug(interfaceapp) << "Ignoring detachOne() because don't have canRezAvatarEntities permission on domain";
return;
}
QUuid entityID;
if (findAvatarEntity(modelURL, jointName, entityID)) {
DependencyManager::get<EntityScriptingInterface>()->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<NodeList>()->getThisNodeCanRezAvatarEntities()) {
qCDebug(interfaceapp) << "Ignoring detachAll() because don't have canRezAvatarEntities permission on domain";
return;
}
QUuid entityID;
while (findAvatarEntity(modelURL, jointName, entityID)) {
DependencyManager::get<EntityScriptingInterface>()->deleteEntity(entityID);
}
emit attachmentsChanged();
}
void MyAvatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
if (QThread::currentThread() != thread()) {
BLOCKING_INVOKE_METHOD(this, "setAttachmentData",
Q_ARG(const QVector<AttachmentData>&, attachmentData));
return;
}
if (!DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities()) {
qCDebug(interfaceapp) << "Ignoring setAttachmentData() because don't have canRezAvatarEntities permission on domain";
return;
}
std::vector<EntityItemProperties> newEntitiesProperties;
for (auto& data : attachmentData) {
QUuid entityID;
EntityItemProperties properties;
if (findAvatarEntity(data.modelURL.toString(), data.jointName, entityID)) {
properties = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityID);
}
attachmentDataToEntityProperties(data, properties);
newEntitiesProperties.push_back(properties);
}
// clear any existing wearables
clearWornAvatarEntities();
for (auto& properties : newEntitiesProperties) {
DependencyManager::get<EntityScriptingInterface>()->addEntity(properties, true);
}
emit attachmentsChanged();
}
QVector<AttachmentData> MyAvatar::getAttachmentData() const {
QVector<AttachmentData> attachmentData;
if (!DependencyManager::get<NodeList>()->getThisNodeCanRezAvatarEntities()) {
qCDebug(interfaceapp) << "Ignoring getAttachmentData() because don't have canRezAvatarEntities permission on domain";
return attachmentData;
}
QList<QUuid> avatarEntityIDs;
_avatarEntitiesLock.withReadLock([&] {
avatarEntityIDs = _packedAvatarEntityData.keys();
});
for (const auto& entityID : avatarEntityIDs) {
auto properties = DependencyManager::get<EntityScriptingInterface>()->getEntityProperties(entityID);
AttachmentData data = entityPropertiesToAttachmentData(properties);
attachmentData.append(data);
}
return attachmentData;
}
QVariantList MyAvatar::getAttachmentsVariant() const {
QVariantList result;
if (!DependencyManager::get<NodeList>()->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<NodeList>()->getThisNodeCanRezAvatarEntities()) {
qCDebug(interfaceapp)
<< "Ignoring setAttachmentsVariant() because don't have canRezAvatarEntities permission on domain";
return;
}
QVector<AttachmentData> 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<QUuid> 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) {

View file

@ -141,8 +141,6 @@ class MyAvatar : public Avatar {
* @property {boolean} lookAtSnappingEnabled=true - <code>true</code> 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 <code>lookAtSnappingEnabled == true</code>.
* @property {string} skeletonModelURL - The avatar's FST file.
* @property {AttachmentData[]} attachmentData - Information on the avatar's attachments.
* <p class="important">Deprecated: This property is deprecated and will be removed. Use avatar entities instead.</p>
* @property {string[]} jointNames - The list of joints in the current avatar model. <em>Read-only.</em>
* @property {Uuid} sessionUUID - Unique ID of the avatar in the domain. <em>Read-only.</em>
* @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 @@ public:
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 @@ public:
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 @@ public:
float computeStandingHeightMode(const controller::Pose& head);
glm::quat computeAverageHeadRotation(const controller::Pose& head);
virtual void setAttachmentData(const QVector<AttachmentData>& attachmentData) override;
virtual QVector<AttachmentData> 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 @@ signals:
*/
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:
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();

View file

@ -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<SkeletonModel>(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;
}
}

View file

@ -73,6 +73,8 @@ protected:
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 @@ protected:
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<OtherAvatar>;

View file

@ -10,7 +10,7 @@
#include "PathPointer.h"
#include<EntityItemProperties.h>
#include <EntityItemProperties.h>
#include <render/Item.h>

View file

@ -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;

View file

@ -9,12 +9,15 @@
//
#include "RenderScriptingInterface.h"
#include <RenderCommonTask.h>
#include <ScriptEngineCast.h>
#include "LightingModel.h"
#include <QScreen>
#include "ScreenName.h"
#include <procedural/Procedural.h>
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<AntialiasingConfig::Mode>(_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<render::SwitchConfig*>(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<render::SwitchConfig*>(qApp->getRenderEngine()->getConfiguration()->getConfig("RenderMainView.DeferredForwardSwitch"));
QString configName = "RenderMainView.DeferredForwardSwitch";
auto config = dynamic_cast<render::SwitchConfig*>(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<void(MakeLightingModelConfig *)> updateLambda, int depth = -1) {
if (depth == -1) {
auto secondaryLightingModelConfig = qApp->getRenderEngine()->getConfiguration()->getConfig<MakeLightingModel>("RenderSecondView.LightingModel");
if (secondaryLightingModelConfig) {
updateLambda(secondaryLightingModelConfig);
}
auto mainLightingModelConfig = qApp->getRenderEngine()->getConfiguration()->getConfig<MakeLightingModel>("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<MakeLightingModel>(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<MakeLightingModel>("RenderMainView.LightingModel");
if (lightingModelConfig) {
Menu::getInstance()->setIsOptionChecked(MenuOption::Shadows, enabled);
lightingModelConfig->setShadow(enabled);
}
auto secondaryLightingModelConfig = renderConfig->getConfig<MakeLightingModel>("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<MakeLightingModel>("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;
void recursivelyUpdateAntialiasingMode(const QString& parentTaskName, AntialiasingConfig::Mode mode, int depth = -1) {
if (depth == -1) {
auto secondViewJitterCamConfig = qApp->getRenderEngine()->getConfiguration()->getConfig<JitterSample>("RenderSecondView.JitterCam");
auto secondViewAntialiasingConfig = qApp->getRenderEngine()->getConfiguration()->getConfig<Antialiasing>("RenderSecondView.Antialiasing");
if (secondViewJitterCamConfig && secondViewAntialiasingConfig) {
setAntialiasingModeForView(mode, secondViewJitterCamConfig, secondViewAntialiasingConfig);
}
auto mainViewJitterCamConfig = qApp->getRenderEngine()->getConfiguration()->getConfig<JitterSample>("RenderMainView.JitterCam");
auto mainViewAntialiasingConfig = qApp->getRenderEngine()->getConfiguration()->getConfig<Antialiasing>("RenderMainView.Antialiasing");
auto secondViewJitterCamConfig = qApp->getRenderEngine()->getConfiguration()->getConfig<JitterSample>("RenderSecondView.JitterCam");
auto secondViewAntialiasingConfig = qApp->getRenderEngine()->getConfiguration()->getConfig<Antialiasing>("RenderSecondView.Antialiasing");
if (mode != AntialiasingConfig::Mode::NONE
&& mode != AntialiasingConfig::Mode::TAA
&& mode != AntialiasingConfig::Mode::FXAA) {
_antialiasingMode = AntialiasingConfig::Mode::NONE;
}
if (mainViewJitterCamConfig && mainViewAntialiasingConfig) {
setAntialiasingModeForView( mode, mainViewJitterCamConfig, mainViewAntialiasingConfig);
}
if (secondViewJitterCamConfig && secondViewAntialiasingConfig) {
setAntialiasingModeForView( mode, secondViewJitterCamConfig, secondViewAntialiasingConfig);
recursivelyUpdateAntialiasingMode("RenderMainView", mode, 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 jitterCamConfig = qApp->getRenderEngine()->getConfiguration()->getConfig<JitterSample>(mirrorTaskString + ".JitterCam");
auto antialiasingConfig = qApp->getRenderEngine()->getConfiguration()->getConfig<Antialiasing>(mirrorTaskString + ".Antialiasing");
if (jitterCamConfig && antialiasingConfig) {
setAntialiasingModeForView(mode, jitterCamConfig, antialiasingConfig);
recursivelyUpdateAntialiasingMode(QString::fromStdString(mirrorTaskString), mode, depth + 1);
}
_antialiasingModeSetting.set(_antialiasingMode);
});
}
float RenderScriptingInterface::getViewportResolutionScale() const {
return _viewportResolutionScale;
}
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

View file

@ -29,8 +29,12 @@
*
* @property {Render.RenderMethod} renderMethod - The render method being used.
* @property {boolean} shadowsEnabled - <code>true</code> if shadows are enabled, <code>false</code> if they're disabled.
* @property {boolean} hazeEnabled - <code>true</code> if haze (fog) is enabled, <code>false</code> if it's disabled.
* @property {boolean} bloomEnabled - <code>true</code> if bloom is enabled, <code>false</code> if it's disabled.
* @property {boolean} ambientOcclusionEnabled - <code>true</code> if ambient occlusion is enabled, <code>false</code> if it's
* disabled.
* @property {boolean} proceduralMaterialsEnabled - <code>true</code> if procedural shaders are enabled, <code>false</code> if
* they're disabled.
* @property {integer} antialiasingMode - The active anti-aliasing mode.
* @property {number} viewportResolutionScale - The view port resolution scale, <code>&gt; 0.0</code>.
*/
@ -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} <code>true</code> if haze is enabled, <code>false</code> if it's disabled.
*/
bool getHazeEnabled() const;
/*@jsdoc
* Sets whether or not haze is enabled.
* @function Render.setHazeEnabled
* @param {boolean} enabled - <code>true</code> to enable haze, <code>false</code> to disable.
*/
void setHazeEnabled(bool enabled);
/*@jsdoc
* Gets whether or not bloom is enabled.
* @function Render.getBloomEnabled
* @returns {boolean} <code>true</code> if bloom is enabled, <code>false</code> if it's disabled.
*/
bool getBloomEnabled() const;
/*@jsdoc
* Sets whether or not bloom is enabled.
* @function Render.setBloomEnabled
* @param {boolean} enabled - <code>true</code> to enable bloom, <code>false</code> 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} <code>true</code> if procedural materials are enabled, <code>false</code> if they're disabled.
*/
bool getProceduralMaterialsEnabled() const;
/*@jsdoc
* Sets whether or not procedural materials are enabled.
* @function Render.setProceduralMaterialsEnabled
* @param {boolean} enabled - <code>true</code> to enable procedural materials, <code>false</code> to disable.
*/
void setProceduralMaterialsEnabled(bool enabled);
/*@jsdoc
* Gets the active anti-aliasing mode.
* @function Render.getAntialiasingMode
@ -233,19 +282,23 @@ private:
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<int> _renderMethodSetting { "renderMethod", RENDER_FORWARD ? render::Args::RenderMethod::FORWARD : render::Args::RenderMethod::DEFERRED };
Setting::Handle<bool> _shadowsEnabledSetting { "shadowsEnabled", true };
Setting::Handle<bool> _ambientOcclusionEnabledSetting { "ambientOcclusionEnabled", false };
//Setting::Handle<AntialiasingConfig::Mode> _antialiasingModeSetting { "antialiasingMode", AntialiasingConfig::Mode::TAA };
Setting::Handle<bool> _hazeEnabledSetting { "hazeEnabled", true };
Setting::Handle<bool> _bloomEnabledSetting { "bloomEnabled", true };
Setting::Handle<bool> _ambientOcclusionEnabledSetting { "ambientOcclusionEnabled", true };
Setting::Handle<bool> _proceduralMaterialsEnabledSetting { "proceduralMaterialsEnabled", true };
Setting::Handle<int> _antialiasingModeSetting { "antialiasingMode", AntialiasingConfig::Mode::NONE };
Setting::Handle<float> _viewportResolutionScaleSetting { "viewportResolutionScale", 1.0f };
Setting::Handle<QString> _fullScreenScreenSetting { "fullScreenScreen", "" };
@ -253,7 +306,10 @@ private:
// 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);

View file

@ -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:
template<typename T>
void maybeCreateDialog(QPointer<T>& member);
QPointer<AnimationsDialog> _animationsDialog;
QPointer<AttachmentsDialog> _attachmentsDialog;
QPointer<CachesSizeDialog> _cachesSizeDialog;
QPointer<QMessageBox> _ircInfoBox;
QPointer<HMDToolsDialog> _hmdToolsDialog;
QPointer<LodToolsDialog> _lodToolsDialog;
QPointer<OctreeStatsDialog> _octreeStatsDialog;

View file

@ -32,7 +32,7 @@
#include <NetworkingConstants.h>
#include <SharedUtil.h>
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.

View file

@ -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<StatTracker>()->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

View file

@ -211,7 +211,10 @@ private: \
* <em>Read-only.</em>
* @property {string[]} downloadUrls - The download URLs.
* <em>Read-only.</em>
* <p><strong>Note:</strong> Property not available in the API.</p>
* @property {number[]} downloadProgresses - The download progresses.
* <em>Read-only.</em>
* @property {number[]} downloadPriorities - The download priorities.
* <em>Read-only.</em>
* @property {number} processing - The number of completed downloads being processed.
* <em>Read-only.</em>
* @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<int> downloadProgresses READ downloadProgresses NOTIFY downloadProgressesChanged)
Q_PROPERTY(QList<float> downloadPriorities READ downloadPriorities NOTIFY downloadPrioritiesChanged)
STATS_PROPERTY(int, processing, 0)
STATS_PROPERTY(int, processingPending, 0)
STATS_PROPERTY(int, triangles, 0)
@ -622,7 +627,9 @@ public:
}
}
QStringList downloadUrls () { return _downloadUrls; }
QStringList downloadUrls() { return _downloadUrls; }
QList<int> downloadProgresses() { return _downloadProgresses; }
QList<float> downloadPriorities() { return _downloadPriorities; }
public slots:
@ -1091,6 +1098,20 @@ signals:
*/
void downloadUrlsChanged();
/*@jsdoc
* Triggered when the value of the <code>downloadProgresses</code> property changes.
* @function Stats.downloadProgressesChanged
* @returns {Signal}
*/
void downloadProgressesChanged();
/*@jsdoc
* Triggered when the value of the <code>downloadPriorities</code> property changes.
* @function Stats.downloadPrioritiesChanged
* @returns {Signal}
*/
void downloadPrioritiesChanged();
/*@jsdoc
* Triggered when the value of the <code>processing</code> property changes.
* @function Stats.processingChanged
@ -1809,14 +1830,16 @@ signals:
*/
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<int> _downloadProgresses { QList<int>() };
QList<float> _downloadPriorities { QList<float>() };
};
#endif // hifi_Stats_h

View file

@ -1085,7 +1085,7 @@ AnimNodeLoader::AnimNodeLoader(const QUrl& url) :
{
_resource = QSharedPointer<Resource>::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();

View file

@ -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;

View file

@ -35,7 +35,7 @@ SharedSoundPointer SoundCache::getSound(const QUrl& url) {
QSharedPointer<Resource> SoundCache::createResource(const QUrl& url) {
auto resource = QSharedPointer<Sound>(new Sound(url), &Resource::deleter);
resource->setLoadPriority(this, SOUNDS_LOADING_PRIORITY);
resource->setLoadPriorityOperator(this, []() { return SOUNDS_LOADING_PRIORITY; });
return resource;
}

View file

@ -30,7 +30,6 @@
#include <VariantMapToScriptValue.h>
#include <DebugDraw.h>
#include <shared/Camera.h>
#include <SoftAttachmentModel.h>
#include <render/TransitionStage.h>
#include <GLMHelpers.h>
#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>(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<scriptable::ModelProviderFactory>()->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<scriptable::ModelProviderFactory>()->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<EntityItem>(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<Model> allocateAttachmentModel(bool isSoft, const Rig& rigOverride, bool isCauterized) {
if (isSoft) {
// cast to std::shared_ptr<Model>
std::shared_ptr<SoftAttachmentModel> softModel = std::make_shared<SoftAttachmentModel>(nullptr, rigOverride);
if (isCauterized) {
softModel->flagAsCauterized();
}
return std::dynamic_pointer_cast<Model>(softModel);
} else {
return std::make_shared<Model>();
}
}
void Avatar::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
if (QThread::currentThread() != thread()) {
BLOCKING_INVOKE_METHOD(this, "setAttachmentData",
Q_ARG(const QVector<AttachmentData>, 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>([&] {
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;

View file

@ -157,7 +157,6 @@ public:
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 @@ public:
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>& attachmentData) override;
void updateDisplayNameAlpha(bool showDisplayName);
virtual void setSessionDisplayName(const QString& sessionDisplayName) override { }; // no-op
@ -556,6 +554,11 @@ public:
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 @@ protected:
mutable bool _modelJointsCached { false };
glm::vec3 _skeletonOffset;
std::vector<std::shared_ptr<Model>> _attachmentModels;
std::vector<bool> _attachmentModelsTexturesLoaded;
std::vector<std::shared_ptr<Model>> _attachmentsToRemove;
std::vector<std::shared_ptr<Model>> _attachmentsToDelete;
float _bodyYawDelta { 0.0f }; // degrees/sec
float _seatedBodyYawDelta{ 0.0f }; // degrees/renderframe
@ -748,12 +747,14 @@ protected:
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 @@ protected:
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<EntityItemID> _renderingDescendantEntityIDs;
uint32_t _lastAncestorChainRenderableVersion { 0 };
};
#endif // hifi_Avatar_h

View file

@ -58,8 +58,6 @@
* when the other avatar is in the line of sight and also has <code>lookAtSnappingEnabled == true</code>.
*
* @property {string} skeletonModelURL - The avatar's FST file.
* @property {AttachmentData[]} attachmentData - Information on the avatar's attachments.
* <p class="important">Deprecated: This property is deprecated and will be removed. Use avatar entities instead.</p>
* @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

View file

@ -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<RayToAvatarIntersectionResult, RayToAvatarIntersectionResultToScriptValue, RayToAvatarIntersectionResultFromScriptValue>(scriptEngine);
scriptRegisterMetaType<AvatarEntityMap, AvatarEntityMapToScriptValue, AvatarEntityMapFromScriptValue>(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<AttachmentData> AvatarData::getAttachmentData() const {
if (QThread::currentThread() != thread()) {
QVector<AttachmentData> result;
BLOCKING_INVOKE_METHOD(const_cast<AvatarData*>(this), "getAttachmentData",
Q_RETURN_ARG(QVector<AttachmentData>, result));
return result;
}
return _attachmentData;
}
void AvatarData::setAttachmentData(const QVector<AttachmentData>& attachmentData) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "setAttachmentData", Q_ARG(const QVector<AttachmentData>&, 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> 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> attachmentData = getAttachmentData();
for (QVector<AttachmentData>::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> attachmentData = getAttachmentData();
for (QVector<AttachmentData>::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<NodeList>();
@ -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<AttachmentData>(thisObject());
data.modelURL = modelURL;
Q_ASSERT(engine());
thisObject() = engine()->toScriptValue(data);
}
QString AttachmentDataObject::getModelURL() const {
return scriptvalue_cast<AttachmentData>(thisObject()).modelURL.toString();
}
void AttachmentDataObject::setJointName(const QString& jointName) {
AttachmentData data = scriptvalue_cast<AttachmentData>(thisObject());
data.jointName = jointName;
Q_ASSERT(engine());
thisObject() = engine()->toScriptValue(data);
}
QString AttachmentDataObject::getJointName() const {
return scriptvalue_cast<AttachmentData>(thisObject()).jointName;
}
void AttachmentDataObject::setTranslation(const glm::vec3& translation) {
AttachmentData data = scriptvalue_cast<AttachmentData>(thisObject());
data.translation = translation;
Q_ASSERT(engine());
thisObject() = engine()->toScriptValue(data);
}
glm::vec3 AttachmentDataObject::getTranslation() const {
return scriptvalue_cast<AttachmentData>(thisObject()).translation;
}
void AttachmentDataObject::setRotation(const glm::quat& rotation) {
AttachmentData data = scriptvalue_cast<AttachmentData>(thisObject());
data.rotation = rotation;
Q_ASSERT(engine());
thisObject() = engine()->toScriptValue(data);
}
glm::quat AttachmentDataObject::getRotation() const {
return scriptvalue_cast<AttachmentData>(thisObject()).rotation;
}
void AttachmentDataObject::setScale(float scale) {
AttachmentData data = scriptvalue_cast<AttachmentData>(thisObject());
data.scale = scale;
Q_ASSERT(engine());
thisObject() = engine()->toScriptValue(data);
}
float AttachmentDataObject::getScale() const {
return scriptvalue_cast<AttachmentData>(thisObject()).scale;
}
void AttachmentDataObject::setIsSoft(bool isSoft) {
AttachmentData data = scriptvalue_cast<AttachmentData>(thisObject());
data.isSoft = isSoft;
Q_ASSERT(engine());
thisObject() = engine()->toScriptValue(data);
}
bool AttachmentDataObject::getIsSoft() const {
return scriptvalue_cast<AttachmentData>(thisObject()).isSoft;
}
void registerAvatarTypes(ScriptEngine* engine) {
scriptRegisterSequenceMetaType<QVector<AttachmentData> >(engine);
}
void registerAvatarPrototypes(ScriptEngine* engine) {
engine->setDefaultPrototype(qMetaTypeId<AttachmentData>(), engine->newQObject(
new AttachmentDataObject(), ScriptEngine::ScriptOwnership));
}
void AvatarData::setRecordingBasis(std::shared_ptr<Transform> recordingBasis) {
if (!recordingBasis) {
recordingBasis = std::make_shared<Transform>();
@ -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<AttachmentData> 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 <code>true</code> and the model has a skeleton, the bones of the attached model's skeleton are
* rotated to fit the avatar's current pose. If <code>true</code>, the <code>translation</code>, <code>rotation</code>, and
* <code>scale</code> 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<AttachmentData> 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([&] {

View file

@ -451,7 +451,6 @@ Q_DECLARE_METATYPE(KillAvatarReason);
class QDataStream;
class AttachmentData;
class Transform;
using TransformPointer = std::shared_ptr<Transform>;
@ -523,8 +522,6 @@ class AvatarData : public QObject, public SpatiallyNestable {
* @property {boolean} lookAtSnappingEnabled=true - <code>true</code> 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 <code>lookAtSnappingEnabled == true</code>.
* @property {string} skeletonModelURL - The avatar's FST file.
* @property {AttachmentData[]} attachmentData - Information on the avatar's attachments.
* <p class="important">Deprecated: This property is deprecated and will be removed. Use avatar entities instead.</p>
* @property {string[]} jointNames - The list of joints in the current avatar model. <em>Read-only.</em>
* @property {Uuid} sessionUUID - Unique ID of the avatar in the domain. <em>Read-only.</em>
* @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> attachmentData READ getAttachmentData WRITE setAttachmentData)
Q_PROPERTY(QStringList jointNames READ getJointNames)
@ -1145,27 +1141,6 @@ public:
*/
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 @@ public:
const HeadData* getHeadData() const { return _headData; }
struct Identity {
QVector<AttachmentData> attachmentData;
QString displayName;
QString sessionDisplayName;
bool isReplicated;
@ -1254,109 +1228,6 @@ public:
}
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 <caption>Report the URLs of all current attachments.</caption>
* 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<AttachmentData> 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 <code>attachmentData</code> to <code>null</code>.
* @function Avatar.setAttachmentData
* @param {AttachmentData[]} attachmentData - The attachment data defining the models to have attached to your avatar. Use
* <code>null</code> to remove all attachments.
* @deprecated This function is deprecated and will be removed. Use avatar entities instead.
* @example <caption>Remove a hat attachment if your avatar is wearing it.</caption>
* 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>& 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 <code>true</code> so that the bones of the
* attached model's skeleton are rotated to fit the avatar's current pose. <code>isSoft</code> is used, for example,
* to have clothing that moves with the avatar.
* <p>If <code>true</code>, the <code>translation</code>, <code>rotation</code>, and <code>scale</code> parameters are
* ignored.</p>
* @param {boolean} [allowDuplicates=false] - If <code>true</code> then more than one copy of any particular model may be
* attached to the same joint; if <code>false</code> then the same model cannot be attached to the same joint.
* @param {boolean} [useSaved=true] - <em>Not used.</em>
* @deprecated This function is deprecated and will be removed. Use avatar entities instead.
* @example <caption>Attach a cowboy hat to your avatar's head.</caption>
* 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 <code>""</code>, 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 <code>""</code>, 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 @@ public:
*/
Q_INVOKABLE virtual void setAvatarEntityData(const AvatarEntityMap& avatarEntityData);
void setAvatarEntityDataChanged(bool value) { _avatarEntityDataChanged = value; }
AvatarEntityIDs getAndClearRecentlyRemovedIDs();
/*@jsdoc
@ -1712,6 +1582,8 @@ protected:
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 @@ protected:
mutable HeadData* _headData { nullptr };
QUrl _skeletonModelURL;
QVector<AttachmentData> _attachmentData;
QVector<AttachmentData> _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<AttachmentData>)
/// 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 };

View file

@ -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<AttachmentData> ScriptAvatarData::getAttachmentData() const {
if (AvatarSharedPointer sharedAvatarData = _avatarData.lock()) {
return sharedAvatarData->getAttachmentData();
} else {
return QVector<AttachmentData>();
}
}
//
// ATTACHMENT AND JOINT PROPERTIES
// JOINT PROPERTIES
// END
//

View file

@ -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> attachmentData READ getAttachmentData)
Q_PROPERTY(QStringList jointNames READ getJointNames)
//
@ -104,7 +103,7 @@ public:
bool getLookAtSnappingEnabled() const;
//
// ATTACHMENT AND JOINT PROPERTIES
// JOINT PROPERTIES
//
QString getSkeletonModelURLFromScript() const;
@ -204,15 +203,6 @@ public:
*/
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 <code>[]</code> if the avatar data
* aren't available.
* @deprecated This function is deprecated and will be removed. Use avatar entities instead.
*/
Q_INVOKABLE QVector<AttachmentData> getAttachmentData() const;
#if DEV_BUILD || PR_BUILD
Q_INVOKABLE AvatarEntityMap getAvatarEntities() const;
#endif

View file

@ -360,7 +360,7 @@ void OpenGLDisplayPlugin::customizeContext() {
auto presentThread = DependencyManager::get<PresentThread>();
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<RefreshRateController>&
if (_currentFrame) {
auto correction = getViewCorrection();
getGLBackend()->setCameraCorrection(correction, _prevRenderView);
getGLBackend()->setCameraCorrection(correction, _prevRenderView, true);
_prevRenderView = correction * _currentFrame->view;
{
withPresentThreadLock([&] {

View file

@ -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()

View file

@ -13,6 +13,7 @@
#include "RenderableEntityItem.h"
#include <glm/gtx/transform.hpp>
#include <ObjectMotionState.h>
#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<QUuid>& 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<EntityTreeRenderer>();
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<EntityTreeRenderer>()->renderableIdForEntityId(portalExitID) : Item::INVALID_ITEM_ID;
}
HighlightStyle EntityRenderer::getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const {
std::lock_guard<std::mutex> 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<ParticleEffectEntityRenderer>(entity);
break;
case Type::ProceduralParticleEffect:
result = make_renderer<ProceduralParticleEffectEntityRenderer>(entity);
break;
case Type::Line:
result = make_renderer<LineEntityRenderer>(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;
}

View file

@ -61,12 +61,13 @@ public:
enum class Pipeline {
SIMPLE,
MATERIAL,
PROCEDURAL
PROCEDURAL,
MIRROR
};
virtual void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName);
virtual void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName);
virtual graphics::MaterialPointer getTopMaterial();
static Pipeline getPipelineType(const graphics::MultiMaterial& materials);
Pipeline getPipelineType(const graphics::MultiMaterial& materials);
virtual gpu::TexturePointer getTexture() { return nullptr; }
virtual scriptable::ScriptableModelBase getScriptableModel() override { return scriptable::ScriptableModelBase(); }
@ -77,6 +78,10 @@ public:
virtual uint32_t metaFetchMetaSubItems(ItemIDs& subItems) const override;
virtual Item::Bound getBound(RenderArgs* args) override;
bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& 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 @@ protected:
virtual void setIsVisibleInSecondaryCamera(bool value) { _isVisibleInSecondaryCamera = value; }
virtual void setRenderLayer(RenderLayer value) { _renderLayer = value; }
virtual void setCullWithParent(bool value) { _cullWithParent = value; }
virtual void setMirrorMode(MirrorMode value) { _mirrorMode = value; }
virtual void setPortalExitID(const QUuid& value) { _portalExitID = value; }
template<typename T>
std::shared_ptr<T> asTypedEntity() { return std::static_pointer_cast<T>(_entity); }
@ -156,6 +163,8 @@ protected:
BillboardMode _billboardMode { BillboardMode::NONE };
bool _cauterized { false };
bool _moving { false };
MirrorMode _mirrorMode { MirrorMode::NONE };
QUuid _portalExitID;
Transform _renderTransform;
MaterialMap _materials;

View file

@ -263,8 +263,9 @@ void GizmoEntityRenderer::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(), true));
usePrimaryFrustum ? BillboardModeHelpers::getPrimaryViewFrustumPosition() : args->getViewFrustum().getPosition(), true));
batch.setModelTransform(transform);
Pipeline pipelineType = getPipelineType(materials);

View file

@ -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);

View file

@ -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<GeometryCache>()->renderQuad(

View file

@ -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<GeometryCache>()->bindSimpleProgram(batch, false, false, false, false, true,

View file

@ -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) {

View file

@ -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<EntityJointData> jointsData;
const QVector<HFMAnimationFrame>& 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<glm::vec3>& translations, const QVector<glm::quat>& 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<glm::quat>& rotations = frames[_lastKnownCurrentFrame].rotations;
const QVector<glm::vec3>& translations = frames[_lastKnownCurrentFrame].translations;
jointsData.resize(_jointMapping.size());
QVector<EntityJointData> 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<HFMAnimationFrame>& 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<glm::quat> rotations = frames[_lastKnownCurrentIntegerFrame].rotations;
QVector<glm::vec3> translations = frames[_lastKnownCurrentIntegerFrame].translations;
const int nextIntegerFrame = entity->getAnimationNextFrame(_lastKnownCurrentIntegerFrame, frameCount);
const QVector<glm::quat>& nextRotations = frames[nextIntegerFrame].rotations;
const QVector<glm::vec3>& 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<scriptable::ModelProviderFactory>()->
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<scriptable::ModelProviderFactory>()->
@ -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");

View file

@ -170,9 +170,12 @@ protected:
void setIsVisibleInSecondaryCamera(bool value) override;
void setRenderLayer(RenderLayer value) override;
void setCullWithParent(bool value) override;
void setMirrorMode(MirrorMode value) override;
void setPortalExitID(const QUuid& value) override;
private:
void animate(const TypedEntityPointer& entity, const ModelPointer& model);
void updateJointData(const QVector<glm::vec3>& translations, const QVector<glm::quat>& rotations, const TypedEntityPointer& entity, const ModelPointer& model);
void mapJoints(const TypedEntityPointer& entity, const ModelPointer& model);
// Transparency is handled in ModelMeshPartPayload
@ -182,7 +185,7 @@ private:
ModelPointer _model;
QString _textures;
bool _texturesLoaded { false };
int _lastKnownCurrentFrame { -1 };
int _lastKnownCurrentIntegerFrame { -1 };
#ifdef MODEL_ENTITY_USE_FADE_EFFECT
bool _hasTransitioned{ false };
#endif

View file

@ -171,6 +171,12 @@ bool ParticleEffectEntityRenderer::isTransparent() const {
return particleTransparent || Parent::isTransparent();
}
ItemKey ParticleEffectEntityRenderer::getKey() {
auto builder = ItemKey::Builder(Parent::getKey());
builder.withSimulate();
return builder.build();
}
ShapeKey ParticleEffectEntityRenderer::getShapeKey() {
auto builder = ShapeKey::Builder().withCustom(CUSTOM_PIPELINE_NUMBER);
@ -386,7 +392,11 @@ ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createPa
return particle;
}
void ParticleEffectEntityRenderer::stepSimulation() {
void ParticleEffectEntityRenderer::renderSimulate(RenderArgs* args) {
if (!_visible || !(_networkTexture && _networkTexture->isLoaded())) {
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());

View file

@ -24,11 +24,14 @@ class ParticleEffectEntityRenderer : public TypedEntityRenderer<ParticleEffectEn
public:
ParticleEffectEntityRenderer(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 Item::Bound getBound(RenderArgs* args) override;
virtual void doRender(RenderArgs* args) override;

View file

@ -10,7 +10,7 @@
//
#include "RenderablePolyLineEntityItem.h"
#include <ParticleEffectEntityItem.h>
#include <PolyLineEntityItem.h>
#include <GeometryCache.h>
#include <StencilMaskPass.h>
@ -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()}]);

View file

@ -13,7 +13,6 @@
#define hifi_RenderablePolyLineEntityItem_h
#include "RenderableEntityItem.h"
#include <PolyLineEntityItem.h>
#include <TextureCache.h>
namespace render { namespace entities {

View file

@ -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<RenderablePolyVoxEntityItem>(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);

View file

@ -81,7 +81,7 @@ public:
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;

View file

@ -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 <procedural/ShaderConstants.h>
#include <shaders/Shaders.h>
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<std::string, std::string> 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));
}

View file

@ -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 <ProceduralParticleEffectEntityItem.h>
#include <procedural/Procedural.h>
namespace render { namespace entities {
class ProceduralParticleEffectEntityRenderer : public TypedEntityRenderer<ProceduralParticleEffectEntityItem> {
using Parent = TypedEntityRenderer<ProceduralParticleEffectEntityItem>;
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<FramebufferPointer, 2> _particleBuffers;
bool _evenPass { true };
};
} } // namespace
#endif // hifi_RenderableProceduralParticleEffectEntityItem_h

View file

@ -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>();
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<GeometryCache>();
auto geometryShape = geometryCache->getShapeForEntityShape(_shape);
auto geometryShape = geometryCache->getShapeForEntityShape((int)_shape);
glm::vec3 vertexColor;
{
std::lock_guard<std::mutex> lock(_materialsLock);

View file

@ -36,12 +36,13 @@ private:
virtual bool isTransparent() const override;
QString _proceduralData;
entity::Shape _shape { entity::Sphere };
EntityShape _shape { EntityShape::Sphere };
PulsePropertyGroup _pulseProperties;
std::shared_ptr<graphics::ProceduralMaterial> _material { std::make_shared<graphics::ProceduralMaterial>() };
glm::vec3 _color { NAN };
float _alpha { NAN };
bool _unlit { false };
gpu::BufferPointer _colorBuffer { std::make_shared<gpu::Buffer>() };
};

View file

@ -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<GeometryCache>();
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<QUu
return false;
}
ItemID entities::TextPayload::computeMirrorView(ViewFrustum& viewFrustum) const {
auto entityTreeRenderer = DependencyManager::get<EntityTreeRenderer>();
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;
}
}

View file

@ -74,6 +74,7 @@ private:
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 @@ public:
ShapeKey getShapeKey() const;
void render(RenderArgs* args);
bool passesZoneOcclusionTest(const std::unordered_set<QUuid>& 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<QUuid>& containingZones);
template <> ItemID payloadComputeMirrorView(const entities::TextPayload::Pointer& payload, ViewFrustum& viewFrustum);
}
#endif // hifi_RenderableTextEntityItem_h

View file

@ -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

View file

@ -67,7 +67,7 @@ protected:
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 @@ private:
bool _useBackground { false };
QString _userAgent;
WebInputMode _inputMode { WebInputMode::TOUCH };
bool _wantsKeyboardFocus { true };
glm::vec3 _contextPosition;

View file

@ -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<TonemappingStage>();
assert(_tonemappingStage);
}
if (!_ambientOcclusionStage) {
_ambientOcclusionStage = args->_scene->getStage<AmbientOcclusionStage>();
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) {

View file

@ -20,6 +20,8 @@
#include <BackgroundStage.h>
#include <HazeStage.h>
#include <BloomStage.h>
#include <TonemappingStage.h>
#include <AmbientOcclusionStage.h>
#include <TextureCache.h>
#include "RenderableEntityItem.h"
#include <ComponentMode.h>
@ -47,6 +49,8 @@ private:
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 @@ private:
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 @@ private:
const graphics::SunSkyStagePointer _background { std::make_shared<graphics::SunSkyStage>() };
const graphics::HazePointer _haze { std::make_shared<graphics::Haze>() };
const graphics::BloomPointer _bloom { std::make_shared<graphics::Bloom>() };
const graphics::TonemappingPointer _tonemapping { std::make_shared<graphics::Tonemapping>() };
const graphics::AmbientOcclusionPointer _ambientOcclusion { std::make_shared<graphics::AmbientOcclusion>() };
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 @@ private:
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;
};

View file

@ -0,0 +1 @@
DEFINES translucent:f forward:f

View file

@ -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@>
}

View file

@ -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)$>
}

View file

@ -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
}

View file

@ -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)

View file

@ -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 <QJsonDocument>
#include <OctreePacketData.h>
#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<NodeList>();
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<QString> &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<QString>& 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;
}

View file

@ -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 <OctreePacketData.h>
#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<NodeList>();
@AmbientLight_GROUP_COPY_TO_SCRIPT@
}
void AmbientLightPropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet<QString> &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<QString>& 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<QString, EntityPropertyInfo>& _propertyInfos,
QHash<EntityPropertyList, QString>& _enumsToPropertyStrings) {
@AmbientLight_GROUP_ADD_TO_MAP@
}

View file

@ -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 <stdint.h>
#include <glm/glm.hpp>
#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
* <code>""</code> then the entity's {@link Entities.Skybox|Skybox} <code>url</code> property value is used, unless that also is <code>""</code> in which
* case the entity's <code>ambientLightMode</code> property is set to <code>"inherit"</code>.
*/
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<QString> &namesSet, bool& _defaultSettings) override;
void merge(const AmbientLightPropertyGroup& other);
virtual void debugDump() const override;
virtual void listChangedProperties(QList<QString>& out) override;
virtual bool appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const override;
virtual bool decodeFromEditPacket(EntityPropertyFlags& propertyFlags,
const unsigned char*& dataAt, int& processedBytes) override;
virtual void markAllChanged() override;
virtual EntityPropertyFlags getChangedProperties() const override;
// EntityItem related helpers
// methods for getting/setting all properties of an entity
virtual void getProperties(EntityItemProperties& propertiesOut) const override;
/// returns true if something changed
virtual bool setProperties(const EntityItemProperties& properties) override;
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override;
virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const override;
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override;
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

View file

@ -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 <stdint.h>
#include <glm/glm.hpp>
#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
* <code>""</code> then the entity's {@link Entities.Skybox|Skybox} <code>url</code> property value is used, unless that also is <code>""</code> in which
* case the entity's <code>ambientLightMode</code> property is set to <code>"inherit"</code>.
* @property {Color} ambientColor=0,0,0 - Sets the color of the ambient light if <code>ambientURL</code> is <code>""</code>, 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

View file

@ -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 <OctreePacketData.h>
#include "EntityItemProperties.h"
inline void addAmbientOcclusionTechnique(QHash<QString, AmbientOcclusionTechnique>& lookup, AmbientOcclusionTechnique technique) { lookup[AmbientOcclusionTechniqueHelpers::getNameForAmbientOcclusionTechnique(technique)] = technique; }
const QHash<QString, AmbientOcclusionTechnique> stringToAmbientOcclusionTechniqueLookup = [] {
QHash<QString, AmbientOcclusionTechnique> 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<QString> &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<QString>& 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<QString, EntityPropertyInfo>& _propertyInfos,
QHash<EntityPropertyList, QString>& _enumsToPropertyStrings) {
@AmbientOcclusion_GROUP_ADD_TO_MAP@
}

View file

@ -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 <AmbientOcclusionTechnique.h>
#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

View file

@ -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 <QJsonDocument>
#include <OctreePacketData.h>
#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).
* <p><strong>Warning:</strong> glTF animations currently do not always animate correctly.</p>
* @property {boolean} allowTranslation=true - <code>true</code> to enable translations contained in the animation to be
* played, <code>false</code> 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 - <code>true</code> if the animation should play, <code>false</code> if it shouldn't.
* @property {boolean} loop=true - <code>true</code> if the animation is continuously repeated in a loop, <code>false</code> if
* it isn't.
* @property {boolean} hold=false - <code>true</code> if the rotations and translations of the last frame played are
* maintained when the animation stops playing, <code>false</code> 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<NodeList>();
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<QString> &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<QString>& 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());
}

View file

@ -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 <QJsonDocument>
#include <OctreePacketData.h>
#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).
* <p><strong>Warning:</strong> glTF animations currently do not always animate correctly.</p>
* @property {boolean} allowTranslation=true - <code>true</code> to enable translations contained in the animation to be
* played, <code>false</code> 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 - <code>true</code> if the animation should play, <code>false</code> if it shouldn't.
* @property {boolean} loop=true - <code>true</code> if the animation is continuously repeated in a loop, <code>false</code> if
* it isn't.
* @property {boolean} hold=false - <code>true</code> if the rotations and translations of the last frame played are
* maintained when the animation stops playing, <code>false</code> if they aren't.
* @property {boolean} smoothFrames=true - <code>true</code> if the frames of the animation should be linearly interpolated to
* create smoother movement, <code>false</code> 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<NodeList>();
@Animation_GROUP_COPY_TO_SCRIPT@
}
void AnimationPropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet<QString> &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<QString>& 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<QString, EntityPropertyInfo>& _propertyInfos,
QHash<EntityPropertyList, QString>& _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());
}

View file

@ -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 <stdint.h>
#include <glm/glm.hpp>
#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<QString> &namesSet, bool& _defaultSettings) override;
void merge(const AnimationPropertyGroup& other);
virtual void debugDump() const override;
virtual void listChangedProperties(QList<QString>& out) override;
virtual bool appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const override;
virtual bool decodeFromEditPacket(EntityPropertyFlags& propertyFlags,
const unsigned char*& dataAt, int& processedBytes) override;
virtual void markAllChanged() override;
virtual EntityPropertyFlags getChangedProperties() const override;
// EntityItem related helpers
// methods for getting/setting all properties of an entity
virtual void getProperties(EntityItemProperties& propertiesOut) const override;
/// returns true if something changed
virtual bool setProperties(const EntityItemProperties& properties) override;
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override;
virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const override;
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override;
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

View file

@ -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 <stdint.h>
#include <glm/glm.hpp>
#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

View file

@ -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 <OctreePacketData.h>
#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<QString> &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<QString>& out) {
if (bloomIntensityChanged()) {
out << "bloom-bloomIntensity";
}
if (bloomThresholdChanged()) {
out << "bloom-bloomThreshold";
}
if (bloomSizeChanged()) {
out << "bloom-bloomSize";
}
}
bool BloomPropertyGroup::appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, getBloomIntensity());
APPEND_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, getBloomThreshold());
APPEND_ENTITY_PROPERTY(PROP_BLOOM_SIZE, getBloomSize());
return true;
}
bool BloomPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) {
int bytesRead = 0;
bool overwriteLocalData = true;
bool somethingChanged = false;
READ_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, float, setBloomIntensity);
READ_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, float, setBloomThreshold);
READ_ENTITY_PROPERTY(PROP_BLOOM_SIZE, float, setBloomSize);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_BLOOM_INTENSITY, BloomIntensity);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_BLOOM_THRESHOLD, BloomThreshold);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_BLOOM_SIZE, BloomSize);
processedBytes += bytesRead;
Q_UNUSED(somethingChanged);
return true;
}
void BloomPropertyGroup::markAllChanged() {
_bloomIntensityChanged = true;
_bloomThresholdChanged = true;
_bloomSizeChanged = true;
}
EntityPropertyFlags BloomPropertyGroup::getChangedProperties() const {
EntityPropertyFlags changedProperties;
CHECK_PROPERTY_CHANGE(PROP_BLOOM_INTENSITY, bloomIntensity);
CHECK_PROPERTY_CHANGE(PROP_BLOOM_THRESHOLD, bloomThreshold);
CHECK_PROPERTY_CHANGE(PROP_BLOOM_SIZE, bloomSize);
return changedProperties;
}
void BloomPropertyGroup::getProperties(EntityItemProperties& properties) const {
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Bloom, BloomIntensity, getBloomIntensity);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Bloom, BloomThreshold, getBloomThreshold);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Bloom, BloomSize, getBloomSize);
}
bool BloomPropertyGroup::setProperties(const EntityItemProperties& properties) {
bool somethingChanged = false;
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Bloom, BloomIntensity, bloomIntensity, setBloomIntensity);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Bloom, BloomThreshold, bloomThreshold, setBloomThreshold);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Bloom, BloomSize, bloomSize, setBloomSize);
return somethingChanged;
}
EntityPropertyFlags BloomPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const {
EntityPropertyFlags requestedProperties;
requestedProperties += PROP_BLOOM_INTENSITY;
requestedProperties += PROP_BLOOM_THRESHOLD;
requestedProperties += PROP_BLOOM_SIZE;
return requestedProperties;
}
void BloomPropertyGroup::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, getBloomIntensity());
APPEND_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, getBloomThreshold());
APPEND_ENTITY_PROPERTY(PROP_BLOOM_SIZE, getBloomSize());
}
int BloomPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) {
int bytesRead = 0;
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, float, setBloomIntensity);
READ_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, float, setBloomThreshold);
READ_ENTITY_PROPERTY(PROP_BLOOM_SIZE, float, setBloomSize);
return bytesRead;
}

View file

@ -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 <OctreePacketData.h>
#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<QString> &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<QString>& 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<QString, EntityPropertyInfo>& _propertyInfos,
QHash<EntityPropertyList, QString>& _enumsToPropertyStrings) {
@Bloom_GROUP_ADD_TO_MAP@
}

View file

@ -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 <stdint.h>
#include <glm/glm.hpp>
#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<QString> &namesSet, bool& _defaultSettings) override;
void merge(const BloomPropertyGroup& other);
virtual void debugDump() const override;
virtual void listChangedProperties(QList<QString>& out) override;
virtual bool appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const override;
virtual bool decodeFromEditPacket(EntityPropertyFlags& propertyFlags,
const unsigned char*& dataAt, int& processedBytes) override;
virtual void markAllChanged() override;
virtual EntityPropertyFlags getChangedProperties() const override;
// EntityItem related helpers
// methods for getting/setting all properties of an entity
virtual void getProperties(EntityItemProperties& propertiesOut) const override;
/// returns true if something changed
virtual bool setProperties(const EntityItemProperties& properties) override;
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override;
virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const override;
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override;
DEFINE_PROPERTY(PROP_BLOOM_INTENSITY, BloomIntensity, bloomIntensity, float, INITIAL_BLOOM_INTENSITY);
DEFINE_PROPERTY(PROP_BLOOM_THRESHOLD, BloomThreshold, bloomThreshold, float, INITIAL_BLOOM_THRESHOLD);
DEFINE_PROPERTY(PROP_BLOOM_SIZE, BloomSize, bloomSize, float, INITIAL_BLOOM_SIZE);
};
#endif // hifi_BloomPropertyGroup_h

View file

@ -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 <stdint.h>
#include <glm/glm.hpp>
#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

View file

@ -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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
bool needsRenderUpdate() const { return _needsRenderUpdate; }
void setNeedsRenderUpdate(bool needsRenderUpdate) { _needsRenderUpdate = needsRenderUpdate; }
void setRenderWithZones(const QVector<QUuid>& renderWithZones);
QVector<QUuid> 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<int32_t, glm::vec4> data);
protected:
@Base_ENTITY_PROPS@
QHash<ChangeHandlerId, ChangeHandlerCallback> _changeHandlers;
void somethingChangedNotification();
@ -581,12 +473,10 @@ protected:
// 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 @@ protected:
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 @@ protected:
// 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 @@ protected:
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 @@ protected:
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<QUuid> _cloneIDs;
GrabPropertyGroup _grabProperties;
QHash<QUuid, EntityDynamicPointer> _grabActions;
QVector<QUuid> _renderWithZones;
mutable bool _needsZoneOcclusionUpdate { false };
BillboardMode _billboardMode { BillboardMode::NONE };
bool _cullWithParent { false };
mutable bool _needsRenderUpdate { false };

View file

@ -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<QUuid>(),
enum:LISTENER_ATTENUATION_COEFFICIENTS prop:listenerAttenuationCoefficients type:qVectorFloat default:QVector<float>(),
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,

Some files were not shown because too many files have changed in this diff Show more