diff options
| -rw-r--r-- | indra/newview/llfloatergltfasseteditor.cpp | 269 | ||||
| -rw-r--r-- | indra/newview/llfloatergltfasseteditor.h | 38 | ||||
| -rw-r--r-- | indra/newview/llgltffolderitem.h | 2 | ||||
| -rw-r--r-- | indra/newview/skins/default/xui/en/floater_gltf_asset_editor.xml | 271 | 
4 files changed, 566 insertions, 14 deletions
| diff --git a/indra/newview/llfloatergltfasseteditor.cpp b/indra/newview/llfloatergltfasseteditor.cpp index 62546c6ed9..ec9ccc1324 100644 --- a/indra/newview/llfloatergltfasseteditor.cpp +++ b/indra/newview/llfloatergltfasseteditor.cpp @@ -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; +} + diff --git a/indra/newview/llfloatergltfasseteditor.h b/indra/newview/llfloatergltfasseteditor.h index 49c5aa4ae7..8164928824 100644 --- a/indra/newview/llfloatergltfasseteditor.h +++ b/indra/newview/llfloatergltfasseteditor.h @@ -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(); +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: -    LLGLTFViewModel mGLTFViewModel; -    LLUIColor mUIColor; +    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 diff --git a/indra/newview/llgltffolderitem.h b/indra/newview/llgltffolderitem.h index be6e264368..83c6449f96 100644 --- a/indra/newview/llgltffolderitem.h +++ b/indra/newview/llgltffolderitem.h @@ -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; 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 4dc0dffcfd..82e0e325fb 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,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> | 
