Coverage Report

Created: 2026-01-07 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/assimp/code/Common/Exporter.cpp
Line
Count
Source
1
/*
2
---------------------------------------------------------------------------
3
Open Asset Import Library (assimp)
4
---------------------------------------------------------------------------
5
6
Copyright (c) 2006-2025, assimp team
7
8
All rights reserved.
9
10
Redistribution and use of this software in source and binary forms,
11
with or without modification, are permitted provided that the following
12
conditions are met:
13
14
* Redistributions of source code must retain the above
15
  copyright notice, this list of conditions and the
16
  following disclaimer.
17
18
* Redistributions in binary form must reproduce the above
19
  copyright notice, this list of conditions and the
20
  following disclaimer in the documentation and/or other
21
  materials provided with the distribution.
22
23
* Neither the name of the assimp team, nor the names of its
24
  contributors may be used to endorse or promote products
25
  derived from this software without specific prior
26
  written permission of the assimp team.
27
28
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
---------------------------------------------------------------------------
40
*/
41
42
/** @file Exporter.cpp
43
44
Assimp export interface. While it's public interface bears many similarities
45
to the import interface (in fact, it is largely symmetric), the internal
46
implementations differs a lot. Exporters are considered stateless and are
47
simple callbacks which we maintain in a global list along with their
48
description strings.
49
50
Here we implement only the C++ interface (Assimp::Exporter).
51
*/
52
53
#ifndef ASSIMP_BUILD_NO_EXPORT
54
55
#include <assimp/BlobIOSystem.h>
56
#include <assimp/SceneCombiner.h>
57
#include <assimp/DefaultIOSystem.h>
58
#include <assimp/Exporter.hpp>
59
#include <assimp/mesh.h>
60
#include <assimp/postprocess.h>
61
#include <assimp/scene.h>
62
#include <assimp/Exceptional.h>
63
64
#include "Common/DefaultProgressHandler.h"
65
#include "Common/BaseProcess.h"
66
#include "Common/ScenePrivate.h"
67
#include "PostProcessing/CalcTangentsProcess.h"
68
#include "PostProcessing/MakeVerboseFormat.h"
69
#include "PostProcessing/JoinVerticesProcess.h"
70
#include "PostProcessing/ConvertToLHProcess.h"
71
#include "PostProcessing/PretransformVertices.h"
72
73
#include <memory>
74
75
namespace Assimp {
76
77
#ifdef _MSC_VER
78
#    pragma warning( disable : 4800 )
79
#endif // _MSC_VER
80
81
82
// PostStepRegistry.cpp
83
void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out);
84
85
// ------------------------------------------------------------------------------------------------
86
// Exporter worker function prototypes. Do not use const, because some exporter need to convert
87
// the scene temporary
88
#ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
89
void ExportSceneCollada(const char*,IOSystem*, const aiScene*, const ExportProperties*);
90
#endif
91
#ifndef ASSIMP_BUILD_NO_X_EXPORTER
92
void ExportSceneXFile(const char*,IOSystem*, const aiScene*, const ExportProperties*);
93
#endif
94
#ifndef ASSIMP_BUILD_NO_STEP_EXPORTER
95
void ExportSceneStep(const char*,IOSystem*, const aiScene*, const ExportProperties*);
96
#endif
97
#ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
98
void ExportSceneObj(const char*,IOSystem*, const aiScene*, const ExportProperties*);
99
void ExportSceneObjNoMtl(const char*,IOSystem*, const aiScene*, const ExportProperties*);
100
#endif
101
#ifndef ASSIMP_BUILD_NO_STL_EXPORTER
102
void ExportSceneSTL(const char*,IOSystem*, const aiScene*, const ExportProperties*);
103
void ExportSceneSTLBinary(const char*,IOSystem*, const aiScene*, const ExportProperties*);
104
#endif
105
#ifndef ASSIMP_BUILD_NO_PLY_EXPORTER
106
void ExportScenePly(const char*,IOSystem*, const aiScene*, const ExportProperties*);
107
void ExportScenePlyBinary(const char*, IOSystem*, const aiScene*, const ExportProperties*);
108
#endif
109
#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
110
void ExportScene3DS(const char*, IOSystem*, const aiScene*, const ExportProperties*);
111
#endif
112
#ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER
113
void ExportSceneGLTF(const char*, IOSystem*, const aiScene*, const ExportProperties*);
114
void ExportSceneGLB(const char*, IOSystem*, const aiScene*, const ExportProperties*);
115
void ExportSceneGLTF2(const char*, IOSystem*, const aiScene*, const ExportProperties*);
116
void ExportSceneGLB2(const char*, IOSystem*, const aiScene*, const ExportProperties*);
117
#endif
118
#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
119
void ExportSceneAssbin(const char*, IOSystem*, const aiScene*, const ExportProperties*);
120
#endif
121
#ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
122
void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportProperties*);
123
#endif
124
#ifndef ASSIMP_BUILD_NO_X3D_EXPORTER
125
void ExportSceneX3D(const char*, IOSystem*, const aiScene*, const ExportProperties*);
126
#endif
127
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
128
void ExportSceneFBX(const char*, IOSystem*, const aiScene*, const ExportProperties*);
129
void ExportSceneFBXA(const char*, IOSystem*, const aiScene*, const ExportProperties*);
130
#endif
131
#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
132
void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* );
133
#endif
134
#ifndef ASSIMP_BUILD_NO_M3D_EXPORTER
135
void ExportSceneM3D(const char*, IOSystem*, const aiScene*, const ExportProperties*);
136
void ExportSceneM3DA(const char*, IOSystem*, const aiScene*, const ExportProperties*);
137
#endif
138
#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
139
void ExportAssimp2Json(const char* , IOSystem*, const aiScene* , const Assimp::ExportProperties*);
140
#endif
141
#ifndef ASSIMP_BUILD_NO_PBRT_EXPORTER
142
void ExportScenePbrt(const char*, IOSystem*, const aiScene*, const ExportProperties*);
143
#endif
144
145
56
static void setupExporterArray(std::vector<Exporter::ExportFormatEntry> &exporters) {
146
56
  (void)exporters;
147
148
56
#ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
149
56
  exporters.emplace_back("collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada);
150
56
#endif
151
152
56
#ifndef ASSIMP_BUILD_NO_X_EXPORTER
153
56
  exporters.emplace_back("x", "X Files", "x", &ExportSceneXFile,
154
56
      aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs);
155
56
#endif
156
157
56
#ifndef ASSIMP_BUILD_NO_STEP_EXPORTER
158
56
  exporters.emplace_back("stp", "Step Files", "stp", &ExportSceneStep, 0);
159
56
#endif
160
161
56
#ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
162
56
  exporters.emplace_back("obj", "Wavefront OBJ format", "obj", &ExportSceneObj);
163
56
  exporters.emplace_back("objnomtl", "Wavefront OBJ format without material file", "obj", &ExportSceneObjNoMtl);
164
56
#endif
165
166
56
#ifndef ASSIMP_BUILD_NO_STL_EXPORTER
167
56
  exporters.emplace_back("stl", "Stereolithography", "stl", &ExportSceneSTL,
168
56
      aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices);
169
56
  exporters.emplace_back("stlb", "Stereolithography (binary)", "stl", &ExportSceneSTLBinary,
170
56
      aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices);
171
56
#endif
172
173
56
#ifndef ASSIMP_BUILD_NO_PLY_EXPORTER
174
56
  exporters.emplace_back("ply", "Stanford Polygon Library", "ply", &ExportScenePly,
175
56
      aiProcess_PreTransformVertices);
176
56
  exporters.emplace_back("plyb", "Stanford Polygon Library (binary)", "ply", &ExportScenePlyBinary,
177
56
      aiProcess_PreTransformVertices);
178
56
#endif
179
180
56
#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
181
56
  exporters.emplace_back("3ds", "Autodesk 3DS (legacy)", "3ds", &ExportScene3DS,
182
56
      aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices);
183
56
#endif
184
185
56
#if !defined(ASSIMP_BUILD_NO_GLTF_EXPORTER) && !defined(ASSIMP_BUILD_NO_GLTF2_EXPORTER)
186
56
  exporters.emplace_back("gltf2", "GL Transmission Format v. 2", "gltf", &ExportSceneGLTF2,
187
56
      aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType);
188
56
  exporters.emplace_back("glb2", "GL Transmission Format v. 2 (binary)", "glb", &ExportSceneGLB2,
189
56
      aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType);
190
56
#endif
191
192
56
#if !defined(ASSIMP_BUILD_NO_GLTF_EXPORTER) && !defined(ASSIMP_BUILD_NO_GLTF1_EXPORTER)
193
56
  exporters.emplace_back("gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF,
194
56
      aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType);
195
56
  exporters.emplace_back("glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB,
196
56
      aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType);
197
56
#endif
198
199
56
#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
200
56
  exporters.emplace_back("assbin", "Assimp Binary File", "assbin", &ExportSceneAssbin, 0);
201
56
#endif
202
203
56
#ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
204
56
  exporters.emplace_back("assxml", "Assimp XML Document", "assxml", &ExportSceneAssxml, 0);
205
56
#endif
206
207
56
#ifndef ASSIMP_BUILD_NO_X3D_EXPORTER
208
56
  exporters.emplace_back("x3d", "Extensible 3D", "x3d", &ExportSceneX3D, 0);
209
56
#endif
210
211
56
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
212
56
  exporters.emplace_back("fbx", "Autodesk FBX (binary)", "fbx", &ExportSceneFBX, 0);
213
56
  exporters.emplace_back("fbxa", "Autodesk FBX (ascii)", "fbx", &ExportSceneFBXA, 0);
214
56
#endif
215
216
#ifndef ASSIMP_BUILD_NO_M3D_EXPORTER
217
  exporters.push_back(Exporter::ExportFormatEntry("m3d", "Model 3D (binary)", "m3d", &ExportSceneM3D, 0));
218
  exporters.push_back(Exporter::ExportFormatEntry("m3da", "Model 3D (ascii)", "a3d", &ExportSceneM3DA, 0));
219
#endif
220
221
56
#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
222
56
  exporters.emplace_back("3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0);
223
56
#endif
224
225
56
#ifndef ASSIMP_BUILD_NO_PBRT_EXPORTER
226
56
  exporters.emplace_back("pbrt", "pbrt-v4 scene description file", "pbrt", &ExportScenePbrt, aiProcess_ConvertToLeftHanded | aiProcess_Triangulate | aiProcess_SortByPType);
227
56
#endif
228
229
56
#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
230
56
  exporters.emplace_back("assjson", "Assimp JSON Document", "json", &ExportAssimp2Json, 0);
231
56
#endif
232
56
}
233
234
class ExporterPimpl {
235
public:
236
    ExporterPimpl()
237
    : blob()
238
56
    , mIOSystem(new Assimp::DefaultIOSystem())
239
56
    , mIsDefaultIOHandler(true)
240
56
    , mProgressHandler( nullptr )
241
56
    , mIsDefaultProgressHandler( true )
242
56
    , mPostProcessingSteps()
243
56
    , mError()
244
56
    , mExporters() {
245
56
        GetPostProcessingStepInstanceList(mPostProcessingSteps);
246
247
        // grab all built-in exporters
248
56
    setupExporterArray(mExporters);
249
56
    }
250
251
56
    ~ExporterPimpl() {
252
56
        delete blob;
253
254
        // Delete all post-processing plug-ins
255
1.90k
        for( unsigned int a = 0; a < mPostProcessingSteps.size(); a++) {
256
1.84k
            delete mPostProcessingSteps[a];
257
1.84k
        }
258
56
        delete mProgressHandler;
259
56
    }
260
261
public:
262
    aiExportDataBlob* blob;
263
    std::shared_ptr< Assimp::IOSystem > mIOSystem;
264
    bool mIsDefaultIOHandler;
265
266
    /** The progress handler */
267
    ProgressHandler *mProgressHandler;
268
    bool mIsDefaultProgressHandler;
269
270
    /** Post processing steps we can apply at the imported data. */
271
    std::vector< BaseProcess* > mPostProcessingSteps;
272
273
    /** Last fatal export error */
274
    std::string mError;
275
276
    /** Exporters, this includes those registered using #Assimp::Exporter::RegisterExporter */
277
    std::vector<Exporter::ExportFormatEntry> mExporters;
278
};
279
280
} // end of namespace Assimp
281
282
using namespace Assimp;
283
284
// ------------------------------------------------------------------------------------------------
285
Exporter :: Exporter()
286
56
: pimpl(new ExporterPimpl()) {
287
56
    pimpl->mProgressHandler = new DefaultProgressHandler();
288
56
}
289
290
// ------------------------------------------------------------------------------------------------
291
56
Exporter::~Exporter() {
292
56
  ai_assert(nullptr != pimpl);
293
56
  FreeBlob();
294
56
    delete pimpl;
295
56
}
296
297
// ------------------------------------------------------------------------------------------------
298
0
void Exporter::SetIOHandler( IOSystem* pIOHandler) {
299
0
  ai_assert(nullptr != pimpl);
300
0
  pimpl->mIsDefaultIOHandler = !pIOHandler;
301
0
    pimpl->mIOSystem.reset(pIOHandler);
302
0
}
303
304
// ------------------------------------------------------------------------------------------------
305
0
IOSystem* Exporter::GetIOHandler() const {
306
0
  ai_assert(nullptr != pimpl);
307
0
  return pimpl->mIOSystem.get();
308
0
}
309
310
// ------------------------------------------------------------------------------------------------
311
0
bool Exporter::IsDefaultIOHandler() const {
312
0
  ai_assert(nullptr != pimpl);
313
0
  return pimpl->mIsDefaultIOHandler;
314
0
}
315
316
// ------------------------------------------------------------------------------------------------
317
0
void Exporter::SetProgressHandler(ProgressHandler* pHandler) {
318
0
    ai_assert(nullptr != pimpl);
319
320
0
    if ( nullptr == pHandler) {
321
        // Release pointer in the possession of the caller
322
0
        pimpl->mProgressHandler = new DefaultProgressHandler();
323
0
        pimpl->mIsDefaultProgressHandler = true;
324
0
        return;
325
0
    }
326
327
0
    if (pimpl->mProgressHandler == pHandler) {
328
0
        return;
329
0
    }
330
331
0
    delete pimpl->mProgressHandler;
332
0
    pimpl->mProgressHandler = pHandler;
333
0
    pimpl->mIsDefaultProgressHandler = false;
334
0
}
335
336
// ------------------------------------------------------------------------------------------------
337
const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const char* pFormatId,
338
56
                                                unsigned int pPreprocessing, const ExportProperties* pProperties) {
339
56
  ai_assert(nullptr != pimpl);
340
56
    if (pimpl->blob) {
341
0
        delete pimpl->blob;
342
0
        pimpl->blob = nullptr;
343
0
    }
344
345
56
    auto baseName = pProperties ? pProperties->GetPropertyString(AI_CONFIG_EXPORT_BLOB_NAME, AI_BLOBIO_MAGIC) : AI_BLOBIO_MAGIC;
346
347
56
    std::shared_ptr<IOSystem> old = pimpl->mIOSystem;
348
56
    BlobIOSystem *blobio = new BlobIOSystem(baseName);
349
56
    pimpl->mIOSystem = std::shared_ptr<IOSystem>( blobio );
350
351
56
    if (AI_SUCCESS != Export(pScene,pFormatId,blobio->GetMagicFileName(), pPreprocessing, pProperties)) {
352
3
        pimpl->mIOSystem = old;
353
3
        return nullptr;
354
3
    }
355
356
53
    pimpl->blob = blobio->GetBlobChain();
357
53
    pimpl->mIOSystem = old;
358
359
53
    return pimpl->blob;
360
56
}
361
362
// ------------------------------------------------------------------------------------------------
363
aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const char* pPath,
364
56
        unsigned int pPreprocessing, const ExportProperties* pProperties) {
365
56
    ASSIMP_BEGIN_EXCEPTION_REGION();
366
56
  ai_assert(nullptr != pimpl);
367
    // when they create scenes from scratch, users will likely create them not in verbose
368
    // format. They will likely not be aware that there is a flag in the scene to indicate
369
    // this, however. To avoid surprises and bug reports, we check for duplicates in
370
    // meshes upfront.
371
56
    const bool is_verbose_format = !(pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) || MakeVerboseFormatProcess::IsVerboseFormat(pScene);
372
373
56
    pimpl->mProgressHandler->UpdateFileWrite(0, 4);
374
375
56
    pimpl->mError = "";
376
1.00k
    for (size_t i = 0; i < pimpl->mExporters.size(); ++i) {
377
1.00k
        const Exporter::ExportFormatEntry& exp = pimpl->mExporters[i];
378
1.00k
        if (!strcmp(exp.mDescription.id,pFormatId)) {
379
56
            try {
380
                // Always create a full copy of the scene. We might optimize this one day,
381
                // but for now it is the most pragmatic way.
382
56
                aiScene* scenecopy_tmp = nullptr;
383
56
                SceneCombiner::CopyScene(&scenecopy_tmp,pScene);
384
385
56
                pimpl->mProgressHandler->UpdateFileWrite(1, 4);
386
387
56
                std::unique_ptr<aiScene> scenecopy(scenecopy_tmp);
388
56
                const ScenePrivateData* const priv = ScenePriv(pScene);
389
390
                // steps that are not idempotent, i.e. we might need to run them again, usually to get back to the
391
                // original state before the step was applied first. When checking which steps we don't need
392
                // to run, those are excluded.
393
56
                const unsigned int nonIdempotentSteps = aiProcess_FlipWindingOrder | aiProcess_FlipUVs | aiProcess_MakeLeftHanded;
394
395
                // Erase all pp steps that were already applied to this scene
396
56
                const unsigned int pp = (exp.mEnforcePP | pPreprocessing) & ~(priv && !priv->mIsCopy
397
56
                    ? (priv->mPPStepsApplied & ~nonIdempotentSteps)
398
56
                    : 0u);
399
400
                // If no extra post-processing was specified, and we obtained this scene from an
401
                // Assimp importer, apply the reverse steps automatically.
402
                // TODO: either drop this, or document it. Otherwise it is just a bad surprise.
403
                //if (!pPreprocessing && priv) {
404
                //  pp |= (nonIdempotentSteps & priv->mPPStepsApplied);
405
                //}
406
407
                // If the input scene is not in verbose format, but there is at least post-processing step that relies on it,
408
                // we need to run the MakeVerboseFormat step first.
409
56
                bool must_join_again = false;
410
56
                if (!is_verbose_format) {
411
37
                    bool verbosify = false;
412
1.25k
                    for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
413
1.22k
                        BaseProcess* const p = pimpl->mPostProcessingSteps[a];
414
415
1.22k
                        if (p->IsActive(pp) && p->RequireVerboseFormat()) {
416
0
                            verbosify = true;
417
0
                            break;
418
0
                        }
419
1.22k
                    }
420
421
37
                    if (verbosify || (exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) {
422
0
                        ASSIMP_LOG_DEBUG("export: Scene data not in verbose format, applying MakeVerboseFormat step first");
423
424
0
                        MakeVerboseFormatProcess proc;
425
0
                        proc.Execute(scenecopy.get());
426
427
0
                        if(!(exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) {
428
0
                            must_join_again = true;
429
0
                        }
430
0
                    }
431
37
                }
432
433
56
                pimpl->mProgressHandler->UpdateFileWrite(2, 4);
434
435
56
                if (pp) {
436
                    // the three 'conversion' steps need to be executed first because all other steps rely on the standard data layout
437
0
                    {
438
0
                        FlipWindingOrderProcess step;
439
0
                        if (step.IsActive(pp)) {
440
0
                            step.Execute(scenecopy.get());
441
0
                        }
442
0
                    }
443
444
0
                    {
445
0
                        FlipUVsProcess step;
446
0
                        if (step.IsActive(pp)) {
447
0
                            step.Execute(scenecopy.get());
448
0
                        }
449
0
                    }
450
451
0
                    {
452
0
                        MakeLeftHandedProcess step;
453
0
                        if (step.IsActive(pp)) {
454
0
                            step.Execute(scenecopy.get());
455
0
                        }
456
0
                    }
457
458
0
                    bool exportPointCloud(false);
459
0
                    if (nullptr != pProperties) {
460
0
                        exportPointCloud = pProperties->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS);
461
0
                    }
462
463
                    // dispatch other processes
464
0
                    for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
465
0
                        BaseProcess* const p = pimpl->mPostProcessingSteps[a];
466
467
0
                        if (p->IsActive(pp)
468
0
                            && !dynamic_cast<FlipUVsProcess*>(p)
469
0
                            && !dynamic_cast<FlipWindingOrderProcess*>(p)
470
0
                            && !dynamic_cast<MakeLeftHandedProcess*>(p)) {
471
0
                            if (dynamic_cast<PretransformVertices*>(p) && exportPointCloud) {
472
0
                                continue;
473
0
                            }
474
0
                            p->Execute(scenecopy.get());
475
0
                        }
476
0
                    }
477
0
                    ScenePrivateData* const privOut = ScenePriv(scenecopy.get());
478
0
                    ai_assert(nullptr != privOut);
479
480
0
                    privOut->mPPStepsApplied |= pp;
481
0
                }
482
483
56
                pimpl->mProgressHandler->UpdateFileWrite(3, 4);
484
485
56
                if(must_join_again) {
486
0
                    JoinVerticesProcess proc;
487
0
                    proc.Execute(scenecopy.get());
488
0
                }
489
490
56
                ExportProperties emptyProperties;  // Never pass nullptr ExportProperties so Exporters don't have to worry.
491
56
                ExportProperties* pProp = pProperties ? (ExportProperties*)pProperties : &emptyProperties;
492
56
            pProp->SetPropertyBool("bJoinIdenticalVertices", pp & aiProcess_JoinIdenticalVertices);
493
56
                exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp);
494
495
56
                pimpl->mProgressHandler->UpdateFileWrite(4, 4);
496
56
            } catch (DeadlyExportError& err) {
497
3
                pimpl->mError = err.what();
498
3
                return AI_FAILURE;
499
3
            }
500
53
            return AI_SUCCESS;
501
56
        }
502
1.00k
    }
503
504
0
    pimpl->mError = std::string("Found no exporter to handle this file format: ") + pFormatId;
505
0
    ASSIMP_END_EXCEPTION_REGION(aiReturn);
506
507
0
    return AI_FAILURE;
508
56
}
509
510
// ------------------------------------------------------------------------------------------------
511
0
const char* Exporter::GetErrorString() const {
512
0
  ai_assert(nullptr != pimpl);
513
0
    return pimpl->mError.c_str();
514
0
}
515
516
// ------------------------------------------------------------------------------------------------
517
56
void Exporter::FreeBlob() {
518
56
  ai_assert(nullptr != pimpl);
519
56
    delete pimpl->blob;
520
56
    pimpl->blob = nullptr;
521
522
56
    pimpl->mError = "";
523
56
}
524
525
// ------------------------------------------------------------------------------------------------
526
0
const aiExportDataBlob* Exporter::GetBlob() const {
527
0
  ai_assert(nullptr != pimpl);
528
0
  return pimpl->blob;
529
0
}
530
531
// ------------------------------------------------------------------------------------------------
532
0
const aiExportDataBlob* Exporter::GetOrphanedBlob() const {
533
0
  ai_assert(nullptr != pimpl);
534
0
  const aiExportDataBlob *tmp = pimpl->blob;
535
0
    pimpl->blob = nullptr;
536
0
    return tmp;
537
0
}
538
539
// ------------------------------------------------------------------------------------------------
540
0
size_t Exporter::GetExportFormatCount() const {
541
0
  ai_assert(nullptr != pimpl);
542
0
    return pimpl->mExporters.size();
543
0
}
544
545
// ------------------------------------------------------------------------------------------------
546
0
const aiExportFormatDesc* Exporter::GetExportFormatDescription( size_t index ) const {
547
0
  ai_assert(nullptr != pimpl);
548
0
  if (index >= GetExportFormatCount()) {
549
0
        return nullptr;
550
0
    }
551
552
    // Return from static storage if the requested index is built-in.
553
0
  if (index < pimpl->mExporters.size()) {
554
0
    return &pimpl->mExporters[index].mDescription;
555
0
    }
556
557
0
    return &pimpl->mExporters[index].mDescription;
558
0
}
559
560
// ------------------------------------------------------------------------------------------------
561
0
aiReturn Exporter::RegisterExporter(const ExportFormatEntry& desc) {
562
0
  ai_assert(nullptr != pimpl);
563
0
  for (const ExportFormatEntry &e : pimpl->mExporters) {
564
0
        if (!strcmp(e.mDescription.id,desc.mDescription.id)) {
565
0
            return aiReturn_FAILURE;
566
0
        }
567
0
    }
568
569
0
    pimpl->mExporters.push_back(desc);
570
0
    return aiReturn_SUCCESS;
571
0
}
572
573
// ------------------------------------------------------------------------------------------------
574
0
void Exporter::UnregisterExporter(const char* id) {
575
0
  ai_assert(nullptr != pimpl);
576
0
  for (std::vector<ExportFormatEntry>::iterator it = pimpl->mExporters.begin();
577
0
            it != pimpl->mExporters.end(); ++it) {
578
0
        if (!strcmp((*it).mDescription.id,id)) {
579
0
            pimpl->mExporters.erase(it);
580
0
            break;
581
0
        }
582
0
    }
583
0
}
584
585
// ------------------------------------------------------------------------------------------------
586
56
ExportProperties::ExportProperties() = default;
587
588
// ------------------------------------------------------------------------------------------------
589
0
ExportProperties::ExportProperties(const ExportProperties &other) = default;
590
591
0
bool ExportProperties::SetPropertyCallback(const char *szName, const std::function<void *(void *)> &f) {
592
0
    return SetGenericProperty<std::function<void *(void *)>>(mCallbackProperties, szName, f);
593
0
}
594
595
0
std::function<void *(void *)> ExportProperties::GetPropertyCallback(const char *szName) const {
596
0
    return GetGenericProperty<std::function<void *(void *)>>(mCallbackProperties, szName, nullptr);
597
0
}
598
599
0
bool ExportProperties::HasPropertyCallback(const char *szName) const {
600
0
    return HasGenericProperty<std::function<void *(void *)>>(mCallbackProperties, szName);
601
0
}
602
603
// ------------------------------------------------------------------------------------------------
604
// Set a configuration property
605
56
bool ExportProperties::SetPropertyInteger(const char* szName, int iValue) {
606
56
    return SetGenericProperty<int>(mIntProperties, szName,iValue);
607
56
}
608
609
// ------------------------------------------------------------------------------------------------
610
// Set a configuration property
611
0
bool ExportProperties::SetPropertyFloat(const char* szName, ai_real iValue) {
612
0
    return SetGenericProperty<ai_real>(mFloatProperties, szName,iValue);
613
0
}
614
615
// ------------------------------------------------------------------------------------------------
616
// Set a configuration property
617
0
bool ExportProperties::SetPropertyString(const char* szName, const std::string& value) {
618
0
    return SetGenericProperty<std::string>(mStringProperties, szName,value);
619
0
}
620
621
// ------------------------------------------------------------------------------------------------
622
// Set a configuration property
623
0
bool ExportProperties::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) {
624
0
    return SetGenericProperty<aiMatrix4x4>(mMatrixProperties, szName,value);
625
0
}
626
627
// ------------------------------------------------------------------------------------------------
628
// Get a configuration property
629
112
int ExportProperties::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const {
630
112
    return GetGenericProperty<int>(mIntProperties,szName,iErrorReturn);
631
112
}
632
633
// ------------------------------------------------------------------------------------------------
634
// Get a configuration property
635
0
ai_real ExportProperties::GetPropertyFloat(const char* szName, ai_real iErrorReturn /*= 10e10*/) const {
636
0
    return GetGenericProperty<ai_real>(mFloatProperties,szName,iErrorReturn);
637
0
}
638
639
// ------------------------------------------------------------------------------------------------
640
// Get a configuration property
641
const std::string ExportProperties::GetPropertyString(const char* szName,
642
0
        const std::string& iErrorReturn /*= ""*/) const {
643
0
    return GetGenericProperty<std::string>(mStringProperties,szName,iErrorReturn);
644
0
}
645
646
// ------------------------------------------------------------------------------------------------
647
// Has a configuration property
648
const aiMatrix4x4 ExportProperties::GetPropertyMatrix(const char* szName,
649
0
        const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const {
650
0
    return GetGenericProperty<aiMatrix4x4>(mMatrixProperties,szName,iErrorReturn);
651
0
}
652
653
// ------------------------------------------------------------------------------------------------
654
// Has a configuration property
655
0
bool ExportProperties::HasPropertyInteger(const char* szName) const {
656
0
    return HasGenericProperty<int>(mIntProperties, szName);
657
0
}
658
659
// ------------------------------------------------------------------------------------------------
660
// Has a configuration property
661
0
bool ExportProperties::HasPropertyBool(const char* szName) const {
662
0
    return HasGenericProperty<int>(mIntProperties, szName);
663
0
}
664
665
// ------------------------------------------------------------------------------------------------
666
// Has a configuration property
667
0
bool ExportProperties::HasPropertyFloat(const char* szName) const {
668
0
    return HasGenericProperty<ai_real>(mFloatProperties, szName);
669
0
}
670
671
// ------------------------------------------------------------------------------------------------
672
// Has a configuration property
673
0
bool ExportProperties::HasPropertyString(const char* szName) const {
674
0
    return HasGenericProperty<std::string>(mStringProperties, szName);
675
0
}
676
677
// ------------------------------------------------------------------------------------------------
678
// Has a configuration property
679
0
bool ExportProperties::HasPropertyMatrix(const char* szName) const {
680
0
    return HasGenericProperty<aiMatrix4x4>(mMatrixProperties, szName);
681
0
}
682
683
684
#endif // !ASSIMP_BUILD_NO_EXPORT