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