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 | |
10 | namespace 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 | } |