summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
authorcosmic-linden <111533034+cosmic-linden@users.noreply.github.com>2024-06-10 11:18:22 -0700
committerGitHub <noreply@github.com>2024-06-10 11:18:22 -0700
commit4705362a332a2347510c81c8d00a1f607ad88af8 (patch)
tree326de5d11a6fa0a4324b7e6456a3fcb6b2f82e08 /indra/newview
parent227e9be06832515fd10eb496d4a2a4528d1ebd92 (diff)
parenteb431ee87948453beec41d4edb22b127b4b01446 (diff)
Merge pull request #1667 from secondlife/v-1475
secondlife/viewer#1475: Add PBR terrain repeats editing
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/app_settings/settings.xml11
-rw-r--r--indra/newview/llfloaterregioninfo.cpp146
-rw-r--r--indra/newview/llfloaterregioninfo.h89
-rw-r--r--indra/newview/llpbrterrainfeatures.cpp198
-rw-r--r--indra/newview/llpbrterrainfeatures.h48
-rwxr-xr-xindra/newview/llviewerregion.cpp43
-rw-r--r--indra/newview/llvlcomposition.cpp30
-rw-r--r--indra/newview/llvlcomposition.h26
-rw-r--r--indra/newview/skins/default/xui/en/panel_region_terrain_texture_transform.xml263
-rw-r--r--indra/newview/skins/default/xui/en/panel_settings_terrain_elevation.xml307
-rw-r--r--indra/newview/skins/default/xui/en/panel_settings_terrain_transform.xml365
12 files changed, 1453 insertions, 75 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index e56534b84d..7568c08430 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -502,6 +502,7 @@ set(viewer_SOURCE_FILES
llpathfindingobject.cpp
llpathfindingobjectlist.cpp
llpathfindingpathtool.cpp
+ llpbrterrainfeatures.cpp
llpersistentnotificationstorage.cpp
llphysicsmotion.cpp
llphysicsshapebuilderutil.cpp
@@ -1148,6 +1149,7 @@ set(viewer_HEADER_FILES
llpathfindingobject.h
llpathfindingobjectlist.h
llpathfindingpathtool.h
+ llpbrterrainfeatures.h
llpersistentnotificationstorage.h
llphysicsmotion.h
llphysicsshapebuilderutil.h
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 3dc72553dc..498b14e211 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -9308,6 +9308,17 @@
<key>Value</key>
<real>8.0</real>
</map>
+ <key>RenderTerrainPBRTransformsEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>EXPERIMENTAL: Enable PBR Terrain texture transforms.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
<key>RenderTerrainPBRNormalsEnabled</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp
index 1f84da4b07..1c4874eae5 100644
--- a/indra/newview/llfloaterregioninfo.cpp
+++ b/indra/newview/llfloaterregioninfo.cpp
@@ -68,6 +68,7 @@
#include "llnamelistctrl.h"
#include "llnotifications.h"
#include "llnotificationsutil.h"
+#include "llpbrterrainfeatures.h"
#include "llregioninfomodel.h"
#include "llscrolllistitem.h"
#include "llsliderctrl.h"
@@ -263,7 +264,16 @@ bool LLFloaterRegionInfo::postBuild()
panel = new LLPanelRegionTerrainInfo;
mInfoPanels.push_back(panel);
- panel->buildFromFile("panel_region_terrain.xml");
+ static LLCachedControl<bool> feature_pbr_terrain_enabled(gSavedSettings, "RenderTerrainPBREnabled", false);
+ static LLCachedControl<bool> feature_pbr_terrain_transforms_enabled(gSavedSettings, "RenderTerrainPBRTransformsEnabled", false);
+ if (!feature_pbr_terrain_transforms_enabled || !feature_pbr_terrain_enabled)
+ {
+ panel->buildFromFile("panel_region_terrain.xml");
+ }
+ else
+ {
+ panel->buildFromFile("panel_region_terrain_texture_transform.xml");
+ }
mTab->addTabPanel(panel);
mEnvironmentPanel = new LLPanelRegionEnvironment;
@@ -554,6 +564,20 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg)
}
// static
+void LLFloaterRegionInfo::sRefreshFromRegion(LLViewerRegion* region)
+{
+ if (region != gAgent.getRegion()) { return; }
+
+ LLFloaterRegionInfo* floater = LLFloaterReg::getTypedInstance<LLFloaterRegionInfo>("region_info");
+ if (!floater) { return; }
+
+ if (floater->getVisible() && region == gAgent.getRegion())
+ {
+ floater->refreshFromRegion(region);
+ }
+}
+
+// static
LLPanelEstateInfo* LLFloaterRegionInfo::getPanelEstate()
{
LLFloaterRegionInfo* floater = LLFloaterReg::getTypedInstance<LLFloaterRegionInfo>("region_info");
@@ -825,6 +849,13 @@ void LLPanelRegionInfo::initCtrl(const std::string& name)
getChild<LLUICtrl>(name)->setCommitCallback(boost::bind(&LLPanelRegionInfo::onChangeAnything, this));
}
+template<typename CTRL>
+void LLPanelRegionInfo::initAndSetCtrl(CTRL*& ctrl, const std::string& name)
+{
+ initCtrl(name);
+ ctrl = findChild<CTRL>(name);
+}
+
void LLPanelRegionInfo::onClickManageTelehub()
{
LLFloaterReg::hideInstance("region_info");
@@ -1494,11 +1525,17 @@ LLPanelRegionTerrainInfo::LLPanelRegionTerrainInfo()
const LLUUID (&default_textures)[LLVLComposition::ASSET_COUNT] = LLVLComposition::getDefaultTextures();
for (S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i)
{
+ mTextureDetailCtrl[i] = nullptr;
+ mMaterialDetailCtrl[i] = nullptr;
+
mLastSetTextures[i] = default_textures[i];
- }
- for (S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i)
- {
mLastSetMaterials[i] = BLANK_MATERIAL_ASSET_ID;
+
+ mMaterialScaleUCtrl[i] = nullptr;
+ mMaterialScaleVCtrl[i] = nullptr;
+ mMaterialRotationCtrl[i] = nullptr;
+ mMaterialOffsetUCtrl[i] = nullptr;
+ mMaterialOffsetVCtrl[i] = nullptr;
}
}
@@ -1519,19 +1556,18 @@ bool LLPanelRegionTerrainInfo::postBuild()
for(S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i)
{
- buffer = llformat("texture_detail_%d", i);
- initCtrl(buffer);
- mTextureDetailCtrl[i] = findChild<LLTextureCtrl>(buffer);
- if (mTextureDetailCtrl)
+ initAndSetCtrl(mTextureDetailCtrl[i], llformat("texture_detail_%d", i));
+ if (mTextureDetailCtrl[i])
{
mTextureDetailCtrl[i]->setBakeTextureEnabled(false);
}
- }
- for(S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i)
- {
- buffer = llformat("material_detail_%d", i);
- initCtrl(buffer);
- mMaterialDetailCtrl[i] = findChild<LLTextureCtrl>(buffer);
+ initAndSetCtrl(mMaterialDetailCtrl[i], llformat("material_detail_%d", i));
+
+ initAndSetCtrl(mMaterialScaleUCtrl[i], llformat("terrain%dScaleU", i));
+ initAndSetCtrl(mMaterialScaleVCtrl[i], llformat("terrain%dScaleV", i));
+ initAndSetCtrl(mMaterialRotationCtrl[i], llformat("terrain%dRotation", i));
+ initAndSetCtrl(mMaterialOffsetUCtrl[i], llformat("terrain%dOffsetU", i));
+ initAndSetCtrl(mMaterialOffsetVCtrl[i], llformat("terrain%dOffsetV", i));
}
for(S32 i = 0; i < CORNER_COUNT; ++i)
@@ -1583,6 +1619,17 @@ void LLPanelRegionTerrainInfo::updateForMaterialType()
}
}
+ // Toggle visibility of terrain tabs
+ LLTabContainer* terrain_tabs = findChild<LLTabContainer>("terrain_tabs");
+ if (terrain_tabs)
+ {
+ LLPanel* pbr_terrain_repeats_tab = findChild<LLPanel>("terrain_transform_panel");
+ if (pbr_terrain_repeats_tab)
+ {
+ terrain_tabs->setTabVisibility(pbr_terrain_repeats_tab, show_material_controls);
+ }
+ }
+
// Toggle visibility of labels
LLUICtrl* texture_label = findChild<LLUICtrl>("detail_texture_text");
if (texture_label) { texture_label->setVisible(show_texture_controls); }
@@ -1711,6 +1758,21 @@ bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region)
}
}
+ for(S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i)
+ {
+ if (!mMaterialScaleUCtrl[i] || !mMaterialScaleVCtrl[i] || !mMaterialRotationCtrl[i] || !mMaterialOffsetUCtrl[i] || !mMaterialOffsetVCtrl[i]) { continue; }
+ const LLGLTFMaterial* mat_override = compp->getMaterialOverride(i);
+ if (!mat_override) { mat_override = &LLGLTFMaterial::sDefault; }
+
+ // Assume all texture transforms have the same value
+ const LLGLTFMaterial::TextureTransform& transform = mat_override->mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR];
+ mMaterialScaleUCtrl[i]->setValue(transform.mScale.mV[VX]);
+ mMaterialScaleVCtrl[i]->setValue(transform.mScale.mV[VY]);
+ mMaterialRotationCtrl[i]->setValue(transform.mRotation * RAD_TO_DEG);
+ mMaterialOffsetUCtrl[i]->setValue(transform.mOffset.mV[VX]);
+ mMaterialOffsetVCtrl[i]->setValue(transform.mOffset.mV[VY]);
+ }
+
std::string buffer;
for(S32 i = 0; i < CORNER_COUNT; ++i)
{
@@ -1725,7 +1787,7 @@ bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region)
LL_DEBUGS() << "no region set" << LL_ENDL;
getChild<LLUICtrl>("region_text")->setValue(LLSD(""));
}
-
+
// Update visibility of terrain swatches, etc
refresh();
@@ -1740,7 +1802,14 @@ bool LLPanelRegionTerrainInfo::refreshFromRegion(LLViewerRegion* region)
// virtual
bool LLPanelRegionTerrainInfo::sendUpdate()
{
- LL_INFOS() << "LLPanelRegionTerrainInfo::sendUpdate" << LL_ENDL;
+ LL_INFOS() << __FUNCTION__ << LL_ENDL;
+
+ LLUICtrl* apply_btn = getChild<LLUICtrl>("apply_btn");
+ if (apply_btn && !apply_btn->getEnabled())
+ {
+ LL_WARNS() << "Duplicate update, ignored" << LL_ENDL;
+ return false;
+ }
// Make sure user hasn't chosen wacky textures.
if (!validateTextureSizes())
@@ -1841,6 +1910,51 @@ bool LLPanelRegionTerrainInfo::sendUpdate()
sendEstateOwnerMessage(msg, "texturecommit", invoice, strings);
+ // ========================================
+ // POST to ModifyRegion endpoint, if enabled
+
+ static LLCachedControl<bool> feature_pbr_terrain_transforms_enabled(gSavedSettings, "RenderTerrainPBRTransformsEnabled", false);
+ if (material_type == LLTerrainMaterials::Type::PBR && feature_pbr_terrain_transforms_enabled)
+ {
+ LLTerrainMaterials composition;
+ for (S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i)
+ {
+ LLPointer<LLGLTFMaterial> mat_override = new LLGLTFMaterial();
+
+ const bool transform_controls_valid = mMaterialScaleUCtrl[i] && mMaterialScaleVCtrl[i] && mMaterialRotationCtrl[i] && mMaterialOffsetUCtrl[i] && mMaterialOffsetVCtrl[i];
+ if (transform_controls_valid)
+ {
+ // Set texture transforms for all texture infos to the same value,
+ // because the PBR terrain shader doesn't currently support
+ // different transforms per texture info. See also
+ // LLDrawPoolTerrain::renderFullShaderPBR .
+ for (U32 tt = 0; tt < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++tt)
+ {
+ LLGLTFMaterial::TextureTransform& transform = mat_override->mTextureTransform[tt];
+ transform.mScale.mV[VX] = mMaterialScaleUCtrl[i]->getValue().asReal();
+ transform.mScale.mV[VY] = mMaterialScaleVCtrl[i]->getValue().asReal();
+ transform.mRotation = mMaterialRotationCtrl[i]->getValue().asReal() * DEG_TO_RAD;
+ transform.mOffset.mV[VX] = mMaterialOffsetUCtrl[i]->getValue().asReal();
+ transform.mOffset.mV[VY] = mMaterialOffsetVCtrl[i]->getValue().asReal();
+ }
+ }
+
+ if (*mat_override == LLGLTFMaterial::sDefault) { mat_override = nullptr; }
+ composition.setMaterialOverride(i, mat_override.get());
+ }
+
+ // queueModify leads to a few messages being sent back and forth:
+ // viewer: POST ModifyRegion
+ // simulator: RegionHandshake
+ // viewer: GET ModifyRegion
+ LLViewerRegion* region = gAgent.getRegion();
+ llassert(region);
+ if (region)
+ {
+ LLPBRTerrainFeatures::queueModify(*region, composition);
+ }
+ }
+
return true;
}
diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h
index 4b81a26210..1634683d90 100644
--- a/indra/newview/llfloaterregioninfo.h
+++ b/indra/newview/llfloaterregioninfo.h
@@ -1,4 +1,4 @@
-/**
+/**
* @file llfloaterregioninfo.h
* @author Aaron Brashears
* @brief Declaration of the region info and controls floater and panels.
@@ -6,21 +6,21 @@
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
@@ -85,6 +85,7 @@ public:
// get and process region info if necessary.
static void processRegionInfo(LLMessageSystem* msg);
+ static void sRefreshFromRegion(LLViewerRegion* region);
static const LLUUID& getLastInvoice() { return sRequestInvoice; }
static void nextInvoice() { sRequestInvoice.generate(); }
@@ -101,14 +102,14 @@ public:
// from LLPanel
void refresh() override;
-
+
void onRegionChanged();
void requestRegionInfo();
void enableTopButtons();
void disableTopButtons();
private:
-
+
LLFloaterRegionInfo(const LLSD& seed);
~LLFloaterRegionInfo();
@@ -137,30 +138,31 @@ class LLPanelRegionInfo : public LLPanel
{
public:
LLPanelRegionInfo();
-
+
void onBtnSet();
void onChangeChildCtrl(LLUICtrl* ctrl);
void onChangeAnything();
static void onChangeText(LLLineEditor* caller, void* user_data);
-
+
virtual bool refreshFromRegion(LLViewerRegion* region);
virtual bool estateUpdate(LLMessageSystem* msg) { return true; }
-
+
bool postBuild() override;
virtual void updateChild(LLUICtrl* child_ctrl);
-
+
void enableButton(const std::string& btn_name, bool enable = true);
void disableButton(const std::string& btn_name);
-
+
void onClickManageTelehub();
-
+
protected:
void initCtrl(const std::string& name);
-
+ template<typename CTRL> void initAndSetCtrl(CTRL*& ctrl, const std::string& name);
+
// Returns true if update sent and apply button should be
// disabled.
virtual bool sendUpdate() { return true; }
-
+
typedef std::vector<std::string> strings_t;
//typedef std::vector<U32> integers_t;
void sendEstateOwnerMessage(
@@ -168,8 +170,8 @@ protected:
const std::string& request,
const LLUUID& invoice,
const strings_t& strings);
-
-
+
+
// member data
LLHost mHost;
};
@@ -180,16 +182,16 @@ protected:
class LLPanelRegionGeneralInfo : public LLPanelRegionInfo
{
-
+
public:
LLPanelRegionGeneralInfo()
: LLPanelRegionInfo() {}
~LLPanelRegionGeneralInfo() {}
-
+
bool refreshFromRegion(LLViewerRegion* region) override;
-
+
bool postBuild() override;
-
+
void onBtnSet();
void setObjBonusFactor(F32 object_bonus_factor) {mObjBonusFactor = object_bonus_factor;}
@@ -217,9 +219,9 @@ public:
~LLPanelRegionDebugInfo() {}
bool postBuild() override;
-
+
bool refreshFromRegion(LLViewerRegion* region) override;
-
+
protected:
bool sendUpdate() override;
@@ -233,7 +235,7 @@ protected:
bool callbackRestart(const LLSD& notification, const LLSD& response);
static void onClickCancelRestart(void* data);
static void onClickDebugConsole(void* data);
-
+
private:
LLUUID mTargetAvatar;
};
@@ -247,9 +249,9 @@ class LLPanelRegionTerrainInfo : public LLPanelRegionInfo
public:
LLPanelRegionTerrainInfo();
~LLPanelRegionTerrainInfo() {}
-
+
bool postBuild() override;
-
+
bool refreshFromRegion(LLViewerRegion* region) override; // refresh local settings from region update from simulator
void setEnvControls(bool available); // Whether environment settings are available for this region
@@ -258,7 +260,7 @@ public:
bool validateTextureHeights();
//static void onChangeAnything(LLUICtrl* ctrl, void* userData); // callback for any change, to enable commit button
-
+
void onSelectMaterialType();
void updateForMaterialType();
@@ -277,8 +279,15 @@ private:
LLCheckBoxCtrl* mMaterialTypeCtrl = nullptr;
LLTextureCtrl* mTextureDetailCtrl[LLTerrainMaterials::ASSET_COUNT];
LLTextureCtrl* mMaterialDetailCtrl[LLTerrainMaterials::ASSET_COUNT];
+
LLUUID mLastSetTextures[LLTerrainMaterials::ASSET_COUNT];
LLUUID mLastSetMaterials[LLTerrainMaterials::ASSET_COUNT];
+
+ LLSpinCtrl* mMaterialScaleUCtrl[LLTerrainMaterials::ASSET_COUNT];
+ LLSpinCtrl* mMaterialScaleVCtrl[LLTerrainMaterials::ASSET_COUNT];
+ LLSpinCtrl* mMaterialRotationCtrl[LLTerrainMaterials::ASSET_COUNT];
+ LLSpinCtrl* mMaterialOffsetUCtrl[LLTerrainMaterials::ASSET_COUNT];
+ LLSpinCtrl* mMaterialOffsetVCtrl[LLTerrainMaterials::ASSET_COUNT];
};
/////////////////////////////////////////////////////////////////////////////
@@ -287,13 +296,13 @@ class LLPanelEstateInfo : public LLPanelRegionInfo
{
public:
static void initDispatch(LLDispatcher& dispatch);
-
+
void onChangeFixedSun();
void onChangeUseGlobalTime();
void onChangeAccessOverride();
-
+
void onClickEditSky();
- void onClickEditSkyHelp();
+ void onClickEditSkyHelp();
void onClickEditDayCycle();
void onClickEditDayCycleHelp();
@@ -305,26 +314,26 @@ public:
void onKickUserCommit(const uuid_vec_t& ids);
static void onClickMessageEstate(void* data);
bool onMessageCommit(const LLSD& notification, const LLSD& response);
-
+
LLPanelEstateInfo();
~LLPanelEstateInfo() {}
-
+
void updateControls(LLViewerRegion* region);
-
+
static void updateEstateName(const std::string& name);
static void updateEstateOwnerName(const std::string& name);
bool refreshFromRegion(LLViewerRegion* region) override;
bool estateUpdate(LLMessageSystem* msg) override;
-
+
bool postBuild() override;
void updateChild(LLUICtrl* child_ctrl) override;
void refresh() override;
void refreshFromEstate();
-
+
static bool isLindenEstate();
-
+
const std::string getOwnerName() const;
void setOwnerName(const std::string& name);
@@ -335,7 +344,7 @@ protected:
void commitEstateAccess();
void commitEstateManagers();
-
+
bool checkSunHourSlider(LLUICtrl* child_ctrl);
U32 mEstateID;
@@ -348,7 +357,7 @@ class LLPanelEstateCovenant : public LLPanelRegionInfo
public:
LLPanelEstateCovenant();
~LLPanelEstateCovenant() {}
-
+
bool postBuild() override;
void updateChild(LLUICtrl* child_ctrl) override;
bool refreshFromRegion(LLViewerRegion* region) override;
@@ -411,7 +420,7 @@ class LLPanelRegionExperiences : public LLPanelRegionInfo
public:
LLPanelRegionExperiences(){}
bool postBuild() override;
-
+
static bool experienceCoreConfirm(const LLSD& notification, const LLSD& response);
static void sendEstateExperienceDelta(U32 flags, const LLUUID& agent_id);
@@ -473,7 +482,7 @@ private:
void onAllowedSearchEdit(const std::string& search_string);
void onAllowedGroupsSearchEdit(const std::string& search_string);
void onBannedSearchEdit(const std::string& search_string);
-
+
// Group picker callback is different, can't use core methods below
bool addAllowedGroup(const LLSD& notification, const LLSD& response);
void addAllowedGroup2(LLUUID id);
diff --git a/indra/newview/llpbrterrainfeatures.cpp b/indra/newview/llpbrterrainfeatures.cpp
new file mode 100644
index 0000000000..bb771c6963
--- /dev/null
+++ b/indra/newview/llpbrterrainfeatures.cpp
@@ -0,0 +1,198 @@
+/**
+ * @file llpbrterrainfeatures.cpp
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, 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 "llpbrterrainfeatures.h"
+
+#include "llappviewer.h"
+#include "llgltfmaterial.h"
+#include "llviewerregion.h"
+#include "llvlcomposition.h"
+
+LLPBRTerrainFeatures gPBRTerrainFeatures;
+
+// static
+void LLPBRTerrainFeatures::queueQuery(LLViewerRegion& region, void(*done_callback)(LLUUID, bool, const LLModifyRegion&))
+{
+ llassert(on_main_thread());
+ llassert(LLCoros::on_main_coro());
+
+ LLUUID region_id = region.getRegionID();
+
+ LLCoros::instance().launch("queryRegionCoro",
+ std::bind(&LLPBRTerrainFeatures::queryRegionCoro,
+ region.getCapability("ModifyRegion"),
+ region_id,
+ done_callback));
+}
+
+// static
+void LLPBRTerrainFeatures::queueModify(LLViewerRegion& region, const LLModifyRegion& composition)
+{
+ llassert(on_main_thread());
+ llassert(LLCoros::on_main_coro());
+
+ LLSD updates = LLSD::emptyMap();
+
+ LLSD override_updates = LLSD::emptyArray();
+ for (S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i)
+ {
+ const LLGLTFMaterial* material_override = composition.getMaterialOverride(i);
+ LLSD override_update;
+ if (material_override)
+ {
+ LLGLTFMaterial::sDefault.getOverrideLLSD(*material_override, override_update);
+ }
+ else
+ {
+ override_update = LLSD::emptyMap();
+ }
+ override_updates.append(override_update);
+ }
+ updates["overrides"] = override_updates;
+
+ LLCoros::instance().launch("modifyRegionCoro",
+ std::bind(&LLPBRTerrainFeatures::modifyRegionCoro,
+ region.getCapability("ModifyRegion"),
+ updates,
+ nullptr));
+}
+
+// static
+void LLPBRTerrainFeatures::queryRegionCoro(std::string cap_url, LLUUID region_id, void(*done_callback)(LLUUID, bool, const LLModifyRegion&) )
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("queryRegionCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+ LLCore::HttpHeaders::ptr_t httpHeaders;
+
+ httpOpts->setFollowRedirects(true);
+
+ LL_DEBUGS("GLTF") << "Querying features via ModifyRegion endpoint" << LL_ENDL;
+
+ LLSD result = httpAdapter->getAndSuspend(httpRequest, cap_url, httpOpts, httpHeaders);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ bool success = true;
+ if (!status || !result["success"].asBoolean())
+ {
+ if (result["message"].isUndefined())
+ {
+ LL_WARNS("PBRTerrain") << "Failed to query PBR terrain features." << LL_ENDL;
+ }
+ else
+ {
+ LL_WARNS("PBRTerrain") << "Failed to query PBR terrain features: " << result["message"] << LL_ENDL;
+ }
+ success = false;
+ }
+
+ LLTerrainMaterials* composition = new LLTerrainMaterials();
+
+ if (success)
+ {
+ const LLSD& overrides = result["overrides"];
+ if (!overrides.isArray() || overrides.size() < LLTerrainMaterials::ASSET_COUNT)
+ {
+ LL_WARNS("PBRTerrain") << "Invalid composition format: Missing/invalid overrides" << LL_ENDL;
+ success = false;
+ }
+ else
+ {
+ for (S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i)
+ {
+ const LLSD& override_llsd = overrides[i];
+ LLPointer<LLGLTFMaterial> material_override = new LLGLTFMaterial();
+ material_override->applyOverrideLLSD(override_llsd);
+ if (*material_override == LLGLTFMaterial::sDefault)
+ {
+ material_override = nullptr;
+ }
+ composition->setMaterialOverride(i, material_override.get());
+ }
+ }
+ }
+
+ if (done_callback)
+ {
+ LLAppViewer::instance()->postToMainCoro([=]()
+ {
+ done_callback(region_id, success, *composition);
+ delete composition;
+ });
+ }
+ else
+ {
+ delete composition;
+ }
+}
+
+// static
+void LLPBRTerrainFeatures::modifyRegionCoro(std::string cap_url, LLSD updates, void(*done_callback)(bool) )
+{
+ LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
+ LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
+ httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("modifyRegionCoro", httpPolicy));
+ LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
+ LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
+ LLCore::HttpHeaders::ptr_t httpHeaders;
+
+ httpOpts->setFollowRedirects(true);
+
+ LL_DEBUGS("GLTF") << "Applying features via ModifyRegion endpoint: " << updates << LL_ENDL;
+
+ LLSD result = httpAdapter->postAndSuspend(httpRequest, cap_url, updates, httpOpts, httpHeaders);
+
+ LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
+ LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
+
+ bool success = true;
+ if (!status || !result["success"].asBoolean())
+ {
+ if (result["message"].isUndefined())
+ {
+ LL_WARNS("PBRTerrain") << "Failed to modify PBR terrain features." << LL_ENDL;
+ }
+ else
+ {
+ LL_WARNS("PBRTerrain") << "Failed to modify PBR terrain features: " << result["message"] << LL_ENDL;
+ }
+ success = false;
+ }
+
+ if (done_callback)
+ {
+ LLAppViewer::instance()->postToMainCoro([=]()
+ {
+ done_callback(success);
+ });
+ }
+}
+
diff --git a/indra/newview/llpbrterrainfeatures.h b/indra/newview/llpbrterrainfeatures.h
new file mode 100644
index 0000000000..f29d4ebf50
--- /dev/null
+++ b/indra/newview/llpbrterrainfeatures.h
@@ -0,0 +1,48 @@
+/**
+ * @file llpbrterrainfeatures.h
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2024, 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$
+ */
+
+
+#pragma once
+
+#include <string>
+
+class LLViewerRegion;
+class LLMessageSystem;
+class LLModifyRegion;
+
+// Queries/modifies PBR terrain repeats, possibly other features in the future
+class LLPBRTerrainFeatures
+{
+public:
+ static void queueQuery(LLViewerRegion& region, void(*done_callback)(LLUUID, bool, const LLModifyRegion&));
+ static void queueModify(LLViewerRegion& region, const LLModifyRegion& composition);
+
+private:
+ static void queryRegionCoro(std::string cap_url, LLUUID region_id, void(*done_callback)(LLUUID, bool, const LLModifyRegion&) );
+ static void modifyRegionCoro(std::string cap_url, LLSD updates, void(*done_callback)(bool) );
+};
+
+extern LLPBRTerrainFeatures gPBRTerrainFeatures;
+
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index bf4bdfd252..699cde8969 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -55,6 +55,7 @@
#include "llfloaterregioninfo.h"
#include "llgltfmateriallist.h"
#include "llhttpnode.h"
+#include "llpbrterrainfeatures.h"
#include "llregioninfomodel.h"
#include "llsdutil.h"
#include "llstartup.h"
@@ -2462,6 +2463,26 @@ void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features)
gSavedSettings.setS32("max_texture_dimension_Y", 1024);
}
+ if (features.has("PBRTerrainEnabled"))
+ {
+ bool enabled = features["PBRTerrainEnabled"];
+ gSavedSettings.setBOOL("RenderTerrainPBREnabled", enabled);
+ }
+ else
+ {
+ gSavedSettings.setBOOL("RenderTerrainPBREnabled", false);
+ }
+
+ if (features.has("PBRMaterialSwatchEnabled"))
+ {
+ bool enabled = features["PBRMaterialSwatchEnabled"];
+ gSavedSettings.setBOOL("UIPreviewMaterial", enabled);
+ }
+ else
+ {
+ gSavedSettings.setBOOL("UIPreviewMaterial", false);
+ }
+
if (features.has("GLTFEnabled"))
{
bool enabled = features["GLTFEnabled"];
@@ -2471,6 +2492,16 @@ void LLViewerRegion::setSimulatorFeatures(const LLSD& sim_features)
{
gSavedSettings.setBOOL("GLTFEnabled", false);
}
+
+ if (features.has("PBRTerrainTransformsEnabled"))
+ {
+ bool enabled = features["PBRTerrainTransformsEnabled"];
+ gSavedSettings.setBOOL("RenderTerrainTransformsPBREnabled", enabled);
+ }
+ else
+ {
+ gSavedSettings.setBOOL("RenderTerrainTransformsPBREnabled", false);
+ }
};
@@ -3109,6 +3140,17 @@ void LLViewerRegion::unpackRegionHandshake()
{
compp->setParamsReady();
}
+
+ LLPBRTerrainFeatures::queueQuery(*this, [](LLUUID region_id, bool success, const LLModifyRegion& composition_changes)
+ {
+ if (!success) { return; }
+ LLViewerRegion* region = LLWorld::getInstance()->getRegionFromID(region_id);
+ if (!region) { return; }
+ LLVLComposition* compp = region->getComposition();
+ if (!compp) { return; }
+ compp->apply(composition_changes);
+ LLFloaterRegionInfo::sRefreshFromRegion(region);
+ });
}
@@ -3206,6 +3248,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
capabilityNames.append("MapLayerGod");
capabilityNames.append("MeshUploadFlag");
capabilityNames.append("ModifyMaterialParams");
+ capabilityNames.append("ModifyRegion");
capabilityNames.append("NavMeshGenerationStatus");
capabilityNames.append("NewFileAgentInventory");
capabilityNames.append("ObjectAnimation");
diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp
index bc2fab99c0..c509d656e1 100644
--- a/indra/newview/llvlcomposition.cpp
+++ b/indra/newview/llvlcomposition.cpp
@@ -1,25 +1,25 @@
-/**
+/**
* @file llvlcomposition.cpp
* @brief Viewer-side representation of a composition layer...
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
@@ -115,6 +115,16 @@ LLTerrainMaterials::~LLTerrainMaterials()
unboost();
}
+void LLTerrainMaterials::apply(const LLModifyRegion& other)
+{
+ for (S32 i = 0; i < LLTerrainMaterials::ASSET_COUNT; ++i)
+ {
+ const LLGLTFMaterial* other_override = other.getMaterialOverride(i);
+ LLGLTFMaterial* material_override = other_override ? new LLGLTFMaterial(*other_override) : nullptr;
+ setMaterialOverride(i, material_override);
+ }
+}
+
bool LLTerrainMaterials::generateMaterials()
{
if (texturesReady(true, true))
@@ -192,7 +202,7 @@ void LLTerrainMaterials::setDetailAssetID(S32 asset, const LLUUID& id)
mMaterialTexturesSet[asset] = false;
}
-const LLGLTFMaterial* LLTerrainMaterials::getMaterialOverride(S32 asset)
+const LLGLTFMaterial* LLTerrainMaterials::getMaterialOverride(S32 asset) const
{
return mDetailMaterialOverrides[asset];
}
@@ -461,7 +471,7 @@ bool LLVLComposition::generateHeights(const F32 x, const F32 y,
llassert(mSurfacep);
- if (!mSurfacep || !mSurfacep->getRegion())
+ if (!mSurfacep || !mSurfacep->getRegion())
{
// We don't always have the region yet here....
return false;
@@ -529,7 +539,7 @@ bool LLVLComposition::generateHeights(const F32 x, const F32 y,
vec[1] = (F32)(origin_global.mdV[VY]+location.mV[VY])*xyScaleInv;
vec[2] = height*zScaleInv;
//
- // Choose material value by adding to the exact height a random value
+ // Choose material value by adding to the exact height a random value
//
vec1[0] = vec[0]*(0.2222222222f);
vec1[1] = vec[1]*(0.2222222222f);
@@ -863,7 +873,7 @@ bool LLVLComposition::generateMinimapTileLand(const F32 x, const F32 y,
U32 st_comps = 3;
U32 st_width = BASE_SIZE;
U32 st_height = BASE_SIZE;
-
+
if (tex_comps != st_comps)
{
llassert(false);
@@ -968,7 +978,7 @@ bool LLVLComposition::generateMinimapTileLand(const F32 x, const F32 y,
{
unboost_minimap_material(mDetailMaterials[i]);
}
-
+
return true;
}
diff --git a/indra/newview/llvlcomposition.h b/indra/newview/llvlcomposition.h
index f7590348f0..a003f74eda 100644
--- a/indra/newview/llvlcomposition.h
+++ b/indra/newview/llvlcomposition.h
@@ -1,25 +1,25 @@
-/**
+/**
* @file llvlcomposition.h
* @brief Viewer-side representation of a composition layer...
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, 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$
*/
@@ -38,7 +38,13 @@ class LLViewerFetchedTexture;
class LLGLTFMaterial;
class LLFetchedGLTFMaterial;
-class LLTerrainMaterials
+class LLModifyRegion
+{
+public:
+ virtual const LLGLTFMaterial* getMaterialOverride(S32 asset) const = 0;
+};
+
+class LLTerrainMaterials : public LLModifyRegion
{
public:
friend class LLDrawPoolTerrain;
@@ -46,6 +52,8 @@ public:
LLTerrainMaterials();
virtual ~LLTerrainMaterials();
+ void apply(const LLModifyRegion& other);
+
// Heights map into textures (or materials) as 0-1 = first, 1-2 = second, etc.
// So we need to compress heights into this range.
static const S32 ASSET_COUNT = 4;
@@ -63,7 +71,7 @@ public:
virtual LLUUID getDetailAssetID(S32 asset);
virtual void setDetailAssetID(S32 asset, const LLUUID& id);
- virtual const LLGLTFMaterial* getMaterialOverride(S32 asset);
+ const LLGLTFMaterial* getMaterialOverride(S32 asset) const override;
virtual void setMaterialOverride(S32 asset, LLGLTFMaterial* mat_override);
Type getMaterialType();
bool texturesReady(bool boost, bool strict);
@@ -107,8 +115,8 @@ public:
bool generateHeights(const F32 x, const F32 y, const F32 width, const F32 height);
bool generateComposition();
// Generate texture from composition values.
- bool generateMinimapTileLand(const F32 x, const F32 y, const F32 width, const F32 height);
- bool generateTexture(const F32 x, const F32 y, const F32 width, const F32 height);
+ bool generateMinimapTileLand(const F32 x, const F32 y, const F32 width, const F32 height);
+ bool generateTexture(const F32 x, const F32 y, const F32 width, const F32 height);
// Use these as indeces ito the get/setters below that use 'corner'
enum ECorner
diff --git a/indra/newview/skins/default/xui/en/panel_region_terrain_texture_transform.xml b/indra/newview/skins/default/xui/en/panel_region_terrain_texture_transform.xml
new file mode 100644
index 0000000000..cbcbe418cd
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_region_terrain_texture_transform.xml
@@ -0,0 +1,263 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel
+ border="true"
+ follows="top|left"
+ height="460"
+ help_topic="panel_region_terrain_tab"
+ label="Terrain"
+ layout="topleft"
+ left="0"
+ name="Terrain"
+ top="320"
+ width="480">
+ <text
+ follows="left|top"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ left="10"
+ name="region_text_lbl"
+ top="10"
+ width="100">
+ Region:
+ </text>
+ <text
+ follows="left|top"
+ font="SansSerif"
+ height="20"
+ layout="topleft"
+ left_delta="50"
+ name="region_text"
+ top_delta="0"
+ width="400">
+ unknown
+ </text>
+ <text
+ type="string"
+ length="1"
+ halign="left"
+ valign="center"
+ follows="left|top"
+ height="20"
+ layout="topleft"
+ name="detail_texture_text"
+ left="10"
+ top="35"
+ width="170">
+ Terrain Textures
+ </text>
+ <text
+ type="string"
+ length="1"
+ halign="left"
+ valign="center"
+ follows="left|top"
+ height="20"
+ layout="topleft"
+ name="detail_material_text"
+ left="10"
+ top="35"
+ width="170">
+ Terrain Materials
+ </text>
+ <check_box
+ height="20"
+ halign="left"
+ valign="center"
+ follows="left|top"
+ layout="topleft"
+ top_delta="1"
+ left_delta="180"
+ label="PBR Metallic Roughness"
+ name="terrain_material_type"
+ tool_tip="If checked, use PBR Metallic Roughness materials for terrain. Otherwise, use textures."
+ left_pad="2"
+ width="200" />
+ <texture_picker
+ follows="left|top"
+ height="121"
+ layout="topleft"
+ left="10"
+ name="texture_detail_0"
+ default_image_id="0bc58228-74a0-7e83-89bc-5c23464bcec5"
+ top_delta="30"
+ width="100" />
+ <texture_picker
+ follows="top"
+ height="121"
+ layout="topleft"
+ left_pad="10"
+ name="texture_detail_1"
+ default_image_id="63338ede-0037-c4fd-855b-015d77112fc8"
+ top_delta="0"
+ width="100" />
+ <texture_picker
+ follows="left|top"
+ height="121"
+ layout="topleft"
+ left_pad="10"
+ name="texture_detail_2"
+ default_image_id="303cd381-8560-7579-23f1-f0a880799740"
+ top_delta="0"
+ width="100" />
+ <texture_picker
+ follows="left|top"
+ height="121"
+ layout="topleft"
+ left_pad="10"
+ name="texture_detail_3"
+ default_image_id="53a2f406-4895-1d13-d541-d2e3b86bc19c"
+ top_delta="0"
+ width="100" />
+ <texture_picker
+ visible="false"
+ follows="left|top"
+ height="121"
+ layout="topleft"
+ left="10"
+ name="material_detail_0"
+ pick_type="material"
+ default_image_id="968cbad0-4dad-d64e-71b5-72bf13ad051a"
+ top_delta="0"
+ width="100" />
+ <texture_picker
+ visible="false"
+ follows="left|top"
+ height="121"
+ layout="topleft"
+ left_pad="10"
+ name="material_detail_1"
+ pick_type="material"
+ default_image_id="968cbad0-4dad-d64e-71b5-72bf13ad051a"
+ top_delta="0"
+ width="100" />
+ <texture_picker
+ visible="false"
+ follows="left|top"
+ height="121"
+ layout="topleft"
+ left_pad="10"
+ name="material_detail_2"
+ pick_type="material"
+ default_image_id="968cbad0-4dad-d64e-71b5-72bf13ad051a"
+ top_delta="0"
+ width="100" />
+ <texture_picker
+ visible="false"
+ follows="left|top"
+ height="121"
+ layout="topleft"
+ left_pad="10"
+ name="material_detail_3"
+ pick_type="material"
+ default_image_id="968cbad0-4dad-d64e-71b5-72bf13ad051a"
+ top_delta="0"
+ width="100" />
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="20"
+ layout="topleft"
+ left="10"
+ name="height_text_lbl"
+ top_delta="104"
+ width="65">
+ 1 (Low)
+ </text>
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="20"
+ layout="topleft"
+ left_pad="45"
+ name="height_text_lbl2"
+ top_delta="0"
+ width="100">
+ 2
+ </text>
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="20"
+ layout="topleft"
+ left_pad="10"
+ name="height_text_lbl3"
+ top_delta="0"
+ width="100">
+ 3
+ </text>
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="20"
+ layout="topleft"
+ left_pad="10"
+ name="height_text_lbl4"
+ top_delta="0"
+ width="100">
+ 4 (High)
+ </text>
+ <layout_stack name="terrain_features_stack"
+ width="477"
+ height="230"
+ follows="all"
+ animate="false"
+ left="0"
+ top_delta="22"
+ orientation="vertical">
+ <layout_panel name="frame_settings_terrain"
+ auto_resize="true"
+ user_resize="false"
+ height="230"
+ width="467"
+ min_height="0"
+ visible="true">
+ <tab_container
+ follows="all"
+ halign="left"
+ height="230"
+ visible="true"
+ layout="topleft"
+ left="0"
+ name="terrain_tabs"
+ tab_position="top"
+ tab_width="100"
+ tab_padding_right="3"
+ top_pad="0"
+ width="700">
+ <panel
+ border="true"
+ class="panel_settings_terrain_elevation"
+ filename="panel_settings_terrain_elevation.xml"
+ label="Elevation"
+ layout="topleft"
+ left_delta="0"
+ top_pad="5"
+ name="terrain_elevation_panel" />
+ <panel
+ border="true"
+ class="panel_settings_terrain_transform"
+ filename="panel_settings_terrain_transform.xml"
+ label="Transforms"
+ layout="topleft"
+ left_delta="0"
+ top_pad="5"
+ name="terrain_transform_panel" />
+ </tab_container>
+ </layout_panel>
+ </layout_stack>
+ <button
+ enabled="true"
+ follows="left|top"
+ height="20"
+ label="Apply"
+ layout="topleft"
+ left="353"
+ name="apply_btn"
+ top_delta="290"
+ width="100" />
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_settings_terrain_elevation.xml b/indra/newview/skins/default/xui/en/panel_settings_terrain_elevation.xml
new file mode 100644
index 0000000000..89443290ce
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_settings_terrain_elevation.xml
@@ -0,0 +1,307 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel
+ border="true"
+ follows="all"
+ label="Elevation"
+ layout="topleft"
+ left="0"
+ name="panel_settings_terrain_elevation"
+ top="0">
+ <spinner
+ follows="left|top"
+ height="20"
+ label="Water Height"
+ label_width="120"
+ layout="topleft"
+ left="15"
+ max_val="100"
+ name="water_height_spin"
+ top_delta="18"
+ width="180" />
+ <spinner
+ follows="left|top"
+ height="20"
+ increment="0.2"
+ label="Terrain Raise Limit"
+ label_width="120"
+ layout="topleft"
+ left="240"
+ max_val="100"
+ name="terrain_raise_spin"
+ top_delta="0"
+ width="180" />
+ <spinner
+ follows="left|top"
+ height="20"
+ increment="0.2"
+ label="Terrain Lower Limit"
+ label_width="120"
+ layout="topleft"
+ left="240"
+ max_val="0"
+ min_val="-100"
+ name="terrain_lower_spin"
+ top_delta="20"
+ width="180" />
+ <view_border
+ bevel_style="none"
+ follows="top|left"
+ height="60"
+ layout="topleft"
+ left="8"
+ top_delta="-30"
+ width="460" />
+ <text
+ type="string"
+ length="1"
+ follows="left|top"
+ height="20"
+ layout="topleft"
+ left="10"
+ name="height_text_lbl5"
+ top_delta="74"
+ width="300">
+ Texture Elevation Ranges
+ </text>
+ <text
+ visible="false"
+ type="string"
+ length="1"
+ follows="left|top"
+ height="20"
+ layout="topleft"
+ left="10"
+ name="height_text_lbl5_material"
+ top_delta="0"
+ width="300">
+ Material Elevation Ranges
+ </text>
+ <text
+ follows="left|top"
+ height="20"
+ layout="topleft"
+ left="10"
+ name="height_text_lbl10"
+ top_delta="30"
+ width="200"
+ word_wrap="true">
+ These values represent the blend range for the textures above.
+ </text>
+ <text
+ visible="false"
+ follows="left|top"
+ height="20"
+ layout="topleft"
+ left="10"
+ name="height_text_lbl10_material"
+ top_delta="0"
+ width="200"
+ word_wrap="true">
+ These values represent the blend range for the materials above.
+ </text>
+ <text
+ follows="left|top"
+ height="60"
+ layout="topleft"
+ left_delta="0"
+ name="height_text_lbl11"
+ top_delta="32"
+ width="200"
+ word_wrap="true">
+ Measured in meters, the LOW value is the MAXIMUM height of Texture #1, and the HIGH value is the MINIMUM height of Texture #4.
+ </text>
+ <text
+ visible="false"
+ follows="left|top"
+ height="60"
+ layout="topleft"
+ left_delta="0"
+ name="height_text_lbl11_material"
+ top_delta="0"
+ width="200"
+ word_wrap="true">
+ Measured in meters, the LOW value is the MAXIMUM height of Material #1, and the HIGH value is the MINIMUM height of Material #4.
+ </text>
+ <text
+ follows="left|top"
+ height="20"
+ layout="topleft"
+ left="270"
+ name="height_text_lbl6"
+ top_delta="-62"
+ width="100">
+ Northwest
+ </text>
+ <text
+ follows="left|top"
+ height="20"
+ layout="topleft"
+ left_pad="10"
+ name="height_text_lbl7"
+ top_delta="0"
+ width="100">
+ Northeast
+ </text>
+<!-- northwest low-->
+ <spinner
+ follows="left|top"
+ height="20"
+ increment="0.5"
+ label="Low"
+ label_width="37"
+ layout="topleft"
+ left="230"
+ max_val="500"
+ min_val="-500"
+ name="height_start_spin_1"
+ top_delta="15"
+ width="100" />
+<!-- northeast low-->
+ <spinner
+ follows="left|top"
+ height="20"
+ increment="0.5"
+ label="Low"
+ label_width="37"
+ layout="topleft"
+ left_pad="10"
+ max_val="500"
+ min_val="-500"
+ name="height_start_spin_3"
+ top_delta="0"
+ width="100" />
+<!-- northwest high-->
+ <spinner
+ follows="left|top"
+ height="20"
+ increment="0.5"
+ label="High"
+ label_width="37"
+ layout="topleft"
+ left="230"
+ max_val="500"
+ min_val="-500"
+ name="height_range_spin_1"
+ top_delta="20"
+ width="100" />
+<!-- northeast high-->
+ <spinner
+ follows="left|top"
+ height="20"
+ increment="0.5"
+ label="High"
+ label_width="37"
+ layout="topleft"
+ left_pad="10"
+ max_val="500"
+ min_val="-500"
+ name="height_range_spin_3"
+ top_delta="0"
+ width="100" />
+ <text
+ follows="left|top"
+ height="20"
+ layout="topleft"
+ left="270"
+ name="height_text_lbl8"
+ top_pad="10"
+ width="100">
+ Southwest
+ </text>
+ <text
+ follows="left|top"
+ height="20"
+ layout="topleft"
+ left_pad="10"
+ name="height_text_lbl9"
+ top_delta="0"
+ width="100">
+ Southeast
+ </text>
+<!-- southwest low-->
+ <spinner
+ follows="left|top"
+ height="20"
+ increment="0.5"
+ label="Low"
+ label_width="37"
+ layout="topleft"
+ left="230"
+ max_val="500"
+ min_val="-500"
+ name="height_start_spin_0"
+ top_delta="15"
+ width="100" />
+<!-- southeast low-->
+ <spinner
+ follows="left|top"
+ height="20"
+ increment="0.5"
+ label="Low"
+ label_width="37"
+ layout="topleft"
+ left_pad="10"
+ max_val="500"
+ min_val="-500"
+ name="height_start_spin_2"
+ top_delta="0"
+ width="100" />
+<!--southwest high-->
+ <spinner
+ follows="left|top"
+ height="20"
+ increment="0.5"
+ label="High"
+ label_width="37"
+ layout="topleft"
+ left="230"
+ max_val="500"
+ min_val="-500"
+ name="height_range_spin_0"
+ top_delta="20"
+ width="100" />
+<!-- southeast high-->
+ <spinner
+ follows="left|top"
+ height="20"
+ increment="0.5"
+ label="High"
+ label_width="37"
+ layout="topleft"
+ left_pad="10"
+ max_val="500"
+ min_val="-500"
+ name="height_range_spin_2"
+ top_delta="0"
+ width="100" />
+<!-- Terrain Download/Upload/Bake buttons -->
+ <button
+ follows="left|top"
+ height="20"
+ label="Download RAW terrain..."
+ layout="topleft"
+ left="10"
+ name="download_raw_btn"
+ tool_tip="Available only to estate owners, not managers"
+ top_delta="40"
+ width="160" />
+ <button
+ follows="left|top"
+ height="20"
+ label="Upload RAW terrain..."
+ layout="topleft"
+ left_pad="10"
+ top_delta="0"
+ name="upload_raw_btn"
+ tool_tip="Available only to estate owners, not managers"
+ width="160" />
+ <button
+ follows="left|top"
+ height="20"
+ label="Bake Terrain"
+ layout="topleft"
+ left_pad="10"
+ name="bake_terrain_btn"
+ tool_tip="Set current terrain as mid-point for raise/lower limits"
+ width="100" />
+</panel>
diff --git a/indra/newview/skins/default/xui/en/panel_settings_terrain_transform.xml b/indra/newview/skins/default/xui/en/panel_settings_terrain_transform.xml
new file mode 100644
index 0000000000..7052622813
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_settings_terrain_transform.xml
@@ -0,0 +1,365 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel
+ border="true"
+ follows="all"
+ label="Samping"
+ layout="topleft"
+ left="0"
+ name="panel_settings_terrain_transform"
+ top="0">
+ <text
+ type="string"
+ length="1"
+ halign="left"
+ valign="center"
+ follows="left|top"
+ height="20"
+ layout="topleft"
+ name="terrain0ScaleU_label"
+ left="10"
+ top_pad="3"
+ width="170">
+ Scale u
+ </text>
+ <view_border
+ bevel_style="none"
+ follows="top|left"
+ height="0"
+ layout="topleft"
+ left="8"
+ top_pad="-2"
+ name="terrain0ScaleU_horizontal"
+ width="430" />
+ <spinner
+ follows="left|top"
+ height="19"
+ initial_value="1"
+ label="Scale u"
+ label_width="0"
+ layout="topleft"
+ left="10"
+ min_val="-100"
+ max_val="100"
+ name="terrain0ScaleU"
+ width="64" />
+ <spinner
+ follows="left|top"
+ height="19"
+ initial_value="1"
+ label="Scale u"
+ label_width="0"
+ layout="topleft"
+ left_delta="110"
+ min_val="-100"
+ max_val="100"
+ name="terrain1ScaleU"
+ width="64" />
+ <spinner
+ follows="left|top"
+ height="19"
+ initial_value="1"
+ label="Scale u"
+ label_width="0"
+ layout="topleft"
+ left_delta="110"
+ min_val="-100"
+ max_val="100"
+ name="terrain2ScaleU"
+ width="64" />
+ <spinner
+ follows="left|top"
+ height="19"
+ initial_value="1"
+ label="Scale u"
+ label_width="0"
+ layout="topleft"
+ left_delta="110"
+ min_val="-100"
+ max_val="100"
+ name="terrain3ScaleU"
+ width="64" />
+ <text
+ type="string"
+ length="1"
+ halign="left"
+ valign="center"
+ follows="left|top"
+ height="20"
+ layout="topleft"
+ name="terrain0ScaleV_label"
+ left="10"
+ top_pad="3"
+ width="170">
+ Scale v
+ </text>
+ <view_border
+ bevel_style="none"
+ follows="top|left"
+ height="0"
+ layout="topleft"
+ left="8"
+ top_pad="-2"
+ name="terrain0ScaleV_horizontal"
+ width="430" />
+ <spinner
+ follows="left|top"
+ height="19"
+ initial_value="1"
+ label="Scale v"
+ label_width="0"
+ layout="topleft"
+ left="10"
+ min_val="-100"
+ max_val="100"
+ name="terrain0ScaleV"
+ width="64" />
+ <spinner
+ follows="left|top"
+ height="19"
+ initial_value="1"
+ label="Scale u"
+ label_width="0"
+ layout="topleft"
+ left_delta="110"
+ min_val="-100"
+ max_val="100"
+ name="terrain1ScaleV"
+ width="64" />
+ <spinner
+ follows="left|top"
+ height="19"
+ initial_value="1"
+ label="Scale u"
+ label_width="0"
+ layout="topleft"
+ left_delta="110"
+ min_val="-100"
+ max_val="100"
+ name="terrain2ScaleV"
+ width="64" />
+ <spinner
+ follows="left|top"
+ height="19"
+ initial_value="1"
+ label="Scale u"
+ label_width="0"
+ layout="topleft"
+ left_delta="110"
+ min_val="-100"
+ max_val="100"
+ name="terrain3ScaleV"
+ width="64" />
+ <text
+ type="string"
+ length="1"
+ halign="left"
+ valign="center"
+ follows="left|top"
+ height="20"
+ layout="topleft"
+ name="terrain0Rotation_label"
+ left="10"
+ top_pad="3"
+ width="170">
+ Rotation
+ </text>
+ <view_border
+ bevel_style="none"
+ follows="top|left"
+ height="0"
+ layout="topleft"
+ left="8"
+ top_pad="-2"
+ name="terrain0Rotation_horizontal"
+ width="430" />
+ <spinner
+ follows="left|top"
+ height="19"
+ initial_value="0"
+ label="Rotation"
+ label_width="0"
+ layout="topleft"
+ left="10"
+ min_val="-360"
+ max_val="360"
+ name="terrain0Rotation"
+ width="64" />
+ <spinner
+ follows="left|top"
+ height="19"
+ initial_value="0"
+ label="Scale u"
+ label_width="0"
+ layout="topleft"
+ left_delta="110"
+ min_val="-100"
+ max_val="100"
+ name="terrain1Rotation"
+ width="64" />
+ <spinner
+ follows="left|top"
+ height="19"
+ initial_value="0"
+ label="Scale u"
+ label_width="0"
+ layout="topleft"
+ left_delta="110"
+ min_val="-100"
+ max_val="100"
+ name="terrain2Rotation"
+ width="64" />
+ <spinner
+ follows="left|top"
+ height="19"
+ initial_value="0"
+ label="Scale u"
+ label_width="0"
+ layout="topleft"
+ left_delta="110"
+ min_val="-100"
+ max_val="100"
+ name="terrain3Rotation"
+ width="64" />
+ <text
+ type="string"
+ length="1"
+ halign="left"
+ valign="center"
+ follows="left|top"
+ height="20"
+ layout="topleft"
+ name="terrain0OffsetU_label"
+ left="10"
+ top_pad="3"
+ width="170">
+ Offset y
+ </text>
+ <view_border
+ bevel_style="none"
+ follows="top|left"
+ height="0"
+ layout="topleft"
+ left="8"
+ top_pad="-2"
+ name="terrain0OffsetU_horizontal"
+ width="430" />
+ <spinner
+ follows="left|top"
+ height="19"
+ initial_value="0"
+ label="Offset u"
+ label_width="0"
+ layout="topleft"
+ left="10"
+ min_val="-999"
+ max_val="999"
+ name="terrain0OffsetU"
+ width="64" />
+ <spinner
+ follows="left|top"
+ height="19"
+ initial_value="0"
+ label="Scale u"
+ label_width="0"
+ layout="topleft"
+ left_delta="110"
+ min_val="-100"
+ max_val="100"
+ name="terrain1OffsetU"
+ width="64" />
+ <spinner
+ follows="left|top"
+ height="19"
+ initial_value="0"
+ label="Scale u"
+ label_width="0"
+ layout="topleft"
+ left_delta="110"
+ min_val="-100"
+ max_val="100"
+ name="terrain2OffsetU"
+ width="64" />
+ <spinner
+ follows="left|top"
+ height="19"
+ initial_value="0"
+ label="Scale u"
+ label_width="0"
+ layout="topleft"
+ left_delta="110"
+ min_val="-100"
+ max_val="100"
+ name="terrain3OffsetU"
+ width="64" />
+ <text
+ type="string"
+ length="1"
+ halign="left"
+ valign="center"
+ follows="left|top"
+ height="20"
+ layout="topleft"
+ name="terrain0OffsetV_label"
+ left="10"
+ top_pad="3"
+ width="170">
+ Offset v
+ </text>
+ <view_border
+ bevel_style="none"
+ follows="top|left"
+ height="0"
+ layout="topleft"
+ left="8"
+ top_pad="-2"
+ name="terrain0OffsetV_horizontal"
+ width="430" />
+ <spinner
+ follows="left|top"
+ height="19"
+ initial_value="0"
+ label="Offset v"
+ label_width="0"
+ layout="topleft"
+ left="10"
+ min_val="-999"
+ max_val="999"
+ name="terrain0OffsetV"
+ width="64" />
+ <spinner
+ follows="left|top"
+ height="19"
+ initial_value="0"
+ label="Scale u"
+ label_width="0"
+ layout="topleft"
+ left_delta="110"
+ min_val="-100"
+ max_val="100"
+ name="terrain1OffsetV"
+ width="64" />
+ <spinner
+ follows="left|top"
+ height="19"
+ initial_value="0"
+ label="Scale u"
+ label_width="0"
+ layout="topleft"
+ left_delta="110"
+ min_val="-100"
+ max_val="100"
+ name="terrain2OffsetV"
+ width="64" />
+ <spinner
+ follows="left|top"
+ height="19"
+ initial_value="0"
+ label="Scale u"
+ label_width="0"
+ layout="topleft"
+ left_delta="110"
+ min_val="-100"
+ max_val="100"
+ name="terrain3OffsetV"
+ width="64" />
+</panel>