!B (Sandbox) (CE-21795) Importing models with multisubmaterials via fbx switches...
[CRYENGINE.git] / Code / CryEngine / CrySchematyc2 / Script / GraphNodes / ScriptGraphSwitchNode.cpp
blob89e95497ddc0a996a04a45c84495f4f17d3d9028
1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "StdAfx.h"
4 #include "Script/GraphNodes/ScriptGraphSwitchNode.h"
6 #include <CryString/CryStringUtils.h>
7 #include <CrySchematyc2/GUIDRemapper.h>
8 #include <CrySchematyc2/IDomainContext.h>
9 #include <CrySchematyc2/IObject.h>
10 #include <CrySchematyc2/LibUtils.h>
11 #include <CrySchematyc2/Script/IScriptGraphNodeCompiler.h>
12 #include <CrySchematyc2/Script/IScriptGraphNodeCreationMenu.h>
13 #include <CrySchematyc2/Serialization/ISerializationContext.h>
15 #include "AggregateTypeIdSerialize.h"
16 #include "DomainContext.h"
17 #include "Script/ScriptVariableDeclaration.h"
18 #include "Script/GraphNodes/ScriptGraphNodeFactory.h"
20 namespace Schematyc2
22 const SGUID CScriptGraphSwitchNode::s_typeGUID = "1d081133-e900-4244-add5-f0831d27b16f";
24 CScriptGraphSwitchNode::SCase::SCase() {}
26 CScriptGraphSwitchNode::SCase::SCase(const IAnyPtr& _pValue)
27 : pValue(_pValue)
30 void CScriptGraphSwitchNode::SCase::Serialize(Serialization::IArchive& archive)
32 const IAny* pDefaultValue = archive.context<IAny>();
33 SCHEMATYC2_SYSTEM_ASSERT(pDefaultValue);
34 if(!pValue && pDefaultValue)
36 pValue = pDefaultValue->Clone();
38 if(pValue)
40 archive(*pValue, "value", "^Value");
41 if(archive.isValidation())
43 char stringBuffer[512] = "";
44 ToString(*pValue, stringBuffer);
45 if(!stringBuffer[0])
47 archive.error(*this, "Empty case value!");
51 else if(archive.isValidation())
53 archive.error(*this, "Unable to instantiate case value!");
57 CScriptGraphSwitchNode::CScriptGraphSwitchNode(const SGUID& guid)
58 : CScriptGraphNodeBase(guid)
61 CScriptGraphSwitchNode::CScriptGraphSwitchNode(const SGUID& guid, const Vec2& pos)
62 : CScriptGraphNodeBase(guid, pos)
65 SGUID CScriptGraphSwitchNode::GetTypeGUID() const
67 return s_typeGUID;
70 EScriptGraphColor CScriptGraphSwitchNode::GetColor() const
72 return EScriptGraphColor::Orange;
75 void CScriptGraphSwitchNode::Refresh(const SScriptRefreshParams& params)
77 CRY_PROFILE_FUNCTION(PROFILE_LOADING_ONLY);
79 CScriptGraphNodeBase::Refresh(params);
81 CScriptGraphNodeBase::SetName("Switch");
82 CScriptGraphNodeBase::AddInput(EScriptGraphPortFlags::MultiLink | EScriptGraphPortFlags::Execute, "In");
83 CScriptGraphNodeBase::AddOutput(EScriptGraphPortFlags::Execute | EScriptGraphPortFlags::SpacerBelow, "Default");
85 if(m_typeId)
87 CScriptGraphNodeBase::AddInput(EScriptGraphPortFlags::Data, "Value", m_typeId);
89 uint32 invalidCaseCount = 0;
90 for(SCase& _case : m_cases)
92 char outputName[128] = "";
93 if(_case.pValue)
95 ToString(*_case.pValue, outputName);
97 if(!outputName[0])
99 cry_sprintf(outputName, "INVALID_CASE[%d]", ++ invalidCaseCount);
101 CScriptGraphNodeBase::AddOutput(EScriptGraphPortFlags::Removable | EScriptGraphPortFlags::Execute, outputName);
106 void CScriptGraphSwitchNode::Serialize(Serialization::IArchive& archive)
108 CRY_PROFILE_FUNCTION(PROFILE_LOADING_ONLY);
110 CScriptGraphNodeBase::Serialize(archive);
112 switch(SerializationContext::GetPass(archive))
114 case ESerializationPass::PreLoad:
116 SerializeBasicInfo(archive);
117 break;
119 case ESerializationPass::PostLoad:
121 CreateDefaultValue();
122 SerializeCases(archive);
123 break;
125 case ESerializationPass::Save:
127 SerializeBasicInfo(archive);
128 SerializeCases(archive);
129 break;
131 case ESerializationPass::Edit:
133 Edit(archive);
134 SerializeCases(archive);
135 Validate(archive);
136 break;
138 case ESerializationPass::Validate:
140 SerializeCases(archive);
141 Validate(archive);
142 break;
147 void CScriptGraphSwitchNode::RemapGUIDs(IGUIDRemapper& guidRemapper)
149 CScriptGraphNodeBase::RemapGUIDs(guidRemapper);
151 if(m_typeId.GetDomain() == EDomain::Script) // #SchematycTODO : Create CAggregateTypeId::RemapGUIDs() function?
153 m_typeId = CAggregateTypeId::FromScriptTypeGUID(guidRemapper.Remap(m_typeId.AsScriptTypeGUID()));
157 void CScriptGraphSwitchNode::Compile_New(IScriptGraphNodeCompiler& compiler) const
159 if(m_pDefaultValue)
161 compiler.BindCallback(&Execute);
163 const uint32 caseCount = m_cases.size();
164 compiler.BindAttribute(EAttributeId::CaseCount, caseCount);
165 for(uint32 caseIdx = 0; caseIdx < caseCount; ++ caseIdx)
167 if(m_cases[caseIdx].pValue)
169 compiler.BindAnyAttribute(EAttributeId::FirstCase + caseIdx, *m_cases[caseIdx].pValue);
173 compiler.BindAnyInput(EInputIdx::Value, *m_pDefaultValue);
177 void CScriptGraphSwitchNode::RegisterCreator(CScriptGraphNodeFactory& factory)
179 class CCreator : public IScriptGraphNodeCreator
181 private:
183 class CNodeCreationMenuCommand : public IScriptGraphNodeCreationMenuCommand
185 public:
187 // IMenuCommand
189 IScriptGraphNodePtr Execute(const Vec2& pos)
191 return std::make_shared<CScriptGraphSwitchNode>(gEnv->pSchematyc2->CreateGUID(), pos);
194 // ~IMenuCommand
197 public:
199 // IScriptGraphNodeCreator
201 virtual SGUID GetTypeGUID() const override
203 return CScriptGraphSwitchNode::s_typeGUID;
206 virtual IScriptGraphNodePtr CreateNode() override
208 return std::make_shared<CScriptGraphSwitchNode>(gEnv->pSchematyc2->CreateGUID());
211 virtual void PopulateNodeCreationMenu(IScriptGraphNodeCreationMenu& nodeCreationMenu, const IDomainContext& domainContext, const IScriptGraphExtension& graph) override
213 nodeCreationMenu.AddOption("Switch", "Switch on input value", "", std::make_shared<CNodeCreationMenuCommand>());
216 // ~IScriptGraphNodeCreator
219 factory.RegisterCreator(std::make_shared<CCreator>());
222 void CScriptGraphSwitchNode::CreateDefaultValue()
224 if(!m_pDefaultValue || (m_pDefaultValue->GetTypeInfo().GetTypeId() != m_typeId))
226 m_pDefaultValue = MakeScriptVariableValueShared(CScriptGraphNodeBase::GetGraph()->GetElement_New().GetFile(), m_typeId);
228 m_cases.clear();
232 void CScriptGraphSwitchNode::SerializeBasicInfo(Serialization::IArchive& archive)
234 archive(m_typeId, "typeId");
237 void CScriptGraphSwitchNode::SerializeCases(Serialization::IArchive& archive)
239 Serialization::SContext context(archive, static_cast<IAny*>(m_pDefaultValue.get()));
240 archive(m_cases, "cases", "Cases");
243 void CScriptGraphSwitchNode::Edit(Serialization::IArchive& archive)
245 TypeIds typeIds;
246 Serialization::StringList typeNames;
247 typeIds.reserve(50);
248 typeNames.reserve(50);
250 auto visitEnvType = [&typeIds, &typeNames] (const IEnvTypeDesc& envTypeDesc) -> EVisitStatus
252 if((envTypeDesc.GetCategory() == EEnvTypeCategory::Enumeration) || ((envTypeDesc.GetFlags() & EEnvTypeFlags::Switchable) != 0))
254 typeIds.push_back(envTypeDesc.GetTypeInfo().GetTypeId());
255 typeNames.push_back(envTypeDesc.GetName());
257 return EVisitStatus::Continue;
259 gEnv->pSchematyc2->GetEnvRegistry().VisitTypeDescs(EnvTypeDescVisitor::FromLambdaFunction(visitEnvType)); // #SchematycTODO : Use domain context?
261 const IScriptElement& scriptElement = CScriptGraphNodeBase::GetGraph()->GetElement_New();
262 CDomainContext domainContext(SDomainContextScope(&scriptElement.GetFile(), scriptElement.GetScopeGUID()));
263 auto visitScriptEnumeration = [&typeIds, &typeNames, &domainContext] (const IScriptEnumeration& scriptEnumeration) -> EVisitStatus
265 typeIds.push_back(scriptEnumeration.GetTypeId());
267 stack_string typeName;
268 domainContext.QualifyName(scriptEnumeration, EDomainQualifier::Local, typeName);
269 typeNames.push_back(typeName.c_str());
271 return EVisitStatus::Continue;
273 domainContext.VisitScriptEnumerations(ScriptEnumerationConstVisitor::FromLambdaFunction(visitScriptEnumeration), EDomainScope::Derived);
275 if(archive.isInput())
277 Serialization::StringListValue typeName(typeNames, 0);
278 archive(typeName, "typeName", "Type");
280 const CAggregateTypeId oldTypeId = m_typeId;
281 const CAggregateTypeId newTypeId = typeIds[typeName.index()];
282 m_typeId = newTypeId;
283 if (oldTypeId != newTypeId)
285 m_cases.clear();
286 CScriptGraphNodeBase::GetGraph()->RemoveLinks(CScriptGraphNodeBase::GetGUID());
288 CreateDefaultValue();
290 else if(archive.isOutput())
292 int typeIdx;
293 TypeIds::iterator itTypeId = std::find(typeIds.begin(), typeIds.end(), m_typeId);
294 if(itTypeId != typeIds.end())
296 typeIdx = static_cast<int>(itTypeId - typeIds.begin());
298 else
300 typeIds.push_back(m_typeId);
301 typeNames.push_back("None");
302 typeIdx = static_cast<int>(typeIds.size() - 1);
305 Serialization::StringListValue typeName(typeNames, typeIdx);
306 archive(typeName, "typeName", "Type");
310 void CScriptGraphSwitchNode::Validate(Serialization::IArchive& archive)
312 std::vector<stack_string> caseStrings;
313 uint32 duplicateCaseValueCount = 0;
314 for(const SCase& _case : m_cases)
316 if(_case.pValue)
318 char stringBuffer[128] = "";
319 ToString(*_case.pValue, stringBuffer);
320 if(stringBuffer[0])
322 stack_string caseString = stringBuffer;
323 if(std::find(caseStrings.begin(), caseStrings.end(), caseString) != caseStrings.end())
325 ++ duplicateCaseValueCount;
327 else
329 caseStrings.push_back(caseString);
334 if(duplicateCaseValueCount)
336 archive.error(*this, "Duplicate case values detected!");
340 SRuntimeResult CScriptGraphSwitchNode::Execute(IObject* pObject, const SRuntimeActivationParams& activationParams, CRuntimeNodeData& data)
342 const IAny* pValue = data.GetInput(EInputIdx::Value);
343 // Note: we can't make this into a fatal assert because this will then crash the editor when the user
344 // changes the type of the switch node.
345 //SCHEMATYC2_SYSTEM_ASSERT_FATAL(pValue != nullptr);
346 if (pValue != nullptr)
348 const uint32 caseCount = *data.GetAttribute<uint32>(EAttributeId::CaseCount);
349 for (uint32 caseIdx = 0; caseIdx < caseCount; ++caseIdx)
351 const IAny* pCaseValue = data.GetAttribute(EAttributeId::FirstCase + caseIdx);
352 if (pCaseValue != nullptr)
354 if (*pValue == *pCaseValue)
356 return SRuntimeResult(ERuntimeStatus::Continue, EOutputIdx::FirstCase + caseIdx);
361 return SRuntimeResult(ERuntimeStatus::Continue, EOutputIdx::Default);