summaryrefslogtreecommitdiffstats
path: root/3rdparty/assimp/code/BaseImporter.h
blob: 39ac3bf5841a4ef44645ed85410dd7a799bf9c69 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
/*
Open Asset Import Library (ASSIMP)
----------------------------------------------------------------------

Copyright (c) 2006-2010, ASSIMP Development Team
All rights reserved.

Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:

* Redistributions of source code must retain the above
  copyright notice, this list of conditions and the
  following disclaimer.

* Redistributions in binary form must reproduce the above
  copyright notice, this list of conditions and the
  following disclaimer in the documentation and/or other
  materials provided with the distribution.

* Neither the name of the ASSIMP team, nor the names of its
  contributors may be used to endorse or promote products
  derived from this software without specific prior
  written permission of the ASSIMP Development Team.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

----------------------------------------------------------------------
*/

/** @file Definition of the base class for all importer worker classes. */
#ifndef INCLUDED_AI_BASEIMPORTER_H
#define INCLUDED_AI_BASEIMPORTER_H

#include "Exceptional.h"

#include <string>
#include <map>
#include <vector>
#include "./../include/aiTypes.h"

struct aiScene;

namespace Assimp    {

class IOSystem;
class Importer;
class BaseImporter;
class BaseProcess;
class SharedPostProcessInfo;
class IOStream;

// utility to do char4 to uint32 in a portable manner
#define AI_MAKE_MAGIC(string) ((uint32_t)((string[0] << 24) + \
    (string[1] << 16) + (string[2] << 8) + string[3]))

// ---------------------------------------------------------------------------
template <typename T>
struct ScopeGuard
{
    ScopeGuard(T* obj) : obj(obj), mdismiss() {}
    ~ScopeGuard () throw() {
        if (!mdismiss) {
            delete obj;
        }
        obj = NULL;
    }

    T* dismiss() {
        mdismiss=true;
        return obj;
    }

    operator T*() {
        return obj;
    }

    T* operator -> () {
        return obj;
    }

private:
    T* obj;
    bool mdismiss;
};

//! @cond never
// ---------------------------------------------------------------------------
/** @brief Internal PIMPL implementation for Assimp::Importer
 *
 *  Using this idiom here allows us to drop the dependency from
 *  std::vector and std::map in the public headers. Furthermore we are dropping
 *  any STL interface problems caused by mismatching STL settings. All
 *  size calculation are now done by us, not the app heap. */
class ASSIMP_API ImporterPimpl
{
public:

    // Data type to store the key hash
    typedef unsigned int KeyType;

    // typedefs for our three configuration maps.
    // We don't need more, so there is no need for a generic solution
    typedef std::map<KeyType, int> IntPropertyMap;
    typedef std::map<KeyType, float> FloatPropertyMap;
    typedef std::map<KeyType, std::string> StringPropertyMap;

public:

    /** IO handler to use for all file accesses. */
    IOSystem* mIOHandler;
    bool mIsDefaultHandler;

    /** Progress handler for feedback. */
    ProgressHandler* mProgressHandler;
    bool mIsDefaultProgressHandler;

    /** Format-specific importer worker objects - one for each format we can read.*/
    std::vector<BaseImporter*> mImporter;

    /** Post processing steps we can apply at the imported data. */
    std::vector<BaseProcess*> mPostProcessingSteps;

    /** The imported data, if ReadFile() was successful, NULL otherwise. */
    aiScene* mScene;

    /** The error description, if there was one. */
    std::string mErrorString;

    /** List of integer properties */
    IntPropertyMap mIntProperties;

    /** List of floating-point properties */
    FloatPropertyMap mFloatProperties;

    /** List of string properties */
    StringPropertyMap mStringProperties;

    /** Used for testing - extra verbose mode causes the ValidateDataStructure-Step
     *  to be executed before and after every single postprocess step */
    bool bExtraVerbose;

    /** Used by post-process steps to share data */
    SharedPostProcessInfo* mPPShared;
};
//! @endcond

// ---------------------------------------------------------------------------
/** FOR IMPORTER PLUGINS ONLY: The BaseImporter defines a common interface
 *  for all importer worker classes.
 *
 * The interface defines two functions: CanRead() is used to check if the
 * importer can handle the format of the given file. If an implementation of
 * this function returns true, the importer then calls ReadFile() which
 * imports the given file. ReadFile is not overridable, it just calls
 * InternReadFile() and catches any ImportErrorException that might occur.
 */
class ASSIMP_API BaseImporter
{
    friend class Importer;

protected:

    /** Constructor to be privately used by #Importer */
    BaseImporter();

    /** Destructor, private as well */
    virtual ~BaseImporter();

public:
    // -------------------------------------------------------------------
    /** Returns whether the class can handle the format of the given file.
     *
     * The implementation should be as quick as possible. A check for
     * the file extension is enough. If no suitable loader is found with
     * this strategy, CanRead() is called again, the 'checkSig' parameter
     * set to true this time. Now the implementation is expected to
     * perform a full check of the file structure, possibly searching the
     * first bytes of the file for magic identifiers or keywords.
     *
     * @param pFile Path and file name of the file to be examined.
     * @param pIOHandler The IO handler to use for accessing any file.
     * @param checkSig Set to true if this method is called a second time.
     *   This time, the implementation may take more time to examine the
     *   contents of the file to be loaded for magic bytes, keywords, etc
     *   to be able to load files with unknown/not existent file extensions.
     * @return true if the class can read this file, false if not.
     */
    virtual bool CanRead(
        const std::string& pFile,
        IOSystem* pIOHandler,
        bool checkSig
        ) const = 0;

    // -------------------------------------------------------------------
    /** Imports the given file and returns the imported data.
     * If the import succeeds, ownership of the data is transferred to
     * the caller. If the import fails, NULL is returned. The function
     * takes care that any partially constructed data is destroyed
     * beforehand.
     *
     * @param pImp #Importer object hosting this loader.
     * @param pFile Path of the file to be imported.
     * @param pIOHandler IO-Handler used to open this and possible other files.
     * @return The imported data or NULL if failed. If it failed a
     * human-readable error description can be retrieved by calling
     * GetErrorText()
     *
     * @note This function is not intended to be overridden. Implement
     * InternReadFile() to do the import. If an exception is thrown somewhere
     * in InternReadFile(), this function will catch it and transform it into
     *  a suitable response to the caller.
     */
    aiScene* ReadFile(
        const Importer* pImp,
        const std::string& pFile,
        IOSystem* pIOHandler
        );

    // -------------------------------------------------------------------
    /** Returns the error description of the last error that occured.
     * @return A description of the last error that occured. An empty
     * string if there was no error.
     */
    const std::string& GetErrorText() const {
        return mErrorText;
    }

    // -------------------------------------------------------------------
    /** Called prior to ReadFile().
     * The function is a request to the importer to update its configuration
     * basing on the Importer's configuration property list.
     * @param pImp Importer instance
     */
    virtual void SetupProperties(
        const Importer* pImp
        );

protected:

    // -------------------------------------------------------------------
    /** Called by Importer::GetExtensionList() for each loaded importer.
     *  Implementations are expected to insert() all file extensions
     *  handled by them into the extension set. A loader capable of
     *  reading certain files with the extension BLA would place the
     *  string bla (lower-case!) in the output set.
     * @param extensions Output set. */
    virtual void GetExtensionList(
        std::set<std::string>& extensions
        ) = 0;

    // -------------------------------------------------------------------
    /** Imports the given file into the given scene structure. The
     * function is expected to throw an ImportErrorException if there is
     * an error. If it terminates normally, the data in aiScene is
     * expected to be correct. Override this function to implement the
     * actual importing.
     * <br>
     *  The output scene must meet the following requirements:<br>
     * <ul>
     * <li>At least a root node must be there, even if its only purpose
     *     is to reference one mesh.</li>
     * <li>aiMesh::mPrimitiveTypes may be 0. The types of primitives
     *   in the mesh are determined automatically in this case.</li>
     * <li>the vertex data is stored in a pseudo-indexed "verbose" format.
     *   In fact this means that every vertex that is referenced by
     *   a face is unique. Or the other way round: a vertex index may
     *   not occur twice in a single aiMesh.</li>
     * <li>aiAnimation::mDuration may be -1. Assimp determines the length
     *   of the animation automatically in this case as the length of
     *   the longest animation channel.</li>
     * <li>aiMesh::mBitangents may be NULL if tangents and normals are
     *   given. In this case bitangents are computed as the cross product
     *   between normal and tangent.</li>
     * <li>There needn't be a material. If none is there a default material
     *   is generated. However, it is recommended practice for loaders
     *   to generate a default material for yourself that matches the
     *   default material setting for the file format better than Assimp's
     *   generic default material. Note that default materials *should*
     *   be named AI_DEFAULT_MATERIAL_NAME if they're just color-shaded
     *   or AI_DEFAULT_TEXTURED_MATERIAL_NAME if they define a (dummy)
     *   texture. </li>
     * </ul>
     * If the AI_SCENE_FLAGS_INCOMPLETE-Flag is <b>not</b> set:<ul>
     * <li> at least one mesh must be there</li>
     * <li> there may be no meshes with 0 vertices or faces</li>
     * </ul>
     * This won't be checked (except by the validation step): Assimp will
     * crash if one of the conditions is not met!
     *
     * @param pFile Path of the file to be imported.
     * @param pScene The scene object to hold the imported data.
     * NULL is not a valid parameter.
     * @param pIOHandler The IO handler to use for any file access.
     * NULL is not a valid parameter. */
    virtual void InternReadFile(
        const std::string& pFile,
        aiScene* pScene,
        IOSystem* pIOHandler
        ) = 0;

public: // static utilities

    // -------------------------------------------------------------------
    /** A utility for CanRead().
     *
     *  The function searches the header of a file for a specific token
     *  and returns true if this token is found. This works for text
     *  files only. There is a rudimentary handling of UNICODE files.
     *  The comparison is case independent.
     *
     *  @param pIOSystem IO System to work with
     *  @param file File name of the file
     *  @param tokens List of tokens to search for
     *  @param numTokens Size of the token array
     *  @param searchBytes Number of bytes to be searched for the tokens.
     */
    static bool SearchFileHeaderForToken(
        IOSystem* pIOSystem,
        const std::string&    file,
        const char** tokens,
        unsigned int numTokens,
        unsigned int searchBytes = 200);


    // -------------------------------------------------------------------
    /** @brief Check whether a file has a specific file extension
     *  @param pFile Input file
     *  @param ext0 Extension to check for. Lowercase characters only, no dot!
     *  @param ext1 Optional second extension
     *  @param ext2 Optional third extension
     *  @note Case-insensitive
     */
    static bool SimpleExtensionCheck (
        const std::string& pFile,
        const char* ext0,
        const char* ext1 = NULL,
        const char* ext2 = NULL);

    // -------------------------------------------------------------------
    /** @brief Extract file extension from a string
     *  @param pFile Input file
     *  @return Extension without trailing dot, all lowercase
     */
    static std::string GetExtension (
        const std::string& pFile);

    // -------------------------------------------------------------------
    /** @brief Check whether a file starts with one or more magic tokens
     *  @param pFile Input file
     *  @param pIOHandler IO system to be used
     *  @param magic n magic tokens
     *  @params num Size of magic
     *  @param offset Offset from file start where tokens are located
     *  @param Size of one token, in bytes. Maximally 16 bytes.
     *  @return true if one of the given tokens was found
     *
     *  @note For convinence, the check is also performed for the
     *  byte-swapped variant of all tokens (big endian). Only for
     *  tokens of size 2,4.
     */
    static bool CheckMagicToken(
        IOSystem* pIOHandler,
        const std::string& pFile,
        const void* magic,
        unsigned int num,
        unsigned int offset = 0,
        unsigned int size   = 4);

    // -------------------------------------------------------------------
    /** An utility for all text file loaders. It converts a file to our
     *   UTF8 character set. Errors are reported, but ignored.
     *
     *  @param data File buffer to be converted to UTF8 data. The buffer
     *  is resized as appropriate. */
    static void ConvertToUTF8(
        std::vector<char>& data);

    // -------------------------------------------------------------------
    /** Utility for text file loaders which copies the contents of the
     *  file into a memory buffer and converts it to our UTF8
     *  representation.
     *  @param stream Stream to read from.
     *  @param data Output buffer to be resized and filled with the
     *   converted text file data. The buffer is terminated with
     *   a binary 0. */
    static void TextFileToBuffer(
        IOStream* stream,
        std::vector<char>& data);

protected:

    /** Error description in case there was one. */
    std::string mErrorText;

    /** Currently set progress handler */
    ProgressHandler* progress;
};

struct BatchData;

// ---------------------------------------------------------------------------
/** FOR IMPORTER PLUGINS ONLY: A helper class for the pleasure of importers
 *  which need to load many extern meshes recursively.
 *
 *  The class uses several threads to load these meshes (or at least it
 *  could, this has not yet been implemented at the moment).
 *
 *  @note The class may not be used by more than one thread*/
class ASSIMP_API BatchLoader
{
    // friend of Importer

public:

    //! @cond never
    // -------------------------------------------------------------------
    /** Wraps a full list of configuration properties for an importer.
     *  Properties can be set using SetGenericProperty */
    struct PropertyMap
    {
        ImporterPimpl::IntPropertyMap     ints;
        ImporterPimpl::FloatPropertyMap   floats;
        ImporterPimpl::StringPropertyMap  strings;

        bool operator == (const PropertyMap& prop) const {
            // fixme: really isocpp? gcc complains
            return ints == prop.ints && floats == prop.floats && strings == prop.strings;
        }

        bool empty () const {
            return ints.empty() && floats.empty() && strings.empty();
        }
    };
    //! @endcond

public:


    // -------------------------------------------------------------------
    /** Construct a batch loader from a given IO system to be used
     *  to acess external files */
    BatchLoader(IOSystem* pIO);
    ~BatchLoader();


    // -------------------------------------------------------------------
    /** Add a new file to the list of files to be loaded.
     *  @param file File to be loaded
     *  @param steps Post-processing steps to be executed on the file
     *  @param map Optional configuration properties
     *  @return 'Load request channel' - an unique ID that can later
     *    be used to access the imported file data.
     *  @see GetImport */
    unsigned int AddLoadRequest    (
        const std::string& file,
        unsigned int steps = 0,
        const PropertyMap* map = NULL
        );


    // -------------------------------------------------------------------
    /** Get an imported scene.
     *  This polls the import from the internal request list.
     *  If an import is requested several times, this function
     *  can be called several times, too.
     *
     *  @param which LRWC returned by AddLoadRequest().
     *  @return NULL if there is no scene with this file name
     *  in the queue of the scene hasn't been loaded yet. */
    aiScene* GetImport(
        unsigned int which
        );


    // -------------------------------------------------------------------
    /** Waits until all scenes have been loaded. This returns
     *  immediately if no scenes are queued.*/
    void LoadAll();

private:

    // No need to have that in the public API ...
    BatchData* data;
};

} // end of namespace Assimp

#endif // AI_BASEIMPORTER_H_INC