1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "BsCorePrerequisites.h"
6#include "Utility/BsModule.h"
7#include "Importer/BsSpecificImporter.h"
8#include "Threading/BsAsyncOp.h"
9
10namespace bs
11{
12 /** @addtogroup Importer
13 * @{
14 */
15
16 /**
17 * Contains a resource that was imported from a file that contains multiple resources (for example an animation from an
18 * FBX file).
19 */
20 struct BS_SCRIPT_EXPORT(m:Importer,pl:true,api:bsf) SubResource
21 {
22 String name; /**< Unique name of the sub-resource. */
23 BS_NORREF HResource value; /**< Contents of the sub-resource. */
24 };
25
26 /** Contains a group of resources imported from a single source file. */
27 struct BS_SCRIPT_EXPORT(m:Importer,api:bsf) MultiResource
28 {
29 BS_SCRIPT_EXPORT()
30 MultiResource() = default;
31
32 BS_SCRIPT_EXPORT()
33 MultiResource(const Vector<SubResource>& entries)
34 :entries(entries)
35 { }
36
37 BS_SCRIPT_EXPORT()
38 Vector<SubResource> entries;
39 };
40
41 /** Module responsible for importing various asset types and converting them to types usable by the engine. */
42 class BS_CORE_EXPORT BS_SCRIPT_EXPORT(m:Importer,api:bsf) Importer : public Module<Importer>
43 {
44 public:
45 Importer();
46 ~Importer();
47
48 /**
49 * Imports a resource at the specified location, and returns the loaded data. If file contains more than one
50 * resource only the primary resource is imported (for example an FBX a mesh would be imported, but animations
51 * ignored).
52 *
53 * @param[in] inputFilePath Pathname of the input file.
54 * @param[in] importOptions (optional) Options for controlling the import. Caller must ensure import options
55 * actually match the type of the importer used for the file type.
56 * @param[in] UUID Specific UUID to assign to the resource. If not specified a randomly generated
57 * UUID will be assigned.
58 * @return Imported resource.
59 *
60 * @see createImportOptions
61 * @note Thread safe.
62 */
63 BS_SCRIPT_EXPORT()
64 BS_NORREF HResource import(const Path& inputFilePath, SPtr<const ImportOptions> importOptions = nullptr,
65 const UUID& UUID = UUID::EMPTY);
66
67 /** @copydoc import */
68 template <class T>
69 ResourceHandle<T> import(const Path& inputFilePath, SPtr<const ImportOptions> importOptions = nullptr,
70 const UUID& UUID = UUID::EMPTY)
71 {
72 return static_resource_cast<T>(import(inputFilePath, importOptions, UUID));
73 }
74
75 /**
76 * Same as import(), except it imports a resource without blocking the main thread. The resulting resource will be
77 * placed in the returned AsyncOp object when the import ends.
78 */
79 BS_SCRIPT_EXPORT()
80 TAsyncOp<HResource> importAsync(const Path& inputFilePath, SPtr<const ImportOptions> importOptions = nullptr,
81 const UUID& UUID = UUID::EMPTY);
82
83 /**
84 * Imports a resource at the specified location, and returns the loaded data. This method returns all imported
85 * resources, which is relevant for files that can contain multiple resources (for example an FBX which may contain
86 * both a mesh and animations).
87 *
88 * @param[in] inputFilePath Pathname of the input file.
89 * @param[in] importOptions (optional) Options for controlling the import. Caller must ensure import options
90 * actually match the type of the importer used for the file type.
91 * @return A list of all imported resources. The primary resource is always the first returned
92 * resource.
93 *
94 * @see createImportOptions
95 * @note Thread safe.
96 */
97 BS_SCRIPT_EXPORT()
98 SPtr<MultiResource> importAll(const Path& inputFilePath, SPtr<const ImportOptions> importOptions = nullptr);
99
100 /**
101 * Same as importAll(), except it imports a resource without blocking the main thread. The returned AsyncOp will
102 * contain a list of the imported resources, after the import ends.
103 */
104 BS_SCRIPT_EXPORT()
105 TAsyncOp<SPtr<MultiResource>> importAllAsync(const Path& inputFilePath,
106 SPtr<const ImportOptions> importOptions = nullptr);
107
108 /**
109 * Automatically detects the importer needed for the provided file and returns valid type of import options for
110 * that importer.
111 *
112 * @param[in] inputFilePath Pathname of the input file.
113 *
114 * @return The new import options. Null is returned if the file path is not valid, or if a
115 * valid importer cannot be found for the specified file.
116 *
117 * @note
118 * You will need to type cast the importer options to a valid type, taking into consideration exact importer you
119 * expect to be used for this file type. If you don't use a proper import options type, an exception will be thrown
120 * during import.
121 */
122 SPtr<ImportOptions> createImportOptions(const Path& inputFilePath);
123
124 /** @copydoc createImportOptions */
125 template<class T>
126 SPtr<T> createImportOptions(const Path& inputFilePath)
127 {
128 return std::static_pointer_cast<T>(createImportOptions(inputFilePath));
129 }
130
131 /**
132 * Checks if we can import a file with the specified extension.
133 *
134 * @param[in] extension The extension without the leading dot.
135 */
136 BS_SCRIPT_EXPORT()
137 bool supportsFileType(const String& extension) const;
138
139 /**
140 * Checks if we can import a file with the specified magic number.
141 *
142 * @param[in] magicNumber The buffer containing the magic number.
143 * @param[in] magicNumSize Size of the magic number buffer.
144 */
145 bool supportsFileType(const UINT8* magicNumber, UINT32 magicNumSize) const;
146
147 /** @name Internal
148 * @{
149 */
150
151 /**
152 * Registers a new asset importer for a specific set of extensions (as determined by the implementation). If an
153 * asset importer for one or multiple extensions already exists, it is removed and replaced with this one.
154 *
155 * @param[in] importer The importer that is able to handle import of certain type of files.
156 *
157 * @note This method should only be called by asset importers themselves on startup. Importer takes ownership
158 * of the provided pointer and will release it. Assumes it is allocated using the general allocator.
159 */
160 void _registerAssetImporter(SpecificImporter* importer);
161
162 /** Alternative to import() which doesn't create a resource handle, but instead returns a raw resource pointer. */
163 SPtr<Resource> _import(const Path& inputFilePath,
164 SPtr<const ImportOptions> importOptions = nullptr);
165
166 /** Alternative to importAll() which doesn't create resource handles, but instead returns raw resource pointers. */
167 Vector<SubResourceRaw> _importAll(const Path& inputFilePath,
168 SPtr<const ImportOptions> importOptions = nullptr);
169
170 /** @} */
171 private:
172 /**
173 * Searches available importers and attempts to find one that can import the file of the provided type. Returns null
174 * if one cannot be found.
175 */
176 SpecificImporter* getImporterForFile(const Path& inputFilePath) const;
177
178 /**
179 * Queues resource for import on a secondary thread. The system will execute the import as soon as possible
180 * and write the resulting resource to the provided @p op object.
181 */
182 template<class ReturnType>
183 void queueForImport(SpecificImporter* importer, const Path& inputFilePath,
184 const SPtr<const ImportOptions>& importOptions, const UUID& uuid, TAsyncOp<ReturnType>& op);
185
186 /**
187 * Prepares for import of a file at the specified path. Returns the type of importer the file can be imported with,
188 * or null if the file isn't valid or is of unsupported type. Also creates the default set of import options unless
189 * already provided.
190 */
191 SpecificImporter* prepareForImport(const Path& filePath, SPtr<const ImportOptions>& importOptions) const;
192
193 /**
194 * Checks is the specific importer currently importing something asynchronously. If the importer doesn't support
195 * multiple threads then the method will wait until async. import completes, register a new task (so further
196 * calls to the same method appropriately wait), and return an index of the task. The caller must check to
197 * remove the task when import is done.
198 */
199 UINT64 waitForAsync(SpecificImporter* importer);
200
201 Vector<SpecificImporter*> mAssetImporters;
202
203 SPtr<AsyncOpSyncData> mAsyncOpSyncData;
204 mutable Mutex mLastTaskMutex;
205 mutable Signal mTaskCompleted;
206 mutable Mutex mImportMutex;
207 mutable UINT64 mTaskId = 0;
208
209 /** Information about a task queued for a specific import operation. */
210 struct QueuedTask
211 {
212 QueuedTask() = default;
213
214 QueuedTask(SPtr<Task> task, UINT64 id)
215 :task(std::move(task)), id(id)
216 { }
217
218 SPtr<Task> task;
219 UINT64 id;
220 };
221
222 UnorderedMap<SpecificImporter*, QueuedTask> mLastQueuedTask;
223 };
224
225 /** Provides easier access to Importer. */
226 BS_CORE_EXPORT Importer& gImporter();
227
228 /** @} */
229}