1 /*
2 Copyright (c) 2008-2009 NetAllied Systems GmbH
3 
4 This file is part of COLLADASaxFrameworkLoader.
5 
6 Licensed under the MIT Open Source License,
7 for details please see LICENSE file or the website
8 http://www.opensource.org/licenses/mit-license.php
9 */
10 
11 #include "COLLADASaxFWLStableHeaders.h"
12 #include "COLLADASaxFWLLoader.h"
13 #include "COLLADASaxFWLFileLoader.h"
14 #include "COLLADASaxFWLPostProcessor.h"
15 #include "COLLADASaxFWLSaxParserErrorHandler.h"
16 #include "COLLADASaxFWLUtils.h"
17 
18 #include "COLLADABUURI.h"
19 
20 #include "COLLADAFWVisualScene.h"
21 #include "COLLADAFWLibraryNodes.h"
22 #include "COLLADAFWIWriter.h"
23 #include "COLLADAFWEffect.h"
24 #include "COLLADAFWLight.h"
25 #include "COLLADAFWCamera.h"
26 #include "COLLADAFWAnimationList.h"
27 #include "COLLADAFWConstants.h"
28 
29 #include <sys/types.h>
30 #include <sys/timeb.h>
31 #include <fstream>
32 
33 namespace COLLADASaxFWL
34 {
35 
36 	const Loader::InstanceControllerDataList Loader::EMPTY_INSTANCE_CONTROLLER_DATALIST = Loader::InstanceControllerDataList();
37 
38 	const Loader::JointSidsOrIds Loader::EMPTY_JOINTSIDSORIDS;
39 
40 
Loader(IErrorHandler * errorHandler)41 	Loader::Loader( IErrorHandler* errorHandler )
42 		: mFileLoader(0)
43 		, mNextFileId(0)
44 		, mCurrentFileId(0)
45 		, mErrorHandler(errorHandler)
46 		, mNextTextureMapId(0)
47 		, mObjectFlags( Loader::ALL_OBJECTS_MASK )
48 		, mParsedObjectFlags( Loader::NO_FLAG )
49 		, mSidTreeRoot( new SidTreeNode("", 0) )
50 		, mSkinControllerSet( compare )
51 		, mExternalReferenceDeciderCallbackFunction()
52 
53 	{
54 	}
55 
56 
57 	//---------------------------------
~Loader()58 	Loader::~Loader()
59 	{
60 		delete mSidTreeRoot;
61 
62 		// delete visual scenes
63 		deleteVectorFW(mVisualScenes);
64 
65 		// delete library nodes
66 		deleteVectorFW(mLibraryNodes);
67 
68 		// delete effects
69 		deleteVectorFW(mEffects);
70 
71 		// delete lights
72 		deleteVectorFW(mLights);
73 
74 		// delete cameras
75 		deleteVectorFW(mCameras);
76 
77 		// We do not delete formulas here. They are deleted by the Formulas class
78 
79 		// delete animation lists
80 		Loader::UniqueIdAnimationListMap::const_iterator it = mUniqueIdAnimationListMap.begin();
81 		for ( ; it != mUniqueIdAnimationListMap.end(); ++it )
82 		{
83 			COLLADAFW::AnimationList* animationList = it->second;
84 			FW_DELETE animationList;
85 		}
86 	}
87 
88     //---------------------------------
getUniqueId(const COLLADABU::URI & uri,COLLADAFW::ClassId classId)89 	const COLLADAFW::UniqueId& Loader::getUniqueId( const COLLADABU::URI& uri, COLLADAFW::ClassId classId )
90 	{
91 		URIUniqueIdMap::iterator it = mURIUniqueIdMap.find(uri);
92 		if ( it == mURIUniqueIdMap.end() )
93 		{
94 			return mURIUniqueIdMap[uri] = COLLADAFW::UniqueId(classId, mLoaderUtil.getLowestObjectIdFor(classId), getFileId(uri));
95 		}
96 		else
97 		{
98 			return it->second;
99 		}
100 	}
101 
102 	//---------------------------------
getUniqueId(const COLLADABU::URI & uri)103 	const COLLADAFW::UniqueId& Loader::getUniqueId( const COLLADABU::URI& uri)
104 	{
105 		URIUniqueIdMap::iterator it = mURIUniqueIdMap.find(uri);
106 		if ( it == mURIUniqueIdMap.end() )
107 		{
108 			return COLLADAFW::UniqueId::INVALID;
109 		}
110 		else
111 		{
112 			return it->second;
113 		}
114 	}
115 
116 	//---------------------------------
getUniqueId(COLLADAFW::ClassId classId)117 	COLLADAFW::UniqueId Loader::getUniqueId( COLLADAFW::ClassId classId )
118 	{
119 		return COLLADAFW::UniqueId(classId, mLoaderUtil.getLowestObjectIdFor(classId), mCurrentFileId);
120 	}
121 
122 	//---------------------------------
getUniqueIdMap(void) const123 	const COLLADASaxFWL::Loader::URIUniqueIdMap& Loader::getUniqueIdMap(void) const
124 	{
125 		return mURIUniqueIdMap;
126 	}
127 	//---------------------------------
getFileId(const COLLADABU::URI & uri)128 	COLLADAFW::FileId Loader::getFileId( const COLLADABU::URI& uri )
129 	{
130 		// check if the uri is relative
131 		bool isRelative = uri.getScheme().empty() &&
132 			              uri.getAuthority().empty() &&
133 						  uri.getPath().empty() &&
134 						  uri.getQuery().empty();
135 		if ( isRelative )
136 		{
137 			// its a relative uri. The file id is that of the current file
138 			return mCurrentFileId;
139 		}
140 
141 		// the uri is not relative. We need to find the correct file id
142 		const COLLADABU::URI* usedUri = 0;
143 
144 		COLLADABU::URI uriWithoutFragment;
145 
146 		if ( uri.getFragment().empty() )
147 		{
148 			// the passed uri has no fragment, we can use it without modification
149 			usedUri = &uri;
150 		}
151 		else
152 		{
153 			// the passed uri has a fragment, we need to make a copy without fragment
154 			uriWithoutFragment.set( uri.getScheme(), uri.getAuthority(), uri.getPath(), uri.getQuery(), COLLADAFW::Constants::EMPTY_STRING);
155 			usedUri = &uriWithoutFragment;
156 		}
157 
158 		URIFileIdMap::iterator it = mURIFileIdMap.find( *usedUri );
159 
160 		if ( it == mURIFileIdMap.end() )
161 		{
162 			COLLADAFW::FileId fileId = mNextFileId++;
163 			addFileIdUriPair( fileId, *usedUri );
164 			return fileId;
165 		}
166 		else
167 		{
168 			return it->second;
169 		}
170 	}
171 
172 	//---------------------------------
getFileUri(COLLADAFW::FileId fileId) const173 	const COLLADABU::URI& Loader::getFileUri( COLLADAFW::FileId fileId )const
174 	{
175 		FileIdURIMap::const_iterator it = mFileIdURIMap.find( fileId );
176 
177 		if ( it == mFileIdURIMap.end() )
178 		{
179 			return COLLADABU::URI::INVALID;
180 		}
181 		else
182 		{
183 			return it->second;
184 		}
185 	}
186 
187 	//---------------------------------
addFileIdUriPair(COLLADAFW::FileId fileId,const COLLADABU::URI & uri)188 	void Loader::addFileIdUriPair( COLLADAFW::FileId fileId, const COLLADABU::URI& uri )
189 	{
190 		mURIFileIdMap[uri] = fileId;
191 		mFileIdURIMap[fileId] = uri;
192 	}
193 
194 	//---------------------------------
loadDocument(const String & fileName,COLLADAFW::IWriter * writer)195 	bool Loader::loadDocument( const String& fileName, COLLADAFW::IWriter* writer )
196 	{
197 		if ( !writer )
198 			return false;
199 		mWriter = writer;
200 
201 		mWriter->start();
202 
203 		SaxParserErrorHandler saxParserErrorHandler(mErrorHandler);
204 
205 		COLLADABU::URI rootFileUri(COLLADABU::URI::nativePathToUri(fileName));
206 
207 		// the root file has always file id 0
208 		addFileIdUriPair( mNextFileId++, rootFileUri );
209 
210 		bool abortLoading = false;
211 
212 		while ( (mCurrentFileId < mNextFileId) && !abortLoading )
213 		{
214 			const COLLADABU::URI& fileUri = getFileUri( mCurrentFileId );
215 
216 			if ( (mCurrentFileId == 0)
217 				|| !mExternalReferenceDeciderCallbackFunction
218 				|| mExternalReferenceDeciderCallbackFunction(fileUri, mCurrentFileId) )
219 			{
220 				mFileLoader = new FileLoader(this,
221 					fileUri,
222 					&saxParserErrorHandler,
223 					mObjectFlags,
224 					mParsedObjectFlags,
225 					mExtraDataCallbackHandlerList );
226 				bool success = mFileLoader->load();
227 				delete mFileLoader;
228 				abortLoading = !success;
229 			}
230 
231 			mCurrentFileId++;
232 		}
233 
234 		if ( !abortLoading )
235 		{
236 			PostProcessor postProcessor(this,
237 				&saxParserErrorHandler,
238 				mObjectFlags,
239 				mParsedObjectFlags);
240 			postProcessor.postProcess();
241 		}
242 		else
243 		{
244 			mWriter->cancel("Generic error");
245 		}
246 
247 		mWriter->finish();
248 
249 		mParsedObjectFlags |= mObjectFlags;
250 
251 		return !abortLoading;
252 	}
253 
254 	//---------------------------------
loadDocument(const String & uri,const char * buffer,int length,COLLADAFW::IWriter * writer)255 	bool Loader::loadDocument( const String& uri, const char* buffer, int length, COLLADAFW::IWriter* writer )
256 	{
257 		if ( !writer )
258 			return false;
259 		mWriter = writer;
260 
261 		SaxParserErrorHandler saxParserErrorHandler(mErrorHandler);
262 
263 		COLLADABU::URI rootUri(uri);
264 
265 		// the root file has always file id 0
266 		addFileIdUriPair( mNextFileId++, rootUri );
267 
268 		bool abortLoading = false;
269 
270 		while ( (mCurrentFileId < mNextFileId) && !abortLoading )
271 		{
272 			const COLLADABU::URI& fileUri = getFileUri( mCurrentFileId );
273 
274 			if ( (mCurrentFileId == 0)
275 				|| !mExternalReferenceDeciderCallbackFunction
276 				|| mExternalReferenceDeciderCallbackFunction(fileUri, mCurrentFileId) )
277 			{
278 				FileLoader fileLoader(this,
279 					getFileUri( mCurrentFileId ),
280 					&saxParserErrorHandler,
281 					mObjectFlags,
282 					mParsedObjectFlags,
283 					mExtraDataCallbackHandlerList );
284 				bool success = fileLoader.load(buffer, length);
285 				abortLoading = !success;
286 			}
287 
288 			mCurrentFileId++;
289 		}
290 
291 		if ( !abortLoading )
292 		{
293 			PostProcessor postProcessor(this,
294 				&saxParserErrorHandler,
295 				mObjectFlags,
296 				mParsedObjectFlags);
297 			postProcessor.postProcess();
298 		}
299 		else
300 		{
301 			mWriter->cancel("Generic error");
302 		}
303 
304 		mWriter->finish();
305 
306 		mParsedObjectFlags |= mObjectFlags;
307 
308 		return !abortLoading;
309 	}
310 
311     //---------------------------------
registerExtraDataCallbackHandler(IExtraDataCallbackHandler * extraDataCallbackHandler)312     bool Loader::registerExtraDataCallbackHandler ( IExtraDataCallbackHandler* extraDataCallbackHandler )
313     {
314         // Push the callback handler in the list of callback handlers.
315         mExtraDataCallbackHandlerList.push_back ( extraDataCallbackHandler );
316 
317         return true;
318     }
319 
320 	//---------------------------------
getMeshMaterialIdInfo()321 	GeometryMaterialIdInfo& Loader::getMeshMaterialIdInfo( )
322 	{
323 		return mGeometryMaterialIdInfo;
324 	}
325 
326 	//---------------------------------
getTextureMapIdBySematic(const String & semantic)327 	COLLADAFW::TextureMapId Loader::getTextureMapIdBySematic( const String& semantic )
328 	{
329 		StringTextureMapIdMap::iterator it = mTextureMapSemanticTextureMapIdMap.find(semantic);
330 		if ( it == mTextureMapSemanticTextureMapIdMap.end() )
331 		{
332 			return mTextureMapSemanticTextureMapIdMap[semantic] = mNextTextureMapId++;
333 		}
334 		else
335 		{
336 			return it->second;
337 		}
338 	}
339 
340 	//-----------------------------
compare(const COLLADAFW::SkinController & lhs,const COLLADAFW::SkinController & rhs)341 	bool Loader::compare( const COLLADAFW::SkinController& lhs, const COLLADAFW::SkinController& rhs )
342 	{
343 
344 		if (lhs.getSkinControllerData() < rhs.getSkinControllerData() )
345 			return true;
346 		if (lhs.getSkinControllerData() > rhs.getSkinControllerData() )
347 			return false;
348 
349 		if (lhs.getSource() < rhs.getSource() )
350 			return true;
351 		if (lhs.getSource() > rhs.getSource() )
352 			return false;
353 
354 		const COLLADAFW::UniqueIdArray& lhsJoints = lhs.getJoints();
355 		const COLLADAFW::UniqueIdArray& rhsJoints = rhs.getJoints();
356 		size_t lhsJointsCount = lhsJoints.getCount();
357 		size_t rhsJointsCount = rhsJoints.getCount();
358 		if (lhsJointsCount < rhsJointsCount )
359 			return true;
360 		if (lhsJointsCount > rhsJointsCount )
361 			return false;
362 
363 		for ( size_t i = 0; i < lhsJointsCount; ++i)
364 		{
365 			const COLLADAFW::UniqueId& lhsJoint = lhsJoints[i];
366 			const COLLADAFW::UniqueId& rhsJoint = rhsJoints[i];
367 			if (lhsJoint < rhsJoint )
368 				return true;
369 			if (lhsJoint > rhsJoint )
370 				return false;
371 		}
372 
373 		return false;
374 	}
375 
376 	//------------------------------
registerExternalReferenceDeciderCallbackFunction(ExternalReferenceDeciderCallbackFunction externalReferenceDeciderCallbackFunction)377 	void Loader::registerExternalReferenceDeciderCallbackFunction( ExternalReferenceDeciderCallbackFunction externalReferenceDeciderCallbackFunction )
378 	{
379 		mExternalReferenceDeciderCallbackFunction = externalReferenceDeciderCallbackFunction;
380 	}
381 
382 } // namespace COLLADA
383