1 /* 2 Copyright (c) 2008-2009 NetAllied Systems GmbH 3 4 This file is part of COLLADAMax. 5 6 Portions of the code are: 7 Copyright (c) 2005-2007 Feeling Software Inc. 8 Copyright (c) 2005-2007 Sony Computer Entertainment America 9 10 Based on the 3dsMax COLLADASW Tools: 11 Copyright (c) 2005-2006 Autodesk Media Entertainment 12 13 Licensed under the MIT Open Source License, 14 for details please see LICENSE file or the website 15 http://www.opensource.org/licenses/mit-license.php 16 */ 17 18 #include "COLLADAMaxStableHeaders.h" 19 #include "COLLADAMaxDocumentImporter.h" 20 #include "COLLADAMaxVisualSceneImporter.h" 21 #include "COLLADAMaxLibraryNodesImporter.h" 22 #include "COLLADAMaxGeometryImporter.h" 23 #include "COLLADAMaxMaterialImporter.h" 24 #include "COLLADAMaxMaterialCreator.h" 25 #include "COLLADAMaxEffectImporter.h" 26 #include "COLLADAMaxCameraImporter.h" 27 #include "COLLADAMaxLightImporter.h" 28 #include "COLLADAMaxImageImporter.h" 29 #include "COLLADAMaxAnimationImporter.h" 30 #include "COLLADAMaxAnimationListImporter.h" 31 #include "COLLADAMaxControllerImporter.h" 32 #include "COLLADAMaxSkinControllerDataImporter.h" 33 #include "COLLADAMaxAnimationAssigner.h" 34 #include "COLLADAMaxSceneGraphCreator.h" 35 #include "COLLADAMaxMorphControllerCreator.h" 36 #include "COLLADAMaxFWLErrorHandler.h" 37 #include "COLLADAMaxExtraDataHandler.h" 38 39 #include "COLLADAFWFileInfo.h" 40 41 #include "COLLADAFWLibraryNodes.h" 42 #include "COLLADAFWAnimationList.h" 43 #include "COLLADAFWVisualScene.h" 44 #include "COLLADAFWInstanceVisualScene.h" 45 #include "COLLADAFWScene.h" 46 47 48 #include "COLLADASaxFWLLoader.h" 49 #include "COLLADAFWRoot.h" 50 51 #include <sys/types.h> 52 #include <sys/timeb.h> 53 54 55 namespace COLLADAMax 56 { 57 58 const char AUTORING_TOOL[] = "authoring_tool"; 59 const char GOOGLE_SKETCHUP6[] = "Google SketchUp 6"; 60 const char GOOGLE_SKETCHUP70[] = "Google SketchUp 7.0"; 61 const char MICROSTATION[] = "MicroStation"; 62 63 static const COLLADABU::Math::Matrix4 X_UPAXIS_CORRECTION( 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1); 64 static const COLLADABU::Math::Matrix4 Y_UPAXIS_CORRECTION( 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 1); 65 66 67 //-------------------------------------------------------------------- DocumentImporter(Interface * maxInterface,ImpInterface * maxImportInterface,const NativeString & filepath)68 DocumentImporter::DocumentImporter(Interface * maxInterface, ImpInterface* maxImportInterface, const NativeString &filepath) 69 : mMaxInterface(maxInterface) 70 , mMaxImportInterface(maxImportInterface) 71 , mImportFilePath(filepath) 72 , mNumberOfAmbientColors(0) 73 , mDummyObject((DummyObject*) getMaxImportInterface()->Create(HELPER_CLASS_ID, Class_ID(DUMMY_CLASS_ID, 0))) 74 , mCurrentParsingPass(GENERAL_PASS) 75 , mInvertTransparency(false) 76 , mExtraDataHandler(0) 77 , mUniqueIdSkyLightMap() 78 , mVisualSceneUniqueId( COLLADAFW::UniqueId::INVALID ) 79 { 80 mUnitConversionFunctors.lengthConversion = 0; 81 mUnitConversionFunctors.inverseLengthConversion = 0; 82 mUnitConversionFunctors.angleConversion = 0; 83 mUnitConversionFunctors.timeConversion = new ScaleConversionFunctor( (float)(GetTicksPerFrame() * GetFrameRate())); 84 85 mExtraDataHandler = new ExtraDataHandler(this); 86 87 #pragma warning(disable: 4996) 88 _timeb startTimeBuffer; 89 _ftime( &startTimeBuffer ); 90 mStartTime = (double)startTimeBuffer.time + (double)startTimeBuffer.millitm / 1000; 91 #pragma warning(default: 4996) 92 } 93 94 //-------------------------------------------------------------------- ~DocumentImporter()95 DocumentImporter::~DocumentImporter() 96 { 97 // Delete all the stored library nodes 98 for ( LibraryNodesList::const_iterator it = mLibraryNodesList.begin(); it != mLibraryNodesList.end(); ++it) 99 delete *it; 100 101 // Delete all the stored library nodes 102 for ( UniqueIdVisualSceneMap::const_iterator it = mUniqueIdVisualSceneMap.begin(); it != mUniqueIdVisualSceneMap.end(); ++it) 103 delete it->second; 104 105 // Delete all the animation lists 106 for ( UniqueIdAnimationListMap::const_iterator it = mUniqueIdAnimationListMap.begin(); it != mUniqueIdAnimationListMap.end(); ++it) 107 delete it->second; 108 109 // Delete all the controllers 110 for ( UniqueIdSkinControllerMap::const_iterator it = mUniqueIdSkinControllersMap.begin(); it != mUniqueIdSkinControllersMap.end(); ++it) 111 delete it->second; 112 113 // Delete all the controllers 114 for ( UniqueIdMorphControllerMap::const_iterator it = mUniqueIdMorphControllersMap.begin(); it != mUniqueIdMorphControllersMap.end(); ++it) 115 delete it->second; 116 117 118 delete mUnitConversionFunctors.lengthConversion; 119 delete mUnitConversionFunctors.angleConversion; 120 delete mUnitConversionFunctors.timeConversion; 121 122 delete mExtraDataHandler; 123 } 124 125 //--------------------------------------------------------------- import()126 bool DocumentImporter::import() 127 { 128 FWLErrorHandler errorHandler; 129 COLLADASaxFWL::Loader loader(&errorHandler); 130 loader.registerExtraDataCallbackHandler(mExtraDataHandler); 131 COLLADAFW::Root root(&loader, this); 132 133 if ( !root.loadDocument(mImportFilePath) ) 134 return false; 135 136 if ( (mNumberOfAmbientColors > 0) && mAmbientColor.isValid() ) 137 { 138 mMaxImportInterface->SetAmbient(0, Point3(mAmbientColor.getRed(), mAmbientColor.getGreen(), mAmbientColor.getBlue() )); 139 } 140 141 if( errorHandler.hasCriticalError() ) 142 return false; 143 144 if ( !createSceneGraph() ) 145 return false; 146 147 if( errorHandler.hasCriticalError() ) 148 return false; 149 150 if ( !createMorphController() ) 151 return false; 152 153 if( errorHandler.hasCriticalError() ) 154 return false; 155 156 mCurrentParsingPass = CONTROLLER_DATA_PASS; 157 158 COLLADASaxFWL::Loader loader2(&errorHandler); 159 160 // We need the second pass to create skin controllers 161 COLLADAFW::Root root2(&loader2, this); 162 if ( !root2.loadDocument(mImportFilePath) ) 163 return false; 164 165 if( errorHandler.hasCriticalError() ) 166 return false; 167 168 MaterialCreator materialCreator(this); 169 if ( !materialCreator.create() ) 170 return false; 171 172 if( errorHandler.hasCriticalError() ) 173 return false; 174 175 if ( !assignControllers(materialCreator) ) 176 return false; 177 178 if( errorHandler.hasCriticalError() ) 179 return false; 180 181 return true; 182 } 183 184 //------------------------------ printMessage(const String & message)185 void DocumentImporter::printMessage( const String& message ) 186 { 187 char* str = (char *)message.c_str(); 188 #ifdef UNICODE 189 WideString wide = COLLADABU::StringUtils::toWideString(str); 190 mMaxInterface->ReplacePrompt(wide.c_str()); 191 #else 192 mMaxInterface->ReplacePrompt(str); 193 #endif 194 // mMaxInterface->PushPrompt(str); 195 } 196 197 //--------------------------------------------------------------- getElapsedTime() const198 double DocumentImporter::getElapsedTime() const 199 { 200 #pragma warning(disable: 4996) 201 _timeb endTimeBuffer; 202 _ftime(&endTimeBuffer); 203 #pragma warning(default: 4996) 204 double endTime = (double)endTimeBuffer.time + (double)endTimeBuffer.millitm / 1000; 205 return endTime - mStartTime; 206 } 207 208 //--------------------------------------------------------------- createMaxObject(SClass_ID superClassId,Class_ID classId)209 void* DocumentImporter::createMaxObject(SClass_ID superClassId, Class_ID classId) 210 { 211 void* c = mMaxImportInterface->Create(superClassId, classId); 212 213 if ( !c ) 214 { 215 // This can be caused if the object referred to is in a deffered plugin. 216 DllDir* dllDir = GetCOREInterface()->GetDllDirectory(); 217 ClassDirectory& classDir = dllDir->ClassDir(); 218 ClassEntry* classEntry = classDir.FindClassEntry(superClassId, classId); 219 220 if ( !classEntry ) 221 return 0; 222 223 // This will force the loading of the specified plug-in 224 classEntry->FullCD(); 225 226 if ( !classEntry->IsLoaded() ) 227 return 0; 228 229 c = mMaxImportInterface->Create(superClassId, classId); 230 } 231 return c; 232 } 233 234 //--------------------------------------------------------------- assignControllers(const MaterialCreator & materialCreator)235 bool DocumentImporter::assignControllers( const MaterialCreator& materialCreator ) 236 { 237 AnimationAssigner animationAssigner(this, materialCreator); 238 return animationAssigner.assign(); 239 } 240 241 //--------------------------------------------------------------- createSceneGraph()242 bool DocumentImporter::createSceneGraph() 243 { 244 //set first available visual scene for fallback if no scene is defined 245 UniqueIdVisualSceneMap::const_iterator it = mUniqueIdVisualSceneMap.begin(); 246 247 if(mVisualSceneUniqueId != COLLADAFW::UniqueId::INVALID) 248 { 249 it = mUniqueIdVisualSceneMap.find( mVisualSceneUniqueId ); 250 251 //reset first available visual scene for fallback if referenced visual scene could not be found 252 if( it == mUniqueIdVisualSceneMap.end() ) 253 it = mUniqueIdVisualSceneMap.begin(); 254 } 255 256 bool visualSceneAvailable = (it != mUniqueIdVisualSceneMap.end()); 257 if ( visualSceneAvailable ) 258 { 259 COLLADABU::Math::Matrix4 upAxisRotation = COLLADABU::Math::Matrix4::IDENTITY; 260 if( COLLADAFW::FileInfo::X_UP == mFileInfo.upAxis ) 261 upAxisRotation = X_UPAXIS_CORRECTION; 262 else if( COLLADAFW::FileInfo::Y_UP == mFileInfo.upAxis ) 263 upAxisRotation = Y_UPAXIS_CORRECTION; 264 //else upAxis unknown or z -> no rotation 265 266 SceneGraphCreator sceneGraphCreator(this, it->second, upAxisRotation); 267 return sceneGraphCreator.create(); 268 } 269 270 return true; 271 } 272 273 //--------------------------------------------------------------- createMorphController()274 bool DocumentImporter::createMorphController() 275 { 276 MorphControllerCreator morphControllerCreator(this); 277 return morphControllerCreator.create(); 278 } 279 280 //--------------------------------------------------------------- addAmbientColor(const COLLADAFW::Color & ambientColor)281 void DocumentImporter::addAmbientColor( const COLLADAFW::Color& ambientColor ) 282 { 283 if ( mAmbientColor.isValid()) 284 { 285 mAmbientColor.setRed( (mAmbientColor.getRed() * mNumberOfAmbientColors + ambientColor.getRed())/(mNumberOfAmbientColors+1) ); 286 mAmbientColor.setGreen( (mAmbientColor.getGreen() * mNumberOfAmbientColors + ambientColor.getGreen())/(mNumberOfAmbientColors+1) ); 287 mAmbientColor.setBlue( (mAmbientColor.getBlue() * mNumberOfAmbientColors + ambientColor.getBlue())/(mNumberOfAmbientColors+1) ); 288 mNumberOfAmbientColors++; 289 } 290 else 291 { 292 mAmbientColor = ambientColor; 293 mNumberOfAmbientColors = 1; 294 } 295 296 } 297 298 //--------------------------------------------------------------- writeGlobalAsset(const COLLADAFW::FileInfo * asset)299 bool DocumentImporter::writeGlobalAsset( const COLLADAFW::FileInfo* asset ) 300 { 301 mFileInfo.absoluteFileUri = asset->getAbsoluteFileUri(); 302 303 const COLLADAFW::FileInfo::ValuePairPointerArray& valuePairs = asset->getValuePairArray(); 304 305 for ( size_t i = 0, count = valuePairs.getCount(); i < count; ++i) 306 { 307 const COLLADAFW::FileInfo::ValuePair* valuePair = valuePairs[i]; 308 const String& key = valuePair->first; 309 const String& value = valuePair->second; 310 if ( key == AUTORING_TOOL ) 311 { 312 int googleSketchUpResult6 = value.compare(0, sizeof(GOOGLE_SKETCHUP6)-1, GOOGLE_SKETCHUP6); 313 int googleSketchUpResult70 = value.compare(0, sizeof(GOOGLE_SKETCHUP70)-1, GOOGLE_SKETCHUP70); 314 int microstationResult = value.compare(0, sizeof(MICROSTATION)-1, MICROSTATION); 315 if ( (googleSketchUpResult6 == 0) || (microstationResult == 0) || (googleSketchUpResult70 == 0)) 316 { 317 mInvertTransparency = true; 318 } 319 } 320 } 321 322 float systemUnitScale = 1.0f; 323 324 // Retrieve the system unit information 325 int systemUnitType = UNITS_CENTIMETERS; 326 GetMasterUnitInfo(&systemUnitType, &systemUnitScale); 327 328 switch (systemUnitType) 329 { 330 case UNITS_INCHES: 331 systemUnitScale *= 0.0254f; 332 break; 333 case UNITS_FEET: 334 systemUnitScale *= 0.3048f; 335 break; 336 case UNITS_MILES: 337 systemUnitScale *= 1609.344f; 338 break; 339 case UNITS_MILLIMETERS: 340 systemUnitScale *= 0.001f; 341 break; 342 case UNITS_CENTIMETERS: 343 systemUnitScale *= 0.01f; 344 break; 345 case UNITS_METERS: 346 break; 347 case UNITS_KILOMETERS: 348 systemUnitScale *= 1000.0f; 349 break; 350 default: break; 351 } 352 mFileInfo.unitScale = (float)asset->getUnit().getLinearUnitMeter() / systemUnitScale; 353 delete mUnitConversionFunctors.lengthConversion; 354 mUnitConversionFunctors.lengthConversion = new ScaleConversionFunctor(mFileInfo.unitScale); 355 if ( mFileInfo.unitScale != 0) 356 { 357 mUnitConversionFunctors.inverseLengthConversion = new ScaleConversionFunctor(1/mFileInfo.unitScale); 358 } 359 360 COLLADAFW::FileInfo::Unit::AngularUnit angularUnit = asset->getUnit().getAngularUnit(); 361 if ( angularUnit == COLLADAFW::FileInfo::Unit::DEGREES ) 362 { 363 delete mUnitConversionFunctors.angleConversion; 364 mUnitConversionFunctors.angleConversion = ConversionFunctors::degToRad.clone(); 365 } 366 367 mFileInfo.upAxis = asset->getUpAxisType(); 368 369 return true; 370 } 371 372 //--------------------------------------------------------------- writeVisualScene(const COLLADAFW::VisualScene * visualScene)373 bool DocumentImporter::writeVisualScene( const COLLADAFW::VisualScene* visualScene ) 374 { 375 if ( mCurrentParsingPass != GENERAL_PASS ) 376 return true; 377 378 VisualSceneImporter visualSceneImporter(this, visualScene); 379 return visualSceneImporter.import(); 380 } 381 382 //--------------------------------------------------------------- writeLibraryNodes(const COLLADAFW::LibraryNodes * libraryNodes)383 bool DocumentImporter::writeLibraryNodes( const COLLADAFW::LibraryNodes* libraryNodes ) 384 { 385 if ( mCurrentParsingPass != GENERAL_PASS ) 386 return true; 387 388 LibraryNodesImporter libraryNodesImporter(this, libraryNodes); 389 bool success = libraryNodesImporter.import(); 390 return success; 391 } 392 393 //--------------------------------------------------------------- writeGeometry(const COLLADAFW::Geometry * geometry)394 bool DocumentImporter::writeGeometry( const COLLADAFW::Geometry* geometry ) 395 { 396 if ( mCurrentParsingPass != GENERAL_PASS ) 397 return true; 398 399 GeometryImporter geometryImporter(this, geometry); 400 return geometryImporter.import(); 401 } 402 403 //--------------------------------------------------------------- writeMaterial(const COLLADAFW::Material * material)404 bool DocumentImporter::writeMaterial( const COLLADAFW::Material* material ) 405 { 406 if ( mCurrentParsingPass != GENERAL_PASS ) 407 return true; 408 409 MaterialImporter materialImporter(this, material); 410 return materialImporter.import(); 411 } 412 413 //--------------------------------------------------------------- writeEffect(const COLLADAFW::Effect * effect)414 bool DocumentImporter::writeEffect( const COLLADAFW::Effect* effect ) 415 { 416 if ( mCurrentParsingPass != GENERAL_PASS ) 417 return true; 418 419 EffectImporter effectImporter(this, effect); 420 return effectImporter.import(); 421 } 422 423 //--------------------------------------------------------------- writeCamera(const COLLADAFW::Camera * camera)424 bool DocumentImporter::writeCamera( const COLLADAFW::Camera* camera ) 425 { 426 if ( mCurrentParsingPass != GENERAL_PASS ) 427 return true; 428 429 CameraImporter cameraImporter(this, camera); 430 return cameraImporter.import(); 431 } 432 433 //--------------------------------------------------------------- writeImage(const COLLADAFW::Image * image)434 bool DocumentImporter::writeImage( const COLLADAFW::Image* image ) 435 { 436 if ( mCurrentParsingPass != GENERAL_PASS ) 437 return true; 438 439 ImageImporter imageImporter(this, image); 440 return imageImporter.import(); 441 } 442 443 //--------------------------------------------------------------- writeLight(const COLLADAFW::Light * light)444 bool DocumentImporter::writeLight( const COLLADAFW::Light* light ) 445 { 446 if ( mCurrentParsingPass != GENERAL_PASS ) 447 return true; 448 449 LightImporter lightImporter(this, light); 450 return lightImporter.import(); 451 } 452 453 //--------------------------------------------------------------- writeAnimation(const COLLADAFW::Animation * animation)454 bool DocumentImporter::writeAnimation( const COLLADAFW::Animation* animation ) 455 { 456 if ( mCurrentParsingPass != GENERAL_PASS ) 457 return true; 458 459 AnimationImporter animationImporter(this, animation); 460 return animationImporter.import(); 461 } 462 463 //--------------------------------------------------------------- writeAnimationList(const COLLADAFW::AnimationList * animationList)464 bool DocumentImporter::writeAnimationList( const COLLADAFW::AnimationList* animationList ) 465 { 466 if ( mCurrentParsingPass != GENERAL_PASS ) 467 return true; 468 469 AnimationListImporter animationListImporter(this, animationList); 470 return animationListImporter.import(); 471 } 472 473 //--------------------------------------------------------------- writeController(const COLLADAFW::Controller * controller)474 bool DocumentImporter::writeController( const COLLADAFW::Controller* controller ) 475 { 476 if ( mCurrentParsingPass != GENERAL_PASS ) 477 return true; 478 479 ControllerImporter controllerImporter(this, controller); 480 return controllerImporter.import(); 481 } 482 483 //--------------------------------------------------------------- writeSkinControllerData(const COLLADAFW::SkinControllerData * skinControllerData)484 bool DocumentImporter::writeSkinControllerData( const COLLADAFW::SkinControllerData* skinControllerData ) 485 { 486 if ( mCurrentParsingPass != CONTROLLER_DATA_PASS ) 487 return true; 488 489 SkinControllerDataImporter skinControllerDataImporter(this, skinControllerData); 490 return skinControllerDataImporter.import(); 491 } 492 493 //--------------------------------------------------------------- convertSpaceUnit(float originalValue)494 float DocumentImporter::convertSpaceUnit( float originalValue ) 495 { 496 return originalValue * mFileInfo.unitScale; 497 } 498 499 //--------------------------------------------------------------- writeScene(const COLLADAFW::Scene * scene)500 bool DocumentImporter::writeScene( const COLLADAFW::Scene* scene ) 501 { 502 if( scene == 0 ) 503 return true; 504 505 const COLLADAFW::InstanceVisualScene* instanceVisualScene = scene->getInstanceVisualScene(); 506 COLLADAFW::UniqueId id = instanceVisualScene->getInstanciatedObjectId(); 507 if(id.getFileId() == 0) 508 mVisualSceneUniqueId = id; 509 return true; 510 } 511 512 //--------------------------------------------------------------- addUniqueIdEffectBumpMapParametersPair(const COLLADAFW::UniqueId & effectUniqueId,const BumpMap & bumpParameters)513 void DocumentImporter::addUniqueIdEffectBumpMapParametersPair( const COLLADAFW::UniqueId& effectUniqueId, const BumpMap& bumpParameters ) 514 { 515 EffectMaps& effectMaps = getUniqueIdEffectMapsMap()[effectUniqueId]; 516 effectMaps.mBumpMap.bumpType = bumpParameters.bumpType; 517 if( effectMaps.mBumpMap.bumpType != BUMP_TYPE_INVALID ) 518 { 519 if( bumpParameters.textureAttributes ) 520 effectMaps.mBumpMap.textureAttributes = bumpParameters.textureAttributes; 521 } 522 } 523 } // namespace COLLADAMax 524