summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Kleshchev <andreykproductengine@lindenlab.com>2024-06-27 18:03:30 +0300
committerAndrey Kleshchev <117672381+akleshchev@users.noreply.github.com>2024-07-01 20:05:31 +0300
commite75595a1c193abb95075b27ab5641a3b28556c2e (patch)
treecf1e2c68c89a73b73e402ba75c24c8ee46e53310
parentc7bd4528a7bc295a17a12951389fcc499483f6c5 (diff)
viewer#1131 gltf model upload UI WIP #2
-rw-r--r--indra/newview/CMakeLists.txt6
-rw-r--r--indra/newview/llfloatergltfasseteditor.cpp251
-rw-r--r--indra/newview/llfloatergltfasseteditor.h89
-rw-r--r--indra/newview/llgltffolderitem.cpp (renamed from indra/newview/llgltffolderviews.cpp)51
-rw-r--r--indra/newview/llgltffolderitem.h (renamed from indra/newview/llgltffolderviews.h)36
-rw-r--r--indra/newview/llgltffoldermodel.cpp73
-rw-r--r--indra/newview/llgltffoldermodel.h91
-rw-r--r--indra/newview/llviewerfloaterreg.cpp2
-rw-r--r--indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml15
9 files changed, 461 insertions, 153 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 67bcab86ff..cbcc85cc1c 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -314,7 +314,8 @@ set(viewer_SOURCE_FILES
llgesturemgr.cpp
llgiveinventory.cpp
llglsandbox.cpp
- llgltffolderviews.cpp
+ llgltffolderitem.cpp
+ llgltffoldermodel.cpp
llgltfmateriallist.cpp
llgltfmaterialpreviewmgr.cpp
llgroupactions.cpp
@@ -978,7 +979,8 @@ set(viewer_HEADER_FILES
llgesturelistener.h
llgesturemgr.h
llgiveinventory.h
- llgltffolderviews.h
+ llgltffolderitem.h
+ llgltffoldermodel.h
llgltfmateriallist.h
llgltfmaterialpreviewmgr.h
llgroupactions.h
diff --git a/indra/newview/llfloatergltfasseteditor.cpp b/indra/newview/llfloatergltfasseteditor.cpp
index a2b5f573bb..62546c6ed9 100644
--- a/indra/newview/llfloatergltfasseteditor.cpp
+++ b/indra/newview/llfloatergltfasseteditor.cpp
@@ -1,7 +1,7 @@
/**
* @file llfloatergltfasseteditor.cpp
- * @author Brad Payne
- * @brief LLFloaterFontTest class implementation
+ * @author Andrii Kleshchev
+ * @brief LLFloaterGltfAssetEditor class implementation
*
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
@@ -29,72 +29,48 @@
#include "llfloatergltfasseteditor.h"
-#include "llfolderviewitem.h"
-#include "llgltffolderviews.h"
+#include "gltf/asset.h"
+#include "llcallbacklist.h"
+#include "llselectmgr.h"
+#include "llviewerobject.h"
-bool LLGLTFSort::operator()(const LLGLTFItem* const& a, const LLGLTFItem* const& b) const
-{
- // Comparison operator: returns "true" is a comes before b, "false" otherwise
- S32 compare = LLStringUtil::compareDict(a->getName(), b->getName());
- return (compare < 0);
-}
-
-/// LLGLTFViewModel
-
-LLGLTFViewModel::LLGLTFViewModel()
- : base_t(new LLGLTFSort(), new LLGLTFFilter())
-{}
-
-void LLGLTFViewModel::sort(LLFolderViewFolder* folder)
-{
- base_t::sort(folder);
-}
+const LLColor4U DEFAULT_WHITE(255, 255, 255);
- /// LLGLTFNode
-// LLUICtrlFactory::create<LLGLTFNode>(params);
-class LLGLTFNode : public LLFolderViewItem
-{
-public:
- struct Params : public LLInitParam::Block<Params, LLFolderViewItem::Params>
- {
- Params();
- };
- ~LLGLTFNode();
-protected:
- LLGLTFNode(const Params& p);
-};
-
-LLGLTFNode::LLGLTFNode(const LLGLTFNode::Params& p)
- : LLFolderViewItem(p)
-{
-}
-
-LLGLTFNode::~LLGLTFNode()
-{
-}
+/// LLFloaterGLTFAssetEditor
-LLFloaterGltfAssetEditor::LLFloaterGltfAssetEditor(const LLSD& key)
+LLFloaterGLTFAssetEditor::LLFloaterGLTFAssetEditor(const LLSD& key)
: LLFloater(key)
+ , mUIColor(LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE))
{
setTitle("GLTF Asset Editor (WIP)");
}
-/// LLFloaterGltfAssetEditor
-
-LLFloaterGltfAssetEditor::~LLFloaterGltfAssetEditor()
+LLFloaterGLTFAssetEditor::~LLFloaterGLTFAssetEditor()
{
+ gIdleCallbacks.deleteFunction(idle, this);
}
-bool LLFloaterGltfAssetEditor::postBuild()
+bool LLFloaterGLTFAssetEditor::postBuild()
{
mItemListPanel = getChild<LLPanel>("item_list_panel");
+ LLRect scroller_view_rect = mItemListPanel->getRect();
+ scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom);
+ LLScrollContainer::Params scroller_params(LLUICtrlFactory::getDefaultParams<LLFolderViewScrollContainer>());
+ scroller_params.rect(scroller_view_rect);
+ scroller_params.name("folder_scroller");
+ mScroller = LLUICtrlFactory::create<LLFolderViewScrollContainer>(scroller_params);
+ mScroller->setFollowsAll();
+
+ // Insert that scroller into the panel widgets hierarchy
+ mItemListPanel->addChild(mScroller);
+
// Create the root model and view for all conversation sessions
- LLGLTFItem* base_item = new LLGLTFItem(mGLTFViewModel);
+ LLGLTFFolderItem* base_item = new LLGLTFFolderItem(mGLTFViewModel);
LLFolderView::Params p(LLUICtrlFactory::getDefaultParams<LLFolderView>());
- p.name = getName();
- p.title = getLabel();
+ p.name = "Root";
+ p.title = "Root";
p.rect = LLRect(0, 0, getRect().getWidth(), 0);
p.parent_panel = mItemListPanel;
p.tool_tip = p.name;
@@ -103,9 +79,176 @@ bool LLFloaterGltfAssetEditor::postBuild()
p.root = NULL;
p.use_ellipses = true;
p.options_menu = "menu_gltf.xml"; // *TODO : create this or fix to be optional
- mConversationsRoot = LLUICtrlFactory::create<LLFolderView>(p);
- mConversationsRoot->setCallbackRegistrar(&mCommitCallbackRegistrar);
- mConversationsRoot->setEnableRegistrar(&mEnableCallbackRegistrar);
+ mFolderRoot = LLUICtrlFactory::create<LLFolderView>(p);
+ mFolderRoot->setCallbackRegistrar(&mCommitCallbackRegistrar);
+ mFolderRoot->setEnableRegistrar(&mEnableCallbackRegistrar);
+ // Attach root to the scroller
+ mScroller->addChild(mFolderRoot);
+ mFolderRoot->setScrollContainer(mScroller);
+ mFolderRoot->setFollowsAll();
+ mFolderRoot->setOpen(true);
+ mScroller->setVisible(true);
+
+ gIdleCallbacks.addFunction(idle, this);
return true;
}
+
+void LLFloaterGLTFAssetEditor::onOpen(const LLSD& key)
+{
+ loadFromSelection();
+}
+
+void LLFloaterGLTFAssetEditor::idle(void* user_data)
+{
+ LLFloaterGLTFAssetEditor* floater = (LLFloaterGLTFAssetEditor*)user_data;
+
+ if (floater->mFolderRoot)
+ {
+ floater->mFolderRoot->update();
+ }
+}
+
+void LLFloaterGLTFAssetEditor::loadItem(S32 id, const std::string& name, LLGLTFFolderItem::EType type, LLFolderViewFolder* parent)
+{
+ LLGLTFFolderItem* listener = new LLGLTFFolderItem(id, name, type, mGLTFViewModel);
+
+ LLFolderViewItem::Params params;
+ params.name(name);
+ params.creation_date(0);
+ params.root(mFolderRoot);
+ params.listener(listener);
+ params.rect(LLRect());
+ params.tool_tip = params.name;
+ params.font_color = mUIColor;
+ params.font_highlight_color = mUIColor;
+ LLFolderViewItem* view = LLUICtrlFactory::create<LLFolderViewItem>(params);
+
+ view->addToFolder(parent);
+ view->setVisible(true);
+}
+
+void LLFloaterGLTFAssetEditor::loadFromNode(S32 node_id, LLFolderViewFolder* parent)
+{
+ if (mAsset->mNodes.size() <= node_id)
+ {
+ return;
+ }
+
+ LL::GLTF::Node& node = mAsset->mNodes[node_id];
+
+ std::string name = node.mName;
+ if (node.mName.empty())
+ {
+ name = getString("node_tittle");
+ }
+ else
+ {
+ name = node.mName;
+ }
+
+ LLGLTFFolderItem* listener = new LLGLTFFolderItem(node_id, name, LLGLTFFolderItem::TYPE_NODE, mGLTFViewModel);
+
+ LLFolderViewFolder::Params p;
+ p.root = mFolderRoot;
+ p.listener = listener;
+ p.name = name;
+ p.tool_tip = name;
+ p.font_color = mUIColor;
+ p.font_highlight_color = mUIColor;
+ LLFolderViewFolder* view = LLUICtrlFactory::create<LLFolderViewFolder>(p);
+
+ view->addToFolder(parent);
+ view->setVisible(true);
+ view->setOpen(true);
+
+ for (S32& node_id : node.mChildren)
+ {
+ loadFromNode(node_id, view);
+ }
+
+ if (node.mMesh != LL::GLTF::INVALID_INDEX && mAsset->mMeshes.size() > node.mMesh)
+ {
+ std::string name = mAsset->mMeshes[node.mMesh].mName;
+ if (name.empty())
+ {
+ name = getString("mesh_tittle");
+ }
+ loadItem(node.mMesh, name, LLGLTFFolderItem::TYPE_MESH, view);
+ }
+
+ if (node.mSkin != LL::GLTF::INVALID_INDEX && mAsset->mSkins.size() > node.mSkin)
+ {
+ std::string name = mAsset->mSkins[node.mSkin].mName;
+ if (name.empty())
+ {
+ name = getString("skin_tittle");
+ }
+ loadItem(node.mSkin, name, LLGLTFFolderItem::TYPE_SKIN, view);
+ }
+
+ view->setChildrenInited(true);
+}
+
+void LLFloaterGLTFAssetEditor::loadFromSelection()
+{
+ if (!mFolderRoot || LLSelectMgr::getInstance()->getSelection()->getObjectCount() != 1)
+ {
+ return;
+ }
+
+ LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
+ if (!objectp)
+ {
+ return;
+ }
+
+ mAsset = objectp->mGLTFAsset;
+ if (!mAsset)
+ {
+ return;
+ }
+
+ LLUIColor item_color = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
+ for (S32 i = 0; i < mAsset->mScenes.size(); i++)
+ {
+ LL::GLTF::Scene& scene = mAsset->mScenes[i];
+ std::string name = scene.mName;
+ if (scene.mName.empty())
+ {
+ name = getString("scene_tittle");
+ }
+ else
+ {
+ name = scene.mName;
+ }
+
+ LLGLTFFolderItem* listener = new LLGLTFFolderItem(i, name, LLGLTFFolderItem::TYPE_SCENE, mGLTFViewModel);
+
+
+ LLFolderViewFolder::Params p;
+ p.name = name;
+ p.root = mFolderRoot;
+ p.listener = listener;
+ p.tool_tip = name;
+ p.font_color = mUIColor;
+ p.font_highlight_color = mUIColor;
+ LLFolderViewFolder* view = LLUICtrlFactory::create<LLFolderViewFolder>(p);
+
+ view->addToFolder(mFolderRoot);
+ view->setVisible(true);
+ view->setOpen(true);
+
+ for (S32& node_id : scene.mNodes)
+ {
+ loadFromNode(node_id, view);
+ }
+ view->setChildrenInited(true);
+ }
+
+ mGLTFViewModel.requestSortAll();
+ mFolderRoot->setChildrenInited(true);
+ mFolderRoot->arrangeAll();
+ mFolderRoot->update();
+}
+
diff --git a/indra/newview/llfloatergltfasseteditor.h b/indra/newview/llfloatergltfasseteditor.h
index 30000506ae..49c5aa4ae7 100644
--- a/indra/newview/llfloatergltfasseteditor.h
+++ b/indra/newview/llfloatergltfasseteditor.h
@@ -1,7 +1,7 @@
/**
* @file llfloatergltfasseteditor.h
- * @author Brad Payne
- * @brief floater to exercise standard fonts
+ * @author Andrii Kleshchev
+ * @brief LLFloaterGltfAssetEditor header file
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
@@ -30,85 +30,40 @@
#include "llfloater.h"
-#include "llfolderviewmodel.h"
-#include "llgltffolderviews.h"
+#include "llgltffoldermodel.h"
-class LLGLTFViewModel;
-class LLFolderViewFolder;
-class LLFolderViewModelItem;
-
-class LLGLTFSort
-{
-public:
- LLGLTFSort() { }
- bool operator()(const LLGLTFItem* const& a, const LLGLTFItem* const& b) const;
-private:
-};
-
-class LLGLTFFilter : public LLFolderViewFilter
-{
-public:
- LLGLTFFilter() { mEmpty = ""; }
- ~LLGLTFFilter() {}
-
- bool check(const LLFolderViewModelItem* item) { return true; }
- bool checkFolder(const LLFolderViewModelItem* folder) const { return true; }
- void setEmptyLookupMessage(const std::string& message) { }
- std::string getEmptyLookupMessage(bool is_empty_folder = false) const { return mEmpty; }
- bool showAllResults() const { return true; }
- std::string::size_type getStringMatchOffset(LLFolderViewModelItem* item) const { return std::string::npos; }
- std::string::size_type getFilterStringSize() const { return 0; }
-
- bool isActive() const { return false; }
- bool isModified() const { return false; }
- void clearModified() { }
- const std::string& getName() const { return mEmpty; }
- const std::string& getFilterText() { return mEmpty; }
- void setModified(EFilterModified behavior = FILTER_RESTART) { }
-
- void resetTime(S32 timeout) { }
- bool isTimedOut() { return false; }
-
- bool isDefault() const { return true; }
- bool isNotDefault() const { return false; }
- void markDefault() { }
- void resetDefault() { }
-
- S32 getCurrentGeneration() const { return 0; }
- S32 getFirstSuccessGeneration() const { return 0; }
- S32 getFirstRequiredGeneration() const { return 0; }
-private:
- std::string mEmpty;
-};
-
-class LLGLTFViewModel
- : public LLFolderViewModel<LLGLTFSort, LLGLTFItem, LLGLTFItem, LLGLTFFilter>
+namespace LL
{
-public:
- typedef LLFolderViewModel< LLGLTFSort, LLGLTFItem, LLGLTFItem, LLGLTFFilter> base_t;
- LLGLTFViewModel();
+ namespace GLTF
+ {
+ class Asset;
+ }
+}
- void sort(LLFolderViewFolder* folder);
- bool startDrag(std::vector<LLFolderViewModelItem*>& items) { return false; }
-
-private:
-};
-
-class LLFloaterGltfAssetEditor : public LLFloater
+class LLFloaterGLTFAssetEditor : public LLFloater
{
public:
- LLFloaterGltfAssetEditor(const LLSD& key);
- ~LLFloaterGltfAssetEditor();
+ LLFloaterGLTFAssetEditor(const LLSD& key);
+ ~LLFloaterGLTFAssetEditor();
bool postBuild() override;
+ void onOpen(const LLSD& key) override;
LLGLTFViewModel& getRootViewModel() { return mGLTFViewModel; }
+ static void idle(void* user_data);
+ void loadItem(S32 id, const std::string& name, LLGLTFFolderItem::EType type, LLFolderViewFolder* parent);
+ void loadFromNode(S32 node, LLFolderViewFolder* parent);
+ void loadFromSelection();
+
private:
LLGLTFViewModel mGLTFViewModel;
+ LLUIColor mUIColor;
LLPanel* mItemListPanel = nullptr;
- LLFolderView* mConversationsRoot = nullptr;
+ LLFolderView* mFolderRoot = nullptr;
+ LLScrollContainer* mScroller = nullptr;
+ std::shared_ptr<LL::GLTF::Asset> mAsset;
};
#endif LL_LLFLOATERGLTFASSETEDITOR_H
diff --git a/indra/newview/llgltffolderviews.cpp b/indra/newview/llgltffolderitem.cpp
index 911b6262ca..c4fcb4f5ce 100644
--- a/indra/newview/llgltffolderviews.cpp
+++ b/indra/newview/llgltffolderitem.cpp
@@ -1,7 +1,7 @@
/**
- * @file llgltffolderviews.cpp
+ * @file llgltffolderitem.cpp
* @author Andrey Kleshchev
- * @brief LLFloaterFontTest class implementation
+ * @brief LLGLTFFolderItem class implementation
*
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
* Second Life Viewer Source Code
@@ -27,36 +27,58 @@
#include "llviewerprecompiledheaders.h"
-#include "llgltffolderviews.h"
+#include "llgltffolderitem.h"
+
#include "llinventoryicon.h"
/// LLGLTFItem
-LLGLTFItem::LLGLTFItem(std::string display_name, LLFolderViewModelInterface& root_view_model)
+LLGLTFFolderItem::LLGLTFFolderItem(S32 id, const std::string &display_name, EType type, LLFolderViewModelInterface& root_view_model)
: LLFolderViewModelItemCommon(root_view_model)
, mName(display_name)
+ , mItemType(type)
+ , mItemId(id)
{
init();
}
-LLGLTFItem::LLGLTFItem(LLFolderViewModelInterface& root_view_model)
+LLGLTFFolderItem::LLGLTFFolderItem(LLFolderViewModelInterface& root_view_model)
: LLFolderViewModelItemCommon(root_view_model)
{
init();
}
-LLGLTFItem::~LLGLTFItem()
+LLGLTFFolderItem::~LLGLTFFolderItem()
{
}
-void LLGLTFItem::init()
+void LLGLTFFolderItem::init()
{
- pIcon = LLInventoryIcon::getIcon(LLInventoryType::ICONNAME_OBJECT);
+ // using inventory icons as a placeholder.
+ // Todo: GLTF needs to have own icons
+ switch (mItemType)
+ {
+ case TYPE_SCENE:
+ pIcon = LLInventoryIcon::getIcon(LLInventoryType::ICONNAME_OBJECT_MULTI);
+ break;
+ case TYPE_NODE:
+ pIcon = LLInventoryIcon::getIcon(LLInventoryType::ICONNAME_OBJECT);
+ break;
+ case TYPE_MESH:
+ pIcon = LLInventoryIcon::getIcon(LLInventoryType::ICONNAME_MESH);
+ break;
+ case TYPE_SKIN:
+ pIcon = LLInventoryIcon::getIcon(LLInventoryType::ICONNAME_BODYPART_SKIN);
+ break;
+ default:
+ pIcon = LLInventoryIcon::getIcon(LLInventoryType::ICONNAME_OBJECT);
+ break;
+ }
}
-bool LLGLTFItem::filterChildItem(LLFolderViewModelItem* item, LLFolderViewFilter& filter)
+bool LLGLTFFolderItem::filterChildItem(LLFolderViewModelItem* item, LLFolderViewFilter& filter)
{
S32 filter_generation = filter.getCurrentGeneration();
@@ -72,21 +94,20 @@ bool LLGLTFItem::filterChildItem(LLFolderViewModelItem* item, LLFolderViewFilter
// Update latest generation to pass filter in parent and propagate up to root
if (item->passedFilter())
{
- LLGLTFItem* view_model = this;
+ LLGLTFFolderItem* view_model = this;
while (view_model && view_model->mMostFilteredDescendantGeneration < filter_generation)
{
view_model->mMostFilteredDescendantGeneration = filter_generation;
- view_model = static_cast<LLGLTFItem*>(view_model->mParent);
+ view_model = static_cast<LLGLTFFolderItem*>(view_model->mParent);
}
}
}
return continue_filtering;
}
-bool LLGLTFItem::filter(LLFolderViewFilter& filter)
+bool LLGLTFFolderItem::filter(LLFolderViewFilter& filter)
{
-
const S32 filter_generation = filter.getCurrentGeneration();
const S32 must_pass_generation = filter.getFirstRequiredGeneration();
@@ -129,11 +150,11 @@ bool LLGLTFItem::filter(LLFolderViewFilter& filter)
const bool passed_filter = filter.check(this);
if (passed_filter && mChildren.empty() && is_folder) // Update the latest filter generation for empty folders
{
- LLGLTFItem* view_model = this;
+ LLGLTFFolderItem* view_model = this;
while (view_model && view_model->mMostFilteredDescendantGeneration < filter_generation)
{
view_model->mMostFilteredDescendantGeneration = filter_generation;
- view_model = static_cast<LLGLTFItem*>(view_model->mParent);
+ view_model = static_cast<LLGLTFFolderItem*>(view_model->mParent);
}
}
setPassedFilter(passed_filter, filter_generation, filter.getStringMatchOffset(this), filter.getFilterStringSize());
diff --git a/indra/newview/llgltffolderviews.h b/indra/newview/llgltffolderitem.h
index 294074fd9f..be6e264368 100644
--- a/indra/newview/llgltffolderviews.h
+++ b/indra/newview/llgltffolderitem.h
@@ -1,7 +1,7 @@
/**
- * @file llgltffolderviews.h
+ * @file llgltffolderitem.h
* @author Andrey Kleshchev
- * @brief floater to exercise standard fonts
+ * @brief LLGLTFFolderItem header file
*
* $LicenseInfo:firstyear=2024&license=viewerlgpl$
* Second Life Viewer Source Code
@@ -25,19 +25,28 @@
* $/LicenseInfo$
*/
-#ifndef LL_LLFLOATERGLTFFOLDERVIEWS_H
-#define LL_LLFLOATERGLTFFOLDERVIEWS_H
+#ifndef LL_LLGLTFFOLDERITEM_H
+#define LL_LLGLTFFOLDERITEM_H
#include "llfloater.h"
#include "llfolderviewmodel.h"
-class LLGLTFItem : public LLFolderViewModelItemCommon
+class LLGLTFFolderItem : public LLFolderViewModelItemCommon
{
public:
- LLGLTFItem(std::string display_name, LLFolderViewModelInterface& root_view_model);
- LLGLTFItem(LLFolderViewModelInterface& root_view_model);
- virtual ~LLGLTFItem();
+ enum EType
+ {
+ TYPE_ROOT,
+ TYPE_SCENE,
+ TYPE_NODE,
+ TYPE_MESH,
+ TYPE_SKIN,
+ };
+
+ LLGLTFFolderItem(S32 id, const std::string &display_name, EType type, LLFolderViewModelInterface& root_view_model);
+ LLGLTFFolderItem(LLFolderViewModelInterface& root_view_model);
+ virtual ~LLGLTFFolderItem();
void init();
@@ -102,9 +111,18 @@ public:
bool filterChildItem(LLFolderViewModelItem* item, LLFolderViewFilter& filter);
bool filter(LLFolderViewFilter& filter) override;
+ EType getType() const { return mItemType; }
+ S32 getId() const { return mItemId; }
+
private:
LLUIImagePtr pIcon;
std::string mName;
+ EType mItemType = TYPE_ROOT;
+
+ // mItemId can be an id in a mesh vector, node vector or any other vector.
+ // mItemId is not nessesarily unique, ex: some nodes can reuse the same
+ // mesh or skin, so mesh-items can have the same id.
+ S32 mItemId = -1;
};
-#endif LL_LLFLOATERGLTFFOLDERVIEWS_H
+#endif LL_LLGLTFFOLDERITEM_H
diff --git a/indra/newview/llgltffoldermodel.cpp b/indra/newview/llgltffoldermodel.cpp
new file mode 100644
index 0000000000..5f22c8b710
--- /dev/null
+++ b/indra/newview/llgltffoldermodel.cpp
@@ -0,0 +1,73 @@
+/**
+ * @file llgltffoldermodel.cpp
+ * @author Andrey Kleshchev
+ * @brief gltf model's folder structure related classes
+ *
+ * $LicenseInfo:firstyear=2008&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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llgltffoldermodel.h"
+
+#include "llfolderviewitem.h"
+
+bool LLGLTFSort::operator()(const LLGLTFFolderItem* const& a, const LLGLTFFolderItem* const& b) const
+{
+ // Comparison operator: returns "true" is a comes before b, "false" otherwise
+ S32 compare = LLStringUtil::compareDict(a->getName(), b->getName());
+ return (compare < 0);
+}
+
+/// LLGLTFViewModel
+
+LLGLTFViewModel::LLGLTFViewModel()
+ : base_t(new LLGLTFSort(), new LLGLTFFilter())
+{}
+
+void LLGLTFViewModel::sort(LLFolderViewFolder* folder)
+{
+ base_t::sort(folder);
+}
+
+ /// LLGLTFNode
+// LLUICtrlFactory::create<LLGLTFNode>(params);
+class LLGLTFNode : public LLFolderViewItem
+{
+public:
+ struct Params : public LLInitParam::Block<Params, LLFolderViewItem::Params>
+ {
+ Params();
+ };
+ ~LLGLTFNode();
+protected:
+ LLGLTFNode(const Params& p);
+};
+
+LLGLTFNode::LLGLTFNode(const LLGLTFNode::Params& p)
+ : LLFolderViewItem(p)
+{
+}
+
+LLGLTFNode::~LLGLTFNode()
+{
+}
diff --git a/indra/newview/llgltffoldermodel.h b/indra/newview/llgltffoldermodel.h
new file mode 100644
index 0000000000..26f05d1ecd
--- /dev/null
+++ b/indra/newview/llgltffoldermodel.h
@@ -0,0 +1,91 @@
+/**
+ * @file llfloatergltfasseteditor.h
+ * @author Andrey Kleshchev
+ * @brief gltf model's folder structure related classes
+ *
+ * $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$
+ */
+
+#ifndef LL_LLGLTFFOLDERMODEL_H
+#define LL_LLGLTFFOLDERMODEL_H
+
+#include "llfolderviewmodel.h"
+#include "llgltffolderitem.h"
+
+class LLGLTFSort
+{
+public:
+ LLGLTFSort() { }
+ bool operator()(const LLGLTFFolderItem* const& a, const LLGLTFFolderItem* const& b) const;
+private:
+};
+
+class LLGLTFFilter : public LLFolderViewFilter
+{
+public:
+ LLGLTFFilter() { mEmpty = ""; }
+ ~LLGLTFFilter() {}
+
+ bool check(const LLFolderViewModelItem* item) { return true; }
+ bool checkFolder(const LLFolderViewModelItem* folder) const { return true; }
+ void setEmptyLookupMessage(const std::string& message) { }
+ std::string getEmptyLookupMessage(bool is_empty_folder = false) const { return mEmpty; }
+ bool showAllResults() const { return true; }
+ std::string::size_type getStringMatchOffset(LLFolderViewModelItem* item) const { return std::string::npos; }
+ std::string::size_type getFilterStringSize() const { return 0; }
+
+ bool isActive() const { return false; }
+ bool isModified() const { return false; }
+ void clearModified() { }
+ const std::string& getName() const { return mEmpty; }
+ const std::string& getFilterText() { return mEmpty; }
+ void setModified(EFilterModified behavior = FILTER_RESTART) { }
+
+ void resetTime(S32 timeout) { }
+ bool isTimedOut() { return false; }
+
+ bool isDefault() const { return true; }
+ bool isNotDefault() const { return false; }
+ void markDefault() { }
+ void resetDefault() { }
+
+ S32 getCurrentGeneration() const { return 0; }
+ S32 getFirstSuccessGeneration() const { return 0; }
+ S32 getFirstRequiredGeneration() const { return 0; }
+private:
+ std::string mEmpty;
+};
+
+class LLGLTFViewModel
+ : public LLFolderViewModel<LLGLTFSort, LLGLTFFolderItem, LLGLTFFolderItem, LLGLTFFilter>
+{
+public:
+ typedef LLFolderViewModel< LLGLTFSort, LLGLTFFolderItem, LLGLTFFolderItem, LLGLTFFilter> base_t;
+ LLGLTFViewModel();
+
+ void sort(LLFolderViewFolder* folder);
+ bool startDrag(std::vector<LLFolderViewModelItem*>& items) { return false; }
+
+private:
+};
+
+#endif LL_LLGLTFFOLDERMODEL_H
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 36fd1015f6..3e1705b8a1 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -373,7 +373,7 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("forget_username", "floater_forget_user.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterForgetUser>);
LLFloaterReg::add("gestures", "floater_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGesture>);
- LLFloaterReg::add("gltf_asset_editor", "floater_gltf_asset_editor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGltfAssetEditor>);
+ LLFloaterReg::add("gltf_asset_editor", "floater_gltf_asset_editor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGLTFAssetEditor>);
LLFloaterReg::add("god_tools", "floater_god_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGodTools>);
LLFloaterReg::add("grid_status", "floater_grid_status.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGridStatus>);
LLFloaterReg::add("group_picker", "floater_choose_group.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterGroupPicker>);
diff --git a/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml b/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml
index 9082486d84..4dc0dffcfd 100644
--- a/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml
+++ b/indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml
@@ -3,19 +3,24 @@
legacy_header_height="18"
can_resize="true"
default_tab_group="1"
- height="891"
+ height="400"
width="256"
- min_height="500"
- min_width="256"
+ min_height="200"
+ min_width="200"
layout="topleft"
name="gltf asset editor"
title="[OBJECT_NAME]">
+ <floater.string name="scene_tittle" value="Scene"/>
+ <floater.string name="node_tittle" value="Node"/>
+ <floater.string name="mesh_tittle" value="Mesh"/>
+ <floater.string name="skin_tittle" value="Skin"/>
<panel
- bottom="-1"
follows="all"
layout="topleft"
name="item_list_panel"
- top_pad="0"
+ visible="true"
+ bottom="-1"
+ top="16"
left="5"
right="-1"/>
</floater>