1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
5
6 Copyright (c) 2006-2021, 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
setupExporterArray(std::vector<Exporter::ExportFormatEntry> & exporters)145 static void setupExporterArray(std::vector<Exporter::ExportFormatEntry> &exporters) {
146 (void)exporters;
147
148 #ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
149 exporters.push_back(Exporter::ExportFormatEntry("collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada));
150 #endif
151
152 #ifndef ASSIMP_BUILD_NO_X_EXPORTER
153 exporters.push_back(Exporter::ExportFormatEntry("x", "X Files", "x", &ExportSceneXFile,
154 aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs));
155 #endif
156
157 #ifndef ASSIMP_BUILD_NO_STEP_EXPORTER
158 exporters.push_back(Exporter::ExportFormatEntry("stp", "Step Files", "stp", &ExportSceneStep, 0));
159 #endif
160
161 #ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
162 exporters.push_back(Exporter::ExportFormatEntry("obj", "Wavefront OBJ format", "obj", &ExportSceneObj,
163 aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */));
164 exporters.push_back(Exporter::ExportFormatEntry("objnomtl", "Wavefront OBJ format without material file", "obj", &ExportSceneObjNoMtl,
165 aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */));
166 #endif
167
168 #ifndef ASSIMP_BUILD_NO_STL_EXPORTER
169 exporters.push_back(Exporter::ExportFormatEntry("stl", "Stereolithography", "stl", &ExportSceneSTL,
170 aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices));
171 exporters.push_back(Exporter::ExportFormatEntry("stlb", "Stereolithography (binary)", "stl", &ExportSceneSTLBinary,
172 aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices));
173 #endif
174
175 #ifndef ASSIMP_BUILD_NO_PLY_EXPORTER
176 exporters.push_back(Exporter::ExportFormatEntry("ply", "Stanford Polygon Library", "ply", &ExportScenePly,
177 aiProcess_PreTransformVertices));
178 exporters.push_back(Exporter::ExportFormatEntry("plyb", "Stanford Polygon Library (binary)", "ply", &ExportScenePlyBinary,
179 aiProcess_PreTransformVertices));
180 #endif
181
182 #ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
183 exporters.push_back(Exporter::ExportFormatEntry("3ds", "Autodesk 3DS (legacy)", "3ds", &ExportScene3DS,
184 aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices));
185 #endif
186
187 #if !defined(ASSIMP_BUILD_NO_GLTF_EXPORTER) && !defined(ASSIMP_BUILD_NO_GLTF2_EXPORTER)
188 exporters.push_back(Exporter::ExportFormatEntry("gltf2", "GL Transmission Format v. 2", "gltf", &ExportSceneGLTF2,
189 aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType));
190 exporters.push_back(Exporter::ExportFormatEntry("glb2", "GL Transmission Format v. 2 (binary)", "glb", &ExportSceneGLB2,
191 aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType));
192 #endif
193
194 #if !defined(ASSIMP_BUILD_NO_GLTF_EXPORTER) && !defined(ASSIMP_BUILD_NO_GLTF1_EXPORTER)
195 exporters.push_back(Exporter::ExportFormatEntry("gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF,
196 aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType));
197 exporters.push_back(Exporter::ExportFormatEntry("glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB,
198 aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType));
199 #endif
200
201 #ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
202 exporters.push_back(Exporter::ExportFormatEntry("assbin", "Assimp Binary File", "assbin", &ExportSceneAssbin, 0));
203 #endif
204
205 #ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
206 exporters.push_back(Exporter::ExportFormatEntry("assxml", "Assimp XML Document", "assxml", &ExportSceneAssxml, 0));
207 #endif
208
209 #ifndef ASSIMP_BUILD_NO_X3D_EXPORTER
210 exporters.push_back(Exporter::ExportFormatEntry("x3d", "Extensible 3D", "x3d", &ExportSceneX3D, 0));
211 #endif
212
213 #ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
214 exporters.push_back(Exporter::ExportFormatEntry("fbx", "Autodesk FBX (binary)", "fbx", &ExportSceneFBX, 0));
215 exporters.push_back(Exporter::ExportFormatEntry("fbxa", "Autodesk FBX (ascii)", "fbx", &ExportSceneFBXA, 0));
216 #endif
217
218 #ifndef ASSIMP_BUILD_NO_M3D_EXPORTER
219 exporters.push_back(Exporter::ExportFormatEntry("m3d", "Model 3D (binary)", "m3d", &ExportSceneM3D, 0));
220 exporters.push_back(Exporter::ExportFormatEntry("m3da", "Model 3D (ascii)", "a3d", &ExportSceneM3DA, 0));
221 #endif
222
223 #ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
224 exporters.push_back(Exporter::ExportFormatEntry("3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0));
225 #endif
226
227 #ifndef ASSIMP_BUILD_NO_PBRT_EXPORTER
228 exporters.push_back(Exporter::ExportFormatEntry("pbrt", "pbrt-v4 scene description file", "pbrt", &ExportScenePbrt, aiProcess_Triangulate | aiProcess_SortByPType));
229 #endif
230
231 #ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
232 exporters.push_back(Exporter::ExportFormatEntry("assjson", "Assimp JSON Document", "json", &ExportAssimp2Json, 0));
233 #endif
234 }
235
236 class ExporterPimpl {
237 public:
ExporterPimpl()238 ExporterPimpl()
239 : blob()
240 , mIOSystem(new Assimp::DefaultIOSystem())
241 , mIsDefaultIOHandler(true)
242 , mProgressHandler( nullptr )
243 , mIsDefaultProgressHandler( true )
244 , mPostProcessingSteps()
245 , mError()
246 , mExporters() {
247 GetPostProcessingStepInstanceList(mPostProcessingSteps);
248
249 // grab all built-in exporters
250 setupExporterArray(mExporters);
251 }
252
~ExporterPimpl()253 ~ExporterPimpl() {
254 delete blob;
255
256 // Delete all post-processing plug-ins
257 for( unsigned int a = 0; a < mPostProcessingSteps.size(); a++) {
258 delete mPostProcessingSteps[a];
259 }
260 delete mProgressHandler;
261 }
262
263 public:
264 aiExportDataBlob* blob;
265 std::shared_ptr< Assimp::IOSystem > mIOSystem;
266 bool mIsDefaultIOHandler;
267
268 /** The progress handler */
269 ProgressHandler *mProgressHandler;
270 bool mIsDefaultProgressHandler;
271
272 /** Post processing steps we can apply at the imported data. */
273 std::vector< BaseProcess* > mPostProcessingSteps;
274
275 /** Last fatal export error */
276 std::string mError;
277
278 /** Exporters, this includes those registered using #Assimp::Exporter::RegisterExporter */
279 std::vector<Exporter::ExportFormatEntry> mExporters;
280 };
281
282 } // end of namespace Assimp
283
284 using namespace Assimp;
285
286 // ------------------------------------------------------------------------------------------------
Exporter()287 Exporter :: Exporter()
288 : pimpl(new ExporterPimpl()) {
289 pimpl->mProgressHandler = new DefaultProgressHandler();
290 }
291
292 // ------------------------------------------------------------------------------------------------
~Exporter()293 Exporter::~Exporter() {
294 ai_assert(nullptr != pimpl);
295 FreeBlob();
296 delete pimpl;
297 }
298
299 // ------------------------------------------------------------------------------------------------
SetIOHandler(IOSystem * pIOHandler)300 void Exporter::SetIOHandler( IOSystem* pIOHandler) {
301 ai_assert(nullptr != pimpl);
302 pimpl->mIsDefaultIOHandler = !pIOHandler;
303 pimpl->mIOSystem.reset(pIOHandler);
304 }
305
306 // ------------------------------------------------------------------------------------------------
GetIOHandler() const307 IOSystem* Exporter::GetIOHandler() const {
308 ai_assert(nullptr != pimpl);
309 return pimpl->mIOSystem.get();
310 }
311
312 // ------------------------------------------------------------------------------------------------
IsDefaultIOHandler() const313 bool Exporter::IsDefaultIOHandler() const {
314 ai_assert(nullptr != pimpl);
315 return pimpl->mIsDefaultIOHandler;
316 }
317
318 // ------------------------------------------------------------------------------------------------
SetProgressHandler(ProgressHandler * pHandler)319 void Exporter::SetProgressHandler(ProgressHandler* pHandler) {
320 ai_assert(nullptr != pimpl);
321
322 if ( nullptr == pHandler) {
323 // Release pointer in the possession of the caller
324 pimpl->mProgressHandler = new DefaultProgressHandler();
325 pimpl->mIsDefaultProgressHandler = true;
326 return;
327 }
328
329 if (pimpl->mProgressHandler == pHandler) {
330 return;
331 }
332
333 delete pimpl->mProgressHandler;
334 pimpl->mProgressHandler = pHandler;
335 pimpl->mIsDefaultProgressHandler = false;
336 }
337
338 // ------------------------------------------------------------------------------------------------
ExportToBlob(const aiScene * pScene,const char * pFormatId,unsigned int pPreprocessing,const ExportProperties * pProperties)339 const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const char* pFormatId,
340 unsigned int pPreprocessing, const ExportProperties* pProperties) {
341 ai_assert(nullptr != pimpl);
342 if (pimpl->blob) {
343 delete pimpl->blob;
344 pimpl->blob = nullptr;
345 }
346
347 auto baseName = pProperties ? pProperties->GetPropertyString(AI_CONFIG_EXPORT_BLOB_NAME, AI_BLOBIO_MAGIC) : AI_BLOBIO_MAGIC;
348
349 std::shared_ptr<IOSystem> old = pimpl->mIOSystem;
350 BlobIOSystem *blobio = new BlobIOSystem(baseName);
351 pimpl->mIOSystem = std::shared_ptr<IOSystem>( blobio );
352
353 if (AI_SUCCESS != Export(pScene,pFormatId,blobio->GetMagicFileName(), pPreprocessing, pProperties)) {
354 pimpl->mIOSystem = old;
355 return nullptr;
356 }
357
358 pimpl->blob = blobio->GetBlobChain();
359 pimpl->mIOSystem = old;
360
361 return pimpl->blob;
362 }
363
364 // ------------------------------------------------------------------------------------------------
Export(const aiScene * pScene,const char * pFormatId,const char * pPath,unsigned int pPreprocessing,const ExportProperties * pProperties)365 aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const char* pPath,
366 unsigned int pPreprocessing, const ExportProperties* pProperties) {
367 ASSIMP_BEGIN_EXCEPTION_REGION();
368 ai_assert(nullptr != pimpl);
369 // when they create scenes from scratch, users will likely create them not in verbose
370 // format. They will likely not be aware that there is a flag in the scene to indicate
371 // this, however. To avoid surprises and bug reports, we check for duplicates in
372 // meshes upfront.
373 const bool is_verbose_format = !(pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) || MakeVerboseFormatProcess::IsVerboseFormat(pScene);
374
375 pimpl->mProgressHandler->UpdateFileWrite(0, 4);
376
377 pimpl->mError = "";
378 for (size_t i = 0; i < pimpl->mExporters.size(); ++i) {
379 const Exporter::ExportFormatEntry& exp = pimpl->mExporters[i];
380 if (!strcmp(exp.mDescription.id,pFormatId)) {
381 try {
382 // Always create a full copy of the scene. We might optimize this one day,
383 // but for now it is the most pragmatic way.
384 aiScene* scenecopy_tmp = nullptr;
385 SceneCombiner::CopyScene(&scenecopy_tmp,pScene);
386
387 pimpl->mProgressHandler->UpdateFileWrite(1, 4);
388
389 std::unique_ptr<aiScene> scenecopy(scenecopy_tmp);
390 const ScenePrivateData* const priv = ScenePriv(pScene);
391
392 // steps that are not idempotent, i.e. we might need to run them again, usually to get back to the
393 // original state before the step was applied first. When checking which steps we don't need
394 // to run, those are excluded.
395 const unsigned int nonIdempotentSteps = aiProcess_FlipWindingOrder | aiProcess_FlipUVs | aiProcess_MakeLeftHanded;
396
397 // Erase all pp steps that were already applied to this scene
398 const unsigned int pp = (exp.mEnforcePP | pPreprocessing) & ~(priv && !priv->mIsCopy
399 ? (priv->mPPStepsApplied & ~nonIdempotentSteps)
400 : 0u);
401
402 // If no extra post-processing was specified, and we obtained this scene from an
403 // Assimp importer, apply the reverse steps automatically.
404 // TODO: either drop this, or document it. Otherwise it is just a bad surprise.
405 //if (!pPreprocessing && priv) {
406 // pp |= (nonIdempotentSteps & priv->mPPStepsApplied);
407 //}
408
409 // If the input scene is not in verbose format, but there is at least post-processing step that relies on it,
410 // we need to run the MakeVerboseFormat step first.
411 bool must_join_again = false;
412 if (!is_verbose_format) {
413 bool verbosify = false;
414 for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
415 BaseProcess* const p = pimpl->mPostProcessingSteps[a];
416
417 if (p->IsActive(pp) && p->RequireVerboseFormat()) {
418 verbosify = true;
419 break;
420 }
421 }
422
423 if (verbosify || (exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) {
424 ASSIMP_LOG_DEBUG("export: Scene data not in verbose format, applying MakeVerboseFormat step first");
425
426 MakeVerboseFormatProcess proc;
427 proc.Execute(scenecopy.get());
428
429 if(!(exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) {
430 must_join_again = true;
431 }
432 }
433 }
434
435 pimpl->mProgressHandler->UpdateFileWrite(2, 4);
436
437 if (pp) {
438 // the three 'conversion' steps need to be executed first because all other steps rely on the standard data layout
439 {
440 FlipWindingOrderProcess step;
441 if (step.IsActive(pp)) {
442 step.Execute(scenecopy.get());
443 }
444 }
445
446 {
447 FlipUVsProcess step;
448 if (step.IsActive(pp)) {
449 step.Execute(scenecopy.get());
450 }
451 }
452
453 {
454 MakeLeftHandedProcess step;
455 if (step.IsActive(pp)) {
456 step.Execute(scenecopy.get());
457 }
458 }
459
460 bool exportPointCloud(false);
461 if (nullptr != pProperties) {
462 exportPointCloud = pProperties->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS);
463 }
464
465 // dispatch other processes
466 for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
467 BaseProcess* const p = pimpl->mPostProcessingSteps[a];
468
469 if (p->IsActive(pp)
470 && !dynamic_cast<FlipUVsProcess*>(p)
471 && !dynamic_cast<FlipWindingOrderProcess*>(p)
472 && !dynamic_cast<MakeLeftHandedProcess*>(p)) {
473 if (dynamic_cast<PretransformVertices*>(p) && exportPointCloud) {
474 continue;
475 }
476 p->Execute(scenecopy.get());
477 }
478 }
479 ScenePrivateData* const privOut = ScenePriv(scenecopy.get());
480 ai_assert(nullptr != privOut);
481
482 privOut->mPPStepsApplied |= pp;
483 }
484
485 pimpl->mProgressHandler->UpdateFileWrite(3, 4);
486
487 if(must_join_again) {
488 JoinVerticesProcess proc;
489 proc.Execute(scenecopy.get());
490 }
491
492 ExportProperties emptyProperties; // Never pass nullptr ExportProperties so Exporters don't have to worry.
493 ExportProperties* pProp = pProperties ? (ExportProperties*)pProperties : &emptyProperties;
494 pProp->SetPropertyBool("bJoinIdenticalVertices", pp & aiProcess_JoinIdenticalVertices);
495 exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp);
496
497 pimpl->mProgressHandler->UpdateFileWrite(4, 4);
498 } catch (DeadlyExportError& err) {
499 pimpl->mError = err.what();
500 return AI_FAILURE;
501 }
502 return AI_SUCCESS;
503 }
504 }
505
506 pimpl->mError = std::string("Found no exporter to handle this file format: ") + pFormatId;
507 ASSIMP_END_EXCEPTION_REGION(aiReturn);
508
509 return AI_FAILURE;
510 }
511
512 // ------------------------------------------------------------------------------------------------
GetErrorString() const513 const char* Exporter::GetErrorString() const {
514 ai_assert(nullptr != pimpl);
515 return pimpl->mError.c_str();
516 }
517
518 // ------------------------------------------------------------------------------------------------
FreeBlob()519 void Exporter::FreeBlob() {
520 ai_assert(nullptr != pimpl);
521 delete pimpl->blob;
522 pimpl->blob = nullptr;
523
524 pimpl->mError = "";
525 }
526
527 // ------------------------------------------------------------------------------------------------
GetBlob() const528 const aiExportDataBlob* Exporter::GetBlob() const {
529 ai_assert(nullptr != pimpl);
530 return pimpl->blob;
531 }
532
533 // ------------------------------------------------------------------------------------------------
GetOrphanedBlob() const534 const aiExportDataBlob* Exporter::GetOrphanedBlob() const {
535 ai_assert(nullptr != pimpl);
536 const aiExportDataBlob *tmp = pimpl->blob;
537 pimpl->blob = nullptr;
538 return tmp;
539 }
540
541 // ------------------------------------------------------------------------------------------------
GetExportFormatCount() const542 size_t Exporter::GetExportFormatCount() const {
543 ai_assert(nullptr != pimpl);
544 return pimpl->mExporters.size();
545 }
546
547 // ------------------------------------------------------------------------------------------------
GetExportFormatDescription(size_t index) const548 const aiExportFormatDesc* Exporter::GetExportFormatDescription( size_t index ) const {
549 ai_assert(nullptr != pimpl);
550 if (index >= GetExportFormatCount()) {
551 return nullptr;
552 }
553
554 // Return from static storage if the requested index is built-in.
555 if (index < pimpl->mExporters.size()) {
556 return &pimpl->mExporters[index].mDescription;
557 }
558
559 return &pimpl->mExporters[index].mDescription;
560 }
561
562 // ------------------------------------------------------------------------------------------------
RegisterExporter(const ExportFormatEntry & desc)563 aiReturn Exporter::RegisterExporter(const ExportFormatEntry& desc) {
564 ai_assert(nullptr != pimpl);
565 for (const ExportFormatEntry &e : pimpl->mExporters) {
566 if (!strcmp(e.mDescription.id,desc.mDescription.id)) {
567 return aiReturn_FAILURE;
568 }
569 }
570
571 pimpl->mExporters.push_back(desc);
572 return aiReturn_SUCCESS;
573 }
574
575 // ------------------------------------------------------------------------------------------------
UnregisterExporter(const char * id)576 void Exporter::UnregisterExporter(const char* id) {
577 ai_assert(nullptr != pimpl);
578 for (std::vector<ExportFormatEntry>::iterator it = pimpl->mExporters.begin();
579 it != pimpl->mExporters.end(); ++it) {
580 if (!strcmp((*it).mDescription.id,id)) {
581 pimpl->mExporters.erase(it);
582 break;
583 }
584 }
585 }
586
587 // ------------------------------------------------------------------------------------------------
ExportProperties()588 ExportProperties::ExportProperties() {
589 // empty
590 }
591
592 // ------------------------------------------------------------------------------------------------
ExportProperties(const ExportProperties & other)593 ExportProperties::ExportProperties(const ExportProperties &other)
594 : mIntProperties(other.mIntProperties)
595 , mFloatProperties(other.mFloatProperties)
596 , mStringProperties(other.mStringProperties)
597 , mMatrixProperties(other.mMatrixProperties)
598 , mCallbackProperties(other.mCallbackProperties){
599 // empty
600 }
601
SetPropertyCallback(const char * szName,const std::function<void * (void *)> & f)602 bool ExportProperties::SetPropertyCallback(const char *szName, const std::function<void *(void *)> &f) {
603 return SetGenericProperty<std::function<void *(void *)>>(mCallbackProperties, szName, f);
604 }
605
GetPropertyCallback(const char * szName) const606 std::function<void *(void *)> ExportProperties::GetPropertyCallback(const char *szName) const {
607 return GetGenericProperty<std::function<void *(void *)>>(mCallbackProperties, szName, 0);
608 }
609
HasPropertyCallback(const char * szName) const610 bool ExportProperties::HasPropertyCallback(const char *szName) const {
611 return HasGenericProperty<std::function<void *(void *)>>(mCallbackProperties, szName);
612 }
613
614 // ------------------------------------------------------------------------------------------------
615 // Set a configuration property
SetPropertyInteger(const char * szName,int iValue)616 bool ExportProperties::SetPropertyInteger(const char* szName, int iValue) {
617 return SetGenericProperty<int>(mIntProperties, szName,iValue);
618 }
619
620 // ------------------------------------------------------------------------------------------------
621 // Set a configuration property
SetPropertyFloat(const char * szName,ai_real iValue)622 bool ExportProperties::SetPropertyFloat(const char* szName, ai_real iValue) {
623 return SetGenericProperty<ai_real>(mFloatProperties, szName,iValue);
624 }
625
626 // ------------------------------------------------------------------------------------------------
627 // Set a configuration property
SetPropertyString(const char * szName,const std::string & value)628 bool ExportProperties::SetPropertyString(const char* szName, const std::string& value) {
629 return SetGenericProperty<std::string>(mStringProperties, szName,value);
630 }
631
632 // ------------------------------------------------------------------------------------------------
633 // Set a configuration property
SetPropertyMatrix(const char * szName,const aiMatrix4x4 & value)634 bool ExportProperties::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) {
635 return SetGenericProperty<aiMatrix4x4>(mMatrixProperties, szName,value);
636 }
637
638 // ------------------------------------------------------------------------------------------------
639 // Get a configuration property
GetPropertyInteger(const char * szName,int iErrorReturn) const640 int ExportProperties::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const {
641 return GetGenericProperty<int>(mIntProperties,szName,iErrorReturn);
642 }
643
644 // ------------------------------------------------------------------------------------------------
645 // Get a configuration property
GetPropertyFloat(const char * szName,ai_real iErrorReturn) const646 ai_real ExportProperties::GetPropertyFloat(const char* szName, ai_real iErrorReturn /*= 10e10*/) const {
647 return GetGenericProperty<ai_real>(mFloatProperties,szName,iErrorReturn);
648 }
649
650 // ------------------------------------------------------------------------------------------------
651 // Get a configuration property
GetPropertyString(const char * szName,const std::string & iErrorReturn) const652 const std::string ExportProperties::GetPropertyString(const char* szName,
653 const std::string& iErrorReturn /*= ""*/) const {
654 return GetGenericProperty<std::string>(mStringProperties,szName,iErrorReturn);
655 }
656
657 // ------------------------------------------------------------------------------------------------
658 // Has a configuration property
GetPropertyMatrix(const char * szName,const aiMatrix4x4 & iErrorReturn) const659 const aiMatrix4x4 ExportProperties::GetPropertyMatrix(const char* szName,
660 const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const {
661 return GetGenericProperty<aiMatrix4x4>(mMatrixProperties,szName,iErrorReturn);
662 }
663
664 // ------------------------------------------------------------------------------------------------
665 // Has a configuration property
HasPropertyInteger(const char * szName) const666 bool ExportProperties::HasPropertyInteger(const char* szName) const {
667 return HasGenericProperty<int>(mIntProperties, szName);
668 }
669
670 // ------------------------------------------------------------------------------------------------
671 // Has a configuration property
HasPropertyBool(const char * szName) const672 bool ExportProperties::HasPropertyBool(const char* szName) const {
673 return HasGenericProperty<int>(mIntProperties, szName);
674 }
675
676 // ------------------------------------------------------------------------------------------------
677 // Has a configuration property
HasPropertyFloat(const char * szName) const678 bool ExportProperties::HasPropertyFloat(const char* szName) const {
679 return HasGenericProperty<ai_real>(mFloatProperties, szName);
680 }
681
682 // ------------------------------------------------------------------------------------------------
683 // Has a configuration property
HasPropertyString(const char * szName) const684 bool ExportProperties::HasPropertyString(const char* szName) const {
685 return HasGenericProperty<std::string>(mStringProperties, szName);
686 }
687
688 // ------------------------------------------------------------------------------------------------
689 // Has a configuration property
HasPropertyMatrix(const char * szName) const690 bool ExportProperties::HasPropertyMatrix(const char* szName) const {
691 return HasGenericProperty<aiMatrix4x4>(mMatrixProperties, szName);
692 }
693
694
695 #endif // !ASSIMP_BUILD_NO_EXPORT
696