!I (1670414, 1670415, 1670416, 1670424, 1670431):
[CRYENGINE.git] / Code / Sandbox / EditorQt / Material / MaterialManager.cpp
blob686501b05f72bbe4212182ec4998c2a55694942a
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "StdAfx.h"
4 #include "MaterialManager.h"
6 #include "Material.h"
7 #include "MaterialLibrary.h"
9 #include "Viewport.h"
10 #include "ModelViewport.h"
11 #include "MaterialSender.h"
13 #include <CryAnimation/ICryAnimation.h>
14 #include "ISourceControl.h"
16 #include "Util/BoostPythonHelpers.h"
18 #include "Terrain/Layer.h"
19 #include "Terrain/TerrainManager.h"
20 #include "Terrain/SurfaceType.h"
22 #include "QT/QtMainFrame.h"
24 #include <CryString/CryPath.h>
25 #include <FilePathUtil.h>
26 #include <Preferences/ViewportPreferences.h>
27 #include <QAbstractNativeEventFilter>
28 #include <QApplication>
30 static const char* MATERIALS_LIBS_PATH = "Materials/";
31 static unsigned int s_highlightUpdateCounter = 0;
33 struct SHighlightMode
35 float m_colorHue;
36 float m_period;
37 bool m_continuous;
40 static SHighlightMode g_highlightModes[] = {
41 { 0.70f, 0.8f, true }, // purple
42 { 0.25f, 0.75f, false }, // green
43 { 0.0, 0.75f, true } // red
46 class CMaterialHighlighter
48 public:
49 void Start(CMaterial* pMaterial, int modeFlag);
50 void Stop(CMaterial* pMaterial, int modeFlag);
51 void GetHighlightColor(ColorF* color, float* intensity, int flags);
53 void ClearMaterials() { m_materials.clear(); };
54 void RestoreMaterials();
55 void Update();
56 private:
57 struct SHighlightOptions
59 int m_modeFlags;
62 typedef std::map<CMaterial*, SHighlightOptions> Materials;
63 Materials m_materials;
66 void CMaterialHighlighter::Start(CMaterial* pMaterial, int modeFlag)
68 Materials::iterator it = m_materials.find(pMaterial);
69 if (it == m_materials.end())
71 SHighlightOptions& options = m_materials[pMaterial];
72 options.m_modeFlags = modeFlag;
74 else
76 SHighlightOptions& options = it->second;
77 options.m_modeFlags |= modeFlag;
81 void CMaterialHighlighter::Stop(CMaterial* pMaterial, int modeFlag)
83 if (pMaterial)
84 pMaterial->SetHighlightFlags(0);
86 Materials::iterator it = m_materials.find(pMaterial);
87 if (it == m_materials.end())
88 return;
90 SHighlightOptions& options = it->second;
91 MAKE_SURE((options.m_modeFlags & modeFlag) != 0, return );
93 options.m_modeFlags &= ~modeFlag;
94 if (options.m_modeFlags == 0)
95 m_materials.erase(it);
98 void CMaterialHighlighter::RestoreMaterials()
100 for (Materials::iterator it = m_materials.begin(); it != m_materials.end(); ++it)
102 if (it->first)
103 it->first->SetHighlightFlags(0);
107 void CMaterialHighlighter::Update()
109 unsigned int counter = s_highlightUpdateCounter;
111 Materials::iterator it;
112 for (it = m_materials.begin(); it != m_materials.end(); ++it)
114 // Only update each material every 4 frames
115 if (counter++ % 4 == 0)
117 it->first->SetHighlightFlags(it->second.m_modeFlags);
121 s_highlightUpdateCounter = (s_highlightUpdateCounter + 1) % 4;
124 void CMaterialHighlighter::GetHighlightColor(ColorF* color, float* intensity, int flags)
126 MAKE_SURE(color != 0, return );
127 MAKE_SURE(intensity != 0, return );
129 *intensity = 0.0f;
131 if (flags == 0)
132 return;
134 int flagIndex = 0;
135 while (flags)
137 if ((flags & 1) != 0)
138 break;
139 flags = flags >> 1;
140 ++flagIndex;
143 MAKE_SURE(flagIndex < sizeof(g_highlightModes) / sizeof(g_highlightModes[0]), return );
145 const SHighlightMode& mode = g_highlightModes[flagIndex];
146 float t = GetTickCount() / 1000.0f;
147 float h = mode.m_colorHue;
148 float s = 1.0f;
149 float v = 1.0f;
151 color->fromHSV(h + sinf(t * g_PI2 * 5.0f) * 0.025f, s, v);
152 color->a = 1.0f;
154 if (mode.m_continuous)
155 *intensity = fabsf(sinf(t * g_PI2 / mode.m_period));
156 else
157 *intensity = max(0.0f, sinf(t * g_PI2 / mode.m_period));
160 boost::python::list PyGetMaterials(string materialName = "", bool selectedOnly = false)
162 boost::python::list result;
164 GetIEditorImpl()->OpenDataBaseLibrary(EDB_TYPE_MATERIAL, NULL);
165 CMaterialManager* pMaterialMgr = GetIEditorImpl()->GetMaterialManager();
167 if (!materialName.IsEmpty())
169 result.append(PyScript::CreatePyGameMaterial((CMaterial*)pMaterialMgr->FindItemByName(materialName)));
171 else if (selectedOnly)
173 if (materialName.IsEmpty() && pMaterialMgr->GetSelectedItem() != NULL)
175 result.append(PyScript::CreatePyGameMaterial((CMaterial*)pMaterialMgr->GetSelectedItem()));
178 else
180 // Acquire all of the materials via iterating across the objects.
181 CBaseObjectsArray objects;
182 GetIEditorImpl()->GetObjectManager()->GetObjects(objects);
183 for (int i = 0; i < objects.size(); i++)
185 result.append(PyScript::CreatePyGameMaterial((CMaterial*)objects[i]->GetMaterial()));
188 return result;
191 BOOST_PYTHON_FUNCTION_OVERLOADS(pyGetMaterialsOverload, PyGetMaterials, 0, 2);
192 REGISTER_PYTHON_OVERLOAD_COMMAND(PyGetMaterials, general, get_materials, pyGetMaterialsOverload,
193 "Get all, subgroup, or selected materials in the material editor.",
194 "general.get_materials(str materialName=\'\', selectedOnly=False, levelOnly=False)");
196 //////////////////////////////////////////////////////////////////////////
197 // CMaterialManager implementation.
198 //////////////////////////////////////////////////////////////////////////
199 CMaterialManager::CMaterialManager()
200 : m_pHighlighter(new CMaterialHighlighter)
201 , m_highlightMask(eHighlight_All & ~(eHighlight_Breakable | eHighlight_NoSurfaceType))
202 , m_currentFolder("")
204 m_bUniqGuidMap = false;
205 m_bUniqNameMap = true;
206 m_bShadersEnumerated = false;
208 m_bMaterialsLoaded = false;
209 m_pLevelLibrary = (CBaseLibrary*)AddLibrary("Level");
210 m_pLevelLibrary->SetLevelLibrary(true);
212 m_MatSender = new CMaterialSender(true);
214 if (gEnv->p3DEngine)
215 gEnv->p3DEngine->GetMaterialManager()->SetListener(this);
216 gViewportDebugPreferences.debugFlagsChanged.Connect(this, &CMaterialManager::OnDebugFlagsChanged);
219 //////////////////////////////////////////////////////////////////////////
220 CMaterialManager::~CMaterialManager()
222 gViewportDebugPreferences.debugFlagsChanged.DisconnectObject(this);
224 delete m_pHighlighter;
225 m_pHighlighter = 0;
227 if (gEnv->p3DEngine)
228 gEnv->p3DEngine->GetMaterialManager()->SetListener(NULL);
230 if (m_MatSender)
232 delete m_MatSender;
233 m_MatSender = 0;
237 //////////////////////////////////////////////////////////////////////////
238 void CMaterialManager::ClearAll()
240 SetCurrentMaterial(NULL);
241 CBaseLibraryManager::ClearAll();
243 m_pLevelLibrary = (CBaseLibrary*)AddLibrary("Level");
244 m_pLevelLibrary->SetLevelLibrary(true);
247 //////////////////////////////////////////////////////////////////////////
248 CMaterial* CMaterialManager::CreateMaterial(const string& sMaterialName, XmlNodeRef& node, int nMtlFlags, unsigned long nLoadingFlags)
250 CMaterial* pMaterial = new CMaterial(sMaterialName, nMtlFlags);
252 if (node)
254 CBaseLibraryItem::SerializeContext serCtx(node, true);
255 serCtx.bUniqName = true;
256 pMaterial->Serialize(serCtx);
258 if (!pMaterial->IsPureChild() && !(pMaterial->GetFlags() & MTL_FLAG_UIMATERIAL))
260 RegisterItem(pMaterial);
263 return pMaterial;
266 //////////////////////////////////////////////////////////////////////////
267 CMaterial* CMaterialManager::CreateMaterial(const char* sMaterialName, XmlNodeRef& node, int nMtlFlags, unsigned long nLoadingFlags)
269 return CreateMaterial(string(sMaterialName), node, nMtlFlags, nLoadingFlags);
272 //////////////////////////////////////////////////////////////////////////
273 void CMaterialManager::Export(XmlNodeRef& node)
275 XmlNodeRef libs = node->newChild("MaterialsLibrary");
276 for (int i = 0; i < GetLibraryCount(); i++)
278 IDataBaseLibrary* pLib = GetLibrary(i);
279 // Level libraries are saved in in level.
280 XmlNodeRef libNode = libs->newChild("Library");
282 // Export library.
283 libNode->setAttr("Name", pLib->GetName());
287 //////////////////////////////////////////////////////////////////////////
288 int CMaterialManager::ExportLib(CMaterialLibrary* pLib, XmlNodeRef& libNode)
290 int num = 0;
291 // Export library.
292 libNode->setAttr("Name", pLib->GetName());
293 libNode->setAttr("File", pLib->GetFilename());
294 libNode->setAttr("SandboxVersion", (const char*)GetIEditorImpl()->GetFileVersion().ToFullString());
295 // Serialize prototypes.
296 for (int j = 0; j < pLib->GetItemCount(); j++)
298 CMaterial* pMtl = (CMaterial*)pLib->GetItem(j);
300 // Only export real used materials.
301 if (pMtl->IsDummy() || pMtl->IsPureChild())
302 continue;
304 XmlNodeRef itemNode = libNode->newChild("Material");
305 itemNode->setAttr("Name", pMtl->GetName());
306 num++;
308 return num;
311 //////////////////////////////////////////////////////////////////////////
312 void CMaterialManager::SetSelectedItem(IDataBaseItem* pItem)
314 m_pSelectedItem = (CBaseLibraryItem*)pItem;
315 SetCurrentMaterial((CMaterial*)pItem);
318 //////////////////////////////////////////////////////////////////////////
319 void CMaterialManager::SetCurrentMaterial(CMaterial* pMtl)
321 if (m_pCurrentMaterial)
323 // Changing current material. save old one.
324 if (m_pCurrentMaterial->IsModified())
325 m_pCurrentMaterial->Save();
328 m_pCurrentMaterial = pMtl;
329 if (m_pCurrentMaterial)
331 m_pCurrentMaterial->OnMakeCurrent();
332 m_pCurrentEngineMaterial = m_pCurrentMaterial->GetMatInfo();
334 else
336 m_pCurrentEngineMaterial = 0;
339 m_pSelectedItem = pMtl;
340 m_pSelectedParent = pMtl ? pMtl->GetParent() : NULL;
342 NotifyItemEvent(m_pCurrentMaterial, EDB_ITEM_EVENT_SELECTED);
345 //////////////////////////////////////////////////////////////////////////
346 void CMaterialManager::SetCurrentFolder(const string& folder)
348 m_currentFolder = folder;
351 //////////////////////////////////////////////////////////////////////////
352 void CMaterialManager::SetMarkedMaterials(const std::vector<_smart_ptr<CMaterial>>& markedMaterials)
354 m_markedMaterials = markedMaterials;
357 void CMaterialManager::OnLoadShader(CMaterial* pMaterial)
359 RemoveFromHighlighting(pMaterial, eHighlight_All);
360 AddForHighlighting(pMaterial);
363 //////////////////////////////////////////////////////////////////////////
364 CMaterial* CMaterialManager::GetCurrentMaterial() const
366 return m_pCurrentMaterial;
369 //////////////////////////////////////////////////////////////////////////
370 CBaseLibraryItem* CMaterialManager::MakeNewItem()
372 CMaterial* pMaterial = new CMaterial("", 0);
373 return pMaterial;
375 //////////////////////////////////////////////////////////////////////////
376 CBaseLibrary* CMaterialManager::MakeNewLibrary()
378 return new CMaterialLibrary(this);
380 //////////////////////////////////////////////////////////////////////////
381 string CMaterialManager::GetRootNodeName()
383 return "MaterialsLibs";
385 //////////////////////////////////////////////////////////////////////////
386 string CMaterialManager::GetLibsPath()
388 if (m_libsPath.IsEmpty())
389 m_libsPath = MATERIALS_LIBS_PATH;
390 return m_libsPath;
393 //////////////////////////////////////////////////////////////////////////
394 void CMaterialManager::ReportDuplicateItem(CBaseLibraryItem* pItem, CBaseLibraryItem* pOldItem)
396 string sLibName;
397 if (pOldItem->GetLibrary())
398 sLibName = pOldItem->GetLibrary()->GetName();
400 CryWarning(VALIDATOR_MODULE_EDITOR, VALIDATOR_WARNING,
401 "Material %s with the duplicate name to the loaded material %s ignored",
402 (const char*)pItem->GetName(), (const char*)pOldItem->GetName());
405 //////////////////////////////////////////////////////////////////////////
406 void CMaterialManager::Serialize(XmlNodeRef& node, bool bLoading)
408 //CBaseLibraryManager::Serialize( node,bLoading );
409 if (bLoading)
412 else
417 int CMaterialManager::GetShaderCount()
419 if (!m_bShadersEnumerated)
420 EnumerateShaders();
422 return m_shaderList.size();
425 const std::vector<string>& CMaterialManager::GetShaderList()
427 if (!m_bShadersEnumerated)
428 EnumerateShaders();
430 return m_shaderList;
433 void CMaterialManager::EnumerateShaders()
435 if (!m_bShadersEnumerated)
437 IRenderer* renderer = GetIEditor()->GetSystem()->GetIRenderer();
438 if (!renderer)
439 return;
441 int numShaders = 0;
443 m_shaderList.clear();
444 m_shaderList.reserve(100);
446 //! Enumerate Shaders.
447 int nNumShaders = 0;
448 string* files = renderer->EF_GetShaderNames(nNumShaders);
450 for (int i = 0; i < nNumShaders; i++)
452 m_shaderList.push_back(files[i]);
455 XmlNodeRef root = GetISystem()->GetXmlUtils()->LoadXmlFromFile("%EDITOR%/Materials/ShaderList.xml");
456 if (root)
458 for (int i = 0; i < root->getChildCount(); ++i)
460 XmlNodeRef ChildNode = root->getChild(i);
461 const char* pTagName = ChildNode->getTag();
462 if (!stricmp(pTagName, "Shader"))
464 string name;
465 if (ChildNode->getAttr("name", name) && !name.IsEmpty())
467 // make sure there is no duplication
468 bool bFound = false;
469 for (const auto& shader : m_shaderList)
471 if (stricmp(name, shader) == 0)
473 bFound = true;
474 break;
478 if(!bFound)
480 m_shaderList.push_back(name);
487 std::sort(m_shaderList.begin(), m_shaderList.end(), [](const string &s1, const string &s2) { return stricmp(s1, s2) < 0; });
489 //capitalize shader names
490 for (string& shaderName : m_shaderList)
492 CRY_ASSERT(shaderName.length() > 0);
493 shaderName.SetAt(0, toupper(shaderName[0]));
496 m_bShadersEnumerated = true;
500 namespace
503 struct SMaterialManagerFilter : QAbstractNativeEventFilter
505 virtual bool nativeEventFilter(const QByteArray& eventType, void* pMessage, long* pResult) override
507 if (eventType != "windows_generic_MSG")
509 return false;
512 const MSG* const pTheMessage = (MSG*)pMessage;
513 if (pTheMessage->message != WM_MATEDITSEND)
515 return false;
518 const CWnd* const pDlg = GetIEditorImpl()->OpenView("Material Editor Legacy");
519 if (pDlg)
521 GetIEditorImpl()->GetMaterialManager()->SyncMaterialEditor();
523 if (pResult)
525 *pResult = 0;
528 return true;
531 return false;
534 static SMaterialManagerFilter& GetInstance()
536 static SMaterialManagerFilter theInstance;
537 return theInstance;
541 } // namespace
543 //////////////////////////////////////////////////////////////////////////
544 void CMaterialManager::OnEditorNotifyEvent(EEditorNotifyEvent event)
546 CBaseLibraryManager::OnEditorNotifyEvent(event);
547 switch (event)
549 case eNotify_OnMainFrameInitialized:
550 InitMatSender();
551 if (!GetIEditorImpl()->IsInMatEditMode())
553 qApp->installNativeEventFilter(&SMaterialManagerFilter::GetInstance());
555 break;
556 case eNotify_OnIdleUpdate:
557 m_pHighlighter->Update();
558 break;
559 case eNotify_OnBeginGameMode:
560 m_pHighlighter->RestoreMaterials();
561 break;
562 case eNotify_OnBeginNewScene:
563 SetCurrentMaterial(0);
564 break;
565 case eNotify_OnBeginSceneOpen:
566 SetCurrentMaterial(0);
567 break;
568 case eNotify_OnMissionChange:
569 SetCurrentMaterial(0);
570 break;
571 case eNotify_OnClearLevelContents:
572 SetCurrentMaterial(0);
573 m_pHighlighter->ClearMaterials();
574 break;
575 case eNotify_OnQuit:
576 SetCurrentMaterial(0);
577 if (gEnv->p3DEngine)
578 gEnv->p3DEngine->GetMaterialManager()->SetListener(NULL);
579 break;
583 //////////////////////////////////////////////////////////////////////////
584 CMaterial* CMaterialManager::LoadMaterial(const string& sMaterialName, bool bMakeIfNotFound)
586 LOADING_TIME_PROFILE_SECTION(GetISystem());
588 string sMaterialNameClear(sMaterialName);
589 int nExtLen = strlen(MATERIAL_FILE_EXT);
590 if (sMaterialNameClear.Right(nExtLen) == MATERIAL_FILE_EXT)
591 sMaterialNameClear = sMaterialNameClear.Left(sMaterialNameClear.GetLength() - nExtLen);
593 // Load material with this name if not yet loaded.
594 CMaterial* pMaterial = (CMaterial*)FindItemByName(sMaterialNameClear);
595 if (pMaterial)
597 return pMaterial;
600 string filename = PathUtil::MakeGamePath(MaterialToFilename(sMaterialNameClear).GetString()).c_str();
601 if (filename.GetLength() - nExtLen < sMaterialNameClear.GetLength() - 1)
603 // Remove game folder in the begin of material name (bad material names in cgf)
604 int nNewLenMaterialName = filename.GetLength() - nExtLen;
605 if (sMaterialNameClear[sMaterialNameClear.GetLength() - nNewLenMaterialName - 1] == '/' &&
606 !stricmp(sMaterialNameClear.Right(nNewLenMaterialName), filename.Left(nNewLenMaterialName)))
608 sMaterialNameClear = sMaterialNameClear.Right(nNewLenMaterialName);
609 filename = PathUtil::MakeGamePath(MaterialToFilename(sMaterialNameClear).GetString()).c_str();
613 // Try to load material with this name again if not yet loaded.
614 pMaterial = (CMaterial*)FindItemByName(sMaterialNameClear);
615 if (pMaterial)
617 return pMaterial;
620 XmlNodeRef mtlNode = GetISystem()->LoadXmlFromFile(filename);
621 if (mtlNode)
623 pMaterial = CreateMaterial(sMaterialNameClear, mtlNode);
625 else
627 if (bMakeIfNotFound)
629 pMaterial = new CMaterial(sMaterialNameClear);
630 pMaterial->SetDummy(true);
631 RegisterItem(pMaterial);
633 CryWarning(VALIDATOR_MODULE_EDITOR, VALIDATOR_WARNING, "Material %s not found", (const char*)sMaterialNameClear);
638 return pMaterial;
641 //////////////////////////////////////////////////////////////////////////
642 CMaterial* CMaterialManager::LoadMaterial(const char* sMaterialName, bool bMakeIfNotFound)
644 return LoadMaterial(string(sMaterialName), bMakeIfNotFound);
647 //////////////////////////////////////////////////////////////////////////
648 static bool MaterialRequiresSurfaceType(CMaterial* pMaterial)
650 // Do not enforce Surface Type...
652 // ...over editor UI materials
653 if ((pMaterial->GetFlags() & MTL_FLAG_UIMATERIAL) != 0)
654 return false;
656 // ...over SKY
657 if (pMaterial->GetShaderName() == "DistanceCloud" ||
658 pMaterial->GetShaderName() == "Sky" ||
659 pMaterial->GetShaderName() == "SkyHDR")
660 return false;
661 // ...over terrain materials
662 if (pMaterial->GetShaderName() == "Terrain.Layer")
663 return false;
664 // ...over vegetation
665 if (pMaterial->GetShaderName() == "Vegetation")
666 return false;
668 // ...over decals
669 CVarBlock* pShaderGenParams = pMaterial->GetShaderGenParamsVars();
670 if (pShaderGenParams)
671 if (IVariable* pVar = pShaderGenParams->FindVariable("Decal"))
673 int value = 0;
674 pVar->Get(value);
675 if (value)
676 return false;
679 return true;
682 //////////////////////////////////////////////////////////////////////////
683 int CMaterialManager::GetHighlightFlags(CMaterial* pMaterial) const
685 if (pMaterial == NULL)
686 return 0;
688 if ((pMaterial->GetFlags() & MTL_FLAG_NODRAW) != 0)
689 return 0;
691 int result = 0;
693 if (pMaterial == m_pHighlightMaterial)
694 result |= eHighlight_Pick;
696 const string& surfaceTypeName = pMaterial->GetSurfaceTypeName();
697 if (surfaceTypeName.IsEmpty() && MaterialRequiresSurfaceType(pMaterial))
698 result |= eHighlight_NoSurfaceType;
700 if (ISurfaceTypeManager* pSurfaceManager = GetIEditorImpl()->Get3DEngine()->GetMaterialManager()->GetSurfaceTypeManager())
702 const ISurfaceType* pSurfaceType = pSurfaceManager->GetSurfaceTypeByName(surfaceTypeName);
703 if (pSurfaceType && pSurfaceType->GetBreakability() != 0)
704 result |= eHighlight_Breakable;
707 return result;
710 //////////////////////////////////////////////////////////////////////////
711 void CMaterialManager::AddForHighlighting(CMaterial* pMaterial)
713 if (pMaterial == NULL)
715 return;
718 int highlightFlags = (GetHighlightFlags(pMaterial) & m_highlightMask);
719 if (highlightFlags != 0)
721 m_pHighlighter->Start(pMaterial, highlightFlags);
724 int count = pMaterial->GetSubMaterialCount();
725 for (int i = 0; i < count; ++i)
727 CMaterial* pChild = pMaterial->GetSubMaterial(i);
728 if (!pChild)
729 continue;
731 AddForHighlighting(pChild);
735 //////////////////////////////////////////////////////////////////////////
736 void CMaterialManager::RemoveFromHighlighting(CMaterial* pMaterial, int mask)
738 if (pMaterial == NULL)
739 return;
741 m_pHighlighter->Stop(pMaterial, mask);
743 int count = pMaterial->GetSubMaterialCount();
744 for (int i = 0; i < count; ++i)
746 CMaterial* pChild = pMaterial->GetSubMaterial(i);
747 if (!pChild)
748 continue;
750 RemoveFromHighlighting(pChild, mask);
754 //////////////////////////////////////////////////////////////////////////
755 void CMaterialManager::UpdateHighlightedMaterials()
757 IDataBaseItemEnumerator* pEnum = CBaseLibraryManager::GetItemEnumerator();
758 if (!pEnum)
759 return;
761 CMaterial* pMaterial = (CMaterial*)pEnum->GetFirst();
762 while (pMaterial)
764 RemoveFromHighlighting(pMaterial, eHighlight_All);
765 AddForHighlighting(pMaterial);
766 pMaterial = (CMaterial*)pEnum->GetNext();
769 pEnum->Release();
772 //////////////////////////////////////////////////////////////////////////
773 IMaterial* CMaterialManager::OnLoadMaterial(const char* sMtlName, bool bForceCreation, unsigned long nLoadingFlags)
775 _smart_ptr<CMaterial> pMaterial = LoadMaterial(sMtlName, bForceCreation);
776 if (pMaterial)
778 AddForHighlighting(pMaterial);
779 return pMaterial->GetMatInfo();
781 return NULL;
784 //////////////////////////////////////////////////////////////////////////
785 void CMaterialManager::OnRequestMaterial(IMaterial* pMatInfo)
787 const char* pcName = pMatInfo->GetName();
788 CMaterial* pMaterial = (CMaterial*) pMatInfo->GetUserData();
790 // LoadMaterial() will return registered items if they match
791 // It will also register items if the item is not found and the XML exists and it's not a pure child
792 if (!pMaterial && pcName && *pcName)
793 pMaterial = LoadMaterial(pcName, false);
795 if (pMaterial)
797 IMaterial* pNewMatInfo = pMaterial->GetMatInfo(true);
798 assert(pNewMatInfo == pMatInfo);
800 // RegisterItem() can be called through multiple request of the same materials or through a cascade
801 // of calls (see above), thus prevent warning messages by calling it conditionally.
802 string fullName = pMaterial->GetFullName();
803 if (!fullName.IsEmpty() && !FindItemByName(fullName))
804 RegisterItem(pMaterial);
808 //////////////////////////////////////////////////////////////////////////
809 void CMaterialManager::OnCreateMaterial(IMaterial* pMatInfo)
811 if (!(pMatInfo->GetFlags() & MTL_FLAG_PURE_CHILD) && !(pMatInfo->GetFlags() & MTL_FLAG_UIMATERIAL))
813 CMaterial* pMaterial = new CMaterial(pMatInfo->GetName());
814 pMaterial->SetFromMatInfo(pMatInfo);
815 RegisterItem(pMaterial);
817 AddForHighlighting(pMaterial);
822 //////////////////////////////////////////////////////////////////////////
823 void CMaterialManager::OnDeleteMaterial(IMaterial* pMaterial)
825 CMaterial* pMtl = (CMaterial*)pMaterial->GetUserData();
826 if (pMtl)
828 RemoveFromHighlighting(pMtl, eHighlight_All);
829 pMtl->ClearMatInfo();
833 //////////////////////////////////////////////////////////////////////////
834 CMaterial* CMaterialManager::FromIMaterial(IMaterial* pMaterial)
836 if (!pMaterial)
837 return 0;
838 CMaterial* pMtl = (CMaterial*)pMaterial->GetUserData();
839 return pMtl;
842 //////////////////////////////////////////////////////////////////////////
843 void CMaterialManager::SaveAllLibs()
847 //////////////////////////////////////////////////////////////////////////
848 string CMaterialManager::FilenameToMaterial(const string& filename)
850 string name = PathUtil::RemoveExtension(filename.GetString()).c_str();
851 name.Replace('\\', '/');
853 string sDataFolder = PathUtil::GetGameFolder();
854 // Remove "DATA_FOLDER/" sub path from the filename.
855 if (name.GetLength() > (sDataFolder.GetLength()) && strnicmp(name, sDataFolder, sDataFolder.GetLength()) == 0)
857 name = name.Mid(sDataFolder.GetLength() + 1); // skip the slash...
861 // Remove "materials/" sub path from the filename.
862 if (name.GetLength() > sizeof(MATERIALS_PATH)-1 && strnicmp(name,MATERIALS_PATH,sizeof(MATERIALS_PATH)-1) == 0)
864 //name = name.Mid(sizeof(MATERIALS_PATH)+1);
867 return name;
870 //////////////////////////////////////////////////////////////////////////
871 string CMaterialManager::MaterialToFilename(const string& sMaterialName, bool bForWriting)
873 string filename = PathUtil::ReplaceExtension(sMaterialName.GetString(), MATERIAL_FILE_EXT).c_str();
874 return filename;
877 //////////////////////////////////////////////////////////////////////////
878 bool CMaterialManager::DeleteMaterial(CMaterial* pMtl)
880 assert(pMtl);
881 _smart_ptr<CMaterial> _ref(pMtl);
882 if (pMtl == GetCurrentMaterial())
883 SetCurrentMaterial(NULL);
885 DeleteItem(pMtl);
887 // Unassign this material from all objects.
888 CBaseObjectsArray objects;
889 GetIEditorImpl()->GetObjectManager()->GetObjects(objects);
890 int i;
891 for (i = 0; i < objects.size(); i++)
893 CBaseObject* pObject = objects[i];
894 if (pObject->GetMaterial() == pMtl)
896 pObject->SetMaterial(NULL);
899 // Delete it from all sub materials.
900 for (i = 0; i < m_pLevelLibrary->GetItemCount(); i++)
902 CMaterial* pMultiMtl = (CMaterial*)m_pLevelLibrary->GetItem(i);
903 if (pMultiMtl->IsMultiSubMaterial())
905 for (int slot = 0; slot < pMultiMtl->GetSubMaterialCount(); slot++)
907 if (pMultiMtl->GetSubMaterial(slot) == pMultiMtl)
909 // Clear this sub material slot.
910 pMultiMtl->SetSubMaterial(slot, 0);
915 bool bRes = true;
916 // Delete file on disk.
917 if (!pMtl->GetFilename().IsEmpty())
919 if (!::DeleteFile(pMtl->GetFilename()))
920 bRes = false;
923 return bRes;
926 //////////////////////////////////////////////////////////////////////////
927 bool CMaterialManager::SelectSaveMaterial(string& itemName, const char* defaultStartPath)
929 string startPath;
930 if (defaultStartPath && defaultStartPath[0] != '\0')
932 startPath = defaultStartPath;
934 else
936 startPath = string(PathUtil::GetGameFolder()) + "/Materials";
939 string filename;
940 if (!CFileUtil::SelectSaveFile("Material Files (*.mtl)|*.mtl", "mtl", startPath, filename))
942 return false;
945 filename = PathUtil::ToDosPath(filename.GetString()).c_str();
947 itemName = PathUtil::AbsolutePathToGamePath(filename.GetString()).c_str();
948 itemName = PathUtil::RemoveExtension(itemName.GetString()).c_str();
949 if (itemName.IsEmpty())
950 return false;
952 return true;
955 //////////////////////////////////////////////////////////////////////////
956 CMaterial* CMaterialManager::SelectNewMaterial(int nMtlFlags, const char* szStartPath)
958 string path;
959 if (szStartPath)
961 path = szStartPath;
963 else if (m_pCurrentMaterial)
965 path = PathUtil::GetPathWithoutFilename(m_pCurrentMaterial->GetFilename());
967 else
969 path = m_currentFolder;
971 string itemName;
972 if (!SelectSaveMaterial(itemName, path))
973 return 0;
975 if (FindItemByName(itemName))
977 Warning("Material with name %s already exist", (const char*)itemName);
978 return 0;
981 _smart_ptr<CMaterial> mtl = CreateMaterial(itemName, XmlNodeRef(), nMtlFlags);
982 mtl->Update();
983 mtl->Save();
984 SetCurrentMaterial(mtl);
985 return mtl;
988 //////////////////////////////////////////////////////////////////////////
989 void CMaterialManager::Command_Create()
991 SelectNewMaterial(0);
994 //////////////////////////////////////////////////////////////////////////
995 void CMaterialManager::Command_CreateMulti()
997 SelectNewMaterial(MTL_FLAG_MULTI_SUBMTL);
1000 //////////////////////////////////////////////////////////////////////////
1001 void CMaterialManager::Command_ConvertToMulti()
1003 CMaterial* pMaterial = GetCurrentMaterial();
1005 if (pMaterial && pMaterial->GetSubMaterialCount() == 0)
1007 pMaterial->ConvertToMultiMaterial();
1008 pMaterial->Save();
1009 pMaterial->Reload();
1010 SetSelectedItem(pMaterial->GetSubMaterial(0));
1012 else
1014 Warning(pMaterial ? "material.convert_to_multi called on invalid material setup" : "material.convert_to_multi called while no material selected");
1018 //////////////////////////////////////////////////////////////////////////
1019 void CMaterialManager::Command_Duplicate()
1021 CMaterial* pSrcMtl = GetCurrentMaterial();
1023 if (!pSrcMtl)
1025 CryWarning(VALIDATOR_MODULE_EDITOR, VALIDATOR_WARNING, "material.duplicate_current called while no materials selected");
1026 return;
1029 if (GetIEditorImpl()->IsSourceControlAvailable())
1031 uint32 attrib = pSrcMtl->GetFileAttributes();
1033 if ((attrib & SCC_FILE_ATTRIBUTE_INPAK) && (attrib & SCC_FILE_ATTRIBUTE_MANAGED) && !(attrib & SCC_FILE_ATTRIBUTE_NORMAL))
1035 // Get latest for making folders with right case
1036 GetIEditorImpl()->GetSourceControl()->GetLatestVersion(pSrcMtl->GetFilename());
1040 if (pSrcMtl != 0 && !pSrcMtl->IsPureChild())
1042 string name = MakeUniqItemName(pSrcMtl->GetName());
1043 // Create a new material.
1044 _smart_ptr<CMaterial> pMtl = DuplicateMaterial(name, pSrcMtl);
1045 if (pMtl)
1047 pMtl->Save();
1048 SetSelectedItem(pMtl);
1053 //////////////////////////////////////////////////////////////////////////
1054 CMaterial* CMaterialManager::DuplicateMaterial(const char* newName, CMaterial* pOriginal)
1056 if (!newName)
1058 assert(0 && "NULL newName passed into " __FUNCTION__);
1059 return 0;
1061 if (!pOriginal)
1063 assert(0 && "NULL pOriginal passed into " __FUNCTION__);
1064 return 0;
1067 XmlNodeRef node = GetISystem()->CreateXmlNode("Material");
1068 CBaseLibraryItem::SerializeContext ctx(node, false);
1069 ctx.bCopyPaste = true;
1070 pOriginal->Serialize(ctx);
1072 return CreateMaterial(newName, node, pOriginal->GetFlags());
1075 //////////////////////////////////////////////////////////////////////////
1076 void CMaterialManager::Command_Merge()
1078 string itemName;
1079 string defaultMaterialPath;
1080 if (m_pCurrentMaterial)
1081 defaultMaterialPath = PathUtil::GetPathWithoutFilename(m_pCurrentMaterial->GetFilename());
1082 if (!SelectSaveMaterial(itemName, defaultMaterialPath))
1083 return;
1085 _smart_ptr<CMaterial> pNewMaterial = CreateMaterial(itemName, XmlNodeRef(), MTL_FLAG_MULTI_SUBMTL);
1087 size_t numRecords = m_markedMaterials.size();
1088 size_t subMaterialIndex = 0;
1089 for (size_t i = 0; i < numRecords; ++i)
1091 _smart_ptr<CMaterial>& pMaterial = m_markedMaterials[i];
1092 int subMaterialCount = pMaterial->GetSubMaterialCount();
1093 pNewMaterial->SetSubMaterialCount(pNewMaterial->GetSubMaterialCount() + subMaterialCount);
1094 for (size_t j = 0; j < subMaterialCount; ++j)
1096 CMaterial* pSubMaterial = pMaterial->GetSubMaterial(j);
1097 CMaterial* pNewSubMaterial = 0;
1098 if (pSubMaterial)
1100 // generate unique name
1101 string name = pSubMaterial->GetName();
1102 size_t nameIndex = 0;
1104 bool nameUpdated = true;
1105 while (nameUpdated)
1107 nameUpdated = false;
1108 for (size_t k = 0; k < subMaterialIndex; ++k)
1110 if (pNewMaterial->GetSubMaterial(k)->GetName() == name)
1112 ++nameIndex;
1113 name.Format("%s%02d", pSubMaterial->GetName(), nameIndex);
1114 nameUpdated = true;
1115 break;
1119 pNewSubMaterial = DuplicateMaterial(name, pSubMaterial);
1121 pNewMaterial->SetSubMaterial(subMaterialIndex, pNewSubMaterial);
1122 ++subMaterialIndex;
1126 pNewMaterial->Update();
1127 pNewMaterial->Save();
1128 SetCurrentMaterial(pNewMaterial);
1131 //////////////////////////////////////////////////////////////////////////
1132 void CMaterialManager::Command_Delete()
1134 CMaterial* pMtl = GetCurrentMaterial();
1135 if (pMtl)
1137 CUndo undo("Delete Material");
1138 string str;
1139 str.Format(_T("Delete Material %s?\r\nNote: Material file %s will also be deleted."),
1140 (const char*)pMtl->GetName(), (const char*)pMtl->GetFilename());
1141 if (MessageBox(AfxGetMainWnd()->GetSafeHwnd(), str, _T("Delete Confirmation"), MB_YESNO | MB_ICONQUESTION) == IDYES)
1143 DeleteMaterial(pMtl);
1144 SetCurrentMaterial(0);
1149 void CMaterialManager::Command_CreateTerrainLayer()
1151 CMaterial* pMaterial = GetCurrentMaterial();
1153 if (!pMaterial)
1154 return;
1156 CLayer* pLayer = 0;
1157 string sMaterialPath = pMaterial ? pMaterial->GetName() : "";
1158 bool bFound = false;
1159 CTerrainManager* terrainManager = GetIEditorImpl()->GetTerrainManager();
1161 for (int i = 0, n = terrainManager->GetLayerCount(); i < n; ++i)
1163 CLayer* pCurLayer = terrainManager->GetLayer(i);
1164 CSurfaceType* pSurfaceType = pCurLayer->GetSurfaceType();
1166 if (pSurfaceType && stricmp(pSurfaceType->GetMaterial(), sMaterialPath.GetBuffer()) == 0)
1168 pLayer = pCurLayer;
1169 break;
1173 if (pLayer)
1175 MessageBox(AfxGetMainWnd()->GetSafeHwnd(), _T("There's already a terrain layer with that material."), _T("Existing layer"), MB_ICONEXCLAMATION);
1177 else
1179 pLayer = new CLayer;
1180 pLayer->SetLayerName(PathUtil::GetFile(sMaterialPath.c_str()));
1181 pLayer->LoadTexture(string(PathUtil::GetGameFolder() + "/Textures/Terrain/Default.dds"));
1182 pLayer->GetOrRequestLayerId();
1183 terrainManager->AddLayer(pLayer);
1184 pLayer->AssignMaterial(sMaterialPath);
1185 terrainManager->ReloadSurfaceTypes(true, false);
1188 for (int i = 0, n = terrainManager->GetLayerCount(); i < n; ++i)
1189 terrainManager->GetLayer(i)->SetSelected(false);
1191 pLayer->SetSelected(true);
1192 GetIEditorImpl()->Notify(eNotify_OnInvalidateControls);
1195 //////////////////////////////////////////////////////////////////////////
1196 void CMaterialManager::Command_AssignToSelection()
1198 CMaterial* pMtl = GetCurrentMaterial();
1199 if (pMtl)
1201 CUndo undo("Assign Material");
1202 const CSelectionGroup* pSel = GetIEditorImpl()->GetSelection();
1203 if (pMtl->IsPureChild())
1205 int nSelectionCount = pSel->GetCount();
1206 bool bAllDesignerObject = nSelectionCount == 0 ? false : true;
1207 for (int i = 0; i < nSelectionCount; ++i)
1209 if (pSel->GetObject(i)->GetType() != OBJTYPE_SOLID)
1211 bAllDesignerObject = false;
1212 break;
1215 if (!bAllDesignerObject)
1217 if (MessageBox(AfxGetMainWnd()->GetSafeHwnd(), _T("You can assign submaterials to objects only for preview purpose. This assignment will not be saved with the level and will not be exported to the game."), _T("Assign Submaterial"), MB_OKCANCEL | MB_ICONINFORMATION) == IDCANCEL)
1218 return;
1221 if (!pSel->IsEmpty())
1223 for (int i = 0; i < pSel->GetCount(); i++)
1225 pSel->GetObject(i)->SetMaterial(pMtl);
1226 pSel->GetObject(i)->UpdateGroup();
1227 pSel->GetObject(i)->UpdatePrefab();
1231 CViewport* pViewport = GetIEditorImpl()->GetActiveView();
1232 if (pViewport)
1234 pViewport->Drop(CPoint(-1, -1), pMtl);
1238 //////////////////////////////////////////////////////////////////////////
1239 void CMaterialManager::Command_ResetSelection()
1241 const CSelectionGroup* pSel = GetIEditorImpl()->GetSelection();
1242 if (!pSel->IsEmpty())
1244 CUndo undo("Reset Material");
1245 for (int i = 0; i < pSel->GetCount(); i++)
1247 CBaseObject* pObject = pSel->GetObject(i);
1248 pObject->SetMaterial(0);
1249 pObject->UpdatePrefab();
1252 CViewport* pViewport = GetIEditorImpl()->GetActiveView();
1253 if (pViewport)
1255 pViewport->Drop(CPoint(-1, -1), 0);
1259 //////////////////////////////////////////////////////////////////////////
1260 void CMaterialManager::Command_SelectAssignedObjects()
1262 CMaterial* pMtl = GetCurrentMaterial();
1263 if (pMtl)
1265 CUndo undo("Select Object(s)");
1266 CBaseObjectsArray objects;
1267 GetIEditorImpl()->GetObjectManager()->GetObjects(objects);
1268 for (int i = 0; i < objects.size(); i++)
1270 CBaseObject* pObject = objects[i];
1271 if (pObject->GetMaterial() == pMtl || pObject->GetRenderMaterial() == pMtl)
1273 if (pObject->IsHidden() || pObject->IsFrozen())
1274 continue;
1275 GetIEditorImpl()->GetObjectManager()->SelectObject(pObject);
1281 //////////////////////////////////////////////////////////////////////////
1282 void CMaterialManager::Command_SelectFromObject()
1284 if (GetIEditorImpl()->IsInPreviewMode())
1286 CViewport* pViewport = GetIEditorImpl()->GetActiveView();
1287 if (pViewport && pViewport->GetType() == ET_ViewportModel)
1289 CMaterial* pMtl = static_cast<CMaterial*>(((CModelViewport*)pViewport)->GetMaterial());
1290 SetCurrentMaterial(pMtl);
1292 return;
1295 const CSelectionGroup* pSel = GetIEditorImpl()->GetSelection();
1296 if (pSel->IsEmpty())
1297 return;
1299 for (int i = 0; i < pSel->GetCount(); i++)
1301 CMaterial* pMtl = (CMaterial*)pSel->GetObject(i)->GetRenderMaterial();
1302 if (pMtl)
1304 SetCurrentMaterial(pMtl);
1305 return;
1310 //////////////////////////////////////////////////////////////////////////
1311 void CMaterialManager::PickPreviewMaterial(HWND hWndCaller)
1313 XmlNodeRef data = XmlHelpers::CreateXmlNode("ExportMaterial");
1314 CMaterial* pMtl = GetCurrentMaterial();
1315 if (!pMtl)
1316 return;
1318 if (pMtl->IsPureChild() && pMtl->GetParent())
1319 pMtl = pMtl->GetParent();
1321 if (pMtl->GetFlags() & MTL_FLAG_WIRE)
1322 data->setAttr("Flag_Wire", 1);
1323 if (pMtl->GetFlags() & MTL_FLAG_2SIDED)
1324 data->setAttr("Flag_2Sided", 1);
1326 data->setAttr("Name", pMtl->GetName());
1327 data->setAttr("FileName", pMtl->GetFilename());
1329 XmlNodeRef node = data->newChild("Material");
1331 CBaseLibraryItem::SerializeContext serCtx(node, false);
1332 pMtl->Serialize(serCtx);
1334 if (!pMtl->IsMultiSubMaterial())
1336 XmlNodeRef texturesNode = node->findChild("Textures");
1337 if (texturesNode)
1339 for (int i = 0; i < texturesNode->getChildCount(); i++)
1341 XmlNodeRef texNode = texturesNode->getChild(i);
1342 string file;
1343 if (texNode->getAttr("File", file))
1346 if (file.size() >= 2 && file.c_str()[0] == '.' && (file.c_str()[1] == '/' || file.c_str()[1] == '\\'))
1348 // Texture file location is relative to material file folder
1349 file = PathUtil::Make(PathUtil::GetPathWithoutFilename(pMtl->GetFilename()), &file.c_str()[2]);
1352 char sFullFilenameLC[MAX_PATH];
1353 GetCurrentDirectory(MAX_PATH, sFullFilenameLC);
1354 cry_strcat(sFullFilenameLC, "\\");
1355 cry_strcat(sFullFilenameLC, PathUtil::GamePathToCryPakPath(file.GetString()));
1356 texNode->setAttr("File", sFullFilenameLC);
1361 else
1363 XmlNodeRef childsNode = node->findChild("SubMaterials");
1364 if (childsNode)
1366 int nSubMtls = childsNode->getChildCount();
1367 for (int i = 0; i < nSubMtls; i++)
1369 XmlNodeRef node = childsNode->getChild(i);
1370 XmlNodeRef texturesNode = node->findChild("Textures");
1371 if (texturesNode)
1373 for (int i = 0; i < texturesNode->getChildCount(); i++)
1375 XmlNodeRef texNode = texturesNode->getChild(i);
1376 string file;
1377 if (texNode->getAttr("File", file))
1380 if (file.size() >= 2 && file.c_str()[0] == '.' && (file.c_str()[1] == '/' || file.c_str()[1] == '\\'))
1382 // Texture file location is relative to material file folder
1383 file = PathUtil::Make(PathUtil::GetPathWithoutFilename(pMtl->GetFilename()), &file.c_str()[2]);
1386 char sFullFilenameLC[MAX_PATH];
1387 GetCurrentDirectory(MAX_PATH, sFullFilenameLC);
1388 cry_strcat(sFullFilenameLC, "\\");
1389 cry_strcat(sFullFilenameLC, PathUtil::GamePathToCryPakPath(file.GetString()));
1390 texNode->setAttr("File", sFullFilenameLC);
1391 //texNode->setAttr( "File", Path::GamePathToFullPath(file) );
1399 m_MatSender->SendMessage(eMSM_GetSelectedMaterial, data);
1402 //////////////////////////////////////////////////////////////////////////
1403 void CMaterialManager::SyncMaterialEditor()
1405 if (!m_MatSender)
1406 return;
1408 if (!m_MatSender->GetMessage())
1409 return;
1411 if (m_MatSender->m_h.msg == eMSM_Create)
1413 XmlNodeRef node = m_MatSender->m_node->findChild("Material");
1414 if (!node)
1415 return;
1417 string sMtlName;
1418 string sMaxFile;
1420 XmlNodeRef root = m_MatSender->m_node;
1421 root->getAttr("Name", sMtlName);
1422 root->getAttr("MaxFile", sMaxFile);
1424 int IsMulti = 0;
1425 root->getAttr("IsMulti", IsMulti);
1427 int nMtlFlags = 0;
1428 if (IsMulti)
1429 nMtlFlags |= MTL_FLAG_MULTI_SUBMTL;
1431 if (root->haveAttr("Flag_Wire"))
1432 nMtlFlags |= MTL_FLAG_WIRE;
1433 if (root->haveAttr("Flag_2Sided"))
1434 nMtlFlags |= MTL_FLAG_2SIDED;
1436 _smart_ptr<CMaterial> pMtl = SelectNewMaterial(nMtlFlags, PathUtil::GetPathWithoutFilename(sMaxFile));
1438 if (!pMtl)
1439 return;
1441 if (!IsMulti)
1443 node->delAttr("Shader"); // Remove shader attribute.
1444 XmlNodeRef texturesNode = node->findChild("Textures");
1445 if (texturesNode)
1447 for (int i = 0; i < texturesNode->getChildCount(); i++)
1449 XmlNodeRef texNode = texturesNode->getChild(i);
1450 string file;
1451 if (texNode->getAttr("File", file))
1453 //make path relative to the project specific game folder
1454 string newfile = PathUtil::AbsolutePathToGamePath(file.GetString()).c_str();
1455 if (newfile.GetLength() > 0)
1456 file = newfile;
1457 texNode->setAttr("File", file);
1462 else
1464 XmlNodeRef childsNode = node->findChild("SubMaterials");
1465 if (childsNode)
1467 int nSubMtls = childsNode->getChildCount();
1468 for (int i = 0; i < nSubMtls; i++)
1470 XmlNodeRef node = childsNode->getChild(i);
1471 node->delAttr("Shader"); // Remove shader attribute.
1472 XmlNodeRef texturesNode = node->findChild("Textures");
1473 if (texturesNode)
1475 for (int i = 0; i < texturesNode->getChildCount(); i++)
1477 XmlNodeRef texNode = texturesNode->getChild(i);
1478 string file;
1479 if (texNode->getAttr("File", file))
1481 //make path relative to the project specific game folder
1482 string newfile = PathUtil::AbsolutePathToGamePath(file.GetString()).c_str();
1483 if (newfile.GetLength() > 0)
1484 file = newfile;
1485 texNode->setAttr("File", file);
1493 CBaseLibraryItem::SerializeContext ctx(node, true);
1494 ctx.bUndo = true;
1495 pMtl->Serialize(ctx);
1497 pMtl->Update();
1499 SetCurrentMaterial(0);
1500 SetCurrentMaterial(pMtl);
1503 if (m_MatSender->m_h.msg == eMSM_GetSelectedMaterial)
1505 PickPreviewMaterial(m_MatSender->m_h.GetMaxHWND());
1509 //////////////////////////////////////////////////////////////////////////
1510 void CMaterialManager::InitMatSender()
1512 //MatSend(true);
1514 HWND mainWnd = (HWND)CEditorMainFrame::GetInstance()->winId();
1515 CRY_ASSERT(mainWnd);
1517 m_MatSender->Create();
1518 m_MatSender->SetupWindows(mainWnd, mainWnd);
1519 XmlNodeRef node = XmlHelpers::CreateXmlNode("Temp");
1520 m_MatSender->SendMessage(eMSM_Init, node);
1523 void CMaterialManager::OnDebugFlagsChanged()
1525 int debugFlags = gViewportDebugPreferences.GetDebugFlags();
1527 int mask = GetHighlightMask();
1528 if (debugFlags & DBG_HIGHLIGHT_BREAKABLE)
1529 mask |= eHighlight_Breakable;
1530 else
1531 mask &= ~eHighlight_Breakable;
1533 if (debugFlags & DBG_HIGHLIGHT_MISSING_SURFACE_TYPE)
1534 mask |= eHighlight_NoSurfaceType;
1535 else
1536 mask &= ~eHighlight_NoSurfaceType;
1538 SetHighlightMask(mask);
1541 //////////////////////////////////////////////////////////////////////////
1542 void CMaterialManager::GotoMaterial(CMaterial* pMaterial)
1544 if (pMaterial)
1545 GetIEditorImpl()->OpenDataBaseLibrary(EDB_TYPE_MATERIAL, pMaterial);
1548 //////////////////////////////////////////////////////////////////////////
1549 void CMaterialManager::GotoMaterial(IMaterial* pMtl)
1551 if (pMtl)
1553 CMaterial* pEdMaterial = FromIMaterial(pMtl);
1554 if (pEdMaterial)
1555 GetIEditorImpl()->OpenDataBaseLibrary(EDB_TYPE_MATERIAL, pEdMaterial);
1559 //////////////////////////////////////////////////////////////////////////
1560 void CMaterialManager::SetHighlightedMaterial(CMaterial* pMtl)
1562 if (m_pHighlightMaterial)
1563 RemoveFromHighlighting(m_pHighlightMaterial, eHighlight_Pick);
1565 m_pHighlightMaterial = pMtl;
1566 if (m_pHighlightMaterial)
1567 AddForHighlighting(m_pHighlightMaterial);
1570 //////////////////////////////////////////////////////////////////////////
1571 void CMaterialManager::HighlightedMaterialChanged(CMaterial* pMtl)
1573 if (!pMtl)
1574 return;
1576 RemoveFromHighlighting(pMtl, eHighlight_All);
1577 AddForHighlighting(pMtl);
1580 //////////////////////////////////////////////////////////////////////////
1581 void CMaterialManager::SetHighlightMask(int highlightMask)
1583 if (m_highlightMask != highlightMask)
1585 m_highlightMask = highlightMask;
1587 UpdateHighlightedMaterials();
1591 //////////////////////////////////////////////////////////////////////////
1592 void CMaterialManager::GatherResources(IMaterial* pMaterial, CUsedResources& resources)
1594 if (!pMaterial)
1595 return;
1597 int nSubMtlCount = pMaterial->GetSubMtlCount();
1598 if (nSubMtlCount > 0)
1600 for (int i = 0; i < nSubMtlCount; i++)
1602 GatherResources(pMaterial->GetSubMtl(i), resources);
1605 else
1607 SShaderItem& shItem = pMaterial->GetShaderItem();
1608 if (shItem.m_pShaderResources)
1610 SInputShaderResourcesPtr res = gEnv->pRenderer->EF_CreateInputShaderResource();
1611 shItem.m_pShaderResources->ConvertToInputResource(res);
1613 for (int i = 0; i < EFTT_MAX; i++)
1615 if (!res->m_Textures[i].m_Name.empty())
1617 resources.Add(res->m_Textures[i].m_Name.c_str());
1624 ///////////////////////////////////////////////////////////////////////////
1625 void CMaterialManager::GetHighlightColor(ColorF* color, float* intensity, int flags)
1627 MAKE_SURE(m_pHighlighter, return );
1628 m_pHighlighter->GetHighlightColor(color, intensity, flags);
1631 void CMaterialManager::CreateTerrainLayerFromMaterial(CMaterial* pMaterial)
1633 if (!pMaterial)
1634 return;
1636 CLayer* pLayer = 0;
1637 string sMaterialPath = pMaterial ? pMaterial->GetName() : "";
1638 bool bFound = false;
1639 CTerrainManager* terrainManager = GetIEditorImpl()->GetTerrainManager();
1641 for (int i = 0, n = terrainManager->GetLayerCount(); i < n; ++i)
1643 CLayer* pCurLayer = terrainManager->GetLayer(i);
1644 CSurfaceType* pSurfaceType = pCurLayer->GetSurfaceType();
1646 if (pSurfaceType && stricmp(pSurfaceType->GetMaterial(), sMaterialPath.c_str()) == 0)
1648 pLayer = pCurLayer;
1649 break;
1653 if (!pLayer)
1655 pLayer = new CLayer;
1656 pLayer->SetLayerName(PathUtil::GetFile(sMaterialPath.c_str()));
1657 pLayer->LoadTexture(string(PathUtil::GetGameFolder() + "/Textures/Terrain/Default.dds"));
1658 pLayer->GetOrRequestLayerId();
1659 terrainManager->AddLayer(pLayer);
1660 pLayer->AssignMaterial(sMaterialPath);
1661 terrainManager->ReloadSurfaceTypes(true, false);
1664 for (int i = 0, n = terrainManager->GetLayerCount(); i < n; ++i)
1665 terrainManager->GetLayer(i)->SetSelected(false);
1667 pLayer->SetSelected(true);
1668 GetIEditorImpl()->Notify(eNotify_OnInvalidateControls);