mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge pull request #1096 from overte-org/protocol_changes
Protocol changes -> master
This commit is contained in:
commit
ce8d57b4be
348 changed files with 15305 additions and 17221 deletions
|
@ -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()
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -316,6 +316,7 @@ void EntityScriptServer::run() {
|
|||
entityScriptingInterface->setEntityTree(_entityViewer.getTree());
|
||||
|
||||
auto treePtr = _entityViewer.getTree();
|
||||
treePtr->setIsServer(true);
|
||||
DependencyManager::set<AssignmentParentFinder>(treePtr);
|
||||
|
||||
if (!_entitySimulation) {
|
||||
|
|
625
cmake/macros/GenerateEntityProperties.cmake
Normal file
625
cmake/macros/GenerateEntityProperties.cmake
Normal 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()
|
|
@ -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)
|
|
@ -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()
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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] + "%"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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] + "%"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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>();
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#include "PathPointer.h"
|
||||
|
||||
#include<EntityItemProperties.h>
|
||||
#include <EntityItemProperties.h>
|
||||
|
||||
#include <render/Item.h>
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>> 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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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([&] {
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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([&] {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()}]);
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#define hifi_RenderablePolyLineEntityItem_h
|
||||
|
||||
#include "RenderableEntityItem.h"
|
||||
#include <PolyLineEntityItem.h>
|
||||
#include <TextureCache.h>
|
||||
|
||||
namespace render { namespace entities {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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>() };
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
DEFINES translucent:f forward:f
|
172
libraries/entities-renderer/src/proceduralParticle.slf
Normal file
172
libraries/entities-renderer/src/proceduralParticle.slf
Normal 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@>
|
||||
}
|
38
libraries/entities-renderer/src/proceduralParticle.slv
Normal file
38
libraries/entities-renderer/src/proceduralParticle.slv
Normal 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)$>
|
||||
}
|
107
libraries/entities-renderer/src/proceduralParticleUpdate.slf
Normal file
107
libraries/entities-renderer/src/proceduralParticleUpdate.slf
Normal 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
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
139
libraries/entities/src/AmbientLightPropertyGroup.cpp.in
Normal file
139
libraries/entities/src/AmbientLightPropertyGroup.cpp.in
Normal 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@
|
||||
|
||||
}
|
|
@ -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
|
56
libraries/entities/src/AmbientLightPropertyGroup.h.in
Normal file
56
libraries/entities/src/AmbientLightPropertyGroup.h.in
Normal 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
|
149
libraries/entities/src/AmbientOcclusionPropertyGroup.cpp.in
Normal file
149
libraries/entities/src/AmbientOcclusionPropertyGroup.cpp.in
Normal 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@
|
||||
|
||||
}
|
58
libraries/entities/src/AmbientOcclusionPropertyGroup.h.in
Normal file
58
libraries/entities/src/AmbientOcclusionPropertyGroup.h.in
Normal 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
|
|
@ -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());
|
||||
}
|
261
libraries/entities/src/AnimationPropertyGroup.cpp.in
Normal file
261
libraries/entities/src/AnimationPropertyGroup.cpp.in
Normal 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());
|
||||
}
|
|
@ -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
|
52
libraries/entities/src/AnimationPropertyGroup.h.in
Normal file
52
libraries/entities/src/AnimationPropertyGroup.h.in
Normal 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
|
|
@ -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;
|
||||
}
|
134
libraries/entities/src/BloomPropertyGroup.cpp.in
Normal file
134
libraries/entities/src/BloomPropertyGroup.cpp.in
Normal 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@
|
||||
|
||||
}
|
|
@ -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
|
52
libraries/entities/src/BloomPropertyGroup.h.in
Normal file
52
libraries/entities/src/BloomPropertyGroup.h.in
Normal 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
|
File diff suppressed because it is too large
Load diff
|
@ -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 };
|
101
libraries/entities/src/EntityItemGroupProperties.txt
Normal file
101
libraries/entities/src/EntityItemGroupProperties.txt
Normal 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
Loading…
Reference in a new issue