Просмотр исходного кода

Managed code now uses the new multi-resource format

BearishSun 10 лет назад
Родитель
Сommit
7a78a6d441

+ 6 - 0
BansheeEditor/Include/BsProjectLibrary.h

@@ -94,6 +94,12 @@ namespace BansheeEngine
 		 */
 		LibraryEntry* findEntry(const Path& path) const;
 
+		/** 
+		 * Checks whether the provided path points to a sub-resource. Sub-resource is any resource that is not the primary
+		 * resource in the file.
+		 */
+		bool isSubresource(const Path& path) const;
+
 		/**
 		 * Attempts to a find a meta information for a resource at the specified path.
 		 *

+ 2 - 2
BansheeEditor/Include/BsProjectResourceMeta.h

@@ -8,7 +8,7 @@
 namespace BansheeEngine
 {
 	/**	Contains meta-data for a resource stored in the ProjectLibrary. */
-	class ProjectResourceMeta : public IReflectable
+	class BS_ED_EXPORT ProjectResourceMeta : public IReflectable
 	{
 	private:
 		struct ConstructPrivately {};
@@ -68,7 +68,7 @@ namespace BansheeEngine
 	 * Contains meta-data for a file stored in the ProjectLibrary. A single file meta-data can contain one or multiple
 	 * ProjectResourceMeta instances.
 	 */
-	class ProjectFileMeta : public IReflectable
+	class BS_ED_EXPORT ProjectFileMeta : public IReflectable
 	{
 	private:
 		struct ConstructPrivately {};

+ 17 - 0
BansheeEditor/Source/BsProjectLibrary.cpp

@@ -689,6 +689,23 @@ namespace BansheeEngine
 		return nullptr;
 	}
 
+	bool ProjectLibrary::isSubresource(const Path& path) const
+	{
+		UINT32 numElems = path.getNumDirectories() + (path.isFile() ? 1 : 0);
+
+		if (numElems <= 1)
+			return false;
+
+		Path filePath = path;
+		filePath.makeParent();
+
+		LibraryEntry* entry = findEntry(filePath);
+		if (entry != nullptr && entry->type == LibraryEntryType::File)
+			return true;
+
+		return false;
+	}
+
 	ProjectResourceMetaPtr ProjectLibrary::findResourceMeta(const Path& path) const
 	{
 		UINT32 numElems = path.getNumDirectories() + (path.isFile() ? 1 : 0);

+ 1 - 1
BansheeEditor/Source/BsProjectResourceMeta.cpp

@@ -65,7 +65,7 @@ namespace BansheeEngine
 	void ProjectFileMeta::remove(const String& UUID)
 	{
 		auto iterFind = std::find_if(mResourceMetaData.begin(), mResourceMetaData.end(),
-			[&](auto& x) { return x.mUUID == UUID; });
+			[&](auto& x) { return x->getUUID() == UUID; });
 
 		if (iterFind != mResourceMetaData.end())
 			mResourceMetaData.erase(iterFind);

+ 24 - 25
MBansheeEditor/GUI/GUISceneTreeView.cs

@@ -103,39 +103,38 @@ namespace BansheeEditor
             List<SceneObject> addedObjects = new List<SceneObject>(); 
             for (int i = 0; i < resourcePaths.Length; i++)
             {
-                LibraryEntry entry = ProjectLibrary.GetEntry(resourcePaths[i]);
-                if (entry != null && entry.Type == LibraryEntryType.File)
+                ResourceMeta meta = ProjectLibrary.GetMeta(resourcePaths[i]);
+                if (meta == null)
+                    continue;
+
+                if (meta.ResType == ResourceType.Mesh)
                 {
-                    FileEntry fileEntry = (FileEntry)entry;
-                    if (fileEntry.ResType == ResourceType.Mesh)
+                    if (!string.IsNullOrEmpty(resourcePaths[i]))
                     {
-                        if (!string.IsNullOrEmpty(resourcePaths[i]))
-                        {
-                            string meshName = Path.GetFileNameWithoutExtension(resourcePaths[i]);
+                        string meshName = Path.GetFileNameWithoutExtension(resourcePaths[i]);
 
-                            Mesh mesh = ProjectLibrary.Load<Mesh>(resourcePaths[i]);
-                            if (mesh == null)
-                                continue;
+                        Mesh mesh = ProjectLibrary.Load<Mesh>(resourcePaths[i]);
+                        if (mesh == null)
+                            continue;
 
-                            SceneObject so = UndoRedo.CreateSO(meshName, "Created a new Renderable \"" + meshName + "\"");
-                            so.Parent = parent;
+                        SceneObject so = UndoRedo.CreateSO(meshName, "Created a new Renderable \"" + meshName + "\"");
+                        so.Parent = parent;
 
-                            Renderable renderable = so.AddComponent<Renderable>();
-                            renderable.Mesh = mesh;
+                        Renderable renderable = so.AddComponent<Renderable>();
+                        renderable.Mesh = mesh;
 
-                            addedObjects.Add(so);
-                        }
+                        addedObjects.Add(so);
                     }
-                    else if (fileEntry.ResType == ResourceType.Prefab)
+                }
+                else if (meta.ResType == ResourceType.Prefab)
+                {
+                    if (!string.IsNullOrEmpty(resourcePaths[i]))
                     {
-                        if (!string.IsNullOrEmpty(resourcePaths[i]))
-                        {
-                            Prefab prefab = ProjectLibrary.Load<Prefab>(resourcePaths[i]);
-                            SceneObject so = UndoRedo.Instantiate(prefab, "Instantiating " + prefab.Name);
-                            so.Parent = parent;
-
-                            addedObjects.Add(so);
-                        }
+                        Prefab prefab = ProjectLibrary.Load<Prefab>(resourcePaths[i]);
+                        SceneObject so = UndoRedo.Instantiate(prefab, "Instantiating " + prefab.Name);
+                        so.Parent = parent;
+
+                        addedObjects.Add(so);
                     }
                 }
             }

+ 3 - 4
MBansheeEditor/Inspector/InspectorWindow.cs

@@ -528,11 +528,10 @@ namespace BansheeEditor
                         {
                             foreach (var resPath in dragData.Paths)
                             {
-                                LibraryEntry entry = ProjectLibrary.GetEntry(resPath);
-                                FileEntry fileEntry = entry as FileEntry;
-                                if (fileEntry != null)
+                                ResourceMeta meta = ProjectLibrary.GetMeta(resPath);
+                                if (meta != null)
                                 {
-                                    if (fileEntry.ResType == ResourceType.ScriptCode)
+                                    if (meta.ResType == ResourceType.ScriptCode)
                                     {
                                         ScriptCode scriptFile = ProjectLibrary.Load<ScriptCode>(resPath);
 

+ 32 - 11
MBansheeEditor/Library/LibraryGUIContent.cs

@@ -2,6 +2,7 @@
 //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
 using System;
 using System.Collections.Generic;
+using System.IO;
 using BansheeEngine;
 
 namespace BansheeEditor
@@ -30,7 +31,7 @@ namespace BansheeEditor
         private int elementsPerRow;
         private int labelWidth;
 
-        private LibraryGUIEntry[] entries = new LibraryGUIEntry[0];
+        private List<LibraryGUIEntry> entries = new List<LibraryGUIEntry>();
         private Dictionary<string, LibraryGUIEntry> entryLookup = new Dictionary<string, LibraryGUIEntry>();
 
         /// <summary>
@@ -68,7 +69,7 @@ namespace BansheeEditor
         /// <summary>
         /// Returns objects representing each of the displayed resource icons.
         /// </summary>
-        public LibraryGUIEntry[] Entries
+        public List<LibraryGUIEntry> Entries
         {
             get { return entries; }
         }
@@ -127,7 +128,7 @@ namespace BansheeEditor
             if (mainPanel != null)
                 mainPanel.Destroy();
 
-            entries = new LibraryGUIEntry[entriesToDisplay.Length];
+            entries.Clear();
             entryLookup.Clear();
 
             mainPanel = parent.Layout.AddPanel();
@@ -139,6 +140,26 @@ namespace BansheeEditor
 
             main = contentPanel.AddLayoutY();
 
+            List<string> resourcesToDisplay = new List<string>();
+            foreach (var entry in entriesToDisplay)
+            {
+                if (entry.Type == LibraryEntryType.Directory)
+                    resourcesToDisplay.Add(entry.Path);
+                else
+                {
+                    FileEntry fileEntry = (FileEntry)entry;
+                    ResourceMeta[] metas = fileEntry.ResourceMetas;
+
+                    if (metas.Length > 0)
+                    {
+                        resourcesToDisplay.Add(entry.Path);
+
+                        for (int i = 1; i < metas.Length; i++)
+                            resourcesToDisplay.Add(Path.Combine(entry.Path, metas[i].SubresourceName));
+                    }
+                }
+            }
+
             if (viewType == ProjectViewType.List16)
             {
                 tileSize = 16;
@@ -169,7 +190,7 @@ namespace BansheeEditor
                 elementsPerRow = (availableWidth - GRID_ENTRY_SPACING * 2) / elemSize;
                 elementsPerRow = Math.Max(elementsPerRow, 1);
 
-                int numRows = MathEx.CeilToInt(entriesToDisplay.Length / (float)elementsPerRow);
+                int numRows = MathEx.CeilToInt(resourcesToDisplay.Count / (float)elementsPerRow);
                 int neededHeight = numRows * (elemSize);
 
                 bool requiresScrollbar = neededHeight > scrollBounds.height;
@@ -187,13 +208,13 @@ namespace BansheeEditor
 
             if (viewType == ProjectViewType.List16)
             {
-                for (int i = 0; i < entriesToDisplay.Length; i++)
+                for (int i = 0; i < resourcesToDisplay.Count; i++)
                 {
-                    LibraryGUIEntry guiEntry = new LibraryGUIEntry(this, main, entriesToDisplay[i], i, labelWidth);
+                    LibraryGUIEntry guiEntry = new LibraryGUIEntry(this, main, resourcesToDisplay[i], i, labelWidth);
                     entries[i] = guiEntry;
                     entryLookup[guiEntry.path] = guiEntry;
 
-                    if (i != entriesToDisplay.Length - 1)
+                    if (i != resourcesToDisplay.Count - 1)
                         main.AddSpace(LIST_ENTRY_SPACING);
                 }
 
@@ -208,7 +229,7 @@ namespace BansheeEditor
 
                 int elemsInRow = 0;
 
-                for (int i = 0; i < entriesToDisplay.Length; i++)
+                for (int i = 0; i < resourcesToDisplay.Count; i++)
                 {
                     if (elemsInRow == elementsPerRow && elemsInRow > 0)
                     {
@@ -219,7 +240,7 @@ namespace BansheeEditor
                         elemsInRow = 0;
                     }
 
-                    LibraryGUIEntry guiEntry = new LibraryGUIEntry(this, rowLayout, entriesToDisplay[i], i, labelWidth);
+                    LibraryGUIEntry guiEntry = new LibraryGUIEntry(this, rowLayout, resourcesToDisplay[i], i, labelWidth);
                     entries[i] = guiEntry;
                     entryLookup[guiEntry.path] = guiEntry;
 
@@ -238,7 +259,7 @@ namespace BansheeEditor
                 main.AddFlexibleSpace();
             }
 
-            for (int i = 0; i < entries.Length; i++)
+            for (int i = 0; i < entries.Count; i++)
             {
                 LibraryGUIEntry guiEntry = entries[i];
                 guiEntry.Initialize();
@@ -250,7 +271,7 @@ namespace BansheeEditor
         /// </summary>
         public void Update()
         {
-            for (int i = 0; i < entries.Length; i++)
+            for (int i = 0; i < entries.Count; i++)
                 entries[i].Update();
         }
 

+ 18 - 14
MBansheeEditor/Library/LibraryGUIEntry.cs

@@ -59,10 +59,10 @@ namespace BansheeEditor
         /// </summary>
         /// <param name="owner">Content area this entry is part of.</param>
         /// <param name="parent">Parent layout to add this entry's GUI elements to.</param>
-        /// <param name="entry">Project library entry this entry displays data for.</param>
+        /// <param name="path">Path to the project library entry to display data for.</param>
         /// <param name="index">Sequential index of the entry in the conent area.</param>
         /// <param name="labelWidth">Width of the GUI labels that display the elements.</param>
-        public LibraryGUIEntry(LibraryGUIContent owner, GUILayout parent, LibraryEntry entry, int index, int labelWidth)
+        public LibraryGUIEntry(LibraryGUIContent owner, GUILayout parent, string path, int index, int labelWidth)
         {
             GUILayout entryLayout;
 
@@ -71,21 +71,22 @@ namespace BansheeEditor
             else
                 entryLayout = parent.AddLayoutX();
 
-            SpriteTexture iconTexture = GetIcon(entry, owner.TileSize);
+            SpriteTexture iconTexture = GetIcon(path, owner.TileSize);
 
             icon = new GUITexture(iconTexture, GUIImageScaleMode.ScaleToFit,
                 true, GUIOption.FixedHeight(owner.TileSize), GUIOption.FixedWidth(owner.TileSize));
 
             label = null;
 
+            string name = PathEx.GetTail(path);
             if (owner.GridLayout)
             {
-                label = new GUILabel(entry.Name, EditorStyles.MultiLineLabelCentered,
+                label = new GUILabel(name, EditorStyles.MultiLineLabelCentered,
                     GUIOption.FixedWidth(labelWidth), GUIOption.FlexibleHeight(0, MAX_LABEL_HEIGHT));
             }
             else
             {
-                label = new GUILabel(entry.Name);
+                label = new GUILabel(name);
             }
 
             entryLayout.AddElement(icon);
@@ -93,7 +94,7 @@ namespace BansheeEditor
 
             this.owner = owner;
             this.index = index;
-            this.path = entry.Path;
+            this.path = path;
             this.bounds = new Rect2I();
             this.underlay = null;
         }
@@ -339,12 +340,14 @@ namespace BansheeEditor
                     owner.Window.EnterDirectory(path);
                 else
                 {
-                    FileEntry resEntry = (FileEntry)entry;
-                    if (resEntry.ResType == ResourceType.Prefab)
+                    ResourceMeta meta = ProjectLibrary.GetMeta(path);
+
+                    FileEntry fileEntry = (FileEntry)entry;
+                    if (meta.ResType == ResourceType.Prefab)
                     {
-                        EditorApplication.LoadScene(resEntry.Path);
+                        EditorApplication.LoadScene(fileEntry.Path);
                     }
-                    else if (resEntry.ResType == ResourceType.ScriptCode)
+                    else if (meta.ResType == ResourceType.ScriptCode)
                     {
                         ProgressBar.Show("Opening external code editor...", 1.0f);
 
@@ -357,19 +360,20 @@ namespace BansheeEditor
         /// <summary>
         /// Returns an icon that can be used for displaying a resource of the specified type.
         /// </summary>
-        /// <param name="entry">Project library entry of the resource to retrieve icon for.</param>
+        /// <param name="path">Path to the project library entry to display data for.</param>
         /// <param name="size">Size of the icon to retrieve, in pixels.</param>
         /// <returns>Icon to display for the specified entry.</returns>
-        private static SpriteTexture GetIcon(LibraryEntry entry, int size)
+        private static SpriteTexture GetIcon(string path, int size)
         {
+            LibraryEntry entry = ProjectLibrary.GetEntry(path);
             if (entry.Type == LibraryEntryType.Directory)
             {
                 return EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.Folder, size);
             }
             else
             {
-                FileEntry fileEntry = (FileEntry)entry;
-                switch (fileEntry.ResType)
+                ResourceMeta meta = ProjectLibrary.GetMeta(path);
+                switch (meta.ResType)
                 {
                     case ResourceType.Font:
                         return EditorBuiltin.GetLibraryItemIcon(LibraryItemIcon.Font, size);

+ 60 - 20
MBansheeEditor/Library/LibraryWindow.cs

@@ -453,7 +453,7 @@ namespace BansheeEditor
 
             if (shiftDown)
             {
-                if (selectionAnchorStart != -1 && selectionAnchorStart < content.Entries.Length)
+                if (selectionAnchorStart != -1 && selectionAnchorStart < content.Entries.Count)
                 {
                     int start = Math.Min(entry.index, selectionAnchorStart);
                     int end = Math.Max(entry.index, selectionAnchorStart);
@@ -533,13 +533,13 @@ namespace BansheeEditor
             if (selectionPaths.Count == 0 || selectionAnchorEnd == -1)
             {
                 // Nothing is selected so we arbitrarily select first or last element
-                if (content.Entries.Length > 0)
+                if (content.Entries.Count > 0)
                 {
                     switch (dir)
                     {
                         case MoveDirection.Left:
                         case MoveDirection.Up:
-                            newPath = content.Entries[content.Entries.Length - 1].path;
+                            newPath = content.Entries[content.Entries.Count - 1].path;
                             break;
                         case MoveDirection.Right:
                         case MoveDirection.Down:
@@ -561,11 +561,11 @@ namespace BansheeEditor
                             newPath = content.Entries[selectionAnchorEnd - content.ElementsPerRow].path;
                         break;
                     case MoveDirection.Right:
-                        if (selectionAnchorEnd + 1 < content.Entries.Length)
+                        if (selectionAnchorEnd + 1 < content.Entries.Count)
                             newPath = content.Entries[selectionAnchorEnd + 1].path;
                         break;
                     case MoveDirection.Down:
-                        if (selectionAnchorEnd + content.ElementsPerRow < content.Entries.Length)
+                        if (selectionAnchorEnd + content.ElementsPerRow < content.Entries.Count)
                             newPath = content.Entries[selectionAnchorEnd + content.ElementsPerRow].path;
                         break;
                 }
@@ -635,8 +635,10 @@ namespace BansheeEditor
             foreach (var path in cutPaths)
                 content.MarkAsCut(path, false);
 
+            string[] filePaths = GetFiles(sourcePaths);
+
             cutPaths.Clear();
-            cutPaths.AddRange(sourcePaths);
+            cutPaths.AddRange(filePaths);
 
             foreach (var path in cutPaths)
                 content.MarkAsCut(path, true);
@@ -651,7 +653,9 @@ namespace BansheeEditor
         internal void Copy(IEnumerable<string> sourcePaths)
         {
             copyPaths.Clear();
-            copyPaths.AddRange(sourcePaths);
+
+            string[] filePaths = GetFiles(sourcePaths);
+            copyPaths.AddRange(filePaths);
 
             foreach (var path in cutPaths)
                 content.MarkAsCut(path, false);
@@ -665,7 +669,8 @@ namespace BansheeEditor
         /// <param name="sourcePaths">Project library paths of the elements to duplicate.</param>
         internal void Duplicate(IEnumerable<string> sourcePaths)
         {
-            foreach (var source in sourcePaths)
+            string[] filePaths = GetFiles(sourcePaths);
+            foreach (var source in filePaths)
             {
                 if (Directory.Exists(source))
                     DirectoryEx.Copy(source, LibraryUtility.GetUniquePath(source));
@@ -1066,17 +1071,19 @@ namespace BansheeEditor
         /// </summary>
         internal void RenameSelection()
         {
-            if (selectionPaths.Count == 0)
+            string[] filePaths = GetFiles(selectionPaths);
+
+            if (filePaths.Length == 0)
                 return;
 
-            if (selectionPaths.Count > 1)
+            if (filePaths.Length > 1)
             {
                 DeselectAll();
-                Select(selectionPaths[0]);
+                Select(filePaths[0]);
             }
 
             LibraryGUIEntry entry;
-            if (content.TryGetEntry(selectionPaths[0], out entry))
+            if (content.TryGetEntry(filePaths[0], out entry))
             {
                 entry.StartRename();
                 inProgressRenameElement = entry;
@@ -1088,7 +1095,9 @@ namespace BansheeEditor
         /// </summary>
         internal void DeleteSelection()
         {
-            if (selectionPaths.Count == 0)
+            string[] filePaths = GetFiles(selectionPaths);
+
+            if (filePaths.Length == 0)
                 return;
 
             DialogBox.Open(new LocEdString("Confirm deletion"), new LocEdString("Are you sure you want to delete the selected object(s)?"),
@@ -1097,10 +1106,8 @@ namespace BansheeEditor
                 {
                     if (type == DialogBox.ResultType.Yes)
                     {
-                        foreach (var path in selectionPaths)
-                        {
+                        foreach (var path in filePaths)
                             ProjectLibrary.Delete(path);
-                        }
 
                         DeselectAll();
                         Refresh();
@@ -1130,6 +1137,40 @@ namespace BansheeEditor
             Refresh();
         }
 
+        /// <summary>
+        /// Takes a list of resource paths and returns only those referencing files or folder and not sub-resources.
+        /// </summary>
+        /// <param name="resourcePaths">List of resource paths to find files for.</param>
+        /// <returns>File paths for all the provided resources.</returns>
+        private string[] GetFiles(IEnumerable<string> resourcePaths)
+        {
+            HashSet<string> filePaths = new HashSet<string>();
+
+            foreach (var resPath in resourcePaths)
+            {
+                if (resPath == null)
+                    continue;
+
+                LibraryEntry entry = ProjectLibrary.GetEntry(resPath);
+                if (entry == null)
+                    continue;
+
+                if (ProjectLibrary.IsSubresource(resPath))
+                    continue;
+
+                if (!filePaths.Contains(entry.Path))
+                    filePaths.Add(entry.Path);
+            }
+
+            string[] output = new string[filePaths.Count];
+
+            int i = 0;
+            foreach(var path in filePaths)
+                output[i++] = path;
+
+            return output;
+        }
+
         /// <summary>
         /// Opens the drop down options window that allows you to customize library window look and feel.
         /// </summary>
@@ -1292,12 +1333,11 @@ namespace BansheeEditor
 
             if (paths != null)
             {
+                string[] filePaths = GetFiles(paths);
+
                 List<string> addedResources = new List<string>();
-                foreach (var path in paths)
+                foreach (var path in filePaths)
                 {
-                    if (path == null)
-                        continue;
-
                     string absolutePath = path;
                     if (!Path.IsPathRooted(absolutePath))
                         absolutePath = Path.Combine(resourceDir, path);

+ 46 - 7
MBansheeEditor/ProjectLibrary.cs

@@ -116,7 +116,9 @@ namespace BansheeEditor
         /// Loads a resource from the project library.
         /// </summary>
         /// <typeparam name="T">Type of the resource to load.</typeparam>
-        /// <param name="path">Path of the resource to load. Absolute or relative to the resources folder.</param>
+        /// <param name="path">Path of the resource to load. Absolute or relative to the resources folder. If a 
+        ///                    sub-resource within a file is needed, append the name of the subresource to the path (e.g. 
+        ///                    mymesh.fbx/my_animation).</param>
         /// <returns>Instance of the loaded resource, or null if not found.</returns>
         public static T Load<T>(string path) where T : Resource
         {
@@ -137,10 +139,10 @@ namespace BansheeEditor
         }
 
         /// <summary>
-        /// Checks does the project library contain a resource at the specified path.
+        /// Checks does the project library contain a file or folder at the specified path.
         /// </summary>
-        /// <param name="path">Path to the resource to check, absolute or relative to resources folder.</param>
-        /// <returns>True if the resourc exists, false otherwise.</returns>
+        /// <param name="path">Path to the file/folder to check, absolute or relative to resources folder.</param>
+        /// <returns>True if the element exists, false otherwise.</returns>
         public static bool Exists(string path)
         {
             return GetEntry(path) != null;
@@ -157,6 +159,29 @@ namespace BansheeEditor
             return Internal_GetEntry(path);
         }
 
+        /// <summary>
+        /// Checks whether the provided path points to a sub-resource. Sub-resource is any resource that is not the
+        /// primary resource in the file.
+        /// </summary>
+        /// <param name="path">Path to the entry, absolute or relative to resources folder.</param>
+        /// <returns>True if the path is a sub-resource, false otherwise.</returns>
+        public static bool IsSubresource(string path)
+        {
+            return Internal_IsSubresource(path);
+        }
+
+        /// <summary>
+        /// Attempts to locate meta-data for a resource at the specified path.
+        /// </summary>
+        /// <param name="path">Path to the entry to retrieve, absolute or relative to resources folder. If a sub-resource 
+        ///                    within a file is needed, append the name of the subresource to the path (e.g. 
+        ///                    mymesh.fbx/my_animation).</param>
+        /// <returns>Resource meta-data if the resource was found, null otherwise.</returns>
+        public static ResourceMeta GetMeta(string path)
+        {
+            return Internal_GetMeta(path);
+        }
+
         /// <summary>
         /// Searches the library for a pattern and returns all entries matching it.
         /// </summary>
@@ -362,12 +387,18 @@ namespace BansheeEditor
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern DirectoryEntry Internal_GetRoot();
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_IsSubresource(string path);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_Reimport(string path, ImportOptions options, bool force);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern LibraryEntry Internal_GetEntry(string path);
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern ResourceMeta Internal_GetMeta(string path);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern LibraryEntry[] Internal_Search(string path, ResourceType[] types);
 
@@ -469,12 +500,12 @@ namespace BansheeEditor
     }
 
     /// <summary>
-    /// A library entry representing a resource.
+    /// A library entry representing a file.
     /// </summary>
     public class FileEntry : LibraryEntry
     {
         /// <summary>
-        /// Import options used for importing the resource.
+        /// Import options used for importing the resources in the file.
         /// </summary>
         public ImportOptions Options { get { return Internal_GetImportOptions(mCachedPtr); } }
 
@@ -484,7 +515,7 @@ namespace BansheeEditor
         public ResourceMeta[] ResourceMetas { get { return Internal_GetResourceMetas(mCachedPtr); } }
 
         /// <summary>
-        /// Determines will the resource be included in the project build.
+        /// Determines will the resources in the file be included in the project build.
         /// </summary>
         public bool IncludeInBuild { get { return Internal_GetIncludeInBuild(mCachedPtr); } }
 
@@ -508,6 +539,11 @@ namespace BansheeEditor
         /// </summary>
         public string UUID { get { return Internal_GetUUID(mCachedPtr); } }
 
+        /// <summary>
+        /// Returns a name of the subresources. Each resource within a file has a unique name.
+        /// </summary>
+        public string SubresourceName { get { return Internal_GetSubresourceName(mCachedPtr); } }
+
         /// <summary>
         /// Custom icon for the resource to display in the editor, if the resource has one.
         /// </summary>
@@ -521,6 +557,9 @@ namespace BansheeEditor
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern string Internal_GetUUID(IntPtr thisPtr);
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern string Internal_GetSubresourceName(IntPtr thisPtr);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern Texture2D Internal_GetIcon(IntPtr thisPtr);
 

+ 4 - 5
MBansheeEditor/Scene/SceneWindow.cs

@@ -475,11 +475,10 @@ namespace BansheeEditor
 
                         for (int i = 0; i < draggedPaths.Length; i++)
                         {
-                            LibraryEntry entry = ProjectLibrary.GetEntry(draggedPaths[i]);
-                            if (entry != null && entry.Type == LibraryEntryType.File)
+                            ResourceMeta meta = ProjectLibrary.GetMeta(draggedPaths[i]);
+                            if (meta != null)
                             {
-                                FileEntry fileEntry = (FileEntry) entry;
-                                if (fileEntry.ResType == ResourceType.Mesh)
+                                if (meta.ResType == ResourceType.Mesh)
                                 {
                                     if (!string.IsNullOrEmpty(draggedPaths[i]))
                                     {
@@ -493,7 +492,7 @@ namespace BansheeEditor
 
                                     break;
                                 }
-                                else if (fileEntry.ResType == ResourceType.Prefab)
+                                else if (meta.ResType == ResourceType.Prefab)
                                 {
                                     if (!string.IsNullOrEmpty(draggedPaths[i]))
                                     {

+ 19 - 3
MBansheeEditor/ScriptCodeManager.cs

@@ -121,7 +121,19 @@ namespace BansheeEditor
                 return;
 
             FileEntry fileEntry = (FileEntry)entry;
-            if (fileEntry.ResType != ResourceType.ScriptCode)
+            ResourceMeta[] resourceMetas = fileEntry.ResourceMetas;
+
+            bool found = false;
+            foreach (var meta in resourceMetas)
+            {
+                if (meta.ResType != ResourceType.ScriptCode)
+                {
+                    found = true;
+                    break;
+                }
+            }
+
+            if (!found)
                 return;
 
             ScriptCode codeFile = ProjectLibrary.Load<ScriptCode>(path);
@@ -145,11 +157,15 @@ namespace BansheeEditor
             if (entry != null && entry.Type == LibraryEntryType.File)
             {
                 FileEntry fileEntry = (FileEntry)entry;
+                ResourceMeta[] resourceMetas = fileEntry.ResourceMetas;
 
                 foreach (var codeType in CodeEditor.CodeTypes)
                 {
-                    if (fileEntry.ResType == codeType)
-                        return true;
+                    foreach (var meta in resourceMetas)
+                    {
+                        if (meta.ResType == codeType)
+                            return true;
+                    }
                 }
             }
 

+ 1 - 1
MBansheeEngine/PathEx.cs

@@ -6,7 +6,7 @@ namespace BansheeEngine
 {
     /// <summary>
     /// Contains helper methods dealing with file and directory paths, extending the functionality provided by 
-    // System.IO.Path.
+    /// System.IO.Path.
     /// </summary>
     public static class PathEx
     {

+ 7 - 4
SBansheeEditor/Include/BsScriptProjectLibrary.h

@@ -65,6 +65,8 @@ namespace BansheeEngine
 		static MonoObject* internal_GetRoot();
 		static void internal_Reimport(MonoString* path, MonoObject* options, bool force);
 		static MonoObject* internal_GetEntry(MonoString* path);
+		static bool internal_IsSubresource(MonoString* path);
+		static MonoObject* internal_GetMeta(MonoString* path);
 		static MonoString* internal_GetPathFromUUID(MonoString* uuid);
 		static MonoString* internal_GetPath(MonoObject* resource);
 		static MonoArray* internal_Search(MonoString* pattern, MonoArray* types);
@@ -167,20 +169,21 @@ namespace BansheeEngine
 	public:
 		SCRIPT_OBJ(EDITOR_ASSEMBLY, "BansheeEditor", "ResourceMeta")
 
-		ScriptResourceMeta(MonoObject* instance, const Path& assetPath);
+		ScriptResourceMeta(MonoObject* instance, const ProjectResourceMetaPtr& meta);
 
 		/**
-		 * Creates a new interop object that wraps the native resource meta object for the resource at the specified path.
+		 * Creates a new interop object that wraps the native resource meta object.
 		 */
-		static MonoObject* create(const Path& assetPath);
+		static MonoObject* create(const ProjectResourceMetaPtr& meta);
 
 	private:
-		Path mAssetPath;
+		ProjectResourceMetaPtr mMeta;
 
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/
 		/************************************************************************/
 		static MonoString* internal_GetUUID(ScriptResourceMeta* thisPtr);
+		static MonoString* internal_GetSubresourceName(ScriptResourceMeta* thisPtr);
 		static MonoObject* internal_GetIcon(ScriptResourceMeta* thisPtr);
 		static ScriptResourceType internal_GetResourceType(ScriptResourceMeta* thisPtr);
 	};

+ 34 - 27
SBansheeEditor/Source/BsScriptProjectLibrary.cpp

@@ -44,6 +44,8 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_GetRoot", &ScriptProjectLibrary::internal_GetRoot);
 		metaData.scriptClass->addInternalCall("Internal_Reimport", &ScriptProjectLibrary::internal_Reimport);
 		metaData.scriptClass->addInternalCall("Internal_GetEntry", &ScriptProjectLibrary::internal_GetEntry);
+		metaData.scriptClass->addInternalCall("Internal_IsSubresource", &ScriptProjectLibrary::internal_IsSubresource);
+		metaData.scriptClass->addInternalCall("Internal_GetMeta", &ScriptProjectLibrary::internal_GetMeta);
 		metaData.scriptClass->addInternalCall("Internal_GetPath", &ScriptProjectLibrary::internal_GetPath);
 		metaData.scriptClass->addInternalCall("Internal_GetPathFromUUID", &ScriptProjectLibrary::internal_GetPathFromUUID);
 		metaData.scriptClass->addInternalCall("Internal_Search", &ScriptProjectLibrary::internal_Search);
@@ -142,6 +144,24 @@ namespace BansheeEngine
 			return ScriptDirectoryEntry::create(static_cast<ProjectLibrary::DirectoryEntry*>(entry));
 	}
 
+	bool ScriptProjectLibrary::internal_IsSubresource(MonoString* path)
+	{
+		Path assetPath = MonoUtil::monoToWString(path);
+
+		return gProjectLibrary().isSubresource(assetPath);
+	}
+
+	MonoObject* ScriptProjectLibrary::internal_GetMeta(MonoString* path)
+	{
+		Path assetPath = MonoUtil::monoToWString(path);
+
+		ProjectResourceMetaPtr meta = gProjectLibrary().findResourceMeta(assetPath);
+		if (meta == nullptr)
+			return nullptr;
+
+		return ScriptResourceMeta::create(meta);
+	}
+
 	MonoString* ScriptProjectLibrary::internal_GetPathFromUUID(MonoString* uuid)
 	{
 		String nativeUUID = MonoUtil::monoToString(uuid);
@@ -434,17 +454,8 @@ namespace BansheeEngine
 				UINT32 numElements = (UINT32)resourceMetas.size();
 
 				ScriptArray output = ScriptArray::create<ScriptResourceMeta>(numElements);
-				if (numElements > 0)
-				{
-					// Don't give the primary resource a subresource name
-					output.set(0, ScriptResourceMeta::create(thisPtr->getAssetPath()));
-
-					for (UINT32 i = 1; i < numElements; i++)
-					{
-						Path assetPath = thisPtr->getAssetPath() + resourceMetas[i]->getUniqueName();
-						output.set(i, ScriptResourceMeta::create(assetPath));
-					}
-				}
+				for (UINT32 i = 0; i < numElements; i++)
+					output.set(i, ScriptResourceMeta::create(resourceMetas[i]));
 
 				return output.getInternal();
 			}
@@ -467,16 +478,14 @@ namespace BansheeEngine
 		return false;
 	}
 
-	ScriptResourceMeta::ScriptResourceMeta(MonoObject* instance, const Path& assetPath)
-		:ScriptObject(instance)
-	{
-		mAssetPath = assetPath;
-	}
+	ScriptResourceMeta::ScriptResourceMeta(MonoObject* instance, const ProjectResourceMetaPtr& meta)
+		:ScriptObject(instance), mMeta(meta)
+	{ }
 
-	MonoObject* ScriptResourceMeta::create(const Path& assetPath)
+	MonoObject* ScriptResourceMeta::create(const ProjectResourceMetaPtr& meta)
 	{
 		MonoObject* managedInstance = metaData.scriptClass->createInstance();
-		bs_new<ScriptResourceMeta>(managedInstance, assetPath);
+		bs_new<ScriptResourceMeta>(managedInstance, meta);
 
 		return managedInstance;
 	}
@@ -484,17 +493,19 @@ namespace BansheeEngine
 	void ScriptResourceMeta::initRuntimeData()
 	{
 		metaData.scriptClass->addInternalCall("Internal_GetUUID", &ScriptResourceMeta::internal_GetUUID);
+		metaData.scriptClass->addInternalCall("Internal_GetSubresourceName", &ScriptResourceMeta::internal_GetSubresourceName);
 		metaData.scriptClass->addInternalCall("Internal_GetIcon", &ScriptResourceMeta::internal_GetIcon);
 		metaData.scriptClass->addInternalCall("Internal_GetResourceType", &ScriptResourceMeta::internal_GetResourceType);
 	}
 
 	MonoString* ScriptResourceMeta::internal_GetUUID(ScriptResourceMeta* thisPtr)
 	{
-		ProjectResourceMetaPtr meta = gProjectLibrary().findResourceMeta(thisPtr->mAssetPath);
-		if (meta == nullptr)
-			return nullptr;
+		return MonoUtil::stringToMono(thisPtr->mMeta->getUUID());
+	}
 
-		return MonoUtil::stringToMono(meta->getUUID());
+	MonoString* ScriptResourceMeta::internal_GetSubresourceName(ScriptResourceMeta* thisPtr)
+	{
+		return MonoUtil::wstringToMono(thisPtr->mMeta->getUniqueName());
 	}
 
 	MonoObject* ScriptResourceMeta::internal_GetIcon(ScriptResourceMeta* thisPtr)
@@ -505,10 +516,6 @@ namespace BansheeEngine
 
 	ScriptResourceType ScriptResourceMeta::internal_GetResourceType(ScriptResourceMeta* thisPtr)
 	{
-		ProjectResourceMetaPtr meta = gProjectLibrary().findResourceMeta(thisPtr->mAssetPath);
-		if (meta == nullptr)
-			return ScriptResourceType::Undefined;
-
-		return ScriptResource::getTypeFromTypeId(meta->getTypeID());
+		return ScriptResource::getTypeFromTypeId(thisPtr->mMeta->getTypeID());
 	}
 }