diff options
Diffstat (limited to 'indra')
-rw-r--r-- | indra/newview/llgltfmateriallist.cpp | 40 | ||||
-rw-r--r-- | indra/newview/llgltfmateriallist.h | 2 | ||||
-rw-r--r-- | indra/newview/llpanelface.cpp | 227 | ||||
-rw-r--r-- | indra/newview/llpanelface.h | 67 |
4 files changed, 262 insertions, 74 deletions
diff --git a/indra/newview/llgltfmateriallist.cpp b/indra/newview/llgltfmateriallist.cpp index 45de0b71ae..cff2d22f18 100644 --- a/indra/newview/llgltfmateriallist.cpp +++ b/indra/newview/llgltfmateriallist.cpp @@ -147,6 +147,11 @@ public: LLGLTFMaterialOverrideDispatchHandler() = default; ~LLGLTFMaterialOverrideDispatchHandler() override = default; + void addCallback(void(*callback)(const LLUUID& object_id, S32 side)) + { + mCallbacks.push_back(callback); + } + bool operator()(const LLDispatcher* dispatcher, const std::string& key, const LLUUID& invoice, const sparam_t& strings) override { LL_PROFILE_ZONE_SCOPED; @@ -210,7 +215,7 @@ public: return true; } - static void applyData(const LLGLTFOverrideCacheEntry &object_override) + void applyData(const LLGLTFOverrideCacheEntry &object_override) { // Parse the data @@ -225,6 +230,8 @@ public: bool mSuccess; }; + std::vector<void(*)(const LLUUID& object_id, S32 side)> callbacks = mCallbacks; + // fromJson() is performance heavy offload to a thread. main_queue->postTo( general_queue, @@ -264,7 +271,7 @@ public: } return results; }, - [object_override](std::vector<ReturnData> results) // Callback to main thread + [object_override, callbacks](std::vector<ReturnData> results) // Callback to main thread { LLViewerObject * obj = gObjectList.findObject(object_override.mObjectId); @@ -288,6 +295,10 @@ public: else if (obj && obj->isAnySelected()) { LLMaterialEditor::updateLive(object_override.mObjectId, results[i].mSide); + for (auto& override_update_callback : callbacks) + { + override_update_callback(object_override.mObjectId, results[i].mSide); + } } } else @@ -296,6 +307,10 @@ public: if (obj && obj->isAnySelected()) { LLMaterialEditor::updateLive(object_override.mObjectId, results[i].mSide); + for (auto& override_update_callback : callbacks) + { + override_update_callback(object_override.mObjectId, results[i].mSide); + } } } } @@ -311,6 +326,10 @@ public: if (object_has_selection) { LLMaterialEditor::updateLive(object_override.mObjectId, i); + for (auto& override_update_callback : callbacks) + { + override_update_callback(object_override.mObjectId, i); + } } } } @@ -325,11 +344,17 @@ public: if (object_has_selection) { LLMaterialEditor::updateLive(obj->getID(), i); + for (auto& override_update_callback : callbacks) + { + override_update_callback(obj->getID(), i); + } } } } }); } + + std::vector<void(*)(const LLUUID& object_id, S32 side)> mCallbacks; }; namespace @@ -371,6 +396,10 @@ void LLGLTFMaterialList::applyQueuedOverrides(LLViewerObject* obj) if (object_has_selection) { LLMaterialEditor::updateLive(id, i); + for (auto& override_update_callback : handle_gltf_override_message.mCallbacks) + { + override_update_callback(id, i); + } } } } @@ -459,6 +488,11 @@ void LLGLTFMaterialList::flushUpdates(void(*done_callback)(bool)) } } +void LLGLTFMaterialList::addUpdateCallback(void(*update_callback)(const LLUUID& object_id, S32 side)) +{ + handle_gltf_override_message.addCallback(update_callback); +} + class AssetLoadUserData { public: @@ -713,5 +747,5 @@ void LLGLTFMaterialList::modifyMaterialCoro(std::string cap_url, LLSD overrides, void LLGLTFMaterialList::loadCacheOverrides(const LLGLTFOverrideCacheEntry& override) { - LLGLTFMaterialOverrideDispatchHandler::applyData(override); + handle_gltf_override_message.applyData(override); } diff --git a/indra/newview/llgltfmateriallist.h b/indra/newview/llgltfmateriallist.h index 0f0edf7414..5a184f5e94 100644 --- a/indra/newview/llgltfmateriallist.h +++ b/indra/newview/llgltfmateriallist.h @@ -74,6 +74,8 @@ public: // Automatically called once per frame, but may be called explicitly // for cases that care about the done_callback forwarded to LLCoros::instance().launch static void flushUpdates(void(*done_callback)(bool) = nullptr); + + static void addUpdateCallback(void(*update_callback)(const LLUUID& object_id, S32 side)); // Queue an explicit LLSD ModifyMaterialParams update apply given override data // overrides -- LLSD map (or array of maps) in the format: diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 84b1ff63f4..b7e92bf315 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -32,7 +32,6 @@ // library includes #include "llcalc.h" #include "llerror.h" -#include "llfocusmgr.h" #include "llrect.h" #include "llstring.h" #include "llfontgl.h" @@ -95,6 +94,8 @@ using namespace std::literals; +LLPanelFace::Selection LLPanelFace::sMaterialOverrideSelection; + // // Constant definitions for comboboxes // Must match the commbobox definitions in panel_tools_texture.xml @@ -136,7 +137,7 @@ LLGLTFMaterial::TextureInfo texture_info_from_pbrtype(S32 pbr_type) } } -void updateSelectedGLTFMaterials(std::function<void(LLGLTFMaterial*)> func) +void LLPanelFace::updateSelectedGLTFMaterials(std::function<void(LLGLTFMaterial*)> func) { struct LLSelectedTEGLTFMaterialFunctor : public LLSelectedTEFunctor { @@ -158,6 +159,7 @@ void updateSelectedGLTFMaterials(std::function<void(LLGLTFMaterial*)> func) std::function<void(LLGLTFMaterial*)> mFunc; } select_func(func); + LLSelectMgr::getInstance()->getSelection()->applyToTEs(&select_func); } @@ -268,11 +270,14 @@ BOOL LLPanelFace::postBuild() childSetCommitCallback("add_media", &LLPanelFace::onClickBtnAddMedia, this); childSetCommitCallback("delete_media", &LLPanelFace::onClickBtnDeleteMedia, this); - childSetCommitCallback("gltfTextureScaleU", boost::bind(&LLPanelFace::onCommitGLTFTextureScaleU, this, _1), nullptr); - childSetCommitCallback("gltfTextureScaleV", boost::bind(&LLPanelFace::onCommitGLTFTextureScaleV, this, _1), nullptr); - childSetCommitCallback("gltfTextureRotation", boost::bind(&LLPanelFace::onCommitGLTFRotation, this, _1), nullptr); - childSetCommitCallback("gltfTextureOffsetU", boost::bind(&LLPanelFace::onCommitGLTFTextureOffsetU, this, _1), nullptr); - childSetCommitCallback("gltfTextureOffsetV", boost::bind(&LLPanelFace::onCommitGLTFTextureOffsetV, this, _1), nullptr); + getChild<LLUICtrl>("gltfTextureScaleU")->setCommitCallback(boost::bind(&LLPanelFace::onCommitGLTFTextureScaleU, this, _1), nullptr); + getChild<LLUICtrl>("gltfTextureScaleV")->setCommitCallback(boost::bind(&LLPanelFace::onCommitGLTFTextureScaleV, this, _1), nullptr); + getChild<LLUICtrl>("gltfTextureRotation")->setCommitCallback(boost::bind(&LLPanelFace::onCommitGLTFRotation, this, _1), nullptr); + getChild<LLUICtrl>("gltfTextureOffsetU")->setCommitCallback(boost::bind(&LLPanelFace::onCommitGLTFTextureOffsetU, this, _1), nullptr); + getChild<LLUICtrl>("gltfTextureOffsetV")->setCommitCallback(boost::bind(&LLPanelFace::onCommitGLTFTextureOffsetV, this, _1), nullptr); + + LLGLTFMaterialList::addUpdateCallback(&LLPanelFace::onMaterialOverrideReceived); + sMaterialOverrideSelection.connect(); childSetAction("button align",&LLPanelFace::onClickAutoFix,this); childSetAction("button align textures", &LLPanelFace::onAlignTexture, this); @@ -486,6 +491,11 @@ void LLPanelFace::draw() updateMediaTitle(); LLPanel::draw(); + + if (sMaterialOverrideSelection.update()) + { + setMaterialOverridesFromSelection(); + } } void LLPanelFace::sendTexture() @@ -1773,7 +1783,7 @@ void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, { has_pbr_material = false; - BOOL editable = objectp->permModify() && !objectp->isPermanentEnforced(); + const bool editable = objectp->permModify() && !objectp->isPermanentEnforced(); bool has_pbr_capabilities = LLMaterialEditor::capabilitiesAvailable(); // pbr material @@ -1784,10 +1794,11 @@ void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, bool identical_pbr; LLSelectedTE::getPbrMaterialId(pbr_id, identical_pbr); + has_pbr_material = pbr_id.notNull(); + pbr_ctrl->setTentative(identical_pbr ? FALSE : TRUE); pbr_ctrl->setEnabled(editable && has_pbr_capabilities); pbr_ctrl->setImageAssetID(pbr_id); - has_pbr_material = pbr_id.notNull(); } getChildView("pbr_from_inventory")->setEnabled(editable && has_pbr_capabilities); @@ -1797,14 +1808,13 @@ void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, const bool show_pbr = mComboMatMedia->getCurrentIndex() == MATMEDIA_PBR && mComboMatMedia->getEnabled(); if (show_pbr) { - const U32 pbr_type = findChild<LLRadioGroup>("radio_pbr_type")->getSelectedIndex(); const LLGLTFMaterial::TextureInfo texture_info = texture_info_from_pbrtype(pbr_type); const bool show_texture_info = texture_info != LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; LLUICtrl* gltfCtrlTextureScaleU = getChild<LLUICtrl>("gltfTextureScaleU"); - LLUICtrl* gltfCtrlTextureScaleV = getChild<LLUICtrl>("gltfTextureScaleV"); - LLUICtrl* gltfCtrlTextureRotation = getChild<LLUICtrl>("gltfTextureRotation"); + LLUICtrl* gltfCtrlTextureScaleV = getChild<LLUICtrl>("gltfTextureScaleV"); + LLUICtrl* gltfCtrlTextureRotation = getChild<LLUICtrl>("gltfTextureRotation"); LLUICtrl* gltfCtrlTextureOffsetU = getChild<LLUICtrl>("gltfTextureOffsetU"); LLUICtrl* gltfCtrlTextureOffsetV = getChild<LLUICtrl>("gltfTextureOffsetV"); @@ -1814,48 +1824,7 @@ void LLPanelFace::updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, gltfCtrlTextureOffsetU->setEnabled(show_texture_info && has_pbr_capabilities); gltfCtrlTextureOffsetV->setEnabled(show_texture_info && has_pbr_capabilities); - if (show_texture_info) - { - LLGLTFMaterial::TextureTransform transform; - bool scale_u_same = true; - bool scale_v_same = true; - bool rotation_same = true; - bool offset_u_same = true; - bool offset_v_same = true; - - readSelectedGLTFMaterial<float>([&](const LLGLTFMaterial* mat) - { - return mat ? mat->mTextureTransform[texture_info].mScale[VX] : 0.f; - }, transform.mScale[VX], scale_u_same, true, 1e-3f); - readSelectedGLTFMaterial<float>([&](const LLGLTFMaterial* mat) - { - return mat ? mat->mTextureTransform[texture_info].mScale[VY] : 0.f; - }, transform.mScale[VY], scale_v_same, true, 1e-3f); - readSelectedGLTFMaterial<float>([&](const LLGLTFMaterial* mat) - { - return mat ? mat->mTextureTransform[texture_info].mRotation : 0.f; - }, transform.mRotation, rotation_same, true, 1e-3f); - readSelectedGLTFMaterial<float>([&](const LLGLTFMaterial* mat) - { - return mat ? mat->mTextureTransform[texture_info].mOffset[VX] : 0.f; - }, transform.mOffset[VX], offset_u_same, true, 1e-3f); - readSelectedGLTFMaterial<float>([&](const LLGLTFMaterial* mat) - { - return mat ? mat->mTextureTransform[texture_info].mOffset[VY] : 0.f; - }, transform.mOffset[VY], offset_v_same, true, 1e-3f); - - gltfCtrlTextureScaleU->setValue(transform.mScale[VX]); - gltfCtrlTextureScaleV->setValue(transform.mScale[VY]); - gltfCtrlTextureRotation->setValue(transform.mRotation * RAD_TO_DEG); - gltfCtrlTextureOffsetU->setValue(transform.mOffset[VX]); - gltfCtrlTextureOffsetV->setValue(transform.mOffset[VY]); - - gltfCtrlTextureScaleU->setTentative(!scale_u_same); - gltfCtrlTextureScaleV->setTentative(!scale_v_same); - gltfCtrlTextureRotation->setTentative(!rotation_same); - gltfCtrlTextureOffsetU->setTentative(!offset_u_same); - gltfCtrlTextureOffsetV->setTentative(!offset_v_same); - } + // Control values are set in setMaterialOverridesFromSelection } } @@ -2084,6 +2053,12 @@ void LLPanelFace::unloadMedia() mTitleMedia->unloadMediaSource(); } +// static +void LLPanelFace::onMaterialOverrideReceived(const LLUUID& object_id, S32 side) +{ + sMaterialOverrideSelection.onObjectUpdated(object_id, side); +} + ////////////////////////////////////////////////////////////////////////////// // void LLPanelFace::navigateToTitleMedia( const std::string url ) @@ -4677,7 +4652,7 @@ void LLPanelFace::onCommitPlanarAlign(LLUICtrl* ctrl, void* userdata) self->sendTextureInfo(); } -void updateGLTFTextureTransform(float value, U32 pbr_type, std::function<void(LLGLTFMaterial::TextureTransform*)> edit) +void LLPanelFace::updateGLTFTextureTransform(float value, U32 pbr_type, std::function<void(LLGLTFMaterial::TextureTransform*)> edit) { U32 texture_info_start; U32 texture_info_end; @@ -4699,6 +4674,148 @@ void updateGLTFTextureTransform(float value, U32 pbr_type, std::function<void(LL edit(&new_transform); } }); + + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + if (node) + { + LLViewerObject* object = node->getObject(); + sMaterialOverrideSelection.setObjectUpdatePending(object->getID(), node->getLastSelectedTE()); + } +} + +void LLPanelFace::setMaterialOverridesFromSelection() +{ + const U32 pbr_type = findChild<LLRadioGroup>("radio_pbr_type")->getSelectedIndex(); + const LLGLTFMaterial::TextureInfo texture_info = texture_info_from_pbrtype(pbr_type); + if (texture_info == LLGLTFMaterial::TextureInfo::GLTF_TEXTURE_INFO_COUNT) + { + return; + } + + LLGLTFMaterial::TextureTransform transform; + bool scale_u_same = true; + bool scale_v_same = true; + bool rotation_same = true; + bool offset_u_same = true; + bool offset_v_same = true; + + readSelectedGLTFMaterial<float>([&](const LLGLTFMaterial* mat) + { + return mat ? mat->mTextureTransform[texture_info].mScale[VX] : 0.f; + }, transform.mScale[VX], scale_u_same, true, 1e-3f); + readSelectedGLTFMaterial<float>([&](const LLGLTFMaterial* mat) + { + return mat ? mat->mTextureTransform[texture_info].mScale[VY] : 0.f; + }, transform.mScale[VY], scale_v_same, true, 1e-3f); + readSelectedGLTFMaterial<float>([&](const LLGLTFMaterial* mat) + { + return mat ? mat->mTextureTransform[texture_info].mRotation : 0.f; + }, transform.mRotation, rotation_same, true, 1e-3f); + readSelectedGLTFMaterial<float>([&](const LLGLTFMaterial* mat) + { + return mat ? mat->mTextureTransform[texture_info].mOffset[VX] : 0.f; + }, transform.mOffset[VX], offset_u_same, true, 1e-3f); + readSelectedGLTFMaterial<float>([&](const LLGLTFMaterial* mat) + { + return mat ? mat->mTextureTransform[texture_info].mOffset[VY] : 0.f; + }, transform.mOffset[VY], offset_v_same, true, 1e-3f); + + LLUICtrl* gltfCtrlTextureScaleU = getChild<LLUICtrl>("gltfTextureScaleU"); + LLUICtrl* gltfCtrlTextureScaleV = getChild<LLUICtrl>("gltfTextureScaleV"); + LLUICtrl* gltfCtrlTextureRotation = getChild<LLUICtrl>("gltfTextureRotation"); + LLUICtrl* gltfCtrlTextureOffsetU = getChild<LLUICtrl>("gltfTextureOffsetU"); + LLUICtrl* gltfCtrlTextureOffsetV = getChild<LLUICtrl>("gltfTextureOffsetV"); + + gltfCtrlTextureScaleU->setValue(transform.mScale[VX]); + gltfCtrlTextureScaleV->setValue(transform.mScale[VY]); + gltfCtrlTextureRotation->setValue(transform.mRotation * RAD_TO_DEG); + gltfCtrlTextureOffsetU->setValue(transform.mOffset[VX]); + gltfCtrlTextureOffsetV->setValue(transform.mOffset[VY]); + + gltfCtrlTextureScaleU->setTentative(!scale_u_same); + gltfCtrlTextureScaleV->setTentative(!scale_v_same); + gltfCtrlTextureRotation->setTentative(!rotation_same); + gltfCtrlTextureOffsetU->setTentative(!offset_u_same); + gltfCtrlTextureOffsetV->setTentative(!offset_v_same); +} + +void LLPanelFace::Selection::connect() +{ + if (!mSelectConnection.connected()) + { + mSelectConnection = LLSelectMgr::instance().mUpdateSignal.connect(boost::bind(&LLPanelFace::Selection::onSelectionChanged, this)); + } +} + +bool LLPanelFace::Selection::update() +{ + const bool selection_changed = compareSelection(); + if (selection_changed) + { + clearObjectUpdatePending(); + } + else if (isObjectUpdatePending()) + { + return false; + } + + const bool changed = mChanged; + mChanged = false; + return changed; +} + +void LLPanelFace::Selection::setObjectUpdatePending(const LLUUID &object_id, S32 side) +{ + mPendingObjectID = object_id; + mPendingSide = side; +} + +void LLPanelFace::Selection::onObjectUpdated(const LLUUID& object_id, S32 side) +{ + if (object_id == mSelectedObjectID && side == mSelectedSide) + { + mChanged = true; + clearObjectUpdatePending(); + } +} + +void LLPanelFace::Selection::clearObjectUpdatePending() +{ + mPendingObjectID = LLUUID::null; + mPendingSide = -1; +} + +bool LLPanelFace::Selection::compareSelection() +{ + if (!mNeedsSelectionCheck) + { + return false; + } + mNeedsSelectionCheck = false; + + const S32 old_object_count = mSelectedObjectCount; + const LLUUID old_object_id = mSelectedObjectID; + const S32 old_side = mSelectedSide; + + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + LLSelectNode* node = selection->getFirstNode(); + if (node) + { + LLViewerObject* object = node->getObject(); + mSelectedObjectCount = selection->getObjectCount(); + mSelectedObjectID = object->getID(); + mSelectedSide = node->getLastSelectedTE(); + } + else + { + mSelectedObjectCount = 0; + mSelectedObjectID = LLUUID::null; + mSelectedSide = -1; + } + + const bool selection_changed = old_object_count != mSelectedObjectCount || old_object_id != mSelectedObjectID || old_side != mSelectedSide; + mChanged = mChanged || selection_changed; + return selection_changed; } void LLPanelFace::onCommitGLTFTextureScaleU(LLUICtrl* ctrl) diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index 69744689b5..520b399d42 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -49,6 +49,8 @@ class LLFloater; class LLMaterialID; class LLMediaCtrl; class LLMenuButton; +class LLGLTFMaterial; +struct LLGLTFMaterial::TextureTransform; // Represents an edit for use in replicating the op across one or more materials in the selection set. // @@ -102,7 +104,7 @@ public: void refreshMedia(); void unloadMedia(); - static void onGLTFMaterialUpdate(const LLUUID& object_id, S32 side); + static void onMaterialOverrideReceived(const LLUUID& object_id, S32 side); /*virtual*/ void draw(); @@ -176,7 +178,6 @@ protected: // // @param force_set_values forces spinners to set value even if they are focused void updateUI(bool force_set_values = false); - void updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, bool force_set_values); // Convenience func to determine if all faces in selection have // identical planar texgen settings during edits @@ -229,11 +230,13 @@ protected: static void onCommitGlow( LLUICtrl* ctrl, void *userdata); static void onCommitPlanarAlign( LLUICtrl* ctrl, void* userdata); static void onCommitRepeatsPerMeter( LLUICtrl* ctrl, void* userinfo); + void onCommitGLTFTextureScaleU(LLUICtrl* ctrl); void onCommitGLTFTextureScaleV(LLUICtrl* ctrl); void onCommitGLTFRotation(LLUICtrl* ctrl); void onCommitGLTFTextureOffsetU(LLUICtrl* ctrl); void onCommitGLTFTextureOffsetV(LLUICtrl* ctrl); + static void onClickAutoFix(void*); static void onAlignTexture(void*); static void onClickBtnLoadInvPBR(void* userdata); @@ -291,7 +294,6 @@ private: // Do NOT call updateUI from within this function. // void updateVisibility(); - void updateVisibilityGLTF(); // Hey look everyone, a type-safe alternative to copy and paste! :) // @@ -451,29 +453,62 @@ private: void onTextureSelectionChanged(LLInventoryItem* itemp); void onPbrSelectionChanged(LLInventoryItem* itemp); + void updateUIGLTF(LLViewerObject* objectp, bool& has_pbr_material, bool force_set_values); + void updateVisibilityGLTF(); + + void updateSelectedGLTFMaterials(std::function<void(LLGLTFMaterial*)> func); + void updateGLTFTextureTransform(float value, U32 pbr_type, std::function<void(LLGLTFMaterial::TextureTransform*)> edit); + + void setMaterialOverridesFromSelection(); + LLMenuButton* mMenuClipboardColor; LLMenuButton* mMenuClipboardTexture; bool mIsAlpha; - /* These variables interlock processing of materials updates sent to - * the sim. mUpdateInFlight is set to flag that an update has been - * sent to the sim and not acknowledged yet, and cleared when an - * update is received from the sim. mUpdatePending is set when - * there's an update in flight and another UI change has been made - * that needs to be sent as a materials update, and cleared when the - * update is sent. This prevents the sim from getting spammed with - * update messages when, for example, the user holds down the - * up-arrow on a spinner, and avoids running afoul of its throttle. - */ - bool mUpdateInFlight; - bool mUpdatePending; - LLSD mClipboardParams; LLSD mMediaSettings; bool mNeedMediaTitle; + class Selection + { + public: + void connect(); + + // Returns true if the selected objects or sides have changed since + // this was last called, and no object update is pending + bool update(); + + // Prevents update() returning true until the provided object is + // updated. Necessary to prevent controls updating when the mouse is + // held down. + void setObjectUpdatePending(const LLUUID &object_id, S32 side); + + // Callbacks + void onSelectionChanged() { mNeedsSelectionCheck = true; } + void onObjectUpdated(const LLUUID &object_id, S32 side); + + protected: + void clearObjectUpdatePending(); + bool isObjectUpdatePending() { return mPendingSide != -1; } + + bool compareSelection(); + + bool mChanged = false; + + boost::signals2::scoped_connection mSelectConnection; + bool mNeedsSelectionCheck = true; + S32 mSelectedObjectCount = 0; + LLUUID mSelectedObjectID; + S32 mSelectedSide = -1; + + LLUUID mPendingObjectID; + S32 mPendingSide = -1; + }; + + static Selection sMaterialOverrideSelection; + public: #if defined(DEF_GET_MAT_STATE) #undef DEF_GET_MAT_STATE |