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