viewer#1131 gltf model upload UI WIP #3

meow-7.2.2
Andrey Kleshchev 2024-07-01 17:10:13 +03:00 committed by Andrey Kleshchev
parent e75595a1c1
commit 279ec534dd
4 changed files with 567 additions and 15 deletions

View File

@ -31,7 +31,9 @@
#include "gltf/asset.h"
#include "llcallbacklist.h"
#include "llmenubutton.h"
#include "llselectmgr.h"
#include "llspinctrl.h"
#include "llviewerobject.h"
const LLColor4U DEFAULT_WHITE(255, 255, 255);
@ -43,16 +45,69 @@ LLFloaterGLTFAssetEditor::LLFloaterGLTFAssetEditor(const LLSD& key)
, mUIColor(LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE))
{
setTitle("GLTF Asset Editor (WIP)");
mCommitCallbackRegistrar.add("PanelObject.menuDoToSelected", [this](LLUICtrl* ctrl, const LLSD& data) { onMenuDoToSelected(data); });
mEnableCallbackRegistrar.add("PanelObject.menuEnable", [this](LLUICtrl* ctrl, const LLSD& data) { return onMenuEnableItem(data); });
}
LLFloaterGLTFAssetEditor::~LLFloaterGLTFAssetEditor()
{
gIdleCallbacks.deleteFunction(idle, this);
if (mScroller)
{
removeChild(mScroller);
delete mScroller;
mScroller = NULL;
}
}
bool LLFloaterGLTFAssetEditor::postBuild()
{
mItemListPanel = getChild<LLPanel>("item_list_panel");
// Position
mMenuClipboardPos = getChild<LLMenuButton>("clipboard_pos_btn");
mCtrlPosX = getChild<LLSpinCtrl>("Pos X", true);
mCtrlPosX->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
mCtrlPosY = getChild<LLSpinCtrl>("Pos Y", true);
mCtrlPosY->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
mCtrlPosZ = getChild<LLSpinCtrl>("Pos Z", true);
mCtrlPosZ->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
// Scale
mMenuClipboardScale = getChild<LLMenuButton>("clipboard_size_btn");
mCtrlScaleX = getChild<LLSpinCtrl>("Scale X", true);
mCtrlScaleX->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
mCtrlScaleY = getChild<LLSpinCtrl>("Scale Y", true);
mCtrlScaleY->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
mCtrlScaleZ = getChild<LLSpinCtrl>("Scale Z", true);
mCtrlScaleZ->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
// Rotation
mMenuClipboardRot = getChild<LLMenuButton>("clipboard_rot_btn");
mCtrlRotX = getChild<LLSpinCtrl>("Rot X", true);
mCtrlRotX->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
mCtrlRotY = getChild<LLSpinCtrl>("Rot Y", true);
mCtrlRotY->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
mCtrlRotZ = getChild<LLSpinCtrl>("Rot Z", true);
mCtrlPosZ->setCommitCallback([this](LLUICtrl* ctrl, const LLSD& param) { onCommitTransform(); });
setTransformsEnabled(false);
// todo: do multiple panels based on selected element.
mTransformsPanel = getChild<LLPanel>("transform_panel", true);
mTransformsPanel->setVisible(false);
mItemListPanel = getChild<LLPanel>("item_list_panel", true);
initFolderRoot();
return true;
}
void LLFloaterGLTFAssetEditor::initFolderRoot()
{
if (mScroller || mFolderRoot)
{
LL_ERRS() << "Folder root already initialized" << LL_ENDL;
return;
}
LLRect scroller_view_rect = mItemListPanel->getRect();
scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom);
@ -87,11 +142,10 @@ bool LLFloaterGLTFAssetEditor::postBuild()
mFolderRoot->setScrollContainer(mScroller);
mFolderRoot->setFollowsAll();
mFolderRoot->setOpen(true);
mFolderRoot->setSelectCallback([this](const std::deque<LLFolderViewItem*>& items, bool user_action) { onFolderSelectionChanged(items, user_action); });
mScroller->setVisible(true);
gIdleCallbacks.addFunction(idle, this);
return true;
}
void LLFloaterGLTFAssetEditor::onOpen(const LLSD& key)
@ -252,3 +306,212 @@ void LLFloaterGLTFAssetEditor::loadFromSelection()
mFolderRoot->update();
}
void LLFloaterGLTFAssetEditor::onFolderSelectionChanged(const std::deque<LLFolderViewItem*>& items, bool user_action)
{
if (items.empty())
{
setTransformsEnabled(false);
return;
}
LLFolderViewItem* item = items.front();
LLGLTFFolderItem* vmi = static_cast<LLGLTFFolderItem*>(item->getViewModelItem());
switch (vmi->getType())
{
case LLGLTFFolderItem::TYPE_NODE:
{
setTransformsEnabled(true);
loadNodeTransforms(vmi->getItemId());
break;
}
default:
{
setTransformsEnabled(false);
break;
}
}
}
void LLFloaterGLTFAssetEditor::setTransformsEnabled(bool val)
{
mMenuClipboardPos->setEnabled(val);
mCtrlPosX->setEnabled(val);
mCtrlPosY->setEnabled(val);
mCtrlPosZ->setEnabled(val);
mMenuClipboardScale->setEnabled(val);
mCtrlScaleX->setEnabled(val);
mCtrlScaleY->setEnabled(val);
mCtrlScaleZ->setEnabled(val);
mMenuClipboardRot->setEnabled(val);
mCtrlRotX->setEnabled(val);
mCtrlRotY->setEnabled(val);
mCtrlRotZ->setEnabled(val);
}
void LLFloaterGLTFAssetEditor::loadNodeTransforms(S32 node_id)
{
if (node_id < 0 || node_id >= mAsset->mNodes.size())
{
LL_ERRS() << "Node id out of range: " << node_id << LL_ENDL;
return;
}
LL::GLTF::Node& node = mAsset->mNodes[node_id];
mCtrlPosX->set(node.mTranslation[0]);
mCtrlPosY->set(node.mTranslation[1]);
mCtrlPosZ->set(node.mTranslation[2]);
mCtrlScaleX->set(node.mScale[0]);
mCtrlScaleY->set(node.mScale[1]);
mCtrlScaleZ->set(node.mScale[2]);
LLQuaternion object_rot = LLQuaternion(node.mRotation[0], node.mRotation[1], node.mRotation[2], node.mRotation[3]);
object_rot.getEulerAngles(&(mLastEulerDegrees.mV[VX]), &(mLastEulerDegrees.mV[VY]), &(mLastEulerDegrees.mV[VZ]));
mLastEulerDegrees *= RAD_TO_DEG;
mLastEulerDegrees.mV[VX] = fmod(ll_round(mLastEulerDegrees.mV[VX], OBJECT_ROTATION_PRECISION) + 360.f, 360.f);
mLastEulerDegrees.mV[VY] = fmod(ll_round(mLastEulerDegrees.mV[VY], OBJECT_ROTATION_PRECISION) + 360.f, 360.f);
mLastEulerDegrees.mV[VZ] = fmod(ll_round(mLastEulerDegrees.mV[VZ], OBJECT_ROTATION_PRECISION) + 360.f, 360.f);
mCtrlRotX->set(mLastEulerDegrees.mV[VX]);
mCtrlRotY->set(mLastEulerDegrees.mV[VY]);
mCtrlRotZ->set(mLastEulerDegrees.mV[VZ]);
}
void LLFloaterGLTFAssetEditor::onCommitTransform()
{
if (!mFolderRoot)
{
LL_ERRS() << "Folder root not initialized" << LL_ENDL;
return;
}
LLFolderViewItem* item = mFolderRoot->getCurSelectedItem();
if (!item)
{
LL_ERRS() << "Nothing selected" << LL_ENDL;
return;
}
LLGLTFFolderItem* vmi = static_cast<LLGLTFFolderItem*>(item->getViewModelItem());
if (!vmi || vmi->getType() != LLGLTFFolderItem::TYPE_NODE)
{
LL_ERRS() << "Only nodes implemented" << LL_ENDL;
return;
}
S32 node_id = vmi->getItemId();
LL::GLTF::Node& node = mAsset->mNodes[node_id];
LL::GLTF::vec3 tr(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get());
node.setTranslation(tr);
LL::GLTF::vec3 scale(mCtrlScaleX->get(), mCtrlScaleY->get(), mCtrlScaleZ->get());
node.setScale(scale);
LLVector3 new_rot(mCtrlRotX->get(), mCtrlRotY->get(), mCtrlRotZ->get());
new_rot.mV[VX] = ll_round(new_rot.mV[VX], OBJECT_ROTATION_PRECISION);
new_rot.mV[VY] = ll_round(new_rot.mV[VY], OBJECT_ROTATION_PRECISION);
new_rot.mV[VZ] = ll_round(new_rot.mV[VZ], OBJECT_ROTATION_PRECISION);
// Note: must compare before conversion to radians, some value can go 'around' 360
LLVector3 delta = new_rot - mLastEulerDegrees;
if (delta.magVec() >= 0.0005f)
{
mLastEulerDegrees = new_rot;
new_rot *= DEG_TO_RAD;
LLQuaternion rotation;
rotation.setQuat(new_rot.mV[VX], new_rot.mV[VY], new_rot.mV[VZ]);
LL::GLTF::quat q;
q[0] = rotation.mQ[VX];
q[1] = rotation.mQ[VY];
q[2] = rotation.mQ[VZ];
q[3] = rotation.mQ[VW];
node.setRotation(q);
}
mAsset->updateTransforms();
}
void LLFloaterGLTFAssetEditor::onMenuDoToSelected(const LLSD& userdata)
{
std::string command = userdata.asString();
if (command == "psr_paste")
{
// todo: implement
// onPastePos();
// onPasteSize();
// onPasteRot();
}
else if (command == "pos_paste")
{
// todo: implement
}
else if (command == "size_paste")
{
// todo: implement
}
else if (command == "rot_paste")
{
// todo: implement
}
else if (command == "psr_copy")
{
// onCopyPos();
// onCopySize();
// onCopyRot();
}
else if (command == "pos_copy")
{
// todo: implement
}
else if (command == "size_copy")
{
// todo: implement
}
else if (command == "rot_copy")
{
// todo: implement
}
}
bool LLFloaterGLTFAssetEditor::onMenuEnableItem(const LLSD& userdata)
{
if (!mFolderRoot)
{
return false;
}
LLFolderViewItem* item = mFolderRoot->getCurSelectedItem();
if (!item)
{
return false;
}
LLGLTFFolderItem* vmi = static_cast<LLGLTFFolderItem*>(item->getViewModelItem());
if (!vmi || vmi->getType() != LLGLTFFolderItem::TYPE_NODE)
{
return false;
}
std::string command = userdata.asString();
if (command == "pos_paste" || command == "size_paste" || command == "rot_paste")
{
// todo: implement
return true;
}
if (command == "psr_copy")
{
// todo: implement
return true;
}
return false;
}

View File

@ -40,6 +40,9 @@ namespace LL
}
}
class LLSpinCtrl;
class LLMenuButton;
class LLFloaterGLTFAssetEditor : public LLFloater
{
public:
@ -48,6 +51,7 @@ public:
bool postBuild() override;
void onOpen(const LLSD& key) override;
void initFolderRoot();
LLGLTFViewModel& getRootViewModel() { return mGLTFViewModel; }
@ -56,14 +60,42 @@ public:
void loadFromNode(S32 node, LLFolderViewFolder* parent);
void loadFromSelection();
private:
LLGLTFViewModel mGLTFViewModel;
LLUIColor mUIColor;
protected:
void onFolderSelectionChanged(const std::deque<LLFolderViewItem*>& items, bool user_action);
void onCommitTransform();
void onMenuDoToSelected(const LLSD& userdata);
bool onMenuEnableItem(const LLSD& userdata);
void setTransformsEnabled(bool val);
void loadNodeTransforms(S32 id);
private:
std::shared_ptr<LL::GLTF::Asset> mAsset;
// Folder view related
LLUIColor mUIColor;
LLGLTFViewModel mGLTFViewModel;
LLPanel* mItemListPanel = nullptr;
LLFolderView* mFolderRoot = nullptr;
LLScrollContainer* mScroller = nullptr;
std::shared_ptr<LL::GLTF::Asset> mAsset;
// Transforms panel
LLVector3 mLastEulerDegrees;
LLPanel* mTransformsPanel = nullptr;
LLMenuButton* mMenuClipboardPos = nullptr;
LLSpinCtrl* mCtrlPosX = nullptr;
LLSpinCtrl* mCtrlPosY = nullptr;
LLSpinCtrl* mCtrlPosZ = nullptr;
LLMenuButton* mMenuClipboardScale = nullptr;
LLSpinCtrl* mCtrlScaleX = nullptr;
LLSpinCtrl* mCtrlScaleY = nullptr;
LLSpinCtrl* mCtrlScaleZ = nullptr;
LLMenuButton* mMenuClipboardRot = nullptr;
LLSpinCtrl* mCtrlRotX = nullptr;
LLSpinCtrl* mCtrlRotY = nullptr;
LLSpinCtrl* mCtrlRotZ = nullptr;
};
#endif LL_LLFLOATERGLTFASSETEDITOR_H

View File

@ -112,7 +112,7 @@ public:
bool filter(LLFolderViewFilter& filter) override;
EType getType() const { return mItemType; }
S32 getId() const { return mItemId; }
S32 getItemId() const { return mItemId; }
private:
LLUIImagePtr pIcon;

View File

@ -3,9 +3,9 @@
legacy_header_height="18"
can_resize="true"
default_tab_group="1"
height="400"
height="530"
width="256"
min_height="200"
min_height="400"
min_width="200"
layout="topleft"
name="gltf asset editor"
@ -14,13 +14,270 @@
<floater.string name="node_tittle" value="Node"/>
<floater.string name="mesh_tittle" value="Mesh"/>
<floater.string name="skin_tittle" value="Skin"/>
<panel
<layout_stack
name="main_layout"
orientation="vertical"
follows="all"
layout="topleft"
name="item_list_panel"
visible="true"
bottom="-1"
top="16"
left="5"
right="-1"/>
right="-1"
border_size="0">
<layout_panel
name="top_lp"
border="true"
bevel_style="in"
auto_resize="false"
user_resize="true"
visible="true"
height="200">
<panel
follows="all"
layout="topleft"
name="item_list_panel"
visible="true"
bottom="-1"
top="16"
left="5"
right="-1"/>
</layout_panel>
<layout_panel
name="transforms_panel"
border="true"
bevel_style="in"
auto_resize="true"
user_resize="true"
visible="true"
height="150">
<menu_button
menu_filename="menu_copy_paste_pos.xml"
follows="top|left"
height="11"
image_disabled="ClipboardSmallMenu_Disabled"
image_selected="ClipboardSmallMenu_Press"
image_unselected="ClipboardSmallMenu_Off"
layout="topleft"
left_delta="0"
top_pad="13"
name="clipboard_pos_btn"
tool_tip="Paste options"
width="19"/>
<text
type="string"
length="1"
follows="left|top"
height="10"
layout="topleft"
name="label position"
tool_tip="Position (meters)"
left_pad="8"
top_delta="0"
width="121">
Position (m)
</text>
<spinner
follows="left|top"
height="19"
increment="0.01"
initial_value="0"
label="X"
label_width="10"
layout="topleft"
left_delta="-27"
max_val="512"
min_val="-256"
name="Pos X"
text_enabled_color="1 0 0.3 .7"
top_pad="8"
width="87" />
<spinner
follows="left|top"
height="19"
increment="0.01"
initial_value="0"
label="Y"
label_width="10"
layout="topleft"
left_delta="0"
max_val="512"
min_val="-256"
name="Pos Y"
text_enabled_color="EmphasisColor"
top_pad="3"
width="87" />
<spinner
follows="left|top"
height="19"
increment="0.01"
initial_value="0"
label="Z"
label_width="10"
layout="topleft"
left_delta="0"
max_val="4096"
min_val="-32"
name="Pos Z"
text_enabled_color="0 0.8 1 .65"
top_pad="3"
width="87" />
<menu_button
menu_filename="menu_copy_paste_size.xml"
follows="top|left"
height="11"
image_disabled="ClipboardSmallMenu_Disabled"
image_selected="ClipboardSmallMenu_Press"
image_unselected="ClipboardSmallMenu_Off"
layout="topleft"
left_delta="0"
top_pad="13"
name="clipboard_size_btn"
tool_tip="Paste options"
width="19"/>
<text
type="string"
length="1"
follows="left|top"
height="10"
layout="topleft"
left_pad="8"
top_delta="0"
name="label size"
tool_tip="Size (meters)"
width="121">
Size (m)
</text>
<spinner
follows="left|top"
height="19"
increment="0.01"
initial_value="0"
label="X"
label_width="10"
layout="topleft"
left_delta="-27"
max_val="64"
min_val="0.01"
name="Scale X"
text_enabled_color="1 1 1 1"
top_pad="8"
width="87" />
<spinner
follows="left|top"
height="19"
increment="0.01"
initial_value="0"
label="Y"
label_width="10"
layout="topleft"
left_delta="0"
max_val="64"
min_val="0.01"
name="Scale Y"
text_enabled_color="1 1 1 1"
top_pad="3"
width="87" />
<spinner
follows="left|top"
height="19"
increment="0.01"
initial_value="0"
label="Z"
label_width="10"
layout="topleft"
left_delta="0"
max_val="64"
min_val="0.01"
name="Scale Z"
text_enabled_color="1 1 1 1"
top_pad="3"
width="87" />
<menu_button
menu_filename="menu_copy_paste_rot.xml"
follows="top|left"
height="11"
image_disabled="ClipboardSmallMenu_Disabled"
image_selected="ClipboardSmallMenu_Press"
image_unselected="ClipboardSmallMenu_Off"
layout="topleft"
left_delta="0"
top_pad="13"
name="clipboard_rot_btn"
tool_tip="Paste options"
width="19"/>
<text
type="string"
length="1"
follows="left|top"
height="10"
layout="topleft"
left_pad="8"
top_delta="0"
name="label rotation"
tool_tip="Rotation (degrees)"
width="121">
Rotation (°)
</text>
<spinner
decimal_digits="2"
follows="left|top"
height="19"
increment="1"
initial_value="0"
label="X"
label_width="10"
layout="topleft"
left_delta="-27"
max_val="9999"
min_val="-9999"
name="Rot X"
text_enabled_color="1 1 1 1"
top_pad="8"
width="87" />
<spinner
decimal_digits="2"
follows="left|top"
height="19"
increment="1"
initial_value="0"
label="Y"
label_width="10"
layout="topleft"
left_delta="0"
max_val="9999"
min_val="-9999"
name="Rot Y"
text_enabled_color="1 1 1 1"
top_pad="3"
width="87" />
<spinner
decimal_digits="2"
follows="left|top"
height="19"
increment="1"
initial_value="0"
label="Z"
label_width="10"
layout="topleft"
left_delta="0"
max_val="9999"
min_val="-9999"
name="Rot Z"
text_enabled_color="1 1 1 1"
top_pad="3"
width="87" />
</layout_panel>
<layout_panel
name="blank_panel"
border="true"
bevel_style="in"
auto_resize="true"
user_resize="true"
visible="false"
height="150">
</layout_panel>
</layout_stack>
</floater>