From 60d3dd98a44230c21803c1606552ee098ed9fa7c Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 21 Feb 2024 21:05:14 +0100 Subject: Convert remaining BOOL to bool --- indra/newview/llenvironment.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview/llenvironment.cpp') diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp index edc7bdef5f..4d893c5c0b 100644 --- a/indra/newview/llenvironment.cpp +++ b/indra/newview/llenvironment.cpp @@ -1639,7 +1639,7 @@ LLVector4 LLEnvironment::getRotatedLightNorm() const return toLightNorm(light_direction); } -extern BOOL gCubeSnapshot; +extern bool gCubeSnapshot; //------------------------------------------------------------------------- void LLEnvironment::update(const LLViewerCamera * cam) @@ -1678,7 +1678,7 @@ void LLEnvironment::update(const LLViewerCamera * cam) && (gPipeline.canUseWindLightShaders() || shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER)) { - shaders_iter->mUniformsDirty = TRUE; + shaders_iter->mUniformsDirty = true; } } } -- cgit v1.2.3 From e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 22 May 2024 21:25:21 +0200 Subject: Fix line endlings --- indra/newview/llenvironment.cpp | 7444 +++++++++++++++++++-------------------- 1 file changed, 3722 insertions(+), 3722 deletions(-) (limited to 'indra/newview/llenvironment.cpp') diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp index 234f0cebf7..775bcb3535 100644 --- a/indra/newview/llenvironment.cpp +++ b/indra/newview/llenvironment.cpp @@ -1,3722 +1,3722 @@ -/** - * @file llenvmanager.cpp - * @brief Implementation of classes managing WindLight and water settings. - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2011, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llenvironment.h" - -#include - -#include "llagent.h" -#include "llviewercontrol.h" // for gSavedSettings -#include "llviewerregion.h" -#include "llwlhandlers.h" -#include "lltrans.h" -#include "lltrace.h" -#include "llfasttimer.h" -#include "llviewercamera.h" -#include "pipeline.h" -#include "llsky.h" - -#include "llviewershadermgr.h" - -#include "llparcel.h" -#include "llviewerparcelmgr.h" - -#include "llsdserialize.h" -#include "lldiriterator.h" - -#include "llsettingsvo.h" -#include "llnotificationsutil.h" - -#include "llregioninfomodel.h" - -#include - -#include "llatmosphere.h" -#include "llagent.h" -#include "roles_constants.h" -#include "llestateinfomodel.h" - -#include "lldispatcher.h" -#include "llviewergenericmessage.h" -#include "llexperiencelog.h" - -//========================================================================= -namespace -{ - const std::string KEY_ENVIRONMENT("environment"); - const std::string KEY_DAYASSET("day_asset"); - const std::string KEY_DAYCYCLE("day_cycle"); - const std::string KEY_DAYHASH("day_hash"); - const std::string KEY_DAYLENGTH("day_length"); - const std::string KEY_DAYNAME("day_name"); - const std::string KEY_DAYNAMES("day_names"); - const std::string KEY_DAYOFFSET("day_offset"); - const std::string KEY_ENVVERSION("env_version"); - const std::string KEY_ISDEFAULT("is_default"); - const std::string KEY_PARCELID("parcel_id"); - const std::string KEY_REGIONID("region_id"); - const std::string KEY_TRACKALTS("track_altitudes"); - const std::string KEY_FLAGS("flags"); - - const std::string MESSAGE_PUSHENVIRONMENT("PushExpEnvironment"); - - const std::string ACTION_CLEARENVIRONMENT("ClearEnvironment"); - const std::string ACTION_PUSHFULLENVIRONMENT("PushFullEnvironment"); - const std::string ACTION_PUSHPARTIALENVIRONMENT("PushPartialEnvironment"); - - const std::string KEY_ASSETID("asset_id"); - const std::string KEY_TRANSITIONTIME("transition_time"); - const std::string KEY_ACTION("action"); - const std::string KEY_ACTIONDATA("action_data"); - const std::string KEY_EXPERIENCEID("public_id"); - const std::string KEY_OBJECTNAME("ObjectName"); // some of these do not conform to the '_' format. - const std::string KEY_PARCELNAME("ParcelName"); // But changing these would also alter the Experience Log requirements. - const std::string KEY_COUNT("Count"); - - const std::string LISTENER_NAME("LLEnvironmentSingleton"); - const std::string PUMP_EXPERIENCE("experience_permission"); - - const std::string LOCAL_ENV_STORAGE_FILE("local_environment_data.bin"); - - //--------------------------------------------------------------------- - LLTrace::BlockTimerStatHandle FTM_ENVIRONMENT_UPDATE("Update Environment Tick"); - - LLSettingsBase::Seconds DEFAULT_UPDATE_THRESHOLD(10.0); - const LLSettingsBase::Seconds MINIMUM_SPANLENGTH(0.01f); - - //--------------------------------------------------------------------- - inline LLSettingsBase::TrackPosition get_wrapping_distance(LLSettingsBase::TrackPosition begin, LLSettingsBase::TrackPosition end) - { - if (begin < end) - { - return end - begin; - } - else if (begin > end) - { - return LLSettingsBase::TrackPosition(1.0) - (begin - end); - } - - return 1.0f; - } - - LLSettingsDay::CycleTrack_t::iterator get_wrapping_atafter(LLSettingsDay::CycleTrack_t &collection, const LLSettingsBase::TrackPosition& key) - { - if (collection.empty()) - return collection.end(); - - LLSettingsDay::CycleTrack_t::iterator it = collection.upper_bound(key); - - if (it == collection.end()) - { // wrap around - it = collection.begin(); - } - - return it; - } - - LLSettingsDay::CycleTrack_t::iterator get_wrapping_atbefore(LLSettingsDay::CycleTrack_t &collection, const LLSettingsBase::TrackPosition& key) - { - if (collection.empty()) - return collection.end(); - - LLSettingsDay::CycleTrack_t::iterator it = collection.lower_bound(key); - - if (it == collection.end()) - { // all keyframes are lower, take the last one. - --it; // we know the range is not empty - } - else if ((*it).first > key) - { // the keyframe we are interested in is smaller than the found. - if (it == collection.begin()) - it = collection.end(); - --it; - } - - return it; - } - - LLSettingsDay::TrackBound_t get_bounding_entries(LLSettingsDay::CycleTrack_t &track, const LLSettingsBase::TrackPosition& keyframe) - { - return LLSettingsDay::TrackBound_t(get_wrapping_atbefore(track, keyframe), get_wrapping_atafter(track, keyframe)); - } - - // Find normalized track position of given time along full length of cycle - inline LLSettingsBase::TrackPosition convert_time_to_position(const LLSettingsBase::Seconds& time, const LLSettingsBase::Seconds& len) - { - // early out to avoid divide by zero. if len is zero then jump to end position - if (len == 0.f) return 1.f; - - LLSettingsBase::TrackPosition position = LLSettingsBase::TrackPosition(fmod((F64)time, (F64)len) / (F64)len); - return llclamp(position, 0.0f, 1.0f); - } - - inline LLSettingsBase::BlendFactor convert_time_to_blend_factor(const LLSettingsBase::Seconds& time, const LLSettingsBase::Seconds& len, LLSettingsDay::CycleTrack_t &track) - { - LLSettingsBase::TrackPosition position = convert_time_to_position(time, len); - LLSettingsDay::TrackBound_t bounds(get_bounding_entries(track, position)); - - LLSettingsBase::TrackPosition spanlength(get_wrapping_distance((*bounds.first).first, (*bounds.second).first)); - if (position < (*bounds.first).first) - position += 1.0; - - LLSettingsBase::TrackPosition start = position - (*bounds.first).first; - - return static_cast(start / spanlength); - } - - //--------------------------------------------------------------------- - class LLTrackBlenderLoopingTime : public LLSettingsBlenderTimeDelta - { - public: - LLTrackBlenderLoopingTime(const LLSettingsBase::ptr_t &target, const LLSettingsDay::ptr_t &day, S32 trackno, - LLSettingsBase::Seconds cyclelength, LLSettingsBase::Seconds cycleoffset, LLSettingsBase::Seconds updateThreshold) : - LLSettingsBlenderTimeDelta(target, LLSettingsBase::ptr_t(), LLSettingsBase::ptr_t(), LLSettingsBase::Seconds(1.0)), - mDay(day), - mTrackNo(0), - mCycleLength(cyclelength), - mCycleOffset(cycleoffset) - { - // must happen prior to getBoundingEntries call... - mTrackNo = selectTrackNumber(trackno); - - LLSettingsBase::Seconds now(getAdjustedNow()); - LLSettingsDay::TrackBound_t initial = getBoundingEntries(now); - - mInitial = (*initial.first).second; - mFinal = (*initial.second).second; - mBlendSpan = getSpanTime(initial); - - initializeTarget(now); - setOnFinished([this](const LLSettingsBlender::ptr_t &){ onFinishedSpan(); }); - } - - void switchTrack(S32 trackno, const LLSettingsBase::TrackPosition&) override - { - S32 use_trackno = selectTrackNumber(trackno); - - if (use_trackno == mTrackNo) - { // results in no change - return; - } - - LLSettingsBase::ptr_t pstartsetting = mTarget->buildDerivedClone(); - mTrackNo = use_trackno; - - LLSettingsBase::Seconds now = getAdjustedNow() + LLEnvironment::TRANSITION_ALTITUDE; - LLSettingsDay::TrackBound_t bounds = getBoundingEntries(now); - - LLSettingsBase::ptr_t pendsetting = (*bounds.first).second->buildDerivedClone(); - LLSettingsBase::TrackPosition targetpos = convert_time_to_position(now, mCycleLength) - (*bounds.first).first; - LLSettingsBase::TrackPosition targetspan = get_wrapping_distance((*bounds.first).first, (*bounds.second).first); - - LLSettingsBase::BlendFactor blendf = calculateBlend(targetpos, targetspan); - pendsetting->blend((*bounds.second).second, blendf); - - reset(pstartsetting, pendsetting, LLEnvironment::TRANSITION_ALTITUDE); - } - - protected: - S32 selectTrackNumber(S32 trackno) - { - if (trackno == 0) - { // We are dealing with the water track. There is only ever one. - return trackno; - } - - for (S32 test = trackno; test != 0; --test) - { // Find the track below the requested one with data. - LLSettingsDay::CycleTrack_t &track = mDay->getCycleTrack(test); - - if (!track.empty()) - return test; - } - - return 1; - } - - LLSettingsDay::TrackBound_t getBoundingEntries(LLSettingsBase::Seconds time) - { - LLSettingsDay::CycleTrack_t &wtrack = mDay->getCycleTrack(mTrackNo); - LLSettingsBase::TrackPosition position = convert_time_to_position(time, mCycleLength); - LLSettingsDay::TrackBound_t bounds = get_bounding_entries(wtrack, position); - return bounds; - } - - void initializeTarget(LLSettingsBase::Seconds time) - { - LLSettingsBase::BlendFactor blendf(convert_time_to_blend_factor(time, mCycleLength, mDay->getCycleTrack(mTrackNo))); - - blendf = llclamp(blendf, 0.0, 0.999); - setTimeSpent(LLSettingsBase::Seconds(blendf * mBlendSpan)); - - setBlendFactor(blendf); - } - - LLSettingsBase::Seconds getAdjustedNow() const - { - LLSettingsBase::Seconds now(LLDate::now().secondsSinceEpoch()); - - return (now + mCycleOffset); - } - - LLSettingsBase::Seconds getSpanTime(const LLSettingsDay::TrackBound_t &bounds) const - { - LLSettingsBase::Seconds span = mCycleLength * get_wrapping_distance((*bounds.first).first, (*bounds.second).first); - if (span < MINIMUM_SPANLENGTH) // for very short spans set a minimum length. - span = MINIMUM_SPANLENGTH; - return span; - } - - private: - LLSettingsDay::ptr_t mDay; - S32 mTrackNo; - LLSettingsBase::Seconds mCycleLength; - LLSettingsBase::Seconds mCycleOffset; - - void onFinishedSpan() - { - LLSettingsBase::Seconds adjusted_now = getAdjustedNow(); - LLSettingsDay::TrackBound_t next = getBoundingEntries(adjusted_now); - LLSettingsBase::Seconds nextspan = getSpanTime(next); - - reset((*next.first).second, (*next.second).second, nextspan); - - // Recalculate (reinitialize) position. Because: - // - 'delta' from applyTimeDelta accumulates errors (probably should be fixed/changed to absolute time) - // - freezes and lag can result in reset being called too late, so we need to add missed time - // - occasional time corrections can happen - // - some transition switches can happen outside applyTimeDelta thus causing 'desync' from 'delta' (can be fixed by getting rid of delta) - initializeTarget(adjusted_now); - } - }; - - class LLEnvironmentPushDispatchHandler : public LLDispatchHandler - { - public: - virtual bool operator()(const LLDispatcher *, const std::string& key, const LLUUID& invoice, const sparam_t& strings) override - { - LLSD message; - sparam_t::const_iterator it = strings.begin(); - - if (it != strings.end()) - { - const std::string& llsdRaw = *it++; - std::istringstream llsdData(llsdRaw); - if (!LLSDSerialize::deserialize(message, llsdData, llsdRaw.length())) - { - LL_WARNS() << "LLEnvironmentPushDispatchHandler: Attempted to read parameter data into LLSD but failed:" << llsdRaw << LL_ENDL; - } - } - - message[KEY_EXPERIENCEID] = invoice; - // Object Name - if (it != strings.end()) - { - message[KEY_OBJECTNAME] = *it++; - } - - // parcel Name - if (it != strings.end()) - { - message[KEY_PARCELNAME] = *it++; - } - message[KEY_COUNT] = 1; - - LLEnvironment::instance().handleEnvironmentPush(message); - return true; - } - }; - - LLEnvironmentPushDispatchHandler environment_push_dispatch_handler; - - template - class LLSettingsInjected : public SETTINGT - { - public: - typedef std::shared_ptr > ptr_t; - - LLSettingsInjected(typename SETTINGT::ptr_t source) : - SETTINGT(), - mSource(source), - mLastSourceHash(0), - mLastHash(0) - {} - - virtual ~LLSettingsInjected() {}; - - typename SETTINGT::ptr_t getSource() const { return this->mSource; } - void setSource(const typename SETTINGT::ptr_t &source) - { - if (source.get() == this) // do not set a source to itself. - return; - this->mSource = source; - this->setDirtyFlag(true); - this->mLastSourceHash = 0; - } - - virtual bool isDirty() const override { return SETTINGT::isDirty() || (this->mSource->isDirty()); } - virtual bool isVeryDirty() const override { return SETTINGT::isVeryDirty() || (this->mSource->isVeryDirty()); } - - void injectSetting(const std::string keyname, LLSD value, LLUUID experience_id, F32Seconds transition) - { - if (transition > 0.1) - { - typename Injection::ptr_t injection = std::make_shared(transition, keyname, value, true, experience_id); - - mInjections.push_back(injection); - std::stable_sort(mInjections.begin(), mInjections.end(), [](const typename Injection::ptr_t &a, const typename Injection::ptr_t &b) { return a->mTimeRemaining < b->mTimeRemaining; }); - } - else - { - mOverrideValues[keyname] = value; - mOverrideExps[keyname] = experience_id; - this->setDirtyFlag(true); - } - } - - void removeInjection(const std::string keyname, LLUUID experience, LLSettingsBase::Seconds transition) - { - injections_t injections_buf; - for (auto it = mInjections.begin(); it != mInjections.end(); it++) - { - if ((keyname.empty() || ((*it)->mKeyName == keyname)) && - (experience.isNull() || (experience == (*it)->mExperience))) - { - if (transition != LLEnvironment::TRANSITION_INSTANT) - { - typename Injection::ptr_t injection = std::make_shared(transition, keyname, (*it)->mLastValue, false, LLUUID::null); - injections_buf.push_front(injection); - } - } - else - { - injections_buf.push_front(*it); - } - } - mInjections.clear(); - mInjections = injections_buf; - - for (auto itexp = mOverrideExps.begin(); itexp != mOverrideExps.end();) - { - if (experience.isNull() || ((*itexp).second == experience)) - { - if (transition != LLEnvironment::TRANSITION_INSTANT) - { - typename Injection::ptr_t injection = std::make_shared(transition, (*itexp).first, mOverrideValues[(*itexp).first], false, LLUUID::null); - mInjections.push_front(injection); - } - mOverrideValues.erase((*itexp).first); - mOverrideExps.erase(itexp++); - } - else - ++itexp; - } - std::stable_sort(mInjections.begin(), mInjections.end(), [](const typename Injection::ptr_t &a, const typename Injection::ptr_t &b) { return a->mTimeRemaining < b->mTimeRemaining; }); - } - - void removeInjections(LLUUID experience_id, LLSettingsBase::Seconds transition) - { - removeInjection(std::string(), experience_id, transition); - } - - void injectExperienceValues(LLSD values, LLUUID experience_id, typename LLSettingsBase::Seconds transition) - { - for (auto it = values.beginMap(); it != values.endMap(); ++it) - { - injectSetting((*it).first, (*it).second, experience_id, transition); - } - this->setDirtyFlag(true); - } - - void applyInjections(LLSettingsBase::Seconds delta) - { - this->mSettings = this->mSource->getSettings(); - - for (auto ito = mOverrideValues.beginMap(); ito != mOverrideValues.endMap(); ++ito) - { - this->mSettings[(*ito).first] = (*ito).second; - } - - const LLSettingsBase::stringset_t &slerps = this->getSlerpKeys(); - const LLSettingsBase::stringset_t &skips = this->getSkipInterpolateKeys(); - const LLSettingsBase::stringset_t &specials = this->getSpecialKeys(); - - typename injections_t::iterator it; - for (it = mInjections.begin(); it != mInjections.end(); ++it) - { - std::string key_name = (*it)->mKeyName; - - LLSD value = this->mSettings[key_name]; - LLSD target = (*it)->mValue; - - if ((*it)->mFirstTime) - (*it)->mFirstTime = false; - else - (*it)->mTimeRemaining -= delta; - - typename LLSettingsBase::BlendFactor mix = 1.0f - ((*it)->mTimeRemaining.value() / (*it)->mTransition.value()); - - if (mix >= 1.0) - { - if ((*it)->mBlendIn) - { - mOverrideValues[key_name] = target; - mOverrideExps[key_name] = (*it)->mExperience; - this->mSettings[key_name] = target; - } - else - { - this->mSettings.erase(key_name); - } - } - else if (specials.find(key_name) != specials.end()) - { - updateSpecial(*it, mix); - } - else if (skips.find(key_name) == skips.end()) - { - if (!(*it)->mBlendIn) - mix = 1.0 - mix; - (*it)->mLastValue = this->interpolateSDValue(key_name, value, target, this->getParameterMap(), mix, slerps); - this->mSettings[key_name] = (*it)->mLastValue; - } - } - - size_t hash = this->getHash(); - - if (hash != mLastHash) - { - this->setDirtyFlag(true); - mLastHash = hash; - } - - it = mInjections.begin(); - it = std::find_if(mInjections.begin(), mInjections.end(), [](const typename Injection::ptr_t &a) { return a->mTimeRemaining > 0.0f; }); - - if (it != mInjections.begin()) - { - mInjections.erase(mInjections.begin(), mInjections.end()); - } - - } - - bool hasInjections() const - { - return (!mInjections.empty() || (mOverrideValues.size() > 0)); - } - - protected: - struct Injection - { - Injection(typename LLSettingsBase::Seconds transition, const std::string &keyname, LLSD value, bool blendin, LLUUID experince, S32 index = -1) : - mTransition(transition), - mTimeRemaining(transition), - mKeyName(keyname), - mValue(value), - mExperience(experince), - mIndex(index), - mBlendIn(blendin), - mFirstTime(true) - {} - - typename LLSettingsBase::Seconds mTransition; - typename LLSettingsBase::Seconds mTimeRemaining; - std::string mKeyName; - LLSD mValue; - LLSD mLastValue; - LLUUID mExperience; - S32 mIndex; - bool mBlendIn; - bool mFirstTime; - - typedef std::shared_ptr ptr_t; - }; - - - virtual void updateSettings() override - { - static LLFrameTimer timer; - - if (!this->mSource) - return; - - // clears the dirty flag on this object. Need to prevent triggering - // more calls into this updateSettings - LLSettingsBase::updateSettings(); - - resetSpecial(); - - if (this->mSource->isDirty()) - { - this->mSource->updateSettings(); - } - - typename LLSettingsBase::Seconds delta(timer.getElapsedTimeAndResetF32()); - - - SETTINGT::updateSettings(); - - if (!mInjections.empty()) - this->setDirtyFlag(true); - } - - LLSettingsBase::stringset_t getSpecialKeys() const; - void resetSpecial(); - void updateSpecial(const typename Injection::ptr_t &injection, typename LLSettingsBase::BlendFactor mix); - - private: - typedef std::map key_to_expid_t; - typedef std::deque injections_t; - - size_t mLastSourceHash; - size_t mLastHash; - typename SETTINGT::ptr_t mSource; - injections_t mInjections; - LLSD mOverrideValues; - key_to_expid_t mOverrideExps; - }; - - template<> - LLSettingsBase::stringset_t LLSettingsInjected::getSpecialKeys() const - { - static LLSettingsBase::stringset_t specialSet; - - if (specialSet.empty()) - { - specialSet.insert(SETTING_BLOOM_TEXTUREID); - specialSet.insert(SETTING_RAINBOW_TEXTUREID); - specialSet.insert(SETTING_HALO_TEXTUREID); - specialSet.insert(SETTING_CLOUD_TEXTUREID); - specialSet.insert(SETTING_MOON_TEXTUREID); - specialSet.insert(SETTING_SUN_TEXTUREID); - specialSet.insert(SETTING_CLOUD_SHADOW); // due to being part of skips - } - return specialSet; - } - - template<> - LLSettingsBase::stringset_t LLSettingsInjected::getSpecialKeys() const - { - static stringset_t specialSet; - - if (specialSet.empty()) - { - specialSet.insert(SETTING_TRANSPARENT_TEXTURE); - specialSet.insert(SETTING_NORMAL_MAP); - } - return specialSet; - } - - template<> - void LLSettingsInjected::resetSpecial() - { - mNextSunTextureId.setNull(); - mNextMoonTextureId.setNull(); - mNextCloudTextureId.setNull(); - mNextBloomTextureId.setNull(); - mNextRainbowTextureId.setNull(); - mNextHaloTextureId.setNull(); - setBlendFactor(0.0f); - } - - template<> - void LLSettingsInjected::resetSpecial() - { - mNextNormalMapID.setNull(); - mNextTransparentTextureID.setNull(); - setBlendFactor(0.0f); - } - - template<> - void LLSettingsInjected::updateSpecial(const typename LLSettingsInjected::Injection::ptr_t &injection, typename LLSettingsBase::BlendFactor mix) - { - bool is_texture = true; - if (injection->mKeyName == SETTING_SUN_TEXTUREID) - { - mNextSunTextureId = injection->mValue.asUUID(); - } - else if (injection->mKeyName == SETTING_MOON_TEXTUREID) - { - mNextMoonTextureId = injection->mValue.asUUID(); - } - else if (injection->mKeyName == SETTING_CLOUD_TEXTUREID) - { - mNextCloudTextureId = injection->mValue.asUUID(); - } - else if (injection->mKeyName == SETTING_BLOOM_TEXTUREID) - { - mNextBloomTextureId = injection->mValue.asUUID(); - } - else if (injection->mKeyName == SETTING_RAINBOW_TEXTUREID) - { - mNextRainbowTextureId = injection->mValue.asUUID(); - } - else if (injection->mKeyName == SETTING_HALO_TEXTUREID) - { - mNextHaloTextureId = injection->mValue.asUUID(); - } - else if (injection->mKeyName == LLSettingsSky::SETTING_CLOUD_SHADOW) - { - // Special case due to being texture dependent and part of skips - is_texture = false; - if (!injection->mBlendIn) - mix = 1.0 - mix; - stringset_t dummy; - F64 value = this->mSettings[injection->mKeyName].asReal(); - if (this->getCloudNoiseTextureId().isNull()) - { - value = 0; // there was no texture so start from zero coverage - } - // Ideally we need to check for texture in injection, but - // in this case user is setting value explicitly, potentially - // with different transitions, don't ignore it - F64 result = lerp(value, injection->mValue.asReal(), mix); - injection->mLastValue = LLSD::Real(result); - this->mSettings[injection->mKeyName] = injection->mLastValue; - } - - // Unfortunately I don't have a per texture blend factor. We'll just pick the one that is furthest along. - if (is_texture && getBlendFactor() < mix) - { - setBlendFactor(mix); - } - } - - template<> - void LLSettingsInjected::updateSpecial(const typename LLSettingsInjected::Injection::ptr_t &injection, typename LLSettingsBase::BlendFactor mix) - { - if (injection->mKeyName == SETTING_NORMAL_MAP) - { - mNextNormalMapID = injection->mValue.asUUID(); - } - else if (injection->mKeyName == SETTING_TRANSPARENT_TEXTURE) - { - mNextTransparentTextureID = injection->mValue.asUUID(); - } - - // Unfortunately I don't have a per texture blend factor. We'll just pick the one that is furthest along. - if (getBlendFactor() < mix) - { - setBlendFactor(mix); - } - } - - typedef LLSettingsInjected LLSettingsInjectedSky; - typedef LLSettingsInjected LLSettingsInjectedWater; - - //===================================================================== - class DayInjection : public LLEnvironment::DayInstance - { - friend class InjectedTransition; - - public: - typedef std::shared_ptr ptr_t; - typedef std::weak_ptr wptr_t; - - DayInjection(LLEnvironment::EnvSelection_t env); - virtual ~DayInjection(); - - virtual bool applyTimeDelta(const LLSettingsBase::Seconds& delta) override; - - void setInjectedDay(const LLSettingsDay::ptr_t &pday, LLUUID experience_id, LLSettingsBase::Seconds transition); - void setInjectedSky(const LLSettingsSky::ptr_t &psky, LLUUID experience_id, LLSettingsBase::Seconds transition); - void setInjectedWater(const LLSettingsWater::ptr_t &pwater, LLUUID experience_id, LLSettingsBase::Seconds transition); - - void injectSkySettings(LLSD settings, LLUUID experience_id, LLSettingsBase::Seconds transition); - void injectWaterSettings(LLSD settings, LLUUID experience_id, LLSettingsBase::Seconds transition); - - void clearInjections(LLUUID experience_id, LLSettingsBase::Seconds transition_time); - - virtual void animate() override; - - LLEnvironment::DayInstance::ptr_t getBaseDayInstance() const { return mBaseDayInstance; } - void setBaseDayInstance(const LLEnvironment::DayInstance::ptr_t &baseday); - - S32 countExperiencesActive() const { return mActiveExperiences.size(); } - - bool isOverriddenSky() const { return !mSkyExperience.isNull(); } - bool isOverriddenWater() const { return !mWaterExperience.isNull(); } - - bool hasInjections() const; - - void testExperiencesOnParcel(S32 parcel_id); - private: - static void testExperiencesOnParcelCoro(wptr_t that, S32 parcel_id); - - - void animateSkyChange(LLSettingsSky::ptr_t psky, LLSettingsBase::Seconds transition); - void animateWaterChange(LLSettingsWater::ptr_t pwater, LLSettingsBase::Seconds transition); - - void onEnvironmentChanged(LLEnvironment::EnvSelection_t env); - void onParcelChange(); - - void checkExperience(); - - - LLEnvironment::DayInstance::ptr_t mBaseDayInstance; - - LLSettingsInjectedSky::ptr_t mInjectedSky; - LLSettingsInjectedWater::ptr_t mInjectedWater; - std::set mActiveExperiences; - LLUUID mDayExperience; - LLUUID mSkyExperience; - LLUUID mWaterExperience; - LLEnvironment::connection_t mEnvChangeConnection; - boost::signals2::connection mParcelChangeConnection; - }; - - class InjectedTransition : public LLEnvironment::DayTransition - { - public: - InjectedTransition(const DayInjection::ptr_t &injection, const LLSettingsSky::ptr_t &skystart, const LLSettingsWater::ptr_t &waterstart, DayInstance::ptr_t &end, LLSettingsDay::Seconds time): - LLEnvironment::DayTransition(skystart, waterstart, end, time), - mInjection(injection) - { } - virtual ~InjectedTransition() { }; - - virtual void animate() override; - - protected: - DayInjection::ptr_t mInjection; - }; - -} - -//========================================================================= -const F64Seconds LLEnvironment::TRANSITION_INSTANT(0.0f); -const F64Seconds LLEnvironment::TRANSITION_FAST(1.0f); -const F64Seconds LLEnvironment::TRANSITION_DEFAULT(5.0f); -const F64Seconds LLEnvironment::TRANSITION_SLOW(10.0f); -const F64Seconds LLEnvironment::TRANSITION_ALTITUDE(5.0f); - -const LLUUID LLEnvironment::KNOWN_SKY_SUNRISE("01e41537-ff51-2f1f-8ef7-17e4df760bfb"); -const LLUUID LLEnvironment::KNOWN_SKY_MIDDAY("c46226b4-0e43-5a56-9708-d27ca1df3292"); -const LLUUID LLEnvironment::KNOWN_SKY_LEGACY_MIDDAY("cef49723-0292-af49-9b14-9598a616b8a3"); -const LLUUID LLEnvironment::KNOWN_SKY_SUNSET("084e26cd-a900-28e8-08d0-64a9de5c15e2"); -const LLUUID LLEnvironment::KNOWN_SKY_MIDNIGHT("8a01b97a-cb20-c1ea-ac63-f7ea84ad0090"); - -const S32 LLEnvironment::NO_TRACK(-1); -const S32 LLEnvironment::NO_VERSION(-3); // For viewer sided change, like ENV_LOCAL. -3 since -1 and -2 are taken by parcel initial server/viewer version -const S32 LLEnvironment::VERSION_CLEANUP(-4); // for cleanups - -const F32 LLEnvironment::SUN_DELTA_YAW(F_PI); // 180deg - - -const U32 LLEnvironment::DayInstance::NO_ANIMATE_SKY(0x01); -const U32 LLEnvironment::DayInstance::NO_ANIMATE_WATER(0x02); - -std::string env_selection_to_string(LLEnvironment::EnvSelection_t sel) -{ -#define RTNENUM(E) case LLEnvironment::E: return #E - switch (sel){ - RTNENUM(ENV_EDIT); - RTNENUM(ENV_LOCAL); - RTNENUM(ENV_PUSH); - RTNENUM(ENV_PARCEL); - RTNENUM(ENV_REGION); - RTNENUM(ENV_DEFAULT); - RTNENUM(ENV_END); - RTNENUM(ENV_CURRENT); - RTNENUM(ENV_NONE); - default: - return llformat("Unknown(%d)", sel); - } -#undef RTNENUM -} - -//------------------------------------------------------------------------- -LLEnvironment::LLEnvironment(): - mCloudScrollDelta(), - mCloudScrollPaused(false), - mSelectedSky(), - mSelectedWater(), - mSelectedDay(), - mSelectedEnvironment(LLEnvironment::ENV_LOCAL), - mCurrentTrack(1), - mEditorCounter(0), - mShowSunBeacon(false), - mShowMoonBeacon(false) -{ -} - -void LLEnvironment::initSingleton() -{ - LLSettingsSky::ptr_t p_default_sky = LLSettingsVOSky::buildDefaultSky(); - LLSettingsWater::ptr_t p_default_water = LLSettingsVOWater::buildDefaultWater(); - - mCurrentEnvironment = std::make_shared(ENV_DEFAULT); - mCurrentEnvironment->setSky(p_default_sky); - mCurrentEnvironment->setWater(p_default_water); - - mEnvironments[ENV_DEFAULT] = mCurrentEnvironment; - - requestRegion(); - - if (!mParcelCallbackConnection.connected()) - { - mParcelCallbackConnection = gAgent.addParcelChangedCallback([this]() { onParcelChange(); }); - - //TODO: This frequently results in one more request than we need. It isn't breaking, but should be nicer. - // We need to know new env version to fix this, without it we can only do full re-request - // Happens: on updates, on opening LLFloaterRegionInfo, on region crossing if info floater is open - mRegionUpdateCallbackConnection = LLRegionInfoModel::instance().setUpdateCallback([this]() { requestRegion(); }); - mRegionChangeCallbackConnection = gAgent.addRegionChangedCallback([this]() { onRegionChange(); }); - - mPositionCallbackConnection = gAgent.whenPositionChanged([this](const LLVector3 &localpos, const LLVector3d &) { onAgentPositionHasChanged(localpos); }); - } - - if (!gGenericDispatcher.isHandlerPresent(MESSAGE_PUSHENVIRONMENT)) - { - gGenericDispatcher.addHandler(MESSAGE_PUSHENVIRONMENT, &environment_push_dispatch_handler); - } - - gSavedSettings.getControl("RenderSkyAutoAdjustProbeAmbiance")->getSignal()->connect( - [](LLControlVariable*, const LLSD& new_val, const LLSD& old_val) - { - LLSettingsSky::sAutoAdjustProbeAmbiance = new_val.asReal(); - } - ); - LLSettingsSky::sAutoAdjustProbeAmbiance = gSavedSettings.getF32("RenderSkyAutoAdjustProbeAmbiance"); - - LLEventPumps::instance().obtain(PUMP_EXPERIENCE).stopListening(LISTENER_NAME); - LLEventPumps::instance().obtain(PUMP_EXPERIENCE).listen(LISTENER_NAME, [this](LLSD message) { listenExperiencePump(message); return false; }); -} - -void LLEnvironment::cleanupSingleton() -{ - if (mParcelCallbackConnection.connected()) - { - mParcelCallbackConnection.disconnect(); - mRegionUpdateCallbackConnection.disconnect(); - mRegionChangeCallbackConnection.disconnect(); - mPositionCallbackConnection.disconnect(); - } - LLEventPumps::instance().obtain(PUMP_EXPERIENCE).stopListening(LISTENER_NAME); -} - -LLEnvironment::~LLEnvironment() -{ - cleanupSingleton(); -} - -bool LLEnvironment::canEdit() const -{ - return true; -} - -LLSettingsSky::ptr_t LLEnvironment::getCurrentSky() const -{ - LLSettingsSky::ptr_t psky = mCurrentEnvironment->getSky(); - - if (!psky && mCurrentEnvironment->getEnvironmentSelection() >= ENV_EDIT) - { - for (int idx = 0; idx < ENV_END; ++idx) - { - if (mEnvironments[idx]->getSky()) - { - psky = mEnvironments[idx]->getSky(); - break; - } - } - } - return psky; -} - -LLSettingsWater::ptr_t LLEnvironment::getCurrentWater() const -{ - LLSettingsWater::ptr_t pwater = mCurrentEnvironment->getWater(); - - if (!pwater && mCurrentEnvironment->getEnvironmentSelection() >= ENV_EDIT) - { - for (int idx = 0; idx < ENV_END; ++idx) - { - if (mEnvironments[idx]->getWater()) - { - pwater = mEnvironments[idx]->getWater(); - break; - } - } - } - return pwater; -} - -void LayerConfigToDensityLayer(const LLSD& layerConfig, DensityLayer& layerOut) -{ - layerOut.constant_term = layerConfig[LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM].asReal(); - layerOut.exp_scale = layerConfig[LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR].asReal(); - layerOut.exp_term = layerConfig[LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM].asReal(); - layerOut.linear_term = layerConfig[LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM].asReal(); - layerOut.width = layerConfig[LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH].asReal(); -} - -void LLEnvironment::getAtmosphericModelSettings(AtmosphericModelSettings& settingsOut, const LLSettingsSky::ptr_t &psky) -{ - settingsOut.m_skyBottomRadius = psky->getSkyBottomRadius(); - settingsOut.m_skyTopRadius = psky->getSkyTopRadius(); - settingsOut.m_sunArcRadians = psky->getSunArcRadians(); - settingsOut.m_mieAnisotropy = psky->getMieAnisotropy(); - - LLSD rayleigh = psky->getRayleighConfigs(); - settingsOut.m_rayleighProfile.clear(); - for (LLSD::array_iterator itf = rayleigh.beginArray(); itf != rayleigh.endArray(); ++itf) - { - DensityLayer layer; - LLSD& layerConfig = (*itf); - LayerConfigToDensityLayer(layerConfig, layer); - settingsOut.m_rayleighProfile.push_back(layer); - } - - LLSD mie = psky->getMieConfigs(); - settingsOut.m_mieProfile.clear(); - for (LLSD::array_iterator itf = mie.beginArray(); itf != mie.endArray(); ++itf) - { - DensityLayer layer; - LLSD& layerConfig = (*itf); - LayerConfigToDensityLayer(layerConfig, layer); - settingsOut.m_mieProfile.push_back(layer); - } - settingsOut.m_mieAnisotropy = psky->getMieAnisotropy(); - - LLSD absorption = psky->getAbsorptionConfigs(); - settingsOut.m_absorptionProfile.clear(); - for (LLSD::array_iterator itf = absorption.beginArray(); itf != absorption.endArray(); ++itf) - { - DensityLayer layer; - LLSD& layerConfig = (*itf); - LayerConfigToDensityLayer(layerConfig, layer); - settingsOut.m_absorptionProfile.push_back(layer); - } -} - -bool LLEnvironment::canAgentUpdateParcelEnvironment() const -{ - LLParcel *parcel(LLViewerParcelMgr::instance().getAgentOrSelectedParcel()); - - return canAgentUpdateParcelEnvironment(parcel); -} - - -bool LLEnvironment::canAgentUpdateParcelEnvironment(LLParcel *parcel) const -{ - if (!parcel) - return false; - - if (!LLEnvironment::instance().isExtendedEnvironmentEnabled()) - return false; - - if (gAgent.isGodlike()) - return true; - - if (!parcel->getRegionAllowEnvironmentOverride()) - return false; - - return LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_ALLOW_ENVIRONMENT); -} - -bool LLEnvironment::canAgentUpdateRegionEnvironment() const -{ - if (gAgent.isGodlike()) - return true; - - return gAgent.canManageEstate(); -} - -bool LLEnvironment::isExtendedEnvironmentEnabled() const -{ - return !gAgent.getRegionCapability("ExtEnvironment").empty(); -} - -bool LLEnvironment::isInventoryEnabled() const -{ - return (!gAgent.getRegionCapability("UpdateSettingsAgentInventory").empty() && - !gAgent.getRegionCapability("UpdateSettingsTaskInventory").empty()); -} - -void LLEnvironment::onRegionChange() -{ -// if (gAgent.getRegionCapability("ExperienceQuery").empty()) -// { -// // for now environmental experiences do not survive region crossings - clearExperienceEnvironment(LLUUID::null, TRANSITION_DEFAULT); -// } - - LLViewerRegion* cur_region = gAgent.getRegion(); - if (!cur_region) - { - return; - } - if (!cur_region->capabilitiesReceived()) - { - cur_region->setCapabilitiesReceivedCallback([](const LLUUID ®ion_id, LLViewerRegion* regionp) { LLEnvironment::instance().requestRegion(); }); - return; - } - requestRegion(); -} - -void LLEnvironment::onParcelChange() -{ - S32 parcel_id(INVALID_PARCEL_ID); - LLParcel* parcel = LLViewerParcelMgr::instance().getAgentParcel(); - - if (parcel) - { - parcel_id = parcel->getLocalID(); - } - - requestParcel(parcel_id); -} - -//------------------------------------------------------------------------- -F32 LLEnvironment::getCamHeight() const -{ - return (mCurrentEnvironment->getSky()->getDomeOffset() * mCurrentEnvironment->getSky()->getDomeRadius()); -} - -F32 LLEnvironment::getWaterHeight() const -{ - LLViewerRegion* cur_region = gAgent.getRegion(); - return cur_region ? cur_region->getWaterHeight() : DEFAULT_WATER_HEIGHT; -} - -bool LLEnvironment::getIsSunUp() const -{ - if (!mCurrentEnvironment || !mCurrentEnvironment->getSky()) - return false; - return mCurrentEnvironment->getSky()->getIsSunUp(); -} - -bool LLEnvironment::getIsMoonUp() const -{ - if (!mCurrentEnvironment || !mCurrentEnvironment->getSky()) - return false; - return mCurrentEnvironment->getSky()->getIsMoonUp(); -} - -//------------------------------------------------------------------------- -void LLEnvironment::setSelectedEnvironment(LLEnvironment::EnvSelection_t env, LLSettingsBase::Seconds transition, bool forced) -{ - mSelectedEnvironment = env; - updateEnvironment(transition, forced); - LL_DEBUGS("ENVIRONMENT") << "Setting environment " << env_selection_to_string(env) << " with transition: " << transition << LL_ENDL; -} - -bool LLEnvironment::hasEnvironment(LLEnvironment::EnvSelection_t env) -{ - if ((env < ENV_EDIT) || (env >= ENV_DEFAULT) || (!mEnvironments[env])) - { - return false; - } - - return true; -} - -LLEnvironment::DayInstance::ptr_t LLEnvironment::getEnvironmentInstance(LLEnvironment::EnvSelection_t env, bool create /*= false*/) -{ - DayInstance::ptr_t environment = mEnvironments[env]; - if (create) - { - if (environment) - environment = environment->clone(); - else - { - if (env == ENV_PUSH) - environment = std::make_shared(env); - else - environment = std::make_shared(env); - } - mEnvironments[env] = environment; - } - - return environment; -} - - -void LLEnvironment::setEnvironment(LLEnvironment::EnvSelection_t env, const LLSettingsDay::ptr_t &pday, LLSettingsDay::Seconds daylength, LLSettingsDay::Seconds dayoffset, S32 env_version) -{ - if ((env < ENV_EDIT) || (env >= ENV_DEFAULT)) - { - LL_WARNS("ENVIRONMENT") << "Attempt to change invalid environment selection (" << env_selection_to_string(env) << ")." << LL_ENDL; - return; - } - - logEnvironment(env, pday, env_version); - - DayInstance::ptr_t environment = getEnvironmentInstance(env, true); - - environment->clear(); - environment->setDay(pday, daylength, dayoffset); - environment->setSkyTrack(mCurrentTrack); - environment->animate(); - - if (!mSignalEnvChanged.empty()) - mSignalEnvChanged(env, env_version); -} - -void LLEnvironment::setCurrentEnvironmentSelection(LLEnvironment::EnvSelection_t env) -{ - mCurrentEnvironment->setEnvironmentSelection(env); -} - -void LLEnvironment::setEnvironment(LLEnvironment::EnvSelection_t env, LLEnvironment::fixedEnvironment_t fixed, S32 env_version) -{ - if ((env < ENV_EDIT) || (env >= ENV_DEFAULT)) - { - LL_WARNS("ENVIRONMENT") << "Attempt to change invalid environment selection (" << env_selection_to_string(env) << ")." << LL_ENDL; - return; - } - - bool reset_probes = false; - - DayInstance::ptr_t environment = getEnvironmentInstance(env, true); - - if (fixed.first) - { - logEnvironment(env, fixed.first, env_version); - reset_probes = environment->setSky(fixed.first); - environment->setFlags(DayInstance::NO_ANIMATE_SKY); - } - else if (!environment->getSky()) - { - if (mCurrentEnvironment->getEnvironmentSelection() != ENV_NONE) - { - // Note: This looks suspicious. Shouldn't we assign whole day if mCurrentEnvironment has whole day? - // and then add water/sky on top - // This looks like it will result in sky using single keyframe instead of whole day if day is present - // when setting static water without static sky - reset_probes = environment->setSky(mCurrentEnvironment->getSky()); - environment->setFlags(DayInstance::NO_ANIMATE_SKY); - } - else - { - // Environment is not properly initialized yet, but we should have environment by this point - DayInstance::ptr_t substitute = getEnvironmentInstance(ENV_PARCEL, true); - if (!substitute || !substitute->getSky()) - { - substitute = getEnvironmentInstance(ENV_REGION, true); - } - if (!substitute || !substitute->getSky()) - { - substitute = getEnvironmentInstance(ENV_DEFAULT, true); - } - - if (substitute && substitute->getSky()) - { - reset_probes = environment->setSky(substitute->getSky()); - environment->setFlags(DayInstance::NO_ANIMATE_SKY); - } - else - { - LL_WARNS("ENVIRONMENT") << "Failed to assign substitute water/sky, environment is not properly initialized" << LL_ENDL; - } - } - } - - if (fixed.second) - { - logEnvironment(env, fixed.second, env_version); - environment->setWater(fixed.second); - environment->setFlags(DayInstance::NO_ANIMATE_WATER); - } - else if (!environment->getWater()) - { - if (mCurrentEnvironment->getEnvironmentSelection() != ENV_NONE) - { - // Note: This looks suspicious. Shouldn't we assign whole day if mCurrentEnvironment has whole day? - // and then add water/sky on top - // This looks like it will result in water using single keyframe instead of whole day if day is present - // when setting static sky without static water - environment->setWater(mCurrentEnvironment->getWater()); - environment->setFlags(DayInstance::NO_ANIMATE_WATER); - } - else - { - // Environment is not properly initialized yet, but we should have environment by this point - DayInstance::ptr_t substitute = getEnvironmentInstance(ENV_PARCEL, true); - if (!substitute || !substitute->getWater()) - { - substitute = getEnvironmentInstance(ENV_REGION, true); - } - if (!substitute || !substitute->getWater()) - { - substitute = getEnvironmentInstance(ENV_DEFAULT, true); - } - - if (substitute && substitute->getWater()) - { - environment->setWater(substitute->getWater()); - environment->setFlags(DayInstance::NO_ANIMATE_WATER); - } - else - { - LL_WARNS("ENVIRONMENT") << "Failed to assign substitute water/sky, environment is not properly initialized" << LL_ENDL; - } - } - } - - if (reset_probes) - { // the sky changed in a way that merits a reset of reflection probes - gPipeline.mReflectionMapManager.reset(); - } - - if (!mSignalEnvChanged.empty()) - mSignalEnvChanged(env, env_version); -} - -void LLEnvironment::setEnvironment(LLEnvironment::EnvSelection_t env, const LLSettingsBase::ptr_t &settings, S32 env_version) -{ - DayInstance::ptr_t environment = getEnvironmentInstance(env); - - if (env == ENV_DEFAULT) - { - LL_WARNS("ENVIRONMENT") << "Attempt to set default environment. Not allowed." << LL_ENDL; - return; - } - - if (!settings) - { - clearEnvironment(env); - return; - } - - if (settings->getSettingsType() == "daycycle") - { - LLSettingsDay::Seconds daylength(LLSettingsDay::DEFAULT_DAYLENGTH); - LLSettingsDay::Seconds dayoffset(LLSettingsDay::DEFAULT_DAYOFFSET); - if (environment) - { - daylength = environment->getDayLength(); - dayoffset = environment->getDayOffset(); - } - setEnvironment(env, std::static_pointer_cast(settings), daylength, dayoffset); - } - else if (settings->getSettingsType() == "sky") - { - fixedEnvironment_t fixedenv(std::static_pointer_cast(settings), LLSettingsWater::ptr_t()); - setEnvironment(env, fixedenv); - } - else if (settings->getSettingsType() == "water") - { - fixedEnvironment_t fixedenv(LLSettingsSky::ptr_t(), std::static_pointer_cast(settings)); - setEnvironment(env, fixedenv); - } -} - -void LLEnvironment::setEnvironment(EnvSelection_t env, const LLUUID &assetId, S32 env_version) -{ - setEnvironment(env, assetId, TRANSITION_DEFAULT, env_version); -} - -void LLEnvironment::setEnvironment(EnvSelection_t env, - const LLUUID &assetId, - LLSettingsBase::Seconds transition, - S32 env_version) -{ - LLSettingsVOBase::getSettingsAsset(assetId, - [this, env, env_version, transition](LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, LLExtStat) - { - onSetEnvAssetLoaded(env, asset_id, settings, transition, status, env_version); - }); -} - -void LLEnvironment::onSetEnvAssetLoaded(EnvSelection_t env, - LLUUID asset_id, - LLSettingsBase::ptr_t settings, - LLSettingsBase::Seconds transition, - S32 status, - S32 env_version) -{ - if (!settings || status) - { - LLSD args; - args["NAME"] = asset_id.asString(); - LLNotificationsUtil::add("FailedToFindSettings", args); - LL_DEBUGS("ENVIRONMENT") << "Failed to find settings for " << env_selection_to_string(env) << ", asset_id: " << asset_id << LL_ENDL; - return; - } - LL_DEBUGS("ENVIRONMENT") << "Loaded asset: " << asset_id << LL_ENDL; - - setEnvironment(env, settings); - updateEnvironment(transition); -} - -void LLEnvironment::clearEnvironment(LLEnvironment::EnvSelection_t env) -{ - if ((env < ENV_EDIT) || (env >= ENV_DEFAULT)) - { - LL_WARNS("ENVIRONMENT") << "Attempt to change invalid environment selection." << LL_ENDL; - return; - } - - LL_DEBUGS("ENVIRONMENT") << "Cleaning environment " << env_selection_to_string(env) << LL_ENDL; - - mEnvironments[env].reset(); - - if (!mSignalEnvChanged.empty()) - mSignalEnvChanged(env, VERSION_CLEANUP); -} - -void LLEnvironment::logEnvironment(EnvSelection_t env, const LLSettingsBase::ptr_t &settings, S32 env_version) -{ - LL_DEBUGS("ENVIRONMENT") << "Setting Day environment " << env_selection_to_string(env) << " with version(update type): " << env_version << LL_NEWLINE; - // code between LL_DEBUGS and LL_ENDL won't execute unless log is enabled - if (settings) - { - LLUUID asset_id = settings->getAssetId(); - if (asset_id.notNull()) - { - LL_CONT << "Asset id: " << asset_id << LL_NEWLINE; - } - - LLUUID id = settings->getId(); // Not in use? - if (id.notNull()) - { - LL_CONT << "Settings id: " << id << LL_NEWLINE; - } - - LL_CONT << "Name: " << settings->getName() << LL_NEWLINE - << "Type: " << settings->getSettingsType() << LL_NEWLINE - << "Flags: " << settings->getFlags(); // Not in use? - } - else - { - LL_CONT << "Empty settings!"; - } - LL_CONT << LL_ENDL; -} - -LLSettingsDay::ptr_t LLEnvironment::getEnvironmentDay(LLEnvironment::EnvSelection_t env) -{ - if ((env < ENV_EDIT) || (env > ENV_DEFAULT)) - { - LL_WARNS("ENVIRONMENT") << "Attempt to retrieve invalid environment selection (" << env_selection_to_string(env) << ")." << LL_ENDL; - return LLSettingsDay::ptr_t(); - } - - DayInstance::ptr_t environment = getEnvironmentInstance(env); - - if (environment) - return environment->getDayCycle(); - - return LLSettingsDay::ptr_t(); -} - -LLSettingsDay::Seconds LLEnvironment::getEnvironmentDayLength(EnvSelection_t env) -{ - if ((env < ENV_EDIT) || (env > ENV_DEFAULT)) - { - LL_WARNS("ENVIRONMENT") << "Attempt to retrieve invalid environment selection (" << env_selection_to_string(env) << ")." << LL_ENDL; - return LLSettingsDay::Seconds(0); - } - - DayInstance::ptr_t environment = getEnvironmentInstance(env); - - if (environment) - return environment->getDayLength(); - - return LLSettingsDay::Seconds(0); -} - -LLSettingsDay::Seconds LLEnvironment::getEnvironmentDayOffset(EnvSelection_t env) -{ - if ((env < ENV_EDIT) || (env > ENV_DEFAULT)) - { - LL_WARNS("ENVIRONMENT") << "Attempt to retrieve invalid environment selection (" << env_selection_to_string(env) << ")." << LL_ENDL; - return LLSettingsDay::Seconds(0); - } - - DayInstance::ptr_t environment = getEnvironmentInstance(env); - if (environment) - return environment->getDayOffset(); - - return LLSettingsDay::Seconds(0); -} - - -LLEnvironment::fixedEnvironment_t LLEnvironment::getEnvironmentFixed(LLEnvironment::EnvSelection_t env, bool resolve) -{ - if ((env == ENV_CURRENT) || resolve) - { - fixedEnvironment_t fixed; - for (S32 idx = ((resolve) ? env : mSelectedEnvironment); idx < ENV_END; ++idx) - { - if (fixed.first && fixed.second) - break; - - if (idx == ENV_EDIT) - continue; // skip the edit environment. - - DayInstance::ptr_t environment = getEnvironmentInstance(static_cast(idx)); - if (environment) - { - if (!fixed.first) - fixed.first = environment->getSky(); - if (!fixed.second) - fixed.second = environment->getWater(); - } - } - - if (!fixed.first || !fixed.second) - LL_WARNS("ENVIRONMENT") << "Can not construct complete fixed environment. Missing Sky and/or Water." << LL_ENDL; - - return fixed; - } - - if ((env < ENV_EDIT) || (env > ENV_DEFAULT)) - { - LL_WARNS("ENVIRONMENT") << "Attempt to retrieve invalid environment selection (" << env_selection_to_string(env) << ")." << LL_ENDL; - return fixedEnvironment_t(); - } - - DayInstance::ptr_t environment = getEnvironmentInstance(env); - - if (environment) - return fixedEnvironment_t(environment->getSky(), environment->getWater()); - - return fixedEnvironment_t(); -} - -LLEnvironment::DayInstance::ptr_t LLEnvironment::getSelectedEnvironmentInstance() -{ - for (S32 idx = mSelectedEnvironment; idx < ENV_DEFAULT; ++idx) - { - if (mEnvironments[idx]) - return mEnvironments[idx]; - } - - return mEnvironments[ENV_DEFAULT]; -} - -LLEnvironment::DayInstance::ptr_t LLEnvironment::getSharedEnvironmentInstance() -{ - for (S32 idx = ENV_PARCEL; idx < ENV_DEFAULT; ++idx) - { - if (mEnvironments[idx]) - return mEnvironments[idx]; - } - - return mEnvironments[ENV_DEFAULT]; -} - -void LLEnvironment::updateEnvironment(LLSettingsBase::Seconds transition, bool forced) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; - DayInstance::ptr_t pinstance = getSelectedEnvironmentInstance(); - - if ((mCurrentEnvironment != pinstance) || forced) - { - if (transition != TRANSITION_INSTANT) - { - DayInstance::ptr_t trans = std::make_shared( - mCurrentEnvironment->getSky(), mCurrentEnvironment->getWater(), pinstance, transition); - - trans->animate(); - - mCurrentEnvironment = trans; - } - else - { - mCurrentEnvironment = pinstance; - } - - updateSettingsUniforms(); - } -} - -LLVector4 LLEnvironment::toCFR(const LLVector3 vec) const -{ - LLVector4 vec_cfr(vec.mV[1], vec.mV[0], vec.mV[2], 0.0f); - return vec_cfr; -} - -LLVector4 LLEnvironment::toLightNorm(const LLVector3 vec) const -{ - LLVector4 vec_ogl(vec.mV[1], vec.mV[2], vec.mV[0], 0.0f); - return vec_ogl; -} - -LLVector3 LLEnvironment::getLightDirection() const -{ - LLSettingsSky::ptr_t psky = mCurrentEnvironment->getSky(); - if (!psky) - { - return LLVector3(0, 0, 1); - } - return psky->getLightDirection(); -} - -LLVector3 LLEnvironment::getSunDirection() const -{ - LLSettingsSky::ptr_t psky = mCurrentEnvironment->getSky(); - if (!psky) - { - return LLVector3(0, 0, 1); - } - return psky->getSunDirection(); -} - -LLVector3 LLEnvironment::getMoonDirection() const -{ - LLSettingsSky::ptr_t psky = mCurrentEnvironment->getSky(); - if (!psky) - { - return LLVector3(0, 0, -1); - } - return psky->getMoonDirection(); -} - -LLVector4 LLEnvironment::getLightDirectionCFR() const -{ - LLVector3 light_direction = getLightDirection(); - LLVector4 light_direction_cfr = toCFR(light_direction); - return light_direction_cfr; -} - -LLVector4 LLEnvironment::getSunDirectionCFR() const -{ - LLVector3 light_direction = getSunDirection(); - LLVector4 light_direction_cfr = toCFR(light_direction); - return light_direction_cfr; -} - -LLVector4 LLEnvironment::getMoonDirectionCFR() const -{ - LLVector3 light_direction = getMoonDirection(); - LLVector4 light_direction_cfr = toCFR(light_direction); - return light_direction_cfr; -} - -LLVector4 LLEnvironment::getClampedLightNorm() const -{ - LLVector3 light_direction = getLightDirection(); - if (light_direction.mV[2] < -0.1f) - { - light_direction.mV[2] = -0.1f; - } - return toLightNorm(light_direction); -} - -LLVector4 LLEnvironment::getClampedSunNorm() const -{ - LLVector3 light_direction = getSunDirection(); - if (light_direction.mV[2] < -0.1f) - { - light_direction.mV[2] = -0.1f; - } - return toLightNorm(light_direction); -} - -LLVector4 LLEnvironment::getClampedMoonNorm() const -{ - LLVector3 light_direction = getMoonDirection(); - if (light_direction.mV[2] < -0.1f) - { - light_direction.mV[2] = -0.1f; - } - return toLightNorm(light_direction); -} - -LLVector4 LLEnvironment::getRotatedLightNorm() const -{ - LLVector3 light_direction = getLightDirection(); - light_direction *= LLQuaternion(-mLastCamYaw, LLVector3(0.f, 1.f, 0.f)); - return toLightNorm(light_direction); -} - -extern bool gCubeSnapshot; - -//------------------------------------------------------------------------- -void LLEnvironment::update(const LLViewerCamera * cam) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; //LL_RECORD_BLOCK_TIME(FTM_ENVIRONMENT_UPDATE); - //F32Seconds now(LLDate::now().secondsSinceEpoch()); - if (!gCubeSnapshot) - { - static LLFrameTimer timer; - - F32Seconds delta(timer.getElapsedTimeAndResetF32()); - - { - DayInstance::ptr_t keeper = mCurrentEnvironment; - // make sure the current environment does not go away until applyTimeDelta is done. - mCurrentEnvironment->applyTimeDelta(delta); - - } - // update clouds, sun, and general - updateCloudScroll(); - - // cache this for use in rotating the rotated light vec for shader param updates later... - mLastCamYaw = cam->getYaw() + SUN_DELTA_YAW; - } - - updateSettingsUniforms(); - - // *TODO: potential optimization - this block may only need to be - // executed some of the time. For example for water shaders only. - { - LLViewerShaderMgr::shader_iter shaders_iter, end_shaders; - end_shaders = LLViewerShaderMgr::instance()->endShaders(); - for (shaders_iter = LLViewerShaderMgr::instance()->beginShaders(); shaders_iter != end_shaders; ++shaders_iter) - { - if ((shaders_iter->mProgramObject != 0) - && (gPipeline.canUseWindLightShaders() - || shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER)) - { - shaders_iter->mUniformsDirty = true; - } - } - } -} - -void LLEnvironment::updateCloudScroll() -{ - // This is a function of the environment rather than the sky, since it should - // persist through sky transitions. - static LLTimer s_cloud_timer; - - F64 delta_t = s_cloud_timer.getElapsedTimeAndResetF64(); - - if (mCurrentEnvironment->getSky() && !mCloudScrollPaused) - { - LLVector2 rate = mCurrentEnvironment->getSky()->getCloudScrollRate(); - if (rate.isExactlyZero()) - { - mCloudScrollDelta.setZero(); - } - else - { - LLVector2 cloud_delta = static_cast(delta_t) * (mCurrentEnvironment->getSky()->getCloudScrollRate()) / 100.0; - mCloudScrollDelta += cloud_delta; - } - } - -} - -// static -void LLEnvironment::updateGLVariablesForSettings(LLShaderUniforms* uniforms, const LLSettingsBase::ptr_t &psetting) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; - - for (int i = 0; i < LLGLSLShader::SG_COUNT; ++i) - { - uniforms[i].clear(); - } - - LLShaderUniforms* shader = &uniforms[LLGLSLShader::SG_ANY]; - //_WARNS("RIDER") << "----------------------------------------------------------------" << LL_ENDL; - LLSettingsBase::parammapping_t params = psetting->getParameterMap(); - for (auto &it: params) - { - LLSD value; - // legacy first since it contains ambient color and we prioritize value from legacy, see getAmbientColor() - if (psetting->mSettings.has(LLSettingsSky::SETTING_LEGACY_HAZE) && psetting->mSettings[LLSettingsSky::SETTING_LEGACY_HAZE].has(it.first)) - { - value = psetting->mSettings[LLSettingsSky::SETTING_LEGACY_HAZE][it.first]; - } - else if (psetting->mSettings.has(it.first)) - { - value = psetting->mSettings[it.first]; - } - else - { - // We need to reset shaders, use defaults - value = it.second.getDefaultValue(); - } - - LLSD::Type setting_type = value.type(); - stop_glerror(); - switch (setting_type) - { - case LLSD::TypeInteger: - shader->uniform1i(it.second.getShaderKey(), value.asInteger()); - //_WARNS("RIDER") << "pushing '" << (*it).first << "' as " << value << LL_ENDL; - break; - case LLSD::TypeReal: - shader->uniform1f(it.second.getShaderKey(), value.asReal()); - //_WARNS("RIDER") << "pushing '" << (*it).first << "' as " << value << LL_ENDL; - break; - - case LLSD::TypeBoolean: - shader->uniform1i(it.second.getShaderKey(), value.asBoolean() ? 1 : 0); - //_WARNS("RIDER") << "pushing '" << (*it).first << "' as " << value << LL_ENDL; - break; - - case LLSD::TypeArray: - { - LLVector4 vect4(value); - - if (gCubeSnapshot && !gPipeline.mReflectionMapManager.isRadiancePass()) - { // maximize and remove tinting if this is an irradiance map render pass and the parameter feeds into the sky background color - auto max_vec = [](LLVector4 col) - { - LLColor3 color(col); - F32 h, s, l; - color.calcHSL(&h, &s, &l); - - col.mV[0] = col.mV[1] = col.mV[2] = l; - return col; - }; - - switch (it.second.getShaderKey()) - { - case LLShaderMgr::BLUE_HORIZON: - case LLShaderMgr::BLUE_DENSITY: - vect4 = max_vec(vect4); - break; - } - } - - //_WARNS("RIDER") << "pushing '" << (*it).first << "' as " << vect4 << LL_ENDL; - shader->uniform3fv(it.second.getShaderKey(), LLVector3(vect4.mV) ); - break; - } - - // case LLSD::TypeMap: - // case LLSD::TypeString: - // case LLSD::TypeUUID: - // case LLSD::TypeURI: - // case LLSD::TypeBinary: - // case LLSD::TypeDate: - default: - break; - } - } - //_WARNS("RIDER") << "----------------------------------------------------------------" << LL_ENDL; - - psetting->applySpecial(uniforms); -} - -void LLEnvironment::updateShaderUniforms(LLGLSLShader* shader) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; - - // apply uniforms that should be applied to all shaders - mSkyUniforms[LLGLSLShader::SG_ANY].apply(shader); - mWaterUniforms[LLGLSLShader::SG_ANY].apply(shader); - - // apply uniforms specific to the given shader's shader group - auto group = shader->mShaderGroup; - mSkyUniforms[group].apply(shader); - mWaterUniforms[group].apply(shader); -} - -void LLEnvironment::updateSettingsUniforms() -{ - if (mCurrentEnvironment->getWater()) - { - updateGLVariablesForSettings(mWaterUniforms, mCurrentEnvironment->getWater()); - } - else - { - LL_WARNS("ENVIRONMENT") << "Failed to update GL variable for water settings, environment is not properly set" << LL_ENDL; - } - if (mCurrentEnvironment->getSky()) - { - updateGLVariablesForSettings(mSkyUniforms, mCurrentEnvironment->getSky()); - } - else - { - LL_WARNS("ENVIRONMENT") << "Failed to update GL variable for sky settings, environment is not properly set" << LL_ENDL; - } -} - -void LLEnvironment::recordEnvironment(S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envinfo, LLSettingsBase::Seconds transition) -{ - if (!gAgent.getRegion()) - { - return; - } - // mRegionId id can be null, no specification as to why and if it's valid so check valid ids only - if (gAgent.getRegion()->getRegionID() != envinfo->mRegionId && envinfo->mRegionId.notNull()) - { - LL_INFOS("ENVIRONMENT") << "Requested environmend region id: " << envinfo->mRegionId << " agent is on: " << gAgent.getRegion()->getRegionID() << LL_ENDL; - return; - } - - if (envinfo->mParcelId == INVALID_PARCEL_ID) - { - // the returned info applies to an entire region. - if (!envinfo->mDayCycle) - { - clearEnvironment(ENV_PARCEL); - setEnvironment(ENV_REGION, LLSettingsDay::GetDefaultAssetId(), TRANSITION_DEFAULT, envinfo->mEnvVersion); - updateEnvironment(); - } - else if (envinfo->mDayCycle->isTrackEmpty(LLSettingsDay::TRACK_WATER) - || envinfo->mDayCycle->isTrackEmpty(LLSettingsDay::TRACK_GROUND_LEVEL)) - { - LL_WARNS("ENVIRONMENT") << "Invalid day cycle for region" << LL_ENDL; - clearEnvironment(ENV_PARCEL); - setEnvironment(ENV_REGION, LLSettingsDay::GetDefaultAssetId(), TRANSITION_DEFAULT, envinfo->mEnvVersion); - updateEnvironment(); - } - else - { - mTrackAltitudes = envinfo->mAltitudes; - // update track selection based on new altitudes - mCurrentTrack = calculateSkyTrackForAltitude(gAgent.getPositionAgent().mV[VZ]); - - setEnvironment(ENV_REGION, envinfo->mDayCycle, envinfo->mDayLength, envinfo->mDayOffset, envinfo->mEnvVersion); - } - - LL_DEBUGS("ENVIRONMENT") << "Altitudes set to {" << mTrackAltitudes[0] << ", "<< mTrackAltitudes[1] << ", " << mTrackAltitudes[2] << ", " << mTrackAltitudes[3] << LL_ENDL; - } - else - { - LLParcel *parcel = LLViewerParcelMgr::instance().getAgentParcel(); - LL_DEBUGS("ENVIRONMENT") << "Have parcel environment #" << envinfo->mParcelId << LL_ENDL; - if (parcel && (parcel->getLocalID() != parcel_id)) - { - LL_DEBUGS("ENVIRONMENT") << "Requested parcel #" << parcel_id << " agent is on " << parcel->getLocalID() << LL_ENDL; - return; - } - - if (!envinfo->mDayCycle) - { - LL_DEBUGS("ENVIRONMENT") << "Clearing environment on parcel #" << parcel_id << LL_ENDL; - clearEnvironment(ENV_PARCEL); - } - else if (envinfo->mDayCycle->isTrackEmpty(LLSettingsDay::TRACK_WATER) - || envinfo->mDayCycle->isTrackEmpty(LLSettingsDay::TRACK_GROUND_LEVEL)) - { - LL_WARNS("ENVIRONMENT") << "Invalid day cycle for parcel #" << parcel_id << LL_ENDL; - clearEnvironment(ENV_PARCEL); - } - else - { - setEnvironment(ENV_PARCEL, envinfo->mDayCycle, envinfo->mDayLength, envinfo->mDayOffset, envinfo->mEnvVersion); - } - } - - updateEnvironment(transition); -} - -void LLEnvironment::adjustRegionOffset(F32 adjust) -{ - if (isExtendedEnvironmentEnabled()) - { - LL_WARNS("ENVIRONMENT") << "Attempt to adjust region offset on EEP region. Legacy regions only." << LL_ENDL; - } - - if (mEnvironments[ENV_REGION]) - { - F32 day_length = mEnvironments[ENV_REGION]->getDayLength(); - F32 day_offset = mEnvironments[ENV_REGION]->getDayOffset(); - - F32 day_adjustment = adjust * day_length; - - day_offset += day_adjustment; - if (day_offset < 0.0f) - day_offset = day_length + day_offset; - mEnvironments[ENV_REGION]->setDayOffset(LLSettingsBase::Seconds(day_offset)); - } -} - -//========================================================================= -void LLEnvironment::requestRegion(environment_apply_fn cb) -{ - requestParcel(INVALID_PARCEL_ID, cb); -} - -void LLEnvironment::updateRegion(const LLSettingsDay::ptr_t &pday, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) -{ - updateParcel(INVALID_PARCEL_ID, pday, day_length, day_offset, altitudes, cb); -} - -void LLEnvironment::updateRegion(const LLUUID &asset_id, std::string display_name, S32 track_num, S32 day_length, S32 day_offset, U32 flags, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) -{ - if (!isExtendedEnvironmentEnabled()) - { - LL_WARNS("ENVIRONMENT") << "attempt to apply asset id to region not supporting it." << LL_ENDL; - LLNotificationsUtil::add("NoEnvironmentSettings"); - return; - } - - updateParcel(INVALID_PARCEL_ID, asset_id, display_name, track_num, day_length, day_offset, flags, altitudes, cb); -} - -void LLEnvironment::updateRegion(const LLSettingsSky::ptr_t &psky, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) -{ - updateParcel(INVALID_PARCEL_ID, psky, day_length, day_offset, altitudes, cb); -} - -void LLEnvironment::updateRegion(const LLSettingsWater::ptr_t &pwater, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) -{ - updateParcel(INVALID_PARCEL_ID, pwater, day_length, day_offset, altitudes, cb); -} - - -void LLEnvironment::resetRegion(environment_apply_fn cb) -{ - resetParcel(INVALID_PARCEL_ID, cb); -} - -void LLEnvironment::requestParcel(S32 parcel_id, environment_apply_fn cb) -{ - if (!isExtendedEnvironmentEnabled()) - { /*TODO: When EEP is live on the entire grid, this can go away. */ - if (parcel_id == INVALID_PARCEL_ID) - { - if (!cb) - { - LLSettingsBase::Seconds transition = LLViewerParcelMgr::getInstance()->getTeleportInProgress() ? TRANSITION_FAST : TRANSITION_DEFAULT; - cb = [this, transition](S32 pid, EnvironmentInfo::ptr_t envinfo) - { - clearEnvironment(ENV_PARCEL); - recordEnvironment(pid, envinfo, transition); - }; - } - - LLEnvironmentRequest::initiate(cb); - } - else if (cb) - cb(parcel_id, EnvironmentInfo::ptr_t()); - return; - } - - if (!cb) - { - LLSettingsBase::Seconds transition = LLViewerParcelMgr::getInstance()->getTeleportInProgress() ? TRANSITION_FAST : TRANSITION_DEFAULT; - cb = [this, transition](S32 pid, EnvironmentInfo::ptr_t envinfo) { recordEnvironment(pid, envinfo, transition); }; - } - - std::string coroname = - LLCoros::instance().launch("LLEnvironment::coroRequestEnvironment", - [this, parcel_id, cb]() { coroRequestEnvironment(parcel_id, cb); }); -} - -void LLEnvironment::updateParcel(S32 parcel_id, const LLUUID &asset_id, std::string display_name, S32 track_num, S32 day_length, S32 day_offset, U32 flags, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) -{ - UpdateInfo::ptr_t updates(std::make_shared(asset_id, display_name, day_length, day_offset, altitudes, flags)); - std::string coroname = - LLCoros::instance().launch("LLEnvironment::coroUpdateEnvironment", - [this, parcel_id, track_num, updates, cb]() { coroUpdateEnvironment(parcel_id, track_num, updates, cb); }); -} - -void LLEnvironment::onUpdateParcelAssetLoaded(LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, S32 parcel_id, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes) -{ - if (status) - { - LL_WARNS("ENVIRONMENT") << "Unable to get settings asset with id " << asset_id << "!" << LL_ENDL; - LLNotificationsUtil::add("FailedToLoadSettingsApply"); - return; - } - - LLSettingsDay::ptr_t pday; - - if (settings->getSettingsType() == "daycycle") - pday = std::static_pointer_cast(settings); - else - { - pday = createDayCycleFromEnvironment( (parcel_id == INVALID_PARCEL_ID) ? ENV_REGION : ENV_PARCEL, settings); - } - - if (!pday) - { - LL_WARNS("ENVIRONMENT") << "Unable to construct day around " << asset_id << "!" << LL_ENDL; - LLNotificationsUtil::add("FailedToBuildSettingsDay"); - return; - } - - updateParcel(parcel_id, pday, day_length, day_offset, altitudes); -} - -void LLEnvironment::updateParcel(S32 parcel_id, const LLSettingsSky::ptr_t &psky, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) -{ - LLSettingsDay::ptr_t pday = createDayCycleFromEnvironment((parcel_id == INVALID_PARCEL_ID) ? ENV_REGION : ENV_PARCEL, psky); - pday->setFlag(psky->getFlags()); - updateParcel(parcel_id, pday, day_length, day_offset, altitudes, cb); -} - -void LLEnvironment::updateParcel(S32 parcel_id, const LLSettingsWater::ptr_t &pwater, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) -{ - LLSettingsDay::ptr_t pday = createDayCycleFromEnvironment((parcel_id == INVALID_PARCEL_ID) ? ENV_REGION : ENV_PARCEL, pwater); - pday->setFlag(pwater->getFlags()); - updateParcel(parcel_id, pday, day_length, day_offset, altitudes, cb); -} - -void LLEnvironment::updateParcel(S32 parcel_id, const LLSettingsDay::ptr_t &pday, S32 track_num, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) -{ - UpdateInfo::ptr_t updates(std::make_shared(pday, day_length, day_offset, altitudes)); - - std::string coroname = - LLCoros::instance().launch("LLEnvironment::coroUpdateEnvironment", - [this, parcel_id, track_num, updates, cb]() { coroUpdateEnvironment(parcel_id, track_num, updates, cb); }); -} - -void LLEnvironment::updateParcel(S32 parcel_id, const LLSettingsDay::ptr_t &pday, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) -{ - updateParcel(parcel_id, pday, NO_TRACK, day_length, day_offset, altitudes, cb); -} - - - -void LLEnvironment::resetParcel(S32 parcel_id, environment_apply_fn cb) -{ - std::string coroname = - LLCoros::instance().launch("LLEnvironment::coroResetEnvironment", - [this, parcel_id, cb]() { coroResetEnvironment(parcel_id, NO_TRACK, cb); }); -} - -void LLEnvironment::coroRequestEnvironment(S32 parcel_id, LLEnvironment::environment_apply_fn apply) -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("ResetEnvironment", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - - std::string url = gAgent.getRegionCapability("ExtEnvironment"); - if (url.empty()) - return; - - LL_DEBUGS("ENVIRONMENT") << "Requesting for parcel_id=" << parcel_id << LL_ENDL; - - if (parcel_id != INVALID_PARCEL_ID) - { - std::stringstream query; - - query << "?parcelid=" << parcel_id; - url += query.str(); - } - - LLSD result = httpAdapter->getAndSuspend(httpRequest, url); - // results that come back may contain the new settings - - LLSD httpResults = result["http_result"]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - if (!status) - { - LL_WARNS("ENVIRONMENT") << "Couldn't retrieve environment settings for " << ((parcel_id == INVALID_PARCEL_ID) ? ("region!") : ("parcel!")) << LL_ENDL; - } - else if (LLApp::isExiting() || gDisconnected) - { - return; - } - else - { - LLSD environment = result[KEY_ENVIRONMENT]; - if (environment.isDefined() && apply) - { - EnvironmentInfo::ptr_t envinfo = LLEnvironment::EnvironmentInfo::extract(environment); - apply(parcel_id, envinfo); - } - } - -} - -void LLEnvironment::coroUpdateEnvironment(S32 parcel_id, S32 track_no, UpdateInfo::ptr_t updates, environment_apply_fn apply) -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("ResetEnvironment", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - - std::string url = gAgent.getRegionCapability("ExtEnvironment"); - if (url.empty()) - return; - - LLSD body(LLSD::emptyMap()); - body[KEY_ENVIRONMENT] = LLSD::emptyMap(); - - if (track_no == NO_TRACK) - { // day length and offset are only applicable if we are addressing the entire day cycle. - if (updates->mDayLength > 0) - body[KEY_ENVIRONMENT][KEY_DAYLENGTH] = updates->mDayLength; - if (updates->mDayOffset > 0) - body[KEY_ENVIRONMENT][KEY_DAYOFFSET] = updates->mDayOffset; - - if ((parcel_id == INVALID_PARCEL_ID) && (updates->mAltitudes.size() == 3)) - { // only test for altitude changes if we are changing the region. - body[KEY_ENVIRONMENT][KEY_TRACKALTS] = LLSD::emptyArray(); - for (S32 i = 0; i < 3; ++i) - { - body[KEY_ENVIRONMENT][KEY_TRACKALTS][i] = updates->mAltitudes[i]; - } - } - } - - if (updates->mDayp) - body[KEY_ENVIRONMENT][KEY_DAYCYCLE] = updates->mDayp->getSettings(); - else if (!updates->mSettingsAsset.isNull()) - { - body[KEY_ENVIRONMENT][KEY_DAYASSET] = updates->mSettingsAsset; - if (!updates->mDayName.empty()) - body[KEY_ENVIRONMENT][KEY_DAYNAME] = updates->mDayName; - } - - body[KEY_ENVIRONMENT][KEY_FLAGS] = LLSD::Integer(updates->mFlags); - //_WARNS("ENVIRONMENT") << "Body = " << body << LL_ENDL; - - if ((parcel_id != INVALID_PARCEL_ID) || (track_no != NO_TRACK)) - { - std::stringstream query; - query << "?"; - - if (parcel_id != INVALID_PARCEL_ID) - { - query << "parcelid=" << parcel_id; - - if (track_no != NO_TRACK) - query << "&"; - } - if (track_no != NO_TRACK) - { - query << "trackno=" << track_no; - } - url += query.str(); - } - - LLSD result = httpAdapter->putAndSuspend(httpRequest, url, body); - // results that come back may contain the new settings - - LLSD notify; - - LLSD httpResults = result["http_result"]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - if ((!status) || !result["success"].asBoolean()) - { - LL_WARNS("ENVIRONMENT") << "Couldn't update Windlight settings for " << ((parcel_id == INVALID_PARCEL_ID) ? ("region!") : ("parcel!")) << LL_ENDL; - - notify = LLSD::emptyMap(); - std::string reason = result["message"].asString(); - if (reason.empty()) - { - notify["FAIL_REASON"] = status.toString(); - } - else - { - notify["FAIL_REASON"] = reason; - } - } - else if (LLApp::isExiting()) - { - return; - } - else - { - LLSD environment = result[KEY_ENVIRONMENT]; - if (environment.isDefined() && apply) - { - EnvironmentInfo::ptr_t envinfo = LLEnvironment::EnvironmentInfo::extract(environment); - apply(parcel_id, envinfo); - } - } - - if (!notify.isUndefined()) - { - LLNotificationsUtil::add("WLRegionApplyFail", notify); - //LLEnvManagerNew::instance().onRegionSettingsApplyResponse(false); - } -} - -void LLEnvironment::coroResetEnvironment(S32 parcel_id, S32 track_no, environment_apply_fn apply) -{ - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("ResetEnvironment", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - - std::string url = gAgent.getRegionCapability("ExtEnvironment"); - if (url.empty()) - return; - - if ((parcel_id != INVALID_PARCEL_ID) || (track_no != NO_TRACK)) - { - std::stringstream query; - query << "?"; - - if (parcel_id != INVALID_PARCEL_ID) - { - query << "parcelid=" << parcel_id; - - if (track_no != NO_TRACK) - query << "&"; - } - if (track_no != NO_TRACK) - { - query << "trackno=" << track_no; - } - url += query.str(); - } - - LLSD result = httpAdapter->deleteAndSuspend(httpRequest, url); - // results that come back may contain the new settings - - LLSD notify; - - LLSD httpResults = result["http_result"]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - if ((!status) || !result["success"].asBoolean()) - { - LL_WARNS("ENVIRONMENT") << "Couldn't reset Windlight settings in " << ((parcel_id == INVALID_PARCEL_ID) ? ("region!") : ("parcel!")) << LL_ENDL; - - notify = LLSD::emptyMap(); - std::string reason = result["message"].asString(); - if (reason.empty()) - { - notify["FAIL_REASON"] = status.toString(); - } - else - { - notify["FAIL_REASON"] = reason; - } - } - else if (LLApp::isExiting()) - { - return; - } - else - { - LLSD environment = result[KEY_ENVIRONMENT]; - if (environment.isDefined() && apply) - { - EnvironmentInfo::ptr_t envinfo = LLEnvironment::EnvironmentInfo::extract(environment); - apply(parcel_id, envinfo); - } - } - - if (!notify.isUndefined()) - { - LLNotificationsUtil::add("WLRegionApplyFail", notify); - //LLEnvManagerNew::instance().onRegionSettingsApplyResponse(false); - } - -} - - -//========================================================================= - -LLEnvironment::EnvironmentInfo::EnvironmentInfo(): - mParcelId(INVALID_PARCEL_ID), - mRegionId(), - mDayLength(0), - mDayOffset(0), - mDayHash(0), - mDayCycle(), - mAltitudes({ { 0.0, 0.0, 0.0, 0.0 } }), - mIsDefault(false), - mIsLegacy(false), - mDayCycleName(), - mNameList(), - mEnvVersion(INVALID_PARCEL_ENVIRONMENT_VERSION) -{ -} - -LLEnvironment::EnvironmentInfo::ptr_t LLEnvironment::EnvironmentInfo::extract(LLSD environment) -{ - ptr_t pinfo = std::make_shared(); - - pinfo->mIsDefault = environment.has(KEY_ISDEFAULT) ? environment[KEY_ISDEFAULT].asBoolean() : true; - pinfo->mParcelId = environment.has(KEY_PARCELID) ? environment[KEY_PARCELID].asInteger() : INVALID_PARCEL_ID; - pinfo->mRegionId = environment.has(KEY_REGIONID) ? environment[KEY_REGIONID].asUUID() : LLUUID::null; - pinfo->mIsLegacy = false; - - if (environment.has(KEY_TRACKALTS)) - { - for (int idx = 0; idx < 3; idx++) - { - pinfo->mAltitudes[idx+1] = environment[KEY_TRACKALTS][idx].asReal(); - } - pinfo->mAltitudes[0] = 0; - } - - if (environment.has(KEY_DAYCYCLE)) - { - pinfo->mDayCycle = LLSettingsVODay::buildFromEnvironmentMessage(environment[KEY_DAYCYCLE]); - pinfo->mDayLength = LLSettingsDay::Seconds(environment.has(KEY_DAYLENGTH) ? environment[KEY_DAYLENGTH].asInteger() : -1); - pinfo->mDayOffset = LLSettingsDay::Seconds(environment.has(KEY_DAYOFFSET) ? environment[KEY_DAYOFFSET].asInteger() : -1); - pinfo->mDayHash = environment.has(KEY_DAYHASH) ? environment[KEY_DAYHASH].asInteger() : 0; - } - else - { - pinfo->mDayLength = LLEnvironment::instance().getEnvironmentDayLength(ENV_REGION); - pinfo->mDayOffset = LLEnvironment::instance().getEnvironmentDayOffset(ENV_REGION); - } - - if (environment.has(KEY_DAYASSET)) - { - pinfo->mAssetId = environment[KEY_DAYASSET].asUUID(); - } - - if (environment.has(KEY_DAYNAMES)) - { - LLSD daynames = environment[KEY_DAYNAMES]; - if (daynames.isArray()) - { - pinfo->mDayCycleName.clear(); - for (S32 index = 0; index < pinfo->mNameList.size(); ++index) - { - pinfo->mNameList[index] = daynames[index].asString(); - } - } - else if (daynames.isString()) - { - for (std::string &name: pinfo->mNameList) - { - name.clear(); - } - - pinfo->mDayCycleName = daynames.asString(); - } - } - else if (pinfo->mDayCycle) - { - pinfo->mDayCycleName = pinfo->mDayCycle->getName(); - } - - - if (environment.has(KEY_ENVVERSION)) - { - LLSD version = environment[KEY_ENVVERSION]; - pinfo->mEnvVersion = version.asInteger(); - } - else - { - // can be used for region, but versions should be same - pinfo->mEnvVersion = pinfo->mIsDefault ? UNSET_PARCEL_ENVIRONMENT_VERSION : INVALID_PARCEL_ENVIRONMENT_VERSION; - } - - return pinfo; -} - - -LLEnvironment::EnvironmentInfo::ptr_t LLEnvironment::EnvironmentInfo::extractLegacy(LLSD legacy) -{ - if (!legacy.isArray() || !legacy[0].has("regionID")) - { - LL_WARNS("ENVIRONMENT") << "Invalid legacy settings for environment: " << legacy << LL_ENDL; - return ptr_t(); - } - - ptr_t pinfo = std::make_shared(); - - pinfo->mIsDefault = false; - pinfo->mParcelId = INVALID_PARCEL_ID; - pinfo->mRegionId = legacy[0]["regionID"].asUUID(); - pinfo->mIsLegacy = true; - - pinfo->mDayLength = LLSettingsDay::DEFAULT_DAYLENGTH; - pinfo->mDayOffset = LLSettingsDay::DEFAULT_DAYOFFSET; - pinfo->mDayCycle = LLSettingsVODay::buildFromLegacyMessage(pinfo->mRegionId, legacy[1], legacy[2], legacy[3]); - if (pinfo->mDayCycle) - pinfo->mDayHash = pinfo->mDayCycle->getHash(); - - pinfo->mAltitudes[0] = 0; - pinfo->mAltitudes[2] = 10001; - pinfo->mAltitudes[3] = 10002; - pinfo->mAltitudes[4] = 10003; - - return pinfo; -} - -//========================================================================= -LLSettingsWater::ptr_t LLEnvironment::createWaterFromLegacyPreset(const std::string filename, LLSD &messages) -{ - std::string name(gDirUtilp->getBaseFileName(filename, true)); - std::string path(gDirUtilp->getDirName(filename)); - - LLSettingsWater::ptr_t water = LLSettingsVOWater::buildFromLegacyPresetFile(name, path, messages); - - if (!water) - { - messages["NAME"] = name; - messages["FILE"] = filename; - } - return water; -} - -LLSettingsSky::ptr_t LLEnvironment::createSkyFromLegacyPreset(const std::string filename, LLSD &messages) -{ - std::string name(gDirUtilp->getBaseFileName(filename, true)); - std::string path(gDirUtilp->getDirName(filename)); - - LLSettingsSky::ptr_t sky = LLSettingsVOSky::buildFromLegacyPresetFile(name, path, messages); - if (!sky) - { - messages["NAME"] = name; - messages["FILE"] = filename; - } - return sky; -} - -LLSettingsDay::ptr_t LLEnvironment::createDayCycleFromLegacyPreset(const std::string filename, LLSD &messages) -{ - std::string name(gDirUtilp->getBaseFileName(filename, true)); - std::string path(gDirUtilp->getDirName(filename)); - - LLSettingsDay::ptr_t day = LLSettingsVODay::buildFromLegacyPresetFile(name, path, messages); - if (!day) - { - messages["NAME"] = name; - messages["FILE"] = filename; - } - return day; -} - -LLSettingsDay::ptr_t LLEnvironment::createDayCycleFromEnvironment(EnvSelection_t env, LLSettingsBase::ptr_t settings) -{ - std::string type(settings->getSettingsType()); - - if (type == "daycycle") - return std::static_pointer_cast(settings); - - if ((env != ENV_PARCEL) && (env != ENV_REGION)) - { - LL_WARNS("ENVIRONMENT") << "May only create from parcel or region environment." << LL_ENDL; - return LLSettingsDay::ptr_t(); - } - - LLSettingsDay::ptr_t day = this->getEnvironmentDay(env); - if (!day && (env == ENV_PARCEL)) - { - day = this->getEnvironmentDay(ENV_REGION); - } - - if (!day) - { - LL_WARNS("ENVIRONMENT") << "Could not retrieve existing day settings." << LL_ENDL; - return LLSettingsDay::ptr_t(); - } - - day = day->buildClone(); - - if (type == "sky") - { - for (S32 idx = 1; idx < LLSettingsDay::TRACK_MAX; ++idx) - day->clearCycleTrack(idx); - day->setSettingsAtKeyframe(settings, 0.0f, 1); - } - else if (type == "water") - { - day->clearCycleTrack(LLSettingsDay::TRACK_WATER); - day->setSettingsAtKeyframe(settings, 0.0f, LLSettingsDay::TRACK_WATER); - } - - return day; -} - -void LLEnvironment::onAgentPositionHasChanged(const LLVector3 &localpos) -{ - S32 trackno = calculateSkyTrackForAltitude(localpos.mV[VZ]); - if (trackno == mCurrentTrack) - return; - - mCurrentTrack = trackno; - - LLViewerRegion* cur_region = gAgent.getRegion(); - if (!cur_region || !cur_region->capabilitiesReceived()) - { - // Environment not ready, environment will be updated later, don't cause 'blend' yet. - // But keep mCurrentTrack updated in case we won't get new altitudes for some reason - return; - } - - for (S32 env = ENV_LOCAL; env < ENV_DEFAULT; ++env) - { - if (mEnvironments[env]) - mEnvironments[env]->setSkyTrack(mCurrentTrack); - } -} - -S32 LLEnvironment::calculateSkyTrackForAltitude(F64 altitude) -{ - auto it = std::find_if_not(mTrackAltitudes.begin(), mTrackAltitudes.end(), [altitude](F32 test) { return altitude > test; }); - - if (it == mTrackAltitudes.begin()) - return 1; - else if (it == mTrackAltitudes.end()) - return 4; - - return std::min(static_cast(std::distance(mTrackAltitudes.begin(), it)), 4); -} - -//------------------------------------------------------------------------- -void LLEnvironment::handleEnvironmentPush(LLSD &message) -{ - // Log the experience message - LLExperienceLog::instance().handleExperienceMessage(message); - - std::string action = message[KEY_ACTION].asString(); - LLUUID experience_id = message[KEY_EXPERIENCEID].asUUID(); - LLSD action_data = message[KEY_ACTIONDATA]; - F32 transition_time = action_data[KEY_TRANSITIONTIME].asReal(); - - //TODO: Check here that the viewer thinks the experience is still valid. - - - if (action == ACTION_CLEARENVIRONMENT) - { - handleEnvironmentPushClear(experience_id, action_data, transition_time); - } - else if (action == ACTION_PUSHFULLENVIRONMENT) - { - handleEnvironmentPushFull(experience_id, action_data, transition_time); - } - else if (action == ACTION_PUSHPARTIALENVIRONMENT) - { - handleEnvironmentPushPartial(experience_id, action_data, transition_time); - } - else - { - LL_WARNS("ENVIRONMENT", "GENERICMESSAGES") << "Unknown environment push action '" << action << "'" << LL_ENDL; - } -} - -void LLEnvironment::handleEnvironmentPushClear(LLUUID experience_id, LLSD &message, F32 transition) -{ - clearExperienceEnvironment(experience_id, LLSettingsBase::Seconds(transition)); -} - -void LLEnvironment::handleEnvironmentPushFull(LLUUID experience_id, LLSD &message, F32 transition) -{ - LLUUID asset_id(message[KEY_ASSETID].asUUID()); - - setExperienceEnvironment(experience_id, asset_id, LLSettingsBase::Seconds(transition)); -} - -void LLEnvironment::handleEnvironmentPushPartial(LLUUID experience_id, LLSD &message, F32 transition) -{ - LLSD settings(message["settings"]); - - if (settings.isUndefined()) - return; - - setExperienceEnvironment(experience_id, settings, LLSettingsBase::Seconds(transition)); -} - -void LLEnvironment::clearExperienceEnvironment(LLUUID experience_id, LLSettingsBase::Seconds transition_time) -{ - DayInjection::ptr_t injection = std::dynamic_pointer_cast(getEnvironmentInstance(ENV_PUSH)); - if (injection) - { - injection->clearInjections(experience_id, transition_time); - } - -} - -void LLEnvironment::setSharedEnvironment() -{ - clearEnvironment(LLEnvironment::ENV_LOCAL); - setSelectedEnvironment(LLEnvironment::ENV_LOCAL); - updateEnvironment(); -} - -void LLEnvironment::setExperienceEnvironment(LLUUID experience_id, LLUUID asset_id, F32 transition_time) -{ - LLSettingsVOBase::getSettingsAsset(asset_id, - [this, experience_id, transition_time](LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, LLExtStat) - { - onSetExperienceEnvAssetLoaded(experience_id, settings, transition_time, status); - }); - - -} - -void LLEnvironment::onSetExperienceEnvAssetLoaded(LLUUID experience_id, LLSettingsBase::ptr_t settings, F32 transition_time, S32 status) -{ - DayInjection::ptr_t environment = std::dynamic_pointer_cast(getEnvironmentInstance(ENV_PUSH)); - bool updateenvironment(false); - - if (!settings || status) - { - LLSD args; - args["NAME"] = experience_id.asString(); - LLNotificationsUtil::add("FailedToFindSettings", args); - return; - } - - if (!environment) - { - environment = std::dynamic_pointer_cast(getEnvironmentInstance(ENV_PUSH, true)); - updateenvironment = true; - } - - if (settings->getSettingsType() == "daycycle") - { - environment->setInjectedDay(std::static_pointer_cast(settings), experience_id, LLSettingsBase::Seconds(transition_time)); - } - else if (settings->getSettingsType() == "sky") - { - environment->setInjectedSky(std::static_pointer_cast(settings), experience_id, LLSettingsBase::Seconds(transition_time)); - } - else if (settings->getSettingsType() == "water") - { - environment->setInjectedWater(std::static_pointer_cast(settings), experience_id, LLSettingsBase::Seconds(transition_time)); - } - - if (updateenvironment) - updateEnvironment(TRANSITION_INSTANT, true); -} - - -void LLEnvironment::setExperienceEnvironment(LLUUID experience_id, LLSD data, F32 transition_time) -{ - LLSD sky(data["sky"]); - LLSD water(data["water"]); - - if (sky.isUndefined() && water.isUndefined()) - { - clearExperienceEnvironment(experience_id, LLSettingsBase::Seconds(transition_time)); - return; - } - - DayInjection::ptr_t environment = std::dynamic_pointer_cast(getEnvironmentInstance(ENV_PUSH)); - bool updateenvironment(false); - - if (!environment) - { - environment = std::dynamic_pointer_cast(getEnvironmentInstance(ENV_PUSH, true)); - updateenvironment = true; - } - - if (!sky.isUndefined()) - { - environment->injectSkySettings(sky, experience_id, LLSettingsBase::Seconds(transition_time)); - } - - if (!water.isUndefined()) - { - environment->injectWaterSettings(water, experience_id, LLSettingsBase::Seconds(transition_time)); - } - - if (updateenvironment) - updateEnvironment(TRANSITION_INSTANT, true); - -} - -void LLEnvironment::listenExperiencePump(const LLSD &message) -{ - LLUUID experience_id = message["experience"]; - LLSD data = message[experience_id.asString()]; - std::string permission(data["permission"].asString()); - - if ((permission == "Forget") || (permission == "Block")) - { - clearExperienceEnvironment(experience_id, (permission == "Block") ? TRANSITION_INSTANT : TRANSITION_FAST); - } -} - -//========================================================================= -LLEnvironment::DayInstance::DayInstance(EnvSelection_t env) : - mDayCycle(), - mSky(), - mWater(), - mDayLength(LLSettingsDay::DEFAULT_DAYLENGTH), - mDayOffset(LLSettingsDay::DEFAULT_DAYOFFSET), - mBlenderSky(), - mBlenderWater(), - mInitialized(false), - mSkyTrack(1), - mEnv(env), - mAnimateFlags(0) -{ } - - -LLEnvironment::DayInstance::ptr_t LLEnvironment::DayInstance::clone() const -{ - ptr_t environment = std::make_shared(mEnv); - - environment->mDayCycle = mDayCycle; - environment->mSky = mSky; - environment->mWater = mWater; - environment->mDayLength = mDayLength; - environment->mDayOffset = mDayOffset; - environment->mBlenderSky = mBlenderSky; - environment->mBlenderWater = mBlenderWater; - environment->mInitialized = mInitialized; - environment->mSkyTrack = mSkyTrack; - environment->mAnimateFlags = mAnimateFlags; - - return environment; -} - -bool LLEnvironment::DayInstance::applyTimeDelta(const LLSettingsBase::Seconds& delta) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; - ptr_t keeper(shared_from_this()); // makes sure that this does not go away while it is being worked on. - - bool changed(false); - if (!mInitialized) - initialize(); - - if (mBlenderSky) - changed |= mBlenderSky->applyTimeDelta(delta); - if (mBlenderWater) - changed |= mBlenderWater->applyTimeDelta(delta); - return changed; -} - -void LLEnvironment::DayInstance::setDay(const LLSettingsDay::ptr_t &pday, LLSettingsDay::Seconds daylength, LLSettingsDay::Seconds dayoffset) -{ - mInitialized = false; - - mAnimateFlags = 0; - - mDayCycle = pday; - mDayLength = daylength; - mDayOffset = dayoffset; - - mBlenderSky.reset(); - mBlenderWater.reset(); - - mSky = LLSettingsVOSky::buildDefaultSky(); - mWater = LLSettingsVOWater::buildDefaultWater(); - - animate(); -} - - -bool LLEnvironment::DayInstance::setSky(const LLSettingsSky::ptr_t &psky) -{ - mInitialized = false; - - bool changed = psky == nullptr || mSky == nullptr || mSky->getHash() != psky->getHash(); - - bool different_sky = mSky != psky; - - mSky = psky; - mSky->mReplaced |= different_sky; - mSky->update(); - mBlenderSky.reset(); - - if (gAtmosphere) - { - AtmosphericModelSettings settings; - LLEnvironment::getAtmosphericModelSettings(settings, psky); - gAtmosphere->configureAtmosphericModel(settings); - } - - return changed; -} - -void LLEnvironment::DayInstance::setWater(const LLSettingsWater::ptr_t &pwater) -{ - mInitialized = false; - - bool different_water = mWater != pwater; - mWater = pwater; - mWater->mReplaced |= different_water; - mWater->update(); - mBlenderWater.reset(); -} - -void LLEnvironment::DayInstance::initialize() -{ - mInitialized = true; - - if (!mWater) - mWater = LLSettingsVOWater::buildDefaultWater(); - if (!mSky) - mSky = LLSettingsVOSky::buildDefaultSky(); -} - -void LLEnvironment::DayInstance::clear() -{ - mDayCycle.reset(); - mSky.reset(); - mWater.reset(); - mDayLength = LLSettingsDay::DEFAULT_DAYLENGTH; - mDayOffset = LLSettingsDay::DEFAULT_DAYOFFSET; - mBlenderSky.reset(); - mBlenderWater.reset(); - mSkyTrack = 1; -} - -void LLEnvironment::DayInstance::setSkyTrack(S32 trackno) -{ - mSkyTrack = trackno; - if (mBlenderSky) - { - mBlenderSky->switchTrack(trackno, 0.0); - } -} - -void LLEnvironment::DayInstance::setBlenders(const LLSettingsBlender::ptr_t &skyblend, const LLSettingsBlender::ptr_t &waterblend) -{ - mBlenderSky = skyblend; - mBlenderWater = waterblend; -} - -LLSettingsBase::TrackPosition LLEnvironment::DayInstance::getProgress() const -{ - LLSettingsBase::Seconds now(LLDate::now().secondsSinceEpoch()); - now += mDayOffset; - - if ((mDayLength <= 0) || !mDayCycle) - return -1.0f; // no actual day cycle. - - return convert_time_to_position(now, mDayLength); -} - -LLSettingsBase::TrackPosition LLEnvironment::DayInstance::secondsToKeyframe(LLSettingsDay::Seconds seconds) -{ - return convert_time_to_position(seconds, mDayLength); -} - -void LLEnvironment::DayInstance::animate() -{ - LLSettingsBase::Seconds now(LLDate::now().secondsSinceEpoch()); - - now += mDayOffset; - - if (!mDayCycle) - return; - - if (!(mAnimateFlags & NO_ANIMATE_WATER)) - { - LLSettingsDay::CycleTrack_t &wtrack = mDayCycle->getCycleTrack(0); - - if (wtrack.empty()) - { - mWater.reset(); - mBlenderWater.reset(); - } - else - { - mWater = LLSettingsVOWater::buildDefaultWater(); - mBlenderWater = std::make_shared(mWater, mDayCycle, 0, - mDayLength, mDayOffset, DEFAULT_UPDATE_THRESHOLD); - } - } - - if (!(mAnimateFlags & NO_ANIMATE_SKY)) - { - // sky, initialize to track 1 - LLSettingsDay::CycleTrack_t &track = mDayCycle->getCycleTrack(1); - - if (track.empty()) - { - mSky.reset(); - mBlenderSky.reset(); - } - else - { - mSky = LLSettingsVOSky::buildDefaultSky(); - mBlenderSky = std::make_shared(mSky, mDayCycle, 1, - mDayLength, mDayOffset, DEFAULT_UPDATE_THRESHOLD); - mBlenderSky->switchTrack(mSkyTrack, 0.0); - } - } -} - -//------------------------------------------------------------------------- -LLEnvironment::DayTransition::DayTransition(const LLSettingsSky::ptr_t &skystart, - const LLSettingsWater::ptr_t &waterstart, LLEnvironment::DayInstance::ptr_t &end, LLSettingsDay::Seconds time) : - DayInstance(ENV_NONE), - mStartSky(skystart), - mStartWater(waterstart), - mNextInstance(end), - mTransitionTime(time) -{ - -} - -bool LLEnvironment::DayTransition::applyTimeDelta(const LLSettingsBase::Seconds& delta) -{ - bool changed(false); - - changed = mNextInstance->applyTimeDelta(delta); - changed |= DayInstance::applyTimeDelta(delta); - return changed; -} - -void LLEnvironment::DayTransition::animate() -{ - mNextInstance->animate(); - - mWater = mStartWater->buildClone(); - mBlenderWater = std::make_shared(mWater, mStartWater, mNextInstance->getWater(), mTransitionTime); - mBlenderWater->setOnFinished( - [this](LLSettingsBlender::ptr_t blender) { - mBlenderWater.reset(); - - if (!mBlenderSky && !mBlenderWater) - LLEnvironment::instance().mCurrentEnvironment = mNextInstance; - else - setWater(mNextInstance->getWater()); - }); - - - // pause probe updates and reset reflection maps on sky change - gPipeline.mReflectionMapManager.pause(); - gPipeline.mReflectionMapManager.reset(); - - mSky = mStartSky->buildClone(); - mBlenderSky = std::make_shared(mSky, mStartSky, mNextInstance->getSky(), mTransitionTime); - mBlenderSky->setOnFinished( - [this](LLSettingsBlender::ptr_t blender) { - mBlenderSky.reset(); - - // resume reflection probe updates - gPipeline.mReflectionMapManager.resume(); - - if (!mBlenderSky && !mBlenderWater) - LLEnvironment::instance().mCurrentEnvironment = mNextInstance; - else - setSky(mNextInstance->getSky()); - }); -} - -void LLEnvironment::saveToSettings() -{ - std::string user_dir = gDirUtilp->getLindenUserDir(); - if (user_dir.empty()) - { - // not logged in - return; - } - bool has_data = false; - - if (gSavedSettings.getBOOL("EnvironmentPersistAcrossLogin")) - { - DayInstance::ptr_t environment = getEnvironmentInstance(ENV_LOCAL); - if (environment) - { - // Environment is 'layered'. No data in ENV_LOCAL means we are using parcel/region - // Store local environment for next session - LLSD env_data; - - LLSettingsDay::ptr_t day = environment->getDayCycle(); - if (day) - { - const std::string name = day->getName(); - const LLUUID asset_id = day->getAssetId(); - if (asset_id.notNull()) - { - // just save the id - env_data["day_id"] = asset_id; - env_data["day_length"] = LLSD::Integer(environment->getDayLength()); - env_data["day_offset"] = LLSD::Integer(environment->getDayOffset()); - has_data = true; - } - else if (!name.empty() && name != LLSettingsBase::DEFAULT_SETTINGS_NAME) - { - // This setting was created locally and was not saved - // The only option is to save the whole thing - env_data["day_llsd"] = day->getSettings(); - env_data["day_length"] = LLSD::Integer(environment->getDayLength()); - env_data["day_offset"] = LLSD::Integer(environment->getDayOffset()); - has_data = true; - } - } - - LLSettingsSky::ptr_t sky = environment->getSky(); - if ((environment->getFlags() & DayInstance::NO_ANIMATE_SKY) && sky) - { - const std::string name = sky->getName(); - const LLUUID asset_id = sky->getAssetId(); - if (asset_id.notNull()) - { - // just save the id - env_data["sky_id"] = asset_id; - has_data = true; - } - else if (!name.empty() && name != LLSettingsBase::DEFAULT_SETTINGS_NAME) - { - // This setting was created locally and was not saved - // The only option is to save the whole thing - env_data["sky_llsd"] = sky->getSettings(); - has_data = true; - } - has_data = true; - } - - LLSettingsWater::ptr_t water = environment->getWater(); - if ((environment->getFlags() & DayInstance::NO_ANIMATE_WATER) && water) - { - const std::string name = water->getName(); - const LLUUID asset_id = water->getAssetId(); - if (asset_id.notNull()) - { - // just save the id - env_data["water_id"] = asset_id; - has_data = true; - } - else if (!name.empty() && name != LLSettingsBase::DEFAULT_SETTINGS_NAME) - { - // This setting was created locally and was not saved - // The only option is to save the whole thing - env_data["water_llsd"] = water->getSettings(); - has_data = true; - } - } - - std::string user_filepath = user_dir + gDirUtilp->getDirDelimiter() + LOCAL_ENV_STORAGE_FILE; - llofstream out(user_filepath.c_str(), std::ios_base::out | std::ios_base::binary); - if (out.good()) - { - LLSDSerialize::toBinary(env_data, out); - out.close(); - } - else - { - LL_WARNS("ENVIRONMENT") << "Unable to open " << user_filepath << " for output." << LL_ENDL; - } - } - } - - if (!has_data) - { - LLFile::remove(user_dir + gDirUtilp->getDirDelimiter() + LOCAL_ENV_STORAGE_FILE, ENOENT); - } -} - -void LLEnvironment::loadSkyWaterFromSettings(const LLSD &env_data, bool &valid, bool &assets_present) -{ - if (env_data.has("sky_id")) - { - // causes asset loaded callback and an update - setEnvironment(ENV_LOCAL, env_data["sky_id"].asUUID()); - valid = true; - assets_present = true; - } - else if (env_data.has("sky_llsd")) - { - LLSettingsSky::ptr_t sky = LLSettingsVOSky::buildSky(env_data["sky_llsd"]); - setEnvironment(ENV_LOCAL, sky); - valid = true; - } - - if (env_data.has("water_id")) - { - // causes asset loaded callback and an update - setEnvironment(ENV_LOCAL, env_data["water_id"].asUUID()); - valid = true; - assets_present = true; - } - else if (env_data.has("water_llsd")) - { - LLSettingsWater::ptr_t sky = LLSettingsVOWater::buildWater(env_data["water_llsd"]); - setEnvironment(ENV_LOCAL, sky); - valid = true; - } -} - -bool LLEnvironment::loadFromSettings() -{ - if (!gSavedSettings.getBOOL("EnvironmentPersistAcrossLogin")) - { - return false; - } - - std::string user_path = gDirUtilp->getLindenUserDir(); - if (user_path.empty()) - { - LL_WARNS("ENVIRONMENT") << "Can't load previous environment, Environment was initialized before user logged in" << LL_ENDL; - return false; - } - std::string user_filepath(user_path + gDirUtilp->getDirDelimiter() + LOCAL_ENV_STORAGE_FILE); - if (!gDirUtilp->fileExists(user_filepath)) - { - // No previous environment - return false; - } - - LLSD env_data; - llifstream file(user_filepath.c_str(), std::ios_base::in | std::ios_base::binary); - if (file.is_open()) - { - LLSDSerialize::fromBinary(env_data, file, LLSDSerialize::SIZE_UNLIMITED); - if (env_data.isUndefined()) - { - LL_WARNS("ENVIRONMENT") << "error loading " << user_filepath << LL_ENDL; - return false; - } - else - { - LL_INFOS("ENVIRONMENT") << "Loaded previous session environment from: " << user_filepath << LL_ENDL; - } - file.close(); - } - else - { - LL_INFOS("ENVIRONMENT") << "Unable to open previous session environment file " << user_filepath << LL_ENDL; - } - - if (!env_data.isMap() || (env_data.size() == 0)) - { - LL_DEBUGS("ENVIRONMENT") << "Empty map loaded from: " << user_filepath << LL_ENDL; - return false; - } - - bool valid = false; - bool has_assets = false; - - if (env_data.has("day_id")) - { - LLUUID assetId = env_data["day_id"].asUUID(); - - LLSettingsVOBase::getSettingsAsset(assetId, - [this, env_data](LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, LLExtStat) - { - // Day should be always applied first, - // otherwise it will override sky or water that was set earlier - // so wait for asset to load before applying sky/water - onSetEnvAssetLoaded(ENV_LOCAL, asset_id, settings, TRANSITION_DEFAULT, status, NO_VERSION); - bool valid = false, has_assets = false; - loadSkyWaterFromSettings(env_data, valid, has_assets); - if (!has_assets && valid) - { - // Settings were loaded from file without having an asset, needs update - // otherwise update will be done by asset callback - updateEnvironment(TRANSITION_DEFAULT, true); - } - }); - // bail early, everything have to be done at callback - return true; - } - else if (env_data.has("day_llsd")) - { - S32 length = env_data["day_length"].asInteger(); - S32 offset = env_data["day_offset"].asInteger(); - LLSettingsDay::ptr_t pday = LLSettingsVODay::buildDay(env_data["day_llsd"]); - setEnvironment(ENV_LOCAL, pday, LLSettingsDay::Seconds(length), LLSettingsDay::Seconds(offset)); - valid = true; - } - - loadSkyWaterFromSettings(env_data, valid, has_assets); - - if (valid && !has_assets) - { - // Settings were loaded from file without having an asset, needs update - // otherwise update will be done by asset callback - updateEnvironment(TRANSITION_DEFAULT, true); - } - return valid; -} - -void LLEnvironment::saveBeaconsState() -{ - if (mEditorCounter == 0) - { - mShowSunBeacon = gSavedSettings.getBOOL("sunbeacon"); - mShowMoonBeacon = gSavedSettings.getBOOL("moonbeacon"); - } - ++mEditorCounter; -} -void LLEnvironment::revertBeaconsState() -{ - --mEditorCounter; - if (mEditorCounter == 0) - { - gSavedSettings.setBOOL("sunbeacon", mShowSunBeacon && gSavedSettings.getBOOL("sunbeacon")); - gSavedSettings.setBOOL("moonbeacon", mShowMoonBeacon && gSavedSettings.getBOOL("moonbeacon")); - } -} - -//========================================================================= -LLTrackBlenderLoopingManual::LLTrackBlenderLoopingManual(const LLSettingsBase::ptr_t &target, const LLSettingsDay::ptr_t &day, S32 trackno) : - LLSettingsBlender(target, LLSettingsBase::ptr_t(), LLSettingsBase::ptr_t()), - mDay(day), - mTrackNo(trackno), - mPosition(0.0) -{ - LLSettingsDay::TrackBound_t initial = getBoundingEntries(mPosition); - - if (initial.first != mEndMarker) - { // No frames in track - mInitial = (*initial.first).second; - mFinal = (*initial.second).second; - - LLSD initSettings = mInitial->getSettings(); - mTarget->replaceSettings(initSettings); - } -} - -LLSettingsBase::BlendFactor LLTrackBlenderLoopingManual::setPosition(const LLSettingsBase::TrackPosition& position) -{ - mPosition = llclamp(position, 0.0f, 1.0f); - - LLSettingsDay::TrackBound_t bounds = getBoundingEntries(mPosition); - - if (bounds.first == mEndMarker) - { // No frames in track. - return 0.0; - } - - mInitial = (*bounds.first).second; - mFinal = (*bounds.second).second; - - F64 spanLength = getSpanLength(bounds); - - F64 spanPos = ((mPosition < (*bounds.first).first) ? (mPosition + 1.0) : mPosition) - (*bounds.first).first; - - if (spanPos > spanLength) - { - // we are clamping position to 0-1 and spanLength is 1 - // so don't account for case of spanPos == spanLength - spanPos = fmod(spanPos, spanLength); - } - - F64 blendf = spanPos / spanLength; - return LLSettingsBlender::setBlendFactor(blendf); -} - -void LLTrackBlenderLoopingManual::switchTrack(S32 trackno, const LLSettingsBase::TrackPosition& position) -{ - mTrackNo = trackno; - - LLSettingsBase::TrackPosition useposition = (position < 0.0) ? mPosition : position; - - setPosition(useposition); -} - -LLSettingsDay::TrackBound_t LLTrackBlenderLoopingManual::getBoundingEntries(F64 position) -{ - LLSettingsDay::CycleTrack_t &wtrack = mDay->getCycleTrack(mTrackNo); - - mEndMarker = wtrack.end(); - - LLSettingsDay::TrackBound_t bounds = get_bounding_entries(wtrack, position); - return bounds; -} - -F64 LLTrackBlenderLoopingManual::getSpanLength(const LLSettingsDay::TrackBound_t &bounds) const -{ - return get_wrapping_distance((*bounds.first).first, (*bounds.second).first); -} - -//========================================================================= -namespace -{ - DayInjection::DayInjection(LLEnvironment::EnvSelection_t env): - LLEnvironment::DayInstance(env), - mBaseDayInstance(), - mInjectedSky(), - mInjectedWater(), - mActiveExperiences(), - mDayExperience(), - mSkyExperience(), - mWaterExperience(), - mEnvChangeConnection(), - mParcelChangeConnection() - { - mInjectedSky = std::make_shared(LLEnvironment::instance().getCurrentSky()); - mInjectedWater = std::make_shared(LLEnvironment::instance().getCurrentWater()); - mBaseDayInstance = LLEnvironment::instance().getSharedEnvironmentInstance(); - mSky = mInjectedSky; - mWater = mInjectedWater; - - mEnvChangeConnection = LLEnvironment::instance().setEnvironmentChanged([this](LLEnvironment::EnvSelection_t env, S32) { onEnvironmentChanged(env); }); - mParcelChangeConnection = gAgent.addParcelChangedCallback([this]() { onParcelChange(); }); - } - - DayInjection::~DayInjection() - { - if (mEnvChangeConnection.connected()) - mEnvChangeConnection.disconnect(); - if (mParcelChangeConnection.connected()) - mParcelChangeConnection.disconnect(); - } - - - bool DayInjection::applyTimeDelta(const LLSettingsBase::Seconds& delta) - { - bool changed(false); - - if (mBaseDayInstance) - changed |= mBaseDayInstance->applyTimeDelta(delta); - mInjectedSky->applyInjections(delta); - mInjectedWater->applyInjections(delta); - changed |= LLEnvironment::DayInstance::applyTimeDelta(delta); - if (changed) - { - mInjectedSky->setDirtyFlag(true); - mInjectedWater->setDirtyFlag(true); - } - mInjectedSky->update(); - mInjectedWater->update(); - - if (!hasInjections()) - { // There are no injections being managed. This should really go away. - LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_PUSH); - LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT); - } - - return changed; - } - - void DayInjection::setBaseDayInstance(const LLEnvironment::DayInstance::ptr_t &baseday) - { - mBaseDayInstance = baseday; - - if (mSkyExperience.isNull()) - mInjectedSky->setSource(mBaseDayInstance->getSky()); - if (mWaterExperience.isNull()) - mInjectedWater->setSource(mBaseDayInstance->getWater()); - } - - - bool DayInjection::hasInjections() const - { - return (!mSkyExperience.isNull() || !mWaterExperience.isNull() || !mDayExperience.isNull() || - mBlenderSky || mBlenderWater || mInjectedSky->hasInjections() || mInjectedWater->hasInjections()); - } - - - void DayInjection::testExperiencesOnParcel(S32 parcel_id) - { - LLCoros::instance().launch("DayInjection::testExperiencesOnParcel", - [this, parcel_id]() { DayInjection::testExperiencesOnParcelCoro(std::static_pointer_cast(this->shared_from_this()), parcel_id); }); - - } - - void DayInjection::setInjectedDay(const LLSettingsDay::ptr_t &pday, LLUUID experience_id, LLSettingsBase::Seconds transition) - { - mSkyExperience = experience_id; - mWaterExperience = experience_id; - mDayExperience = experience_id; - - mBaseDayInstance = mBaseDayInstance->clone(); - mBaseDayInstance->setEnvironmentSelection(LLEnvironment::ENV_NONE); - mBaseDayInstance->setDay(pday, mBaseDayInstance->getDayLength(), mBaseDayInstance->getDayOffset()); - animateSkyChange(mBaseDayInstance->getSky(), transition); - animateWaterChange(mBaseDayInstance->getWater(), transition); - - mActiveExperiences.insert(experience_id); - } - - void DayInjection::setInjectedSky(const LLSettingsSky::ptr_t &psky, LLUUID experience_id, LLSettingsBase::Seconds transition) - { - mSkyExperience = experience_id; - mActiveExperiences.insert(experience_id); - checkExperience(); - animateSkyChange(psky, transition); - } - - void DayInjection::setInjectedWater(const LLSettingsWater::ptr_t &pwater, LLUUID experience_id, LLSettingsBase::Seconds transition) - { - mWaterExperience = experience_id; - mActiveExperiences.insert(experience_id); - checkExperience(); - animateWaterChange(pwater, transition); - } - - void DayInjection::injectSkySettings(LLSD settings, LLUUID experience_id, LLSettingsBase::Seconds transition) - { - mInjectedSky->injectExperienceValues(settings, experience_id, transition); - mActiveExperiences.insert(experience_id); - } - - void DayInjection::injectWaterSettings(LLSD settings, LLUUID experience_id, LLSettingsBase::Seconds transition) - { - mInjectedWater->injectExperienceValues(settings, experience_id, transition); - mActiveExperiences.insert(experience_id); - } - - void DayInjection::clearInjections(LLUUID experience_id, LLSettingsBase::Seconds transition_time) - { - if ((experience_id.isNull() && !mDayExperience.isNull()) || (experience_id == mDayExperience)) - { - mDayExperience.setNull(); - if (mSkyExperience == experience_id) - mSkyExperience.setNull(); - if (mWaterExperience == experience_id) - mWaterExperience.setNull(); - - mBaseDayInstance = LLEnvironment::instance().getSharedEnvironmentInstance(); - - if (mSkyExperience.isNull()) - animateSkyChange(mBaseDayInstance->getSky(), transition_time); - if (mWaterExperience.isNull()) - animateWaterChange(mBaseDayInstance->getWater(), transition_time); - } - - if ((experience_id.isNull() && !mSkyExperience.isNull()) || (experience_id == mSkyExperience)) - { - mSkyExperience.setNull(); - animateSkyChange(mBaseDayInstance->getSky(), transition_time); - } - if ((experience_id.isNull() && !mWaterExperience.isNull()) || (experience_id == mWaterExperience)) - { - mWaterExperience.setNull(); - animateWaterChange(mBaseDayInstance->getWater(), transition_time); - } - - mInjectedSky->removeInjections(experience_id, transition_time); - mInjectedWater->removeInjections(experience_id, transition_time); - - if (experience_id.isNull()) - mActiveExperiences.clear(); - else - mActiveExperiences.erase(experience_id); - - if ((transition_time == LLEnvironment::TRANSITION_INSTANT) && (countExperiencesActive() == 0)) - { // Only do this if instant and there are no other experiences injecting values. - // (otherwise will be handled after transition) - LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_PUSH); - LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT); - } - } - - - void DayInjection::testExperiencesOnParcelCoro(wptr_t that, S32 parcel_id) - { - LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); - LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t - httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("testExperiencesOnParcelCoro", httpPolicy)); - LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - std::string url = gAgent.getRegionCapability("ExperienceQuery"); - - if (url.empty()) - { - LL_WARNS("ENVIRONMENT") << "No experience query cap." << LL_ENDL; - return; // no checking in this region. - } - - { - ptr_t thatlock(that); - std::stringstream fullurl; - - if (!thatlock) - return; - - fullurl << url << "?"; - fullurl << "parcelid=" << parcel_id; - - for (auto it = thatlock->mActiveExperiences.begin(); it != thatlock->mActiveExperiences.end(); ++it) - { - if (it != thatlock->mActiveExperiences.begin()) - fullurl << ","; - else - fullurl << "&experiences="; - fullurl << (*it).asString(); - } - url = fullurl.str(); - } - - LLSD result = httpAdapter->getAndSuspend(httpRequest, url); - LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; - LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); - - if (!status) - { - LL_WARNS() << "Unable to retrieve experience status for parcel." << LL_ENDL; - return; - } - - { - LLParcel* parcel = LLViewerParcelMgr::instance().getAgentParcel(); - if (!parcel) - return; - - if (parcel_id != parcel->getLocalID()) - { - // Agent no longer on queried parcel. - return; - } - } - - - LLSD experiences = result["experiences"]; - { - ptr_t thatlock(that); - if (!thatlock) - return; - - for (LLSD::map_iterator itr = experiences.beginMap(); itr != experiences.endMap(); ++itr) - { - if (!((*itr).second.asBoolean())) - thatlock->clearInjections(LLUUID((*itr).first), LLEnvironment::TRANSITION_FAST); - - } - } - } - - void DayInjection::animateSkyChange(LLSettingsSky::ptr_t psky, LLSettingsBase::Seconds transition) - { - if (mInjectedSky.get() == psky.get()) - { // An attempt to animate to itself... don't do it. - return; - } - if (transition == LLEnvironment::TRANSITION_INSTANT) - { - mBlenderSky.reset(); - mInjectedSky->setSource(psky); - } - else - { - LLSettingsSky::ptr_t start_sky(mInjectedSky->getSource()->buildClone()); - LLSettingsSky::ptr_t target_sky(start_sky->buildClone()); - mInjectedSky->setSource(target_sky); - - // clear reflection probes and pause updates during sky change - gPipeline.mReflectionMapManager.pause(); - gPipeline.mReflectionMapManager.reset(); - - mBlenderSky = std::make_shared(target_sky, start_sky, psky, transition); - mBlenderSky->setOnFinished( - [this, psky](LLSettingsBlender::ptr_t blender) - { - mBlenderSky.reset(); - mInjectedSky->setSource(psky); - - // resume updating reflection probes when done animating sky - gPipeline.mReflectionMapManager.resume(); - setSky(mInjectedSky); - if (!mBlenderWater && (countExperiencesActive() == 0)) - { - LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_PUSH); - LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT); - } - }); - } - } - - void DayInjection::animateWaterChange(LLSettingsWater::ptr_t pwater, LLSettingsBase::Seconds transition) - { - if (mInjectedWater.get() == pwater.get()) - { // An attempt to animate to itself. Bad idea. - return; - } - if (transition == LLEnvironment::TRANSITION_INSTANT) - { - mBlenderWater.reset(); - mInjectedWater->setSource(pwater); - } - else - { - LLSettingsWater::ptr_t start_Water(mInjectedWater->getSource()->buildClone()); - LLSettingsWater::ptr_t scratch_Water(start_Water->buildClone()); - mInjectedWater->setSource(scratch_Water); - - mBlenderWater = std::make_shared(scratch_Water, start_Water, pwater, transition); - mBlenderWater->setOnFinished( - [this, pwater](LLSettingsBlender::ptr_t blender) - { - mBlenderWater.reset(); - mInjectedWater->setSource(pwater); - setWater(mInjectedWater); - if (!mBlenderSky && (countExperiencesActive() == 0)) - { - LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_PUSH); - LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT); - } - }); - } - } - - void DayInjection::onEnvironmentChanged(LLEnvironment::EnvSelection_t env) - { - if (env >= LLEnvironment::ENV_PARCEL) - { - LLEnvironment::EnvSelection_t base_env(mBaseDayInstance->getEnvironmentSelection()); - LLEnvironment::DayInstance::ptr_t nextbase = LLEnvironment::instance().getSharedEnvironmentInstance(); - - if ((base_env == LLEnvironment::ENV_NONE) || (nextbase == mBaseDayInstance) || - (!mSkyExperience.isNull() && !mWaterExperience.isNull())) - { // base instance completely overridden, or not changed no transition will happen - return; - } - - LL_WARNS("PUSHENV", "ENVIRONMENT") << "Underlying environment has changed (" << env << ")! Base env is type " << base_env << LL_ENDL; - - LLEnvironment::DayInstance::ptr_t trans = std::make_shared(std::static_pointer_cast(shared_from_this()), - mBaseDayInstance->getSky(), mBaseDayInstance->getWater(), nextbase, LLEnvironment::TRANSITION_DEFAULT); - - trans->animate(); - setBaseDayInstance(trans); - } - } - - void DayInjection::onParcelChange() - { - S32 parcel_id(INVALID_PARCEL_ID); - LLParcel* parcel = LLViewerParcelMgr::instance().getAgentParcel(); - - if (!parcel) - return; - - parcel_id = parcel->getLocalID(); - - testExperiencesOnParcel(parcel_id); - } - - void DayInjection::checkExperience() - { - if ((!mDayExperience.isNull()) && (mSkyExperience != mDayExperience) && (mWaterExperience != mDayExperience)) - { // There was a day experience but we've replaced it with a water and a sky experience. - mDayExperience.setNull(); - mBaseDayInstance = LLEnvironment::instance().getSharedEnvironmentInstance(); - } - } - - void DayInjection::animate() - { - - } - - void InjectedTransition::animate() - { - mNextInstance->animate(); - - if (!mInjection->isOverriddenSky()) - { - mSky = mStartSky->buildClone(); - mBlenderSky = std::make_shared(mSky, mStartSky, mNextInstance->getSky(), mTransitionTime); - mBlenderSky->setOnFinished( - [this](LLSettingsBlender::ptr_t blender) { - mBlenderSky.reset(); - - if (!mBlenderSky && !mBlenderSky) - mInjection->setBaseDayInstance(mNextInstance); - else - mInjection->mInjectedSky->setSource(mNextInstance->getSky()); - }); - } - else - { - mSky = mInjection->getSky(); - mBlenderSky.reset(); - } - - if (!mInjection->isOverriddenWater()) - { - mWater = mStartWater->buildClone(); - mBlenderWater = std::make_shared(mWater, mStartWater, mNextInstance->getWater(), mTransitionTime); - mBlenderWater->setOnFinished( - [this](LLSettingsBlender::ptr_t blender) { - mBlenderWater.reset(); - - if (!mBlenderSky && !mBlenderWater) - mInjection->setBaseDayInstance(mNextInstance); - else - mInjection->mInjectedWater->setSource(mNextInstance->getWater()); - }); - } - else - { - mWater = mInjection->getWater(); - mBlenderWater.reset(); - } - - } - -} - +/** + * @file llenvmanager.cpp + * @brief Implementation of classes managing WindLight and water settings. + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llenvironment.h" + +#include + +#include "llagent.h" +#include "llviewercontrol.h" // for gSavedSettings +#include "llviewerregion.h" +#include "llwlhandlers.h" +#include "lltrans.h" +#include "lltrace.h" +#include "llfasttimer.h" +#include "llviewercamera.h" +#include "pipeline.h" +#include "llsky.h" + +#include "llviewershadermgr.h" + +#include "llparcel.h" +#include "llviewerparcelmgr.h" + +#include "llsdserialize.h" +#include "lldiriterator.h" + +#include "llsettingsvo.h" +#include "llnotificationsutil.h" + +#include "llregioninfomodel.h" + +#include + +#include "llatmosphere.h" +#include "llagent.h" +#include "roles_constants.h" +#include "llestateinfomodel.h" + +#include "lldispatcher.h" +#include "llviewergenericmessage.h" +#include "llexperiencelog.h" + +//========================================================================= +namespace +{ + const std::string KEY_ENVIRONMENT("environment"); + const std::string KEY_DAYASSET("day_asset"); + const std::string KEY_DAYCYCLE("day_cycle"); + const std::string KEY_DAYHASH("day_hash"); + const std::string KEY_DAYLENGTH("day_length"); + const std::string KEY_DAYNAME("day_name"); + const std::string KEY_DAYNAMES("day_names"); + const std::string KEY_DAYOFFSET("day_offset"); + const std::string KEY_ENVVERSION("env_version"); + const std::string KEY_ISDEFAULT("is_default"); + const std::string KEY_PARCELID("parcel_id"); + const std::string KEY_REGIONID("region_id"); + const std::string KEY_TRACKALTS("track_altitudes"); + const std::string KEY_FLAGS("flags"); + + const std::string MESSAGE_PUSHENVIRONMENT("PushExpEnvironment"); + + const std::string ACTION_CLEARENVIRONMENT("ClearEnvironment"); + const std::string ACTION_PUSHFULLENVIRONMENT("PushFullEnvironment"); + const std::string ACTION_PUSHPARTIALENVIRONMENT("PushPartialEnvironment"); + + const std::string KEY_ASSETID("asset_id"); + const std::string KEY_TRANSITIONTIME("transition_time"); + const std::string KEY_ACTION("action"); + const std::string KEY_ACTIONDATA("action_data"); + const std::string KEY_EXPERIENCEID("public_id"); + const std::string KEY_OBJECTNAME("ObjectName"); // some of these do not conform to the '_' format. + const std::string KEY_PARCELNAME("ParcelName"); // But changing these would also alter the Experience Log requirements. + const std::string KEY_COUNT("Count"); + + const std::string LISTENER_NAME("LLEnvironmentSingleton"); + const std::string PUMP_EXPERIENCE("experience_permission"); + + const std::string LOCAL_ENV_STORAGE_FILE("local_environment_data.bin"); + + //--------------------------------------------------------------------- + LLTrace::BlockTimerStatHandle FTM_ENVIRONMENT_UPDATE("Update Environment Tick"); + + LLSettingsBase::Seconds DEFAULT_UPDATE_THRESHOLD(10.0); + const LLSettingsBase::Seconds MINIMUM_SPANLENGTH(0.01f); + + //--------------------------------------------------------------------- + inline LLSettingsBase::TrackPosition get_wrapping_distance(LLSettingsBase::TrackPosition begin, LLSettingsBase::TrackPosition end) + { + if (begin < end) + { + return end - begin; + } + else if (begin > end) + { + return LLSettingsBase::TrackPosition(1.0) - (begin - end); + } + + return 1.0f; + } + + LLSettingsDay::CycleTrack_t::iterator get_wrapping_atafter(LLSettingsDay::CycleTrack_t &collection, const LLSettingsBase::TrackPosition& key) + { + if (collection.empty()) + return collection.end(); + + LLSettingsDay::CycleTrack_t::iterator it = collection.upper_bound(key); + + if (it == collection.end()) + { // wrap around + it = collection.begin(); + } + + return it; + } + + LLSettingsDay::CycleTrack_t::iterator get_wrapping_atbefore(LLSettingsDay::CycleTrack_t &collection, const LLSettingsBase::TrackPosition& key) + { + if (collection.empty()) + return collection.end(); + + LLSettingsDay::CycleTrack_t::iterator it = collection.lower_bound(key); + + if (it == collection.end()) + { // all keyframes are lower, take the last one. + --it; // we know the range is not empty + } + else if ((*it).first > key) + { // the keyframe we are interested in is smaller than the found. + if (it == collection.begin()) + it = collection.end(); + --it; + } + + return it; + } + + LLSettingsDay::TrackBound_t get_bounding_entries(LLSettingsDay::CycleTrack_t &track, const LLSettingsBase::TrackPosition& keyframe) + { + return LLSettingsDay::TrackBound_t(get_wrapping_atbefore(track, keyframe), get_wrapping_atafter(track, keyframe)); + } + + // Find normalized track position of given time along full length of cycle + inline LLSettingsBase::TrackPosition convert_time_to_position(const LLSettingsBase::Seconds& time, const LLSettingsBase::Seconds& len) + { + // early out to avoid divide by zero. if len is zero then jump to end position + if (len == 0.f) return 1.f; + + LLSettingsBase::TrackPosition position = LLSettingsBase::TrackPosition(fmod((F64)time, (F64)len) / (F64)len); + return llclamp(position, 0.0f, 1.0f); + } + + inline LLSettingsBase::BlendFactor convert_time_to_blend_factor(const LLSettingsBase::Seconds& time, const LLSettingsBase::Seconds& len, LLSettingsDay::CycleTrack_t &track) + { + LLSettingsBase::TrackPosition position = convert_time_to_position(time, len); + LLSettingsDay::TrackBound_t bounds(get_bounding_entries(track, position)); + + LLSettingsBase::TrackPosition spanlength(get_wrapping_distance((*bounds.first).first, (*bounds.second).first)); + if (position < (*bounds.first).first) + position += 1.0; + + LLSettingsBase::TrackPosition start = position - (*bounds.first).first; + + return static_cast(start / spanlength); + } + + //--------------------------------------------------------------------- + class LLTrackBlenderLoopingTime : public LLSettingsBlenderTimeDelta + { + public: + LLTrackBlenderLoopingTime(const LLSettingsBase::ptr_t &target, const LLSettingsDay::ptr_t &day, S32 trackno, + LLSettingsBase::Seconds cyclelength, LLSettingsBase::Seconds cycleoffset, LLSettingsBase::Seconds updateThreshold) : + LLSettingsBlenderTimeDelta(target, LLSettingsBase::ptr_t(), LLSettingsBase::ptr_t(), LLSettingsBase::Seconds(1.0)), + mDay(day), + mTrackNo(0), + mCycleLength(cyclelength), + mCycleOffset(cycleoffset) + { + // must happen prior to getBoundingEntries call... + mTrackNo = selectTrackNumber(trackno); + + LLSettingsBase::Seconds now(getAdjustedNow()); + LLSettingsDay::TrackBound_t initial = getBoundingEntries(now); + + mInitial = (*initial.first).second; + mFinal = (*initial.second).second; + mBlendSpan = getSpanTime(initial); + + initializeTarget(now); + setOnFinished([this](const LLSettingsBlender::ptr_t &){ onFinishedSpan(); }); + } + + void switchTrack(S32 trackno, const LLSettingsBase::TrackPosition&) override + { + S32 use_trackno = selectTrackNumber(trackno); + + if (use_trackno == mTrackNo) + { // results in no change + return; + } + + LLSettingsBase::ptr_t pstartsetting = mTarget->buildDerivedClone(); + mTrackNo = use_trackno; + + LLSettingsBase::Seconds now = getAdjustedNow() + LLEnvironment::TRANSITION_ALTITUDE; + LLSettingsDay::TrackBound_t bounds = getBoundingEntries(now); + + LLSettingsBase::ptr_t pendsetting = (*bounds.first).second->buildDerivedClone(); + LLSettingsBase::TrackPosition targetpos = convert_time_to_position(now, mCycleLength) - (*bounds.first).first; + LLSettingsBase::TrackPosition targetspan = get_wrapping_distance((*bounds.first).first, (*bounds.second).first); + + LLSettingsBase::BlendFactor blendf = calculateBlend(targetpos, targetspan); + pendsetting->blend((*bounds.second).second, blendf); + + reset(pstartsetting, pendsetting, LLEnvironment::TRANSITION_ALTITUDE); + } + + protected: + S32 selectTrackNumber(S32 trackno) + { + if (trackno == 0) + { // We are dealing with the water track. There is only ever one. + return trackno; + } + + for (S32 test = trackno; test != 0; --test) + { // Find the track below the requested one with data. + LLSettingsDay::CycleTrack_t &track = mDay->getCycleTrack(test); + + if (!track.empty()) + return test; + } + + return 1; + } + + LLSettingsDay::TrackBound_t getBoundingEntries(LLSettingsBase::Seconds time) + { + LLSettingsDay::CycleTrack_t &wtrack = mDay->getCycleTrack(mTrackNo); + LLSettingsBase::TrackPosition position = convert_time_to_position(time, mCycleLength); + LLSettingsDay::TrackBound_t bounds = get_bounding_entries(wtrack, position); + return bounds; + } + + void initializeTarget(LLSettingsBase::Seconds time) + { + LLSettingsBase::BlendFactor blendf(convert_time_to_blend_factor(time, mCycleLength, mDay->getCycleTrack(mTrackNo))); + + blendf = llclamp(blendf, 0.0, 0.999); + setTimeSpent(LLSettingsBase::Seconds(blendf * mBlendSpan)); + + setBlendFactor(blendf); + } + + LLSettingsBase::Seconds getAdjustedNow() const + { + LLSettingsBase::Seconds now(LLDate::now().secondsSinceEpoch()); + + return (now + mCycleOffset); + } + + LLSettingsBase::Seconds getSpanTime(const LLSettingsDay::TrackBound_t &bounds) const + { + LLSettingsBase::Seconds span = mCycleLength * get_wrapping_distance((*bounds.first).first, (*bounds.second).first); + if (span < MINIMUM_SPANLENGTH) // for very short spans set a minimum length. + span = MINIMUM_SPANLENGTH; + return span; + } + + private: + LLSettingsDay::ptr_t mDay; + S32 mTrackNo; + LLSettingsBase::Seconds mCycleLength; + LLSettingsBase::Seconds mCycleOffset; + + void onFinishedSpan() + { + LLSettingsBase::Seconds adjusted_now = getAdjustedNow(); + LLSettingsDay::TrackBound_t next = getBoundingEntries(adjusted_now); + LLSettingsBase::Seconds nextspan = getSpanTime(next); + + reset((*next.first).second, (*next.second).second, nextspan); + + // Recalculate (reinitialize) position. Because: + // - 'delta' from applyTimeDelta accumulates errors (probably should be fixed/changed to absolute time) + // - freezes and lag can result in reset being called too late, so we need to add missed time + // - occasional time corrections can happen + // - some transition switches can happen outside applyTimeDelta thus causing 'desync' from 'delta' (can be fixed by getting rid of delta) + initializeTarget(adjusted_now); + } + }; + + class LLEnvironmentPushDispatchHandler : public LLDispatchHandler + { + public: + virtual bool operator()(const LLDispatcher *, const std::string& key, const LLUUID& invoice, const sparam_t& strings) override + { + LLSD message; + sparam_t::const_iterator it = strings.begin(); + + if (it != strings.end()) + { + const std::string& llsdRaw = *it++; + std::istringstream llsdData(llsdRaw); + if (!LLSDSerialize::deserialize(message, llsdData, llsdRaw.length())) + { + LL_WARNS() << "LLEnvironmentPushDispatchHandler: Attempted to read parameter data into LLSD but failed:" << llsdRaw << LL_ENDL; + } + } + + message[KEY_EXPERIENCEID] = invoice; + // Object Name + if (it != strings.end()) + { + message[KEY_OBJECTNAME] = *it++; + } + + // parcel Name + if (it != strings.end()) + { + message[KEY_PARCELNAME] = *it++; + } + message[KEY_COUNT] = 1; + + LLEnvironment::instance().handleEnvironmentPush(message); + return true; + } + }; + + LLEnvironmentPushDispatchHandler environment_push_dispatch_handler; + + template + class LLSettingsInjected : public SETTINGT + { + public: + typedef std::shared_ptr > ptr_t; + + LLSettingsInjected(typename SETTINGT::ptr_t source) : + SETTINGT(), + mSource(source), + mLastSourceHash(0), + mLastHash(0) + {} + + virtual ~LLSettingsInjected() {}; + + typename SETTINGT::ptr_t getSource() const { return this->mSource; } + void setSource(const typename SETTINGT::ptr_t &source) + { + if (source.get() == this) // do not set a source to itself. + return; + this->mSource = source; + this->setDirtyFlag(true); + this->mLastSourceHash = 0; + } + + virtual bool isDirty() const override { return SETTINGT::isDirty() || (this->mSource->isDirty()); } + virtual bool isVeryDirty() const override { return SETTINGT::isVeryDirty() || (this->mSource->isVeryDirty()); } + + void injectSetting(const std::string keyname, LLSD value, LLUUID experience_id, F32Seconds transition) + { + if (transition > 0.1) + { + typename Injection::ptr_t injection = std::make_shared(transition, keyname, value, true, experience_id); + + mInjections.push_back(injection); + std::stable_sort(mInjections.begin(), mInjections.end(), [](const typename Injection::ptr_t &a, const typename Injection::ptr_t &b) { return a->mTimeRemaining < b->mTimeRemaining; }); + } + else + { + mOverrideValues[keyname] = value; + mOverrideExps[keyname] = experience_id; + this->setDirtyFlag(true); + } + } + + void removeInjection(const std::string keyname, LLUUID experience, LLSettingsBase::Seconds transition) + { + injections_t injections_buf; + for (auto it = mInjections.begin(); it != mInjections.end(); it++) + { + if ((keyname.empty() || ((*it)->mKeyName == keyname)) && + (experience.isNull() || (experience == (*it)->mExperience))) + { + if (transition != LLEnvironment::TRANSITION_INSTANT) + { + typename Injection::ptr_t injection = std::make_shared(transition, keyname, (*it)->mLastValue, false, LLUUID::null); + injections_buf.push_front(injection); + } + } + else + { + injections_buf.push_front(*it); + } + } + mInjections.clear(); + mInjections = injections_buf; + + for (auto itexp = mOverrideExps.begin(); itexp != mOverrideExps.end();) + { + if (experience.isNull() || ((*itexp).second == experience)) + { + if (transition != LLEnvironment::TRANSITION_INSTANT) + { + typename Injection::ptr_t injection = std::make_shared(transition, (*itexp).first, mOverrideValues[(*itexp).first], false, LLUUID::null); + mInjections.push_front(injection); + } + mOverrideValues.erase((*itexp).first); + mOverrideExps.erase(itexp++); + } + else + ++itexp; + } + std::stable_sort(mInjections.begin(), mInjections.end(), [](const typename Injection::ptr_t &a, const typename Injection::ptr_t &b) { return a->mTimeRemaining < b->mTimeRemaining; }); + } + + void removeInjections(LLUUID experience_id, LLSettingsBase::Seconds transition) + { + removeInjection(std::string(), experience_id, transition); + } + + void injectExperienceValues(LLSD values, LLUUID experience_id, typename LLSettingsBase::Seconds transition) + { + for (auto it = values.beginMap(); it != values.endMap(); ++it) + { + injectSetting((*it).first, (*it).second, experience_id, transition); + } + this->setDirtyFlag(true); + } + + void applyInjections(LLSettingsBase::Seconds delta) + { + this->mSettings = this->mSource->getSettings(); + + for (auto ito = mOverrideValues.beginMap(); ito != mOverrideValues.endMap(); ++ito) + { + this->mSettings[(*ito).first] = (*ito).second; + } + + const LLSettingsBase::stringset_t &slerps = this->getSlerpKeys(); + const LLSettingsBase::stringset_t &skips = this->getSkipInterpolateKeys(); + const LLSettingsBase::stringset_t &specials = this->getSpecialKeys(); + + typename injections_t::iterator it; + for (it = mInjections.begin(); it != mInjections.end(); ++it) + { + std::string key_name = (*it)->mKeyName; + + LLSD value = this->mSettings[key_name]; + LLSD target = (*it)->mValue; + + if ((*it)->mFirstTime) + (*it)->mFirstTime = false; + else + (*it)->mTimeRemaining -= delta; + + typename LLSettingsBase::BlendFactor mix = 1.0f - ((*it)->mTimeRemaining.value() / (*it)->mTransition.value()); + + if (mix >= 1.0) + { + if ((*it)->mBlendIn) + { + mOverrideValues[key_name] = target; + mOverrideExps[key_name] = (*it)->mExperience; + this->mSettings[key_name] = target; + } + else + { + this->mSettings.erase(key_name); + } + } + else if (specials.find(key_name) != specials.end()) + { + updateSpecial(*it, mix); + } + else if (skips.find(key_name) == skips.end()) + { + if (!(*it)->mBlendIn) + mix = 1.0 - mix; + (*it)->mLastValue = this->interpolateSDValue(key_name, value, target, this->getParameterMap(), mix, slerps); + this->mSettings[key_name] = (*it)->mLastValue; + } + } + + size_t hash = this->getHash(); + + if (hash != mLastHash) + { + this->setDirtyFlag(true); + mLastHash = hash; + } + + it = mInjections.begin(); + it = std::find_if(mInjections.begin(), mInjections.end(), [](const typename Injection::ptr_t &a) { return a->mTimeRemaining > 0.0f; }); + + if (it != mInjections.begin()) + { + mInjections.erase(mInjections.begin(), mInjections.end()); + } + + } + + bool hasInjections() const + { + return (!mInjections.empty() || (mOverrideValues.size() > 0)); + } + + protected: + struct Injection + { + Injection(typename LLSettingsBase::Seconds transition, const std::string &keyname, LLSD value, bool blendin, LLUUID experince, S32 index = -1) : + mTransition(transition), + mTimeRemaining(transition), + mKeyName(keyname), + mValue(value), + mExperience(experince), + mIndex(index), + mBlendIn(blendin), + mFirstTime(true) + {} + + typename LLSettingsBase::Seconds mTransition; + typename LLSettingsBase::Seconds mTimeRemaining; + std::string mKeyName; + LLSD mValue; + LLSD mLastValue; + LLUUID mExperience; + S32 mIndex; + bool mBlendIn; + bool mFirstTime; + + typedef std::shared_ptr ptr_t; + }; + + + virtual void updateSettings() override + { + static LLFrameTimer timer; + + if (!this->mSource) + return; + + // clears the dirty flag on this object. Need to prevent triggering + // more calls into this updateSettings + LLSettingsBase::updateSettings(); + + resetSpecial(); + + if (this->mSource->isDirty()) + { + this->mSource->updateSettings(); + } + + typename LLSettingsBase::Seconds delta(timer.getElapsedTimeAndResetF32()); + + + SETTINGT::updateSettings(); + + if (!mInjections.empty()) + this->setDirtyFlag(true); + } + + LLSettingsBase::stringset_t getSpecialKeys() const; + void resetSpecial(); + void updateSpecial(const typename Injection::ptr_t &injection, typename LLSettingsBase::BlendFactor mix); + + private: + typedef std::map key_to_expid_t; + typedef std::deque injections_t; + + size_t mLastSourceHash; + size_t mLastHash; + typename SETTINGT::ptr_t mSource; + injections_t mInjections; + LLSD mOverrideValues; + key_to_expid_t mOverrideExps; + }; + + template<> + LLSettingsBase::stringset_t LLSettingsInjected::getSpecialKeys() const + { + static LLSettingsBase::stringset_t specialSet; + + if (specialSet.empty()) + { + specialSet.insert(SETTING_BLOOM_TEXTUREID); + specialSet.insert(SETTING_RAINBOW_TEXTUREID); + specialSet.insert(SETTING_HALO_TEXTUREID); + specialSet.insert(SETTING_CLOUD_TEXTUREID); + specialSet.insert(SETTING_MOON_TEXTUREID); + specialSet.insert(SETTING_SUN_TEXTUREID); + specialSet.insert(SETTING_CLOUD_SHADOW); // due to being part of skips + } + return specialSet; + } + + template<> + LLSettingsBase::stringset_t LLSettingsInjected::getSpecialKeys() const + { + static stringset_t specialSet; + + if (specialSet.empty()) + { + specialSet.insert(SETTING_TRANSPARENT_TEXTURE); + specialSet.insert(SETTING_NORMAL_MAP); + } + return specialSet; + } + + template<> + void LLSettingsInjected::resetSpecial() + { + mNextSunTextureId.setNull(); + mNextMoonTextureId.setNull(); + mNextCloudTextureId.setNull(); + mNextBloomTextureId.setNull(); + mNextRainbowTextureId.setNull(); + mNextHaloTextureId.setNull(); + setBlendFactor(0.0f); + } + + template<> + void LLSettingsInjected::resetSpecial() + { + mNextNormalMapID.setNull(); + mNextTransparentTextureID.setNull(); + setBlendFactor(0.0f); + } + + template<> + void LLSettingsInjected::updateSpecial(const typename LLSettingsInjected::Injection::ptr_t &injection, typename LLSettingsBase::BlendFactor mix) + { + bool is_texture = true; + if (injection->mKeyName == SETTING_SUN_TEXTUREID) + { + mNextSunTextureId = injection->mValue.asUUID(); + } + else if (injection->mKeyName == SETTING_MOON_TEXTUREID) + { + mNextMoonTextureId = injection->mValue.asUUID(); + } + else if (injection->mKeyName == SETTING_CLOUD_TEXTUREID) + { + mNextCloudTextureId = injection->mValue.asUUID(); + } + else if (injection->mKeyName == SETTING_BLOOM_TEXTUREID) + { + mNextBloomTextureId = injection->mValue.asUUID(); + } + else if (injection->mKeyName == SETTING_RAINBOW_TEXTUREID) + { + mNextRainbowTextureId = injection->mValue.asUUID(); + } + else if (injection->mKeyName == SETTING_HALO_TEXTUREID) + { + mNextHaloTextureId = injection->mValue.asUUID(); + } + else if (injection->mKeyName == LLSettingsSky::SETTING_CLOUD_SHADOW) + { + // Special case due to being texture dependent and part of skips + is_texture = false; + if (!injection->mBlendIn) + mix = 1.0 - mix; + stringset_t dummy; + F64 value = this->mSettings[injection->mKeyName].asReal(); + if (this->getCloudNoiseTextureId().isNull()) + { + value = 0; // there was no texture so start from zero coverage + } + // Ideally we need to check for texture in injection, but + // in this case user is setting value explicitly, potentially + // with different transitions, don't ignore it + F64 result = lerp(value, injection->mValue.asReal(), mix); + injection->mLastValue = LLSD::Real(result); + this->mSettings[injection->mKeyName] = injection->mLastValue; + } + + // Unfortunately I don't have a per texture blend factor. We'll just pick the one that is furthest along. + if (is_texture && getBlendFactor() < mix) + { + setBlendFactor(mix); + } + } + + template<> + void LLSettingsInjected::updateSpecial(const typename LLSettingsInjected::Injection::ptr_t &injection, typename LLSettingsBase::BlendFactor mix) + { + if (injection->mKeyName == SETTING_NORMAL_MAP) + { + mNextNormalMapID = injection->mValue.asUUID(); + } + else if (injection->mKeyName == SETTING_TRANSPARENT_TEXTURE) + { + mNextTransparentTextureID = injection->mValue.asUUID(); + } + + // Unfortunately I don't have a per texture blend factor. We'll just pick the one that is furthest along. + if (getBlendFactor() < mix) + { + setBlendFactor(mix); + } + } + + typedef LLSettingsInjected LLSettingsInjectedSky; + typedef LLSettingsInjected LLSettingsInjectedWater; + + //===================================================================== + class DayInjection : public LLEnvironment::DayInstance + { + friend class InjectedTransition; + + public: + typedef std::shared_ptr ptr_t; + typedef std::weak_ptr wptr_t; + + DayInjection(LLEnvironment::EnvSelection_t env); + virtual ~DayInjection(); + + virtual bool applyTimeDelta(const LLSettingsBase::Seconds& delta) override; + + void setInjectedDay(const LLSettingsDay::ptr_t &pday, LLUUID experience_id, LLSettingsBase::Seconds transition); + void setInjectedSky(const LLSettingsSky::ptr_t &psky, LLUUID experience_id, LLSettingsBase::Seconds transition); + void setInjectedWater(const LLSettingsWater::ptr_t &pwater, LLUUID experience_id, LLSettingsBase::Seconds transition); + + void injectSkySettings(LLSD settings, LLUUID experience_id, LLSettingsBase::Seconds transition); + void injectWaterSettings(LLSD settings, LLUUID experience_id, LLSettingsBase::Seconds transition); + + void clearInjections(LLUUID experience_id, LLSettingsBase::Seconds transition_time); + + virtual void animate() override; + + LLEnvironment::DayInstance::ptr_t getBaseDayInstance() const { return mBaseDayInstance; } + void setBaseDayInstance(const LLEnvironment::DayInstance::ptr_t &baseday); + + S32 countExperiencesActive() const { return mActiveExperiences.size(); } + + bool isOverriddenSky() const { return !mSkyExperience.isNull(); } + bool isOverriddenWater() const { return !mWaterExperience.isNull(); } + + bool hasInjections() const; + + void testExperiencesOnParcel(S32 parcel_id); + private: + static void testExperiencesOnParcelCoro(wptr_t that, S32 parcel_id); + + + void animateSkyChange(LLSettingsSky::ptr_t psky, LLSettingsBase::Seconds transition); + void animateWaterChange(LLSettingsWater::ptr_t pwater, LLSettingsBase::Seconds transition); + + void onEnvironmentChanged(LLEnvironment::EnvSelection_t env); + void onParcelChange(); + + void checkExperience(); + + + LLEnvironment::DayInstance::ptr_t mBaseDayInstance; + + LLSettingsInjectedSky::ptr_t mInjectedSky; + LLSettingsInjectedWater::ptr_t mInjectedWater; + std::set mActiveExperiences; + LLUUID mDayExperience; + LLUUID mSkyExperience; + LLUUID mWaterExperience; + LLEnvironment::connection_t mEnvChangeConnection; + boost::signals2::connection mParcelChangeConnection; + }; + + class InjectedTransition : public LLEnvironment::DayTransition + { + public: + InjectedTransition(const DayInjection::ptr_t &injection, const LLSettingsSky::ptr_t &skystart, const LLSettingsWater::ptr_t &waterstart, DayInstance::ptr_t &end, LLSettingsDay::Seconds time): + LLEnvironment::DayTransition(skystart, waterstart, end, time), + mInjection(injection) + { } + virtual ~InjectedTransition() { }; + + virtual void animate() override; + + protected: + DayInjection::ptr_t mInjection; + }; + +} + +//========================================================================= +const F64Seconds LLEnvironment::TRANSITION_INSTANT(0.0f); +const F64Seconds LLEnvironment::TRANSITION_FAST(1.0f); +const F64Seconds LLEnvironment::TRANSITION_DEFAULT(5.0f); +const F64Seconds LLEnvironment::TRANSITION_SLOW(10.0f); +const F64Seconds LLEnvironment::TRANSITION_ALTITUDE(5.0f); + +const LLUUID LLEnvironment::KNOWN_SKY_SUNRISE("01e41537-ff51-2f1f-8ef7-17e4df760bfb"); +const LLUUID LLEnvironment::KNOWN_SKY_MIDDAY("c46226b4-0e43-5a56-9708-d27ca1df3292"); +const LLUUID LLEnvironment::KNOWN_SKY_LEGACY_MIDDAY("cef49723-0292-af49-9b14-9598a616b8a3"); +const LLUUID LLEnvironment::KNOWN_SKY_SUNSET("084e26cd-a900-28e8-08d0-64a9de5c15e2"); +const LLUUID LLEnvironment::KNOWN_SKY_MIDNIGHT("8a01b97a-cb20-c1ea-ac63-f7ea84ad0090"); + +const S32 LLEnvironment::NO_TRACK(-1); +const S32 LLEnvironment::NO_VERSION(-3); // For viewer sided change, like ENV_LOCAL. -3 since -1 and -2 are taken by parcel initial server/viewer version +const S32 LLEnvironment::VERSION_CLEANUP(-4); // for cleanups + +const F32 LLEnvironment::SUN_DELTA_YAW(F_PI); // 180deg + + +const U32 LLEnvironment::DayInstance::NO_ANIMATE_SKY(0x01); +const U32 LLEnvironment::DayInstance::NO_ANIMATE_WATER(0x02); + +std::string env_selection_to_string(LLEnvironment::EnvSelection_t sel) +{ +#define RTNENUM(E) case LLEnvironment::E: return #E + switch (sel){ + RTNENUM(ENV_EDIT); + RTNENUM(ENV_LOCAL); + RTNENUM(ENV_PUSH); + RTNENUM(ENV_PARCEL); + RTNENUM(ENV_REGION); + RTNENUM(ENV_DEFAULT); + RTNENUM(ENV_END); + RTNENUM(ENV_CURRENT); + RTNENUM(ENV_NONE); + default: + return llformat("Unknown(%d)", sel); + } +#undef RTNENUM +} + +//------------------------------------------------------------------------- +LLEnvironment::LLEnvironment(): + mCloudScrollDelta(), + mCloudScrollPaused(false), + mSelectedSky(), + mSelectedWater(), + mSelectedDay(), + mSelectedEnvironment(LLEnvironment::ENV_LOCAL), + mCurrentTrack(1), + mEditorCounter(0), + mShowSunBeacon(false), + mShowMoonBeacon(false) +{ +} + +void LLEnvironment::initSingleton() +{ + LLSettingsSky::ptr_t p_default_sky = LLSettingsVOSky::buildDefaultSky(); + LLSettingsWater::ptr_t p_default_water = LLSettingsVOWater::buildDefaultWater(); + + mCurrentEnvironment = std::make_shared(ENV_DEFAULT); + mCurrentEnvironment->setSky(p_default_sky); + mCurrentEnvironment->setWater(p_default_water); + + mEnvironments[ENV_DEFAULT] = mCurrentEnvironment; + + requestRegion(); + + if (!mParcelCallbackConnection.connected()) + { + mParcelCallbackConnection = gAgent.addParcelChangedCallback([this]() { onParcelChange(); }); + + //TODO: This frequently results in one more request than we need. It isn't breaking, but should be nicer. + // We need to know new env version to fix this, without it we can only do full re-request + // Happens: on updates, on opening LLFloaterRegionInfo, on region crossing if info floater is open + mRegionUpdateCallbackConnection = LLRegionInfoModel::instance().setUpdateCallback([this]() { requestRegion(); }); + mRegionChangeCallbackConnection = gAgent.addRegionChangedCallback([this]() { onRegionChange(); }); + + mPositionCallbackConnection = gAgent.whenPositionChanged([this](const LLVector3 &localpos, const LLVector3d &) { onAgentPositionHasChanged(localpos); }); + } + + if (!gGenericDispatcher.isHandlerPresent(MESSAGE_PUSHENVIRONMENT)) + { + gGenericDispatcher.addHandler(MESSAGE_PUSHENVIRONMENT, &environment_push_dispatch_handler); + } + + gSavedSettings.getControl("RenderSkyAutoAdjustProbeAmbiance")->getSignal()->connect( + [](LLControlVariable*, const LLSD& new_val, const LLSD& old_val) + { + LLSettingsSky::sAutoAdjustProbeAmbiance = new_val.asReal(); + } + ); + LLSettingsSky::sAutoAdjustProbeAmbiance = gSavedSettings.getF32("RenderSkyAutoAdjustProbeAmbiance"); + + LLEventPumps::instance().obtain(PUMP_EXPERIENCE).stopListening(LISTENER_NAME); + LLEventPumps::instance().obtain(PUMP_EXPERIENCE).listen(LISTENER_NAME, [this](LLSD message) { listenExperiencePump(message); return false; }); +} + +void LLEnvironment::cleanupSingleton() +{ + if (mParcelCallbackConnection.connected()) + { + mParcelCallbackConnection.disconnect(); + mRegionUpdateCallbackConnection.disconnect(); + mRegionChangeCallbackConnection.disconnect(); + mPositionCallbackConnection.disconnect(); + } + LLEventPumps::instance().obtain(PUMP_EXPERIENCE).stopListening(LISTENER_NAME); +} + +LLEnvironment::~LLEnvironment() +{ + cleanupSingleton(); +} + +bool LLEnvironment::canEdit() const +{ + return true; +} + +LLSettingsSky::ptr_t LLEnvironment::getCurrentSky() const +{ + LLSettingsSky::ptr_t psky = mCurrentEnvironment->getSky(); + + if (!psky && mCurrentEnvironment->getEnvironmentSelection() >= ENV_EDIT) + { + for (int idx = 0; idx < ENV_END; ++idx) + { + if (mEnvironments[idx]->getSky()) + { + psky = mEnvironments[idx]->getSky(); + break; + } + } + } + return psky; +} + +LLSettingsWater::ptr_t LLEnvironment::getCurrentWater() const +{ + LLSettingsWater::ptr_t pwater = mCurrentEnvironment->getWater(); + + if (!pwater && mCurrentEnvironment->getEnvironmentSelection() >= ENV_EDIT) + { + for (int idx = 0; idx < ENV_END; ++idx) + { + if (mEnvironments[idx]->getWater()) + { + pwater = mEnvironments[idx]->getWater(); + break; + } + } + } + return pwater; +} + +void LayerConfigToDensityLayer(const LLSD& layerConfig, DensityLayer& layerOut) +{ + layerOut.constant_term = layerConfig[LLSettingsSky::SETTING_DENSITY_PROFILE_CONSTANT_TERM].asReal(); + layerOut.exp_scale = layerConfig[LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_SCALE_FACTOR].asReal(); + layerOut.exp_term = layerConfig[LLSettingsSky::SETTING_DENSITY_PROFILE_EXP_TERM].asReal(); + layerOut.linear_term = layerConfig[LLSettingsSky::SETTING_DENSITY_PROFILE_LINEAR_TERM].asReal(); + layerOut.width = layerConfig[LLSettingsSky::SETTING_DENSITY_PROFILE_WIDTH].asReal(); +} + +void LLEnvironment::getAtmosphericModelSettings(AtmosphericModelSettings& settingsOut, const LLSettingsSky::ptr_t &psky) +{ + settingsOut.m_skyBottomRadius = psky->getSkyBottomRadius(); + settingsOut.m_skyTopRadius = psky->getSkyTopRadius(); + settingsOut.m_sunArcRadians = psky->getSunArcRadians(); + settingsOut.m_mieAnisotropy = psky->getMieAnisotropy(); + + LLSD rayleigh = psky->getRayleighConfigs(); + settingsOut.m_rayleighProfile.clear(); + for (LLSD::array_iterator itf = rayleigh.beginArray(); itf != rayleigh.endArray(); ++itf) + { + DensityLayer layer; + LLSD& layerConfig = (*itf); + LayerConfigToDensityLayer(layerConfig, layer); + settingsOut.m_rayleighProfile.push_back(layer); + } + + LLSD mie = psky->getMieConfigs(); + settingsOut.m_mieProfile.clear(); + for (LLSD::array_iterator itf = mie.beginArray(); itf != mie.endArray(); ++itf) + { + DensityLayer layer; + LLSD& layerConfig = (*itf); + LayerConfigToDensityLayer(layerConfig, layer); + settingsOut.m_mieProfile.push_back(layer); + } + settingsOut.m_mieAnisotropy = psky->getMieAnisotropy(); + + LLSD absorption = psky->getAbsorptionConfigs(); + settingsOut.m_absorptionProfile.clear(); + for (LLSD::array_iterator itf = absorption.beginArray(); itf != absorption.endArray(); ++itf) + { + DensityLayer layer; + LLSD& layerConfig = (*itf); + LayerConfigToDensityLayer(layerConfig, layer); + settingsOut.m_absorptionProfile.push_back(layer); + } +} + +bool LLEnvironment::canAgentUpdateParcelEnvironment() const +{ + LLParcel *parcel(LLViewerParcelMgr::instance().getAgentOrSelectedParcel()); + + return canAgentUpdateParcelEnvironment(parcel); +} + + +bool LLEnvironment::canAgentUpdateParcelEnvironment(LLParcel *parcel) const +{ + if (!parcel) + return false; + + if (!LLEnvironment::instance().isExtendedEnvironmentEnabled()) + return false; + + if (gAgent.isGodlike()) + return true; + + if (!parcel->getRegionAllowEnvironmentOverride()) + return false; + + return LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_ALLOW_ENVIRONMENT); +} + +bool LLEnvironment::canAgentUpdateRegionEnvironment() const +{ + if (gAgent.isGodlike()) + return true; + + return gAgent.canManageEstate(); +} + +bool LLEnvironment::isExtendedEnvironmentEnabled() const +{ + return !gAgent.getRegionCapability("ExtEnvironment").empty(); +} + +bool LLEnvironment::isInventoryEnabled() const +{ + return (!gAgent.getRegionCapability("UpdateSettingsAgentInventory").empty() && + !gAgent.getRegionCapability("UpdateSettingsTaskInventory").empty()); +} + +void LLEnvironment::onRegionChange() +{ +// if (gAgent.getRegionCapability("ExperienceQuery").empty()) +// { +// // for now environmental experiences do not survive region crossings + clearExperienceEnvironment(LLUUID::null, TRANSITION_DEFAULT); +// } + + LLViewerRegion* cur_region = gAgent.getRegion(); + if (!cur_region) + { + return; + } + if (!cur_region->capabilitiesReceived()) + { + cur_region->setCapabilitiesReceivedCallback([](const LLUUID ®ion_id, LLViewerRegion* regionp) { LLEnvironment::instance().requestRegion(); }); + return; + } + requestRegion(); +} + +void LLEnvironment::onParcelChange() +{ + S32 parcel_id(INVALID_PARCEL_ID); + LLParcel* parcel = LLViewerParcelMgr::instance().getAgentParcel(); + + if (parcel) + { + parcel_id = parcel->getLocalID(); + } + + requestParcel(parcel_id); +} + +//------------------------------------------------------------------------- +F32 LLEnvironment::getCamHeight() const +{ + return (mCurrentEnvironment->getSky()->getDomeOffset() * mCurrentEnvironment->getSky()->getDomeRadius()); +} + +F32 LLEnvironment::getWaterHeight() const +{ + LLViewerRegion* cur_region = gAgent.getRegion(); + return cur_region ? cur_region->getWaterHeight() : DEFAULT_WATER_HEIGHT; +} + +bool LLEnvironment::getIsSunUp() const +{ + if (!mCurrentEnvironment || !mCurrentEnvironment->getSky()) + return false; + return mCurrentEnvironment->getSky()->getIsSunUp(); +} + +bool LLEnvironment::getIsMoonUp() const +{ + if (!mCurrentEnvironment || !mCurrentEnvironment->getSky()) + return false; + return mCurrentEnvironment->getSky()->getIsMoonUp(); +} + +//------------------------------------------------------------------------- +void LLEnvironment::setSelectedEnvironment(LLEnvironment::EnvSelection_t env, LLSettingsBase::Seconds transition, bool forced) +{ + mSelectedEnvironment = env; + updateEnvironment(transition, forced); + LL_DEBUGS("ENVIRONMENT") << "Setting environment " << env_selection_to_string(env) << " with transition: " << transition << LL_ENDL; +} + +bool LLEnvironment::hasEnvironment(LLEnvironment::EnvSelection_t env) +{ + if ((env < ENV_EDIT) || (env >= ENV_DEFAULT) || (!mEnvironments[env])) + { + return false; + } + + return true; +} + +LLEnvironment::DayInstance::ptr_t LLEnvironment::getEnvironmentInstance(LLEnvironment::EnvSelection_t env, bool create /*= false*/) +{ + DayInstance::ptr_t environment = mEnvironments[env]; + if (create) + { + if (environment) + environment = environment->clone(); + else + { + if (env == ENV_PUSH) + environment = std::make_shared(env); + else + environment = std::make_shared(env); + } + mEnvironments[env] = environment; + } + + return environment; +} + + +void LLEnvironment::setEnvironment(LLEnvironment::EnvSelection_t env, const LLSettingsDay::ptr_t &pday, LLSettingsDay::Seconds daylength, LLSettingsDay::Seconds dayoffset, S32 env_version) +{ + if ((env < ENV_EDIT) || (env >= ENV_DEFAULT)) + { + LL_WARNS("ENVIRONMENT") << "Attempt to change invalid environment selection (" << env_selection_to_string(env) << ")." << LL_ENDL; + return; + } + + logEnvironment(env, pday, env_version); + + DayInstance::ptr_t environment = getEnvironmentInstance(env, true); + + environment->clear(); + environment->setDay(pday, daylength, dayoffset); + environment->setSkyTrack(mCurrentTrack); + environment->animate(); + + if (!mSignalEnvChanged.empty()) + mSignalEnvChanged(env, env_version); +} + +void LLEnvironment::setCurrentEnvironmentSelection(LLEnvironment::EnvSelection_t env) +{ + mCurrentEnvironment->setEnvironmentSelection(env); +} + +void LLEnvironment::setEnvironment(LLEnvironment::EnvSelection_t env, LLEnvironment::fixedEnvironment_t fixed, S32 env_version) +{ + if ((env < ENV_EDIT) || (env >= ENV_DEFAULT)) + { + LL_WARNS("ENVIRONMENT") << "Attempt to change invalid environment selection (" << env_selection_to_string(env) << ")." << LL_ENDL; + return; + } + + bool reset_probes = false; + + DayInstance::ptr_t environment = getEnvironmentInstance(env, true); + + if (fixed.first) + { + logEnvironment(env, fixed.first, env_version); + reset_probes = environment->setSky(fixed.first); + environment->setFlags(DayInstance::NO_ANIMATE_SKY); + } + else if (!environment->getSky()) + { + if (mCurrentEnvironment->getEnvironmentSelection() != ENV_NONE) + { + // Note: This looks suspicious. Shouldn't we assign whole day if mCurrentEnvironment has whole day? + // and then add water/sky on top + // This looks like it will result in sky using single keyframe instead of whole day if day is present + // when setting static water without static sky + reset_probes = environment->setSky(mCurrentEnvironment->getSky()); + environment->setFlags(DayInstance::NO_ANIMATE_SKY); + } + else + { + // Environment is not properly initialized yet, but we should have environment by this point + DayInstance::ptr_t substitute = getEnvironmentInstance(ENV_PARCEL, true); + if (!substitute || !substitute->getSky()) + { + substitute = getEnvironmentInstance(ENV_REGION, true); + } + if (!substitute || !substitute->getSky()) + { + substitute = getEnvironmentInstance(ENV_DEFAULT, true); + } + + if (substitute && substitute->getSky()) + { + reset_probes = environment->setSky(substitute->getSky()); + environment->setFlags(DayInstance::NO_ANIMATE_SKY); + } + else + { + LL_WARNS("ENVIRONMENT") << "Failed to assign substitute water/sky, environment is not properly initialized" << LL_ENDL; + } + } + } + + if (fixed.second) + { + logEnvironment(env, fixed.second, env_version); + environment->setWater(fixed.second); + environment->setFlags(DayInstance::NO_ANIMATE_WATER); + } + else if (!environment->getWater()) + { + if (mCurrentEnvironment->getEnvironmentSelection() != ENV_NONE) + { + // Note: This looks suspicious. Shouldn't we assign whole day if mCurrentEnvironment has whole day? + // and then add water/sky on top + // This looks like it will result in water using single keyframe instead of whole day if day is present + // when setting static sky without static water + environment->setWater(mCurrentEnvironment->getWater()); + environment->setFlags(DayInstance::NO_ANIMATE_WATER); + } + else + { + // Environment is not properly initialized yet, but we should have environment by this point + DayInstance::ptr_t substitute = getEnvironmentInstance(ENV_PARCEL, true); + if (!substitute || !substitute->getWater()) + { + substitute = getEnvironmentInstance(ENV_REGION, true); + } + if (!substitute || !substitute->getWater()) + { + substitute = getEnvironmentInstance(ENV_DEFAULT, true); + } + + if (substitute && substitute->getWater()) + { + environment->setWater(substitute->getWater()); + environment->setFlags(DayInstance::NO_ANIMATE_WATER); + } + else + { + LL_WARNS("ENVIRONMENT") << "Failed to assign substitute water/sky, environment is not properly initialized" << LL_ENDL; + } + } + } + + if (reset_probes) + { // the sky changed in a way that merits a reset of reflection probes + gPipeline.mReflectionMapManager.reset(); + } + + if (!mSignalEnvChanged.empty()) + mSignalEnvChanged(env, env_version); +} + +void LLEnvironment::setEnvironment(LLEnvironment::EnvSelection_t env, const LLSettingsBase::ptr_t &settings, S32 env_version) +{ + DayInstance::ptr_t environment = getEnvironmentInstance(env); + + if (env == ENV_DEFAULT) + { + LL_WARNS("ENVIRONMENT") << "Attempt to set default environment. Not allowed." << LL_ENDL; + return; + } + + if (!settings) + { + clearEnvironment(env); + return; + } + + if (settings->getSettingsType() == "daycycle") + { + LLSettingsDay::Seconds daylength(LLSettingsDay::DEFAULT_DAYLENGTH); + LLSettingsDay::Seconds dayoffset(LLSettingsDay::DEFAULT_DAYOFFSET); + if (environment) + { + daylength = environment->getDayLength(); + dayoffset = environment->getDayOffset(); + } + setEnvironment(env, std::static_pointer_cast(settings), daylength, dayoffset); + } + else if (settings->getSettingsType() == "sky") + { + fixedEnvironment_t fixedenv(std::static_pointer_cast(settings), LLSettingsWater::ptr_t()); + setEnvironment(env, fixedenv); + } + else if (settings->getSettingsType() == "water") + { + fixedEnvironment_t fixedenv(LLSettingsSky::ptr_t(), std::static_pointer_cast(settings)); + setEnvironment(env, fixedenv); + } +} + +void LLEnvironment::setEnvironment(EnvSelection_t env, const LLUUID &assetId, S32 env_version) +{ + setEnvironment(env, assetId, TRANSITION_DEFAULT, env_version); +} + +void LLEnvironment::setEnvironment(EnvSelection_t env, + const LLUUID &assetId, + LLSettingsBase::Seconds transition, + S32 env_version) +{ + LLSettingsVOBase::getSettingsAsset(assetId, + [this, env, env_version, transition](LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, LLExtStat) + { + onSetEnvAssetLoaded(env, asset_id, settings, transition, status, env_version); + }); +} + +void LLEnvironment::onSetEnvAssetLoaded(EnvSelection_t env, + LLUUID asset_id, + LLSettingsBase::ptr_t settings, + LLSettingsBase::Seconds transition, + S32 status, + S32 env_version) +{ + if (!settings || status) + { + LLSD args; + args["NAME"] = asset_id.asString(); + LLNotificationsUtil::add("FailedToFindSettings", args); + LL_DEBUGS("ENVIRONMENT") << "Failed to find settings for " << env_selection_to_string(env) << ", asset_id: " << asset_id << LL_ENDL; + return; + } + LL_DEBUGS("ENVIRONMENT") << "Loaded asset: " << asset_id << LL_ENDL; + + setEnvironment(env, settings); + updateEnvironment(transition); +} + +void LLEnvironment::clearEnvironment(LLEnvironment::EnvSelection_t env) +{ + if ((env < ENV_EDIT) || (env >= ENV_DEFAULT)) + { + LL_WARNS("ENVIRONMENT") << "Attempt to change invalid environment selection." << LL_ENDL; + return; + } + + LL_DEBUGS("ENVIRONMENT") << "Cleaning environment " << env_selection_to_string(env) << LL_ENDL; + + mEnvironments[env].reset(); + + if (!mSignalEnvChanged.empty()) + mSignalEnvChanged(env, VERSION_CLEANUP); +} + +void LLEnvironment::logEnvironment(EnvSelection_t env, const LLSettingsBase::ptr_t &settings, S32 env_version) +{ + LL_DEBUGS("ENVIRONMENT") << "Setting Day environment " << env_selection_to_string(env) << " with version(update type): " << env_version << LL_NEWLINE; + // code between LL_DEBUGS and LL_ENDL won't execute unless log is enabled + if (settings) + { + LLUUID asset_id = settings->getAssetId(); + if (asset_id.notNull()) + { + LL_CONT << "Asset id: " << asset_id << LL_NEWLINE; + } + + LLUUID id = settings->getId(); // Not in use? + if (id.notNull()) + { + LL_CONT << "Settings id: " << id << LL_NEWLINE; + } + + LL_CONT << "Name: " << settings->getName() << LL_NEWLINE + << "Type: " << settings->getSettingsType() << LL_NEWLINE + << "Flags: " << settings->getFlags(); // Not in use? + } + else + { + LL_CONT << "Empty settings!"; + } + LL_CONT << LL_ENDL; +} + +LLSettingsDay::ptr_t LLEnvironment::getEnvironmentDay(LLEnvironment::EnvSelection_t env) +{ + if ((env < ENV_EDIT) || (env > ENV_DEFAULT)) + { + LL_WARNS("ENVIRONMENT") << "Attempt to retrieve invalid environment selection (" << env_selection_to_string(env) << ")." << LL_ENDL; + return LLSettingsDay::ptr_t(); + } + + DayInstance::ptr_t environment = getEnvironmentInstance(env); + + if (environment) + return environment->getDayCycle(); + + return LLSettingsDay::ptr_t(); +} + +LLSettingsDay::Seconds LLEnvironment::getEnvironmentDayLength(EnvSelection_t env) +{ + if ((env < ENV_EDIT) || (env > ENV_DEFAULT)) + { + LL_WARNS("ENVIRONMENT") << "Attempt to retrieve invalid environment selection (" << env_selection_to_string(env) << ")." << LL_ENDL; + return LLSettingsDay::Seconds(0); + } + + DayInstance::ptr_t environment = getEnvironmentInstance(env); + + if (environment) + return environment->getDayLength(); + + return LLSettingsDay::Seconds(0); +} + +LLSettingsDay::Seconds LLEnvironment::getEnvironmentDayOffset(EnvSelection_t env) +{ + if ((env < ENV_EDIT) || (env > ENV_DEFAULT)) + { + LL_WARNS("ENVIRONMENT") << "Attempt to retrieve invalid environment selection (" << env_selection_to_string(env) << ")." << LL_ENDL; + return LLSettingsDay::Seconds(0); + } + + DayInstance::ptr_t environment = getEnvironmentInstance(env); + if (environment) + return environment->getDayOffset(); + + return LLSettingsDay::Seconds(0); +} + + +LLEnvironment::fixedEnvironment_t LLEnvironment::getEnvironmentFixed(LLEnvironment::EnvSelection_t env, bool resolve) +{ + if ((env == ENV_CURRENT) || resolve) + { + fixedEnvironment_t fixed; + for (S32 idx = ((resolve) ? env : mSelectedEnvironment); idx < ENV_END; ++idx) + { + if (fixed.first && fixed.second) + break; + + if (idx == ENV_EDIT) + continue; // skip the edit environment. + + DayInstance::ptr_t environment = getEnvironmentInstance(static_cast(idx)); + if (environment) + { + if (!fixed.first) + fixed.first = environment->getSky(); + if (!fixed.second) + fixed.second = environment->getWater(); + } + } + + if (!fixed.first || !fixed.second) + LL_WARNS("ENVIRONMENT") << "Can not construct complete fixed environment. Missing Sky and/or Water." << LL_ENDL; + + return fixed; + } + + if ((env < ENV_EDIT) || (env > ENV_DEFAULT)) + { + LL_WARNS("ENVIRONMENT") << "Attempt to retrieve invalid environment selection (" << env_selection_to_string(env) << ")." << LL_ENDL; + return fixedEnvironment_t(); + } + + DayInstance::ptr_t environment = getEnvironmentInstance(env); + + if (environment) + return fixedEnvironment_t(environment->getSky(), environment->getWater()); + + return fixedEnvironment_t(); +} + +LLEnvironment::DayInstance::ptr_t LLEnvironment::getSelectedEnvironmentInstance() +{ + for (S32 idx = mSelectedEnvironment; idx < ENV_DEFAULT; ++idx) + { + if (mEnvironments[idx]) + return mEnvironments[idx]; + } + + return mEnvironments[ENV_DEFAULT]; +} + +LLEnvironment::DayInstance::ptr_t LLEnvironment::getSharedEnvironmentInstance() +{ + for (S32 idx = ENV_PARCEL; idx < ENV_DEFAULT; ++idx) + { + if (mEnvironments[idx]) + return mEnvironments[idx]; + } + + return mEnvironments[ENV_DEFAULT]; +} + +void LLEnvironment::updateEnvironment(LLSettingsBase::Seconds transition, bool forced) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; + DayInstance::ptr_t pinstance = getSelectedEnvironmentInstance(); + + if ((mCurrentEnvironment != pinstance) || forced) + { + if (transition != TRANSITION_INSTANT) + { + DayInstance::ptr_t trans = std::make_shared( + mCurrentEnvironment->getSky(), mCurrentEnvironment->getWater(), pinstance, transition); + + trans->animate(); + + mCurrentEnvironment = trans; + } + else + { + mCurrentEnvironment = pinstance; + } + + updateSettingsUniforms(); + } +} + +LLVector4 LLEnvironment::toCFR(const LLVector3 vec) const +{ + LLVector4 vec_cfr(vec.mV[1], vec.mV[0], vec.mV[2], 0.0f); + return vec_cfr; +} + +LLVector4 LLEnvironment::toLightNorm(const LLVector3 vec) const +{ + LLVector4 vec_ogl(vec.mV[1], vec.mV[2], vec.mV[0], 0.0f); + return vec_ogl; +} + +LLVector3 LLEnvironment::getLightDirection() const +{ + LLSettingsSky::ptr_t psky = mCurrentEnvironment->getSky(); + if (!psky) + { + return LLVector3(0, 0, 1); + } + return psky->getLightDirection(); +} + +LLVector3 LLEnvironment::getSunDirection() const +{ + LLSettingsSky::ptr_t psky = mCurrentEnvironment->getSky(); + if (!psky) + { + return LLVector3(0, 0, 1); + } + return psky->getSunDirection(); +} + +LLVector3 LLEnvironment::getMoonDirection() const +{ + LLSettingsSky::ptr_t psky = mCurrentEnvironment->getSky(); + if (!psky) + { + return LLVector3(0, 0, -1); + } + return psky->getMoonDirection(); +} + +LLVector4 LLEnvironment::getLightDirectionCFR() const +{ + LLVector3 light_direction = getLightDirection(); + LLVector4 light_direction_cfr = toCFR(light_direction); + return light_direction_cfr; +} + +LLVector4 LLEnvironment::getSunDirectionCFR() const +{ + LLVector3 light_direction = getSunDirection(); + LLVector4 light_direction_cfr = toCFR(light_direction); + return light_direction_cfr; +} + +LLVector4 LLEnvironment::getMoonDirectionCFR() const +{ + LLVector3 light_direction = getMoonDirection(); + LLVector4 light_direction_cfr = toCFR(light_direction); + return light_direction_cfr; +} + +LLVector4 LLEnvironment::getClampedLightNorm() const +{ + LLVector3 light_direction = getLightDirection(); + if (light_direction.mV[2] < -0.1f) + { + light_direction.mV[2] = -0.1f; + } + return toLightNorm(light_direction); +} + +LLVector4 LLEnvironment::getClampedSunNorm() const +{ + LLVector3 light_direction = getSunDirection(); + if (light_direction.mV[2] < -0.1f) + { + light_direction.mV[2] = -0.1f; + } + return toLightNorm(light_direction); +} + +LLVector4 LLEnvironment::getClampedMoonNorm() const +{ + LLVector3 light_direction = getMoonDirection(); + if (light_direction.mV[2] < -0.1f) + { + light_direction.mV[2] = -0.1f; + } + return toLightNorm(light_direction); +} + +LLVector4 LLEnvironment::getRotatedLightNorm() const +{ + LLVector3 light_direction = getLightDirection(); + light_direction *= LLQuaternion(-mLastCamYaw, LLVector3(0.f, 1.f, 0.f)); + return toLightNorm(light_direction); +} + +extern bool gCubeSnapshot; + +//------------------------------------------------------------------------- +void LLEnvironment::update(const LLViewerCamera * cam) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; //LL_RECORD_BLOCK_TIME(FTM_ENVIRONMENT_UPDATE); + //F32Seconds now(LLDate::now().secondsSinceEpoch()); + if (!gCubeSnapshot) + { + static LLFrameTimer timer; + + F32Seconds delta(timer.getElapsedTimeAndResetF32()); + + { + DayInstance::ptr_t keeper = mCurrentEnvironment; + // make sure the current environment does not go away until applyTimeDelta is done. + mCurrentEnvironment->applyTimeDelta(delta); + + } + // update clouds, sun, and general + updateCloudScroll(); + + // cache this for use in rotating the rotated light vec for shader param updates later... + mLastCamYaw = cam->getYaw() + SUN_DELTA_YAW; + } + + updateSettingsUniforms(); + + // *TODO: potential optimization - this block may only need to be + // executed some of the time. For example for water shaders only. + { + LLViewerShaderMgr::shader_iter shaders_iter, end_shaders; + end_shaders = LLViewerShaderMgr::instance()->endShaders(); + for (shaders_iter = LLViewerShaderMgr::instance()->beginShaders(); shaders_iter != end_shaders; ++shaders_iter) + { + if ((shaders_iter->mProgramObject != 0) + && (gPipeline.canUseWindLightShaders() + || shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER)) + { + shaders_iter->mUniformsDirty = true; + } + } + } +} + +void LLEnvironment::updateCloudScroll() +{ + // This is a function of the environment rather than the sky, since it should + // persist through sky transitions. + static LLTimer s_cloud_timer; + + F64 delta_t = s_cloud_timer.getElapsedTimeAndResetF64(); + + if (mCurrentEnvironment->getSky() && !mCloudScrollPaused) + { + LLVector2 rate = mCurrentEnvironment->getSky()->getCloudScrollRate(); + if (rate.isExactlyZero()) + { + mCloudScrollDelta.setZero(); + } + else + { + LLVector2 cloud_delta = static_cast(delta_t) * (mCurrentEnvironment->getSky()->getCloudScrollRate()) / 100.0; + mCloudScrollDelta += cloud_delta; + } + } + +} + +// static +void LLEnvironment::updateGLVariablesForSettings(LLShaderUniforms* uniforms, const LLSettingsBase::ptr_t &psetting) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + for (int i = 0; i < LLGLSLShader::SG_COUNT; ++i) + { + uniforms[i].clear(); + } + + LLShaderUniforms* shader = &uniforms[LLGLSLShader::SG_ANY]; + //_WARNS("RIDER") << "----------------------------------------------------------------" << LL_ENDL; + LLSettingsBase::parammapping_t params = psetting->getParameterMap(); + for (auto &it: params) + { + LLSD value; + // legacy first since it contains ambient color and we prioritize value from legacy, see getAmbientColor() + if (psetting->mSettings.has(LLSettingsSky::SETTING_LEGACY_HAZE) && psetting->mSettings[LLSettingsSky::SETTING_LEGACY_HAZE].has(it.first)) + { + value = psetting->mSettings[LLSettingsSky::SETTING_LEGACY_HAZE][it.first]; + } + else if (psetting->mSettings.has(it.first)) + { + value = psetting->mSettings[it.first]; + } + else + { + // We need to reset shaders, use defaults + value = it.second.getDefaultValue(); + } + + LLSD::Type setting_type = value.type(); + stop_glerror(); + switch (setting_type) + { + case LLSD::TypeInteger: + shader->uniform1i(it.second.getShaderKey(), value.asInteger()); + //_WARNS("RIDER") << "pushing '" << (*it).first << "' as " << value << LL_ENDL; + break; + case LLSD::TypeReal: + shader->uniform1f(it.second.getShaderKey(), value.asReal()); + //_WARNS("RIDER") << "pushing '" << (*it).first << "' as " << value << LL_ENDL; + break; + + case LLSD::TypeBoolean: + shader->uniform1i(it.second.getShaderKey(), value.asBoolean() ? 1 : 0); + //_WARNS("RIDER") << "pushing '" << (*it).first << "' as " << value << LL_ENDL; + break; + + case LLSD::TypeArray: + { + LLVector4 vect4(value); + + if (gCubeSnapshot && !gPipeline.mReflectionMapManager.isRadiancePass()) + { // maximize and remove tinting if this is an irradiance map render pass and the parameter feeds into the sky background color + auto max_vec = [](LLVector4 col) + { + LLColor3 color(col); + F32 h, s, l; + color.calcHSL(&h, &s, &l); + + col.mV[0] = col.mV[1] = col.mV[2] = l; + return col; + }; + + switch (it.second.getShaderKey()) + { + case LLShaderMgr::BLUE_HORIZON: + case LLShaderMgr::BLUE_DENSITY: + vect4 = max_vec(vect4); + break; + } + } + + //_WARNS("RIDER") << "pushing '" << (*it).first << "' as " << vect4 << LL_ENDL; + shader->uniform3fv(it.second.getShaderKey(), LLVector3(vect4.mV) ); + break; + } + + // case LLSD::TypeMap: + // case LLSD::TypeString: + // case LLSD::TypeUUID: + // case LLSD::TypeURI: + // case LLSD::TypeBinary: + // case LLSD::TypeDate: + default: + break; + } + } + //_WARNS("RIDER") << "----------------------------------------------------------------" << LL_ENDL; + + psetting->applySpecial(uniforms); +} + +void LLEnvironment::updateShaderUniforms(LLGLSLShader* shader) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + // apply uniforms that should be applied to all shaders + mSkyUniforms[LLGLSLShader::SG_ANY].apply(shader); + mWaterUniforms[LLGLSLShader::SG_ANY].apply(shader); + + // apply uniforms specific to the given shader's shader group + auto group = shader->mShaderGroup; + mSkyUniforms[group].apply(shader); + mWaterUniforms[group].apply(shader); +} + +void LLEnvironment::updateSettingsUniforms() +{ + if (mCurrentEnvironment->getWater()) + { + updateGLVariablesForSettings(mWaterUniforms, mCurrentEnvironment->getWater()); + } + else + { + LL_WARNS("ENVIRONMENT") << "Failed to update GL variable for water settings, environment is not properly set" << LL_ENDL; + } + if (mCurrentEnvironment->getSky()) + { + updateGLVariablesForSettings(mSkyUniforms, mCurrentEnvironment->getSky()); + } + else + { + LL_WARNS("ENVIRONMENT") << "Failed to update GL variable for sky settings, environment is not properly set" << LL_ENDL; + } +} + +void LLEnvironment::recordEnvironment(S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envinfo, LLSettingsBase::Seconds transition) +{ + if (!gAgent.getRegion()) + { + return; + } + // mRegionId id can be null, no specification as to why and if it's valid so check valid ids only + if (gAgent.getRegion()->getRegionID() != envinfo->mRegionId && envinfo->mRegionId.notNull()) + { + LL_INFOS("ENVIRONMENT") << "Requested environmend region id: " << envinfo->mRegionId << " agent is on: " << gAgent.getRegion()->getRegionID() << LL_ENDL; + return; + } + + if (envinfo->mParcelId == INVALID_PARCEL_ID) + { + // the returned info applies to an entire region. + if (!envinfo->mDayCycle) + { + clearEnvironment(ENV_PARCEL); + setEnvironment(ENV_REGION, LLSettingsDay::GetDefaultAssetId(), TRANSITION_DEFAULT, envinfo->mEnvVersion); + updateEnvironment(); + } + else if (envinfo->mDayCycle->isTrackEmpty(LLSettingsDay::TRACK_WATER) + || envinfo->mDayCycle->isTrackEmpty(LLSettingsDay::TRACK_GROUND_LEVEL)) + { + LL_WARNS("ENVIRONMENT") << "Invalid day cycle for region" << LL_ENDL; + clearEnvironment(ENV_PARCEL); + setEnvironment(ENV_REGION, LLSettingsDay::GetDefaultAssetId(), TRANSITION_DEFAULT, envinfo->mEnvVersion); + updateEnvironment(); + } + else + { + mTrackAltitudes = envinfo->mAltitudes; + // update track selection based on new altitudes + mCurrentTrack = calculateSkyTrackForAltitude(gAgent.getPositionAgent().mV[VZ]); + + setEnvironment(ENV_REGION, envinfo->mDayCycle, envinfo->mDayLength, envinfo->mDayOffset, envinfo->mEnvVersion); + } + + LL_DEBUGS("ENVIRONMENT") << "Altitudes set to {" << mTrackAltitudes[0] << ", "<< mTrackAltitudes[1] << ", " << mTrackAltitudes[2] << ", " << mTrackAltitudes[3] << LL_ENDL; + } + else + { + LLParcel *parcel = LLViewerParcelMgr::instance().getAgentParcel(); + LL_DEBUGS("ENVIRONMENT") << "Have parcel environment #" << envinfo->mParcelId << LL_ENDL; + if (parcel && (parcel->getLocalID() != parcel_id)) + { + LL_DEBUGS("ENVIRONMENT") << "Requested parcel #" << parcel_id << " agent is on " << parcel->getLocalID() << LL_ENDL; + return; + } + + if (!envinfo->mDayCycle) + { + LL_DEBUGS("ENVIRONMENT") << "Clearing environment on parcel #" << parcel_id << LL_ENDL; + clearEnvironment(ENV_PARCEL); + } + else if (envinfo->mDayCycle->isTrackEmpty(LLSettingsDay::TRACK_WATER) + || envinfo->mDayCycle->isTrackEmpty(LLSettingsDay::TRACK_GROUND_LEVEL)) + { + LL_WARNS("ENVIRONMENT") << "Invalid day cycle for parcel #" << parcel_id << LL_ENDL; + clearEnvironment(ENV_PARCEL); + } + else + { + setEnvironment(ENV_PARCEL, envinfo->mDayCycle, envinfo->mDayLength, envinfo->mDayOffset, envinfo->mEnvVersion); + } + } + + updateEnvironment(transition); +} + +void LLEnvironment::adjustRegionOffset(F32 adjust) +{ + if (isExtendedEnvironmentEnabled()) + { + LL_WARNS("ENVIRONMENT") << "Attempt to adjust region offset on EEP region. Legacy regions only." << LL_ENDL; + } + + if (mEnvironments[ENV_REGION]) + { + F32 day_length = mEnvironments[ENV_REGION]->getDayLength(); + F32 day_offset = mEnvironments[ENV_REGION]->getDayOffset(); + + F32 day_adjustment = adjust * day_length; + + day_offset += day_adjustment; + if (day_offset < 0.0f) + day_offset = day_length + day_offset; + mEnvironments[ENV_REGION]->setDayOffset(LLSettingsBase::Seconds(day_offset)); + } +} + +//========================================================================= +void LLEnvironment::requestRegion(environment_apply_fn cb) +{ + requestParcel(INVALID_PARCEL_ID, cb); +} + +void LLEnvironment::updateRegion(const LLSettingsDay::ptr_t &pday, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) +{ + updateParcel(INVALID_PARCEL_ID, pday, day_length, day_offset, altitudes, cb); +} + +void LLEnvironment::updateRegion(const LLUUID &asset_id, std::string display_name, S32 track_num, S32 day_length, S32 day_offset, U32 flags, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) +{ + if (!isExtendedEnvironmentEnabled()) + { + LL_WARNS("ENVIRONMENT") << "attempt to apply asset id to region not supporting it." << LL_ENDL; + LLNotificationsUtil::add("NoEnvironmentSettings"); + return; + } + + updateParcel(INVALID_PARCEL_ID, asset_id, display_name, track_num, day_length, day_offset, flags, altitudes, cb); +} + +void LLEnvironment::updateRegion(const LLSettingsSky::ptr_t &psky, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) +{ + updateParcel(INVALID_PARCEL_ID, psky, day_length, day_offset, altitudes, cb); +} + +void LLEnvironment::updateRegion(const LLSettingsWater::ptr_t &pwater, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) +{ + updateParcel(INVALID_PARCEL_ID, pwater, day_length, day_offset, altitudes, cb); +} + + +void LLEnvironment::resetRegion(environment_apply_fn cb) +{ + resetParcel(INVALID_PARCEL_ID, cb); +} + +void LLEnvironment::requestParcel(S32 parcel_id, environment_apply_fn cb) +{ + if (!isExtendedEnvironmentEnabled()) + { /*TODO: When EEP is live on the entire grid, this can go away. */ + if (parcel_id == INVALID_PARCEL_ID) + { + if (!cb) + { + LLSettingsBase::Seconds transition = LLViewerParcelMgr::getInstance()->getTeleportInProgress() ? TRANSITION_FAST : TRANSITION_DEFAULT; + cb = [this, transition](S32 pid, EnvironmentInfo::ptr_t envinfo) + { + clearEnvironment(ENV_PARCEL); + recordEnvironment(pid, envinfo, transition); + }; + } + + LLEnvironmentRequest::initiate(cb); + } + else if (cb) + cb(parcel_id, EnvironmentInfo::ptr_t()); + return; + } + + if (!cb) + { + LLSettingsBase::Seconds transition = LLViewerParcelMgr::getInstance()->getTeleportInProgress() ? TRANSITION_FAST : TRANSITION_DEFAULT; + cb = [this, transition](S32 pid, EnvironmentInfo::ptr_t envinfo) { recordEnvironment(pid, envinfo, transition); }; + } + + std::string coroname = + LLCoros::instance().launch("LLEnvironment::coroRequestEnvironment", + [this, parcel_id, cb]() { coroRequestEnvironment(parcel_id, cb); }); +} + +void LLEnvironment::updateParcel(S32 parcel_id, const LLUUID &asset_id, std::string display_name, S32 track_num, S32 day_length, S32 day_offset, U32 flags, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) +{ + UpdateInfo::ptr_t updates(std::make_shared(asset_id, display_name, day_length, day_offset, altitudes, flags)); + std::string coroname = + LLCoros::instance().launch("LLEnvironment::coroUpdateEnvironment", + [this, parcel_id, track_num, updates, cb]() { coroUpdateEnvironment(parcel_id, track_num, updates, cb); }); +} + +void LLEnvironment::onUpdateParcelAssetLoaded(LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, S32 parcel_id, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes) +{ + if (status) + { + LL_WARNS("ENVIRONMENT") << "Unable to get settings asset with id " << asset_id << "!" << LL_ENDL; + LLNotificationsUtil::add("FailedToLoadSettingsApply"); + return; + } + + LLSettingsDay::ptr_t pday; + + if (settings->getSettingsType() == "daycycle") + pday = std::static_pointer_cast(settings); + else + { + pday = createDayCycleFromEnvironment( (parcel_id == INVALID_PARCEL_ID) ? ENV_REGION : ENV_PARCEL, settings); + } + + if (!pday) + { + LL_WARNS("ENVIRONMENT") << "Unable to construct day around " << asset_id << "!" << LL_ENDL; + LLNotificationsUtil::add("FailedToBuildSettingsDay"); + return; + } + + updateParcel(parcel_id, pday, day_length, day_offset, altitudes); +} + +void LLEnvironment::updateParcel(S32 parcel_id, const LLSettingsSky::ptr_t &psky, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) +{ + LLSettingsDay::ptr_t pday = createDayCycleFromEnvironment((parcel_id == INVALID_PARCEL_ID) ? ENV_REGION : ENV_PARCEL, psky); + pday->setFlag(psky->getFlags()); + updateParcel(parcel_id, pday, day_length, day_offset, altitudes, cb); +} + +void LLEnvironment::updateParcel(S32 parcel_id, const LLSettingsWater::ptr_t &pwater, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) +{ + LLSettingsDay::ptr_t pday = createDayCycleFromEnvironment((parcel_id == INVALID_PARCEL_ID) ? ENV_REGION : ENV_PARCEL, pwater); + pday->setFlag(pwater->getFlags()); + updateParcel(parcel_id, pday, day_length, day_offset, altitudes, cb); +} + +void LLEnvironment::updateParcel(S32 parcel_id, const LLSettingsDay::ptr_t &pday, S32 track_num, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) +{ + UpdateInfo::ptr_t updates(std::make_shared(pday, day_length, day_offset, altitudes)); + + std::string coroname = + LLCoros::instance().launch("LLEnvironment::coroUpdateEnvironment", + [this, parcel_id, track_num, updates, cb]() { coroUpdateEnvironment(parcel_id, track_num, updates, cb); }); +} + +void LLEnvironment::updateParcel(S32 parcel_id, const LLSettingsDay::ptr_t &pday, S32 day_length, S32 day_offset, LLEnvironment::altitudes_vect_t altitudes, environment_apply_fn cb) +{ + updateParcel(parcel_id, pday, NO_TRACK, day_length, day_offset, altitudes, cb); +} + + + +void LLEnvironment::resetParcel(S32 parcel_id, environment_apply_fn cb) +{ + std::string coroname = + LLCoros::instance().launch("LLEnvironment::coroResetEnvironment", + [this, parcel_id, cb]() { coroResetEnvironment(parcel_id, NO_TRACK, cb); }); +} + +void LLEnvironment::coroRequestEnvironment(S32 parcel_id, LLEnvironment::environment_apply_fn apply) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("ResetEnvironment", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + std::string url = gAgent.getRegionCapability("ExtEnvironment"); + if (url.empty()) + return; + + LL_DEBUGS("ENVIRONMENT") << "Requesting for parcel_id=" << parcel_id << LL_ENDL; + + if (parcel_id != INVALID_PARCEL_ID) + { + std::stringstream query; + + query << "?parcelid=" << parcel_id; + url += query.str(); + } + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + // results that come back may contain the new settings + + LLSD httpResults = result["http_result"]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + if (!status) + { + LL_WARNS("ENVIRONMENT") << "Couldn't retrieve environment settings for " << ((parcel_id == INVALID_PARCEL_ID) ? ("region!") : ("parcel!")) << LL_ENDL; + } + else if (LLApp::isExiting() || gDisconnected) + { + return; + } + else + { + LLSD environment = result[KEY_ENVIRONMENT]; + if (environment.isDefined() && apply) + { + EnvironmentInfo::ptr_t envinfo = LLEnvironment::EnvironmentInfo::extract(environment); + apply(parcel_id, envinfo); + } + } + +} + +void LLEnvironment::coroUpdateEnvironment(S32 parcel_id, S32 track_no, UpdateInfo::ptr_t updates, environment_apply_fn apply) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("ResetEnvironment", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + std::string url = gAgent.getRegionCapability("ExtEnvironment"); + if (url.empty()) + return; + + LLSD body(LLSD::emptyMap()); + body[KEY_ENVIRONMENT] = LLSD::emptyMap(); + + if (track_no == NO_TRACK) + { // day length and offset are only applicable if we are addressing the entire day cycle. + if (updates->mDayLength > 0) + body[KEY_ENVIRONMENT][KEY_DAYLENGTH] = updates->mDayLength; + if (updates->mDayOffset > 0) + body[KEY_ENVIRONMENT][KEY_DAYOFFSET] = updates->mDayOffset; + + if ((parcel_id == INVALID_PARCEL_ID) && (updates->mAltitudes.size() == 3)) + { // only test for altitude changes if we are changing the region. + body[KEY_ENVIRONMENT][KEY_TRACKALTS] = LLSD::emptyArray(); + for (S32 i = 0; i < 3; ++i) + { + body[KEY_ENVIRONMENT][KEY_TRACKALTS][i] = updates->mAltitudes[i]; + } + } + } + + if (updates->mDayp) + body[KEY_ENVIRONMENT][KEY_DAYCYCLE] = updates->mDayp->getSettings(); + else if (!updates->mSettingsAsset.isNull()) + { + body[KEY_ENVIRONMENT][KEY_DAYASSET] = updates->mSettingsAsset; + if (!updates->mDayName.empty()) + body[KEY_ENVIRONMENT][KEY_DAYNAME] = updates->mDayName; + } + + body[KEY_ENVIRONMENT][KEY_FLAGS] = LLSD::Integer(updates->mFlags); + //_WARNS("ENVIRONMENT") << "Body = " << body << LL_ENDL; + + if ((parcel_id != INVALID_PARCEL_ID) || (track_no != NO_TRACK)) + { + std::stringstream query; + query << "?"; + + if (parcel_id != INVALID_PARCEL_ID) + { + query << "parcelid=" << parcel_id; + + if (track_no != NO_TRACK) + query << "&"; + } + if (track_no != NO_TRACK) + { + query << "trackno=" << track_no; + } + url += query.str(); + } + + LLSD result = httpAdapter->putAndSuspend(httpRequest, url, body); + // results that come back may contain the new settings + + LLSD notify; + + LLSD httpResults = result["http_result"]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if ((!status) || !result["success"].asBoolean()) + { + LL_WARNS("ENVIRONMENT") << "Couldn't update Windlight settings for " << ((parcel_id == INVALID_PARCEL_ID) ? ("region!") : ("parcel!")) << LL_ENDL; + + notify = LLSD::emptyMap(); + std::string reason = result["message"].asString(); + if (reason.empty()) + { + notify["FAIL_REASON"] = status.toString(); + } + else + { + notify["FAIL_REASON"] = reason; + } + } + else if (LLApp::isExiting()) + { + return; + } + else + { + LLSD environment = result[KEY_ENVIRONMENT]; + if (environment.isDefined() && apply) + { + EnvironmentInfo::ptr_t envinfo = LLEnvironment::EnvironmentInfo::extract(environment); + apply(parcel_id, envinfo); + } + } + + if (!notify.isUndefined()) + { + LLNotificationsUtil::add("WLRegionApplyFail", notify); + //LLEnvManagerNew::instance().onRegionSettingsApplyResponse(false); + } +} + +void LLEnvironment::coroResetEnvironment(S32 parcel_id, S32 track_no, environment_apply_fn apply) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("ResetEnvironment", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + + std::string url = gAgent.getRegionCapability("ExtEnvironment"); + if (url.empty()) + return; + + if ((parcel_id != INVALID_PARCEL_ID) || (track_no != NO_TRACK)) + { + std::stringstream query; + query << "?"; + + if (parcel_id != INVALID_PARCEL_ID) + { + query << "parcelid=" << parcel_id; + + if (track_no != NO_TRACK) + query << "&"; + } + if (track_no != NO_TRACK) + { + query << "trackno=" << track_no; + } + url += query.str(); + } + + LLSD result = httpAdapter->deleteAndSuspend(httpRequest, url); + // results that come back may contain the new settings + + LLSD notify; + + LLSD httpResults = result["http_result"]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if ((!status) || !result["success"].asBoolean()) + { + LL_WARNS("ENVIRONMENT") << "Couldn't reset Windlight settings in " << ((parcel_id == INVALID_PARCEL_ID) ? ("region!") : ("parcel!")) << LL_ENDL; + + notify = LLSD::emptyMap(); + std::string reason = result["message"].asString(); + if (reason.empty()) + { + notify["FAIL_REASON"] = status.toString(); + } + else + { + notify["FAIL_REASON"] = reason; + } + } + else if (LLApp::isExiting()) + { + return; + } + else + { + LLSD environment = result[KEY_ENVIRONMENT]; + if (environment.isDefined() && apply) + { + EnvironmentInfo::ptr_t envinfo = LLEnvironment::EnvironmentInfo::extract(environment); + apply(parcel_id, envinfo); + } + } + + if (!notify.isUndefined()) + { + LLNotificationsUtil::add("WLRegionApplyFail", notify); + //LLEnvManagerNew::instance().onRegionSettingsApplyResponse(false); + } + +} + + +//========================================================================= + +LLEnvironment::EnvironmentInfo::EnvironmentInfo(): + mParcelId(INVALID_PARCEL_ID), + mRegionId(), + mDayLength(0), + mDayOffset(0), + mDayHash(0), + mDayCycle(), + mAltitudes({ { 0.0, 0.0, 0.0, 0.0 } }), + mIsDefault(false), + mIsLegacy(false), + mDayCycleName(), + mNameList(), + mEnvVersion(INVALID_PARCEL_ENVIRONMENT_VERSION) +{ +} + +LLEnvironment::EnvironmentInfo::ptr_t LLEnvironment::EnvironmentInfo::extract(LLSD environment) +{ + ptr_t pinfo = std::make_shared(); + + pinfo->mIsDefault = environment.has(KEY_ISDEFAULT) ? environment[KEY_ISDEFAULT].asBoolean() : true; + pinfo->mParcelId = environment.has(KEY_PARCELID) ? environment[KEY_PARCELID].asInteger() : INVALID_PARCEL_ID; + pinfo->mRegionId = environment.has(KEY_REGIONID) ? environment[KEY_REGIONID].asUUID() : LLUUID::null; + pinfo->mIsLegacy = false; + + if (environment.has(KEY_TRACKALTS)) + { + for (int idx = 0; idx < 3; idx++) + { + pinfo->mAltitudes[idx+1] = environment[KEY_TRACKALTS][idx].asReal(); + } + pinfo->mAltitudes[0] = 0; + } + + if (environment.has(KEY_DAYCYCLE)) + { + pinfo->mDayCycle = LLSettingsVODay::buildFromEnvironmentMessage(environment[KEY_DAYCYCLE]); + pinfo->mDayLength = LLSettingsDay::Seconds(environment.has(KEY_DAYLENGTH) ? environment[KEY_DAYLENGTH].asInteger() : -1); + pinfo->mDayOffset = LLSettingsDay::Seconds(environment.has(KEY_DAYOFFSET) ? environment[KEY_DAYOFFSET].asInteger() : -1); + pinfo->mDayHash = environment.has(KEY_DAYHASH) ? environment[KEY_DAYHASH].asInteger() : 0; + } + else + { + pinfo->mDayLength = LLEnvironment::instance().getEnvironmentDayLength(ENV_REGION); + pinfo->mDayOffset = LLEnvironment::instance().getEnvironmentDayOffset(ENV_REGION); + } + + if (environment.has(KEY_DAYASSET)) + { + pinfo->mAssetId = environment[KEY_DAYASSET].asUUID(); + } + + if (environment.has(KEY_DAYNAMES)) + { + LLSD daynames = environment[KEY_DAYNAMES]; + if (daynames.isArray()) + { + pinfo->mDayCycleName.clear(); + for (S32 index = 0; index < pinfo->mNameList.size(); ++index) + { + pinfo->mNameList[index] = daynames[index].asString(); + } + } + else if (daynames.isString()) + { + for (std::string &name: pinfo->mNameList) + { + name.clear(); + } + + pinfo->mDayCycleName = daynames.asString(); + } + } + else if (pinfo->mDayCycle) + { + pinfo->mDayCycleName = pinfo->mDayCycle->getName(); + } + + + if (environment.has(KEY_ENVVERSION)) + { + LLSD version = environment[KEY_ENVVERSION]; + pinfo->mEnvVersion = version.asInteger(); + } + else + { + // can be used for region, but versions should be same + pinfo->mEnvVersion = pinfo->mIsDefault ? UNSET_PARCEL_ENVIRONMENT_VERSION : INVALID_PARCEL_ENVIRONMENT_VERSION; + } + + return pinfo; +} + + +LLEnvironment::EnvironmentInfo::ptr_t LLEnvironment::EnvironmentInfo::extractLegacy(LLSD legacy) +{ + if (!legacy.isArray() || !legacy[0].has("regionID")) + { + LL_WARNS("ENVIRONMENT") << "Invalid legacy settings for environment: " << legacy << LL_ENDL; + return ptr_t(); + } + + ptr_t pinfo = std::make_shared(); + + pinfo->mIsDefault = false; + pinfo->mParcelId = INVALID_PARCEL_ID; + pinfo->mRegionId = legacy[0]["regionID"].asUUID(); + pinfo->mIsLegacy = true; + + pinfo->mDayLength = LLSettingsDay::DEFAULT_DAYLENGTH; + pinfo->mDayOffset = LLSettingsDay::DEFAULT_DAYOFFSET; + pinfo->mDayCycle = LLSettingsVODay::buildFromLegacyMessage(pinfo->mRegionId, legacy[1], legacy[2], legacy[3]); + if (pinfo->mDayCycle) + pinfo->mDayHash = pinfo->mDayCycle->getHash(); + + pinfo->mAltitudes[0] = 0; + pinfo->mAltitudes[2] = 10001; + pinfo->mAltitudes[3] = 10002; + pinfo->mAltitudes[4] = 10003; + + return pinfo; +} + +//========================================================================= +LLSettingsWater::ptr_t LLEnvironment::createWaterFromLegacyPreset(const std::string filename, LLSD &messages) +{ + std::string name(gDirUtilp->getBaseFileName(filename, true)); + std::string path(gDirUtilp->getDirName(filename)); + + LLSettingsWater::ptr_t water = LLSettingsVOWater::buildFromLegacyPresetFile(name, path, messages); + + if (!water) + { + messages["NAME"] = name; + messages["FILE"] = filename; + } + return water; +} + +LLSettingsSky::ptr_t LLEnvironment::createSkyFromLegacyPreset(const std::string filename, LLSD &messages) +{ + std::string name(gDirUtilp->getBaseFileName(filename, true)); + std::string path(gDirUtilp->getDirName(filename)); + + LLSettingsSky::ptr_t sky = LLSettingsVOSky::buildFromLegacyPresetFile(name, path, messages); + if (!sky) + { + messages["NAME"] = name; + messages["FILE"] = filename; + } + return sky; +} + +LLSettingsDay::ptr_t LLEnvironment::createDayCycleFromLegacyPreset(const std::string filename, LLSD &messages) +{ + std::string name(gDirUtilp->getBaseFileName(filename, true)); + std::string path(gDirUtilp->getDirName(filename)); + + LLSettingsDay::ptr_t day = LLSettingsVODay::buildFromLegacyPresetFile(name, path, messages); + if (!day) + { + messages["NAME"] = name; + messages["FILE"] = filename; + } + return day; +} + +LLSettingsDay::ptr_t LLEnvironment::createDayCycleFromEnvironment(EnvSelection_t env, LLSettingsBase::ptr_t settings) +{ + std::string type(settings->getSettingsType()); + + if (type == "daycycle") + return std::static_pointer_cast(settings); + + if ((env != ENV_PARCEL) && (env != ENV_REGION)) + { + LL_WARNS("ENVIRONMENT") << "May only create from parcel or region environment." << LL_ENDL; + return LLSettingsDay::ptr_t(); + } + + LLSettingsDay::ptr_t day = this->getEnvironmentDay(env); + if (!day && (env == ENV_PARCEL)) + { + day = this->getEnvironmentDay(ENV_REGION); + } + + if (!day) + { + LL_WARNS("ENVIRONMENT") << "Could not retrieve existing day settings." << LL_ENDL; + return LLSettingsDay::ptr_t(); + } + + day = day->buildClone(); + + if (type == "sky") + { + for (S32 idx = 1; idx < LLSettingsDay::TRACK_MAX; ++idx) + day->clearCycleTrack(idx); + day->setSettingsAtKeyframe(settings, 0.0f, 1); + } + else if (type == "water") + { + day->clearCycleTrack(LLSettingsDay::TRACK_WATER); + day->setSettingsAtKeyframe(settings, 0.0f, LLSettingsDay::TRACK_WATER); + } + + return day; +} + +void LLEnvironment::onAgentPositionHasChanged(const LLVector3 &localpos) +{ + S32 trackno = calculateSkyTrackForAltitude(localpos.mV[VZ]); + if (trackno == mCurrentTrack) + return; + + mCurrentTrack = trackno; + + LLViewerRegion* cur_region = gAgent.getRegion(); + if (!cur_region || !cur_region->capabilitiesReceived()) + { + // Environment not ready, environment will be updated later, don't cause 'blend' yet. + // But keep mCurrentTrack updated in case we won't get new altitudes for some reason + return; + } + + for (S32 env = ENV_LOCAL; env < ENV_DEFAULT; ++env) + { + if (mEnvironments[env]) + mEnvironments[env]->setSkyTrack(mCurrentTrack); + } +} + +S32 LLEnvironment::calculateSkyTrackForAltitude(F64 altitude) +{ + auto it = std::find_if_not(mTrackAltitudes.begin(), mTrackAltitudes.end(), [altitude](F32 test) { return altitude > test; }); + + if (it == mTrackAltitudes.begin()) + return 1; + else if (it == mTrackAltitudes.end()) + return 4; + + return std::min(static_cast(std::distance(mTrackAltitudes.begin(), it)), 4); +} + +//------------------------------------------------------------------------- +void LLEnvironment::handleEnvironmentPush(LLSD &message) +{ + // Log the experience message + LLExperienceLog::instance().handleExperienceMessage(message); + + std::string action = message[KEY_ACTION].asString(); + LLUUID experience_id = message[KEY_EXPERIENCEID].asUUID(); + LLSD action_data = message[KEY_ACTIONDATA]; + F32 transition_time = action_data[KEY_TRANSITIONTIME].asReal(); + + //TODO: Check here that the viewer thinks the experience is still valid. + + + if (action == ACTION_CLEARENVIRONMENT) + { + handleEnvironmentPushClear(experience_id, action_data, transition_time); + } + else if (action == ACTION_PUSHFULLENVIRONMENT) + { + handleEnvironmentPushFull(experience_id, action_data, transition_time); + } + else if (action == ACTION_PUSHPARTIALENVIRONMENT) + { + handleEnvironmentPushPartial(experience_id, action_data, transition_time); + } + else + { + LL_WARNS("ENVIRONMENT", "GENERICMESSAGES") << "Unknown environment push action '" << action << "'" << LL_ENDL; + } +} + +void LLEnvironment::handleEnvironmentPushClear(LLUUID experience_id, LLSD &message, F32 transition) +{ + clearExperienceEnvironment(experience_id, LLSettingsBase::Seconds(transition)); +} + +void LLEnvironment::handleEnvironmentPushFull(LLUUID experience_id, LLSD &message, F32 transition) +{ + LLUUID asset_id(message[KEY_ASSETID].asUUID()); + + setExperienceEnvironment(experience_id, asset_id, LLSettingsBase::Seconds(transition)); +} + +void LLEnvironment::handleEnvironmentPushPartial(LLUUID experience_id, LLSD &message, F32 transition) +{ + LLSD settings(message["settings"]); + + if (settings.isUndefined()) + return; + + setExperienceEnvironment(experience_id, settings, LLSettingsBase::Seconds(transition)); +} + +void LLEnvironment::clearExperienceEnvironment(LLUUID experience_id, LLSettingsBase::Seconds transition_time) +{ + DayInjection::ptr_t injection = std::dynamic_pointer_cast(getEnvironmentInstance(ENV_PUSH)); + if (injection) + { + injection->clearInjections(experience_id, transition_time); + } + +} + +void LLEnvironment::setSharedEnvironment() +{ + clearEnvironment(LLEnvironment::ENV_LOCAL); + setSelectedEnvironment(LLEnvironment::ENV_LOCAL); + updateEnvironment(); +} + +void LLEnvironment::setExperienceEnvironment(LLUUID experience_id, LLUUID asset_id, F32 transition_time) +{ + LLSettingsVOBase::getSettingsAsset(asset_id, + [this, experience_id, transition_time](LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, LLExtStat) + { + onSetExperienceEnvAssetLoaded(experience_id, settings, transition_time, status); + }); + + +} + +void LLEnvironment::onSetExperienceEnvAssetLoaded(LLUUID experience_id, LLSettingsBase::ptr_t settings, F32 transition_time, S32 status) +{ + DayInjection::ptr_t environment = std::dynamic_pointer_cast(getEnvironmentInstance(ENV_PUSH)); + bool updateenvironment(false); + + if (!settings || status) + { + LLSD args; + args["NAME"] = experience_id.asString(); + LLNotificationsUtil::add("FailedToFindSettings", args); + return; + } + + if (!environment) + { + environment = std::dynamic_pointer_cast(getEnvironmentInstance(ENV_PUSH, true)); + updateenvironment = true; + } + + if (settings->getSettingsType() == "daycycle") + { + environment->setInjectedDay(std::static_pointer_cast(settings), experience_id, LLSettingsBase::Seconds(transition_time)); + } + else if (settings->getSettingsType() == "sky") + { + environment->setInjectedSky(std::static_pointer_cast(settings), experience_id, LLSettingsBase::Seconds(transition_time)); + } + else if (settings->getSettingsType() == "water") + { + environment->setInjectedWater(std::static_pointer_cast(settings), experience_id, LLSettingsBase::Seconds(transition_time)); + } + + if (updateenvironment) + updateEnvironment(TRANSITION_INSTANT, true); +} + + +void LLEnvironment::setExperienceEnvironment(LLUUID experience_id, LLSD data, F32 transition_time) +{ + LLSD sky(data["sky"]); + LLSD water(data["water"]); + + if (sky.isUndefined() && water.isUndefined()) + { + clearExperienceEnvironment(experience_id, LLSettingsBase::Seconds(transition_time)); + return; + } + + DayInjection::ptr_t environment = std::dynamic_pointer_cast(getEnvironmentInstance(ENV_PUSH)); + bool updateenvironment(false); + + if (!environment) + { + environment = std::dynamic_pointer_cast(getEnvironmentInstance(ENV_PUSH, true)); + updateenvironment = true; + } + + if (!sky.isUndefined()) + { + environment->injectSkySettings(sky, experience_id, LLSettingsBase::Seconds(transition_time)); + } + + if (!water.isUndefined()) + { + environment->injectWaterSettings(water, experience_id, LLSettingsBase::Seconds(transition_time)); + } + + if (updateenvironment) + updateEnvironment(TRANSITION_INSTANT, true); + +} + +void LLEnvironment::listenExperiencePump(const LLSD &message) +{ + LLUUID experience_id = message["experience"]; + LLSD data = message[experience_id.asString()]; + std::string permission(data["permission"].asString()); + + if ((permission == "Forget") || (permission == "Block")) + { + clearExperienceEnvironment(experience_id, (permission == "Block") ? TRANSITION_INSTANT : TRANSITION_FAST); + } +} + +//========================================================================= +LLEnvironment::DayInstance::DayInstance(EnvSelection_t env) : + mDayCycle(), + mSky(), + mWater(), + mDayLength(LLSettingsDay::DEFAULT_DAYLENGTH), + mDayOffset(LLSettingsDay::DEFAULT_DAYOFFSET), + mBlenderSky(), + mBlenderWater(), + mInitialized(false), + mSkyTrack(1), + mEnv(env), + mAnimateFlags(0) +{ } + + +LLEnvironment::DayInstance::ptr_t LLEnvironment::DayInstance::clone() const +{ + ptr_t environment = std::make_shared(mEnv); + + environment->mDayCycle = mDayCycle; + environment->mSky = mSky; + environment->mWater = mWater; + environment->mDayLength = mDayLength; + environment->mDayOffset = mDayOffset; + environment->mBlenderSky = mBlenderSky; + environment->mBlenderWater = mBlenderWater; + environment->mInitialized = mInitialized; + environment->mSkyTrack = mSkyTrack; + environment->mAnimateFlags = mAnimateFlags; + + return environment; +} + +bool LLEnvironment::DayInstance::applyTimeDelta(const LLSettingsBase::Seconds& delta) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; + ptr_t keeper(shared_from_this()); // makes sure that this does not go away while it is being worked on. + + bool changed(false); + if (!mInitialized) + initialize(); + + if (mBlenderSky) + changed |= mBlenderSky->applyTimeDelta(delta); + if (mBlenderWater) + changed |= mBlenderWater->applyTimeDelta(delta); + return changed; +} + +void LLEnvironment::DayInstance::setDay(const LLSettingsDay::ptr_t &pday, LLSettingsDay::Seconds daylength, LLSettingsDay::Seconds dayoffset) +{ + mInitialized = false; + + mAnimateFlags = 0; + + mDayCycle = pday; + mDayLength = daylength; + mDayOffset = dayoffset; + + mBlenderSky.reset(); + mBlenderWater.reset(); + + mSky = LLSettingsVOSky::buildDefaultSky(); + mWater = LLSettingsVOWater::buildDefaultWater(); + + animate(); +} + + +bool LLEnvironment::DayInstance::setSky(const LLSettingsSky::ptr_t &psky) +{ + mInitialized = false; + + bool changed = psky == nullptr || mSky == nullptr || mSky->getHash() != psky->getHash(); + + bool different_sky = mSky != psky; + + mSky = psky; + mSky->mReplaced |= different_sky; + mSky->update(); + mBlenderSky.reset(); + + if (gAtmosphere) + { + AtmosphericModelSettings settings; + LLEnvironment::getAtmosphericModelSettings(settings, psky); + gAtmosphere->configureAtmosphericModel(settings); + } + + return changed; +} + +void LLEnvironment::DayInstance::setWater(const LLSettingsWater::ptr_t &pwater) +{ + mInitialized = false; + + bool different_water = mWater != pwater; + mWater = pwater; + mWater->mReplaced |= different_water; + mWater->update(); + mBlenderWater.reset(); +} + +void LLEnvironment::DayInstance::initialize() +{ + mInitialized = true; + + if (!mWater) + mWater = LLSettingsVOWater::buildDefaultWater(); + if (!mSky) + mSky = LLSettingsVOSky::buildDefaultSky(); +} + +void LLEnvironment::DayInstance::clear() +{ + mDayCycle.reset(); + mSky.reset(); + mWater.reset(); + mDayLength = LLSettingsDay::DEFAULT_DAYLENGTH; + mDayOffset = LLSettingsDay::DEFAULT_DAYOFFSET; + mBlenderSky.reset(); + mBlenderWater.reset(); + mSkyTrack = 1; +} + +void LLEnvironment::DayInstance::setSkyTrack(S32 trackno) +{ + mSkyTrack = trackno; + if (mBlenderSky) + { + mBlenderSky->switchTrack(trackno, 0.0); + } +} + +void LLEnvironment::DayInstance::setBlenders(const LLSettingsBlender::ptr_t &skyblend, const LLSettingsBlender::ptr_t &waterblend) +{ + mBlenderSky = skyblend; + mBlenderWater = waterblend; +} + +LLSettingsBase::TrackPosition LLEnvironment::DayInstance::getProgress() const +{ + LLSettingsBase::Seconds now(LLDate::now().secondsSinceEpoch()); + now += mDayOffset; + + if ((mDayLength <= 0) || !mDayCycle) + return -1.0f; // no actual day cycle. + + return convert_time_to_position(now, mDayLength); +} + +LLSettingsBase::TrackPosition LLEnvironment::DayInstance::secondsToKeyframe(LLSettingsDay::Seconds seconds) +{ + return convert_time_to_position(seconds, mDayLength); +} + +void LLEnvironment::DayInstance::animate() +{ + LLSettingsBase::Seconds now(LLDate::now().secondsSinceEpoch()); + + now += mDayOffset; + + if (!mDayCycle) + return; + + if (!(mAnimateFlags & NO_ANIMATE_WATER)) + { + LLSettingsDay::CycleTrack_t &wtrack = mDayCycle->getCycleTrack(0); + + if (wtrack.empty()) + { + mWater.reset(); + mBlenderWater.reset(); + } + else + { + mWater = LLSettingsVOWater::buildDefaultWater(); + mBlenderWater = std::make_shared(mWater, mDayCycle, 0, + mDayLength, mDayOffset, DEFAULT_UPDATE_THRESHOLD); + } + } + + if (!(mAnimateFlags & NO_ANIMATE_SKY)) + { + // sky, initialize to track 1 + LLSettingsDay::CycleTrack_t &track = mDayCycle->getCycleTrack(1); + + if (track.empty()) + { + mSky.reset(); + mBlenderSky.reset(); + } + else + { + mSky = LLSettingsVOSky::buildDefaultSky(); + mBlenderSky = std::make_shared(mSky, mDayCycle, 1, + mDayLength, mDayOffset, DEFAULT_UPDATE_THRESHOLD); + mBlenderSky->switchTrack(mSkyTrack, 0.0); + } + } +} + +//------------------------------------------------------------------------- +LLEnvironment::DayTransition::DayTransition(const LLSettingsSky::ptr_t &skystart, + const LLSettingsWater::ptr_t &waterstart, LLEnvironment::DayInstance::ptr_t &end, LLSettingsDay::Seconds time) : + DayInstance(ENV_NONE), + mStartSky(skystart), + mStartWater(waterstart), + mNextInstance(end), + mTransitionTime(time) +{ + +} + +bool LLEnvironment::DayTransition::applyTimeDelta(const LLSettingsBase::Seconds& delta) +{ + bool changed(false); + + changed = mNextInstance->applyTimeDelta(delta); + changed |= DayInstance::applyTimeDelta(delta); + return changed; +} + +void LLEnvironment::DayTransition::animate() +{ + mNextInstance->animate(); + + mWater = mStartWater->buildClone(); + mBlenderWater = std::make_shared(mWater, mStartWater, mNextInstance->getWater(), mTransitionTime); + mBlenderWater->setOnFinished( + [this](LLSettingsBlender::ptr_t blender) { + mBlenderWater.reset(); + + if (!mBlenderSky && !mBlenderWater) + LLEnvironment::instance().mCurrentEnvironment = mNextInstance; + else + setWater(mNextInstance->getWater()); + }); + + + // pause probe updates and reset reflection maps on sky change + gPipeline.mReflectionMapManager.pause(); + gPipeline.mReflectionMapManager.reset(); + + mSky = mStartSky->buildClone(); + mBlenderSky = std::make_shared(mSky, mStartSky, mNextInstance->getSky(), mTransitionTime); + mBlenderSky->setOnFinished( + [this](LLSettingsBlender::ptr_t blender) { + mBlenderSky.reset(); + + // resume reflection probe updates + gPipeline.mReflectionMapManager.resume(); + + if (!mBlenderSky && !mBlenderWater) + LLEnvironment::instance().mCurrentEnvironment = mNextInstance; + else + setSky(mNextInstance->getSky()); + }); +} + +void LLEnvironment::saveToSettings() +{ + std::string user_dir = gDirUtilp->getLindenUserDir(); + if (user_dir.empty()) + { + // not logged in + return; + } + bool has_data = false; + + if (gSavedSettings.getBOOL("EnvironmentPersistAcrossLogin")) + { + DayInstance::ptr_t environment = getEnvironmentInstance(ENV_LOCAL); + if (environment) + { + // Environment is 'layered'. No data in ENV_LOCAL means we are using parcel/region + // Store local environment for next session + LLSD env_data; + + LLSettingsDay::ptr_t day = environment->getDayCycle(); + if (day) + { + const std::string name = day->getName(); + const LLUUID asset_id = day->getAssetId(); + if (asset_id.notNull()) + { + // just save the id + env_data["day_id"] = asset_id; + env_data["day_length"] = LLSD::Integer(environment->getDayLength()); + env_data["day_offset"] = LLSD::Integer(environment->getDayOffset()); + has_data = true; + } + else if (!name.empty() && name != LLSettingsBase::DEFAULT_SETTINGS_NAME) + { + // This setting was created locally and was not saved + // The only option is to save the whole thing + env_data["day_llsd"] = day->getSettings(); + env_data["day_length"] = LLSD::Integer(environment->getDayLength()); + env_data["day_offset"] = LLSD::Integer(environment->getDayOffset()); + has_data = true; + } + } + + LLSettingsSky::ptr_t sky = environment->getSky(); + if ((environment->getFlags() & DayInstance::NO_ANIMATE_SKY) && sky) + { + const std::string name = sky->getName(); + const LLUUID asset_id = sky->getAssetId(); + if (asset_id.notNull()) + { + // just save the id + env_data["sky_id"] = asset_id; + has_data = true; + } + else if (!name.empty() && name != LLSettingsBase::DEFAULT_SETTINGS_NAME) + { + // This setting was created locally and was not saved + // The only option is to save the whole thing + env_data["sky_llsd"] = sky->getSettings(); + has_data = true; + } + has_data = true; + } + + LLSettingsWater::ptr_t water = environment->getWater(); + if ((environment->getFlags() & DayInstance::NO_ANIMATE_WATER) && water) + { + const std::string name = water->getName(); + const LLUUID asset_id = water->getAssetId(); + if (asset_id.notNull()) + { + // just save the id + env_data["water_id"] = asset_id; + has_data = true; + } + else if (!name.empty() && name != LLSettingsBase::DEFAULT_SETTINGS_NAME) + { + // This setting was created locally and was not saved + // The only option is to save the whole thing + env_data["water_llsd"] = water->getSettings(); + has_data = true; + } + } + + std::string user_filepath = user_dir + gDirUtilp->getDirDelimiter() + LOCAL_ENV_STORAGE_FILE; + llofstream out(user_filepath.c_str(), std::ios_base::out | std::ios_base::binary); + if (out.good()) + { + LLSDSerialize::toBinary(env_data, out); + out.close(); + } + else + { + LL_WARNS("ENVIRONMENT") << "Unable to open " << user_filepath << " for output." << LL_ENDL; + } + } + } + + if (!has_data) + { + LLFile::remove(user_dir + gDirUtilp->getDirDelimiter() + LOCAL_ENV_STORAGE_FILE, ENOENT); + } +} + +void LLEnvironment::loadSkyWaterFromSettings(const LLSD &env_data, bool &valid, bool &assets_present) +{ + if (env_data.has("sky_id")) + { + // causes asset loaded callback and an update + setEnvironment(ENV_LOCAL, env_data["sky_id"].asUUID()); + valid = true; + assets_present = true; + } + else if (env_data.has("sky_llsd")) + { + LLSettingsSky::ptr_t sky = LLSettingsVOSky::buildSky(env_data["sky_llsd"]); + setEnvironment(ENV_LOCAL, sky); + valid = true; + } + + if (env_data.has("water_id")) + { + // causes asset loaded callback and an update + setEnvironment(ENV_LOCAL, env_data["water_id"].asUUID()); + valid = true; + assets_present = true; + } + else if (env_data.has("water_llsd")) + { + LLSettingsWater::ptr_t sky = LLSettingsVOWater::buildWater(env_data["water_llsd"]); + setEnvironment(ENV_LOCAL, sky); + valid = true; + } +} + +bool LLEnvironment::loadFromSettings() +{ + if (!gSavedSettings.getBOOL("EnvironmentPersistAcrossLogin")) + { + return false; + } + + std::string user_path = gDirUtilp->getLindenUserDir(); + if (user_path.empty()) + { + LL_WARNS("ENVIRONMENT") << "Can't load previous environment, Environment was initialized before user logged in" << LL_ENDL; + return false; + } + std::string user_filepath(user_path + gDirUtilp->getDirDelimiter() + LOCAL_ENV_STORAGE_FILE); + if (!gDirUtilp->fileExists(user_filepath)) + { + // No previous environment + return false; + } + + LLSD env_data; + llifstream file(user_filepath.c_str(), std::ios_base::in | std::ios_base::binary); + if (file.is_open()) + { + LLSDSerialize::fromBinary(env_data, file, LLSDSerialize::SIZE_UNLIMITED); + if (env_data.isUndefined()) + { + LL_WARNS("ENVIRONMENT") << "error loading " << user_filepath << LL_ENDL; + return false; + } + else + { + LL_INFOS("ENVIRONMENT") << "Loaded previous session environment from: " << user_filepath << LL_ENDL; + } + file.close(); + } + else + { + LL_INFOS("ENVIRONMENT") << "Unable to open previous session environment file " << user_filepath << LL_ENDL; + } + + if (!env_data.isMap() || (env_data.size() == 0)) + { + LL_DEBUGS("ENVIRONMENT") << "Empty map loaded from: " << user_filepath << LL_ENDL; + return false; + } + + bool valid = false; + bool has_assets = false; + + if (env_data.has("day_id")) + { + LLUUID assetId = env_data["day_id"].asUUID(); + + LLSettingsVOBase::getSettingsAsset(assetId, + [this, env_data](LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, LLExtStat) + { + // Day should be always applied first, + // otherwise it will override sky or water that was set earlier + // so wait for asset to load before applying sky/water + onSetEnvAssetLoaded(ENV_LOCAL, asset_id, settings, TRANSITION_DEFAULT, status, NO_VERSION); + bool valid = false, has_assets = false; + loadSkyWaterFromSettings(env_data, valid, has_assets); + if (!has_assets && valid) + { + // Settings were loaded from file without having an asset, needs update + // otherwise update will be done by asset callback + updateEnvironment(TRANSITION_DEFAULT, true); + } + }); + // bail early, everything have to be done at callback + return true; + } + else if (env_data.has("day_llsd")) + { + S32 length = env_data["day_length"].asInteger(); + S32 offset = env_data["day_offset"].asInteger(); + LLSettingsDay::ptr_t pday = LLSettingsVODay::buildDay(env_data["day_llsd"]); + setEnvironment(ENV_LOCAL, pday, LLSettingsDay::Seconds(length), LLSettingsDay::Seconds(offset)); + valid = true; + } + + loadSkyWaterFromSettings(env_data, valid, has_assets); + + if (valid && !has_assets) + { + // Settings were loaded from file without having an asset, needs update + // otherwise update will be done by asset callback + updateEnvironment(TRANSITION_DEFAULT, true); + } + return valid; +} + +void LLEnvironment::saveBeaconsState() +{ + if (mEditorCounter == 0) + { + mShowSunBeacon = gSavedSettings.getBOOL("sunbeacon"); + mShowMoonBeacon = gSavedSettings.getBOOL("moonbeacon"); + } + ++mEditorCounter; +} +void LLEnvironment::revertBeaconsState() +{ + --mEditorCounter; + if (mEditorCounter == 0) + { + gSavedSettings.setBOOL("sunbeacon", mShowSunBeacon && gSavedSettings.getBOOL("sunbeacon")); + gSavedSettings.setBOOL("moonbeacon", mShowMoonBeacon && gSavedSettings.getBOOL("moonbeacon")); + } +} + +//========================================================================= +LLTrackBlenderLoopingManual::LLTrackBlenderLoopingManual(const LLSettingsBase::ptr_t &target, const LLSettingsDay::ptr_t &day, S32 trackno) : + LLSettingsBlender(target, LLSettingsBase::ptr_t(), LLSettingsBase::ptr_t()), + mDay(day), + mTrackNo(trackno), + mPosition(0.0) +{ + LLSettingsDay::TrackBound_t initial = getBoundingEntries(mPosition); + + if (initial.first != mEndMarker) + { // No frames in track + mInitial = (*initial.first).second; + mFinal = (*initial.second).second; + + LLSD initSettings = mInitial->getSettings(); + mTarget->replaceSettings(initSettings); + } +} + +LLSettingsBase::BlendFactor LLTrackBlenderLoopingManual::setPosition(const LLSettingsBase::TrackPosition& position) +{ + mPosition = llclamp(position, 0.0f, 1.0f); + + LLSettingsDay::TrackBound_t bounds = getBoundingEntries(mPosition); + + if (bounds.first == mEndMarker) + { // No frames in track. + return 0.0; + } + + mInitial = (*bounds.first).second; + mFinal = (*bounds.second).second; + + F64 spanLength = getSpanLength(bounds); + + F64 spanPos = ((mPosition < (*bounds.first).first) ? (mPosition + 1.0) : mPosition) - (*bounds.first).first; + + if (spanPos > spanLength) + { + // we are clamping position to 0-1 and spanLength is 1 + // so don't account for case of spanPos == spanLength + spanPos = fmod(spanPos, spanLength); + } + + F64 blendf = spanPos / spanLength; + return LLSettingsBlender::setBlendFactor(blendf); +} + +void LLTrackBlenderLoopingManual::switchTrack(S32 trackno, const LLSettingsBase::TrackPosition& position) +{ + mTrackNo = trackno; + + LLSettingsBase::TrackPosition useposition = (position < 0.0) ? mPosition : position; + + setPosition(useposition); +} + +LLSettingsDay::TrackBound_t LLTrackBlenderLoopingManual::getBoundingEntries(F64 position) +{ + LLSettingsDay::CycleTrack_t &wtrack = mDay->getCycleTrack(mTrackNo); + + mEndMarker = wtrack.end(); + + LLSettingsDay::TrackBound_t bounds = get_bounding_entries(wtrack, position); + return bounds; +} + +F64 LLTrackBlenderLoopingManual::getSpanLength(const LLSettingsDay::TrackBound_t &bounds) const +{ + return get_wrapping_distance((*bounds.first).first, (*bounds.second).first); +} + +//========================================================================= +namespace +{ + DayInjection::DayInjection(LLEnvironment::EnvSelection_t env): + LLEnvironment::DayInstance(env), + mBaseDayInstance(), + mInjectedSky(), + mInjectedWater(), + mActiveExperiences(), + mDayExperience(), + mSkyExperience(), + mWaterExperience(), + mEnvChangeConnection(), + mParcelChangeConnection() + { + mInjectedSky = std::make_shared(LLEnvironment::instance().getCurrentSky()); + mInjectedWater = std::make_shared(LLEnvironment::instance().getCurrentWater()); + mBaseDayInstance = LLEnvironment::instance().getSharedEnvironmentInstance(); + mSky = mInjectedSky; + mWater = mInjectedWater; + + mEnvChangeConnection = LLEnvironment::instance().setEnvironmentChanged([this](LLEnvironment::EnvSelection_t env, S32) { onEnvironmentChanged(env); }); + mParcelChangeConnection = gAgent.addParcelChangedCallback([this]() { onParcelChange(); }); + } + + DayInjection::~DayInjection() + { + if (mEnvChangeConnection.connected()) + mEnvChangeConnection.disconnect(); + if (mParcelChangeConnection.connected()) + mParcelChangeConnection.disconnect(); + } + + + bool DayInjection::applyTimeDelta(const LLSettingsBase::Seconds& delta) + { + bool changed(false); + + if (mBaseDayInstance) + changed |= mBaseDayInstance->applyTimeDelta(delta); + mInjectedSky->applyInjections(delta); + mInjectedWater->applyInjections(delta); + changed |= LLEnvironment::DayInstance::applyTimeDelta(delta); + if (changed) + { + mInjectedSky->setDirtyFlag(true); + mInjectedWater->setDirtyFlag(true); + } + mInjectedSky->update(); + mInjectedWater->update(); + + if (!hasInjections()) + { // There are no injections being managed. This should really go away. + LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_PUSH); + LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT); + } + + return changed; + } + + void DayInjection::setBaseDayInstance(const LLEnvironment::DayInstance::ptr_t &baseday) + { + mBaseDayInstance = baseday; + + if (mSkyExperience.isNull()) + mInjectedSky->setSource(mBaseDayInstance->getSky()); + if (mWaterExperience.isNull()) + mInjectedWater->setSource(mBaseDayInstance->getWater()); + } + + + bool DayInjection::hasInjections() const + { + return (!mSkyExperience.isNull() || !mWaterExperience.isNull() || !mDayExperience.isNull() || + mBlenderSky || mBlenderWater || mInjectedSky->hasInjections() || mInjectedWater->hasInjections()); + } + + + void DayInjection::testExperiencesOnParcel(S32 parcel_id) + { + LLCoros::instance().launch("DayInjection::testExperiencesOnParcel", + [this, parcel_id]() { DayInjection::testExperiencesOnParcelCoro(std::static_pointer_cast(this->shared_from_this()), parcel_id); }); + + } + + void DayInjection::setInjectedDay(const LLSettingsDay::ptr_t &pday, LLUUID experience_id, LLSettingsBase::Seconds transition) + { + mSkyExperience = experience_id; + mWaterExperience = experience_id; + mDayExperience = experience_id; + + mBaseDayInstance = mBaseDayInstance->clone(); + mBaseDayInstance->setEnvironmentSelection(LLEnvironment::ENV_NONE); + mBaseDayInstance->setDay(pday, mBaseDayInstance->getDayLength(), mBaseDayInstance->getDayOffset()); + animateSkyChange(mBaseDayInstance->getSky(), transition); + animateWaterChange(mBaseDayInstance->getWater(), transition); + + mActiveExperiences.insert(experience_id); + } + + void DayInjection::setInjectedSky(const LLSettingsSky::ptr_t &psky, LLUUID experience_id, LLSettingsBase::Seconds transition) + { + mSkyExperience = experience_id; + mActiveExperiences.insert(experience_id); + checkExperience(); + animateSkyChange(psky, transition); + } + + void DayInjection::setInjectedWater(const LLSettingsWater::ptr_t &pwater, LLUUID experience_id, LLSettingsBase::Seconds transition) + { + mWaterExperience = experience_id; + mActiveExperiences.insert(experience_id); + checkExperience(); + animateWaterChange(pwater, transition); + } + + void DayInjection::injectSkySettings(LLSD settings, LLUUID experience_id, LLSettingsBase::Seconds transition) + { + mInjectedSky->injectExperienceValues(settings, experience_id, transition); + mActiveExperiences.insert(experience_id); + } + + void DayInjection::injectWaterSettings(LLSD settings, LLUUID experience_id, LLSettingsBase::Seconds transition) + { + mInjectedWater->injectExperienceValues(settings, experience_id, transition); + mActiveExperiences.insert(experience_id); + } + + void DayInjection::clearInjections(LLUUID experience_id, LLSettingsBase::Seconds transition_time) + { + if ((experience_id.isNull() && !mDayExperience.isNull()) || (experience_id == mDayExperience)) + { + mDayExperience.setNull(); + if (mSkyExperience == experience_id) + mSkyExperience.setNull(); + if (mWaterExperience == experience_id) + mWaterExperience.setNull(); + + mBaseDayInstance = LLEnvironment::instance().getSharedEnvironmentInstance(); + + if (mSkyExperience.isNull()) + animateSkyChange(mBaseDayInstance->getSky(), transition_time); + if (mWaterExperience.isNull()) + animateWaterChange(mBaseDayInstance->getWater(), transition_time); + } + + if ((experience_id.isNull() && !mSkyExperience.isNull()) || (experience_id == mSkyExperience)) + { + mSkyExperience.setNull(); + animateSkyChange(mBaseDayInstance->getSky(), transition_time); + } + if ((experience_id.isNull() && !mWaterExperience.isNull()) || (experience_id == mWaterExperience)) + { + mWaterExperience.setNull(); + animateWaterChange(mBaseDayInstance->getWater(), transition_time); + } + + mInjectedSky->removeInjections(experience_id, transition_time); + mInjectedWater->removeInjections(experience_id, transition_time); + + if (experience_id.isNull()) + mActiveExperiences.clear(); + else + mActiveExperiences.erase(experience_id); + + if ((transition_time == LLEnvironment::TRANSITION_INSTANT) && (countExperiencesActive() == 0)) + { // Only do this if instant and there are no other experiences injecting values. + // (otherwise will be handled after transition) + LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_PUSH); + LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT); + } + } + + + void DayInjection::testExperiencesOnParcelCoro(wptr_t that, S32 parcel_id) + { + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("testExperiencesOnParcelCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + std::string url = gAgent.getRegionCapability("ExperienceQuery"); + + if (url.empty()) + { + LL_WARNS("ENVIRONMENT") << "No experience query cap." << LL_ENDL; + return; // no checking in this region. + } + + { + ptr_t thatlock(that); + std::stringstream fullurl; + + if (!thatlock) + return; + + fullurl << url << "?"; + fullurl << "parcelid=" << parcel_id; + + for (auto it = thatlock->mActiveExperiences.begin(); it != thatlock->mActiveExperiences.end(); ++it) + { + if (it != thatlock->mActiveExperiences.begin()) + fullurl << ","; + else + fullurl << "&experiences="; + fullurl << (*it).asString(); + } + url = fullurl.str(); + } + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url); + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS() << "Unable to retrieve experience status for parcel." << LL_ENDL; + return; + } + + { + LLParcel* parcel = LLViewerParcelMgr::instance().getAgentParcel(); + if (!parcel) + return; + + if (parcel_id != parcel->getLocalID()) + { + // Agent no longer on queried parcel. + return; + } + } + + + LLSD experiences = result["experiences"]; + { + ptr_t thatlock(that); + if (!thatlock) + return; + + for (LLSD::map_iterator itr = experiences.beginMap(); itr != experiences.endMap(); ++itr) + { + if (!((*itr).second.asBoolean())) + thatlock->clearInjections(LLUUID((*itr).first), LLEnvironment::TRANSITION_FAST); + + } + } + } + + void DayInjection::animateSkyChange(LLSettingsSky::ptr_t psky, LLSettingsBase::Seconds transition) + { + if (mInjectedSky.get() == psky.get()) + { // An attempt to animate to itself... don't do it. + return; + } + if (transition == LLEnvironment::TRANSITION_INSTANT) + { + mBlenderSky.reset(); + mInjectedSky->setSource(psky); + } + else + { + LLSettingsSky::ptr_t start_sky(mInjectedSky->getSource()->buildClone()); + LLSettingsSky::ptr_t target_sky(start_sky->buildClone()); + mInjectedSky->setSource(target_sky); + + // clear reflection probes and pause updates during sky change + gPipeline.mReflectionMapManager.pause(); + gPipeline.mReflectionMapManager.reset(); + + mBlenderSky = std::make_shared(target_sky, start_sky, psky, transition); + mBlenderSky->setOnFinished( + [this, psky](LLSettingsBlender::ptr_t blender) + { + mBlenderSky.reset(); + mInjectedSky->setSource(psky); + + // resume updating reflection probes when done animating sky + gPipeline.mReflectionMapManager.resume(); + setSky(mInjectedSky); + if (!mBlenderWater && (countExperiencesActive() == 0)) + { + LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_PUSH); + LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT); + } + }); + } + } + + void DayInjection::animateWaterChange(LLSettingsWater::ptr_t pwater, LLSettingsBase::Seconds transition) + { + if (mInjectedWater.get() == pwater.get()) + { // An attempt to animate to itself. Bad idea. + return; + } + if (transition == LLEnvironment::TRANSITION_INSTANT) + { + mBlenderWater.reset(); + mInjectedWater->setSource(pwater); + } + else + { + LLSettingsWater::ptr_t start_Water(mInjectedWater->getSource()->buildClone()); + LLSettingsWater::ptr_t scratch_Water(start_Water->buildClone()); + mInjectedWater->setSource(scratch_Water); + + mBlenderWater = std::make_shared(scratch_Water, start_Water, pwater, transition); + mBlenderWater->setOnFinished( + [this, pwater](LLSettingsBlender::ptr_t blender) + { + mBlenderWater.reset(); + mInjectedWater->setSource(pwater); + setWater(mInjectedWater); + if (!mBlenderSky && (countExperiencesActive() == 0)) + { + LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_PUSH); + LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT); + } + }); + } + } + + void DayInjection::onEnvironmentChanged(LLEnvironment::EnvSelection_t env) + { + if (env >= LLEnvironment::ENV_PARCEL) + { + LLEnvironment::EnvSelection_t base_env(mBaseDayInstance->getEnvironmentSelection()); + LLEnvironment::DayInstance::ptr_t nextbase = LLEnvironment::instance().getSharedEnvironmentInstance(); + + if ((base_env == LLEnvironment::ENV_NONE) || (nextbase == mBaseDayInstance) || + (!mSkyExperience.isNull() && !mWaterExperience.isNull())) + { // base instance completely overridden, or not changed no transition will happen + return; + } + + LL_WARNS("PUSHENV", "ENVIRONMENT") << "Underlying environment has changed (" << env << ")! Base env is type " << base_env << LL_ENDL; + + LLEnvironment::DayInstance::ptr_t trans = std::make_shared(std::static_pointer_cast(shared_from_this()), + mBaseDayInstance->getSky(), mBaseDayInstance->getWater(), nextbase, LLEnvironment::TRANSITION_DEFAULT); + + trans->animate(); + setBaseDayInstance(trans); + } + } + + void DayInjection::onParcelChange() + { + S32 parcel_id(INVALID_PARCEL_ID); + LLParcel* parcel = LLViewerParcelMgr::instance().getAgentParcel(); + + if (!parcel) + return; + + parcel_id = parcel->getLocalID(); + + testExperiencesOnParcel(parcel_id); + } + + void DayInjection::checkExperience() + { + if ((!mDayExperience.isNull()) && (mSkyExperience != mDayExperience) && (mWaterExperience != mDayExperience)) + { // There was a day experience but we've replaced it with a water and a sky experience. + mDayExperience.setNull(); + mBaseDayInstance = LLEnvironment::instance().getSharedEnvironmentInstance(); + } + } + + void DayInjection::animate() + { + + } + + void InjectedTransition::animate() + { + mNextInstance->animate(); + + if (!mInjection->isOverriddenSky()) + { + mSky = mStartSky->buildClone(); + mBlenderSky = std::make_shared(mSky, mStartSky, mNextInstance->getSky(), mTransitionTime); + mBlenderSky->setOnFinished( + [this](LLSettingsBlender::ptr_t blender) { + mBlenderSky.reset(); + + if (!mBlenderSky && !mBlenderSky) + mInjection->setBaseDayInstance(mNextInstance); + else + mInjection->mInjectedSky->setSource(mNextInstance->getSky()); + }); + } + else + { + mSky = mInjection->getSky(); + mBlenderSky.reset(); + } + + if (!mInjection->isOverriddenWater()) + { + mWater = mStartWater->buildClone(); + mBlenderWater = std::make_shared(mWater, mStartWater, mNextInstance->getWater(), mTransitionTime); + mBlenderWater->setOnFinished( + [this](LLSettingsBlender::ptr_t blender) { + mBlenderWater.reset(); + + if (!mBlenderSky && !mBlenderWater) + mInjection->setBaseDayInstance(mNextInstance); + else + mInjection->mInjectedWater->setSource(mNextInstance->getWater()); + }); + } + else + { + mWater = mInjection->getWater(); + mBlenderWater.reset(); + } + + } + +} + -- cgit v1.2.3 From b42f9d836b4c0f7fbd4bdae1734021e2a09fdbe8 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sat, 1 Jun 2024 15:49:26 +0200 Subject: Re-enable a lot of compiler warnings for MSVC and address the C4267 "possible loss of precision" warnings --- indra/newview/llenvironment.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llenvironment.cpp') diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp index 775bcb3535..9d02cd1d10 100644 --- a/indra/newview/llenvironment.cpp +++ b/indra/newview/llenvironment.cpp @@ -757,7 +757,7 @@ namespace LLEnvironment::DayInstance::ptr_t getBaseDayInstance() const { return mBaseDayInstance; } void setBaseDayInstance(const LLEnvironment::DayInstance::ptr_t &baseday); - S32 countExperiencesActive() const { return mActiveExperiences.size(); } + S32 countExperiencesActive() const { return static_cast(mActiveExperiences.size()); } bool isOverriddenSky() const { return !mSkyExperience.isNull(); } bool isOverriddenWater() const { return !mWaterExperience.isNull(); } -- cgit v1.2.3 From c0fad3028fd55c2067ce6a0ae4382cffe1014284 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 10 Jun 2024 16:42:43 +0200 Subject: Re-enable compiler warnings C4018, C4100, C4231 and C4506 --- indra/newview/llenvironment.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview/llenvironment.cpp') diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp index 9d02cd1d10..5bee087b38 100644 --- a/indra/newview/llenvironment.cpp +++ b/indra/newview/llenvironment.cpp @@ -2508,7 +2508,7 @@ LLSettingsDay::ptr_t LLEnvironment::createDayCycleFromEnvironment(EnvSelection_t if (type == "sky") { - for (S32 idx = 1; idx < LLSettingsDay::TRACK_MAX; ++idx) + for (U32 idx = 1; idx < LLSettingsDay::TRACK_MAX; ++idx) day->clearCycleTrack(idx); day->setSettingsAtKeyframe(settings, 0.0f, 1); } -- cgit v1.2.3