diff options
Diffstat (limited to 'indra/newview/llenvironment.cpp')
-rw-r--r-- | indra/newview/llenvironment.cpp | 1325 |
1 files changed, 1325 insertions, 0 deletions
diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp new file mode 100644 index 0000000000..3451b0efef --- /dev/null +++ b/indra/newview/llenvironment.cpp @@ -0,0 +1,1325 @@ +/** + * @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 "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 <boost/make_shared.hpp> + +//define EXPORT_PRESETS 1 +//========================================================================= +namespace +{ + LLTrace::BlockTimerStatHandle FTM_ENVIRONMENT_UPDATE("Update Environment Tick"); + LLTrace::BlockTimerStatHandle FTM_SHADER_PARAM_UPDATE("Update Shader Parameters"); +} + +//========================================================================= +const F32Seconds LLEnvironment::TRANSITION_INSTANT(0.0f); +const F32Seconds LLEnvironment::TRANSITION_FAST(1.0f); +const F32Seconds LLEnvironment::TRANSITION_DEFAULT(5.0f); +const F32Seconds LLEnvironment::TRANSITION_SLOW(10.0f); + +const F32 LLEnvironment::SUN_DELTA_YAW(F_PI); // 180deg +const F32 LLEnvironment::NIGHTTIME_ELEVATION_COS(LLSky::NIGHTTIME_ELEVATION_COS); + +//------------------------------------------------------------------------- +LLEnvironment::LLEnvironment(): + mSelectedSky(), + mSelectedWater(), + mSelectedDay(), + mSkysById(), + mSkysByName(), + mWaterByName(), + mWaterById(), + mDayCycleByName(), + mDayCycleById(), + mUserPrefs(), + mSelectedEnvironment(ENV_LOCAL), + mDayLength(LLSettingsDay::DEFAULT_DAYLENGTH), + mDayOffset(LLSettingsDay::DEFAULT_DAYOFFSET) +{ + mSetSkys.resize(ENV_END); + mSetWater.resize(ENV_END); + mSetDays.resize(ENV_END); +} + +void LLEnvironment::initSingleton() +{ + LLSettingsSky::ptr_t p_default_sky = LLSettingsVOSky::buildDefaultSky(); + addSky(p_default_sky); + mCurrentSky = p_default_sky; + + LLSettingsWater::ptr_t p_default_water = LLSettingsVOWater::buildDefaultWater(); + addWater(p_default_water); + mCurrentWater = p_default_water; + + LLSettingsDay::ptr_t p_default_day = LLSettingsVODay::buildDefaultDayCycle(); + addDayCycle(p_default_day); + mCurrentDay.reset(); + + // LEGACY! + legacyLoadAllPresets(); + + requestRegionEnvironment(); + gAgent.addRegionChangedCallback(boost::bind(&LLEnvironment::onRegionChange, this)); + gAgent.addParcelChangedCallback(boost::bind(&LLEnvironment::onParcelChange, this)); +} + +LLEnvironment::~LLEnvironment() +{ +} + +void LLEnvironment::loadPreferences() +{ + mUserPrefs.load(); +} + +void LLEnvironment::updatePreferences() +{ + /*NOOP for now. TODO record prefs and store.*/ +} + +bool LLEnvironment::canEdit() const +{ + return true; +} + + +LLEnvironment::connection_t LLEnvironment::setSkyListChange(const LLEnvironment::change_signal_t::slot_type& cb) +{ + return mSkyListChange.connect(cb); +} + +LLEnvironment::connection_t LLEnvironment::setWaterListChange(const LLEnvironment::change_signal_t::slot_type& cb) +{ + return mWaterListChange.connect(cb); +} + +LLEnvironment::connection_t LLEnvironment::setDayCycleListChange(const LLEnvironment::change_signal_t::slot_type& cb) +{ + return mDayCycleListChange.connect(cb); +} + +void LLEnvironment::onRegionChange() +{ + requestRegionEnvironment(); +} + +void LLEnvironment::onParcelChange() +{ + S32 parcel_id(INVALID_PARCEL_ID); + LLParcel* parcel = LLViewerParcelMgr::instance().getAgentParcel(); + + if (parcel) + { + parcel_id = parcel->getLocalID(); + } + + requestParcel(parcel_id); +} + +void LLEnvironment::requestRegionEnvironment() +{ + requestRegion(); +} + +void LLEnvironment::onLegacyRegionSettings(LLSD data) +{ + LLUUID regionId = data[0]["regionID"].asUUID(); + + LLSettingsDay::ptr_t regionday; + if (data[1].isUndefined()) + regionday = LLEnvironment::findDayCycleByName("Default"); + else + regionday = LLSettingsVODay::buildFromLegacyMessage(regionId, data[1], data[2], data[3]); + + setSkyFor(ENV_REGION, LLSettingsSky::ptr_t()); + setWaterFor(ENV_REGION, LLSettingsWater::ptr_t()); + setDayFor(ENV_REGION, regionday); + + applyChosenEnvironment(); +} + +//------------------------------------------------------------------------- +F32 LLEnvironment::getCamHeight() const +{ + return (mCurrentSky->getDomeOffset() * mCurrentSky->getDomeRadius()); +} + +F32 LLEnvironment::getWaterHeight() const +{ + return gAgent.getRegion()->getWaterHeight(); +} + +bool LLEnvironment::getIsDayTime() const +{ + return mCurrentSky->getSunDirection().mV[2] > NIGHTTIME_ELEVATION_COS; +} + +void LLEnvironment::setDayLength(S64Seconds seconds) +{ + mDayLength = seconds; + if (mCurrentDay) + mCurrentDay->setDayLength(mDayLength); +} + +void LLEnvironment::setDayOffset(S64Seconds seconds) +{ + mDayOffset = seconds; + if (mCurrentDay) + mCurrentDay->setDayOffset(seconds); +} + +//------------------------------------------------------------------------- +void LLEnvironment::update(const LLViewerCamera * cam) +{ + LL_RECORD_BLOCK_TIME(FTM_ENVIRONMENT_UPDATE); + //F32Seconds now(LLDate::now().secondsSinceEpoch()); + static LLFrameTimer timer; + + F32Seconds delta(timer.getElapsedTimeAndResetF32()); + + if (mBlenderSky) + mBlenderSky->update(delta); + if (mBlenderWater) + mBlenderWater->update(delta); + + // update clouds, sun, and general + updateCloudScroll(); + + if (mCurrentDay) + mCurrentDay->update(); + + if (mCurrentSky) + mCurrentSky->update(); + if (mCurrentWater) + mCurrentWater->update(); + + F32 camYaw = cam->getYaw(); + + stop_glerror(); + + // *TODO: potential optimization - this block may only need to be + // executed some of the time. For example for water shaders only. + { + LLVector3 lightNorm3( getLightDirection() ); + + lightNorm3 *= LLQuaternion(-(camYaw + SUN_DELTA_YAW), LLVector3(0.f, 1.f, 0.f)); + mRotatedLight = LLVector4(lightNorm3, 0.f); + + 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(); + + LLVector2 cloud_delta = static_cast<F32>(delta_t)* (mCurrentSky->getCloudScrollRate() - LLVector2(10.0, 10.0)) / 100.0; + mCloudScrollDelta += cloud_delta; + + + +} + +void LLEnvironment::updateGLVariablesForSettings(LLGLSLShader *shader, const LLSettingsBase::ptr_t &psetting) +{ + LL_RECORD_BLOCK_TIME(FTM_SHADER_PARAM_UPDATE); + + //_WARNS("RIDER") << "----------------------------------------------------------------" << LL_ENDL; + LLSettingsBase::parammapping_t params = psetting->getParameterMap(); + for (LLSettingsBase::parammapping_t::iterator it = params.begin(); it != params.end(); ++it) + { + if (!psetting->mSettings.has((*it).first)) + continue; + + LLSD value = psetting->mSettings[(*it).first]; + LLSD::Type setting_type = value.type(); + + stop_glerror(); + switch (setting_type) + { + case LLSD::TypeInteger: + shader->uniform1i((*it).second, value.asInteger()); + //_WARNS("RIDER") << "pushing '" << (*it).first << "' as " << value << LL_ENDL; + break; + case LLSD::TypeReal: + shader->uniform1f((*it).second, value.asReal()); + //_WARNS("RIDER") << "pushing '" << (*it).first << "' as " << value << LL_ENDL; + break; + + case LLSD::TypeBoolean: + shader->uniform1i((*it).second, value.asBoolean() ? 1 : 0); + //_WARNS("RIDER") << "pushing '" << (*it).first << "' as " << value << LL_ENDL; + break; + + case LLSD::TypeArray: + { + LLVector4 vect4(value); + //_WARNS("RIDER") << "pushing '" << (*it).first << "' as " << vect4 << LL_ENDL; + shader->uniform4fv((*it).second, 1, vect4.mV); + + break; + } + + // case LLSD::TypeMap: + // case LLSD::TypeString: + // case LLSD::TypeUUID: + // case LLSD::TypeURI: + // case LLSD::TypeBinary: + // case LLSD::TypeDate: + default: + break; + } + stop_glerror(); + } + //_WARNS("RIDER") << "----------------------------------------------------------------" << LL_ENDL; + + psetting->applySpecial(shader); + + if (LLPipeline::sRenderDeferred && !LLPipeline::sReflectionRender && !LLPipeline::sUnderWaterRender) + { + shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 2.2); + } + else + { + shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 1.0); + } + +} + +void LLEnvironment::updateShaderUniforms(LLGLSLShader *shader) +{ + + if (gPipeline.canUseWindLightShaders()) + { + updateGLVariablesForSettings(shader, mCurrentSky); + updateGLVariablesForSettings(shader, mCurrentWater); + } + + if (shader->mShaderGroup == LLGLSLShader::SG_DEFAULT) + { + stop_glerror(); + shader->uniform4fv(LLShaderMgr::LIGHTNORM, 1, mRotatedLight.mV); + shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV); + stop_glerror(); + } + else if (shader->mShaderGroup == LLGLSLShader::SG_SKY) + { + stop_glerror(); + shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, getClampedLightDirection().mV); + stop_glerror(); + } + + shader->uniform1f(LLShaderMgr::SCENE_LIGHT_STRENGTH, getSceneLightStrength()); + + +} +//-------------------------------------------------------------------------- +void LLEnvironment::selectSky(const std::string &name, F32Seconds transition) +{ + LLSettingsSky::ptr_t next_sky = findSkyByName(name); + if (!next_sky) + { + LL_WARNS("ENVIRONMENT") << "Unable to select sky with unknown name '" << name << "'" << LL_ENDL; + return; + } + + selectSky(next_sky, transition); +} + +void LLEnvironment::selectSky(const LLSettingsSky::ptr_t &sky, F32Seconds transition) +{ + if (!sky) + { + mCurrentSky = mSelectedSky; + mBlenderSky.reset(); + return; + } + mSelectedSky = sky; + if (fabs(transition.value()) <= F_ALMOST_ZERO) + { + mBlenderSky.reset(); + mCurrentSky = sky; + mCurrentSky->setDirtyFlag(true); + mSelectedSky = sky; + } + else + { + LLSettingsSky::ptr_t skytarget = mCurrentSky->buildClone(); + + mBlenderSky = boost::make_shared<LLSettingsBlender>( skytarget, mCurrentSky, sky, transition ); + mBlenderSky->setOnFinished(boost::bind(&LLEnvironment::onSkyTransitionDone, this, _1)); + mCurrentSky = skytarget; + mSelectedSky = sky; + } +} + +void LLEnvironment::onSkyTransitionDone(const LLSettingsBlender::ptr_t &blender) +{ + mCurrentSky = mSelectedSky; + mBlenderSky.reset(); +} + +void LLEnvironment::selectWater(const std::string &name, F32Seconds transition) +{ + LLSettingsWater::ptr_t next_water = findWaterByName(name); + + if (!next_water) + { + LL_WARNS("ENVIRONMENT") << "Unable to select water with unknown name '" << name << "'" << LL_ENDL; + return; + } + + selectWater(next_water, transition); +} + +void LLEnvironment::selectWater(const LLSettingsWater::ptr_t &water, F32Seconds transition) +{ + if (!water) + { + mCurrentWater = mSelectedWater; + mBlenderWater.reset(); + return; + } + mSelectedWater = water; + if (fabs(transition.value()) <= F_ALMOST_ZERO) + { + mBlenderWater.reset(); + mCurrentWater = water; + mCurrentWater->setDirtyFlag(true); + mSelectedWater = water; + } + else + { + LLSettingsWater::ptr_t watertarget = mCurrentWater->buildClone(); + + mBlenderWater = boost::make_shared<LLSettingsBlender>(watertarget, mCurrentWater, water, transition); + mBlenderWater->setOnFinished(boost::bind(&LLEnvironment::onWaterTransitionDone, this, _1)); + mCurrentWater = watertarget; + mSelectedWater = water; + } +} + +void LLEnvironment::onWaterTransitionDone(const LLSettingsBlender::ptr_t &blender) +{ + mCurrentWater = mSelectedWater; + mBlenderWater.reset(); +} + +void LLEnvironment::selectDayCycle(const std::string &name, F32Seconds transition) +{ + LLSettingsDay::ptr_t next_daycycle = findDayCycleByName(name); + + if (!next_daycycle) + { + LL_WARNS("ENVIRONMENT") << "Unable to select daycycle with unknown name '" << name << "'" << LL_ENDL; + return; + } + + selectDayCycle(next_daycycle, transition); +} + +void LLEnvironment::selectDayCycle(const LLSettingsDay::ptr_t &daycycle, F32Seconds transition) +{ + if (!daycycle || (daycycle == mCurrentDay)) + { + return; + } + + mCurrentDay = daycycle; + mCurrentDay->setDayLength(mDayLength); + mCurrentDay->setDayOffset(mDayOffset); + + daycycle->startDayCycle(); + selectWater(daycycle->getCurrentWater(), transition); + selectSky(daycycle->getCurrentSky(), transition); +} + + +void LLEnvironment::setSelectedEnvironment(EnvSelection_t env) +{ + if (env == mSelectedEnvironment) + { // No action to take + return; + } + + mSelectedEnvironment = env; + applyChosenEnvironment(); +} + +void LLEnvironment::applyChosenEnvironment() +{ + mSelectedSky.reset(); + mSelectedWater.reset(); + mSelectedDay.reset(); + + for (S32 idx = mSelectedEnvironment; idx < ENV_END; ++idx) + { + if (mSetDays[idx] && !mSelectedSky && !mSelectedWater) + selectDayCycle(mSetDays[idx]); + if (mSetSkys[idx] && !mSelectedSky) + selectSky(mSetSkys[idx]); + if (mSetWater[idx] && !mSelectedWater) + selectWater(mSetWater[idx]); + if (mSelectedSky && mSelectedWater) + return; + } + + if (!mSelectedSky) + selectSky("Default"); + if (!mSelectedWater) + selectWater("Default"); +} + +LLSettingsSky::ptr_t LLEnvironment::getChosenSky() const +{ + for (S32 idx = mSelectedEnvironment; idx < ENV_END; ++idx) + { + if (mSetSkys[idx]) + return mSetSkys[idx]; + } + + return LLSettingsSky::ptr_t(); +} + +LLSettingsWater::ptr_t LLEnvironment::getChosenWater() const +{ + for (S32 idx = mSelectedEnvironment; idx < ENV_END; ++idx) + { + if (mSetWater[idx]) + return mSetWater[idx]; + } + + return LLSettingsWater::ptr_t(); +} + +LLSettingsDay::ptr_t LLEnvironment::getChosenDay() const +{ + for (S32 idx = mSelectedEnvironment; idx < ENV_END; ++idx) + { + if (mSetDays[idx]) + return mSetDays[idx]; + } + + return LLSettingsDay::ptr_t(); +} + +void LLEnvironment::setSkyFor(EnvSelection_t env, const LLSettingsSky::ptr_t &sky) +{ + mSetSkys[env] = sky; +} + +LLSettingsSky::ptr_t LLEnvironment::getSkyFor(EnvSelection_t env) const +{ + return mSetSkys[env]; +} + +void LLEnvironment::setWaterFor(EnvSelection_t env, const LLSettingsWater::ptr_t &water) +{ + mSetWater[env] = water; +} + +LLSettingsWater::ptr_t LLEnvironment::getWaterFor(EnvSelection_t env) const +{ + return mSetWater[env]; +} + +void LLEnvironment::setDayFor(EnvSelection_t env, const LLSettingsDay::ptr_t &day) +{ + mSetDays[env] = day; +} + +LLSettingsDay::ptr_t LLEnvironment::getDayFor(EnvSelection_t env) const +{ + return mSetDays[env]; +} + +void LLEnvironment::clearUserSettings() +{ + mSetSkys[ENV_LOCAL].reset(); + mSetWater[ENV_LOCAL].reset(); + mSetDays[ENV_LOCAL].reset(); +} + + +LLEnvironment::list_name_id_t LLEnvironment::getSkyList() const +{ + list_name_id_t list; + + list.reserve(mSkysByName.size()); + + for (namedSettingMap_t::const_iterator it = mSkysByName.begin(); it != mSkysByName.end(); ++it) + { + list.push_back(std::vector<name_id_t>::value_type((*it).second->getName(), (*it).second->getId())); + } + + return list; +} + +LLEnvironment::list_name_id_t LLEnvironment::getWaterList() const +{ + list_name_id_t list; + + list.reserve(mWaterByName.size()); + + for (namedSettingMap_t::const_iterator it = mWaterByName.begin(); it != mWaterByName.end(); ++it) + { + list.push_back(std::vector<name_id_t>::value_type((*it).second->getName(), (*it).second->getId())); + } + + return list; +} + +LLEnvironment::list_name_id_t LLEnvironment::getDayCycleList() const +{ + list_name_id_t list; + + list.reserve(mDayCycleByName.size()); + + for (namedSettingMap_t::const_iterator it = mDayCycleByName.begin(); it != mDayCycleByName.end(); ++it) + { + list.push_back(std::vector<name_id_t>::value_type((*it).second->getName(), (*it).second->getId())); + } + + return list; +} + +void LLEnvironment::addSky(const LLSettingsSky::ptr_t &sky) +{ + std::string name = sky->getValue(LLSettingsSky::SETTING_NAME).asString(); + + LL_WARNS("RIDER") << "Adding sky as '" << name << "'" << LL_ENDL; + + std::pair<namedSettingMap_t::iterator, bool> result; + result = mSkysByName.insert(namedSettingMap_t::value_type(name, sky)); + + if (!result.second) + (*(result.first)).second = sky; + mSkyListChange(); +} + +void LLEnvironment::removeSky(const std::string &name) +{ + namedSettingMap_t::iterator it = mSkysByName.find(name); + if (it != mSkysByName.end()) + mSkysByName.erase(it); + mSkyListChange(); +} + +void LLEnvironment::clearAllSkys() +{ + mSkysByName.clear(); + mSkysById.clear(); + mSkyListChange(); +} + +void LLEnvironment::addWater(const LLSettingsWater::ptr_t &water) +{ + std::string name = water->getValue(LLSettingsWater::SETTING_NAME).asString(); + + LL_WARNS("RIDER") << "Adding water as '" << name << "'" << LL_ENDL; + + std::pair<namedSettingMap_t::iterator, bool> result; + result = mWaterByName.insert(namedSettingMap_t::value_type(name, water)); + + if (!result.second) + (*(result.first)).second = water; + mWaterListChange(); +} + + +void LLEnvironment::removeWater(const std::string &name) +{ + namedSettingMap_t::iterator it = mWaterByName.find(name); + if (it != mWaterByName.end()) + mWaterByName.erase(it); + mWaterListChange(); +} + +void LLEnvironment::clearAllWater() +{ + mWaterByName.clear(); + mWaterById.clear(); + mWaterListChange(); +} + +void LLEnvironment::addDayCycle(const LLSettingsDay::ptr_t &daycycle) +{ + std::string name = daycycle->getValue(LLSettingsDay::SETTING_NAME).asString(); + + LL_WARNS("RIDER") << "Adding daycycle as '" << name << "'" << LL_ENDL; + + std::pair<namedSettingMap_t::iterator, bool> result; + result = mDayCycleByName.insert(namedSettingMap_t::value_type(name, daycycle)); + + if (!result.second) + (*(result.first)).second = daycycle; + mDayCycleListChange(); +} + +//void LLEnvironment::addDayCycle(const LLUUID &id, const LLSettingsSky::ptr_t &sky); + +void LLEnvironment::removeDayCycle(const std::string &name) +{ + namedSettingMap_t::iterator it = mDayCycleByName.find(name); + if (it != mDayCycleByName.end()) + mDayCycleByName.erase(it); + mDayCycleListChange(); +} + +//void LLEnvironment::removeDayCycle(const LLUUID &id); +void LLEnvironment::clearAllDayCycles() +{ + mDayCycleByName.clear(); + mWaterById.clear(); + mDayCycleListChange(); +} + +LLSettingsSky::ptr_t LLEnvironment::findSkyByName(std::string name) const +{ + namedSettingMap_t::const_iterator it = mSkysByName.find(name); + + if (it == mSkysByName.end()) + { + LL_WARNS("ENVIRONMENT") << "Unable to find sky with unknown name '" << name << "'" << LL_ENDL; + return LLSettingsSky::ptr_t(); + } + + return boost::static_pointer_cast<LLSettingsSky>((*it).second); +} + +LLSettingsWater::ptr_t LLEnvironment::findWaterByName(std::string name) const +{ + namedSettingMap_t::const_iterator it = mWaterByName.find(name); + + if (it == mWaterByName.end()) + { + LL_WARNS("ENVIRONMENT") << "Unable to find water with unknown name '" << name << "'" << LL_ENDL; + return LLSettingsWater::ptr_t(); + } + + return boost::static_pointer_cast<LLSettingsWater>((*it).second); +} + +LLSettingsDay::ptr_t LLEnvironment::findDayCycleByName(std::string name) const +{ + namedSettingMap_t::const_iterator it = mDayCycleByName.find(name); + + if (it == mDayCycleByName.end()) + { + LL_WARNS("ENVIRONMENT") << "Unable to find daycycle with unknown name '" << name << "'" << LL_ENDL; + return LLSettingsDay::ptr_t(); + } + + return boost::static_pointer_cast<LLSettingsDay>((*it).second); +} + + +void LLEnvironment::selectAgentEnvironment() +{ + S64Seconds day_length(LLSettingsDay::DEFAULT_DAYLENGTH); + S64Seconds day_offset(LLSettingsDay::DEFAULT_DAYOFFSET); + LLSettingsDay::ptr_t pday; + + // TODO: First test if agent has local environment set. + + LLParcel *parcel = LLViewerParcelMgr::instance().getAgentParcel(); + LLViewerRegion *pRegion = gAgent.getRegion(); + + if (!parcel || parcel->getUsesDefaultDayCycle() || !parcel->getParcelDayCycle()) + { + day_length = pRegion->getDayLength(); + day_offset = pRegion->getDayOffset(); + pday = pRegion->getRegionDayCycle(); + } + else + { + day_length = parcel->getDayLength(); + day_offset = parcel->getDayOffset(); + pday = parcel->getParcelDayCycle(); + } + + if (getDayLength() != day_length) + setDayLength(day_length); + + if (getDayOffset() != day_offset) + setDayOffset(day_offset); + + if (pday) + selectDayCycle(pday); + +} + +void LLEnvironment::recordEnvironment(S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envinfo) +{ + LL_WARNS("ENVIRONMENT") << "Have environment" << LL_ENDL; + + if (parcel_id == INVALID_PARCEL_ID) + { + LLViewerRegion *pRegion = gAgent.getRegion(); + + if (pRegion) + { + pRegion->setDayLength(envinfo->mDayLength); + pRegion->setDayOffset(envinfo->mDayOffset); + pRegion->setIsDefaultDayCycle(envinfo->mIsDefault); + pRegion->setRegionDayCycle(LLSettingsVODay::buildFromEnvironmentMessage(envinfo->mDaycycleData)); + + /*TODO: track_altitudes*/ + } + } + else + { + LLParcel *parcel = LLViewerParcelMgr::instance().getAgentParcel(); + + if (parcel->getLocalID() == parcel_id) + { + parcel->setDayLength(envinfo->mDayLength); + parcel->setDayOffset(envinfo->mDayOffset); + parcel->setUsesDefaultDayCycle(envinfo->mIsDefault); + + LLSettingsDay::ptr_t pday; + if (!envinfo->mIsDefault) + { + pday = LLSettingsVODay::buildFromEnvironmentMessage(envinfo->mDaycycleData); + } + parcel->setParcelDayCycle(pday); + + // select parcel day + } + } + + selectAgentEnvironment(); +} + +//========================================================================= +void LLEnvironment::requestRegion() +{ + if (gAgent.getRegionCapability("ExtEnvironment").empty()) + { + LLEnvironmentRequest::initiate(); + return; + } + + requestParcel(INVALID_PARCEL_ID); +} + +void LLEnvironment::updateRegion(LLSettingsDay::ptr_t &pday, S32 day_length, S32 day_offset) +{ + if (gAgent.getRegionCapability("ExtEnvironment").empty()) + { + LLEnvironmentApply::initiateRequest( LLSettingsVODay::convertToLegacy(pday) ); + return; + } + + updateParcel(INVALID_PARCEL_ID, pday, day_length, day_offset); +} + +void LLEnvironment::resetRegion() +{ + resetParcel(INVALID_PARCEL_ID); +} + +void LLEnvironment::requestParcel(S32 parcel_id) +{ + environment_apply_fn apply = boost::bind(&LLEnvironment::recordEnvironment, this, _1, _2); + + std::string coroname = + LLCoros::instance().launch("LLEnvironment::coroRequestEnvironment", + boost::bind(&LLEnvironment::coroRequestEnvironment, this, parcel_id, apply)); + +} + +void LLEnvironment::updateParcel(S32 parcel_id, LLSettingsDay::ptr_t &pday, S32 day_length, S32 day_offset) +{ + environment_apply_fn apply = boost::bind(&LLEnvironment::recordEnvironment, this, _1, _2); + + std::string coroname = + LLCoros::instance().launch("LLEnvironment::coroUpdateEnvironment", + boost::bind(&LLEnvironment::coroUpdateEnvironment, this, parcel_id, + pday, day_length, day_offset, apply)); + +} + +void LLEnvironment::resetParcel(S32 parcel_id) +{ + environment_apply_fn apply = boost::bind(&LLEnvironment::recordEnvironment, this, _1, _2); + + std::string coroname = + LLCoros::instance().launch("LLEnvironment::coroResetEnvironment", + boost::bind(&LLEnvironment::coroResetEnvironment, this, parcel_id, apply)); +} + +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_WARNS("LAPRAS") << "Requesting for parcel_id=" << parcel_id << LL_ENDL; + + if (parcel_id != INVALID_PARCEL_ID) + { + std::stringstream query; + + query << "?parcelid=" << parcel_id; + url += query.str(); + } + + LL_WARNS("LAPRAS") << "url=" << url << LL_ENDL; + + LLSD result = httpAdapter->getAndSuspend(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) + { + LL_WARNS("WindlightCaps") << "Couldn't retrieve Windlight settings for " << ((parcel_id == INVALID_PARCEL_ID) ? ("region!") : ("parcel!")) << LL_ENDL; + + std::stringstream msg; + msg << status.toString() << " (Code " << status.toTerseString() << ")"; + notify = LLSD::emptyMap(); + notify["FAIL_REASON"] = msg.str(); + + } + else + { + LLSD environment = result["environment"]; + if (environment.isDefined() && !apply.empty()) + { + 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::coroUpdateEnvironment(S32 parcel_id, LLSettingsDay::ptr_t pday, S32 day_length, S32 day_offset, 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; + + LLSD body(LLSD::emptyMap()); + body["environment"] = LLSD::emptyMap(); + + if (day_length >= 0) + body["environment"]["day_length"] = day_length; + if (day_offset >= 0) + body["environment"]["day_offset"] = day_offset; + if (pday) + body["environment"]["day_cycle"] = pday->getSettings(); + + LL_WARNS("LAPRAS") << "Body = " << body << LL_ENDL; + + if (parcel_id != INVALID_PARCEL_ID) + { + std::stringstream query; + + query << "?parcelid=" << parcel_id; + url += query.str(); + } + + LL_WARNS("LAPRAS") << "url=" << url << LL_ENDL; + + 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) + { + LL_WARNS("WindlightCaps") << "Couldn't update Windlight settings for " << ((parcel_id == INVALID_PARCEL_ID) ? ("region!") : ("parcel!")) << LL_ENDL; + + std::stringstream msg; + msg << status.toString() << " (Code " << status.toTerseString() << ")"; + notify = LLSD::emptyMap(); + notify["FAIL_REASON"] = msg.str(); + } + else + { + LLSD environment = result["environment"]; + if (environment.isDefined() && !apply.empty()) + { + 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, 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) + { + std::stringstream query; + + query << "?parcelid=" << parcel_id; + url += query.str(); + } + + LL_WARNS("LAPRAS") << "url=" << url << LL_ENDL; + + 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) + { + LL_WARNS("WindlightCaps") << "Couldn't reset Windlight settings in " << ((parcel_id == INVALID_PARCEL_ID) ? ("region!") : ("parcel!")) << LL_ENDL; + + std::stringstream msg; + msg << status.toString() << " (Code " << status.toTerseString() << ")"; + notify = LLSD::emptyMap(); + notify["FAIL_REASON"] = msg.str(); + + } + else + { + LLSD environment = result["environment"]; + if (environment.isDefined() && !apply.empty()) + { + EnvironmentInfo::ptr_t envinfo = LLEnvironment::EnvironmentInfo::extract(environment); + apply(parcel_id, envinfo); + } + } + + if (!notify.isUndefined()) + { + LLNotificationsUtil::add("WLRegionApplyFail", notify); + //LLEnvManagerNew::instance().onRegionSettingsApplyResponse(false); + } + +} + + +//========================================================================= +LLEnvironment::UserPrefs::UserPrefs(): + mUseRegionSettings(true), + mUseDayCycle(true), + mPersistEnvironment(false), + mWaterPresetName(), + mSkyPresetName(), + mDayCycleName() +{} + + +void LLEnvironment::UserPrefs::load() +{ + mPersistEnvironment = gSavedSettings.getBOOL("EnvironmentPersistAcrossLogin"); + + mWaterPresetName = gSavedSettings.getString("WaterPresetName"); + mSkyPresetName = gSavedSettings.getString("SkyPresetName"); + mDayCycleName = gSavedSettings.getString("DayCycleName"); + + mUseRegionSettings = mPersistEnvironment ? gSavedSettings.getBOOL("UseEnvironmentFromRegion") : true; + mUseDayCycle = mPersistEnvironment ? gSavedSettings.getBOOL("UseDayCycle") : true; +} + +void LLEnvironment::UserPrefs::store() +{ + gSavedSettings.setBOOL("EnvironmentPersistAcrossLogin", mPersistEnvironment); + if (mPersistEnvironment) + { + gSavedSettings.setString("WaterPresetName", getWaterPresetName()); + gSavedSettings.setString("SkyPresetName", getSkyPresetName()); + gSavedSettings.setString("DayCycleName", getDayCycleName()); + + gSavedSettings.setBOOL("UseEnvironmentFromRegion", getUseRegionSettings()); + gSavedSettings.setBOOL("UseDayCycle", getUseDayCycle()); + } +} + +LLEnvironment::EnvironmentInfo::EnvironmentInfo(): + mParcelId(), + mDayLength(LLSettingsDay::DEFAULT_DAYLENGTH), + mDayOffset(LLSettingsDay::DEFAULT_DAYOFFSET), + mDaycycleData(), + mAltitudes(), + mIsDefault(false) +{ +} + +LLEnvironment::EnvironmentInfo::ptr_t LLEnvironment::EnvironmentInfo::extract(LLSD environment) +{ + ptr_t pinfo = boost::make_shared<EnvironmentInfo>(); + + if (environment.has("parcel_id")) + pinfo->mParcelId = environment["parcel_id"].asUUID(); + if (environment.has("day_length")) + pinfo->mDayLength = S64Seconds(environment["day_length"].asInteger()); + if (environment.has("day_offset")) + pinfo->mDayOffset = S64Seconds(environment["day_offset"].asInteger()); + if (environment.has("day_cycle")) + pinfo->mDaycycleData = environment["day_cycle"]; + if (environment.has("is_default")) + pinfo->mIsDefault = environment["is_default"].asBoolean(); + if (environment.has("track_altitudes")) + pinfo->mAltitudes = environment["track_altitudes"]; + + return pinfo; +} + +//========================================================================= +// Transitional Code. +// static +std::string LLEnvironment::getSysDir(const std::string &subdir) +{ + return gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight\\"+subdir, ""); +} + +// static +std::string LLEnvironment::getUserDir(const std::string &subdir) +{ + return gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "windlight\\"+subdir, ""); +} + +LLSD LLEnvironment::legacyLoadPreset(const std::string& path) +{ + llifstream xml_file; + std::string name(gDirUtilp->getBaseFileName(LLURI::unescape(path), /*strip_exten = */ true)); + + xml_file.open(path.c_str()); + if (!xml_file) + { + return LLSD(); + } + + LLSD params_data; + LLPointer<LLSDParser> parser = new LLSDXMLParser(); + parser->parse(xml_file, params_data, LLSDSerialize::SIZE_UNLIMITED); + xml_file.close(); + + return params_data; +} + +void LLEnvironment::legacyLoadAllPresets() +{ + std::string dir; + std::string file; + + // System skies + { + dir = getSysDir("skies"); + LLDirIterator dir_iter(dir, "*.xml"); + while (dir_iter.next(file)) + { + std::string path = gDirUtilp->add(dir, file); + + LLSD data = legacyLoadPreset(path); + if (data) + { + std::string name(gDirUtilp->getBaseFileName(LLURI::unescape(path), true)); + + LLSettingsSky::ptr_t sky = LLSettingsVOSky::buildFromLegacyPreset(name, data); + LLEnvironment::instance().addSky(sky); + } + } + } + + // User skies + { + dir = getUserDir("skies"); + LLDirIterator dir_iter(dir, "*.xml"); + while (dir_iter.next(file)) + { + std::string path = gDirUtilp->add(dir, file); + + LLSD data = legacyLoadPreset(path); + if (data) + { + std::string name(gDirUtilp->getBaseFileName(LLURI::unescape(path), true)); + + LLSettingsSky::ptr_t sky = LLSettingsVOSky::buildFromLegacyPreset(name, data); + LLEnvironment::instance().addSky(sky); + } + } + } + + // System water + { + dir = getSysDir("water"); + LLDirIterator dir_iter(dir, "*.xml"); + while (dir_iter.next(file)) + { + std::string path = gDirUtilp->add(dir, file); + + LLSD data = legacyLoadPreset(path); + if (data) + { + std::string name(gDirUtilp->getBaseFileName(LLURI::unescape(path), true)); + + LLSettingsWater::ptr_t water = LLSettingsVOWater::buildFromLegacyPreset(name, data); + LLEnvironment::instance().addWater(water); + } + } + } + + // User water + { + dir = getUserDir("water"); + LLDirIterator dir_iter(dir, "*.xml"); + while (dir_iter.next(file)) + { + std::string path = gDirUtilp->add(dir, file); + + LLSD data = legacyLoadPreset(path); + if (data) + { + std::string name(gDirUtilp->getBaseFileName(LLURI::unescape(path), true)); + + LLSettingsWater::ptr_t water = LLSettingsVOWater::buildFromLegacyPreset(name, data); + LLEnvironment::instance().addWater(water); + } + } + } + + // System water + { + dir = getSysDir("days"); + LLDirIterator dir_iter(dir, "*.xml"); + while (dir_iter.next(file)) + { + std::string path = gDirUtilp->add(dir, file); + + LLSD data = legacyLoadPreset(path); + if (data) + { + std::string name(gDirUtilp->getBaseFileName(LLURI::unescape(path), true)); + + LLSettingsDay::ptr_t day = LLSettingsVODay::buildFromLegacyPreset(name, data); + LLEnvironment::instance().addDayCycle(day); + +#ifdef EXPORT_PRESETS + std::string exportfile = LLURI::escape(name) + "(new).xml"; + std::string exportpath = gDirUtilp->add(getSysDir("new"), exportfile); + + LLSD settings = day->getSettings(); + + std::ofstream daycyclefile(exportpath); + LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter(); + formatter->format(settings, daycyclefile, LLSDFormatter::OPTIONS_PRETTY); + daycyclefile.close(); +#endif + } + } + } + + // User water + { + dir = getUserDir("days"); + LLDirIterator dir_iter(dir, "*.xml"); + while (dir_iter.next(file)) + { + std::string path = gDirUtilp->add(dir, file); + + LLSD data = legacyLoadPreset(path); + if (data) + { + std::string name(gDirUtilp->getBaseFileName(LLURI::unescape(path), true)); + + LLSettingsDay::ptr_t day = LLSettingsVODay::buildFromLegacyPreset(name, data); + LLEnvironment::instance().addDayCycle(day); + } + } + } +} |