!XT (BREAK-16) (Sandbox) Remove double-newlines at the end of files.
[CRYENGINE.git] / Code / Sandbox / Plugins / MeshImporter / SceneModel.cpp
blobb24c15e6d09b86baf3c54c4fe0a7f9cdfb680dc5
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
2 #include "StdAfx.h"
3 #include "SceneModel.h"
4 #include "Scene/SceneElementSourceNode.h"
5 #include "Scene/SceneElementPhysProxies.h"
6 #include "Scene/SceneElementProxyGeom.h"
7 #include "Scene/SceneElementSkin.h"
8 #include "Scene/SceneElementTypes.h"
9 #include "Scene/Scene.h"
10 #include "SceneUserData.h"
11 #include "DialogMesh/DialogMesh_SceneUserData.h"
12 #include "FbxMetaData.h"
13 #include <QVariant>
14 #include <QPixmap>
16 #include <CryIcon.h>
18 #include <EditorStyleHelper.h>
20 namespace
23 const FbxTool::ENodeExportSetting kDefaultSceneExportSetting = FbxTool::eNodeExportSetting_Include;
25 CItemModelAttributeEnumFunc s_meshTypeAttribute("Mesh Type", []()
27 QStringList strs;
28 strs.reserve(MAX_STATOBJ_LODS_NUM + 1);
29 for (int i = 0; i < MAX_STATOBJ_LODS_NUM; ++i)
31 strs.push_back(QString("LOD %1").arg(i));
33 strs.push_back(QStringLiteral("Physics Proxy"));
34 return strs;
35 });
37 } // namespace
39 CSceneModel::CSceneModel()
40 : CSceneModelCommon()
41 , m_pExportIcon(new CryIcon())
42 , m_pSceneUserData(nullptr)
44 QPixmap enabledIcon = QStringLiteral("icons:General/Tick_On.ico");
45 QPixmap disabledIcon = QStringLiteral("icons:General/Tick_Off.ico");
46 assert(enabledIcon.width() == enabledIcon.height());
47 assert(disabledIcon.width() == disabledIcon.height());
48 assert(enabledIcon.width() == disabledIcon.width());
49 m_pExportIcon->addPixmap(enabledIcon, CryIcon::Normal, CryIcon::On);
50 m_pExportIcon->addPixmap(disabledIcon, CryIcon::Normal, CryIcon::Off);
51 m_iconDimension = enabledIcon.height();
54 CSceneModel::~CSceneModel()
56 delete m_pExportIcon;
59 static bool IsNotExcluded(CSceneElementSourceNode* pSceneElement)
61 const FbxTool::SNode* pNode = pSceneElement->GetNode();
62 const FbxTool::ENodeExportSetting exportSetting = pNode->pScene->GetNodeExportSetting(pNode);
63 return exportSetting != FbxTool::eNodeExportSetting_Exclude;
66 const FbxMetaData::SSceneUserSettings& CSceneModel::GetSceneUserSettings() const
68 return m_userSettings;
71 static bool GetLodIndex(const char* const szName, const char* szPrefix, int& lod)
73 const size_t lodNamePrefixLength = strlen(szPrefix);
75 if (strnicmp(szName, szPrefix, lodNamePrefixLength))
77 return false;
80 const int value = atoi(szName + lodNamePrefixLength);
81 if (value >= 1 && value < MAX_STATOBJ_LODS_NUM)
83 lod = value;
84 return true;
87 return false;
90 static bool IsSceneRoot(CSceneElementSourceNode* pSceneElement)
92 return pSceneElement->GetNode() && !pSceneElement->GetNode()->pParent;
95 static void AutoAssignLods(CScene& scene, FbxTool::CScene* pFbxScene)
97 for (int i = 0; i < scene.GetElementCount(); ++i)
99 if (scene.GetElementByIndex(i)->GetType() != ESceneElementType::SourceNode)
101 continue;
104 CSceneElementSourceNode* const pElement = (CSceneElementSourceNode*)scene.GetElementByIndex(i);
106 if (!pElement->IsLeaf())
108 continue;
111 int lod = -1;
113 // Try to match 3ds Max convention:
114 // $lod{N}[name] is N-th LOD of parent.
115 if (GetLodIndex(pElement->GetName().c_str(), "$lod", lod))
117 pFbxScene->SetNodeLod(pElement->GetNode(), lod);
120 // Try to match Maya convention:
121 // single child of node with name _lod{N}_name_group is N-th LOD of parent.
122 if (pElement->GetParent() && GetLodIndex(pElement->GetParent()->GetName().c_str(), "_lod", lod))
124 pFbxScene->SetNodeLod(pElement->GetNode(), lod);
129 void CSceneModel::SetScene(FbxTool::CScene* pScene, const FbxMetaData::SSceneUserSettings& userSettings)
131 CSceneModelCommon::SetScene(pScene);
133 m_userSettings = userSettings;
135 for (int i = 0; i < GetElementCount(); ++i)
137 if (GetElementById(i)->GetType() != ESceneElementType::SourceNode)
139 continue;
142 CSceneElementSourceNode* const pElement = (CSceneElementSourceNode*)GetElementById(i);
143 const FbxTool::SNode* const pNode = pElement->GetNode();
145 pScene->SetNodeExportSetting(pNode, GetDefaultNodeExportSetting(pNode));
148 AutoAssignLods(*GetModelScene(), GetScene());
151 void CSceneModel::SetSceneUserData(DialogMesh::CSceneUserData* pSceneUserData)
153 m_pSceneUserData = pSceneUserData;
156 void CSceneModel::SetExportSetting(const QModelIndex& index, FbxTool::ENodeExportSetting value)
158 setData(index, (int)value, eRoleType_Export);
161 static void ResetExportSettingsInSubtree(FbxTool::CScene* pScene, const FbxTool::SNode* pFbxNode)
163 pScene->SetNodeExportSetting(pFbxNode, FbxTool::eNodeExportSetting_Include);
165 for (int i = 0; i < pFbxNode->numChildren; ++i)
167 ResetExportSettingsInSubtree(pScene, pFbxNode->ppChildren[i]);
171 void CSceneModel::ResetExportSettingsInSubtree(const QModelIndex& index)
173 CSceneElementCommon* const pSelf = GetSceneElementFromModelIndex(index);
174 if (!pSelf || pSelf->GetType() != ESceneElementType::SourceNode)
176 return;
179 CSceneElementSourceNode* const pSourceNodeElement = (CSceneElementSourceNode*)pSelf;
180 CRY_ASSERT(IsSceneRoot(pSourceNodeElement));
182 // Reset settings of this LOD's FBX root element.
183 ::ResetExportSettingsInSubtree(GetScene(), pSourceNodeElement->GetNode());
185 Reset();
188 void CSceneModel::OnDataSerialized(CSceneElementCommon* pElement, bool bChanged)
190 if (bChanged)
192 QModelIndex index = GetModelIndexFromSceneElement(pElement);
193 assert(index.isValid());
194 const QModelIndex firstChanged = sibling(index.row(), 0, index);
195 const QModelIndex lastChanged = sibling(index.row(), columnCount(index) - 1, index);
196 dataChanged(firstChanged, lastChanged);
200 int CSceneModel::columnCount(const QModelIndex& index) const
202 return eColumnType_COUNT;
205 static FbxTool::ENodeExportSetting EvaluateExportSetting(const FbxTool::CScene* pFbxScene, const FbxTool::SNode* pFbxNode)
207 return pFbxScene->IsNodeIncluded(pFbxNode) ? FbxTool::eNodeExportSetting_Include : FbxTool::eNodeExportSetting_Exclude;
210 void CSceneModel::GetCheckStateRole(CSceneElementSourceNode* pSelf, EState& state, bool& bPartial) const
212 const CSceneElementSourceNode* pParent = nullptr;
213 if (pSelf->GetParent() && pSelf->GetParent()->GetType() == ESceneElementType::SourceNode)
215 pParent = (CSceneElementSourceNode*)pSelf->GetParent();
218 if (EvaluateExportSetting(GetScene(), pSelf->GetNode()) == FbxTool::eNodeExportSetting_Include)
220 state = eState_Enabled_Included;
222 else if (pParent && EvaluateExportSetting(GetScene(), pParent->GetNode()) == FbxTool::eNodeExportSetting_Include)
224 state = eState_Enabled_Excluded;
226 else if (GetScene()->GetNodeExportSetting(pSelf->GetNode()) == FbxTool::eNodeExportSetting_Include)
228 state = eState_Disabled_Included;
230 else
232 state = eState_Disabled_Excluded;
235 bPartial = false;
237 // TODO: Compute this for all elements in a single pass.
238 std::vector<const CSceneElementCommon*> elementStack;
239 elementStack.push_back(pSelf);
240 while (!elementStack.empty() && !bPartial)
242 const CSceneElementCommon* pElement = elementStack.back();
243 elementStack.pop_back();
245 if (pElement->GetType() == ESceneElementType::SourceNode)
247 const FbxTool::SNode* const pNode = ((CSceneElementSourceNode*)pElement)->GetNode();
248 if (GetScene()->GetNodeExportSetting(pNode) == FbxTool::eNodeExportSetting_Exclude)
250 bPartial = true;
254 for (int i = 0; i < pElement->GetNumChildren(); ++i)
256 elementStack.push_back(pElement->GetChild(i));
262 bool CanBeLod(const FbxTool::SNode* pNode)
264 return
265 pNode->pParent &&
266 !pNode->numChildren &&
267 EvaluateExportSetting(pNode->pScene, pNode) == FbxTool::eNodeExportSetting_Include &&
268 pNode->numMeshes;
271 template<typename T>
272 QVariant CreateSerializationVariant(const T& t)
274 std::unique_ptr<Serialization::SStruct> sstruct(new Serialization::SStruct(t));
275 return QVariant::fromValue((void*)sstruct.release());
278 QVariant CSceneModel::GetSourceNodeData(CSceneElementSourceNode* pSelf, const QModelIndex& index, int role) const
280 if (role == eItemDataRole_YasliSStruct)
282 return CreateSerializationVariant(*pSelf);
285 const FbxTool::SNode* const pNode = pSelf->GetNode();
287 EState state;
288 bool bPartial;
289 GetCheckStateRole(pSelf, state, bPartial);
291 switch (index.column())
293 case eColumnType_Name:
294 if (role == Qt::DisplayRole)
296 return QtUtil::ToQString(pSelf->GetName());
298 else if (role == Qt::CheckStateRole)
300 if (m_pSceneUserData->GetSelectedSkin())
302 return QVariant();
305 if (state == eState_Enabled_Included || state == eState_Disabled_Included)
307 return bPartial ? Qt::PartiallyChecked : Qt::Checked;
309 else if (state == eState_Enabled_Excluded || state == eState_Disabled_Excluded)
311 return Qt::Unchecked;
314 else if (role == Qt::ForegroundRole)
316 if (state == eState_Disabled_Included || state == eState_Disabled_Excluded)
318 return QBrush(GetStyleHelper()->disabledTextColor());
320 else
322 return QBrush(GetStyleHelper()->textColor());
325 break;
326 case eColumnType_Type:
327 if (role == Qt::EditRole && CanBeLod(pNode))
329 return GetScene()->IsProxy(pNode) ? MAX_STATOBJ_LODS_NUM : GetScene()->GetNodeLod(pNode);
331 else if (role == Qt::DisplayRole && CanBeLod(pNode))
333 return QString("LOD %1").arg(GetScene()->IsProxy(pNode) ? MAX_STATOBJ_LODS_NUM : GetScene()->GetNodeLod(pNode));
335 else if (role == Qt::DisplayRole && !IsSceneRoot(pSelf) && !CanBeLod(pNode))
337 return "LOD 0"; // Just display lod, non-editable.
339 break;
340 case eColumnType_SourceNodeAttribute:
341 if (role == Qt::DisplayRole && !pNode->namedAttributes.empty())
343 return QtUtil::ToQString(pNode->namedAttributes[0]);
345 break;
346 default:
347 assert(false);
348 break;
350 if (role == Qt::ToolTipRole)
352 return GetToolTipForColumn(index.column());
355 return CSceneModelCommon::data(index, role);
358 bool IsSkinElementSelected(DialogMesh::CSceneUserData* pSceneUserData, CSceneElementSkin* pSkinElement)
360 CSceneElementSourceNode* const pSourceNodeElement = (CSceneElementSourceNode*)pSkinElement->GetParent();
361 return pSceneUserData->GetSelectedSkin() && pSourceNodeElement->GetNode() == pSceneUserData->GetSelectedSkin()->pNode;
364 QVariant CSceneModel::GetSkinData(CSceneElementSkin* pSelf, const QModelIndex& index, int role) const
366 switch (index.column())
368 case eColumnType_Name:
369 if (role == Qt::DisplayRole)
371 return QtUtil::ToQString(pSelf->GetName());
373 else if (role == Qt::CheckStateRole)
375 if (IsSkinElementSelected(m_pSceneUserData, pSelf))
377 return Qt::Checked;
379 else
381 return Qt::Unchecked;
384 break;
385 case eColumnType_Type:
386 if (role == Qt::DisplayRole)
388 return "Skin";
390 break;
391 default:
392 break;
394 if (role == Qt::ToolTipRole)
396 return GetToolTipForColumn(index.column());
399 return CSceneModelCommon::data(index, role);
402 QVariant CSceneModel::data(const QModelIndex& index, int role) const
404 if (!index.isValid())
406 return QVariant();
409 CSceneElementCommon* const pSelf = GetSceneElementFromModelIndex(index);
410 assert(pSelf);
412 if (pSelf->GetType() == ESceneElementType::SourceNode)
414 return GetSourceNodeData((CSceneElementSourceNode*)pSelf, index, role);
416 else if(pSelf->GetType() == ESceneElementType::Skin)
418 return GetSkinData((CSceneElementSkin*)pSelf, index, role);
420 else if (pSelf->GetType() == ESceneElementType::ProxyGeom || pSelf->GetType() == ESceneElementType::PhysProxy)
422 if (role == eItemDataRole_YasliSStruct)
424 if (pSelf->GetType() == ESceneElementType::PhysProxy)
426 return CreateSerializationVariant(*(CSceneElementPhysProxies*)pSelf);
428 else
430 return CreateSerializationVariant(*(CSceneElementProxyGeom*)pSelf);
433 else if (index.column() == eColumnType_Name && role == Qt::DisplayRole)
435 return QtUtil::ToQString(pSelf->GetName());
438 return CSceneModelCommon::data(index, role);
441 bool CSceneModel::SetDataSourceNodeElement(const QModelIndex& index, const QVariant& value, int role)
443 CSceneElementSourceNode* const pSourceNodeElement = (CSceneElementSourceNode*)GetSceneElementFromModelIndex(index);
445 const FbxTool::SNode* const pNode = pSourceNodeElement->GetNode();
447 if (role == Qt::CheckStateRole)
449 const auto checkState = (Qt::CheckState)value.toUInt();
451 if (GetScene()->GetNodeExportSetting(pNode) == FbxTool::eNodeExportSetting_Include && checkState == Qt::Checked)
453 GetScene()->SetNodeExportSetting(pNode, FbxTool::eNodeExportSetting_Exclude);
455 else
457 const auto exportSetting =
458 checkState == Qt::Checked
459 ? FbxTool::eNodeExportSetting_Include
460 : FbxTool::eNodeExportSetting_Exclude;
461 GetScene()->SetNodeExportSetting(pNode, exportSetting);
464 Reset();
466 return true;
468 if (role == eRoleType_Export)
470 GetScene()->SetNodeExportSetting(pNode, static_cast<FbxTool::ENodeExportSetting>(value.value<int>()));
472 Reset();
474 return true;
476 else if (index.column() == eColumnType_Type && role == Qt::EditRole)
478 const int i = value.toInt();
479 if (i < MAX_STATOBJ_LODS_NUM)
481 GetScene()->SetNodeLod(pNode, i);
482 GetScene()->SetProxy(pNode, false);
484 else
486 GetScene()->SetNodeLod(pNode, 0);
487 GetScene()->SetProxy(pNode, true);
490 const QModelIndex firstChanged = sibling(index.row(), 0, index);
491 const QModelIndex lastChanged = sibling(index.row(), eColumnType_COUNT - 1, index);
492 dataChanged(firstChanged, lastChanged);
493 return true;
496 return false;
499 bool CSceneModel::SetDataSkinElement(const QModelIndex& index, const QVariant& value, int role)
501 CSceneElementSkin* const pSkinElement = (CSceneElementSkin*)GetSceneElementFromModelIndex(index);
503 CRY_ASSERT(pSkinElement->GetParent() && pSkinElement->GetParent()->GetType() == ESceneElementType::SourceNode);
504 CSceneElementSourceNode* const pSourceNodeElement = (CSceneElementSourceNode*)pSkinElement->GetParent();
506 const FbxTool::SNode* const pNode = pSourceNodeElement->GetNode();
508 if (role == Qt::CheckStateRole)
510 const auto checkState = (Qt::CheckState)value.toUInt();
512 if (checkState == Qt::Checked)
514 m_pSceneUserData->SelectAnySkin(pNode);
516 else
518 m_pSceneUserData->DeselectSkin();
521 Reset();
523 return true;
526 return false;
529 bool CSceneModel::setData(const QModelIndex& index, const QVariant& value, int role)
531 if (!index.isValid())
533 return false;
536 CSceneElementCommon* const pElement = GetSceneElementFromModelIndex(index);
537 CRY_ASSERT(pElement);
539 if (pElement->GetType() == ESceneElementType::SourceNode)
541 return SetDataSourceNodeElement(index, value, role);
543 else if (pElement->GetType() == ESceneElementType::Skin)
545 return SetDataSkinElement(index, value, role);
548 return false;
551 CItemModelAttribute* CSceneModel::GetColumnAttribute(int col) const
553 switch(col)
555 case eColumnType_Name:
556 return &Attributes::s_nameAttribute;
557 case eColumnType_Type:
558 return &s_meshTypeAttribute;
559 case eColumnType_SourceNodeAttribute:
560 return GetSourceNodeAttributeAttribute();
561 default:
562 return nullptr;
566 QVariant CSceneModel::headerData(int column, Qt::Orientation orientation, int role) const
568 switch (column)
570 case eColumnType_Name:
571 if (role == Qt::DisplayRole)
573 return tr("Name");
575 break;
576 case eColumnType_Type:
577 if (role == Qt::DisplayRole)
579 return tr("Type");
581 break;
582 case eColumnType_SourceNodeAttribute:
583 if (role == Qt::DisplayRole)
585 return tr("Attribute");
587 default:
588 break;
591 if (role == Qt::ToolTipRole)
593 return GetToolTipForColumn(column);
596 // Attributes.
597 if (role == Attributes::s_getAttributeRole)
599 CItemModelAttribute* const pAttribute = GetColumnAttribute(column);
600 if (pAttribute)
602 return QVariant::fromValue(pAttribute);
606 return QVariant();
609 Qt::ItemFlags CSceneModel::flags(const QModelIndex& modelIndex) const
611 if (!modelIndex.isValid())
613 return CSceneModelCommon::flags(modelIndex);
616 const CSceneElementCommon* const pSelf = GetSceneElementFromModelIndex(modelIndex);
617 CRY_ASSERT(pSelf);
619 bool bCanBeLod = false;
621 if (pSelf->GetType() == ESceneElementType::SourceNode)
623 bCanBeLod = CanBeLod(((CSceneElementSourceNode*)pSelf)->GetNode());
626 if (modelIndex.column() == eColumnType_Type && bCanBeLod)
628 return Qt::ItemIsEditable | QAbstractItemModel::flags(modelIndex);
630 else if (modelIndex.column() == eColumnType_Name)
632 return Qt::ItemIsUserCheckable | QAbstractItemModel::flags(modelIndex);
634 else
636 return QAbstractItemModel::flags(modelIndex);
640 QVariant CSceneModel::GetToolTipForColumn(int column)
642 switch (column)
644 case eColumnType_Name:
645 return tr("Name of the node in the scene");
646 case eColumnType_Type:
647 return tr("Type of this node");
648 case eColumnType_SourceNodeAttribute:
649 return tr("Attributes of this node");
650 default:
651 assert(false);
652 break;
654 return QVariant();