vrshoot

annotate libs/assimp/Exporter.cpp @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
rev   line source
nuclear@0 1 /*
nuclear@0 2 ---------------------------------------------------------------------------
nuclear@0 3 Open Asset Import Library (assimp)
nuclear@0 4 ---------------------------------------------------------------------------
nuclear@0 5
nuclear@0 6 Copyright (c) 2006-2012, assimp team
nuclear@0 7
nuclear@0 8 All rights reserved.
nuclear@0 9
nuclear@0 10 Redistribution and use of this software in source and binary forms,
nuclear@0 11 with or without modification, are permitted provided that the following
nuclear@0 12 conditions are met:
nuclear@0 13
nuclear@0 14 * Redistributions of source code must retain the above
nuclear@0 15 copyright notice, this list of conditions and the
nuclear@0 16 following disclaimer.
nuclear@0 17
nuclear@0 18 * Redistributions in binary form must reproduce the above
nuclear@0 19 copyright notice, this list of conditions and the
nuclear@0 20 following disclaimer in the documentation and/or other
nuclear@0 21 materials provided with the distribution.
nuclear@0 22
nuclear@0 23 * Neither the name of the assimp team, nor the names of its
nuclear@0 24 contributors may be used to endorse or promote products
nuclear@0 25 derived from this software without specific prior
nuclear@0 26 written permission of the assimp team.
nuclear@0 27
nuclear@0 28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
nuclear@0 29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
nuclear@0 30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
nuclear@0 31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
nuclear@0 32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
nuclear@0 33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
nuclear@0 34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
nuclear@0 35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
nuclear@0 36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
nuclear@0 37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
nuclear@0 38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
nuclear@0 39 ---------------------------------------------------------------------------
nuclear@0 40 */
nuclear@0 41
nuclear@0 42 /** @file Exporter.cpp
nuclear@0 43
nuclear@0 44 Assimp export interface. While it's public interface bears many similarities
nuclear@0 45 to the import interface (in fact, it is largely symmetric), the internal
nuclear@0 46 implementations differs a lot. Exporters are considered stateless and are
nuclear@0 47 simple callbacks which we maintain in a global list along with their
nuclear@0 48 description strings.
nuclear@0 49
nuclear@0 50 Here we implement only the C++ interface (Assimp::Exporter).
nuclear@0 51 */
nuclear@0 52
nuclear@0 53 #include "AssimpPCH.h"
nuclear@0 54
nuclear@0 55 #ifndef ASSIMP_BUILD_NO_EXPORT
nuclear@0 56
nuclear@0 57 #include "DefaultIOSystem.h"
nuclear@0 58 #include "BlobIOSystem.h"
nuclear@0 59 #include "SceneCombiner.h"
nuclear@0 60 #include "BaseProcess.h"
nuclear@0 61 #include "Importer.h" // need this for GetPostProcessingStepInstanceList()
nuclear@0 62
nuclear@0 63 #include "MakeVerboseFormat.h"
nuclear@0 64 #include "ConvertToLHProcess.h"
nuclear@0 65
nuclear@0 66 namespace Assimp {
nuclear@0 67
nuclear@0 68 // PostStepRegistry.cpp
nuclear@0 69 void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out);
nuclear@0 70
nuclear@0 71 // ------------------------------------------------------------------------------------------------
nuclear@0 72 // Exporter worker function prototypes. Should not be necessary to #ifndef them, it's just a prototype
nuclear@0 73 void ExportSceneCollada(const char*,IOSystem*, const aiScene*);
nuclear@0 74 void ExportSceneObj(const char*,IOSystem*, const aiScene*);
nuclear@0 75 void ExportSceneSTL(const char*,IOSystem*, const aiScene*);
nuclear@0 76 void ExportScenePly(const char*,IOSystem*, const aiScene*);
nuclear@0 77 void ExportScene3DS(const char*, IOSystem*, const aiScene*) {}
nuclear@0 78
nuclear@0 79 // ------------------------------------------------------------------------------------------------
nuclear@0 80 // global array of all export formats which Assimp supports in its current build
nuclear@0 81 Exporter::ExportFormatEntry gExporters[] =
nuclear@0 82 {
nuclear@0 83 #ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
nuclear@0 84 Exporter::ExportFormatEntry( "collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada),
nuclear@0 85 #endif
nuclear@0 86
nuclear@0 87 #ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
nuclear@0 88 Exporter::ExportFormatEntry( "obj", "Wavefront OBJ format", "obj", &ExportSceneObj,
nuclear@0 89 aiProcess_GenNormals | aiProcess_PreTransformVertices),
nuclear@0 90 #endif
nuclear@0 91
nuclear@0 92 #ifndef ASSIMP_BUILD_NO_STL_EXPORTER
nuclear@0 93 Exporter::ExportFormatEntry( "stl", "Stereolithography", "stl" , &ExportSceneSTL,
nuclear@0 94 aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices
nuclear@0 95 ),
nuclear@0 96 #endif
nuclear@0 97
nuclear@0 98 #ifndef ASSIMP_BUILD_NO_PLY_EXPORTER
nuclear@0 99 Exporter::ExportFormatEntry( "ply", "Stanford Polygon Library", "ply" , &ExportScenePly,
nuclear@0 100 aiProcess_PreTransformVertices
nuclear@0 101 ),
nuclear@0 102 #endif
nuclear@0 103
nuclear@0 104 //#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
nuclear@0 105 // ExportFormatEntry( "3ds", "Autodesk 3DS (legacy format)", "3ds" , &ExportScene3DS),
nuclear@0 106 //#endif
nuclear@0 107 };
nuclear@0 108
nuclear@0 109 #define ASSIMP_NUM_EXPORTERS (sizeof(gExporters)/sizeof(gExporters[0]))
nuclear@0 110
nuclear@0 111
nuclear@0 112 class ExporterPimpl {
nuclear@0 113 public:
nuclear@0 114
nuclear@0 115 ExporterPimpl()
nuclear@0 116 : blob()
nuclear@0 117 , mIOSystem(new Assimp::DefaultIOSystem())
nuclear@0 118 , mIsDefaultIOHandler(true)
nuclear@0 119 {
nuclear@0 120 GetPostProcessingStepInstanceList(mPostProcessingSteps);
nuclear@0 121
nuclear@0 122 // grab all builtin exporters
nuclear@0 123 mExporters.resize(ASSIMP_NUM_EXPORTERS);
nuclear@0 124 std::copy(gExporters,gExporters+ASSIMP_NUM_EXPORTERS,mExporters.begin());
nuclear@0 125 }
nuclear@0 126
nuclear@0 127 ~ExporterPimpl()
nuclear@0 128 {
nuclear@0 129 delete blob;
nuclear@0 130
nuclear@0 131 // Delete all post-processing plug-ins
nuclear@0 132 for( unsigned int a = 0; a < mPostProcessingSteps.size(); a++) {
nuclear@0 133 delete mPostProcessingSteps[a];
nuclear@0 134 }
nuclear@0 135 }
nuclear@0 136
nuclear@0 137 public:
nuclear@0 138
nuclear@0 139 aiExportDataBlob* blob;
nuclear@0 140 boost::shared_ptr< Assimp::IOSystem > mIOSystem;
nuclear@0 141 bool mIsDefaultIOHandler;
nuclear@0 142
nuclear@0 143 /** Post processing steps we can apply at the imported data. */
nuclear@0 144 std::vector< BaseProcess* > mPostProcessingSteps;
nuclear@0 145
nuclear@0 146 /** Last fatal export error */
nuclear@0 147 std::string mError;
nuclear@0 148
nuclear@0 149 /** Exporters, this includes those registered using #Assimp::Exporter::RegisterExporter */
nuclear@0 150 std::vector<Exporter::ExportFormatEntry> mExporters;
nuclear@0 151 };
nuclear@0 152
nuclear@0 153
nuclear@0 154 } // end of namespace Assimp
nuclear@0 155
nuclear@0 156
nuclear@0 157
nuclear@0 158
nuclear@0 159
nuclear@0 160 using namespace Assimp;
nuclear@0 161
nuclear@0 162
nuclear@0 163 // ------------------------------------------------------------------------------------------------
nuclear@0 164 Exporter :: Exporter()
nuclear@0 165 : pimpl(new ExporterPimpl())
nuclear@0 166 {
nuclear@0 167 }
nuclear@0 168
nuclear@0 169
nuclear@0 170 // ------------------------------------------------------------------------------------------------
nuclear@0 171 Exporter :: ~Exporter()
nuclear@0 172 {
nuclear@0 173 FreeBlob();
nuclear@0 174 }
nuclear@0 175
nuclear@0 176
nuclear@0 177 // ------------------------------------------------------------------------------------------------
nuclear@0 178 void Exporter :: SetIOHandler( IOSystem* pIOHandler)
nuclear@0 179 {
nuclear@0 180 pimpl->mIsDefaultIOHandler = !pIOHandler;
nuclear@0 181 pimpl->mIOSystem.reset(pIOHandler);
nuclear@0 182 }
nuclear@0 183
nuclear@0 184
nuclear@0 185 // ------------------------------------------------------------------------------------------------
nuclear@0 186 IOSystem* Exporter :: GetIOHandler() const
nuclear@0 187 {
nuclear@0 188 return pimpl->mIOSystem.get();
nuclear@0 189 }
nuclear@0 190
nuclear@0 191
nuclear@0 192 // ------------------------------------------------------------------------------------------------
nuclear@0 193 bool Exporter :: IsDefaultIOHandler() const
nuclear@0 194 {
nuclear@0 195 return pimpl->mIsDefaultIOHandler;
nuclear@0 196 }
nuclear@0 197
nuclear@0 198
nuclear@0 199 // ------------------------------------------------------------------------------------------------
nuclear@0 200 const aiExportDataBlob* Exporter :: ExportToBlob( const aiScene* pScene, const char* pFormatId, unsigned int pPreprocessing )
nuclear@0 201 {
nuclear@0 202 if (pimpl->blob) {
nuclear@0 203 delete pimpl->blob;
nuclear@0 204 pimpl->blob = NULL;
nuclear@0 205 }
nuclear@0 206
nuclear@0 207
nuclear@0 208 boost::shared_ptr<IOSystem> old = pimpl->mIOSystem;
nuclear@0 209
nuclear@0 210 BlobIOSystem* blobio = new BlobIOSystem();
nuclear@0 211 pimpl->mIOSystem = boost::shared_ptr<IOSystem>( blobio );
nuclear@0 212
nuclear@0 213 if (AI_SUCCESS != Export(pScene,pFormatId,blobio->GetMagicFileName())) {
nuclear@0 214 pimpl->mIOSystem = old;
nuclear@0 215 return NULL;
nuclear@0 216 }
nuclear@0 217
nuclear@0 218 pimpl->blob = blobio->GetBlobChain();
nuclear@0 219 pimpl->mIOSystem = old;
nuclear@0 220
nuclear@0 221 return pimpl->blob;
nuclear@0 222 }
nuclear@0 223
nuclear@0 224
nuclear@0 225 // ------------------------------------------------------------------------------------------------
nuclear@0 226 aiReturn Exporter :: Export( const aiScene* pScene, const char* pFormatId, const char* pPath, unsigned int pPreprocessing )
nuclear@0 227 {
nuclear@0 228 ASSIMP_BEGIN_EXCEPTION_REGION();
nuclear@0 229
nuclear@0 230 pimpl->mError = "";
nuclear@0 231 for (size_t i = 0; i < pimpl->mExporters.size(); ++i) {
nuclear@0 232 const Exporter::ExportFormatEntry& exp = pimpl->mExporters[i];
nuclear@0 233 if (!strcmp(exp.mDescription.id,pFormatId)) {
nuclear@0 234
nuclear@0 235 try {
nuclear@0 236
nuclear@0 237 // Always create a full copy of the scene. We might optimize this one day,
nuclear@0 238 // but for now it is the most pragmatic way.
nuclear@0 239 aiScene* scenecopy_tmp;
nuclear@0 240 SceneCombiner::CopyScene(&scenecopy_tmp,pScene);
nuclear@0 241
nuclear@0 242 std::auto_ptr<aiScene> scenecopy(scenecopy_tmp);
nuclear@0 243 const ScenePrivateData* const priv = ScenePriv(pScene);
nuclear@0 244
nuclear@0 245 // steps that are not idempotent, i.e. we might need to run them again, usually to get back to the
nuclear@0 246 // original state before the step was applied first. When checking which steps we don't need
nuclear@0 247 // to run, those are excluded.
nuclear@0 248 const unsigned int nonIdempotentSteps = aiProcess_FlipWindingOrder | aiProcess_FlipUVs | aiProcess_MakeLeftHanded;
nuclear@0 249
nuclear@0 250 // Erase all pp steps that were already applied to this scene
nuclear@0 251 unsigned int pp = (exp.mEnforcePP | pPreprocessing) & ~(priv
nuclear@0 252 ? (priv->mPPStepsApplied & ~nonIdempotentSteps)
nuclear@0 253 : 0u);
nuclear@0 254
nuclear@0 255 // If no extra postprocessing was specified, and we obtained this scene from an
nuclear@0 256 // Assimp importer, apply the reverse steps automatically.
nuclear@0 257 if (!pPreprocessing && priv) {
nuclear@0 258 pp |= (nonIdempotentSteps & priv->mPPStepsApplied);
nuclear@0 259 }
nuclear@0 260
nuclear@0 261 // If the input scene is not in verbose format, but there is at least postprocessing step that relies on it,
nuclear@0 262 // we need to run the MakeVerboseFormat step first.
nuclear@0 263 if (scenecopy->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) {
nuclear@0 264
nuclear@0 265 bool verbosify = false;
nuclear@0 266 for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
nuclear@0 267 BaseProcess* const p = pimpl->mPostProcessingSteps[a];
nuclear@0 268
nuclear@0 269 if (p->IsActive(pp) && p->RequireVerboseFormat()) {
nuclear@0 270 verbosify = true;
nuclear@0 271 break;
nuclear@0 272 }
nuclear@0 273 }
nuclear@0 274
nuclear@0 275 if (verbosify || (exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) {
nuclear@0 276 DefaultLogger::get()->debug("export: Scene data not in verbose format, applying MakeVerboseFormat step first");
nuclear@0 277
nuclear@0 278 MakeVerboseFormatProcess proc;
nuclear@0 279 proc.Execute(scenecopy.get());
nuclear@0 280 }
nuclear@0 281 }
nuclear@0 282
nuclear@0 283 if (pp) {
nuclear@0 284 // the three 'conversion' steps need to be executed first because all other steps rely on the standard data layout
nuclear@0 285 {
nuclear@0 286 FlipWindingOrderProcess step;
nuclear@0 287 if (step.IsActive(pp)) {
nuclear@0 288 step.Execute(scenecopy.get());
nuclear@0 289 }
nuclear@0 290 }
nuclear@0 291
nuclear@0 292 {
nuclear@0 293 FlipUVsProcess step;
nuclear@0 294 if (step.IsActive(pp)) {
nuclear@0 295 step.Execute(scenecopy.get());
nuclear@0 296 }
nuclear@0 297 }
nuclear@0 298
nuclear@0 299 {
nuclear@0 300 MakeLeftHandedProcess step;
nuclear@0 301 if (step.IsActive(pp)) {
nuclear@0 302 step.Execute(scenecopy.get());
nuclear@0 303 }
nuclear@0 304 }
nuclear@0 305
nuclear@0 306 // dispatch other processes
nuclear@0 307 for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
nuclear@0 308 BaseProcess* const p = pimpl->mPostProcessingSteps[a];
nuclear@0 309
nuclear@0 310 if (p->IsActive(pp)
nuclear@0 311 && !dynamic_cast<FlipUVsProcess*>(p)
nuclear@0 312 && !dynamic_cast<FlipWindingOrderProcess*>(p)
nuclear@0 313 && !dynamic_cast<MakeLeftHandedProcess*>(p)) {
nuclear@0 314
nuclear@0 315 p->Execute(scenecopy.get());
nuclear@0 316 }
nuclear@0 317 }
nuclear@0 318 ScenePrivateData* const privOut = ScenePriv(scenecopy.get());
nuclear@0 319 ai_assert(privOut);
nuclear@0 320
nuclear@0 321 privOut->mPPStepsApplied |= pp;
nuclear@0 322 }
nuclear@0 323
nuclear@0 324 exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get());
nuclear@0 325 }
nuclear@0 326 catch (DeadlyExportError& err) {
nuclear@0 327 pimpl->mError = err.what();
nuclear@0 328 return AI_FAILURE;
nuclear@0 329 }
nuclear@0 330 return AI_SUCCESS;
nuclear@0 331 }
nuclear@0 332 }
nuclear@0 333
nuclear@0 334 pimpl->mError = std::string("Found no exporter to handle this file format: ") + pFormatId;
nuclear@0 335 ASSIMP_END_EXCEPTION_REGION(aiReturn);
nuclear@0 336 return AI_FAILURE;
nuclear@0 337 }
nuclear@0 338
nuclear@0 339
nuclear@0 340 // ------------------------------------------------------------------------------------------------
nuclear@0 341 const char* Exporter :: GetErrorString() const
nuclear@0 342 {
nuclear@0 343 return pimpl->mError.c_str();
nuclear@0 344 }
nuclear@0 345
nuclear@0 346
nuclear@0 347 // ------------------------------------------------------------------------------------------------
nuclear@0 348 void Exporter :: FreeBlob( )
nuclear@0 349 {
nuclear@0 350 delete pimpl->blob;
nuclear@0 351 pimpl->blob = NULL;
nuclear@0 352
nuclear@0 353 pimpl->mError = "";
nuclear@0 354 }
nuclear@0 355
nuclear@0 356
nuclear@0 357 // ------------------------------------------------------------------------------------------------
nuclear@0 358 const aiExportDataBlob* Exporter :: GetBlob() const
nuclear@0 359 {
nuclear@0 360 return pimpl->blob;
nuclear@0 361 }
nuclear@0 362
nuclear@0 363
nuclear@0 364 // ------------------------------------------------------------------------------------------------
nuclear@0 365 const aiExportDataBlob* Exporter :: GetOrphanedBlob() const
nuclear@0 366 {
nuclear@0 367 const aiExportDataBlob* tmp = pimpl->blob;
nuclear@0 368 pimpl->blob = NULL;
nuclear@0 369 return tmp;
nuclear@0 370 }
nuclear@0 371
nuclear@0 372
nuclear@0 373 // ------------------------------------------------------------------------------------------------
nuclear@0 374 size_t Exporter :: GetExportFormatCount() const
nuclear@0 375 {
nuclear@0 376 return pimpl->mExporters.size();
nuclear@0 377 }
nuclear@0 378
nuclear@0 379 // ------------------------------------------------------------------------------------------------
nuclear@0 380 const aiExportFormatDesc* Exporter :: GetExportFormatDescription( size_t pIndex ) const
nuclear@0 381 {
nuclear@0 382 if (pIndex >= GetExportFormatCount()) {
nuclear@0 383 return NULL;
nuclear@0 384 }
nuclear@0 385
nuclear@0 386 return &pimpl->mExporters[pIndex].mDescription;
nuclear@0 387 }
nuclear@0 388
nuclear@0 389 // ------------------------------------------------------------------------------------------------
nuclear@0 390 aiReturn Exporter :: RegisterExporter(const ExportFormatEntry& desc)
nuclear@0 391 {
nuclear@0 392 BOOST_FOREACH(const ExportFormatEntry& e, pimpl->mExporters) {
nuclear@0 393 if (!strcmp(e.mDescription.id,desc.mDescription.id)) {
nuclear@0 394 return aiReturn_FAILURE;
nuclear@0 395 }
nuclear@0 396 }
nuclear@0 397
nuclear@0 398 pimpl->mExporters.push_back(desc);
nuclear@0 399 return aiReturn_SUCCESS;
nuclear@0 400 }
nuclear@0 401
nuclear@0 402
nuclear@0 403 // ------------------------------------------------------------------------------------------------
nuclear@0 404 void Exporter :: UnregisterExporter(const char* id)
nuclear@0 405 {
nuclear@0 406 for(std::vector<ExportFormatEntry>::iterator it = pimpl->mExporters.begin(); it != pimpl->mExporters.end(); ++it) {
nuclear@0 407 if (!strcmp((*it).mDescription.id,id)) {
nuclear@0 408 pimpl->mExporters.erase(it);
nuclear@0 409 break;
nuclear@0 410 }
nuclear@0 411 }
nuclear@0 412 }
nuclear@0 413
nuclear@0 414 #endif // !ASSIMP_BUILD_NO_EXPORT