phoenix-firestorm/indra/newview/llsettingsvo.cpp

1570 lines
57 KiB
C++

/**
* @file llsettingsvo.cpp
* @author Rider Linden
* @brief Subclasses for viewer specific settings behaviors.
*
* $LicenseInfo:2011&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2017, 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 "llviewercontrol.h"
#include "llsettingsvo.h"
#include "pipeline.h"
#include <algorithm>
#include <cstdio>
#include <boost/make_shared.hpp>
#include "lltrace.h"
#include "llfasttimer.h"
#include "v3colorutil.h"
#include "llglslshader.h"
#include "llviewershadermgr.h"
#include "llagent.h"
#include "llassettype.h"
#include "llfloaterperms.h"
#include "llnotificationsutil.h"
#include "llviewerregion.h"
#include "llviewerassetupload.h"
#include "llviewerinventory.h"
#include "llenvironment.h"
#include "llsky.h"
#include "llpermissions.h"
#include "llinventorymodel.h"
#include "llassetstorage.h"
#include "llfilesystem.h"
#include "lldrawpoolwater.h"
#include <boost/algorithm/string/replace.hpp>
#include "llinventoryobserver.h"
#include "llinventorydefines.h"
#include "llworld.h"
#include "lltrans.h"
#undef VERIFY_LEGACY_CONVERSION
extern bool gCubeSnapshot;
//=========================================================================
namespace
{
LLSD ensure_array_4(LLSD in, F32 fill);
LLSD read_legacy_preset_data(const std::string &name, const std::string& path, LLSD &messages);
//-------------------------------------------------------------------------
class LLSettingsInventoryCB : public LLInventoryCallback
{
public:
typedef std::function<void(const LLUUID &)> callback_t;
LLSettingsInventoryCB(callback_t cbfn) :
mCbfn(cbfn)
{ }
void fire(const LLUUID& inv_item) override { if (mCbfn) mCbfn(inv_item); }
private:
callback_t mCbfn;
};
//-------------------------------------------------------------------------
}
//=========================================================================
void LLSettingsVOBase::createNewInventoryItem(LLSettingsType::type_e stype, const LLUUID& parent_id, std::function<void(const LLUUID&)> created_cb)
{
inventory_result_fn cb = NULL;
if (created_cb != NULL)
{
cb = [created_cb](LLUUID asset_id, LLUUID inventory_id, LLUUID object_id, LLSD results)
{
created_cb(inventory_id);
};
}
createNewInventoryItem(stype, parent_id, cb);
}
void LLSettingsVOBase::createNewInventoryItem(LLSettingsType::type_e stype, const LLUUID &parent_id, inventory_result_fn callback)
{
LLTransactionID tid;
U32 nextOwnerPerm = LLFloaterPerms::getNextOwnerPerms("Settings");
nextOwnerPerm |= PERM_COPY;
if (!LLEnvironment::instance().isInventoryEnabled())
{
LL_WARNS("SETTINGS") << "Region does not support settings inventory objects." << LL_ENDL;
LLNotificationsUtil::add("SettingsUnsuported");
return;
}
tid.generate();
LLPointer<LLInventoryCallback> cb = new LLSettingsInventoryCB([callback](const LLUUID &inventoryId) {
LLSettingsVOBase::onInventoryItemCreated(inventoryId, LLSettingsBase::ptr_t(), callback);
});
create_inventory_settings(gAgent.getID(), gAgent.getSessionID(),
parent_id, LLTransactionID::tnull,
LLSettingsType::getDefaultName(stype), "",
stype, nextOwnerPerm, cb);
}
void LLSettingsVOBase::createInventoryItem(const LLSettingsBase::ptr_t &settings, const LLUUID &parent_id, std::string settings_name, inventory_result_fn callback)
{
U32 nextOwnerPerm = LLFloaterPerms::getNextOwnerPerms("Settings");
createInventoryItem(settings, nextOwnerPerm, parent_id, settings_name, callback);
}
void LLSettingsVOBase::createInventoryItem(const LLSettingsBase::ptr_t &settings, U32 next_owner_perm, const LLUUID &parent_id, std::string settings_name, inventory_result_fn callback)
{
LLTransactionID tid;
if (!LLEnvironment::instance().isInventoryEnabled())
{
LL_WARNS("SETTINGS") << "Region does not support settings inventory objects." << LL_ENDL;
LLNotificationsUtil::add("SettingsUnsuported");
return;
}
tid.generate();
LLPointer<LLInventoryCallback> cb = new LLSettingsInventoryCB([settings, callback](const LLUUID &inventoryId) {
LLSettingsVOBase::onInventoryItemCreated(inventoryId, settings, callback);
});
if (settings_name.empty())
{
settings_name = settings->getName();
}
create_inventory_settings(gAgent.getID(), gAgent.getSessionID(),
parent_id, tid,
settings_name, "",
settings->getSettingsTypeValue(), next_owner_perm, cb);
}
void LLSettingsVOBase::onInventoryItemCreated(const LLUUID &inventoryId, LLSettingsBase::ptr_t settings, inventory_result_fn callback)
{
LLViewerInventoryItem *pitem = gInventory.getItem(inventoryId);
if (pitem)
{
LLPermissions perm = pitem->getPermissions();
if (perm.getMaskEveryone() != PERM_COPY)
{
perm.setMaskEveryone(PERM_COPY);
pitem->setPermissions(perm);
pitem->updateServer(false);
}
}
if (!settings)
{ // The item was created as new with no settings passed in. Simulator should have given it the default for the type... check ID,
// no need to upload asset.
LLUUID asset_id;
if (pitem)
{
asset_id = pitem->getAssetUUID();
}
if (callback)
callback(asset_id, inventoryId, LLUUID::null, LLSD());
return;
}
// We need to update some inventory stuff here.... maybe.
updateInventoryItem(settings, inventoryId, callback, false);
}
void LLSettingsVOBase::updateInventoryItem(const LLSettingsBase::ptr_t &settings, LLUUID inv_item_id, inventory_result_fn callback, bool update_name)
{
const LLViewerRegion* region = gAgent.getRegion();
if (!region)
{
LL_WARNS("SETTINGS") << "Not connected to a region, cannot save setting." << LL_ENDL;
return;
}
std::string agent_url(region->getCapability("UpdateSettingsAgentInventory"));
if (!LLEnvironment::instance().isInventoryEnabled())
{
LL_WARNS("SETTINGS") << "Region does not support settings inventory objects." << LL_ENDL;
LLNotificationsUtil::add("SettingsUnsuported");
return;
}
LLViewerInventoryItem *inv_item = gInventory.getItem(inv_item_id);
if (inv_item)
{
bool need_update(false);
LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(inv_item);
if (settings->getFlag(LLSettingsBase::FLAG_NOTRANS) && new_item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()))
{
LLPermissions perm(inv_item->getPermissions());
perm.setBaseBits(LLUUID::null, false, PERM_TRANSFER);
perm.setOwnerBits(LLUUID::null, false, PERM_TRANSFER);
new_item->setPermissions(perm);
need_update |= true;
}
if (update_name && (settings->getName() != new_item->getName()))
{
new_item->rename(settings->getName());
settings->setName(new_item->getName()); // account for corrections
need_update |= true;
}
if (need_update)
{
new_item->updateServer(false);
gInventory.updateItem(new_item);
gInventory.notifyObservers();
}
}
std::stringstream buffer;
LLSD settingdata(settings->getSettings());
LLSDSerialize::serialize(settingdata, buffer, LLSDSerialize::LLSD_NOTATION);
LLResourceUploadInfo::ptr_t uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(inv_item_id, LLAssetType::AT_SETTINGS, buffer.str(),
[settings, callback](LLUUID itemId, LLUUID newAssetId, LLUUID newItemId, LLSD response)
{
LLSettingsVOBase::onAgentAssetUploadComplete(itemId, newAssetId, newItemId, response, settings, callback);
},
nullptr);
LLViewerAssetUpload::EnqueueInventoryUpload(agent_url, uploadInfo);
}
void LLSettingsVOBase::updateInventoryItem(const LLSettingsBase::ptr_t &settings, LLUUID object_id, LLUUID inv_item_id, inventory_result_fn callback)
{
const LLViewerRegion* region = gAgent.getRegion();
if (!region)
{
LL_WARNS("SETTINGS") << "Not connected to a region, cannot save setting." << LL_ENDL;
return;
}
std::string agent_url(region->getCapability("UpdateSettingsAgentInventory"));
if (!LLEnvironment::instance().isInventoryEnabled())
{
LL_WARNS("SETTINGS") << "Region does not support settings inventory objects." << LL_ENDL;
LLNotificationsUtil::add("SettingsUnsuported");
return;
}
std::stringstream buffer;
LLSD settingdata(settings->getSettings());
LLSDSerialize::serialize(settingdata, buffer, LLSDSerialize::LLSD_NOTATION);
LLResourceUploadInfo::ptr_t uploadInfo = std::make_shared<LLBufferedAssetUploadInfo>(object_id, inv_item_id, LLAssetType::AT_SETTINGS, buffer.str(),
[settings, callback](LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response)
{
LLSettingsVOBase::onTaskAssetUploadComplete(itemId, taskId, newAssetId, response, settings, callback);
},
nullptr);
LLViewerAssetUpload::EnqueueInventoryUpload(agent_url, uploadInfo);
}
void LLSettingsVOBase::onAgentAssetUploadComplete(LLUUID itemId, LLUUID newAssetId, LLUUID newItemId, LLSD response, LLSettingsBase::ptr_t psettings, inventory_result_fn callback)
{
LL_INFOS("SETTINGS") << "itemId:" << itemId << " newAssetId:" << newAssetId << " newItemId:" << newItemId << " response:" << response << LL_ENDL;
psettings->setAssetId(newAssetId);
if (callback)
callback( newAssetId, itemId, LLUUID::null, response );
}
void LLSettingsVOBase::onTaskAssetUploadComplete(LLUUID itemId, LLUUID taskId, LLUUID newAssetId, LLSD response, LLSettingsBase::ptr_t psettings, inventory_result_fn callback)
{
LL_INFOS("SETTINGS") << "Upload to task complete!" << LL_ENDL;
psettings->setAssetId(newAssetId);
if (callback)
callback(newAssetId, itemId, taskId, response);
}
void LLSettingsVOBase::getSettingsAsset(const LLUUID &assetId, LLSettingsVOBase::asset_download_fn callback)
{
gAssetStorage->getAssetData(assetId, LLAssetType::AT_SETTINGS,
[callback](const LLUUID &asset_id, LLAssetType::EType, void *, S32 status, LLExtStat ext_status)
{ onAssetDownloadComplete(asset_id, status, ext_status, callback); },
nullptr, true);
}
void LLSettingsVOBase::onAssetDownloadComplete(const LLUUID &asset_id, S32 status, LLExtStat ext_status, LLSettingsVOBase::asset_download_fn callback)
{
LLSettingsBase::ptr_t settings;
if (!status)
{
LLFileSystem file(asset_id, LLAssetType::AT_SETTINGS, LLFileSystem::READ);
S32 size = file.getSize();
std::string buffer(size + 1, '\0');
file.read((U8 *)buffer.data(), size);
std::stringstream llsdstream(buffer);
LLSD llsdsettings;
if (LLSDSerialize::deserialize(llsdsettings, llsdstream, LLSDSerialize::SIZE_UNLIMITED))
{
settings = createFromLLSD(llsdsettings);
}
if (!settings)
{
status = 1;
LL_WARNS("SETTINGS") << "Unable to create settings object." << LL_ENDL;
}
else
{
settings->setAssetId(asset_id);
}
}
else
{
LL_WARNS("SETTINGS") << "Error retrieving asset " << asset_id << ". Status code=" << status << "(" << LLAssetStorage::getErrorString(status) << ") ext_status=" << (U32)ext_status << LL_ENDL;
}
if (callback)
callback(asset_id, settings, status, ext_status);
}
void LLSettingsVOBase::getSettingsInventory(const LLUUID &inventoryId, inventory_download_fn callback)
{
}
bool LLSettingsVOBase::exportFile(const LLSettingsBase::ptr_t &settings, const std::string &filename, LLSDSerialize::ELLSD_Serialize format)
{
try
{
std::ofstream file(filename, std::ios::out | std::ios::trunc);
file.exceptions(std::ios_base::failbit | std::ios_base::badbit);
if (!file)
{
LL_WARNS("SETTINGS") << "Unable to open '" << filename << "' for writing." << LL_ENDL;
return false;
}
LLSDSerialize::serialize(settings->getSettings(), file, format);
}
catch (const std::ios_base::failure &e)
{
LL_WARNS("SETTINGS") << "Unable to save settings to file '" << filename << "': " << e.what() << LL_ENDL;
return false;
}
return true;
}
LLSettingsBase::ptr_t LLSettingsVOBase::importFile(const std::string &filename)
{
LLSD settings;
try
{
std::ifstream file(filename, std::ios::in);
file.exceptions(std::ios_base::failbit | std::ios_base::badbit);
if (!file)
{
LL_WARNS("SETTINGS") << "Unable to open '" << filename << "' for reading." << LL_ENDL;
return LLSettingsBase::ptr_t();
}
if (!LLSDSerialize::deserialize(settings, file, LLSDSerialize::SIZE_UNLIMITED))
{
LL_WARNS("SETTINGS") << "Unable to deserialize settings from '" << filename << "'" << LL_ENDL;
return LLSettingsBase::ptr_t();
}
}
catch (const std::ios_base::failure &e)
{
LL_WARNS("SETTINGS") << "Unable to save settings to file '" << filename << "': " << e.what() << LL_ENDL;
return LLSettingsBase::ptr_t();
}
return createFromLLSD(settings);
}
LLSettingsBase::ptr_t LLSettingsVOBase::createFromLLSD(const LLSD &settings)
{
if (!settings.has(SETTING_TYPE))
{
LL_WARNS("SETTINGS") << "No settings type in LLSD" << LL_ENDL;
return LLSettingsBase::ptr_t();
}
std::string settingtype = settings[SETTING_TYPE].asString();
LLSettingsBase::ptr_t psetting;
if (settingtype == "water")
{
return LLSettingsVOWater::buildWater(settings);
}
else if (settingtype == "sky")
{
return LLSettingsVOSky::buildSky(settings);
}
else if (settingtype == "daycycle")
{
return LLSettingsVODay::buildDay(settings);
}
LL_WARNS("SETTINGS") << "Unable to determine settings type for '" << settingtype << "'." << LL_ENDL;
return LLSettingsBase::ptr_t();
}
//=========================================================================
LLSettingsVOSky::LLSettingsVOSky(const LLSD &data, bool isAdvanced)
: LLSettingsSky(data)
, m_isAdvanced(isAdvanced)
{
}
LLSettingsVOSky::LLSettingsVOSky()
: LLSettingsSky()
, m_isAdvanced(false)
{
}
//-------------------------------------------------------------------------
LLSettingsSky::ptr_t LLSettingsVOSky::buildSky(LLSD settings)
{
LLSettingsSky::validation_list_t validations = LLSettingsSky::validationList();
LLSD results = LLSettingsBase::settingValidation(settings, validations);
if (!results["success"].asBoolean())
{
LL_WARNS("SETTINGS") << "Sky setting validation failed!\n" << results << LL_ENDL;
LLSettingsSky::ptr_t();
}
return std::make_shared<LLSettingsVOSky>(settings, true);
}
LLSettingsSky::ptr_t LLSettingsVOSky::buildFromLegacyPreset(const std::string &name, const LLSD &oldsettings, LLSD &messages)
{
LLSD newsettings = LLSettingsSky::translateLegacySettings(oldsettings);
if (newsettings.isUndefined())
{
messages["REASONS"] = LLTrans::getString("SettingTranslateError", LLSDMap("NAME", name));
return LLSettingsSky::ptr_t();
}
newsettings[SETTING_NAME] = name;
LLSettingsSky::validation_list_t validations = LLSettingsSky::validationList();
LLSD results = LLSettingsBase::settingValidation(newsettings, validations);
if (!results["success"].asBoolean())
{
messages["REASONS"] = LLTrans::getString("SettingValidationError", LLSDMap("NAME", name));
LL_WARNS("SETTINGS") << "Sky setting validation failed!\n" << results << LL_ENDL;
LLSettingsSky::ptr_t();
}
LLSettingsSky::ptr_t skyp = std::make_shared<LLSettingsVOSky>(newsettings);
#ifdef VERIFY_LEGACY_CONVERSION
LLSD oldsettings = LLSettingsVOSky::convertToLegacy(skyp, isAdvanced());
if (!llsd_equals(oldsettings, oldsettings))
{
LL_WARNS("SKY") << "Conversion to/from legacy does not match!\n"
<< "Old: " << oldsettings
<< "new: " << oldsettings << LL_ENDL;
}
#endif
return skyp;
}
LLSettingsSky::ptr_t LLSettingsVOSky::buildFromLegacyPresetFile(const std::string &name, const std::string &path, LLSD &messages)
{
LLSD legacy_data = read_legacy_preset_data(name, path, messages);
if (!legacy_data)
{ // messages filled in by read_legacy_preset_data
LL_WARNS("SETTINGS") << "Could not load legacy Windlight \"" << name << "\" from " << path << LL_ENDL;
return ptr_t();
}
return buildFromLegacyPreset(LLURI::unescape(name), legacy_data, messages);
}
LLSettingsSky::ptr_t LLSettingsVOSky::buildDefaultSky()
{
static LLSD default_settings;
if (!default_settings.size())
{
default_settings = LLSettingsSky::defaults();
default_settings[SETTING_NAME] = DEFAULT_SETTINGS_NAME;
LLSettingsSky::validation_list_t validations = LLSettingsSky::validationList();
LLSD results = LLSettingsBase::settingValidation(default_settings, validations);
if (!results["success"].asBoolean())
{
LL_WARNS("SETTINGS") << "Sky setting validation failed!\n" << results << LL_ENDL;
LLSettingsSky::ptr_t();
}
}
LLSettingsSky::ptr_t skyp = std::make_shared<LLSettingsVOSky>(default_settings);
return skyp;
}
LLSettingsSky::ptr_t LLSettingsVOSky::buildClone() const
{
LLSD settings = cloneSettings();
U32 flags = getFlags();
LLSettingsSky::validation_list_t validations = LLSettingsSky::validationList();
LLSD results = LLSettingsBase::settingValidation(settings, validations);
if (!results["success"].asBoolean())
{
LL_WARNS("SETTINGS") << "Sky setting validation failed!\n" << results << LL_ENDL;
LLSettingsSky::ptr_t();
}
LLSettingsSky::ptr_t skyp = std::make_shared<LLSettingsVOSky>(settings);
skyp->setFlags(flags);
return skyp;
}
void LLSettingsVOSky::convertAtmosphericsToLegacy(LLSD& legacy, LLSD& settings)
{
// These may need to be inferred from new settings' density profiles
// if the legacy settings values are not available.
if (settings.has(SETTING_LEGACY_HAZE))
{
LLSD legacyhaze = settings[SETTING_LEGACY_HAZE];
// work-around for setter formerly putting ambient values in wrong loc...
if (legacyhaze.has(SETTING_AMBIENT))
{
legacy[SETTING_AMBIENT] = ensure_array_4(legacyhaze[SETTING_AMBIENT], 1.0f);
}
else if (settings.has(SETTING_AMBIENT))
{
legacy[SETTING_AMBIENT] = ensure_array_4(settings[SETTING_AMBIENT], 1.0f);
}
legacy[SETTING_BLUE_DENSITY] = ensure_array_4(legacyhaze[SETTING_BLUE_DENSITY], 1.0);
legacy[SETTING_BLUE_HORIZON] = ensure_array_4(legacyhaze[SETTING_BLUE_HORIZON], 1.0);
legacy[SETTING_DENSITY_MULTIPLIER] = llsd::array(legacyhaze[SETTING_DENSITY_MULTIPLIER].asReal(), 0.0f, 0.0f, 1.0f);
legacy[SETTING_DISTANCE_MULTIPLIER] = llsd::array(legacyhaze[SETTING_DISTANCE_MULTIPLIER].asReal(), 0.0f, 0.0f, 1.0f);
legacy[SETTING_HAZE_DENSITY] = llsd::array(legacyhaze[SETTING_HAZE_DENSITY], 0.0f, 0.0f, 1.0f);
legacy[SETTING_HAZE_HORIZON] = llsd::array(legacyhaze[SETTING_HAZE_HORIZON], 0.0f, 0.0f, 1.0f);
}
}
LLSD LLSettingsVOSky::convertToLegacy(const LLSettingsSky::ptr_t &psky, bool isAdvanced)
{
LLSD legacy(LLSD::emptyMap());
LLSD settings = psky->getSettings();
convertAtmosphericsToLegacy(legacy, settings);
legacy[SETTING_CLOUD_COLOR] = ensure_array_4(settings[SETTING_CLOUD_COLOR], 1.0);
legacy[SETTING_CLOUD_POS_DENSITY1] = ensure_array_4(settings[SETTING_CLOUD_POS_DENSITY1], 1.0);
legacy[SETTING_CLOUD_POS_DENSITY2] = ensure_array_4(settings[SETTING_CLOUD_POS_DENSITY2], 1.0);
legacy[SETTING_CLOUD_SCALE] = llsd::array(settings[SETTING_CLOUD_SCALE], LLSD::Real(0.0), LLSD::Real(0.0), LLSD::Real(1.0));
legacy[SETTING_CLOUD_SCROLL_RATE] = settings[SETTING_CLOUD_SCROLL_RATE];
legacy[SETTING_LEGACY_ENABLE_CLOUD_SCROLL] = llsd::array(LLSD::Boolean(!is_approx_zero(settings[SETTING_CLOUD_SCROLL_RATE][0].asReal())),
LLSD::Boolean(!is_approx_zero(settings[SETTING_CLOUD_SCROLL_RATE][1].asReal())));
legacy[SETTING_CLOUD_SHADOW] = llsd::array(settings[SETTING_CLOUD_SHADOW].asReal(), 0.0f, 0.0f, 1.0f);
legacy[SETTING_GAMMA] = llsd::array(settings[SETTING_GAMMA], 0.0f, 0.0f, 1.0f);
legacy[SETTING_GLOW] = ensure_array_4(settings[SETTING_GLOW], 1.0);
legacy[SETTING_LIGHT_NORMAL] = ensure_array_4(psky->getLightDirection().getValue(), 0.0f);
legacy[SETTING_MAX_Y] = llsd::array(settings[SETTING_MAX_Y], 0.0f, 0.0f, 1.0f);
legacy[SETTING_STAR_BRIGHTNESS] = settings[SETTING_STAR_BRIGHTNESS].asReal() / 250.0f; // convert from 0-500 -> 0-2 ala pre-FS-compat changes
legacy[SETTING_SUNLIGHT_COLOR] = ensure_array_4(settings[SETTING_SUNLIGHT_COLOR], 1.0f);
LLVector3 dir = psky->getLightDirection();
F32 phi = asin(dir.mV[2]);
F32 cos_phi = cosf(phi);
F32 theta = (cos_phi != 0) ? asin(dir.mV[1] / cos_phi) : 0.0f;
theta = -theta;
// get angles back into valid ranges for legacy viewer...
//
while (theta < 0)
{
theta += F_PI * 2;
}
if (theta > 4 * F_PI)
{
theta = fmod(theta, 2 * F_PI);
}
while (phi < -F_PI)
{
phi += 2 * F_PI;
}
if (phi > 3 * F_PI)
{
phi = F_PI + fmod(phi - F_PI, 2 * F_PI);
}
legacy[SETTING_LEGACY_EAST_ANGLE] = theta;
legacy[SETTING_LEGACY_SUN_ANGLE] = phi;
return legacy;
}
//-------------------------------------------------------------------------
void LLSettingsVOSky::updateSettings()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
LLSettingsSky::updateSettings();
LLVector3 sun_direction = getSunDirection();
LLVector3 moon_direction = getMoonDirection();
// Want the dot prod of sun w/ high noon vector (0,0,1), which is just the z component
F32 dp = llmax(sun_direction[2], 0.0f); // clamped to 0 when sun is down
// Since WL scales everything by 2, there should always be at least a 2:1 brightness ratio
// between sunlight and point lights in windlight to normalize point lights.
//
// After some A/B comparison of relesae vs EEP, tweak to allow strength to fall below 2
// at night, for better match. (mSceneLightStrength is a divisor, so lower value means brighter
// local lights)
F32 sun_dynamic_range = llmax(gSavedSettings.getF32("RenderSunDynamicRange"), 0.0001f);
mSceneLightStrength = 2.0f * (0.75f + sun_dynamic_range * dp);
gSky.setSunAndMoonDirectionsCFR(sun_direction, moon_direction);
gSky.setSunTextures(getSunTextureId(), getNextSunTextureId());
gSky.setMoonTextures(getMoonTextureId(), getNextMoonTextureId());
gSky.setCloudNoiseTextures(getCloudNoiseTextureId(), getNextCloudNoiseTextureId());
gSky.setBloomTextures(getBloomTextureId(), getNextBloomTextureId());
gSky.setSunScale(getSunScale());
gSky.setMoonScale(getMoonScale());
}
void LLSettingsVOSky::applySpecial(void *ptarget, bool force)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
LLVector3 light_direction = LLVector3(LLEnvironment::instance().getClampedLightNorm().mV);
bool irradiance_pass = gCubeSnapshot && !gPipeline.mReflectionMapManager.isRadiancePass();
LLShaderUniforms* shader = &((LLShaderUniforms*)ptarget)[LLGLSLShader::SG_DEFAULT];
{
shader->uniform3fv(LLViewerShaderMgr::LIGHTNORM, light_direction);
shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, LLViewerCamera::getInstance()->getOrigin());
}
shader = &((LLShaderUniforms*)ptarget)[LLGLSLShader::SG_SKY];
shader->uniform3fv(LLViewerShaderMgr::LIGHTNORM, light_direction);
// Legacy? SETTING_CLOUD_SCROLL_RATE("cloud_scroll_rate")
LLVector4 vect_c_p_d1(mSettings[SETTING_CLOUD_POS_DENSITY1]);
LLVector4 cloud_scroll( LLEnvironment::instance().getCloudScrollDelta() );
// SL-13084 EEP added support for custom cloud textures -- flip them horizontally to match the preview of Clouds > Cloud Scroll
// Keep in Sync!
// * indra\newview\llsettingsvo.cpp
// * indra\newview\app_settings\shaders\class2\windlight\cloudsV.glsl
// * indra\newview\app_settings\shaders\class1\deferred\cloudsV.glsl
cloud_scroll[0] = -cloud_scroll[0];
vect_c_p_d1 += cloud_scroll;
shader->uniform3fv(LLShaderMgr::CLOUD_POS_DENSITY1, LLVector3(vect_c_p_d1.mV));
LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky();
// TODO -- make these getters return vec3s
LLVector3 sunDiffuse = LLVector3(psky->getSunlightColor().mV);
LLVector3 moonDiffuse = LLVector3(psky->getMoonlightColor().mV);
shader->uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, sunDiffuse);
shader->uniform3fv(LLShaderMgr::MOONLIGHT_COLOR, moonDiffuse);
shader->uniform3fv(LLShaderMgr::CLOUD_COLOR, LLVector3(psky->getCloudColor().mV));
shader = &((LLShaderUniforms*)ptarget)[LLGLSLShader::SG_ANY];
shader->uniform1f(LLShaderMgr::SCENE_LIGHT_STRENGTH, mSceneLightStrength);
LLColor3 ambient(getTotalAmbient());
F32 g = getGamma();
static LLCachedControl<bool> should_auto_adjust(gSavedSettings, "RenderSkyAutoAdjustLegacy", true);
static LLCachedControl<F32> auto_adjust_ambient_scale(gSavedSettings, "RenderSkyAutoAdjustAmbientScale", 0.75f);
static LLCachedControl<F32> auto_adjust_hdr_scale(gSavedSettings, "RenderSkyAutoAdjustHDRScale", 2.f);
static LLCachedControl<F32> auto_adjust_blue_horizon_scale(gSavedSettings, "RenderSkyAutoAdjustBlueHorizonScale", 1.f);
static LLCachedControl<F32> auto_adjust_blue_density_scale(gSavedSettings, "RenderSkyAutoAdjustBlueDensityScale", 1.f);
static LLCachedControl<F32> auto_adjust_sun_color_scale(gSavedSettings, "RenderSkyAutoAdjustSunColorScale", 1.f);
static LLCachedControl<F32> sunlight_scale(gSavedSettings, "RenderSkySunlightScale", 1.5f);
static LLCachedControl<F32> ambient_scale(gSavedSettings, "RenderSkyAmbientScale", 1.5f);
shader->uniform1f(LLShaderMgr::SKY_SUNLIGHT_SCALE, sunlight_scale);
shader->uniform1f(LLShaderMgr::SKY_AMBIENT_SCALE, ambient_scale);
static LLCachedControl<F32> cloud_shadow_scale(gSavedSettings, "RenderCloudShadowAmbianceFactor", 0.125f);
F32 probe_ambiance = getTotalReflectionProbeAmbiance(cloud_shadow_scale);
if (irradiance_pass)
{ // during an irradiance map update, disable ambient lighting (direct lighting only) and desaturate sky color (avoid tinting the world blue)
shader->uniform3fv(LLShaderMgr::AMBIENT, LLVector3::zero.mV);
}
else
{
if (psky->getReflectionProbeAmbiance() != 0.f)
{
shader->uniform3fv(LLShaderMgr::AMBIENT, LLVector3(ambient.mV));
shader->uniform1f(LLShaderMgr::SKY_HDR_SCALE, sqrtf(g)*2.0); // use a modifier here so 1.0 maps to the "most desirable" default and the maximum value doesn't go off the rails
}
else if (psky->canAutoAdjust() && should_auto_adjust)
{ // auto-adjust legacy sky to take advantage of probe ambiance
shader->uniform3fv(LLShaderMgr::AMBIENT, (ambient * auto_adjust_ambient_scale).mV);
shader->uniform1f(LLShaderMgr::SKY_HDR_SCALE, auto_adjust_hdr_scale);
LLColor3 blue_horizon = getBlueHorizon() * auto_adjust_blue_horizon_scale;
LLColor3 blue_density = getBlueDensity() * auto_adjust_blue_density_scale;
LLColor3 sun_diffuse = getSunDiffuse() * auto_adjust_sun_color_scale;
shader->uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, sun_diffuse.mV);
shader->uniform3fv(LLShaderMgr::BLUE_DENSITY, blue_density.mV);
shader->uniform3fv(LLShaderMgr::BLUE_HORIZON, blue_horizon.mV);
probe_ambiance = sAutoAdjustProbeAmbiance;
}
else
{
shader->uniform1f(LLShaderMgr::SKY_HDR_SCALE, 1.f);
shader->uniform3fv(LLShaderMgr::AMBIENT, LLVector3(ambient.mV));
}
}
shader->uniform1f(LLShaderMgr::REFLECTION_PROBE_AMBIANCE, probe_ambiance);
shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, getIsSunUp() ? 1 : 0);
shader->uniform1f(LLShaderMgr::SUN_MOON_GLOW_FACTOR, getSunMoonGlowFactor());
shader->uniform1f(LLShaderMgr::DENSITY_MULTIPLIER, getDensityMultiplier());
shader->uniform1f(LLShaderMgr::DISTANCE_MULTIPLIER, getDistanceMultiplier());
shader->uniform1f(LLShaderMgr::GAMMA, g);
}
LLSettingsSky::parammapping_t LLSettingsVOSky::getParameterMap() const
{
static parammapping_t param_map;
if (param_map.empty())
{
// LEGACY_ATMOSPHERICS
// Todo: default 'legacy' values duplicate the ones from functions like getBlueDensity() find a better home for them
// There is LLSettingsSky::defaults(), but it doesn't contain everything since it is geared towards creating new settings.
param_map[SETTING_AMBIENT] = DefaultParam(LLShaderMgr::AMBIENT, LLColor3(0.25f, 0.25f, 0.25f).getValue());
param_map[SETTING_BLUE_DENSITY] = DefaultParam(LLShaderMgr::BLUE_DENSITY, LLColor3(0.2447f, 0.4487f, 0.7599f).getValue());
param_map[SETTING_BLUE_HORIZON] = DefaultParam(LLShaderMgr::BLUE_HORIZON, LLColor3(0.4954f, 0.4954f, 0.6399f).getValue());
param_map[SETTING_HAZE_DENSITY] = DefaultParam(LLShaderMgr::HAZE_DENSITY, LLSD(0.7f));
param_map[SETTING_HAZE_HORIZON] = DefaultParam(LLShaderMgr::HAZE_HORIZON, LLSD(0.19f));
param_map[SETTING_DENSITY_MULTIPLIER] = DefaultParam(LLShaderMgr::DENSITY_MULTIPLIER, LLSD(0.0001f));
param_map[SETTING_DISTANCE_MULTIPLIER] = DefaultParam(LLShaderMgr::DISTANCE_MULTIPLIER, LLSD(0.8f));
// Following values are always present, so we can just zero these ones, but used values from defaults()
LLSD sky_defaults = LLSettingsSky::defaults();
param_map[SETTING_CLOUD_POS_DENSITY2] = DefaultParam(LLShaderMgr::CLOUD_POS_DENSITY2, sky_defaults[SETTING_CLOUD_POS_DENSITY2]);
param_map[SETTING_CLOUD_SCALE] = DefaultParam(LLShaderMgr::CLOUD_SCALE, sky_defaults[SETTING_CLOUD_SCALE]);
param_map[SETTING_CLOUD_SHADOW] = DefaultParam(LLShaderMgr::CLOUD_SHADOW, sky_defaults[SETTING_CLOUD_SHADOW]);
param_map[SETTING_CLOUD_VARIANCE] = DefaultParam(LLShaderMgr::CLOUD_VARIANCE, sky_defaults[SETTING_CLOUD_VARIANCE]);
param_map[SETTING_GLOW] = DefaultParam(LLShaderMgr::GLOW, sky_defaults[SETTING_GLOW]);
param_map[SETTING_MAX_Y] = DefaultParam(LLShaderMgr::MAX_Y, sky_defaults[SETTING_MAX_Y]);
//param_map[SETTING_SUNLIGHT_COLOR] = DefaultParam(LLShaderMgr::SUNLIGHT_COLOR, sky_defaults[SETTING_SUNLIGHT_COLOR]);
//param_map[SETTING_CLOUD_COLOR] = DefaultParam(LLShaderMgr::CLOUD_COLOR, sky_defaults[SETTING_CLOUD_COLOR]);
param_map[SETTING_MOON_BRIGHTNESS] = DefaultParam(LLShaderMgr::MOON_BRIGHTNESS, sky_defaults[SETTING_MOON_BRIGHTNESS]);
param_map[SETTING_SKY_MOISTURE_LEVEL] = DefaultParam(LLShaderMgr::MOISTURE_LEVEL, sky_defaults[SETTING_SKY_MOISTURE_LEVEL]);
param_map[SETTING_SKY_DROPLET_RADIUS] = DefaultParam(LLShaderMgr::DROPLET_RADIUS, sky_defaults[SETTING_SKY_DROPLET_RADIUS]);
param_map[SETTING_SKY_ICE_LEVEL] = DefaultParam(LLShaderMgr::ICE_LEVEL, sky_defaults[SETTING_SKY_ICE_LEVEL]);
param_map[SETTING_REFLECTION_PROBE_AMBIANCE] = DefaultParam(LLShaderMgr::REFLECTION_PROBE_AMBIANCE, sky_defaults[SETTING_REFLECTION_PROBE_AMBIANCE]);
// AdvancedAtmospherics TODO
// Provide mappings for new shader params here
}
return param_map;
}
//=========================================================================
const F32 LLSettingsVOWater::WATER_FOG_LIGHT_CLAMP(0.3f);
//-------------------------------------------------------------------------
LLSettingsVOWater::LLSettingsVOWater(const LLSD &data) :
LLSettingsWater(data)
{
}
LLSettingsVOWater::LLSettingsVOWater() :
LLSettingsWater()
{
}
LLSettingsWater::ptr_t LLSettingsVOWater::buildWater(LLSD settings)
{
LLSettingsWater::validation_list_t validations = LLSettingsWater::validationList();
LLSD results = LLSettingsWater::settingValidation(settings, validations);
if (!results["success"].asBoolean())
{
LL_WARNS("SETTINGS") << "Water setting validation failed!\n" << results << LL_ENDL;
LLSettingsWater::ptr_t();
}
return std::make_shared<LLSettingsVOWater>(settings);
}
//-------------------------------------------------------------------------
LLSettingsWater::ptr_t LLSettingsVOWater::buildFromLegacyPreset(const std::string &name, const LLSD &oldsettings, LLSD &messages)
{
LLSD newsettings(LLSettingsWater::translateLegacySettings(oldsettings));
if (newsettings.isUndefined())
{
messages["REASONS"] = LLTrans::getString("SettingTranslateError", LLSDMap("NAME", name));
return LLSettingsWater::ptr_t();
}
newsettings[SETTING_NAME] = name;
LLSettingsWater::validation_list_t validations = LLSettingsWater::validationList();
LLSD results = LLSettingsWater::settingValidation(newsettings, validations);
if (!results["success"].asBoolean())
{
messages["REASONS"] = LLTrans::getString("SettingValidationError", name);
LL_WARNS("SETTINGS") << "Water setting validation failed!: " << results << LL_ENDL;
return LLSettingsWater::ptr_t();
}
LLSettingsWater::ptr_t waterp = std::make_shared<LLSettingsVOWater>(newsettings);
#ifdef VERIFY_LEGACY_CONVERSION
LLSD oldsettings = LLSettingsVOWater::convertToLegacy(waterp);
if (!llsd_equals(oldsettings, oldsettings))
{
LL_WARNS("WATER") << "Conversion to/from legacy does not match!\n"
<< "Old: " << oldsettings
<< "new: " << oldsettings << LL_ENDL;
}
#endif
return waterp;
}
LLSettingsWater::ptr_t LLSettingsVOWater::buildFromLegacyPresetFile(const std::string &name, const std::string &path, LLSD &messages)
{
LLSD legacy_data = read_legacy_preset_data(name, path, messages);
if (!legacy_data)
{ // messages filled in by read_legacy_preset_data
LL_WARNS("SETTINGS") << "Could not load legacy Windlight \"" << name << "\" from " << path << LL_ENDL;
return ptr_t();
}
return buildFromLegacyPreset(LLURI::unescape(name), legacy_data, messages);
}
LLSettingsWater::ptr_t LLSettingsVOWater::buildDefaultWater()
{
static LLSD default_settings;
if (!default_settings.size())
{
default_settings = LLSettingsWater::defaults();
default_settings[SETTING_NAME] = DEFAULT_SETTINGS_NAME;
LLSettingsWater::validation_list_t validations = LLSettingsWater::validationList();
LLSD results = LLSettingsWater::settingValidation(default_settings, validations);
if (!results["success"].asBoolean())
{
LL_WARNS("SETTINGS") << "Water setting validation failed!: " << results << LL_ENDL;
return LLSettingsWater::ptr_t();
}
}
LLSettingsWater::ptr_t waterp = std::make_shared<LLSettingsVOWater>(default_settings);
return waterp;
}
LLSettingsWater::ptr_t LLSettingsVOWater::buildClone() const
{
LLSD settings = cloneSettings();
U32 flags = getFlags();
LLSettingsWater::validation_list_t validations = LLSettingsWater::validationList();
LLSD results = LLSettingsWater::settingValidation(settings, validations);
if (!results["success"].asBoolean())
{
LL_WARNS("SETTINGS") << "Water setting validation failed!: " << results << LL_ENDL;
return LLSettingsWater::ptr_t();
}
LLSettingsWater::ptr_t waterp = std::make_shared<LLSettingsVOWater>(settings);
waterp->setFlags(flags);
return waterp;
}
LLSD LLSettingsVOWater::convertToLegacy(const LLSettingsWater::ptr_t &pwater)
{
LLSD legacy(LLSD::emptyMap());
LLSD settings = pwater->getSettings();
legacy[SETTING_LEGACY_BLUR_MULTIPLIER] = settings[SETTING_BLUR_MULTIPLIER];
legacy[SETTING_LEGACY_FOG_COLOR] = ensure_array_4(settings[SETTING_FOG_COLOR], 1.0f);
legacy[SETTING_LEGACY_FOG_DENSITY] = settings[SETTING_FOG_DENSITY];
legacy[SETTING_LEGACY_FOG_MOD] = settings[SETTING_FOG_MOD];
legacy[SETTING_LEGACY_FRESNEL_OFFSET] = settings[SETTING_FRESNEL_OFFSET];
legacy[SETTING_LEGACY_FRESNEL_SCALE] = settings[SETTING_FRESNEL_SCALE];
legacy[SETTING_LEGACY_NORMAL_MAP] = settings[SETTING_NORMAL_MAP];
legacy[SETTING_LEGACY_NORMAL_SCALE] = settings[SETTING_NORMAL_SCALE];
legacy[SETTING_LEGACY_SCALE_ABOVE] = settings[SETTING_SCALE_ABOVE];
legacy[SETTING_LEGACY_SCALE_BELOW] = settings[SETTING_SCALE_BELOW];
legacy[SETTING_LEGACY_WAVE1_DIR] = settings[SETTING_WAVE1_DIR];
legacy[SETTING_LEGACY_WAVE2_DIR] = settings[SETTING_WAVE2_DIR];
return legacy;
}
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
void LLSettingsVOWater::applySpecial(void *ptarget, bool force)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER;
LLEnvironment& env = LLEnvironment::instance();
auto group = LLGLSLShader::SG_ANY;
LLShaderUniforms* shader = &((LLShaderUniforms*)ptarget)[group];
{
F32 water_height = env.getWaterHeight();
if (LLViewerCamera::instance().cameraUnderWater())
{ // when the camera is under water, use the water height at the camera position
LLViewerRegion* region = LLWorld::instance().getRegionFromPosAgent(LLViewerCamera::instance().getOrigin());
if (region)
{
water_height = region->getWaterHeight();
}
}
//transform water plane to eye space
glh::vec3f norm(0.f, 0.f, 1.f);
glh::vec3f p(0.f, 0.f, water_height);
F32 modelView[16];
for (U32 i = 0; i < 16; i++)
{
modelView[i] = (F32)gGLModelView[i];
}
glh::matrix4f mat(modelView);
glh::matrix4f invtrans = mat.inverse().transpose();
glh::vec3f enorm;
glh::vec3f ep;
invtrans.mult_matrix_vec(norm, enorm);
enorm.normalize();
mat.mult_matrix_vec(p, ep);
LLVector4 waterPlane(enorm.v[0], enorm.v[1], enorm.v[2], -ep.dot(enorm));
LLDrawPoolAlpha::sWaterPlane = waterPlane;
shader->uniform4fv(LLShaderMgr::WATER_WATERPLANE, waterPlane.mV);
LLVector4 light_direction = env.getClampedLightNorm();
F32 waterFogKS = 1.f / llmax(light_direction.mV[2], WATER_FOG_LIGHT_CLAMP);
shader->uniform1f(LLShaderMgr::WATER_FOGKS, waterFogKS);
F32 eyedepth = LLViewerCamera::getInstance()->getOrigin().mV[2] - water_height;
bool underwater = (eyedepth <= 0.0f);
F32 waterFogDensity = env.getCurrentWater()->getModifiedWaterFogDensity(underwater);
shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, waterFogDensity);
LLColor4 fog_color(env.getCurrentWater()->getWaterFogColor());
shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, fog_color.mV);
shader->uniform3fv(LLShaderMgr::WATER_FOGCOLOR_LINEAR, linearColor3(fog_color).mV);
F32 blend_factor = env.getCurrentWater()->getBlendFactor();
shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor);
// update to normal lightnorm, water shader itself will use rotated lightnorm as necessary
shader->uniform3fv(LLShaderMgr::LIGHTNORM, light_direction.mV);
}
}
void LLSettingsVOWater::updateSettings()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
// base class clears dirty flag so as to not trigger recursive update
LLSettingsBase::updateSettings();
LLDrawPoolWater* pwaterpool = (LLDrawPoolWater*)gPipeline.getPool(LLDrawPool::POOL_WATER);
if (pwaterpool)
{
pwaterpool->setTransparentTextures(getTransparentTextureID(), getNextTransparentTextureID());
pwaterpool->setOpaqueTexture(GetDefaultOpaqueTextureAssetId());
pwaterpool->setNormalMaps(getNormalMapID(), getNextNormalMapID());
}
}
LLSettingsWater::parammapping_t LLSettingsVOWater::getParameterMap() const
{
static parammapping_t param_map;
return param_map;
}
//=========================================================================
LLSettingsVODay::LLSettingsVODay(const LLSD &data):
LLSettingsDay(data)
{}
LLSettingsVODay::LLSettingsVODay():
LLSettingsDay()
{}
LLSettingsDay::ptr_t LLSettingsVODay::buildDay(LLSD settings)
{
LLSettingsDay::validation_list_t validations = LLSettingsDay::validationList();
LLSD results = LLSettingsDay::settingValidation(settings, validations);
if (!results["success"].asBoolean())
{
LL_WARNS("SETTINGS") << "Day setting validation failed!\n" << results << LL_ENDL;
LLSettingsDay::ptr_t();
}
LLSettingsDay::ptr_t pday = std::make_shared<LLSettingsVODay>(settings);
if (pday)
pday->initialize();
return pday;
}
//-------------------------------------------------------------------------
LLSettingsDay::ptr_t LLSettingsVODay::buildFromLegacyPreset(const std::string &name, const std::string &path, const LLSD &oldsettings, LLSD &messages)
{
LLSD newsettings(defaults());
std::set<std::string> framenames;
std::set<std::string> notfound;
// expected and correct folder sctructure is to have
// three folders in widnlight's root: days, water, skies
std::string base_path(gDirUtilp->getDirName(path));
std::string water_path(base_path);
std::string sky_path(base_path);
std::string day_path(base_path);
gDirUtilp->append(water_path, "water");
gDirUtilp->append(sky_path, "skies");
gDirUtilp->append(day_path, "days");
if (!gDirUtilp->fileExists(day_path))
{
LL_WARNS("SETTINGS") << "File " << name << ".xml is not in \"days\" folder." << LL_ENDL;
}
if (!gDirUtilp->fileExists(water_path))
{
LL_WARNS("SETTINGS") << "Failed to find accompaniying water folder for file " << name
<< ".xml. Falling back to using default folder" << LL_ENDL;
water_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight");
gDirUtilp->append(water_path, "water");
}
if (!gDirUtilp->fileExists(sky_path))
{
LL_WARNS("SETTINGS") << "Failed to find accompaniying skies folder for file " << name
<< ".xml. Falling back to using default folder" << LL_ENDL;
sky_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight");
gDirUtilp->append(sky_path, "skies");
}
newsettings[SETTING_NAME] = name;
LLSD watertrack = llsd::array(
LLSDMap(SETTING_KEYKFRAME, LLSD::Real(0.0f))
(SETTING_KEYNAME, "water:Default"));
LLSD skytrack = LLSD::emptyArray();
for (LLSD::array_const_iterator it = oldsettings.beginArray(); it != oldsettings.endArray(); ++it)
{
std::string framename = (*it)[1].asString();
LLSD entry = LLSDMap(SETTING_KEYKFRAME, (*it)[0].asReal())
(SETTING_KEYNAME, "sky:" + framename);
framenames.insert(framename);
skytrack.append(entry);
}
newsettings[SETTING_TRACKS] = llsd::array(watertrack, skytrack);
LLSD frames(LLSD::emptyMap());
{
LLSettingsWater::ptr_t pwater = LLSettingsVOWater::buildFromLegacyPresetFile("Default", water_path, messages);
if (!pwater)
{ // messages filled in by buildFromLegacyPresetFile
return LLSettingsDay::ptr_t();
}
frames["water:Default"] = pwater->getSettings();
}
for (std::set<std::string>::iterator itn = framenames.begin(); itn != framenames.end(); ++itn)
{
LLSettingsSky::ptr_t psky = LLSettingsVOSky::buildFromLegacyPresetFile((*itn), sky_path, messages);
if (!psky)
{ // messages filled in by buildFromLegacyPresetFile
return LLSettingsDay::ptr_t();
}
frames["sky:" + (*itn)] = psky->getSettings();
}
newsettings[SETTING_FRAMES] = frames;
LLSettingsDay::validation_list_t validations = LLSettingsDay::validationList();
LLSD results = LLSettingsDay::settingValidation(newsettings, validations);
if (!results["success"].asBoolean())
{
messages["REASONS"] = LLTrans::getString("SettingValidationError", LLSDMap("NAME", name));
LL_WARNS("SETTINGS") << "Day setting validation failed!: " << results << LL_ENDL;
return LLSettingsDay::ptr_t();
}
LLSettingsDay::ptr_t dayp = std::make_shared<LLSettingsVODay>(newsettings);
#ifdef VERIFY_LEGACY_CONVERSION
LLSD testsettings = LLSettingsVODay::convertToLegacy(dayp);
if (!llsd_equals(oldsettings, testsettings))
{
LL_WARNS("DAYCYCLE") << "Conversion to/from legacy does not match!\n"
<< "Old: " << oldsettings
<< "new: " << testsettings << LL_ENDL;
}
#endif
dayp->initialize();
return dayp;
}
LLSettingsDay::ptr_t LLSettingsVODay::buildFromLegacyPresetFile(const std::string &name, const std::string &path, LLSD &messages)
{
LLSD legacy_data = read_legacy_preset_data(name, path, messages);
if (!legacy_data)
{ // messages filled in by read_legacy_preset_data
LL_WARNS("SETTINGS") << "Could not load legacy Windlight \"" << name << "\" from " << path << LL_ENDL;
return ptr_t();
}
// Name for LLSettingsDay only, path to get related files from filesystem
return buildFromLegacyPreset(LLURI::unescape(name), path, legacy_data, messages);
}
LLSettingsDay::ptr_t LLSettingsVODay::buildFromLegacyMessage(const LLUUID &regionId, LLSD daycycle, LLSD skydefs, LLSD waterdef)
{
LLSD frames(LLSD::emptyMap());
for (LLSD::map_iterator itm = skydefs.beginMap(); itm != skydefs.endMap(); ++itm)
{
std::string newname = "sky:" + (*itm).first;
LLSD newsettings = LLSettingsSky::translateLegacySettings((*itm).second);
newsettings[SETTING_NAME] = newname;
frames[newname] = newsettings;
LL_WARNS("SETTINGS") << "created region sky '" << newname << "'" << LL_ENDL;
}
LLSD watersettings = LLSettingsWater::translateLegacySettings(waterdef);
std::string watername = "water:"+ watersettings[SETTING_NAME].asString();
watersettings[SETTING_NAME] = watername;
frames[watername] = watersettings;
LLSD watertrack = llsd::array(
LLSDMap(SETTING_KEYKFRAME, LLSD::Real(0.0f))
(SETTING_KEYNAME, watername));
LLSD skytrack(LLSD::emptyArray());
for (LLSD::array_const_iterator it = daycycle.beginArray(); it != daycycle.endArray(); ++it)
{
LLSD entry = LLSDMap(SETTING_KEYKFRAME, (*it)[0].asReal())
(SETTING_KEYNAME, "sky:" + (*it)[1].asString());
skytrack.append(entry);
}
LLSD newsettings = LLSDMap
( SETTING_NAME, "Region (legacy)" )
( SETTING_TRACKS, llsd::array(watertrack, skytrack))
( SETTING_FRAMES, frames )
( SETTING_TYPE, "daycycle" );
LLSettingsSky::validation_list_t validations = LLSettingsDay::validationList();
LLSD results = LLSettingsDay::settingValidation(newsettings, validations);
if (!results["success"].asBoolean())
{
LL_WARNS("SETTINGS") << "Day setting validation failed!:" << results << LL_ENDL;
return LLSettingsDay::ptr_t();
}
LLSettingsDay::ptr_t dayp = std::make_shared<LLSettingsVODay>(newsettings);
if (dayp)
{
// true for validation - either validate here, or when cloning for floater.
dayp->initialize(true);
}
return dayp;
}
LLSettingsDay::ptr_t LLSettingsVODay::buildDefaultDayCycle()
{
static LLSD default_settings;
if (!default_settings.size())
{
default_settings = LLSettingsDay::defaults();
default_settings[SETTING_NAME] = DEFAULT_SETTINGS_NAME;
LLSettingsDay::validation_list_t validations = LLSettingsDay::validationList();
LLSD results = LLSettingsDay::settingValidation(default_settings, validations);
if (!results["success"].asBoolean())
{
LL_WARNS("SETTINGS") << "Day setting validation failed!\n" << results << LL_ENDL;
LLSettingsDay::ptr_t();
}
}
LLSettingsDay::ptr_t dayp = std::make_shared<LLSettingsVODay>(default_settings);
dayp->initialize();
return dayp;
}
LLSettingsDay::ptr_t LLSettingsVODay::buildFromEnvironmentMessage(LLSD settings)
{
LLSettingsDay::validation_list_t validations = LLSettingsDay::validationList();
LLSD results = LLSettingsDay::settingValidation(settings, validations);
if (!results["success"].asBoolean())
{
LL_WARNS("SETTINGS") << "Day setting validation failed!\n" << results << LL_ENDL;
LLSettingsDay::ptr_t();
}
LLSettingsDay::ptr_t dayp = std::make_shared<LLSettingsVODay>(settings);
dayp->initialize();
return dayp;
}
void LLSettingsVODay::buildFromOtherSetting(LLSettingsBase::ptr_t settings, LLSettingsVODay::asset_built_fn cb)
{
if (settings->getSettingsType() == "daycycle")
{
if (cb)
cb(std::static_pointer_cast<LLSettingsDay>(settings));
}
else
{
LLSettingsVOBase::getSettingsAsset(LLSettingsDay::GetDefaultAssetId(),
[settings, cb](LLUUID, LLSettingsBase::ptr_t pday, S32, LLExtStat){ combineIntoDayCycle(std::static_pointer_cast<LLSettingsDay>(pday), settings, cb); });
}
}
void LLSettingsVODay::combineIntoDayCycle(LLSettingsDay::ptr_t pday, LLSettingsBase::ptr_t settings, asset_built_fn cb)
{
if (settings->getSettingsType() == "sky")
{
pday->setName("sky: " + settings->getName());
pday->clearCycleTrack(1);
pday->setSettingsAtKeyframe(settings, 0.0, 1);
}
else if (settings->getSettingsType() == "water")
{
pday->setName("water: " + settings->getName());
pday->clearCycleTrack(0);
pday->setSettingsAtKeyframe(settings, 0.0, 0);
}
else
{
pday.reset();
}
if (cb)
cb(pday);
}
LLSettingsDay::ptr_t LLSettingsVODay::buildClone() const
{
LLSD settings = cloneSettings();
LLSettingsDay::validation_list_t validations = LLSettingsDay::validationList();
LLSD results = LLSettingsDay::settingValidation(settings, validations);
if (!results["success"].asBoolean())
{
LL_WARNS("SETTINGS") << "Day setting validation failed!\n" << results << LL_ENDL;
LLSettingsDay::ptr_t();
}
LLSettingsDay::ptr_t dayp = std::make_shared<LLSettingsVODay>(settings);
U32 flags = getFlags();
if (flags)
dayp->setFlags(flags);
dayp->initialize();
return dayp;
}
LLSettingsDay::ptr_t LLSettingsVODay::buildDeepCloneAndUncompress() const
{
// no need for SETTING_TRACKS or SETTING_FRAMES, so take base LLSD
LLSD settings = llsd_clone(mSettings);
U32 flags = getFlags();
LLSettingsDay::ptr_t day_clone = std::make_shared<LLSettingsVODay>(settings);
for (S32 i = 0; i < LLSettingsDay::TRACK_MAX; ++i)
{
const LLSettingsDay::CycleTrack_t& track = getCycleTrackConst(i);
LLSettingsDay::CycleTrack_t::const_iterator iter = track.begin();
while (iter != track.end())
{
// 'Unpack', usually for editing
// - frames 'share' settings multiple times
// - settings can reuse LLSDs they were initialized from
// We do not want for edited frame to change multiple frames in same track, so do a clone
day_clone->setSettingsAtKeyframe(iter->second->buildDerivedClone(), iter->first, i);
iter++;
}
}
day_clone->setFlags(flags);
return day_clone;
}
LLSD LLSettingsVODay::convertToLegacy(const LLSettingsVODay::ptr_t &pday)
{
CycleTrack_t &trackwater = pday->getCycleTrack(TRACK_WATER);
LLSettingsWater::ptr_t pwater;
if (!trackwater.empty())
{
pwater = std::static_pointer_cast<LLSettingsWater>((*trackwater.begin()).second);
}
if (!pwater)
pwater = LLSettingsVOWater::buildDefaultWater();
LLSD llsdwater = LLSettingsVOWater::convertToLegacy(pwater);
CycleTrack_t &tracksky = pday->getCycleTrack(1); // first sky track
std::map<std::string, LLSettingsSky::ptr_t> skys;
LLSD llsdcycle(LLSD::emptyArray());
for(CycleTrack_t::iterator it = tracksky.begin(); it != tracksky.end(); ++it)
{
size_t hash = (*it).second->getHash();
std::stringstream name;
name << hash;
skys[name.str()] = std::static_pointer_cast<LLSettingsSky>((*it).second);
F32 frame = ((tracksky.size() == 1) && (it == tracksky.begin())) ? -1.0f : (*it).first;
llsdcycle.append( llsd::array(LLSD::Real(frame), name.str()) );
}
LLSD llsdskylist(LLSD::emptyMap());
for (std::map<std::string, LLSettingsSky::ptr_t>::iterator its = skys.begin(); its != skys.end(); ++its)
{
LLSD llsdsky = LLSettingsVOSky::convertToLegacy((*its).second, false);
llsdsky[SETTING_NAME] = (*its).first;
llsdskylist[(*its).first] = llsdsky;
}
return llsd::array(LLSD::emptyMap(), llsdcycle, llsdskylist, llsdwater);
}
LLSettingsSkyPtr_t LLSettingsVODay::getDefaultSky() const
{
return LLSettingsVOSky::buildDefaultSky();
}
LLSettingsWaterPtr_t LLSettingsVODay::getDefaultWater() const
{
return LLSettingsVOWater::buildDefaultWater();
}
LLSettingsSkyPtr_t LLSettingsVODay::buildSky(LLSD settings) const
{
LLSettingsSky::ptr_t skyp = std::make_shared<LLSettingsVOSky>(settings);
if (skyp->validate())
return skyp;
return LLSettingsSky::ptr_t();
}
LLSettingsWaterPtr_t LLSettingsVODay::buildWater(LLSD settings) const
{
LLSettingsWater::ptr_t waterp = std::make_shared<LLSettingsVOWater>(settings);
if (waterp->validate())
return waterp;
return LLSettingsWater::ptr_t();
}
//=========================================================================
namespace
{
LLSD ensure_array_4(LLSD in, F32 fill)
{
if (in.size() >= 4)
return in;
LLSD out(LLSD::emptyArray());
for (S32 idx = 0; idx < in.size(); ++idx)
{
out.append(in[idx]);
}
while (out.size() < 4)
{
out.append(LLSD::Real(fill));
}
return out;
}
// This is a disturbing hack
std::string legacy_name_to_filename(const std::string &name, bool convertdash = false)
{
std::string fixedname(LLURI::escape(name));
if (convertdash)
boost::algorithm::replace_all(fixedname, "-", "%2D");
return fixedname;
}
//---------------------------------------------------------------------
LLSD read_legacy_preset_data(const std::string &name, const std::string& path, LLSD &messages)
{
llifstream xml_file;
std::string full_path(path);
std::string full_name(name);
full_name += ".xml";
gDirUtilp->append(full_path, full_name);
xml_file.open(full_path.c_str());
if (!xml_file)
{
std::string bad_path(full_path);
full_path = path;
full_name = legacy_name_to_filename(name);
full_name += ".xml";
gDirUtilp->append(full_path, full_name);
LL_INFOS("LEGACYSETTING") << "Could not open \"" << bad_path << "\" trying escaped \"" << full_path << "\"" << LL_ENDL;
xml_file.open(full_path.c_str());
if (!xml_file)
{
LL_WARNS("LEGACYSETTING") << "Unable to open legacy windlight \"" << name << "\" from " << path << LL_ENDL;
full_path = path;
full_name = legacy_name_to_filename(name, true);
full_name += ".xml";
gDirUtilp->append(full_path, full_name);
xml_file.open(full_path.c_str());
if (!xml_file)
{
messages["REASONS"] = LLTrans::getString("SettingImportFileError", LLSDMap("FILE", bad_path));
LL_WARNS("LEGACYSETTING") << "Unable to open legacy windlight \"" << name << "\" from " << path << LL_ENDL;
return LLSD();
}
}
}
LLSD params_data;
LLPointer<LLSDParser> parser = new LLSDXMLParser();
if (parser->parse(xml_file, params_data, LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE)
{
xml_file.close();
messages["REASONS"] = LLTrans::getString("SettingParseFileError", LLSDMap("FILE", full_path));
return LLSD();
}
xml_file.close();
return params_data;
}
}