1/*
2Open Asset Import Library (assimp)
3----------------------------------------------------------------------
4
5Copyright (c) 2006-2017, assimp team
6
7All rights reserved.
8
9Redistribution and use of this software in source and binary forms,
10with or without modification, are permitted provided that the
11following conditions are met:
12
13* Redistributions of source code must retain the above
14 copyright notice, this list of conditions and the
15 following disclaimer.
16
17* Redistributions in binary form must reproduce the above
18 copyright notice, this list of conditions and the
19 following disclaimer in the documentation and/or other
20 materials provided with the distribution.
21
22* Neither the name of the assimp team, nor the names of its
23 contributors may be used to endorse or promote products
24 derived from this software without specific prior
25 written permission of the assimp team.
26
27THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39----------------------------------------------------------------------
40*/
41
42/** @file Declares a helper class, "SceneCombiner" providing various
43 * utilities to merge scenes.
44 */
45#ifndef AI_SCENE_COMBINER_H_INC
46#define AI_SCENE_COMBINER_H_INC
47
48#include <assimp/ai_assert.h>
49#include <assimp/types.h>
50#include <assimp/Defines.h>
51#include <stddef.h>
52#include <set>
53#include <list>
54#include <stdint.h>
55
56#include <vector>
57
58struct aiScene;
59struct aiNode;
60struct aiMaterial;
61struct aiTexture;
62struct aiCamera;
63struct aiLight;
64struct aiMetadata;
65struct aiBone;
66struct aiMesh;
67struct aiAnimation;
68struct aiNodeAnim;
69
70namespace Assimp {
71
72// ---------------------------------------------------------------------------
73/** \brief Helper data structure for SceneCombiner.
74 *
75 * Describes to which node a scene must be attached to.
76 */
77struct AttachmentInfo
78{
79 AttachmentInfo()
80 : scene (NULL)
81 , attachToNode (NULL)
82 {}
83
84 AttachmentInfo(aiScene* _scene, aiNode* _attachToNode)
85 : scene (_scene)
86 , attachToNode (_attachToNode)
87 {}
88
89 aiScene* scene;
90 aiNode* attachToNode;
91};
92
93// ---------------------------------------------------------------------------
94struct NodeAttachmentInfo
95{
96 NodeAttachmentInfo()
97 : node (NULL)
98 , attachToNode (NULL)
99 , resolved (false)
100 , src_idx (SIZE_MAX)
101 {}
102
103 NodeAttachmentInfo(aiNode* _scene, aiNode* _attachToNode,size_t idx)
104 : node (_scene)
105 , attachToNode (_attachToNode)
106 , resolved (false)
107 , src_idx (idx)
108 {}
109
110 aiNode* node;
111 aiNode* attachToNode;
112 bool resolved;
113 size_t src_idx;
114};
115
116// ---------------------------------------------------------------------------
117/** @def AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES
118 * Generate unique names for all named scene items
119 */
120#define AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES 0x1
121
122/** @def AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES
123 * Generate unique names for materials, too.
124 * This is not absolutely required to pass the validation.
125 */
126#define AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES 0x2
127
128/** @def AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY
129 * Use deep copies of duplicate scenes
130 */
131#define AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY 0x4
132
133/** @def AI_INT_MERGE_SCENE_RESOLVE_CROSS_ATTACHMENTS
134 * If attachment nodes are not found in the given master scene,
135 * search the other imported scenes for them in an any order.
136 */
137#define AI_INT_MERGE_SCENE_RESOLVE_CROSS_ATTACHMENTS 0x8
138
139/** @def AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY
140 * Can be combined with AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES.
141 * Unique names are generated, but only if this is absolutely
142 * required to avoid name conflicts.
143 */
144#define AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY 0x10
145
146typedef std::pair<aiBone*,unsigned int> BoneSrcIndex;
147
148// ---------------------------------------------------------------------------
149/** @brief Helper data structure for SceneCombiner::MergeBones.
150 */
151struct BoneWithHash : public std::pair<uint32_t,aiString*> {
152 std::vector<BoneSrcIndex> pSrcBones;
153};
154
155// ---------------------------------------------------------------------------
156/** @brief Utility for SceneCombiner
157 */
158struct SceneHelper
159{
160 SceneHelper ()
161 : scene (NULL)
162 , idlen (0)
163 {
164 id[0] = 0;
165 }
166
167 explicit SceneHelper (aiScene* _scene)
168 : scene (_scene)
169 , idlen (0)
170 {
171 id[0] = 0;
172 }
173
174 AI_FORCE_INLINE aiScene* operator-> () const
175 {
176 return scene;
177 }
178
179 // scene we're working on
180 aiScene* scene;
181
182 // prefix to be added to all identifiers in the scene ...
183 char id [32];
184
185 // and its strlen()
186 unsigned int idlen;
187
188 // hash table to quickly check whether a name is contained in the scene
189 std::set<unsigned int> hashes;
190};
191
192// ---------------------------------------------------------------------------
193/** \brief Static helper class providing various utilities to merge two
194 * scenes. It is intended as internal utility and NOT for use by
195 * applications.
196 *
197 * The class is currently being used by various postprocessing steps
198 * and loaders (ie. LWS).
199 */
200class ASSIMP_API SceneCombiner {
201 // class cannot be instanced
202 SceneCombiner() {
203 // empty
204 }
205
206 ~SceneCombiner() {
207 // empty
208 }
209
210public:
211 // -------------------------------------------------------------------
212 /** Merges two or more scenes.
213 *
214 * @param dest Receives a pointer to the destination scene. If the
215 * pointer doesn't point to NULL when the function is called, the
216 * existing scene is cleared and refilled.
217 * @param src Non-empty list of scenes to be merged. The function
218 * deletes the input scenes afterwards. There may be duplicate scenes.
219 * @param flags Combination of the AI_INT_MERGE_SCENE flags defined above
220 */
221 static void MergeScenes(aiScene** dest,std::vector<aiScene*>& src,
222 unsigned int flags = 0);
223
224 // -------------------------------------------------------------------
225 /** Merges two or more scenes and attaches all scenes to a specific
226 * position in the node graph of the master scene.
227 *
228 * @param dest Receives a pointer to the destination scene. If the
229 * pointer doesn't point to NULL when the function is called, the
230 * existing scene is cleared and refilled.
231 * @param master Master scene. It will be deleted afterwards. All
232 * other scenes will be inserted in its node graph.
233 * @param src Non-empty list of scenes to be merged along with their
234 * corresponding attachment points in the master scene. The function
235 * deletes the input scenes afterwards. There may be duplicate scenes.
236 * @param flags Combination of the AI_INT_MERGE_SCENE flags defined above
237 */
238 static void MergeScenes(aiScene** dest, aiScene* master,
239 std::vector<AttachmentInfo>& src,
240 unsigned int flags = 0);
241
242 // -------------------------------------------------------------------
243 /** Merges two or more meshes
244 *
245 * The meshes should have equal vertex formats. Only components
246 * that are provided by ALL meshes will be present in the output mesh.
247 * An exception is made for VColors - they are set to black. The
248 * meshes should have the same material indices, too. The output
249 * material index is always the material index of the first mesh.
250 *
251 * @param dest Destination mesh. Must be empty.
252 * @param flags Currently no parameters
253 * @param begin First mesh to be processed
254 * @param end Points to the mesh after the last mesh to be processed
255 */
256 static void MergeMeshes(aiMesh** dest,unsigned int flags,
257 std::vector<aiMesh*>::const_iterator begin,
258 std::vector<aiMesh*>::const_iterator end);
259
260 // -------------------------------------------------------------------
261 /** Merges two or more bones
262 *
263 * @param out Mesh to receive the output bone list
264 * @param flags Currently no parameters
265 * @param begin First mesh to be processed
266 * @param end Points to the mesh after the last mesh to be processed
267 */
268 static void MergeBones(aiMesh* out,std::vector<aiMesh*>::const_iterator it,
269 std::vector<aiMesh*>::const_iterator end);
270
271 // -------------------------------------------------------------------
272 /** Merges two or more materials
273 *
274 * The materials should be complementary as much as possible. In case
275 * of a property present in different materials, the first occurrence
276 * is used.
277 *
278 * @param dest Destination material. Must be empty.
279 * @param begin First material to be processed
280 * @param end Points to the material after the last material to be processed
281 */
282 static void MergeMaterials(aiMaterial** dest,
283 std::vector<aiMaterial*>::const_iterator begin,
284 std::vector<aiMaterial*>::const_iterator end);
285
286 // -------------------------------------------------------------------
287 /** Builds a list of uniquely named bones in a mesh list
288 *
289 * @param asBones Receives the output list
290 * @param it First mesh to be processed
291 * @param end Last mesh to be processed
292 */
293 static void BuildUniqueBoneList(std::list<BoneWithHash>& asBones,
294 std::vector<aiMesh*>::const_iterator it,
295 std::vector<aiMesh*>::const_iterator end);
296
297 // -------------------------------------------------------------------
298 /** Add a name prefix to all nodes in a scene.
299 *
300 * @param Current node. This function is called recursively.
301 * @param prefix Prefix to be added to all nodes
302 * @param len STring length
303 */
304 static void AddNodePrefixes(aiNode* node, const char* prefix,
305 unsigned int len);
306
307 // -------------------------------------------------------------------
308 /** Add an offset to all mesh indices in a node graph
309 *
310 * @param Current node. This function is called recursively.
311 * @param offset Offset to be added to all mesh indices
312 */
313 static void OffsetNodeMeshIndices (aiNode* node, unsigned int offset);
314
315 // -------------------------------------------------------------------
316 /** Attach a list of node graphs to well-defined nodes in a master
317 * graph. This is a helper for MergeScenes()
318 *
319 * @param master Master scene
320 * @param srcList List of source scenes along with their attachment
321 * points. If an attachment point is NULL (or does not exist in
322 * the master graph), a scene is attached to the root of the master
323 * graph (as an additional child node)
324 * @duplicates List of duplicates. If elem[n] == n the scene is not
325 * a duplicate. Otherwise elem[n] links scene n to its first occurrence.
326 */
327 static void AttachToGraph ( aiScene* master,
328 std::vector<NodeAttachmentInfo>& srcList);
329
330 static void AttachToGraph (aiNode* attach,
331 std::vector<NodeAttachmentInfo>& srcList);
332
333
334 // -------------------------------------------------------------------
335 /** Get a deep copy of a scene
336 *
337 * @param dest Receives a pointer to the destination scene
338 * @param src Source scene - remains unmodified.
339 */
340 static void CopyScene(aiScene** dest,const aiScene* source,bool allocate = true);
341
342
343 // -------------------------------------------------------------------
344 /** Get a flat copy of a scene
345 *
346 * Only the first hierarchy layer is copied. All pointer members of
347 * aiScene are shared by source and destination scene. If the
348 * pointer doesn't point to NULL when the function is called, the
349 * existing scene is cleared and refilled.
350 * @param dest Receives a pointer to the destination scene
351 * @param src Source scene - remains unmodified.
352 */
353 static void CopySceneFlat(aiScene** dest,const aiScene* source);
354
355
356 // -------------------------------------------------------------------
357 /** Get a deep copy of a mesh
358 *
359 * @param dest Receives a pointer to the destination mesh
360 * @param src Source mesh - remains unmodified.
361 */
362 static void Copy (aiMesh** dest, const aiMesh* src);
363
364 // similar to Copy():
365 static void Copy (aiMaterial** dest, const aiMaterial* src);
366 static void Copy (aiTexture** dest, const aiTexture* src);
367 static void Copy (aiAnimation** dest, const aiAnimation* src);
368 static void Copy (aiCamera** dest, const aiCamera* src);
369 static void Copy (aiBone** dest, const aiBone* src);
370 static void Copy (aiLight** dest, const aiLight* src);
371 static void Copy (aiNodeAnim** dest, const aiNodeAnim* src);
372 static void Copy (aiMetadata** dest, const aiMetadata* src);
373
374 // recursive, of course
375 static void Copy (aiNode** dest, const aiNode* src);
376
377
378private:
379
380 // -------------------------------------------------------------------
381 // Same as AddNodePrefixes, but with an additional check
382 static void AddNodePrefixesChecked(aiNode* node, const char* prefix,
383 unsigned int len,
384 std::vector<SceneHelper>& input,
385 unsigned int cur);
386
387 // -------------------------------------------------------------------
388 // Add node identifiers to a hashing set
389 static void AddNodeHashes(aiNode* node, std::set<unsigned int>& hashes);
390
391
392 // -------------------------------------------------------------------
393 // Search for duplicate names
394 static bool FindNameMatch(const aiString& name,
395 std::vector<SceneHelper>& input, unsigned int cur);
396};
397
398}
399
400#endif // !! AI_SCENE_COMBINER_H_INC
401