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