Răsfoiți Sursa

WIP work on ProjectWindow

Marko Pintera 10 ani în urmă
părinte
comite
929611c919

+ 26 - 0
BansheeEditor/Include/BsBuiltinEditorResources.h

@@ -7,6 +7,14 @@
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
+	/**
+	 * @brief	Types of valid icons used when viewing the project library
+	 */
+	enum class ProjectIcon
+	{
+		Folder, Mesh, Font, Texture
+	};
+
 	class BS_ED_EXPORT BuiltinEditorResources : public BansheeEngine::Module<BuiltinEditorResources>
 	class BS_ED_EXPORT BuiltinEditorResources : public BansheeEngine::Module<BuiltinEditorResources>
 	{
 	{
 	public:
 	public:
@@ -75,6 +83,12 @@ namespace BansheeEngine
 		 */
 		 */
 		HMaterial createSelectionMat() const;
 		HMaterial createSelectionMat() const;
 
 
+		/**
+		 * @brief	Retrieves an icon that represents a specific resource type
+		 *			that may be displayed when viewing the project library.
+		 */
+		HSpriteTexture getLibraryIcon(ProjectIcon icon) const;
+
 		static const String ObjectFieldStyleName;
 		static const String ObjectFieldStyleName;
 		static const String ObjectFieldLabelStyleName;
 		static const String ObjectFieldLabelStyleName;
 		static const String ObjectFieldDropBtnStyleName;
 		static const String ObjectFieldDropBtnStyleName;
@@ -82,6 +96,7 @@ namespace BansheeEngine
 
 
 		static const Path BuiltinDataFolder;
 		static const Path BuiltinDataFolder;
 		static const Path EditorSkinFolder;
 		static const Path EditorSkinFolder;
+		static const Path EditorIconFolder;
 		static const Path EditorShaderFolder;
 		static const Path EditorShaderFolder;
 		static const Path EditorShaderIncludeFolder;
 		static const Path EditorShaderIncludeFolder;
 
 
@@ -104,6 +119,11 @@ namespace BansheeEngine
 		 */
 		 */
 		static HSpriteTexture getGUITexture(const WString& name);
 		static HSpriteTexture getGUITexture(const WString& name);
 
 
+		/**
+		 * @brief	Loads a GUI icon with the specified filename.
+		 */
+		static HSpriteTexture getGUIIcon(const WString& name);
+
 		/**
 		/**
 		 * @brief	Loads a shader with the specified filename
 		 * @brief	Loads a shader with the specified filename
 		 */
 		 */
@@ -128,6 +148,7 @@ namespace BansheeEngine
 
 
 		static const Path ShaderFolder;
 		static const Path ShaderFolder;
 		static const Path SkinFolder;
 		static const Path SkinFolder;
+		static const Path IconFolder;
 		static const Path ShaderIncludeFolder;
 		static const Path ShaderIncludeFolder;
 
 
 		static const Path BuiltinRawDataFolder;
 		static const Path BuiltinRawDataFolder;
@@ -142,6 +163,11 @@ namespace BansheeEngine
 
 
 		static const WString GUISkinFile;
 		static const WString GUISkinFile;
 
 
+		static const WString FolderIconTex;
+		static const WString MeshIconTex;
+		static const WString TextureIconTex;
+		static const WString FontIconTex;
+
 		static const WString WindowBackgroundTexture;
 		static const WString WindowBackgroundTexture;
 
 
 		static const WString WindowFrameNormal;
 		static const WString WindowFrameNormal;

+ 45 - 0
BansheeEditor/Source/BsBuiltinEditorResources.cpp

@@ -56,6 +56,7 @@ namespace BansheeEngine
 
 
 	const Path BuiltinEditorResources::ShaderFolder = L"Shaders\\";
 	const Path BuiltinEditorResources::ShaderFolder = L"Shaders\\";
 	const Path BuiltinEditorResources::SkinFolder = L"Skin\\";
 	const Path BuiltinEditorResources::SkinFolder = L"Skin\\";
+	const Path BuiltinEditorResources::IconFolder = L"Skin\\Icons";
 	const Path BuiltinEditorResources::ShaderIncludeFolder = L"Includes\\";
 	const Path BuiltinEditorResources::ShaderIncludeFolder = L"Includes\\";
 
 
 	const Path BuiltinEditorResources::BuiltinRawDataFolder = L"..\\..\\..\\..\\Data\\Raw\\Editor\\";
 	const Path BuiltinEditorResources::BuiltinRawDataFolder = L"..\\..\\..\\..\\Data\\Raw\\Editor\\";
@@ -65,11 +66,17 @@ namespace BansheeEngine
 
 
 	const Path BuiltinEditorResources::BuiltinDataFolder = L"..\\..\\..\\..\\Data\\Editor\\";
 	const Path BuiltinEditorResources::BuiltinDataFolder = L"..\\..\\..\\..\\Data\\Editor\\";
 	const Path BuiltinEditorResources::EditorSkinFolder = BuiltinDataFolder + SkinFolder;
 	const Path BuiltinEditorResources::EditorSkinFolder = BuiltinDataFolder + SkinFolder;
+	const Path BuiltinEditorResources::EditorIconFolder = BuiltinDataFolder + IconFolder;
 	const Path BuiltinEditorResources::EditorShaderFolder = BuiltinDataFolder + ShaderFolder;
 	const Path BuiltinEditorResources::EditorShaderFolder = BuiltinDataFolder + ShaderFolder;
 	const Path BuiltinEditorResources::EditorShaderIncludeFolder = BuiltinDataFolder + ShaderIncludeFolder;
 	const Path BuiltinEditorResources::EditorShaderIncludeFolder = BuiltinDataFolder + ShaderIncludeFolder;
 
 
 	const Path BuiltinEditorResources::ResourceManifestPath = BuiltinDataFolder + "ResourceManifest.asset";
 	const Path BuiltinEditorResources::ResourceManifestPath = BuiltinDataFolder + "ResourceManifest.asset";
 
 
+	const WString BuiltinEditorResources::FolderIconTex = L"FolderIcon.psd";
+	const WString BuiltinEditorResources::MeshIconTex = L"MeshIcon.psd";
+	const WString BuiltinEditorResources::TextureIconTex = L"TextureIcon.psd";
+	const WString BuiltinEditorResources::FontIconTex = L"FontIcon.psd";
+
 	const WString BuiltinEditorResources::WindowBackgroundTexture = L"WindowBgTile.psd";
 	const WString BuiltinEditorResources::WindowBackgroundTexture = L"WindowBgTile.psd";
 
 
 	const WString BuiltinEditorResources::ButtonNormalTex = L"ButtonNormal.psd";
 	const WString BuiltinEditorResources::ButtonNormalTex = L"ButtonNormal.psd";
@@ -313,6 +320,18 @@ namespace BansheeEngine
 
 
 		skin->setStyle(GUILabel::getGUITypeName(), labelStyle);
 		skin->setStyle(GUILabel::getGUITypeName(), labelStyle);
 
 
+		// Multi-line label
+		GUIElementStyle multiLinelabelStyle;
+		multiLinelabelStyle.font = font;
+		multiLinelabelStyle.fontSize = DefaultFontSize;
+		multiLinelabelStyle.fixedWidth = false;
+		multiLinelabelStyle.fixedHeight = true;
+		multiLinelabelStyle.height = 11;
+		multiLinelabelStyle.minWidth = 10;
+		multiLinelabelStyle.wordWrap = true;
+
+		skin->setStyle("MultiLineLabel", multiLinelabelStyle);
+
 		// Window frame
 		// Window frame
 		GUIElementStyle windowFrameStyle;
 		GUIElementStyle windowFrameStyle;
 		windowFrameStyle.normal.texture = getGUITexture(WindowFrameNormal);
 		windowFrameStyle.normal.texture = getGUITexture(WindowFrameNormal);
@@ -1215,6 +1234,15 @@ namespace BansheeEngine
 		return Resources::instance().load<SpriteTexture>(texturePath);
 		return Resources::instance().load<SpriteTexture>(texturePath);
 	}
 	}
 
 
+	HSpriteTexture BuiltinEditorResources::getGUIIcon(const WString& name)
+	{
+		Path texturePath = FileSystem::getWorkingDirectoryPath();
+		texturePath.append(EditorIconFolder);
+		texturePath.append(L"sprite_" + name + L".asset");
+
+		return Resources::instance().load<SpriteTexture>(texturePath);
+	}
+
 	HShader BuiltinEditorResources::getShader(const WString& name)
 	HShader BuiltinEditorResources::getShader(const WString& name)
 	{
 	{
 		Path programPath = EditorShaderFolder;
 		Path programPath = EditorShaderFolder;
@@ -1286,4 +1314,21 @@ namespace BansheeEngine
 	{
 	{
 		return Material::create(mShaderSelection);
 		return Material::create(mShaderSelection);
 	}
 	}
+
+	HSpriteTexture BuiltinEditorResources::getLibraryIcon(ProjectIcon icon) const
+	{
+		switch (icon)
+		{
+		case ProjectIcon::Folder:
+			return getGUIIcon(FolderIconTex);
+		case ProjectIcon::Font:
+			return getGUIIcon(FontIconTex);
+		case ProjectIcon::Mesh:
+			return getGUIIcon(MeshIconTex);
+		case ProjectIcon::Texture:
+			return getGUIIcon(TextureIconTex);
+		}
+
+		return nullptr;
+	}
 }
 }

+ 1 - 0
MBansheeEditor/EditorStyles.cs

@@ -9,6 +9,7 @@ namespace BansheeEditor
     public static class EditorStyles
     public static class EditorStyles
     {
     {
         public const string Label = "Label";
         public const string Label = "Label";
+        public const string MultiLineLabel = "MultiLineLabel";
         public const string Button = "Button";
         public const string Button = "Button";
         public const string Toggle = "Toggle";
         public const string Toggle = "Toggle";
         public const string InputBox = "InputBox";
         public const string InputBox = "InputBox";

+ 1 - 0
MBansheeEditor/MBansheeEditor.csproj

@@ -96,6 +96,7 @@
     <Compile Include="MenuItem.cs" />
     <Compile Include="MenuItem.cs" />
     <Compile Include="ModalWindow.cs" />
     <Compile Include="ModalWindow.cs" />
     <Compile Include="ProgressBar.cs" />
     <Compile Include="ProgressBar.cs" />
+    <Compile Include="ProjectWindow.cs" />
     <Compile Include="Scene\SceneCamera.cs" />
     <Compile Include="Scene\SceneCamera.cs" />
     <Compile Include="Scene\SceneViewHandler.cs" />
     <Compile Include="Scene\SceneViewHandler.cs" />
     <Compile Include="Scene\SceneWindow.cs" />
     <Compile Include="Scene\SceneWindow.cs" />

+ 1 - 1
MBansheeEditor/ProjectLibrary.cs

@@ -144,7 +144,7 @@ namespace BansheeEditor
     // Note: Must be the same as C++ enum ScriptResourceType
     // Note: Must be the same as C++ enum ScriptResourceType
     public enum ResourceType
     public enum ResourceType
     {
     {
-        Texture, SpriteTexture, Mesh, Font, GpuProgram, PlainText, ScriptCode, Undefined
+        Texture, SpriteTexture, Mesh, Font, Shader, Material, PlainText, ScriptCode, Undefined
     }
     }
 
 
     public class LibraryEntry : ScriptObject
     public class LibraryEntry : ScriptObject

+ 213 - 0
MBansheeEditor/ProjectWindow.cs

@@ -0,0 +1,213 @@
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    internal sealed class ProjectWindow : EditorWindow
+    {
+        private enum ViewType
+        {
+            Grid64, Grid48, Grid32, List16
+        }
+
+        private const int GRID_ENTRY_SPACING = 15;
+        private const int LIST_ENTRY_SPACING = 7;
+        private const int MAX_LABEL_HEIGHT = 50;
+
+        private bool hasContentFocus = false;
+        private bool HasContentFocus { get { return HasFocus && hasContentFocus; } }
+
+        private ViewType viewType = ViewType.Grid32;
+
+        private string currentDirectory;
+        private string currentSelection;
+        private string currentPing;
+
+        private GUIScrollArea contentScrollArea;
+        private GUILayout contentLayout;
+
+        [MenuItem("Windows/Project", ButtonModifier.Ctrl, ButtonCode.P)]
+        private static void OpenProjectWindow()
+        {
+            OpenWindow<ProjectWindow>();
+        }
+
+        private void OnInitialize()
+        {
+            ProjectLibrary.OnEntryAdded += OnEntryChanged;
+            ProjectLibrary.OnEntryRemoved += OnEntryChanged;
+
+            contentScrollArea = new GUIScrollArea(GUIOption.FlexibleWidth(), GUIOption.FlexibleHeight());
+            GUI.layout.AddElement(contentScrollArea);
+
+            Reset();
+        }
+
+        public void Ping(Resource resource)
+        {
+            currentPing = ProjectLibrary.GetPath(resource);
+
+            Refresh();
+        }
+
+        private void Select(Resource resource)
+        {
+            currentSelection = ProjectLibrary.GetPath(resource);
+            currentPing = "";
+
+            Refresh();
+        }
+
+        private void EnterDirectory(string directory)
+        {
+            currentDirectory = directory;
+            currentPing = "";
+            currentSelection = "";
+
+            Refresh();
+        }
+
+        private void SetView(ViewType type)
+        {
+            viewType = type;
+            Refresh();
+        }
+
+        private void EditorUpdate()
+        {
+            // TODO - Handle input, drag and drop and whatever else might be needed
+        }
+
+        private void OnEntryChanged(string entry)
+        {
+            Refresh();
+        }
+
+        private SpriteTexture GetIcon(LibraryEntry entry)
+        {
+            if (entry.Type == LibraryEntryType.Directory)
+            {
+                return EditorBuiltin.FolderIcon;
+            }
+            else
+            {
+                FileEntry fileEntry = (FileEntry)entry;
+                switch (fileEntry.ResType)
+                {
+                    case ResourceType.Font:
+                        return EditorBuiltin.FontIcon;
+                    case ResourceType.Mesh:
+                        return EditorBuiltin.MeshIcon;
+                    case ResourceType.Texture:
+                        return EditorBuiltin.TextureIcon;
+                    case ResourceType.PlainText:
+                        return null; // TODO
+                    case ResourceType.ScriptCode:
+                        return null; // TODO
+                    case ResourceType.SpriteTexture:
+                        return null; // TODO
+                    case ResourceType.Shader:
+                        return null; // TODO
+                    case ResourceType.Material:
+                        return null; // TODO
+                }
+            }
+
+            return null;
+        }
+
+        private void Refresh()
+        {
+            DirectoryEntry entry = ProjectLibrary.GetEntry(currentDirectory) as DirectoryEntry;
+            if (entry == null)
+            {
+                Reset();
+                return;
+            }
+
+            if (contentLayout != null)
+                contentLayout.Destroy();
+
+            contentLayout = contentScrollArea.layout.AddLayoutY();
+
+            Rect2I contentBounds = contentScrollArea.Bounds;
+            LibraryEntry[] childEntries = entry.Children;
+
+            if (childEntries.Length == 0)
+                return;
+
+            if (viewType == ViewType.List16)
+            {
+                int tileSize = 16;
+
+                for (int i = 0; i < childEntries.Length; i++)
+                {
+                    // TODO
+                }
+            }
+            else
+            {
+                int tileSize = 64;
+                switch (viewType)
+                {
+                    case ViewType.Grid64: tileSize = 64; break;
+                    case ViewType.Grid48: tileSize = 48; break;
+                    case ViewType.Grid32: tileSize = 32; break;
+                }
+
+                GUILayoutX rowLayout = contentLayout.AddLayoutX();
+                contentLayout.AddFlexibleSpace();
+
+                rowLayout.AddFlexibleSpace();
+                int currentWidth = GRID_ENTRY_SPACING * 2;
+                bool addedAny = false;
+
+                for (int i = 0; i < childEntries.Length; i++)
+                {
+                    if (currentWidth >= contentBounds.width && addedAny) // We force at least one entry per row, even if it doesn't fit
+                    {
+                        rowLayout = contentLayout.AddLayoutX();
+                        contentLayout.AddFlexibleSpace();
+
+                        rowLayout.AddFlexibleSpace();
+
+                        currentWidth = GRID_ENTRY_SPACING * 2;
+                    }
+
+                    LibraryEntry currentEntry = childEntries[i];
+
+                    GUILayoutY entryLayout = rowLayout.AddLayoutY();
+                    rowLayout.AddFlexibleSpace();
+
+                    SpriteTexture iconTexture = GetIcon(currentEntry);
+
+                    GUITexture icon = new GUITexture(iconTexture, GUIImageScaleMode.ScaleToFit, 
+                        true, GUIOption.FixedHeight(tileSize), GUIOption.FixedWidth(tileSize));
+
+                    GUILabel label = new GUILabel(currentEntry.Name, EditorStyles.MultiLineLabel, 
+                        GUIOption.FixedWidth(tileSize), GUIOption.FlexibleHeight(0, MAX_LABEL_HEIGHT));
+
+                    entryLayout.AddElement(icon);
+                    entryLayout.AddElement(label);
+
+                    addedAny = true;
+                    currentWidth += tileSize + GRID_ENTRY_SPACING;
+                }
+            }
+
+            // TODO - Handle ping/selection and whatever else
+        }
+
+        private void Reset()
+        {
+            currentDirectory = ProjectLibrary.Root.Path;
+            Refresh();
+        }
+
+        protected override void WindowResized(int width, int height)
+        {
+            base.WindowResized(width, height);
+
+            Refresh();
+        }
+    }
+}

+ 5 - 0
MBansheeEngine/GUI/GUILabel.cs

@@ -15,6 +15,11 @@ namespace BansheeEngine
             Internal_CreateInstance(this, content, style, new GUIOption[0]);
             Internal_CreateInstance(this, content, style, new GUIOption[0]);
         }
         }
 
 
+        public GUILabel(GUIContent content, params GUIOption[] options)
+        {
+            Internal_CreateInstance(this, content, "", options);
+        }
+
         public void SetContent(GUIContent content)
         public void SetContent(GUIContent content)
         {
         {
             Internal_SetContent(mCachedPtr, content);
             Internal_SetContent(mCachedPtr, content);

+ 2 - 2
MBansheeEngine/GUI/GUIOption.cs

@@ -34,7 +34,7 @@ namespace BansheeEngine
             return option;
             return option;
         }
         }
 
 
-        public static GUIOption FlexibleWidth(int minWidth, int maxWidth)
+        public static GUIOption FlexibleWidth(int minWidth = 0, int maxWidth = 0)
         {
         {
             GUIOption option = new GUIOption();
             GUIOption option = new GUIOption();
             option.min = minWidth;
             option.min = minWidth;
@@ -44,7 +44,7 @@ namespace BansheeEngine
             return option;
             return option;
         }
         }
 
 
-        public static GUIOption FlexibleHeight(int minHeight, int maxHeight)
+        public static GUIOption FlexibleHeight(int minHeight = 0, int maxHeight = 0)
         {
         {
             GUIOption option = new GUIOption();
             GUIOption option = new GUIOption();
             option.min = minHeight;
             option.min = minHeight;

+ 4 - 4
SBansheeEditor/Source/BsScriptEditorBuiltin.cpp

@@ -23,28 +23,28 @@ namespace BansheeEngine
 
 
 	MonoObject* ScriptEditorBuiltin::internal_getFolderIcon()
 	MonoObject* ScriptEditorBuiltin::internal_getFolderIcon()
 	{
 	{
-		HSpriteTexture tex = HSpriteTexture(); // TODO - Get actual texture
+		HSpriteTexture tex = BuiltinEditorResources::instance().getLibraryIcon(ProjectIcon::Folder);
 
 
 		return ScriptSpriteTexture::toManaged(tex);
 		return ScriptSpriteTexture::toManaged(tex);
 	}
 	}
 
 
 	MonoObject* ScriptEditorBuiltin::internal_getMeshIcon()
 	MonoObject* ScriptEditorBuiltin::internal_getMeshIcon()
 	{
 	{
-		HSpriteTexture tex = HSpriteTexture(); // TODO - Get actual texture
+		HSpriteTexture tex = BuiltinEditorResources::instance().getLibraryIcon(ProjectIcon::Mesh);
 
 
 		return ScriptSpriteTexture::toManaged(tex);
 		return ScriptSpriteTexture::toManaged(tex);
 	}
 	}
 
 
 	MonoObject* ScriptEditorBuiltin::internal_getFontIcon()
 	MonoObject* ScriptEditorBuiltin::internal_getFontIcon()
 	{
 	{
-		HSpriteTexture tex = HSpriteTexture(); // TODO - Get actual texture
+		HSpriteTexture tex = BuiltinEditorResources::instance().getLibraryIcon(ProjectIcon::Font);
 
 
 		return ScriptSpriteTexture::toManaged(tex);
 		return ScriptSpriteTexture::toManaged(tex);
 	}
 	}
 
 
 	MonoObject* ScriptEditorBuiltin::internal_getTextureIcon()
 	MonoObject* ScriptEditorBuiltin::internal_getTextureIcon()
 	{
 	{
-		HSpriteTexture tex = HSpriteTexture(); // TODO - Get actual texture
+		HSpriteTexture tex = BuiltinEditorResources::instance().getLibraryIcon(ProjectIcon::Texture);
 
 
 		return ScriptSpriteTexture::toManaged(tex);
 		return ScriptSpriteTexture::toManaged(tex);
 	}
 	}

+ 1 - 1
SBansheeEngine/Include/BsScriptResource.h

@@ -7,7 +7,7 @@ namespace BansheeEngine
 {
 {
 	enum class ScriptResourceType
 	enum class ScriptResourceType
 	{
 	{
-		Texture, SpriteTexture, Mesh, Font, GpuProgram, PlainText, ScriptCode, Undefined
+		Texture, SpriteTexture, Mesh, Font, Shader, Material, PlainText, ScriptCode, Undefined
 	};
 	};
 
 
 	class BS_SCR_BE_EXPORT ScriptResourceBase : public PersistentScriptObjectBase
 	class BS_SCR_BE_EXPORT ScriptResourceBase : public PersistentScriptObjectBase

+ 8 - 4
SBansheeEngine/Source/BsScriptResource.cpp

@@ -30,8 +30,10 @@ namespace BansheeEngine
 			return ScriptResourceType::SpriteTexture;
 			return ScriptResourceType::SpriteTexture;
 		case TID_Mesh:
 		case TID_Mesh:
 			return ScriptResourceType::Mesh;
 			return ScriptResourceType::Mesh;
-		case TID_GpuProgram:
-			return ScriptResourceType::GpuProgram;
+		case TID_Shader:
+			return ScriptResourceType::Shader;
+		case TID_Material:
+			return ScriptResourceType::Material;
 		case TID_Font:
 		case TID_Font:
 			return ScriptResourceType::Font;
 			return ScriptResourceType::Font;
 		case TID_PlainText:
 		case TID_PlainText:
@@ -53,10 +55,12 @@ namespace BansheeEngine
 			return TID_SpriteTexture;
 			return TID_SpriteTexture;
 		case ScriptResourceType::Mesh:
 		case ScriptResourceType::Mesh:
 			return TID_Mesh;
 			return TID_Mesh;
-		case ScriptResourceType::GpuProgram:
-			return TID_GpuProgram;
+		case ScriptResourceType::Shader:
+			return TID_Shader;
 		case ScriptResourceType::Font:
 		case ScriptResourceType::Font:
 			return TID_Font;
 			return TID_Font;
+		case ScriptResourceType::Material:
+			return TID_Material;
 		case ScriptResourceType::PlainText:
 		case ScriptResourceType::PlainText:
 			return TID_PlainText;
 			return TID_PlainText;
 		case ScriptResourceType::ScriptCode:
 		case ScriptResourceType::ScriptCode:

+ 10 - 0
TODO.txt

@@ -14,6 +14,16 @@ Almost all of PRojectLibrary functionality is completely untested
 My GUID generation is screwed up. If multiple GUIDs are generated in succession then the timestamp will remain
 My GUID generation is screwed up. If multiple GUIDs are generated in succession then the timestamp will remain
 the same and the only variable will be the 4byte random number, which can sometimes end up identical to the previous number.
 the same and the only variable will be the 4byte random number, which can sometimes end up identical to the previous number.
 
 
+----------------------------------------------------------------------
+Project window
+
+When working with scroll areas I cannot create multiple child areas of different depths. Can I rely on just the order I add the elements in the layout?
+ - Or can I just have a child GUIArea inside a scroll area?
+
+Simple tasks:
+ - Add GUI button as overlay. Hook up its input event to select (click) + enter directory (double click) + context (right click, for later)
+ - Add element highlights: ping (blue bg), selection (orange bg), cut (fade out icon/label)
+
 ----------------------------------------------------------------------
 ----------------------------------------------------------------------
 Resources
 Resources
  - Load/Unload/UnloadUnused
  - Load/Unload/UnloadUnused