Przeglądaj źródła

Added sub-resource import and reimport to ProjectLibrary

BearishSun 10 lat temu
rodzic
commit
9833d47b49

+ 1 - 1
BansheeCore/Include/BsImporter.h

@@ -18,7 +18,7 @@ namespace BansheeEngine
 	 */
 	struct SubResource
 	{
-		String name; /**< Unique name of the sub-resource. */
+		WString name; /**< Unique name of the sub-resource. */
 		HResource value; /**< Contents of the sub-resource. */
 	};
 

+ 1 - 1
BansheeCore/Include/BsSpecificImporter.h

@@ -17,7 +17,7 @@ namespace BansheeEngine
 	 */
 	struct SubResourceRaw
 	{
-		String name; /**< Unique name of the sub-resource. */
+		WString name; /**< Unique name of the sub-resource. */
 		SPtr<Resource> value; /**< Contents of the sub-resource. */
 	};
 

+ 1 - 1
BansheeCore/Source/BsSpecificImporter.cpp

@@ -12,7 +12,7 @@ namespace BansheeEngine
 		if (resource == nullptr)
 			return Vector<SubResourceRaw>();
 
-		return { { "primary", resource } };;
+		return { { L"primary", resource } };;
 	}
 
 	ImportOptionsPtr SpecificImporter::createImportOptions() const

+ 145 - 186
BansheeEditor/Include/BsProjectLibrary.h

@@ -8,10 +8,9 @@
 namespace BansheeEngine
 {
 	/**
-	 * @brief	Project library is the primary location for interacting with all the resources
-	 *			in the current project. A complete hierarchy of resources is provided which
-	 *			can be interacted with by importing new ones, deleting them, moving, renaming
-	 *			and similar.
+	 * Project library is the primary location for interacting with all the resources in the current project. A complete
+	 * hierarchy of resources is provided which can be interacted with by importing new ones, deleting them, moving,
+	 * renaming and similar.
 	 */
 	class BS_ED_EXPORT ProjectLibrary : public Module<ProjectLibrary>
 	{
@@ -20,20 +19,14 @@ namespace BansheeEngine
 		struct FileEntry;
 		struct DirectoryEntry;
 
-		/**
-		 * @brief	Types of elements in the library, either a file
-		 *			or a folder.
-		 */
+		/** Types of elements in the library, either a file or a folder. */
 		enum class LibraryEntryType
 		{
 			File,
 			Directory
 		};
 
-		/**
-		 * @brief	A generic library entry that may be a file or a folder
-		 *			depending on its type.
-		 */
+		/**	A generic library entry that may be a file or a folder depending on its type. */
 		struct LibraryEntry
 		{
 			LibraryEntry();
@@ -46,21 +39,17 @@ namespace BansheeEngine
 			DirectoryEntry* parent; /**< Folder this entry is located in. */
 		};
 
-		/**
-		 * @brief	A library entry representing a file.
-		 */
+		/**	A library entry representing a file. Each file can have one or multiple resources. */
 		struct FileEntry : public LibraryEntry
 		{
 			FileEntry();
 			FileEntry(const Path& path, const WString& name, DirectoryEntry* parent);
 
-			ProjectFileMetaPtr meta; /**< Meta file containing various information about the resource. */
+			ProjectFileMetaPtr meta; /**< Meta file containing various information about the resource(s). */
 			std::time_t lastUpdateTime; /**< Timestamp of when we last imported the resource. */
 		};
 
-		/**
-		 * @brief	A library entry representing a folder that contains other entries.
-		 */
+		/**	A library entry representing a folder that contains other entries. */
 		struct DirectoryEntry : public LibraryEntry
 		{
 			DirectoryEntry();
@@ -74,324 +63,296 @@ namespace BansheeEngine
 		~ProjectLibrary();
 
 		/**
-		 * @brief	Checks if any resources at the specified path have been modified, added or deleted,
-		 *			and updates the internal hierarchy accordingly. 
+		 * Checks if any resources at the specified path have been modified, added or deleted, and updates the internal
+		 * hierarchy accordingly. Automatically imports dirty resources.
 		 *
-		 * @param	path	Absolute path of the file or folder to check. If a folder is provided
-		 *					all its children will be checked recursively.
+		 * @param[in]	path	Absolute path of the file or folder to check. If a folder is provided all its children will
+		 *						be checked recursively.
 		 */
 		void checkForModifications(const Path& path);
 
 		/**
-		 * @brief	Checks if any resources at the specified path have been modified, added or deleted,
-		 *			and updates the internal hierarchy accordingly. 
+		 * Checks if any resources at the specified path have been modified, added or deleted, and updates the internal
+		 * hierarchy accordingly. 
 		 *
-		 * @param	path			Absolute path of the file or folder to check. If a folder is provided
-		 *							all its children will be checked recursively.
-		 * @param	import			Should the dirty resources be automatically reimported.
-		 * @param	dirtyResources	A list of resources that should be reimported.
+		 * @param[in]	path			Absolute path of the file or folder to check. If a folder is provided all its 
+		 *								children will be checked recursively.
+		 * @param[in]	import			Should the dirty resources be automatically reimported.
+		 * @param[in]	dirtyResources	A list of resources that should be reimported.
 		 */
 		void checkForModifications(const Path& path, bool import, Vector<Path>& dirtyResources);
 
-		/**
-		 * @brief	Returns the root library entry that references the entire library hierarchy.
-		 */
+		/**	Returns the root library entry that references the entire library hierarchy. */
 		const LibraryEntry* getRootEntry() const { return mRootEntry; }
 
 		/**
-		 * @brief	Attempts to a find a library entry at the specified path.
-		 *
-		 * @param	path	Path to the entry, either absolute or relative to resources folder.
+		 * Attempts to a find a library entry at the specified path.
 		 *
-		 * @return	Found entry, or null if not found. Value returned by this method is transient,
-		 *			it may be destroyed on any following ProjectLibrary call.
+		 * @param[in]	path	Path to the entry, either absolute or relative to resources folder.
+		 * @return				Found entry, or null if not found. Value returned by this method is transient, it may be
+		 *						destroyed on any following ProjectLibrary call.
 		 */
 		LibraryEntry* findEntry(const Path& path) const;
 
 		/**
-		 * @brief	Attempts to a find a meta information for a resource at the specified path.
-		 *
-		 * @param	path	Path to the entry, either 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).
+		 * Attempts to a find a meta information for a resource at the specified path.
 		 *
-		 * @return	Found meta information for the resource, or null if not found. 
+		 * @param[in]	path	Path to the entry, either 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).
+		 * @return				Found meta information for the resource, or null if not found. 
 		 */
 		ProjectResourceMetaPtr findResourceMeta(const Path& path) const;
 
 		/**
-		 * @brief	Searches the library for a pattern and returns all entries matching it.
+		 * Searches the library for a pattern and returns all entries matching it.
 		 *
-		 * @param	pattern	Pattern to search for. Use wildcard * to match any character(s).
-		 *
-		 * @return	A list of entries matching the pattern. Values returned by this method are transient,
-		 *			they may be destroyed on any following ProjectLibrary call.
+		 * @param[in]	pattern	Pattern to search for. Use wildcard * to match any character(s).
+		 * @return		A list of entries matching the pattern. Values returned by this method are transient, they may be
+		 *				destroyed on any following ProjectLibrary call.
 		 */
 		Vector<LibraryEntry*> search(const WString& pattern);
 
 		/**
-		 * @brief	Searches the library for a pattern, but only among specific resource types.
-		 *
-		 * @param	pattern	Pattern to search for. Use wildcard * to match any character(s).
-		 * @param	typeIds	RTTI type IDs of the resource types we're interested in searching.
+		 * Searches the library for a pattern, but only among specific resource types.
 		 *
-		 * @return	A list of entries matching the pattern. Values returned by this method are transient, 
-		 *			they may be destroyed on any following ProjectLibrary call.
+		 * @param[in]	pattern	Pattern to search for. Use wildcard * to match any character(s).
+		 * @param[in]	typeIds	RTTI type IDs of the resource types we're interested in searching.
+		 * @return		A list of entries matching the pattern. Values returned by this method are transient, they may be
+		 *				destroyed on any following ProjectLibrary call.
 		 */
 		Vector<LibraryEntry*> search(const WString& pattern, const Vector<UINT32>& typeIds);
 
 		/**
-		 * @brief	Returns resource path based on its UUID.
-		 *
-		 * @param	uuid	UUID of the resource to look for.
+		 * Returns resource path based on its UUID.
 		 *
-		 * @return	Absolute path to the resource.
+		 * @param[in]	uuid	UUID of the resource to look for.
+		 * @return				Absolute path to the resource.
 		 */
 		Path uuidToPath(const String& uuid) const;
 
 		/**
-		 * @brief	Registers a new resource in the library.
+		 * Registers a new resource in the library.
 		 *
-		 * @param	resource	Resource instance to add to the library. A copy of the
-		 *						resource will be saved at the provided path.
-		 * @param	path		Path where where to store the resource. Absolute or relative to the resources folder.
+		 * @param[in]	resource	Resource instance to add to the library. A copy of the resource will be saved at the
+		 *							provided path.
+		 * @param[in]	path		Path where where to store the resource. Absolute or relative to the resources folder.
 		 */
 		void createEntry(const HResource& resource, const Path& path);
 
 		/**
-		 * @brief	Creates a new folder in the library.
+		 * Creates a new folder in the library.
 		 *
-		 * @param	path		Path where where to store the folder. Absolute or relative to the resources folder.
+		 * @param[in]	path		Path where where to store the folder. Absolute or relative to the resources folder.
 		 */
 		void createFolderEntry(const Path& path);
 
-		/**
-		 * @brief	Updates a resource that is already in the library.
-		 */
+		/**	Updates a resource that is already in the library. */
 		void saveEntry(const HResource& resource);
 
 		/**
-		 * @brief	Moves a library entry from one path to another.
+		 * Moves a library entry from one path to another.
 		 *
-		 * @param	oldPath		Source path of the entry, absolute or relative to resources folder.
-		 * @param	newPath		Destination path of the entry, absolute or relative to resources folder.
-		 * @param	overwrite	If an entry already exists at the destination path, should it be overwritten.
+		 * @param[in]	oldPath		Source path of the entry, absolute or relative to resources folder.
+		 * @param[in]	newPath		Destination path of the entry, absolute or relative to resources folder.
+		 * @param[in]	overwrite	If an entry already exists at the destination path, should it be overwritten.
 		 */
 		void moveEntry(const Path& oldPath, const Path& newPath, bool overwrite = true);
 
 		/**
-		 * @brief	Copies a library entry from one path to another.
+		 * Copies a library entry from one path to another.
 		 *
-		 * @param	oldPath		Source path of the entry, absolute or relative to resources folder.
-		 * @param	newPath		Destination path of the entry, absolute or relative to resources folder.
-		 * @param	overwrite	If an entry already exists at the destination path, should it be overwritten.
+		 * @param[in]	oldPath		Source path of the entry, absolute or relative to resources folder.
+		 * @param[in]	newPath		Destination path of the entry, absolute or relative to resources folder.
+		 * @param[in]	overwrite	If an entry already exists at the destination path, should it be overwritten.
 		 */
 		void copyEntry(const Path& oldPath, const Path& newPath, bool overwrite = true);
 
 		/**
-		 * @brief	Deletes an entry from the library.
+		 * Deletes an entry from the library.
 		 *
-		 * @param	path		Path of the entry, absolute or relative to resources folder.
+		 * @param[in]	path		Path of the entry, absolute or relative to resources folder.
 		 */
 		void deleteEntry(const Path& path);
 
 		/**
-		 * @brief	Triggers a reimport of a resource using the provided import options, if needed.
+		 * Triggers a reimport of a resource using the provided import options, if needed.
 		 *
-		 * @param	path			Path to the resource to reimport, absolute or relative to resources folder.
-		 * @param	importOptions	Optional import options to use when importing the resource. Caller must ensure the
-		 *							import options are of the correct type for the resource in question. If null is provided
-		 *							default import options are used.
-		 * @param	forceReimport	Should the resource be reimported even if no changes are detected. This should be true
-		 *							if import options changed since last import.
+		 * @param[in]	path			Path to the resource to reimport, absolute or relative to resources folder.
+		 * @param[in]	importOptions	Optional import options to use when importing the resource. Caller must ensure the
+		 *								import options are of the correct type for the resource in question. If null is
+		 *								provided default import options are used.
+		 * @param[in]	forceReimport	Should the resource be reimported even if no changes are detected. This should be
+		 *								true if import options changed since last import.
 		 */
 		void reimport(const Path& path, const ImportOptionsPtr& importOptions = nullptr, bool forceReimport = false);
 
 		/**
-		 * @brief	Determines if this resource will always be included in the build, regardless if
-		 *			it's being referenced or not.
+		 * Determines if this resource will always be included in the build, regardless if it's being referenced or not.
 		 *
-		 * @param	path	Path to the resource to modify, absolute or relative to resources folder.
-		 * @param	force	True if we want the resource to be included in the build, false otherwise.
+		 * @param[in]	path	Path to the resource to modify, absolute or relative to resources folder.
+		 * @param[in]	force	True if we want the resource to be included in the build, false otherwise.
 		 */
 		void setIncludeInBuild(const Path& path, bool force);
 
 		/**
-		 * @brief	Finds all top-level resource entries that should be included in a build.
-		 *			Values returned by this method are transient, they may be destroyed
-		 *			on any following ProjectLibrary call.
+		 * Finds all top-level resource entries that should be included in a build. Values returned by this method are
+		 * transient, they may be destroyed on any following ProjectLibrary call.
 		 */
 		Vector<FileEntry*> getResourcesForBuild() const;
 
 		/**
-		 * @brief	Loads a resource at the specified path, synchronously.
-		 *
-		 * @param	path	Path of the resource, 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).
+		 * Loads a resource at the specified path, synchronously.
 		 *
-		 * @return	Loaded resource, or null handle if one is not found.
+		 * @param[in]	path	Path of the resource, 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).
+		 * @return				Loaded resource, or null handle if one is not found.
 		 */
 		HResource load(const Path& path);
 
-		/**
-		 * @brief	Returns the path to the project's resource folder where all
-		 *			the assets are stored.
-		 */
+		/** Returns the path to the project's resource folder where all the assets are stored. */
 		const Path& getResourcesFolder() const { return mResourcesFolder; }
 
-		/**
-		 * @brief	Returns the resource manifest managed by the project library.
-		 *
-		 * @note	Internal method.
-		 */
+		/**	Returns the resource manifest managed by the project library. */
 		const ResourceManifestPtr& _getManifest() const { return mResourceManifest; }
 
 		/**
-		 * @brief	Saves all the project library data so it may be restored later,
-		 *			at the default save location in the project folder. Project
-		 *			must be loaded when calling this.
+		 * Saves all the project library data so it may be restored later, at the default save location in the project
+		 * folder. Project must be loaded when calling this.
 		 */
 		void saveLibrary();
 
 		/**
-		 * @brief	Loads previously saved project library data from the default save 
-		 *			location in the project folder. Nothing is loaded if it doesn't
-		 *			exist.Project must be loaded when calling this.
+		 * Loads previously saved project library data from the default save location in the project folder. Nothing is
+		 * loaded if it doesn't exist.Project must be loaded when calling this.
 		 */
 		void loadLibrary();
 
-		/**
-		 * @brief	Clears all library data.
-		 */
+		/**	Clears all library data. */
 		void unloadLibrary();
 
-		Event<void(const Path&)> onEntryRemoved; /**< Triggered whenever an entry is removed from the library. Path provided is absolute. */
-		Event<void(const Path&)> onEntryAdded; /**< Triggered whenever an entry is added to the library. Path provided is absolute. */
-		Event<void(const Path&)> onEntryImported; /**< Triggered when a resource is being (re)imported. Path provided is absolute. */
+		/** Triggered whenever an entry is removed from the library. Path provided is absolute. */
+		Event<void(const Path&)> onEntryRemoved; 
+
+		/** Triggered whenever an entry is added to the library. Path provided is absolute. */
+		Event<void(const Path&)> onEntryAdded; 
+
+		/** Triggered when a resource is being (re)imported. Path provided is absolute. */
+		Event<void(const Path&)> onEntryImported; 
 
 		static const Path RESOURCES_DIR;
 		static const Path INTERNAL_RESOURCES_DIR;
 	private:
 		/**
-		 * @brief	Common code for adding a new resource entry to the library.
+		 * Common code for adding a new resource entry to the library.
 		 *
-		 * @param	parent			Parent of the new entry.
-		 * @param	filePath		Absolute path to the resource.
-		 * @param	importOptions	Optional import options to use when importing the resource. Caller must ensure the
-		 *							import options are of the correct type for the resource in question. If null is provided
-		 *							default import options are used.
-		 * @param	forceReimport	Should the resource be reimported even if we detect no changes. This should be true
-		 *							if import options changed since last import.
-		 *
-		 * @return	Newly added resource entry.
+		 * @param[in]	parent			Parent of the new entry.
+		 * @param[in]	filePath		Absolute path to the resource.
+		 * @param[in]	importOptions	Optional import options to use when importing the resource. Caller must ensure the
+		 *								import options are of the correct type for the resource in question. If null is 
+		 *								provided default import options are used.
+		 * @param[in]	forceReimport	Should the resource be reimported even if we detect no changes. This should be true
+		 *								if import options changed since last import.
+		 * @return						Newly added resource entry.
 		 */
-		FileEntry* addResourceInternal(DirectoryEntry* parent, const Path& filePath, const ImportOptionsPtr& importOptions = nullptr, bool forceReimport = false);
+		FileEntry* addResourceInternal(DirectoryEntry* parent, const Path& filePath, 
+			const ImportOptionsPtr& importOptions = nullptr, bool forceReimport = false);
 
 		/**
-		 * @brief	Common code for adding a new folder entry to the library.
-		 *
-		 * @param	parent	Parent of the new entry.
-		 * @param	dirPath	Absolute path to the directory.
+		 * Common code for adding a new folder entry to the library.
 		 *
-		 * @return	Newly added directory entry.
+		 * @param[in]	parent	Parent of the new entry.
+		 * @param[in]	dirPath	Absolute path to the directory.
+		 * @return		Newly added directory entry.
 		 */
 		DirectoryEntry* addDirectoryInternal(DirectoryEntry* parent, const Path& dirPath);
 
 		/**
-		 * @brief	Common code for deleting a resource from the library. This code only removes
-		 *			the library entry, not the actual resource file.
+		 * Common code for deleting a resource from the library. This code only removes the library entry, not the actual
+		 * resource file.
 		 *
-		 * @param	resource	Entry to delete.
+		 * @param[in]	resource	Entry to delete.
 		 */
 		void deleteResourceInternal(FileEntry* resource);
 
 		/**
-		 * @brief	Common code for deleting a directory from the library. This code only removes
-		 *			the library entry, not the actual directory.
+		 * Common code for deleting a directory from the library. This code only removes the library entry, not the actual
+		 * directory.
 		 *
-		 * @param	resource	Entry to delete.
+		 * @param[in]	resource	Entry to delete.
 		 */
 		void deleteDirectoryInternal(DirectoryEntry* directory);
 
 		/**
-		 * @brief	Triggers a reimport of a resource using the provided import options, if needed. Doesn't import dependencies.
+		 * Triggers a reimport of a resource using the provided import options, if needed. Doesn't import dependencies.
 		 *
-		 * @param	path			Absolute Path to the resource to reimport.
-		 * @param	importOptions	Optional import options to use when importing the resource. Caller must ensure the
-		 *							import options are of the correct type for the resource in question. If null is provided
-		 *							default import options are used.
-		 * @param	forceReimport	Should the resource be reimported even if we detect no changes. This should be true
-		 *							if import options changed since last import.
+		 * @param[in]	path				Absolute Path to the resource to reimport.
+		 * @param[in]	importOptions		Optional import options to use when importing the resource. Caller must ensure 
+		 *									the import options are of the correct type for the resource in question. If null
+		 *									is provided default import options are used.
+		 * @param[in]	forceReimport		Should the resource be reimported even if we detect no changes. This should be 
+		 *									true if import options changed since last import.
+		 * @param[in]	pruneResourceMetas	Determines should resource meta data for resources that no longer exist within
+		 *									the file be deleted. Default behaviour is to keep these alive so that if their
+		 *									resources are eventually restored, references to them will remain valid. If you
+		 *									feel that you need to clear this data, set this to true but be aware that you
+		 *									might need to re-apply those references.
 		 */
-		void reimportResourceInternal(FileEntry* resource, const ImportOptionsPtr& importOptions = nullptr, bool forceReimport = false);
+		void reimportResourceInternal(FileEntry* file, const ImportOptionsPtr& importOptions = nullptr, 
+			bool forceReimport = false, bool pruneResourceMetas = false);
 
 		/**
-		 * @brief	Creates a full hierarchy of directory entries up to the provided directory, if any are needed.
+		 * Creates a full hierarchy of directory entries up to the provided directory, if any are needed.
 		 *
-		 * @param	fullPath			Absolute path to a directory we are creating the hierarchy to.
-		 * @param	newHierarchyRoot	First directory entry that already existed in our hierarchy.
-		 * @param	newHierarchyLeaf	Leaf entry corresponding to the exact entry at \p path.
+		 * @param[in]	fullPath			Absolute path to a directory we are creating the hierarchy to.
+		 * @param[in]	newHierarchyRoot	First directory entry that already existed in our hierarchy.
+		 * @param[in]	newHierarchyLeaf	Leaf entry corresponding to the exact entry at \p path.
 		 */
 		void createInternalParentHierarchy(const Path& fullPath, DirectoryEntry** newHierarchyRoot, DirectoryEntry** newHierarchyLeaf);
 
-		/**
-		 * @brief	Checks has the resource been modified since the last import.
-		 */
-		bool isUpToDate(FileEntry* resource) const;
+		/**	Checks has a file been modified since the last import. */
+		bool isUpToDate(FileEntry* file) const;
 
-		/**
-		 * @brief	Checks is the resource a native engine resource that doesn't require importing.
-		 */
+		/**	Checks is the resource a native engine resource that doesn't require importing. */
 		bool isNative(const Path& path) const;
 
 		/**
-		 * @brief	Returns a path to a .meta file based on the resource path.
+		 * Returns a path to a .meta file based on the resource path.
 		 *
-		 * @param	path	Absolute path to the resource.
-		 *
-		 * @return	Path to the .meta file.
+		 * @param[in]	path	Absolute path to the resource.
+		 * @return				Path to the .meta file.
 		 */
 		Path getMetaPath(const Path& path) const;
 		
-		/**
-		 * @brief	Checks does the path represent a .meta file.
-		 */
+		/**	Checks does the path represent a .meta file. */
 		bool isMeta(const Path& fullPath) const;
 
 		/**
-		 * @brief	Returns a set of resource paths that are dependent on the provided
-		 *			resource entry. (e.g. a shader file might be dependent on shader include file).
+		 * Returns a set of resource paths that are dependent on the provided resource entry. (e.g. a shader file might be
+		 * dependent on shader include file).
 		 */
 		Vector<Path> getImportDependencies(const FileEntry* entry);
 
-		/**
-		 * @brief	Registers any import dependencies for the specified resource.
-		 */
+		/**	Registers any import dependencies for the specified resource. */
 		void addDependencies(const FileEntry* entry);
 
-		/**
-		 * @brief	Removes any import dependencies for the specified resource.
-		 */
+		/**	Removes any import dependencies for the specified resource. */
 		void removeDependencies(const FileEntry* entry);
 
-		/**
-		 * @brief	Finds dependants resource for the specified resource entry and reimports them.
-		 */
+		/**	Finds dependants resource for the specified resource entry and reimports them. */
 		void reimportDependants(const Path& entryPath);
 
-		/**
-		 * @brief	Makes all library entry paths relative to the current resources folder.
-		 */
+		/**	Makes all library entry paths relative to the current resources folder. */
 		void makeEntriesRelative();
 
 		/**
-		 * @brief	Makes all library entry paths absolute by appending them to the current resources folder.
-		 *			Entries must have previously been made relative by calling ::makeEntriesRelative.
+		 * Makes all library entry paths absolute by appending them to the current resources folder. Entries must have
+		 * previously been made relative by calling makeEntriesRelative().
 		 */
 		void makeEntriesAbsolute();
 
-		/**  
-		 * @brief	Deletes all library entries.
-		 */
+		/** Deletes all library entries. */
 		void clearEntries();
 
 		static const WString LIBRARY_ENTRIES_FILENAME;
@@ -407,8 +368,6 @@ namespace BansheeEngine
 		UnorderedMap<String, Path> mUUIDToPath;
 	};
 
-	/**
-	 * @brief	Provides global access to the project library.
-	 */
+	/**	Provides easy access to ProjectLibrary. */
 	BS_ED_EXPORT ProjectLibrary& gProjectLibrary();
 }

+ 4 - 1
BansheeEditor/Include/BsProjectResourceMeta.h

@@ -26,7 +26,7 @@ namespace BansheeEngine
 		 *
 		 * @return	New project library resource meta data instance.
 		 */
-		static ProjectResourceMetaPtr create(const WString name, const String& uuid, UINT32 typeId, 
+		static ProjectResourceMetaPtr create(const WString& name, const String& uuid, UINT32 typeId, 
 			const ResourceMetaDataPtr& resourceMetaData);
 
 		/** Returns the name of the resource, unique within the file containing the resource. */
@@ -94,6 +94,9 @@ namespace BansheeEngine
 		/** Returns meta-data for all resources contained in the file represented by this meta-data object. */
 		const Vector<ProjectResourceMetaPtr>& getResourceMetaData() const { return mResourceMetaData; }
 
+		/** Removes all resource meta-data stored by this object. */
+		void clearResourceMetaData() { mResourceMetaData.clear(); }
+
 		/**	Returns the import options used for importing the resource this object is referencing. */
 		const ImportOptionsPtr& getImportOptions() const { return mImportOptions; }
 

+ 100 - 42
BansheeEditor/Source/BsProjectLibrary.cpp

@@ -359,12 +359,13 @@ namespace BansheeEngine
 		bs_delete(directory);
 	}
 
-	void ProjectLibrary::reimportResourceInternal(FileEntry* resource, const ImportOptionsPtr& importOptions, bool forceReimport)
+	void ProjectLibrary::reimportResourceInternal(FileEntry* fileEntry, const ImportOptionsPtr& importOptions,
+		bool forceReimport, bool pruneResourceMetas)
 	{
-		Path metaPath = resource->path;
+		Path metaPath = fileEntry->path;
 		metaPath.setFilename(metaPath.getWFilename() + L".meta");
 
-		if(resource->meta == nullptr)
+		if(fileEntry->meta == nullptr)
 		{
 			if(FileSystem::isFile(metaPath))
 			{
@@ -374,90 +375,144 @@ namespace BansheeEngine
 				if(loadedMeta != nullptr && loadedMeta->isDerivedFrom(ProjectFileMeta::getRTTIStatic()))
 				{
 					ProjectFileMetaPtr fileMeta = std::static_pointer_cast<ProjectFileMeta>(loadedMeta);
-					resource->meta = fileMeta;
+					fileEntry->meta = fileMeta;
 
-					auto& resourceMetas = resource->meta->getResourceMetaData();
+					auto& resourceMetas = fileEntry->meta->getResourceMetaData();
 
 					if (resourceMetas.size() > 0)
 					{
-						mUUIDToPath[resourceMetas[0]->getUUID()] = resource->path;
+						mUUIDToPath[resourceMetas[0]->getUUID()] = fileEntry->path;
 						for (auto& entry : resourceMetas)
-							mUUIDToPath[entry->getUUID()] = resource->path + entry->getUniqueName();
+							mUUIDToPath[entry->getUUID()] = fileEntry->path + entry->getUniqueName();
 					}
 				}
 			}
 		}
 
-		if (!isUpToDate(resource) || forceReimport)
+		if (!isUpToDate(fileEntry) || forceReimport)
 		{
 			// Note: If resource is native we just copy it to the internal folder. We could avoid the copy and 
 			// load the resource directly from the Resources folder but that requires complicating library code.
-			bool isNativeResource = isNative(resource->path);
+			bool isNativeResource = isNative(fileEntry->path);
 
 			ImportOptionsPtr curImportOptions = nullptr;
 			if (importOptions == nullptr && !isNativeResource)
 			{
-				if (resource->meta != nullptr)
-					curImportOptions = resource->meta->getImportOptions();
+				if (fileEntry->meta != nullptr)
+					curImportOptions = fileEntry->meta->getImportOptions();
 				else
-					curImportOptions = Importer::instance().createImportOptions(resource->path);
+					curImportOptions = Importer::instance().createImportOptions(fileEntry->path);
 			}
 			else
 				curImportOptions = importOptions;
 
-			HResource importedResource;
+			Vector<SubResource> importedResources;
 			if (isNativeResource)
 			{
 				// If meta exists make sure it is registered in the manifest before load, otherwise it will get assigned a new UUID.
 				// This can happen if library isn't properly saved before exiting the application.
-				if (resource->meta != nullptr)
+				if (fileEntry->meta != nullptr)
 				{
-					auto& resourceMetas = resource->meta->getResourceMetaData();
-					mResourceManifest->registerResource(resourceMetas[0]->getUUID(), resource->path);
+					auto& resourceMetas = fileEntry->meta->getResourceMetaData();
+					mResourceManifest->registerResource(resourceMetas[0]->getUUID(), fileEntry->path);
 				}
 
 				// Don't load dependencies because we don't need them, but also because they might not be in the manifest
 				// which would screw up their UUIDs.
-				importedResource = gResources().load(resource->path, false, false);
+				importedResources.push_back({ L"primary", gResources().load(fileEntry->path, false, false) });
 			}
 
-			if(resource->meta == nullptr)
+			if(fileEntry->meta == nullptr)
 			{
 				if (!isNativeResource)
-					importedResource = Importer::instance().import(resource->path, curImportOptions);
+					importedResources = Importer::instance().importAll(fileEntry->path, curImportOptions);
+
+				fileEntry->meta = ProjectFileMeta::create(curImportOptions);
 
-				if (importedResource != nullptr)
+				if(importedResources.size() > 0)
 				{
-					ResourceMetaDataPtr subMeta = importedResource->getMetaData();
-					UINT32 typeId = importedResource->getTypeId();
-					resource->meta = ProjectFileMeta::create(importedResource.getUUID(), typeId, subMeta, curImportOptions);
+					HResource primary = importedResources[0].value;
+
+					mUUIDToPath[primary.getUUID()] = fileEntry->path;
+					for(auto& entry : importedResources)
+					{
+						ResourceMetaDataPtr subMeta = entry.value->getMetaData();
+						UINT32 typeId = entry.value->getTypeId();
+						const String& UUID = entry.value.getUUID();
+
+						ProjectResourceMetaPtr resMeta = ProjectResourceMeta::create(entry.name, UUID, typeId, subMeta);
+						fileEntry->meta->add(resMeta);
+
+						mUUIDToPath[UUID] = fileEntry->path + entry.name;
+					}
 				}
-				else
-					resource->meta = ProjectFileMeta::create(importedResource.getUUID(), 0, nullptr, curImportOptions);
 
 				FileEncoder fs(metaPath);
-				fs.encode(resource->meta.get());
-
-				mUUIDToPath[resource->meta->getUUID()] = resource->path;
+				fs.encode(fileEntry->meta.get());
 			}
 			else
 			{
-				removeDependencies(resource);
+				removeDependencies(fileEntry);
 
 				if (!isNativeResource)
 				{
-					importedResource = gResources()._getResourceHandle(resource->meta->getUUID());
-					Importer::instance().reimport(importedResource, resource->path, curImportOptions);
+					Vector<SubResourceRaw> importedResourcesRaw = gImporter()._importAllRaw(fileEntry->path, curImportOptions);
+					Vector<ProjectResourceMetaPtr> existingResourceMetas = fileEntry->meta->getResourceMetaData();
+					fileEntry->meta->clearResourceMetaData();
+
+					for(auto& resEntry : importedResourcesRaw)
+					{
+						bool foundMeta = false;
+						for (auto iter = existingResourceMetas.begin(); iter != existingResourceMetas.end(); ++iter)
+						{
+							ProjectResourceMetaPtr metaEntry = *iter;
+
+							if(resEntry.name == metaEntry->getUniqueName())
+							{
+								HResource importedResource = gResources()._getResourceHandle(metaEntry->getUUID());
+								gResources().update(importedResource, resEntry.value);
+
+								importedResources.push_back({ resEntry.name, importedResource });
+								fileEntry->meta->add(metaEntry);
+
+								existingResourceMetas.erase(iter);
+								foundMeta = true;
+								break;
+							}
+						}
+
+						if(!foundMeta)
+						{
+							HResource importedResource = gResources()._createResourceHandle(resEntry.value);
+							importedResources.push_back({ resEntry.name, importedResource });
+
+							ResourceMetaDataPtr subMeta = resEntry.value->getMetaData();
+							UINT32 typeId = resEntry.value->getTypeId();
+							const String& UUID = importedResource.getUUID();
+
+							ProjectResourceMetaPtr resMeta = ProjectResourceMeta::create(resEntry.name, UUID, typeId, subMeta);
+							fileEntry->meta->add(resMeta);
+						}
+					}
+
+					// Keep resource metas that we are not currently using, in case they get restored so their references
+					// don't get broken
+					if(!pruneResourceMetas)
+					{
+						for (auto& entry : existingResourceMetas)
+							fileEntry->meta->add(entry);
+					}
 				}
 
-				resource->meta->mImportOptions = curImportOptions;
+				fileEntry->meta->mImportOptions = curImportOptions;
+
 				FileEncoder fs(metaPath);
-				fs.encode(resource->meta.get());
+				fs.encode(fileEntry->meta.get());
 			}
 
-			addDependencies(resource);
+			addDependencies(fileEntry);
 
-			if (importedResource != nullptr)
+			if (importedResources.size() > 0)
 			{
 				Path internalResourcesPath = mProjectFolder;
 				internalResourcesPath.append(INTERNAL_RESOURCES_DIR);
@@ -465,17 +520,20 @@ namespace BansheeEngine
 				if (!FileSystem::isDirectory(internalResourcesPath))
 					FileSystem::createDir(internalResourcesPath);
 
-				internalResourcesPath.setFilename(toWString(importedResource.getUUID()) + L".asset");
-				gResources().save(importedResource, internalResourcesPath, true);
+				for (auto& entry : importedResources)
+				{
+					internalResourcesPath.setFilename(toWString(entry.value.getUUID()) + L".asset");
+					gResources().save(entry.value, internalResourcesPath, true);
 
-				String uuid = importedResource.getUUID();
-				mResourceManifest->registerResource(uuid, internalResourcesPath);
+					String uuid = entry.value.getUUID();
+					mResourceManifest->registerResource(uuid, internalResourcesPath);
+				}
 			}
 
-			resource->lastUpdateTime = std::time(nullptr);
+			fileEntry->lastUpdateTime = std::time(nullptr);
 
-			onEntryImported(resource->path);
-			reimportDependants(resource->path);
+			onEntryImported(fileEntry->path);
+			reimportDependants(fileEntry->path);
 		}
 	}
 

+ 1 - 1
BansheeEditor/Source/BsProjectResourceMeta.cpp

@@ -11,7 +11,7 @@ namespace BansheeEngine
 
 	}
 
-	ProjectResourceMetaPtr ProjectResourceMeta::create(const WString name, const String& uuid, UINT32 typeId,
+	ProjectResourceMetaPtr ProjectResourceMeta::create(const WString& name, const String& uuid, UINT32 typeId,
 		const ResourceMetaDataPtr& resourceMetaData)
 	{
 		ProjectResourceMetaPtr meta = bs_shared_ptr_new<ProjectResourceMeta>(ConstructPrivately());