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