Merge pull request #1667 from secondlife/v-1475

secondlife/viewer#1475: Add PBR terrain repeats editing
master
cosmic-linden 2024-06-10 11:18:22 -07:00 committed by GitHub
commit 4705362a33
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 1456 additions and 78 deletions

View File

@ -681,7 +681,7 @@ void LLGLTFMaterial::applyOverride(const LLGLTFMaterial& override_mat)
}
}
void LLGLTFMaterial::getOverrideLLSD(const LLGLTFMaterial& override_mat, LLSD& data)
void LLGLTFMaterial::getOverrideLLSD(const LLGLTFMaterial& override_mat, LLSD& data) const
{
LL_PROFILE_ZONE_SCOPED;
llassert(data.isUndefined());
@ -690,7 +690,7 @@ void LLGLTFMaterial::getOverrideLLSD(const LLGLTFMaterial& override_mat, LLSD& d
for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)
{
LLUUID& texture_id = mTextureId[i];
const LLUUID& texture_id = mTextureId[i];
const LLUUID& override_texture_id = override_mat.mTextureId[i];
if (override_texture_id.notNull() && override_texture_id != texture_id)
{

View File

@ -202,7 +202,7 @@ public:
// Get the given override on this LLGLTFMaterial as LLSD
// override_mat -- the override source data
// data -- output LLSD object (should be passed in empty)
void getOverrideLLSD(const LLGLTFMaterial& override_mat, LLSD& data);
void getOverrideLLSD(const LLGLTFMaterial& override_mat, LLSD& data) const;
// For base materials only (i.e. assets). Clears transforms to
// default since they're not supported in assets yet.

View File

@ -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

View File

@ -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>

View File

@ -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;
@ -553,6 +563,20 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg)
} // else will rerequest on onOpen either way
}
// 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()
{
@ -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;
}

View File

@ -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);

View File

@ -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);
});
}
}

View File

@ -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;

View File

@ -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");

View File

@ -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;
}

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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>