"Custom" | Custom refresh rate for full control over the refresh rate in all states.
*
*
* @typedef {string} RefreshRateProfileName
*/
static const std::array REFRESH_RATE_PROFILE_TO_STRING =
- { { "Eco", "Interactive", "Realtime" } };
+ { { "Eco", "Interactive", "Realtime", "Custom" } };
/*@jsdoc
* Interface states that affect the refresh rate.
@@ -94,7 +95,8 @@ static const std::array UX_MODE
static const std::map REFRESH_RATE_PROFILE_FROM_STRING =
{ { "Eco", RefreshRateManager::RefreshRateProfile::ECO },
{ "Interactive", RefreshRateManager::RefreshRateProfile::INTERACTIVE },
- { "Realtime", RefreshRateManager::RefreshRateProfile::REALTIME } };
+ { "Realtime", RefreshRateManager::RefreshRateProfile::REALTIME },
+ { "Custom", RefreshRateManager::RefreshRateProfile::CUSTOM } };
// Porfile regimes are:
@@ -107,10 +109,12 @@ static const std::array
{ { 30, 20, 10, 2, 30, 30 } };
static const std::array REALTIME_PROFILE =
- { { 60, 60, 60, 2, 30, 30} };
+ { { 60, 60, 60, 2, 30, 30 } };
-static const std::array, RefreshRateManager::RefreshRateProfile::PROFILE_NUM> REFRESH_RATE_PROFILES =
- { { ECO_PROFILE, INTERACTIVE_PROFILE, REALTIME_PROFILE } };
+static const std::array CUSTOM_PROFILE = REALTIME_PROFILE; // derived from settings and modified by scripts below
+
+static std::array, RefreshRateManager::RefreshRateProfile::PROFILE_NUM> REFRESH_RATE_PROFILES =
+ { { ECO_PROFILE, INTERACTIVE_PROFILE, REALTIME_PROFILE, CUSTOM_PROFILE } };
static const int INACTIVE_TIMER_LIMIT = 3000;
@@ -134,6 +138,10 @@ std::string RefreshRateManager::uxModeToString(RefreshRateManager::RefreshRateMa
RefreshRateManager::RefreshRateManager() {
_refreshRateProfile = (RefreshRateManager::RefreshRateProfile) _refreshRateProfileSetting.get();
+ for (size_t i = 0; i < _customRefreshRateSettings.size(); i++) {
+ REFRESH_RATE_PROFILES[CUSTOM][i] = _customRefreshRateSettings[i].get();
+ }
+
_inactiveTimer->setInterval(INACTIVE_TIMER_LIMIT);
_inactiveTimer->setSingleShot(true);
QObject::connect(_inactiveTimer.get(), &QTimer::timeout, [&] {
@@ -168,6 +176,25 @@ void RefreshRateManager::setRefreshRateProfile(RefreshRateManager::RefreshRatePr
}
}
+int RefreshRateManager::getCustomRefreshRate(RefreshRateRegime regime) {
+ if (isValidRefreshRateRegime(regime)) {
+ return REFRESH_RATE_PROFILES[RefreshRateProfile::CUSTOM][regime];
+ }
+
+ return 0;
+}
+
+void RefreshRateManager::setCustomRefreshRate(RefreshRateRegime regime, int value) {
+ value = std::max(value, 1);
+ if (isValidRefreshRateRegime(regime)) {
+ _refreshRateProfileSettingLock.withWriteLock([&] {
+ REFRESH_RATE_PROFILES[RefreshRateProfile::CUSTOM][regime] = value;
+ _customRefreshRateSettings[regime].set(value);
+ });
+ updateRefreshRateController();
+ }
+}
+
RefreshRateManager::RefreshRateProfile RefreshRateManager::getRefreshRateProfile() const {
RefreshRateManager::RefreshRateProfile profile = RefreshRateManager::RefreshRateProfile::REALTIME;
@@ -191,7 +218,6 @@ void RefreshRateManager::setRefreshRateRegime(RefreshRateManager::RefreshRateReg
_refreshRateRegime = refreshRateRegime;
updateRefreshRateController();
}
-
}
void RefreshRateManager::setUXMode(RefreshRateManager::UXMode uxMode) {
diff --git a/interface/src/RefreshRateManager.h b/interface/src/RefreshRateManager.h
index 4b91f0c45e..6b94a94a4a 100644
--- a/interface/src/RefreshRateManager.h
+++ b/interface/src/RefreshRateManager.h
@@ -32,10 +32,11 @@ public:
ECO = 0,
INTERACTIVE,
REALTIME,
+ CUSTOM,
PROFILE_NUM
};
Q_ENUM(RefreshRateProfile)
- static bool isValidRefreshRateProfile(RefreshRateProfile value) { return (value >= RefreshRateProfile::ECO && value <= RefreshRateProfile::REALTIME); }
+ static bool isValidRefreshRateProfile(RefreshRateProfile value) { return (value >= 0 && value < RefreshRateProfile::PROFILE_NUM); }
/*@jsdoc
* Interface states that affect the refresh rate.
@@ -106,6 +107,9 @@ public:
// query the refresh rate target at the specified combination
int queryRefreshRateTarget(RefreshRateProfile profile, RefreshRateRegime regime, UXMode uxMode) const;
+ int getCustomRefreshRate(RefreshRateRegime regime);
+ void setCustomRefreshRate(RefreshRateRegime regime, int value);
+
void resetInactiveTimer();
void toggleInactive();
@@ -121,7 +125,15 @@ private:
UXMode _uxMode { UXMode::DESKTOP };
mutable ReadWriteLockable _refreshRateProfileSettingLock;
- Setting::Handle _refreshRateProfileSetting { "refreshRateProfile", RefreshRateProfile::INTERACTIVE };
+ Setting::Handle _refreshRateProfileSetting{ "refreshRateProfile", RefreshRateProfile::INTERACTIVE };
+ std::array, REGIME_NUM> _customRefreshRateSettings { {
+ { "customRefreshRateFocusActive", 60 },
+ { "customRefreshRateFocusInactive", 60 },
+ { "customRefreshRateUnfocus", 60 },
+ { "customRefreshRateMinimized", 2 },
+ { "customRefreshRateStartup", 30 },
+ { "customRefreshRateShutdown", 30 }
+ } };
std::function _refreshRateOperator { nullptr };
diff --git a/interface/src/avatar/AvatarDoctor.cpp b/interface/src/avatar/AvatarDoctor.cpp
index 5c2fc01911..a46652c7d9 100644
--- a/interface/src/avatar/AvatarDoctor.cpp
+++ b/interface/src/avatar/AvatarDoctor.cpp
@@ -333,6 +333,14 @@ void AvatarDoctor::diagnoseTextures() {
addTextureToList(material.occlusionTexture);
addTextureToList(material.scatteringTexture);
addTextureToList(material.lightmapTexture);
+
+ if (material.isMToonMaterial) {
+ addTextureToList(material.shadeTexture);
+ addTextureToList(material.shadingShiftTexture);
+ addTextureToList(material.matcapTexture);
+ addTextureToList(material.rimTexture);
+ addTextureToList(material.uvAnimationTexture);
+ }
}
for (const auto& materialMapping : model->getMaterialMapping()) {
diff --git a/interface/src/avatar/AvatarMotionState.cpp b/interface/src/avatar/AvatarMotionState.cpp
index 97085c8443..362ac579a9 100644
--- a/interface/src/avatar/AvatarMotionState.cpp
+++ b/interface/src/avatar/AvatarMotionState.cpp
@@ -27,6 +27,10 @@ void AvatarMotionState::handleEasyChanges(uint32_t& flags) {
if (flags & Simulation::DIRTY_PHYSICS_ACTIVATION && !_body->isActive()) {
_body->activate();
}
+
+ if (flags & Simulation::DIRTY_MASS) {
+ updateBodyMassProperties();
+ }
}
AvatarMotionState::~AvatarMotionState() {
diff --git a/interface/src/avatar/AvatarProject.cpp b/interface/src/avatar/AvatarProject.cpp
index 466db613f6..cf41c0a040 100644
--- a/interface/src/avatar/AvatarProject.cpp
+++ b/interface/src/avatar/AvatarProject.cpp
@@ -136,6 +136,14 @@ AvatarProject* AvatarProject::createAvatarProject(const QString& projectsFolder,
addTextureToList(material.occlusionTexture);
addTextureToList(material.scatteringTexture);
addTextureToList(material.lightmapTexture);
+
+ if (material.isMToonMaterial) {
+ addTextureToList(material.shadeTexture);
+ addTextureToList(material.shadingShiftTexture);
+ addTextureToList(material.matcapTexture);
+ addTextureToList(material.rimTexture);
+ addTextureToList(material.uvAnimationTexture);
+ }
}
QDir textureDir(textureFolder.isEmpty() ? fbxInfo.absoluteDir() : textureFolder);
diff --git a/interface/src/avatar/DetailedMotionState.cpp b/interface/src/avatar/DetailedMotionState.cpp
index 02a2b9d425..a22d533bc9 100644
--- a/interface/src/avatar/DetailedMotionState.cpp
+++ b/interface/src/avatar/DetailedMotionState.cpp
@@ -31,6 +31,10 @@ void DetailedMotionState::handleEasyChanges(uint32_t& flags) {
if (flags & Simulation::DIRTY_PHYSICS_ACTIVATION && !_body->isActive()) {
_body->activate();
}
+
+ if (flags & Simulation::DIRTY_MASS) {
+ updateBodyMassProperties();
+ }
}
DetailedMotionState::~DetailedMotionState() {
diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index bb6fbcd899..0c61b0d01a 100644
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -73,6 +73,7 @@
#include "MovingEntitiesOperator.h"
#include "SceneScriptingInterface.h"
#include "WarningsSuppression.h"
+#include "ScriptPermissions.h"
using namespace std;
@@ -226,7 +227,7 @@ MyAvatar::MyAvatar(QThread* thread) :
_yawSpeedSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "yawSpeed", _yawSpeed),
_hmdYawSpeedSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "hmdYawSpeed", _hmdYawSpeed),
_pitchSpeedSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "pitchSpeed", _pitchSpeed),
- _fullAvatarURLSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "fullAvatarURL",
+ _fullAvatarURLSetting(QStringList() << SETTINGS_FULL_PRIVATE_GROUP_NAME << AVATAR_SETTINGS_GROUP_NAME << "fullAvatarURL",
AvatarData::defaultFullAvatarModelUrl()),
_fullAvatarModelNameSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "fullAvatarModelName", _fullAvatarModelName),
_animGraphURLSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "animGraphURL", QUrl("")),
@@ -1035,8 +1036,8 @@ void MyAvatar::simulate(float deltaTime, bool inView) {
std::pair zoneInteractionProperties;
entityTree->withWriteLock([&] {
zoneInteractionProperties = entityTreeRenderer->getZoneInteractionProperties();
- EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender();
- entityTree->updateEntityQueryAACube(shared_from_this(), packetSender, false, true);
+ std::shared_ptr packetSender = qApp->getEntityEditPacketSender();
+ entityTree->updateEntityQueryAACube(shared_from_this(), packetSender.get(), false, true);
});
bool isPhysicsEnabled = qApp->isPhysicsEnabled();
bool zoneAllowsFlying = zoneInteractionProperties.first;
@@ -1729,7 +1730,7 @@ void MyAvatar::handleChangedAvatarEntityData() {
entityTree->deleteEntitiesByID(entitiesToDelete);
// ADD real entities
- EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender();
+ auto packetSender = qApp->getEntityEditPacketSender();
for (const auto& id : entitiesToAdd) {
bool blobFailed = false;
EntityItemProperties properties;
@@ -1739,10 +1740,11 @@ void MyAvatar::handleChangedAvatarEntityData() {
blobFailed = true; // blob doesn't exist
return;
}
- std::lock_guard guard(_scriptEngineLock);
- if (!EntityItemProperties::blobToProperties(*_scriptEngine, itr.value(), properties)) {
- blobFailed = true; // blob is corrupt
- }
+ _helperScriptEngine.run( [&] {
+ if (!EntityItemProperties::blobToProperties(*_helperScriptEngine.get(), itr.value(), properties)) {
+ blobFailed = true; // blob is corrupt
+ }
+ });
});
if (blobFailed) {
// remove from _cachedAvatarEntityBlobUpdatesToSkip just in case:
@@ -1775,10 +1777,11 @@ void MyAvatar::handleChangedAvatarEntityData() {
skip = true;
return;
}
- std::lock_guard guard(_scriptEngineLock);
- if (!EntityItemProperties::blobToProperties(*_scriptEngine, itr.value(), properties)) {
- skip = true;
- }
+ _helperScriptEngine.run( [&] {
+ if (!EntityItemProperties::blobToProperties(*_helperScriptEngine.get(), itr.value(), properties)) {
+ skip = true;
+ }
+ });
});
if (!skip && canRezAvatarEntites) {
sanitizeAvatarEntityProperties(properties);
@@ -1883,10 +1886,9 @@ bool MyAvatar::updateStaleAvatarEntityBlobs() const {
if (found) {
++numFound;
QByteArray blob;
- {
- std::lock_guard guard(_scriptEngineLock);
- EntityItemProperties::propertiesToBlob(*_scriptEngine, getID(), properties, blob);
- }
+ _helperScriptEngine.run( [&] {
+ EntityItemProperties::propertiesToBlob(*_helperScriptEngine.get(), getID(), properties, blob);
+ });
_avatarEntitiesLock.withWriteLock([&] {
_cachedAvatarEntityBlobs[id] = blob;
});
@@ -1947,10 +1949,9 @@ AvatarEntityMap MyAvatar::getAvatarEntityData() const {
EntityItemProperties properties = entity->getProperties(desiredProperties);
QByteArray blob;
- {
- std::lock_guard guard(_scriptEngineLock);
- EntityItemProperties::propertiesToBlob(*_scriptEngine, getID(), properties, blob, true);
- }
+ _helperScriptEngine.run( [&] {
+ EntityItemProperties::propertiesToBlob(*_helperScriptEngine.get(), getID(), properties, blob, true);
+ });
data[entityID] = blob;
}
@@ -2092,9 +2093,6 @@ void MyAvatar::avatarEntityDataToJson(QJsonObject& root) const {
}
void MyAvatar::loadData() {
- if (!_scriptEngine) {
- _scriptEngine = newScriptEngine();
- }
getHead()->setBasePitch(_headPitchSetting.get());
_yawSpeed = _yawSpeedSetting.get(_yawSpeed);
@@ -2236,6 +2234,9 @@ AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL, const QString&
return attachment;
}
+bool MyAvatar::isMyAvatarURLProtected() const {
+ return !ScriptPermissions::isCurrentScriptAllowed(ScriptPermissions::Permission::SCRIPT_PERMISSION_GET_AVATAR_URL);
+}
int MyAvatar::parseDataFromBuffer(const QByteArray& buffer) {
qCDebug(interfaceapp) << "Error: ignoring update packet for MyAvatar"
@@ -2700,11 +2701,10 @@ QVariantList MyAvatar::getAvatarEntitiesVariant() {
QVariantMap avatarEntityData;
avatarEntityData["id"] = entityID;
EntityItemProperties entityProperties = entity->getProperties(desiredProperties);
- {
- std::lock_guard guard(_scriptEngineLock);
- ScriptValue scriptProperties = EntityItemPropertiesToScriptValue(_scriptEngine.get(), entityProperties);
+ _helperScriptEngine.run( [&] {
+ ScriptValue scriptProperties = EntityItemPropertiesToScriptValue(_helperScriptEngine.get(), entityProperties);
avatarEntityData["properties"] = scriptProperties.toVariant();
- }
+ });
avatarEntitiesData.append(QVariant(avatarEntityData));
}
}
@@ -4232,7 +4232,7 @@ void MyAvatar::setSessionUUID(const QUuid& sessionUUID) {
_avatarEntitiesLock.withReadLock([&] {
avatarEntityIDs = _packedAvatarEntityData.keys();
});
- EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender();
+ auto packetSender = qApp->getEntityEditPacketSender();
entityTree->withWriteLock([&] {
for (const auto& entityID : avatarEntityIDs) {
auto entity = entityTree->findEntityByID(entityID);
@@ -5769,8 +5769,7 @@ void MyAvatar::FollowHelper::deactivate() {
}
void MyAvatar::FollowHelper::deactivate(CharacterController::FollowType type) {
- int int_type = static_cast(type);
- assert(int_type >= 0 && int_type < static_cast(CharacterController::FollowType::Count));
+ assert(type < CharacterController::FollowType::Count);
_timeRemaining[(int)type] = 0.0f;
}
@@ -5778,16 +5777,14 @@ void MyAvatar::FollowHelper::deactivate(CharacterController::FollowType type) {
// eg. activate(FollowType::Rotation, true) snaps the FollowHelper's rotation immediately
// to the rotation of its _followDesiredBodyTransform.
void MyAvatar::FollowHelper::activate(CharacterController::FollowType type, const bool snapFollow) {
- int int_type = static_cast(type);
- assert(int_type >= 0 && int_type < static_cast(CharacterController::FollowType::Count));
+ assert(type < CharacterController::FollowType::Count);
// TODO: Perhaps, the follow time should be proportional to the displacement.
_timeRemaining[(int)type] = snapFollow ? CharacterController::FOLLOW_TIME_IMMEDIATE_SNAP : FOLLOW_TIME;
}
bool MyAvatar::FollowHelper::isActive(CharacterController::FollowType type) const {
- int int_type = static_cast(type);
- assert(int_type >= 0 && int_type < static_cast(CharacterController::FollowType::Count));
+ assert(type < CharacterController::FollowType::Count);
return _timeRemaining[(int)type] > 0.0f;
}
@@ -6889,7 +6886,7 @@ void MyAvatar::sendPacket(const QUuid& entityID) const {
if (entityTree) {
entityTree->withWriteLock([&] {
// force an update packet
- EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender();
+ auto packetSender = qApp->getEntityEditPacketSender();
packetSender->queueEditAvatarEntityMessage(entityTree, entityID);
});
}
diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h
index 5e0627360c..60c07ad42c 100644
--- a/interface/src/avatar/MyAvatar.h
+++ b/interface/src/avatar/MyAvatar.h
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -2683,6 +2684,7 @@ private:
void setEnableDrawAverageFacing(bool drawAverage) { _drawAverageFacingEnabled = drawAverage; }
bool getEnableDrawAverageFacing() const { return _drawAverageFacingEnabled; }
virtual bool isMyAvatar() const override { return true; }
+ virtual bool isMyAvatarURLProtected() const override;
virtual int parseDataFromBuffer(const QByteArray& buffer) override;
virtual glm::vec3 getSkeletonPosition() const override;
int _skeletonModelChangeCount { 0 };
@@ -3101,8 +3103,10 @@ private:
mutable std::set _staleCachedAvatarEntityBlobs;
//
// keep a ScriptEngine around so we don't have to instantiate on the fly (these are very slow to create/delete)
- mutable std::mutex _scriptEngineLock;
- ScriptEnginePointer _scriptEngine { nullptr };
+ // TODO: profile if it performs better when script engine is on avatar thread or on its own thread
+ // Own thread is safer from deadlocks
+ mutable HelperScriptEngine _helperScriptEngine;
+
bool _needToSaveAvatarEntitySettings { false };
bool _reactionTriggers[NUM_AVATAR_TRIGGER_REACTIONS] { false, false };
diff --git a/interface/src/graphics/GraphicsEngine.cpp b/interface/src/graphics/GraphicsEngine.cpp
index bf69efd23e..5075d9b57f 100644
--- a/interface/src/graphics/GraphicsEngine.cpp
+++ b/interface/src/graphics/GraphicsEngine.cpp
@@ -281,7 +281,7 @@ void GraphicsEngine::render_performFrame() {
{
PROFILE_RANGE(render, "/runRenderFrame");
- renderArgs._hudOperator = displayPlugin->getHUDOperator();
+ renderArgs._hudOperator = qApp->getApplicationOverlay().enabled() ? displayPlugin->getHUDOperator() : nullptr;
renderArgs._hudTexture = qApp->getApplicationOverlay().getOverlayTexture();
renderArgs._takingSnapshot = qApp->takeSnapshotOperators(snapshotOperators);
renderArgs._blitFramebuffer = finalFramebuffer;
diff --git a/interface/src/main.cpp b/interface/src/main.cpp
index 835e4060a7..7e8c1afff3 100644
--- a/interface/src/main.cpp
+++ b/interface/src/main.cpp
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include "AddressManager.h"
#include "Application.h"
@@ -33,6 +34,9 @@
#include "MainWindow.h"
#include "Profile.h"
#include "LogHandler.h"
+#include
+#include
+#include
#ifdef Q_OS_WIN
#include
@@ -63,11 +67,24 @@ int main(int argc, const char* argv[]) {
}
#endif
+ // Setup QCoreApplication settings, install log message handler
setupHifiApplication(BuildInfo::INTERFACE_NAME);
// Journald by default in user applications is probably a bit too modern still.
LogHandler::getInstance().setShouldUseJournald(false);
+
+ // Extend argv to enable WebGL rendering
+ std::vector argvExtended(&argv[0], &argv[argc]);
+ argvExtended.push_back("--ignore-gpu-blocklist");
+#ifdef Q_OS_ANDROID
+ argvExtended.push_back("--suppress-settings-reset");
+#endif
+ int argcExtended = (int)argvExtended.size();
+
+ QElapsedTimer startupTime;
+ startupTime.start();
+
QCommandLineParser parser;
parser.setApplicationDescription("Overte -- A free/libre and open-source virtual worlds client");
QCommandLineOption helpOption = parser.addHelpOption();
@@ -125,12 +142,12 @@ int main(int argc, const char* argv[]) {
"displays"
);
QCommandLineOption disableDisplaysOption(
- "disable-displays",
+ "disableDisplayPlugins",
"Displays to disable. Valid options include \"OpenVR (Vive)\" and \"Oculus Rift\"",
"string"
);
QCommandLineOption disableInputsOption(
- "disable-inputs",
+ "disableInputPlugins",
"Inputs to disable. Valid options include \"OpenVR (Vive)\" and \"Oculus Rift\"",
"string"
);
@@ -246,6 +263,19 @@ int main(int argc, const char* argv[]) {
"Logging options, comma separated: color,nocolor,process_id,thread_id,milliseconds,keep_repeats,journald,nojournald",
"options"
);
+ QCommandLineOption getPluginsOption(
+ "getPlugins",
+ "Print out a list of plugins in JSON"
+ );
+ QCommandLineOption abortAfterStartupOption(
+ "abortAfterStartup",
+ "Debug option. Aborts right after startup."
+ );
+ QCommandLineOption abortAfterInitOption(
+ "abortAfterInit",
+ "Debug option. Aborts after initialization, right before the program starts running the event loop."
+ );
+
// "--qmljsdebugger", which appears in output from "--help-all".
// Those below don't seem to be optional.
// --ignore-gpu-blacklist
@@ -288,6 +318,10 @@ int main(int argc, const char* argv[]) {
parser.addOption(quitWhenFinishedOption);
parser.addOption(fastHeartbeatOption);
parser.addOption(logOption);
+ parser.addOption(abortAfterStartupOption);
+ parser.addOption(abortAfterInitOption);
+ parser.addOption(getPluginsOption);
+
QString applicationPath;
// A temporary application instance is needed to get the location of the running executable
@@ -310,6 +344,16 @@ int main(int argc, const char* argv[]) {
#endif
}
+ // TODO: We need settings for Application, but Settings needs an Application
+ // to handle events. Needs splitting into two parts: enough initialization
+ // for Application to work, and then thread start afterwards.
+ Setting::init();
+ Application app(argcExtended, const_cast(argvExtended.data()), parser, startupTime);
+
+ if (parser.isSet("abortAfterStartup")) {
+ return 99;
+ }
+
// We want to configure the logging system as early as possible
auto& logHandler = LogHandler::getInstance();
@@ -321,6 +365,75 @@ int main(int argc, const char* argv[]) {
}
}
+ app.initializePluginManager(parser);
+
+ if (parser.isSet(getPluginsOption)) {
+ auto pluginManager = PluginManager::getInstance();
+
+ QJsonObject pluginsJson;
+ for (const auto &plugin : pluginManager->getPluginInfo()) {
+ QJsonObject data;
+ data["data"] = plugin.metaData;
+ data["loaded"] = plugin.loaded;
+ data["disabled"] = plugin.disabled;
+ data["filteredOut"] = plugin.filteredOut;
+ data["wrongVersion"] = plugin.wrongVersion;
+ pluginsJson[plugin.name] = data;
+ }
+
+ QJsonObject inputJson;
+ for (const auto &plugin : pluginManager->getInputPlugins()) {
+ QJsonObject data;
+ data["subdeviceNames"] = QJsonArray::fromStringList(plugin->getSubdeviceNames());
+ data["deviceName"] = plugin->getDeviceName();
+ data["configurable"] = plugin->configurable();
+ data["isHandController"] = plugin->isHandController();
+ data["isHeadController"] = plugin->isHeadController();
+ data["isActive"] = plugin->isActive();
+ data["isSupported"] = plugin->isSupported();
+
+ inputJson[plugin->getName()] = data;
+ }
+
+ QJsonObject displayJson;
+ for (const auto &plugin : pluginManager->getDisplayPlugins()) {
+ QJsonObject data;
+ data["isHmd"] = plugin->isHmd();
+ data["isStereo"] = plugin->isStereo();
+ data["targetFramerate"] = plugin->getTargetFrameRate();
+ data["hasAsyncReprojection"] = plugin->hasAsyncReprojection();
+ data["isActive"] = plugin->isActive();
+ data["isSupported"] = plugin->isSupported();
+
+ displayJson[plugin->getName()] = data;
+ }
+
+ QJsonObject codecsJson;
+ for (const auto &plugin : pluginManager->getCodecPlugins()) {
+ QJsonObject data;
+ data["isActive"] = plugin->isActive();
+ data["isSupported"] = plugin->isSupported();
+
+ codecsJson[plugin->getName()] = data;
+ }
+
+ QJsonObject platformsJson;
+ platformsJson["steamAvailable"] = (pluginManager->getSteamClientPlugin() != nullptr);
+ platformsJson["oculusAvailable"] = (pluginManager->getOculusPlatformPlugin() != nullptr);
+
+ QJsonObject root;
+ root["plugins"] = pluginsJson;
+ root["inputs"] = inputJson;
+ root["displays"] = displayJson;
+ root["codecs"] = codecsJson;
+ root["platforms"] = platformsJson;
+
+ std::cout << QJsonDocument(root).toJson().toStdString() << "\n";
+
+ return 0;
+ }
+
+
// Act on arguments for early termination.
if (parser.isSet(versionOption)) {
parser.showVersion();
@@ -407,10 +520,9 @@ int main(int argc, const char* argv[]) {
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
#endif
- QElapsedTimer startupTime;
- startupTime.start();
- Setting::init();
+
+
// Instance UserActivityLogger now that the settings are loaded
auto& ual = UserActivityLogger::getInstance();
@@ -549,7 +661,7 @@ int main(int argc, const char* argv[]) {
// Oculus initialization MUST PRECEDE OpenGL context creation.
// The nature of the Application constructor means this has to be either here,
// or in the main window ctor, before GL startup.
- Application::initPlugins(parser);
+ //app.configurePlugins(parser);
#ifdef Q_OS_WIN
// If we're running in steam mode, we need to do an explicit check to ensure we're up to the required min spec
@@ -587,17 +699,10 @@ int main(int argc, const char* argv[]) {
SandboxUtils::runLocalSandbox(serverContentPath, true, noUpdater);
}
- // Extend argv to enable WebGL rendering
- std::vector argvExtended(&argv[0], &argv[argc]);
- argvExtended.push_back("--ignore-gpu-blocklist");
-#ifdef Q_OS_ANDROID
- argvExtended.push_back("--suppress-settings-reset");
-#endif
- int argcExtended = (int)argvExtended.size();
-
PROFILE_SYNC_END(startup, "main startup", "");
PROFILE_SYNC_BEGIN(startup, "app full ctor", "");
- Application app(argcExtended, const_cast(argvExtended.data()), parser, startupTime, runningMarkerExisted);
+ app.setPreviousSessionCrashed(runningMarkerExisted);
+ app.initialize(parser);
PROFILE_SYNC_END(startup, "app full ctor", "");
#if defined(Q_OS_LINUX)
@@ -665,6 +770,9 @@ int main(int argc, const char* argv[]) {
translator.load("i18n/interface_en");
app.installTranslator(&translator);
qCDebug(interfaceapp, "Created QT Application.");
+ if (parser.isSet("abortAfterInit")) {
+ return 99;
+ }
exitCode = app.exec();
server.close();
diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp
index ce44d3011c..91af721ea6 100644
--- a/interface/src/raypick/LaserPointer.cpp
+++ b/interface/src/raypick/LaserPointer.cpp
@@ -137,12 +137,12 @@ LaserPointer::RenderState::RenderState(const QUuid& startID, const QUuid& pathID
{
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_IGNORE_PICK_INTERSECTION;
- _pathIgnorePicks = entityScriptingInterface->getEntityPropertiesInternal(getPathID(), desiredProperties).getIgnorePickIntersection();
+ _pathIgnorePicks = entityScriptingInterface->getEntityPropertiesInternal(getPathID(), desiredProperties, false).getIgnorePickIntersection();
}
{
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_STROKE_WIDTHS;
- auto widths = entityScriptingInterface->getEntityPropertiesInternal(getPathID(), desiredProperties).getStrokeWidths();
+ auto widths = entityScriptingInterface->getEntityPropertiesInternal(getPathID(), desiredProperties, false).getStrokeWidths();
_lineWidth = widths.length() == 0 ? PolyLineEntityItem::DEFAULT_LINE_WIDTH : widths[0];
}
}
diff --git a/interface/src/raypick/ParabolaPick.cpp b/interface/src/raypick/ParabolaPick.cpp
index 378a46b96b..e8dd759449 100644
--- a/interface/src/raypick/ParabolaPick.cpp
+++ b/interface/src/raypick/ParabolaPick.cpp
@@ -71,7 +71,7 @@ PickResultPointer ParabolaPick::getEntityIntersection(const PickParabola& pick)
if (getFilter().doesPickLocalEntities()) {
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_ENTITY_HOST_TYPE;
- if (DependencyManager::get()->getEntityPropertiesInternal(entityRes.entityID, desiredProperties).getEntityHostType() == entity::HostType::LOCAL) {
+ if (DependencyManager::get()->getEntityPropertiesInternal(entityRes.entityID, desiredProperties, false).getEntityHostType() == entity::HostType::LOCAL) {
type = IntersectionType::LOCAL_ENTITY;
}
}
diff --git a/interface/src/raypick/PathPointer.cpp b/interface/src/raypick/PathPointer.cpp
index b24c5630c4..9333e0f03b 100644
--- a/interface/src/raypick/PathPointer.cpp
+++ b/interface/src/raypick/PathPointer.cpp
@@ -257,7 +257,7 @@ StartEndRenderState::StartEndRenderState(const QUuid& startID, const QUuid& endI
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_DIMENSIONS;
desiredProperties += PROP_IGNORE_PICK_INTERSECTION;
- auto properties = entityScriptingInterface->getEntityPropertiesInternal(_startID, desiredProperties);
+ auto properties = entityScriptingInterface->getEntityPropertiesInternal(_startID, desiredProperties, false);
_startDim = properties.getDimensions();
_startIgnorePicks = properties.getIgnorePickIntersection();
}
@@ -266,7 +266,7 @@ StartEndRenderState::StartEndRenderState(const QUuid& startID, const QUuid& endI
desiredProperties += PROP_DIMENSIONS;
desiredProperties += PROP_ROTATION;
desiredProperties += PROP_IGNORE_PICK_INTERSECTION;
- auto properties = entityScriptingInterface->getEntityPropertiesInternal(_endID, desiredProperties);
+ auto properties = entityScriptingInterface->getEntityPropertiesInternal(_endID, desiredProperties, false);
_endDim = properties.getDimensions();
_endRot = properties.getRotation();
_endIgnorePicks = properties.getIgnorePickIntersection();
diff --git a/interface/src/raypick/RayPick.cpp b/interface/src/raypick/RayPick.cpp
index 17326baa1a..4cb7232095 100644
--- a/interface/src/raypick/RayPick.cpp
+++ b/interface/src/raypick/RayPick.cpp
@@ -40,7 +40,7 @@ PickResultPointer RayPick::getEntityIntersection(const PickRay& pick) {
if (getFilter().doesPickLocalEntities()) {
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_ENTITY_HOST_TYPE;
- if (DependencyManager::get()->getEntityPropertiesInternal(entityRes.entityID, desiredProperties).getEntityHostType() == entity::HostType::LOCAL) {
+ if (DependencyManager::get()->getEntityPropertiesInternal(entityRes.entityID, desiredProperties, false).getEntityHostType() == entity::HostType::LOCAL) {
type = IntersectionType::LOCAL_ENTITY;
}
}
@@ -123,6 +123,6 @@ glm::vec2 RayPick::projectOntoEntityXYPlane(const QUuid& entityID, const glm::ve
desiredProperties += PROP_ROTATION;
desiredProperties += PROP_DIMENSIONS;
desiredProperties += PROP_REGISTRATION_POINT;
- auto props = DependencyManager::get()->getEntityPropertiesInternal(entityID, desiredProperties);
+ auto props = DependencyManager::get()->getEntityPropertiesInternal(entityID, desiredProperties, false);
return projectOntoXYPlane(worldPos, props.getPosition(), props.getRotation(), props.getDimensions(), props.getRegistrationPoint(), unNormalized);
}
diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h
index 175021e559..4128976fdc 100644
--- a/interface/src/scripting/ControllerScriptingInterface.h
+++ b/interface/src/scripting/ControllerScriptingInterface.h
@@ -216,6 +216,7 @@ class ScriptEngine;
*
* @property {Controller.Actions} Actions - Predefined actions on Interface and the user's avatar. These can be used as end
* points in a {@link RouteObject} mapping. A synonym for Controller.Hardware.Actions .
+ * Getting this property is computationally expensive, so it's best to cache it once on script start.
* Read-only.
* Default mappings are provided from the Controller.Hardware.Keyboard and Controller.Standard
* to actions in
@@ -225,13 +226,16 @@ class ScriptEngine;
* standard.json, respectively.
*
* @property {Controller.Hardware} Hardware - Standard and hardware-specific controller and computer outputs, plus predefined
- * actions on Interface and the user's avatar. The outputs can be mapped to Actions or functions in a
+ * actions on Interface and the user's avatar. Getting this property is computationally expensive, so it's best to cache it
+ * instead of calling on every update.
+ * The outputs can be mapped to Actions or functions in a
* {@link RouteObject} mapping. Additionally, hardware-specific controller outputs can be mapped to
* Controller.Standard controller outputs. Read-only.
*
* @property {Controller.Standard} Standard - Standard controller outputs that can be mapped to Actions or
* functions in a {@link RouteObject} mapping. Read-only.
- * Each hardware device has a mapping from its outputs to Controller.Standard items, specified in a JSON file.
+ * Each hardware device has a mapping from its outputs to Controller.Standard items, specified in a JSON file.
+ * Getting this property is computationally expensive, so it's best to cache it once on script start.
* For example,
* leapmotion.json and
* vive.json.
diff --git a/interface/src/scripting/PerformanceScriptingInterface.cpp b/interface/src/scripting/PerformanceScriptingInterface.cpp
index 9f3534b3e8..f619729eff 100644
--- a/interface/src/scripting/PerformanceScriptingInterface.cpp
+++ b/interface/src/scripting/PerformanceScriptingInterface.cpp
@@ -56,12 +56,22 @@ void PerformanceScriptingInterface::setRefreshRateProfile(RefreshRateProfile ref
emit settingsChanged();
}
+void PerformanceScriptingInterface::setCustomRefreshRate(RefreshRateManager::RefreshRateRegime refreshRateRegime, int value)
+{
+ qApp->getRefreshRateManager().setCustomRefreshRate(refreshRateRegime, value);
+ emit settingsChanged();
+}
+
+int PerformanceScriptingInterface::getCustomRefreshRate(RefreshRateManager::RefreshRateRegime refreshRateRegime) const {
+ return qApp->getRefreshRateManager().getCustomRefreshRate(refreshRateRegime);
+}
+
PerformanceScriptingInterface::RefreshRateProfile PerformanceScriptingInterface::getRefreshRateProfile() const {
return (PerformanceScriptingInterface::RefreshRateProfile)qApp->getRefreshRateManager().getRefreshRateProfile();
}
QStringList PerformanceScriptingInterface::getRefreshRateProfileNames() const {
- static const QStringList refreshRateProfileNames = { "ECO", "INTERACTIVE", "REALTIME" };
+ static const QStringList refreshRateProfileNames = { "ECO", "INTERACTIVE", "REALTIME", "CUSTOM" };
return refreshRateProfileNames;
}
diff --git a/interface/src/scripting/PerformanceScriptingInterface.h b/interface/src/scripting/PerformanceScriptingInterface.h
index 86350c8a1f..05e2c1d7bc 100644
--- a/interface/src/scripting/PerformanceScriptingInterface.h
+++ b/interface/src/scripting/PerformanceScriptingInterface.h
@@ -127,6 +127,22 @@ public slots:
*/
void setRefreshRateProfile(RefreshRateProfile refreshRateProfile);
+ /*@jsdoc
+ * Sets a custom refresh rate.
+ * @function Performance.setCustomRefreshRate
+ * @param {RefreshRateRegime} refreshRateRegime - The refresh rate regime
+ * @param {int} value - The value for the regime
+ */
+ void setCustomRefreshRate(RefreshRateManager::RefreshRateRegime refreshRateRegime, int value);
+
+ /*@jsdoc
+ * Gets the value for a specific RefreshRateRegime.
+ * @function Performance.getCustomRefreshRate
+ * @param {RefreshRateRegime} - The regime to get the value from
+ * @returns {int} - The value from the specified regime
+ */
+ int getCustomRefreshRate(RefreshRateManager::RefreshRateRegime regime) const;
+
/*@jsdoc
* Gets the current refresh rate profile in use.
* @function Performance.getRefreshRateProfile
diff --git a/interface/src/scripting/SettingsScriptingInterface.cpp b/interface/src/scripting/SettingsScriptingInterface.cpp
index b7ef172f19..00cdf009eb 100644
--- a/interface/src/scripting/SettingsScriptingInterface.cpp
+++ b/interface/src/scripting/SettingsScriptingInterface.cpp
@@ -21,6 +21,9 @@ SettingsScriptingInterface* SettingsScriptingInterface::getInstance() {
}
QVariant SettingsScriptingInterface::getValue(const QString& setting) {
+ if (_restrictPrivateValues && setting.startsWith(SETTINGS_FULL_PRIVATE_GROUP_NAME + "/")) {
+ return {""};
+ }
QVariant value = Setting::Handle(setting).get();
if (!value.isValid()) {
value = "";
@@ -29,6 +32,9 @@ QVariant SettingsScriptingInterface::getValue(const QString& setting) {
}
QVariant SettingsScriptingInterface::getValue(const QString& setting, const QVariant& defaultValue) {
+ if (_restrictPrivateValues && setting.startsWith(SETTINGS_FULL_PRIVATE_GROUP_NAME + "/")) {
+ return {""};
+ }
QVariant value = Setting::Handle(setting, defaultValue).get();
if (!value.isValid()) {
value = "";
@@ -40,7 +46,7 @@ void SettingsScriptingInterface::setValue(const QString& setting, const QVariant
if (getValue(setting) == value) {
return;
}
- if (setting.startsWith("private/")) {
+ if (setting.startsWith("private/") || setting.startsWith(SETTINGS_FULL_PRIVATE_GROUP_NAME + "/")) {
if (_restrictPrivateValues) {
qWarning() << "SettingsScriptingInterface::setValue -- restricted write: " << setting << value;
return;
diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp
index 27564b39eb..b70798d02a 100644
--- a/interface/src/scripting/WindowScriptingInterface.cpp
+++ b/interface/src/scripting/WindowScriptingInterface.cpp
@@ -78,7 +78,7 @@ WindowScriptingInterface::~WindowScriptingInterface() {
}
ScriptValue WindowScriptingInterface::hasFocus() {
- Q_ASSERT(engine);
+ Q_ASSERT(engine());
return engine()->newValue(qApp->hasFocus());
}
@@ -107,7 +107,7 @@ void WindowScriptingInterface::alert(const QString& message) {
/// \param const QString& message message to display
/// \return ScriptValue `true` if 'Yes' was clicked, `false` otherwise
ScriptValue WindowScriptingInterface::confirm(const QString& message) {
- Q_ASSERT(engine);
+ Q_ASSERT(engine());
return engine()->newValue((QMessageBox::Yes == OffscreenUi::question("", message, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)));
}
@@ -117,7 +117,7 @@ ScriptValue WindowScriptingInterface::confirm(const QString& message) {
/// \return ScriptValue string text value in text box if the dialog was accepted, `null` otherwise.
ScriptValue WindowScriptingInterface::prompt(const QString& message, const QString& defaultText) {
QString result = OffscreenUi::getText(nullptr, "", message, QLineEdit::Normal, defaultText);
- Q_ASSERT(engine);
+ Q_ASSERT(engine());
auto sResult = engine()->newValue(result);
if (sResult.equals(engine()->newValue(""))) {
return engine()->nullValue();
@@ -234,7 +234,7 @@ ScriptValue WindowScriptingInterface::browseDir(const QString& title, const QStr
if (!result.isEmpty()) {
setPreviousBrowseLocation(QFileInfo(result).absolutePath());
}
- Q_ASSERT(engine);
+ Q_ASSERT(engine());
return result.isEmpty() ? engine()->nullValue() : engine()->newValue(result);
}
@@ -279,7 +279,7 @@ ScriptValue WindowScriptingInterface::browse(const QString& title, const QString
if (!result.isEmpty()) {
setPreviousBrowseLocation(QFileInfo(result).absolutePath());
}
- Q_ASSERT(engine);
+ Q_ASSERT(engine());
return result.isEmpty() ? engine()->nullValue() : engine()->newValue(result);
}
@@ -327,7 +327,7 @@ ScriptValue WindowScriptingInterface::save(const QString& title, const QString&
if (!result.isEmpty()) {
setPreviousBrowseLocation(QFileInfo(result).absolutePath());
}
- Q_ASSERT(engine);
+ Q_ASSERT(engine());
return result.isEmpty() ? engine()->nullValue() : engine()->newValue(result);
}
@@ -378,7 +378,7 @@ ScriptValue WindowScriptingInterface::browseAssets(const QString& title, const Q
if (!result.isEmpty()) {
setPreviousBrowseAssetLocation(QFileInfo(result).absolutePath());
}
- Q_ASSERT(engine);
+ Q_ASSERT(engine());
return result.isEmpty() ? engine()->nullValue() : engine()->newValue(result);
}
diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h
index 23055cf246..9db09b0b9b 100644
--- a/interface/src/ui/ApplicationOverlay.h
+++ b/interface/src/ui/ApplicationOverlay.h
@@ -27,18 +27,17 @@ public:
void renderOverlay(RenderArgs* renderArgs);
- gpu::TexturePointer getOverlayTexture();
+ gpu::TexturePointer getOverlayTexture();
+
+ bool enabled() const { return _enabled; }
+ void setEnabled(bool enabled) { _enabled = enabled; }
private:
- void renderStatsAndLogs(RenderArgs* renderArgs);
void renderDomainConnectionStatusBorder(RenderArgs* renderArgs);
void renderQmlUi(RenderArgs* renderArgs);
void renderOverlays(RenderArgs* renderArgs);
void buildFramebufferObject();
- float _alpha{ 1.0f };
- float _trailingAudioLoudness{ 0.0f };
-
int _domainStatusBorder;
int _magnifierBorder;
@@ -47,6 +46,8 @@ private:
gpu::TexturePointer _overlayColorTexture;
gpu::FramebufferPointer _overlayFramebuffer;
int _qmlGeometryId { 0 };
+
+ bool _enabled { true };
};
#endif // hifi_ApplicationOverlay_h
diff --git a/interface/src/ui/Keyboard.cpp b/interface/src/ui/Keyboard.cpp
index 80ba33d0c7..d8038e8727 100644
--- a/interface/src/ui/Keyboard.cpp
+++ b/interface/src/ui/Keyboard.cpp
@@ -118,7 +118,7 @@ std::pair calculateKeyboardPositionAndOrientation() {
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_POSITION;
desiredProperties += PROP_ROTATION;
- auto properties = DependencyManager::get()->getEntityPropertiesInternal(tabletID, desiredProperties);
+ auto properties = DependencyManager::get()->getEntityPropertiesInternal(tabletID, desiredProperties, false);
auto tablet = DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system");
bool landscapeMode = tablet->getLandscape();
@@ -146,7 +146,7 @@ void Key::saveDimensionsAndLocalPosition() {
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_LOCAL_POSITION;
desiredProperties += PROP_DIMENSIONS;
- auto properties = DependencyManager::get()->getEntityPropertiesInternal(_keyID, desiredProperties);
+ auto properties = DependencyManager::get()->getEntityPropertiesInternal(_keyID, desiredProperties, false);
_originalLocalPosition = properties.getLocalPosition();
_originalDimensions = properties.getDimensions();
@@ -469,7 +469,7 @@ void Keyboard::switchToLayer(int layerIndex) {
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_POSITION;
desiredProperties += PROP_ROTATION;
- auto oldProperties = entityScriptingInterface->getEntityPropertiesInternal(_anchor.entityID, desiredProperties);
+ auto oldProperties = entityScriptingInterface->getEntityPropertiesInternal(_anchor.entityID, desiredProperties, false);
glm::vec3 currentPosition = oldProperties.getPosition();
glm::quat currentOrientation = oldProperties.getRotation();
@@ -530,7 +530,7 @@ void Keyboard::handleTriggerBegin(const QUuid& id, const PointerEvent& event) {
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_POSITION;
- glm::vec3 keyWorldPosition = DependencyManager::get()->getEntityPropertiesInternal(id, desiredProperties).getPosition();
+ glm::vec3 keyWorldPosition = DependencyManager::get()->getEntityPropertiesInternal(id, desiredProperties, false).getPosition();
AudioInjectorOptions audioOptions;
audioOptions.localOnly = true;
@@ -662,7 +662,7 @@ void Keyboard::handleTriggerContinue(const QUuid& id, const PointerEvent& event)
auto entityScriptingInterface = DependencyManager::get();
EntityPropertyFlags desiredProperties;
desiredProperties += PROP_ROTATION;
- glm::quat orientation = entityScriptingInterface->getEntityPropertiesInternal(id, desiredProperties).getRotation();
+ glm::quat orientation = entityScriptingInterface->getEntityPropertiesInternal(id, desiredProperties, false).getRotation();
glm::vec3 yAxis = orientation * Z_AXIS;
glm::vec3 yOffset = yAxis * Z_OFFSET;
glm::vec3 localPosition = key.getCurrentLocalPosition() - yOffset;
diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp
index 8597cb5717..ce5a588776 100644
--- a/interface/src/ui/PreferencesDialog.cpp
+++ b/interface/src/ui/PreferencesDialog.cpp
@@ -100,7 +100,8 @@ void setupPreferences() {
QStringList refreshRateProfiles
{ QString::fromStdString(RefreshRateManager::refreshRateProfileToString(RefreshRateManager::RefreshRateProfile::ECO)),
QString::fromStdString(RefreshRateManager::refreshRateProfileToString(RefreshRateManager::RefreshRateProfile::INTERACTIVE)),
- QString::fromStdString(RefreshRateManager::refreshRateProfileToString(RefreshRateManager::RefreshRateProfile::REALTIME)) };
+ QString::fromStdString(RefreshRateManager::refreshRateProfileToString(RefreshRateManager::RefreshRateProfile::REALTIME)),
+ QString::fromStdString(RefreshRateManager::refreshRateProfileToString(RefreshRateManager::RefreshRateProfile::CUSTOM)) };
preference->setItems(refreshRateProfiles);
preferences->addPreference(preference);
diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp
index e245acfd40..5349564043 100644
--- a/interface/src/ui/overlays/Overlays.cpp
+++ b/interface/src/ui/overlays/Overlays.cpp
@@ -153,14 +153,6 @@ void Overlays::render(RenderArgs* renderArgs) {
}
}
-void Overlays::disable() {
- _enabled = false;
-}
-
-void Overlays::enable() {
- _enabled = true;
-}
-
Overlay::Pointer Overlays::take2DOverlay(const QUuid& id) {
if (_shuttingDown) {
return nullptr;
@@ -378,7 +370,7 @@ QObject* Overlays::getOverlayObject(const QUuid& id) {
}
QUuid Overlays::getOverlayAtPoint(const glm::vec2& point) {
- if (_shuttingDown || !_enabled) {
+ if (_shuttingDown) {
return UNKNOWN_ENTITY_ID;
}
diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h
index a0f2e866e2..fcf0c71bc9 100644
--- a/interface/src/ui/overlays/Overlays.h
+++ b/interface/src/ui/overlays/Overlays.h
@@ -99,8 +99,6 @@ public:
void init();
void update(float deltatime);
void render(RenderArgs* renderArgs);
- void disable();
- void enable();
Overlay::Pointer take2DOverlay(const QUuid& id);
Overlay::Pointer get2DOverlay(const QUuid& id) const;
@@ -683,7 +681,6 @@ private:
unsigned int _stackOrder { 1 };
- bool _enabled { true };
std::atomic _shuttingDown { false };
PointerEvent calculateOverlayPointerEvent(const QUuid& id, const PickRay& ray, const RayToOverlayIntersectionResult& rayPickResult,
diff --git a/launchers/qt/CMakeLists.txt b/launchers/qt/CMakeLists.txt
index 12cf7f08d4..0e5ddd6990 100644
--- a/launchers/qt/CMakeLists.txt
+++ b/launchers/qt/CMakeLists.txt
@@ -281,7 +281,7 @@ if (APPLE)
set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME})
- set(DMG_SUBFOLDER_NAME "Vircadia")
+ set(DMG_SUBFOLDER_NAME "Overte")
set(ESCAPED_DMG_SUBFOLDER_NAME "")
set(DMG_SUBFOLDER_ICON "${CMAKE_SOURCE_DIR}/cmake/installer/install-folder.rsrc")
diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp
index 6eb77da4d7..16b217bc53 100644
--- a/libraries/audio-client/src/AudioClient.cpp
+++ b/libraries/audio-client/src/AudioClient.cpp
@@ -27,7 +27,9 @@
#endif
#ifdef WIN32
+#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN 1
+#endif
#include
#include
#include
diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp
index c71da50b1a..4068f7c547 100644
--- a/libraries/avatars/src/AvatarData.cpp
+++ b/libraries/avatars/src/AvatarData.cpp
@@ -2106,6 +2106,14 @@ const QUrl& AvatarData::getSkeletonModelURL() const {
}
}
+QString AvatarData::getSkeletonModelURLFromScript() const {
+ if (isMyAvatar() && !isMyAvatarURLProtected()) {
+ return _skeletonModelURL.toString();
+ }
+
+ return QString();
+};
+
QByteArray AvatarData::packSkeletonData() const {
// Send an avatar trait packet with the skeleton data before the mesh is loaded
int avatarDataSize = 0;
@@ -2558,7 +2566,7 @@ QDataStream& operator>>(QDataStream& in, AttachmentData& attachment) {
void AttachmentDataObject::setModelURL(const QString& modelURL) {
AttachmentData data = scriptvalue_cast(thisObject());
data.modelURL = modelURL;
- Q_ASSERT(engine);
+ Q_ASSERT(engine());
thisObject() = engine()->toScriptValue(data);
}
@@ -2569,7 +2577,7 @@ QString AttachmentDataObject::getModelURL() const {
void AttachmentDataObject::setJointName(const QString& jointName) {
AttachmentData data = scriptvalue_cast(thisObject());
data.jointName = jointName;
- Q_ASSERT(engine);
+ Q_ASSERT(engine());
thisObject() = engine()->toScriptValue(data);
}
@@ -2580,7 +2588,7 @@ QString AttachmentDataObject::getJointName() const {
void AttachmentDataObject::setTranslation(const glm::vec3& translation) {
AttachmentData data = scriptvalue_cast(thisObject());
data.translation = translation;
- Q_ASSERT(engine);
+ Q_ASSERT(engine());
thisObject() = engine()->toScriptValue(data);
}
@@ -2591,7 +2599,7 @@ glm::vec3 AttachmentDataObject::getTranslation() const {
void AttachmentDataObject::setRotation(const glm::quat& rotation) {
AttachmentData data = scriptvalue_cast(thisObject());
data.rotation = rotation;
- Q_ASSERT(engine);
+ Q_ASSERT(engine());
thisObject() = engine()->toScriptValue(data);
}
@@ -2602,7 +2610,7 @@ glm::quat AttachmentDataObject::getRotation() const {
void AttachmentDataObject::setScale(float scale) {
AttachmentData data = scriptvalue_cast(thisObject());
data.scale = scale;
- Q_ASSERT(engine);
+ Q_ASSERT(engine());
thisObject() = engine()->toScriptValue(data);
}
@@ -2613,7 +2621,7 @@ float AttachmentDataObject::getScale() const {
void AttachmentDataObject::setIsSoft(bool isSoft) {
AttachmentData data = scriptvalue_cast(thisObject());
data.isSoft = isSoft;
- Q_ASSERT(engine);
+ Q_ASSERT(engine());
thisObject() = engine()->toScriptValue(data);
}
diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h
index 0b2a925de0..d3bf8a3282 100644
--- a/libraries/avatars/src/AvatarData.h
+++ b/libraries/avatars/src/AvatarData.h
@@ -610,6 +610,8 @@ public:
AvatarData();
virtual ~AvatarData();
+ virtual bool isMyAvatarURLProtected() const { return false; } // This needs to be here because both MyAvatar and AvatarData inherit from MyAvatar
+
static const QUrl& defaultFullAvatarModelUrl();
const QUuid getSessionUUID() const { return getID(); }
@@ -1355,7 +1357,7 @@ public:
*/
Q_INVOKABLE virtual void detachAll(const QString& modelURL, const QString& jointName = QString());
- QString getSkeletonModelURLFromScript() const { return _skeletonModelURL.toString(); }
+ QString getSkeletonModelURLFromScript() const;
void setSkeletonModelURLFromScript(const QString& skeletonModelString) { setSkeletonModelURL(QUrl(skeletonModelString)); }
void setOwningAvatarMixer(const QWeakPointer& owningAvatarMixer) { _owningAvatarMixer = owningAvatarMixer; }
diff --git a/libraries/avatars/src/ScriptAvatarData.cpp b/libraries/avatars/src/ScriptAvatarData.cpp
index a07c402555..1d93a6e954 100644
--- a/libraries/avatars/src/ScriptAvatarData.cpp
+++ b/libraries/avatars/src/ScriptAvatarData.cpp
@@ -13,6 +13,7 @@
#include "ScriptAvatarData.h"
+#include
#include
#include
@@ -204,7 +205,12 @@ bool ScriptAvatarData::getLookAtSnappingEnabled() const {
//
QString ScriptAvatarData::getSkeletonModelURLFromScript() const {
if (AvatarSharedPointer sharedAvatarData = _avatarData.lock()) {
- return sharedAvatarData->getSkeletonModelURLFromScript();
+ auto nodeList = DependencyManager::get();
+ if (sharedAvatarData->isMyAvatar() && !sharedAvatarData->isMyAvatarURLProtected() && nodeList->getThisNodeCanViewAssetURLs()) {
+ return sharedAvatarData->getSkeletonModelURLFromScript();
+ }
+
+ return QString();
} else {
return QString();
}
diff --git a/libraries/baking/src/MaterialBaker.cpp b/libraries/baking/src/MaterialBaker.cpp
index 48718cd6c3..631a10fd11 100644
--- a/libraries/baking/src/MaterialBaker.cpp
+++ b/libraries/baking/src/MaterialBaker.cpp
@@ -36,8 +36,7 @@ MaterialBaker::MaterialBaker(const QString& materialData, bool isURL, const QStr
_isURL(isURL),
_destinationPath(destinationPath),
_bakedOutputDir(bakedOutputDir),
- _textureOutputDir(bakedOutputDir + "/materialTextures/" + QString::number(materialNum++)),
- _scriptEngine(newScriptEngine())
+ _textureOutputDir(bakedOutputDir + "/materialTextures/" + QString::number(materialNum++))
{
}
@@ -214,16 +213,20 @@ void MaterialBaker::outputMaterial() {
if (_materialResource->parsedMaterials.networkMaterials.size() == 1) {
auto networkMaterial = _materialResource->parsedMaterials.networkMaterials.begin();
auto scriptableMaterial = scriptable::ScriptableMaterial(networkMaterial->second);
- QVariant materialVariant =
- scriptable::scriptableMaterialToScriptValue(_scriptEngine.get(), scriptableMaterial).toVariant();
- json.insert("materials", QJsonDocument::fromVariant(materialVariant).object());
+ _helperScriptEngine.run( [&] {
+ QVariant materialVariant =
+ scriptable::scriptableMaterialToScriptValue(_helperScriptEngine.get(), scriptableMaterial).toVariant();
+ json.insert("materials", QJsonDocument::fromVariant(materialVariant).object());
+ });
} else {
QJsonArray materialArray;
for (auto networkMaterial : _materialResource->parsedMaterials.networkMaterials) {
auto scriptableMaterial = scriptable::ScriptableMaterial(networkMaterial.second);
- QVariant materialVariant =
- scriptable::scriptableMaterialToScriptValue(_scriptEngine.get(), scriptableMaterial).toVariant();
- materialArray.append(QJsonDocument::fromVariant(materialVariant).object());
+ _helperScriptEngine.run( [&] {
+ QVariant materialVariant =
+ scriptable::scriptableMaterialToScriptValue(_helperScriptEngine.get(), scriptableMaterial).toVariant();
+ materialArray.append(QJsonDocument::fromVariant(materialVariant).object());
+ });
}
json.insert("materials", materialArray);
}
@@ -269,19 +272,32 @@ void MaterialBaker::setMaterials(const QHash& materials,
_materialResource = NetworkMaterialResourcePointer(new NetworkMaterialResource(), [](NetworkMaterialResource* ptr) { ptr->deleteLater(); });
for (auto& material : materials) {
_materialResource->parsedMaterials.names.push_back(material.name.toStdString());
- _materialResource->parsedMaterials.networkMaterials[material.name.toStdString()] = std::make_shared(material, baseURL);
+ if (!material.isMToonMaterial) {
+ _materialResource->parsedMaterials.networkMaterials[material.name.toStdString()] = std::make_shared(material, baseURL);
+ } else {
+ _materialResource->parsedMaterials.networkMaterials[material.name.toStdString()] = std::make_shared(material, baseURL);
+ }
// Store any embedded texture content
addTexture(material.name, image::TextureUsage::NORMAL_TEXTURE, material.normalTexture);
addTexture(material.name, image::TextureUsage::ALBEDO_TEXTURE, material.albedoTexture);
- addTexture(material.name, image::TextureUsage::GLOSS_TEXTURE, material.glossTexture);
- addTexture(material.name, image::TextureUsage::ROUGHNESS_TEXTURE, material.roughnessTexture);
- addTexture(material.name, image::TextureUsage::SPECULAR_TEXTURE, material.specularTexture);
- addTexture(material.name, image::TextureUsage::METALLIC_TEXTURE, material.metallicTexture);
addTexture(material.name, image::TextureUsage::EMISSIVE_TEXTURE, material.emissiveTexture);
- addTexture(material.name, image::TextureUsage::OCCLUSION_TEXTURE, material.occlusionTexture);
- addTexture(material.name, image::TextureUsage::SCATTERING_TEXTURE, material.scatteringTexture);
- addTexture(material.name, image::TextureUsage::LIGHTMAP_TEXTURE, material.lightmapTexture);
+
+ if (!material.isMToonMaterial) {
+ addTexture(material.name, image::TextureUsage::GLOSS_TEXTURE, material.glossTexture);
+ addTexture(material.name, image::TextureUsage::ROUGHNESS_TEXTURE, material.roughnessTexture);
+ addTexture(material.name, image::TextureUsage::SPECULAR_TEXTURE, material.specularTexture);
+ addTexture(material.name, image::TextureUsage::METALLIC_TEXTURE, material.metallicTexture);
+ addTexture(material.name, image::TextureUsage::OCCLUSION_TEXTURE, material.occlusionTexture);
+ addTexture(material.name, image::TextureUsage::SCATTERING_TEXTURE, material.scatteringTexture);
+ addTexture(material.name, image::TextureUsage::LIGHTMAP_TEXTURE, material.lightmapTexture);
+ } else {
+ addTexture(material.name, image::TextureUsage::ALBEDO_TEXTURE, material.shadeTexture);
+ addTexture(material.name, image::TextureUsage::ROUGHNESS_TEXTURE, material.shadingShiftTexture);
+ addTexture(material.name, image::TextureUsage::EMISSIVE_TEXTURE, material.matcapTexture);
+ addTexture(material.name, image::TextureUsage::ALBEDO_TEXTURE, material.rimTexture);
+ addTexture(material.name, image::TextureUsage::ROUGHNESS_TEXTURE, material.uvAnimationTexture);
+ }
}
}
diff --git a/libraries/baking/src/MaterialBaker.h b/libraries/baking/src/MaterialBaker.h
index 129b36aa8f..4fd8948b03 100644
--- a/libraries/baking/src/MaterialBaker.h
+++ b/libraries/baking/src/MaterialBaker.h
@@ -21,6 +21,7 @@
#include "TextureBaker.h"
#include "baking/TextureFileNamer.h"
+#include
#include
#include
@@ -72,7 +73,7 @@ private:
QString _textureOutputDir;
QString _bakedMaterialData;
- ScriptEnginePointer _scriptEngine;
+ HelperScriptEngine _helperScriptEngine;
static std::function _getNextOvenWorkerThreadOperator;
TextureFileNamer _textureFileNamer;
diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp
index 4861bc6ecb..8fba576616 100644
--- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp
+++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp
@@ -232,6 +232,14 @@ void EntityTreeRenderer::resetPersistentEntitiesScriptEngine() {
_persistentEntitiesScriptManager = scriptManagerFactory(ScriptManager::ENTITY_CLIENT_SCRIPT, NO_SCRIPT,
QString("about:Entities %1").arg(++_entitiesScriptEngineCount));
DependencyManager::get()->runScriptInitializers(_persistentEntitiesScriptManager);
+
+ // Make script engine messages available through ScriptDiscoveryService
+ auto scriptEngines = DependencyManager::get().data();
+ connect(_persistentEntitiesScriptManager.get(), &ScriptManager::infoEntityMessage, scriptEngines, &ScriptEngines::infoEntityMessage);
+ connect(_persistentEntitiesScriptManager.get(), &ScriptManager::printedEntityMessage, scriptEngines, &ScriptEngines::printedEntityMessage);
+ connect(_persistentEntitiesScriptManager.get(), &ScriptManager::errorEntityMessage, scriptEngines, &ScriptEngines::errorEntityMessage);
+ connect(_persistentEntitiesScriptManager.get(), &ScriptManager::warningEntityMessage, scriptEngines, &ScriptEngines::warningEntityMessage);
+
_persistentEntitiesScriptManager->runInThread();
std::shared_ptr entitiesScriptEngineProvider = _persistentEntitiesScriptManager;
auto entityScriptingInterface = DependencyManager::get();
@@ -255,6 +263,14 @@ void EntityTreeRenderer::resetNonPersistentEntitiesScriptEngine() {
_nonPersistentEntitiesScriptManager = scriptManagerFactory(ScriptManager::ENTITY_CLIENT_SCRIPT, NO_SCRIPT,
QString("about:Entities %1").arg(++_entitiesScriptEngineCount));
DependencyManager::get()->runScriptInitializers(_nonPersistentEntitiesScriptManager);
+
+ // Make script engine messages available through ScriptDiscoveryService
+ auto scriptEngines = DependencyManager::get().data();
+ connect(_nonPersistentEntitiesScriptManager.get(), &ScriptManager::infoEntityMessage, scriptEngines, &ScriptEngines::infoEntityMessage);
+ connect(_nonPersistentEntitiesScriptManager.get(), &ScriptManager::printedEntityMessage, scriptEngines, &ScriptEngines::printedEntityMessage);
+ connect(_nonPersistentEntitiesScriptManager.get(), &ScriptManager::errorEntityMessage, scriptEngines, &ScriptEngines::errorEntityMessage);
+ connect(_nonPersistentEntitiesScriptManager.get(), &ScriptManager::warningEntityMessage, scriptEngines, &ScriptEngines::warningEntityMessage);
+
_nonPersistentEntitiesScriptManager->runInThread();
std::shared_ptr entitiesScriptEngineProvider = _nonPersistentEntitiesScriptManager;
DependencyManager::get()->setNonPersistentEntitiesScriptEngine(entitiesScriptEngineProvider);
@@ -912,7 +928,7 @@ QUuid EntityTreeRenderer::mousePressEvent(QMouseEvent* event) {
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event),
- Qt::NoModifier); // TODO -- check for modifier keys?
+ event->modifiers());
emit entityScriptingInterface->mousePressOnEntity(rayPickResult.entityID, pointerEvent);
@@ -943,9 +959,10 @@ void EntityTreeRenderer::mouseDoublePressEvent(QMouseEvent* event) {
if (rayPickResult.intersects && (entity = getTree()->findEntityByID(rayPickResult.entityID))) {
glm::vec2 pos2D = projectOntoEntityXYPlane(entity, ray, rayPickResult);
PointerEvent pointerEvent(PointerEvent::Press, PointerManager::MOUSE_POINTER_ID,
- pos2D, rayPickResult.intersection,
- rayPickResult.surfaceNormal, ray.direction,
- toPointerButton(*event), toPointerButtons(*event), Qt::NoModifier);
+ pos2D, rayPickResult.intersection,
+ rayPickResult.surfaceNormal, ray.direction,
+ toPointerButton(*event), toPointerButtons(*event),
+ event->modifiers());
emit entityScriptingInterface->mouseDoublePressOnEntity(rayPickResult.entityID, pointerEvent);
@@ -979,7 +996,7 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) {
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event),
- Qt::NoModifier); // TODO -- check for modifier keys?
+ event->modifiers());
emit entityScriptingInterface->mouseReleaseOnEntity(rayPickResult.entityID, pointerEvent);
@@ -995,7 +1012,7 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) {
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event),
- Qt::NoModifier); // TODO -- check for modifier keys?
+ event->modifiers());
emit entityScriptingInterface->clickReleaseOnEntity(_currentClickingOnEntityID, pointerEvent);
}
@@ -1022,7 +1039,7 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event),
- Qt::NoModifier); // TODO -- check for modifier keys?
+ event->modifiers());
emit entityScriptingInterface->mouseMoveOnEntity(rayPickResult.entityID, pointerEvent);
@@ -1036,7 +1053,7 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
pos2D, rayPickResult.intersection,
rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event),
- Qt::NoModifier); // TODO -- check for modifier keys?
+ event->modifiers());
emit entityScriptingInterface->hoverLeaveEntity(_currentHoverOverEntityID, pointerEvent);
}
@@ -1064,10 +1081,10 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) {
if (!_currentHoverOverEntityID.isInvalidID()) {
glm::vec2 pos2D = projectOntoEntityXYPlane(entity, ray, rayPickResult);
PointerEvent pointerEvent(PointerEvent::Move, PointerManager::MOUSE_POINTER_ID,
- pos2D, rayPickResult.intersection,
- rayPickResult.surfaceNormal, ray.direction,
+ pos2D, rayPickResult.intersection,
+ rayPickResult.surfaceNormal, ray.direction,
toPointerButton(*event), toPointerButtons(*event),
- Qt::NoModifier); // TODO -- check for modifier keys?
+ event->modifiers());
emit entityScriptingInterface->hoverLeaveEntity(_currentHoverOverEntityID, pointerEvent);
_currentHoverOverEntityID = UNKNOWN_ENTITY_ID; // makes it the unknown ID
diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp
index 2b57c8b78a..c68651d42c 100644
--- a/libraries/entities-renderer/src/RenderableEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp
@@ -4,6 +4,7 @@
//
// Created by Brad Hefta-Gaub on 12/6/13.
// Copyright 2013 High Fidelity, Inc.
+// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@@ -202,6 +203,8 @@ ItemKey EntityRenderer::getKey() {
builder.withInvisible();
}
+ updateItemKeyBuilderFromMaterials(builder);
+
return builder;
}
@@ -328,6 +331,20 @@ ItemID EntityRenderer::computeMirrorViewOperator(ViewFrustum& viewFrustum, const
return foundPortalExit ? DependencyManager::get()->renderableIdForEntityId(portalExitID) : Item::INVALID_ITEM_ID;
}
+HighlightStyle EntityRenderer::getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const {
+ std::lock_guard lock(_materialsLock);
+ auto materials = _materials.find("0");
+ if (materials != _materials.end()) {
+ glm::vec3 position;
+ withReadLock([&] {
+ position = _renderTransform.getTranslation();
+ });
+ return HighlightStyle::calculateOutlineStyle(materials->second.getOutlineWidthMode(), materials->second.getOutlineWidth(),
+ materials->second.getOutline(), position, viewFrustum, height);
+ }
+ return HighlightStyle();
+}
+
void EntityRenderer::render(RenderArgs* args) {
if (!isValidRenderItem()) {
return;
@@ -627,7 +644,7 @@ EntityRenderer::Pipeline EntityRenderer::getPipelineType(const graphics::MultiMa
}
graphics::MaterialKey drawMaterialKey = materials.getMaterialKey();
- if (drawMaterialKey.isEmissive() || drawMaterialKey.isMetallic() || drawMaterialKey.isScattering()) {
+ if (materials.isMToon() || drawMaterialKey.isEmissive() || drawMaterialKey.isMetallic() || drawMaterialKey.isScattering()) {
return Pipeline::MATERIAL;
}
@@ -747,6 +764,26 @@ Item::Bound EntityRenderer::getMaterialBound(RenderArgs* args) {
return EntityRenderer::getBound(args);
}
+void EntityRenderer::updateItemKeyBuilderFromMaterials(ItemKey::Builder& builder) {
+ MaterialMap::iterator materials;
+ {
+ std::lock_guard lock(_materialsLock);
+ materials = _materials.find("0");
+
+ if (materials != _materials.end()) {
+ if (materials->second.shouldUpdate()) {
+ RenderPipelines::updateMultiMaterial(materials->second);
+ }
+ } else {
+ return;
+ }
+ }
+
+ if (materials->second.hasOutline()) {
+ builder.withOutline();
+ }
+}
+
void EntityRenderer::updateShapeKeyBuilderFromMaterials(ShapeKey::Builder& builder) {
MaterialMap::iterator materials;
{
@@ -773,7 +810,7 @@ void EntityRenderer::updateShapeKeyBuilderFromMaterials(ShapeKey::Builder& build
builder.withCullFaceMode(materials->second.getCullFaceMode());
graphics::MaterialKey drawMaterialKey = materials->second.getMaterialKey();
- if (drawMaterialKey.isUnlit()) {
+ if (!materials->second.isMToon() && drawMaterialKey.isUnlit()) {
builder.withUnlit();
}
@@ -783,8 +820,12 @@ void EntityRenderer::updateShapeKeyBuilderFromMaterials(ShapeKey::Builder& build
if (drawMaterialKey.isNormalMap()) {
builder.withTangents();
}
- if (drawMaterialKey.isLightMap()) {
- builder.withLightMap();
+ if (!materials->second.isMToon()) {
+ if (drawMaterialKey.isLightMap()) {
+ builder.withLightMap();
+ }
+ } else {
+ builder.withMToon();
}
} else if (pipelineType == Pipeline::PROCEDURAL) {
builder.withOwnPipeline();
diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h
index 495eeea220..949590c472 100644
--- a/libraries/entities-renderer/src/RenderableEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableEntityItem.h
@@ -4,6 +4,7 @@
//
// Created by Brad Hefta-Gaub on 12/6/13.
// Copyright 2013 High Fidelity, Inc.
+// Copyright 2024 Overte e.V.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@@ -13,6 +14,8 @@
#define hifi_RenderableEntityItem_h
#include
+#include
+
#include
#include
#include "AbstractViewStateInterface.h"
@@ -79,6 +82,7 @@ public:
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:
virtual bool needsRenderUpdateFromEntity() const final { return needsRenderUpdateFromEntity(_entity); }
@@ -138,6 +142,7 @@ protected:
void updateMaterials(bool baseMaterialChanged = false);
bool materialsTransparent() const;
Item::Bound getMaterialBound(RenderArgs* args);
+ void updateItemKeyBuilderFromMaterials(ItemKey::Builder& builder);
void updateShapeKeyBuilderFromMaterials(ShapeKey::Builder& builder);
Item::Bound _bound;
diff --git a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp
index 66a5d0d609..0b76038cd4 100644
--- a/libraries/entities-renderer/src/RenderableImageEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableImageEntityItem.cpp
@@ -130,8 +130,7 @@ void ImageEntityRenderer::doRender(RenderArgs* args) {
materials = _materials["0"];
}
- auto& schema = materials.getSchemaBuffer().get();
- glm::vec4 color = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity);
+ glm::vec4 color = materials.getColor();
color = EntityRenderer::calculatePulseColor(color, _pulseProperties, _created);
if (!_texture || !_texture->isLoaded() || color.a == 0.0f) {
diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp
index fe44c41094..576e842f84 100644
--- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp
@@ -1,6 +1,7 @@
//
// Created by Sam Gondelman on 1/18/2018
// Copyright 2018 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
@@ -219,7 +220,7 @@ void MaterialEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo
ItemKey MaterialEntityRenderer::getKey() {
auto builder = ItemKey::Builder().withTypeShape().withTagBits(getTagMask()).withLayer(getHifiRenderLayer());
- if (!_visible) {
+ if (!_visible || !_parentID.isNull()) {
builder.withInvisible();
}
@@ -229,6 +230,10 @@ ItemKey MaterialEntityRenderer::getKey() {
if (matKey.isTranslucent()) {
builder.withTransparent();
}
+
+ if (drawMaterial->getOutlineWidthMode() != NetworkMToonMaterial::OutlineWidthMode::OUTLINE_NONE && drawMaterial->getOutlineWidth() > 0.0f) {
+ builder.withOutline();
+ }
}
return builder.build();
@@ -258,11 +263,16 @@ ShapeKey MaterialEntityRenderer::getShapeKey() {
if (drawMaterialKey.isNormalMap()) {
builder.withTangents();
}
- if (drawMaterialKey.isLightMap()) {
- builder.withLightMap();
- }
- if (drawMaterialKey.isUnlit()) {
- builder.withUnlit();
+
+ if (drawMaterial && drawMaterial->isMToon()) {
+ builder.withMToon();
+ } else {
+ if (drawMaterialKey.isLightMap()) {
+ builder.withLightMap();
+ }
+ if (drawMaterialKey.isUnlit()) {
+ builder.withUnlit();
+ }
}
}
@@ -273,6 +283,18 @@ ShapeKey MaterialEntityRenderer::getShapeKey() {
return builder.build();
}
+HighlightStyle MaterialEntityRenderer::getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const {
+ if (const auto drawMaterial = getMaterial()) {
+ glm::vec3 position;
+ withReadLock([&] {
+ position = _renderTransform.getTranslation();
+ });
+ return HighlightStyle::calculateOutlineStyle(drawMaterial->getOutlineWidthMode(), drawMaterial->getOutlineWidth(),
+ drawMaterial->getOutline(), position, viewFrustum, height);
+ }
+ return HighlightStyle();
+}
+
void MaterialEntityRenderer::doRender(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableMaterialEntityItem::render");
Q_ASSERT(args->_batch);
@@ -316,21 +338,26 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
}
// Draw!
- DependencyManager::get()->renderSphere(batch);
+ const uint32_t compactColor = 0xFFFFFFFF;
+ _colorBuffer->setData(sizeof(compactColor), (const gpu::Byte*) &compactColor);
+ DependencyManager::get()->renderShape(batch, GeometryCache::Shape::Sphere, _colorBuffer);
} else {
auto proceduralDrawMaterial = std::static_pointer_cast(drawMaterial);
glm::vec4 outColor = glm::vec4(drawMaterial->getAlbedo(), drawMaterial->getOpacity());
outColor = proceduralDrawMaterial->getColor(outColor);
proceduralDrawMaterial->prepare(batch, transform.getTranslation(), transform.getScale(),
transform.getRotation(), _created, ProceduralProgramKey(outColor.a < 1.0f));
+
+ const uint32_t compactColor = GeometryCache::toCompactColor(glm::vec4(outColor));
+ _colorBuffer->setData(sizeof(compactColor), (const gpu::Byte*) &compactColor);
if (render::ShapeKey(args->_globalShapeKey).isWireframe() || _primitiveMode == PrimitiveMode::LINES) {
- DependencyManager::get()->renderWireSphere(batch, outColor);
+ DependencyManager::get()->renderWireShape(batch, GeometryCache::Shape::Sphere, _colorBuffer);
} else {
- DependencyManager::get()->renderSphere(batch, outColor);
+ DependencyManager::get()->renderShape(batch, GeometryCache::Shape::Sphere, _colorBuffer);
}
}
- args->_details._trianglesRendered += (int)DependencyManager::get()->getSphereTriangleCount();
+ args->_details._trianglesRendered += (int)DependencyManager::get()->getShapeTriangleCount(GeometryCache::Shape::Sphere);
}
void MaterialEntityRenderer::setCurrentMaterialName(const std::string& currentMaterialName) {
diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h
index 25403e8a2b..efded3aab3 100644
--- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h
@@ -1,6 +1,7 @@
//
// Created by Sam Gondelman on 1/18/2018
// Copyright 2018 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
@@ -32,6 +33,7 @@ private:
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override;
+ virtual HighlightStyle getOutlineStyle(const ViewFrustum& viewFrustum, const size_t height) const override;
ItemKey getKey() override;
ShapeKey getShapeKey() override;
@@ -65,6 +67,7 @@ private:
std::shared_ptr _appliedMaterial;
std::string _currentMaterialName;
+ gpu::BufferPointer _colorBuffer { std::make_shared() };
};
} }
diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp
index 8fa787d413..6393f76603 100644
--- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp
@@ -21,23 +21,48 @@ using namespace render::entities;
static uint8_t CUSTOM_PIPELINE_NUMBER = 0;
static gpu::Stream::FormatPointer _vertexFormat;
-static std::weak_ptr _texturedPipeline;
+// forward, transparent, shadow, wireframe
+static std::map, gpu::PipelinePointer> _pipelines;
static ShapePipelinePointer shapePipelineFactory(const ShapePlumber& plumber, const ShapeKey& key, RenderArgs* args) {
- auto texturedPipeline = _texturedPipeline.lock();
- if (!texturedPipeline) {
- auto state = std::make_shared();
- state->setCullMode(gpu::State::CULL_BACK);
- state->setDepthTest(true, false, gpu::LESS_EQUAL);
- state->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);
- PrepareStencil::testMask(*state);
+ if (_pipelines.empty()) {
+ using namespace shader::entities_renderer::program;
- auto program = gpu::Shader::createProgram(shader::entities_renderer::program::textured_particle);
- _texturedPipeline = texturedPipeline = gpu::Pipeline::create(program, state);
+ // forward, translucent, shadow
+ static const std::vector> keys = {
+ std::make_tuple(false, false, false, textured_particle),
+ std::make_tuple(true, false, false, textured_particle_forward),
+ std::make_tuple(false, true, false, textured_particle_translucent),
+ std::make_tuple(true, true, false, textured_particle_translucent_forward),
+ std::make_tuple(false, false, true, textured_particle_shadow),
+ // no such thing as shadow and forward/translucent
+ };
+
+ for (auto& key : keys) {
+ for (int i = 0; i < 2; ++i) {
+ bool transparent = std::get<1>(key);
+ bool wireframe = i == 0;
+
+ auto state = std::make_shared();
+ state->setCullMode(gpu::State::CULL_BACK);
+
+ if (wireframe) {
+ state->setFillMode(gpu::State::FILL_LINE);
+ }
+
+ state->setDepthTest(true, !transparent, gpu::LESS_EQUAL);
+ state->setBlendFunction(transparent, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE,
+ gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
+ transparent ? PrepareStencil::testMask(*state) : PrepareStencil::testMaskDrawShape(*state);
+
+ auto program = gpu::Shader::createProgram(std::get<3>(key));
+ _pipelines[std::make_tuple(std::get<0>(key), transparent, std::get<2>(key), wireframe)] = gpu::Pipeline::create(program, state);
+ }
+ }
}
- return std::make_shared(texturedPipeline, nullptr, nullptr, nullptr);
+ return std::make_shared(_pipelines[std::make_tuple(args->_renderMethod == Args::RenderMethod::FORWARD, key.isTranslucent(),
+ args->_renderMode == Args::RenderMode::SHADOW_RENDER_MODE, key.isWireframe())], nullptr, nullptr, nullptr);
}
struct GpuParticle {
@@ -138,28 +163,31 @@ void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEn
_uniformBuffer.edit() = particleUniforms;
}
+bool ParticleEffectEntityRenderer::isTransparent() const {
+ bool particleTransparent = _particleProperties.getColorStart().a < 1.0f || _particleProperties.getColorMiddle().a < 1.0f ||
+ _particleProperties.getColorFinish().a < 1.0f || _particleProperties.getColorSpread().a > 0.0f ||
+ _pulseProperties.getAlphaMode() != PulseMode::NONE || (_textureLoaded && _networkTexture && _networkTexture->getGPUTexture() &&
+ _networkTexture->getGPUTexture()->getUsage().isAlpha() && !_networkTexture->getGPUTexture()->getUsage().isAlphaMask());
+ return particleTransparent || Parent::isTransparent();
+}
+
ItemKey ParticleEffectEntityRenderer::getKey() {
- // FIXME: implement isTransparent() for particles and an opaque pipeline
- auto builder = ItemKey::Builder::transparentShape().withTagBits(getTagMask()).withLayer(getHifiRenderLayer());
-
- if (!_visible) {
- builder.withInvisible();
- }
-
- if (_cullWithParent) {
- builder.withSubMetaCulled();
- }
-
+ auto builder = ItemKey::Builder(Parent::getKey());
builder.withSimulate();
-
return builder.build();
}
ShapeKey ParticleEffectEntityRenderer::getShapeKey() {
- auto builder = ShapeKey::Builder().withCustom(CUSTOM_PIPELINE_NUMBER).withTranslucent();
+ auto builder = ShapeKey::Builder().withCustom(CUSTOM_PIPELINE_NUMBER);
+
+ if (isTransparent()) {
+ builder.withTranslucent();
+ }
+
if (_primitiveMode == PrimitiveMode::LINES) {
builder.withWireframe();
}
+
return builder.build();
}
diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h
index b3414594c3..d9a1745b06 100644
--- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h
@@ -30,6 +30,7 @@ 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;
diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
index 26091a1ed4..bda800abe2 100644
--- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp
@@ -1719,21 +1719,28 @@ using namespace render;
using namespace render::entities;
static uint8_t CUSTOM_PIPELINE_NUMBER;
-static std::map, ShapePipelinePointer> _pipelines;
+// forward, shadow, fade, wireframe
+static std::map, ShapePipelinePointer> _pipelines;
static gpu::Stream::FormatPointer _vertexFormat;
ShapePipelinePointer shapePipelineFactory(const ShapePlumber& plumber, const ShapeKey& key, RenderArgs* args) {
- // FIXME: custom pipelines like this don't handle shadows or renderLayers correctly
-
if (_pipelines.empty()) {
using namespace shader::entities_renderer::program;
- static const std::vector> keys = {
- std::make_tuple(false, false, polyvox), std::make_tuple(true, false, polyvox_forward)
+ // forward, shadow, fade
+ static const std::vector> keys = {
+ std::make_tuple(false, false, false, polyvox),
+ std::make_tuple(true, false, false, polyvox_forward),
+ std::make_tuple(false, true, false, polyvox_shadow),
+ // no such thing as forward + shadow
#ifdef POLYVOX_ENTITY_USE_FADE_EFFECT
- , std::make_tuple(false, true, polyvox_fade), std::make_tuple(true, true, polyvox_forward_fade)
+ std::make_tuple(false, false, true, polyvox_fade),
+ std::make_tuple(false, true, true, polyvox_shadow_fade),
+ // no such thing as forward + fade/shadow
#else
- , std::make_tuple(false, true, polyvox), std::make_tuple(true, true, polyvox_forward)
+ std::make_tuple(false, false, true, polyvox),
+ std::make_tuple(false, true, true, polyvox_shadow),
+ // no such thing as forward + fade/shadow
#endif
};
for (auto& key : keys) {
@@ -1749,19 +1756,19 @@ ShapePipelinePointer shapePipelineFactory(const ShapePlumber& plumber, const Sha
state->setFillMode(gpu::State::FILL_LINE);
}
- auto pipeline = gpu::Pipeline::create(gpu::Shader::createProgram(std::get<2>(key)), state);
- if (std::get<1>(key)) {
- _pipelines[std::make_tuple(std::get<0>(key), std::get<1>(key), wireframe)] = std::make_shared(pipeline, nullptr, nullptr, nullptr);
+ auto pipeline = gpu::Pipeline::create(gpu::Shader::createProgram(std::get<3>(key)), state);
+ if (!std::get<2>(key)) {
+ _pipelines[std::make_tuple(std::get<0>(key), std::get<1>(key), std::get<2>(key), wireframe)] = std::make_shared(pipeline, nullptr, nullptr, nullptr);
} else {
const auto& fadeEffect = DependencyManager::get();
- _pipelines[std::make_tuple(std::get<0>(key), std::get<1>(key), wireframe)] = std::make_shared(pipeline, nullptr,
+ _pipelines[std::make_tuple(std::get<0>(key), std::get<1>(key), std::get<2>(key), wireframe)] = std::make_shared(pipeline, nullptr,
fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter());
}
}
}
}
- return _pipelines[std::make_tuple(args->_renderMethod == Args::RenderMethod::FORWARD, key.isFaded(), key.isWireframe())];
+ return _pipelines[std::make_tuple(args->_renderMethod == Args::RenderMethod::FORWARD, args->_renderMode == Args::RenderMode::SHADOW_RENDER_MODE, key.isFaded(), key.isWireframe())];
}
PolyVoxEntityRenderer::PolyVoxEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {
@@ -1775,16 +1782,6 @@ PolyVoxEntityRenderer::PolyVoxEntityRenderer(const EntityItemPointer& entity) :
_params = std::make_shared(sizeof(glm::vec4), nullptr);
}
-ItemKey PolyVoxEntityRenderer::getKey() {
- auto builder = ItemKey::Builder::opaqueShape().withTagBits(getTagMask()).withLayer(getHifiRenderLayer());
-
- if (_cullWithParent) {
- builder.withSubMetaCulled();
- }
-
- return builder.build();
-}
-
ShapeKey PolyVoxEntityRenderer::getShapeKey() {
auto builder = ShapeKey::Builder().withCustom(CUSTOM_PIPELINE_NUMBER);
if (_primitiveMode == PrimitiveMode::LINES) {
@@ -1867,13 +1864,7 @@ void PolyVoxEntityRenderer::doRender(RenderArgs* args) {
batch.setModelTransform(transform);
batch.setInputFormat(_vertexFormat);
- batch.setInputBuffer(gpu::Stream::POSITION, _mesh->getVertexBuffer()._buffer, 0,
- sizeof(PolyVox::PositionMaterialNormal));
-
- // TODO -- should we be setting this?
- // batch.setInputBuffer(gpu::Stream::NORMAL, mesh->getVertexBuffer()._buffer,
- // 12,
- // sizeof(PolyVox::PositionMaterialNormal));
+ batch.setInputBuffer(gpu::Stream::POSITION, _mesh->getVertexBuffer()._buffer, 0, sizeof(PolyVox::PositionMaterialNormal));
batch.setIndexBuffer(gpu::UINT32, _mesh->getIndexBuffer()._buffer, 0);
for (size_t i = 0; i < _xyzTextures.size(); ++i) {
diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h
index c1c35a21c8..1debeb957c 100644
--- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h
+++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h
@@ -203,7 +203,6 @@ public:
}
protected:
- virtual ItemKey getKey() override;
virtual ShapeKey getShapeKey() override;
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
index 82350f54bf..2286045d5e 100644
--- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp
@@ -99,8 +99,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
materials = _materials["0"];
}
- auto& schema = materials.getSchemaBuffer().get();
- glm::vec4 outColor = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity);
+ glm::vec4 outColor = materials.getColor();
outColor = EntityRenderer::calculatePulseColor(outColor, _pulseProperties, _created);
if (outColor.a == 0.0f) {
@@ -133,10 +132,12 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
procedural->prepare(batch, transform.getTranslation(), transform.getScale(), transform.getRotation(), _created, ProceduralProgramKey(outColor.a < 1.0f));
});
+ const uint32_t compactColor = GeometryCache::toCompactColor(glm::vec4(outColor));
+ _colorBuffer->setData(sizeof(compactColor), (const gpu::Byte*) &compactColor);
if (wireframe) {
- geometryCache->renderWireShape(batch, geometryShape, outColor);
+ geometryCache->renderWireShape(batch, geometryShape, _colorBuffer);
} else {
- geometryCache->renderShape(batch, geometryShape, outColor);
+ geometryCache->renderShape(batch, geometryShape, _colorBuffer);
}
} else if (pipelineType == Pipeline::SIMPLE) {
// FIXME, support instanced multi-shape rendering using multidraw indirect
@@ -151,10 +152,12 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
geometryCache->renderSolidShapeInstance(args, batch, geometryShape, outColor, pipeline);
}
} else {
+ const uint32_t compactColor = GeometryCache::toCompactColor(glm::vec4(outColor));
+ _colorBuffer->setData(sizeof(compactColor), (const gpu::Byte*) &compactColor);
if (wireframe) {
- geometryCache->renderWireShape(batch, geometryShape, outColor);
+ geometryCache->renderWireShape(batch, geometryShape, _colorBuffer);
} else {
- geometryCache->renderShape(batch, geometryShape, outColor);
+ geometryCache->renderShape(batch, geometryShape, _colorBuffer);
}
}
} else {
@@ -162,7 +165,9 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
args->_details._materialSwitches++;
}
- geometryCache->renderShape(batch, geometryShape);
+ const uint32_t compactColor = GeometryCache::toCompactColor(glm::vec4(outColor));
+ _colorBuffer->setData(sizeof(compactColor), (const gpu::Byte*) &compactColor);
+ geometryCache->renderShape(batch, geometryShape, _colorBuffer);
}
const auto triCount = geometryCache->getShapeTriangleCount(geometryShape);
@@ -179,7 +184,7 @@ scriptable::ScriptableModelBase ShapeEntityRenderer::getScriptableModel() {
result.appendMaterials(_materials);
auto materials = _materials.find("0");
if (materials != _materials.end()) {
- vertexColor = ColorUtils::tosRGBVec3(materials->second.getSchemaBuffer().get()._albedo);
+ vertexColor = materials->second.getColor();
}
}
if (auto mesh = geometryCache->meshFromShape(geometryShape, vertexColor)) {
diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.h b/libraries/entities-renderer/src/RenderableShapeEntityItem.h
index 686014f4de..fd7bd4795b 100644
--- a/libraries/entities-renderer/src/RenderableShapeEntityItem.h
+++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.h
@@ -42,6 +42,8 @@ private:
std::shared_ptr _material { std::make_shared() };
glm::vec3 _color { NAN };
float _alpha { NAN };
+
+ gpu::BufferPointer _colorBuffer { std::make_shared() };
};
} }
diff --git a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp
index a15e2839a4..1cfab07986 100644
--- a/libraries/entities-renderer/src/RenderableTextEntityItem.cpp
+++ b/libraries/entities-renderer/src/RenderableTextEntityItem.cpp
@@ -147,8 +147,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
materials = _materials["0"];
}
- auto& schema = materials.getSchemaBuffer().get();
- glm::vec4 backgroundColor = glm::vec4(ColorUtils::tosRGBVec3(schema._albedo), schema._opacity);
+ glm::vec4 backgroundColor = materials.getColor();
backgroundColor = EntityRenderer::calculatePulseColor(backgroundColor, _pulseProperties, _created);
if (backgroundColor.a <= 0.0f) {
diff --git a/libraries/entities-renderer/src/entities-renderer/textured_particle.slp b/libraries/entities-renderer/src/entities-renderer/textured_particle.slp
index e69de29bb2..80b57dee25 100644
--- a/libraries/entities-renderer/src/entities-renderer/textured_particle.slp
+++ b/libraries/entities-renderer/src/entities-renderer/textured_particle.slp
@@ -0,0 +1 @@
+DEFINES (translucent:f forward:f)/shadow:f
\ No newline at end of file
diff --git a/libraries/entities-renderer/src/textured_particle.slf b/libraries/entities-renderer/src/textured_particle.slf
index 7dadb6fc49..04b74771a0 100644
--- a/libraries/entities-renderer/src/textured_particle.slf
+++ b/libraries/entities-renderer/src/textured_particle.slf
@@ -15,8 +15,34 @@ LAYOUT(binding=0) uniform sampler2D colorMap;
layout(location=0) in vec4 varColor;
layout(location=1) in vec2 varTexcoord;
-layout(location=0) out vec4 outFragColor;
+<@if HIFI_USE_FORWARD or HIFI_USE_SHADOW@>
+ layout(location=0) out vec4 _fragColor0;
+<@else@>
+ <@include DeferredBufferWrite.slh@>
+<@endif@>
void main(void) {
- outFragColor = texture(colorMap, varTexcoord.xy) * varColor;
+ vec4 albedo = texture(colorMap, varTexcoord.xy) * varColor;
+
+<@if HIFI_USE_FORWARD or HIFI_USE_SHADOW@>
+ <@if not HIFI_USE_TRANSLUCENT@>
+ // to reduce texel flickering for floating point error we discard when alpha is "almost one"
+ if (albedo.a < 0.999999) {
+ discard;
+ }
+ <@endif@>
+
+<@if HIFI_USE_FORWARD@>
+ _fragColor0 = albedo;
+<@else@>
+ _fragColor0 = vec4(1.0);
+<@endif@>
+<@else@>
+ vec3 NORMAL = vec3(1.0, 0.0, 0.0);
+ <@if not HIFI_USE_TRANSLUCENT@>
+ packDeferredFragmentUnlit(NORMAL, albedo.a, albedo.rgb);
+ <@else@>
+ packDeferredFragmentTranslucent(NORMAL, albedo.a, albedo.rgb, DEFAULT_ROUGHNESS);
+ <@endif@>
+<@endif@>
}
diff --git a/libraries/entities-renderer/src/textured_particle.slv b/libraries/entities-renderer/src/textured_particle.slv
index 98d25eae2e..9fd5e87d32 100644
--- a/libraries/entities-renderer/src/textured_particle.slv
+++ b/libraries/entities-renderer/src/textured_particle.slv
@@ -152,9 +152,9 @@ void main(void) {
<$transformModelToWorldDir(cam, obj, UP, modelUpWorld)$>
vec3 upWorld = mix(UP, normalize(modelUpWorld), float(particle.rotateWithEntity));
vec3 upEye = normalize(view3 * upWorld);
- vec3 FORWARD = vec3(0, 0, -1);
- vec3 particleRight = normalize(cross(FORWARD, upEye));
- vec3 particleUp = cross(particleRight, FORWARD); // don't need to normalize
+ vec3 eyeToParticle = normalize(anchorPoint.xyz - vec3(0.0));
+ vec3 particleRight = cross(eyeToParticle, upEye);
+ vec3 particleUp = cross(particleRight, eyeToParticle); // don't need to normalize
// This ordering ensures that un-rotated particles render upright in the viewer.
vec3 UNIT_QUAD[NUM_VERTICES_PER_PARTICLE] = vec3[NUM_VERTICES_PER_PARTICLE](
normalize(-particleRight + particleUp),
diff --git a/libraries/entities/src/AmbientLightPropertyGroup.cpp b/libraries/entities/src/AmbientLightPropertyGroup.cpp
index 829d8ecdf6..c430688113 100644
--- a/libraries/entities/src/AmbientLightPropertyGroup.cpp
+++ b/libraries/entities/src/AmbientLightPropertyGroup.cpp
@@ -22,10 +22,12 @@
const float AmbientLightPropertyGroup::DEFAULT_AMBIENT_LIGHT_INTENSITY = 0.5f;
void AmbientLightPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties,
- ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const {
-
+ ScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags,
+ bool isMyOwnAvatarEntity) const {
+
+ auto nodeList = DependencyManager::get();
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_AMBIENT_LIGHT_INTENSITY, AmbientLight, ambientLight, AmbientIntensity, ambientIntensity);
- COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_AMBIENT_LIGHT_URL, AmbientLight, ambientLight, AmbientURL, ambientURL);
+ COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(PROP_AMBIENT_LIGHT_URL, AmbientLight, ambientLight, AmbientURL, ambientURL);
}
void AmbientLightPropertyGroup::copyFromScriptValue(const ScriptValue& object, const QSet &namesSet, bool& _defaultSettings) {
diff --git a/libraries/entities/src/AmbientLightPropertyGroup.h b/libraries/entities/src/AmbientLightPropertyGroup.h
index 52451a6f8b..67597d1713 100644
--- a/libraries/entities/src/AmbientLightPropertyGroup.h
+++ b/libraries/entities/src/AmbientLightPropertyGroup.h
@@ -43,7 +43,8 @@ public:
// EntityItemProperty related helpers
virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties,
ScriptEngine* engine, bool skipDefaults,
- EntityItemProperties& defaultEntityProperties) const override;
+ EntityItemProperties& defaultEntityProperties, bool returnNothingOnEmptyPropertyFlags,
+ bool isMyOwnAvatarEntity) const override;
virtual void copyFromScriptValue(const ScriptValue& object, const QSet |