1 //****************************************************************************//
2 // loader.cpp                                                                 //
3 // Copyright (C) 2001, 2002 Bruno 'Beosil' Heidelberger                       //
4 //****************************************************************************//
5 // This library is free software; you can redistribute it and/or modify it    //
6 // under the terms of the GNU Lesser General Public License as published by   //
7 // the Free Software Foundation; either version 2.1 of the License, or (at    //
8 // your option) any later version.                                            //
9 //****************************************************************************//
10 
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14 
15 //****************************************************************************//
16 // Includes                                                                   //
17 //****************************************************************************//
18 
19 #include "cal3d/loader.h"
20 #include "cal3d/error.h"
21 #include "cal3d/matrix.h"
22 #include "cal3d/vector.h"
23 #include "cal3d/quaternion.h"
24 #include "cal3d/coremodel.h"
25 #include "cal3d/coreskeleton.h"
26 #include "cal3d/corebone.h"
27 #include "cal3d/coreanimation.h"
28 #include "cal3d/coremesh.h"
29 #include "cal3d/coresubmesh.h"
30 #include "cal3d/corematerial.h"
31 #include "cal3d/corekeyframe.h"
32 #include "cal3d/coretrack.h"
33 #include "cal3d/tinyxml.h"
34 #include "cal3d/streamsource.h"
35 #include "cal3d/buffersource.h"
36 
37 using namespace cal3d;
38 
39 int CalLoader::loadingMode;
40 
41  /*****************************************************************************/
42 /** Sets optional flags which affect how the model is loaded into memory.
43   *
44   * This function sets the loading mode for all future loader calls.
45   *
46   * @param flags A boolean OR of any of the following flags
47   *         \li LOADER_ROTATE_X_AXIS will rotate the mesh 90 degrees about the X axis,
48   *             which has the effect of swapping Y/Z coordinates.
49   *         \li LOADER_INVERT_V_COORD will substitute (1-v) for any v texture coordinate
50   *             to eliminate the need for texture inversion after export.
51   *
52   *****************************************************************************/
setLoadingMode(int flags)53 void CalLoader::setLoadingMode(int flags)
54 {
55     loadingMode = flags;
56 }
57 
58  /*****************************************************************************/
59 /** Loads a core animation instance.
60   *
61   * This function loads a core animation instance from a file.
62   *
63   * @param strFilename The file to load the core animation instance from.
64   *
65   * @return One of the following values:
66   *         \li a pointer to the core animation
67   *         \li \b 0 if an error happened
68   *****************************************************************************/
69 
loadCoreAnimation(const std::string & strFilename,CalCoreSkeleton * skel)70 CalCoreAnimationPtr CalLoader::loadCoreAnimation(const std::string& strFilename, CalCoreSkeleton *skel)
71 {
72   if(strFilename.size()>= 3 && stricmp(strFilename.substr(strFilename.size()-3,3).c_str(),Cal::ANIMATION_XMLFILE_MAGIC)==0)
73     return loadXmlCoreAnimation(strFilename, skel);
74 
75   // open the file
76   std::ifstream file(strFilename.c_str(), std::ios::in | std::ios::binary);
77 
78   //make sure it was opened properly
79   if(!file)
80   {
81     CalError::setLastError(CalError::FILE_NOT_FOUND, __FILE__, __LINE__, strFilename);
82     return 0;
83   }
84 
85   //make a new stream data source and use it to load the animation
86   CalStreamSource streamSrc( file );
87 
88   CalCoreAnimationPtr coreanim = loadCoreAnimation( streamSrc,skel );
89   if(coreanim) coreanim->setFilename( strFilename );
90 
91   //close the file
92   file.close();
93 
94   return coreanim;
95 }
96 
97  /*****************************************************************************/
98 /** Loads a core material instance.
99   *
100   * This function loads a core material instance from a file.
101   *
102   * @param strFilename The file to load the core material instance from.
103   *
104   * @return One of the following values:
105   *         \li a pointer to the core material
106   *         \li \b 0 if an error happened
107   *****************************************************************************/
108 
loadCoreMaterial(const std::string & strFilename)109 CalCoreMaterialPtr CalLoader::loadCoreMaterial(const std::string& strFilename)
110 {
111 
112   if(strFilename.size()>= 3 && stricmp(strFilename.substr(strFilename.size()-3,3).c_str(),Cal::MATERIAL_XMLFILE_MAGIC)==0)
113     return loadXmlCoreMaterial(strFilename);
114 
115   // open the file
116   std::ifstream file;
117   file.open(strFilename.c_str(), std::ios::in | std::ios::binary);
118 
119   // make sure it opened properly
120   if(!file)
121   {
122     CalError::setLastError(CalError::FILE_NOT_FOUND, __FILE__, __LINE__, strFilename);
123     return 0;
124   }
125 
126   //make a new stream data source and use it to load the material
127   CalStreamSource streamSrc( file );
128 
129   CalCoreMaterialPtr coremat = loadCoreMaterial( streamSrc );
130 
131   if(coremat) coremat->setFilename( strFilename );
132 
133   //close the file
134   file.close();
135 
136   return coremat;
137 
138 }
139 
140  /*****************************************************************************/
141 /** Loads a core mesh instance.
142   *
143   * This function loads a core mesh instance from a file.
144   *
145   * @param strFilename The file to load the core mesh instance from.
146   *
147   * @return One of the following values:
148   *         \li a pointer to the core mesh
149   *         \li \b 0 if an error happened
150   *****************************************************************************/
151 
loadCoreMesh(const std::string & strFilename)152 CalCoreMeshPtr CalLoader::loadCoreMesh(const std::string& strFilename)
153 {
154 
155   if(strFilename.size()>= 3 && stricmp(strFilename.substr(strFilename.size()-3,3).c_str(),Cal::MESH_XMLFILE_MAGIC)==0)
156     return loadXmlCoreMesh(strFilename);
157 
158   // open the file
159   std::ifstream file;
160   file.open(strFilename.c_str(), std::ios::in | std::ios::binary);
161 
162   // make sure it opened properly
163   if(!file)
164   {
165     CalError::setLastError(CalError::FILE_NOT_FOUND, __FILE__, __LINE__, strFilename);
166     return 0;
167   }
168 
169   //make a new stream data source and use it to load the mesh
170   CalStreamSource streamSrc( file );
171 
172   CalCoreMeshPtr coremesh = loadCoreMesh( streamSrc );
173 
174   if(coremesh) coremesh->setFilename( strFilename );
175 
176 
177   //close the file
178   file.close();
179 
180   return coremesh;
181 
182 }
183 
184  /*****************************************************************************/
185 /** Loads a core skeleton instance.
186   *
187   * This function loads a core skeleton instance from a file.
188   *
189   * @param strFilename The file to load the core skeleton instance from.
190   *
191   * @return One of the following values:
192   *         \li a pointer to the core skeleton
193   *         \li \b 0 if an error happened
194   *****************************************************************************/
195 
loadCoreSkeleton(const std::string & strFilename)196 CalCoreSkeletonPtr CalLoader::loadCoreSkeleton(const std::string& strFilename)
197 {
198 
199   if(strFilename.size()>= 3 && stricmp(strFilename.substr(strFilename.size()-3,3).c_str(),Cal::SKELETON_XMLFILE_MAGIC)==0)
200     return loadXmlCoreSkeleton(strFilename);
201 
202   // open the file
203   std::ifstream file;
204   file.open(strFilename.c_str(), std::ios::in | std::ios::binary);
205 
206   //make sure it opened properly
207   if(!file)
208   {
209     CalError::setLastError(CalError::FILE_NOT_FOUND, __FILE__, __LINE__, strFilename);
210     return 0;
211   }
212 
213   //make a new stream data source and use it to load the skeleton
214   CalStreamSource streamSrc( file );
215 
216   CalCoreSkeletonPtr coreskeleton = loadCoreSkeleton( streamSrc );
217 
218   //close the file
219   file.close();
220 
221   return coreskeleton;
222 
223 }
224 
225 
226  /*****************************************************************************/
227 /** Loads a core animation instance.
228   *
229   * This function loads a core animation instance from an input stream.
230   *
231   * @param inputStream The stream to load the core animation instance from. This
232   *                    stream should be initialized and ready to be read from.
233   *
234   * @return One of the following values:
235   *         \li a pointer to the core animation
236   *         \li \b 0 if an error happened
237   *****************************************************************************/
238 
loadCoreAnimation(std::istream & inputStream,CalCoreSkeleton * skel)239 CalCoreAnimationPtr CalLoader::loadCoreAnimation(std::istream& inputStream, CalCoreSkeleton *skel )
240 {
241    //Create a new istream data source and pass it on
242    CalStreamSource streamSrc(inputStream);
243    return loadCoreAnimation(streamSrc, skel);
244 }
245 
246  /*****************************************************************************/
247 /** Loads a core material instance.
248   *
249   * This function loads a core material instance from an input stream.
250   *
251   * @param inputStream The stream to load the core material instance from. This
252   *                    stream should be initialized and ready to be read from.
253   *
254   * @return One of the following values:
255   *         \li a pointer to the core material
256   *         \li \b 0 if an error happened
257   *****************************************************************************/
258 
loadCoreMaterial(std::istream & inputStream)259 CalCoreMaterialPtr CalLoader::loadCoreMaterial(std::istream& inputStream)
260 {
261    //Create a new istream data source and pass it on
262    CalStreamSource streamSrc(inputStream);
263    return loadCoreMaterial(streamSrc);
264 }
265 
266  /*****************************************************************************/
267 /** Loads a core mesh instance.
268   *
269   * This function loads a core mesh instance from an input stream.
270   *
271   * @param inputStream The stream to load the core mesh instance from. This
272   *                    stream should be initialized and ready to be read from.
273   *
274   * @return One of the following values:
275   *         \li a pointer to the core mesh
276   *         \li \b 0 if an error happened
277   *****************************************************************************/
278 
loadCoreMesh(std::istream & inputStream)279 CalCoreMeshPtr CalLoader::loadCoreMesh(std::istream& inputStream)
280 {
281    //Create a new istream data source and pass it on
282    CalStreamSource streamSrc(inputStream);
283    return loadCoreMesh(streamSrc);
284 }
285 
286  /*****************************************************************************/
287 /** Loads a core skeleton instance.
288   *
289   * This function loads a core skeleton instance from an input stream.
290   *
291   * @param inputStream The stream to load the core skeleton instance from. This
292   *                    stream should be initialized and ready to be read from.
293   *
294   * @return One of the following values:
295   *         \li a pointer to the core skeleton
296   *         \li \b 0 if an error happened
297   *****************************************************************************/
298 
loadCoreSkeleton(std::istream & inputStream)299 CalCoreSkeletonPtr CalLoader::loadCoreSkeleton(std::istream& inputStream)
300 {
301    //Create a new istream data source and pass it on
302    CalStreamSource streamSrc(inputStream);
303    return loadCoreSkeleton(streamSrc);
304 }
305 
306 
307 
308 
309  /*****************************************************************************/
310 /** Loads a core animation instance.
311   *
312   * This function loads a core animation instance from a memory buffer.
313   *
314   * @param inputBuffer The memory buffer to load the core animation instance
315   *                    from. This buffer should be initialized and ready to
316   *                    be read from.
317   *
318   * @return One of the following values:
319   *         \li a pointer to the core animation
320   *         \li \b 0 if an error happened
321   *****************************************************************************/
322 
loadCoreAnimation(void * inputBuffer,CalCoreSkeleton * skel)323 CalCoreAnimationPtr CalLoader::loadCoreAnimation(void* inputBuffer, CalCoreSkeleton *skel)
324 {
325    //Create a new buffer data source and pass it on
326    CalBufferSource bufferSrc(inputBuffer);
327    return loadCoreAnimation(bufferSrc,skel);
328 }
329 
330  /*****************************************************************************/
331 /** Loads a core material instance.
332   *
333   * This function loads a core material instance from a memory buffer.
334   *
335   * @param inputBuffer The memory buffer to load the core material instance
336   *                    from. This buffer should be initialized and ready to
337   *                    be read from.
338   *
339   * @return One of the following values:
340   *         \li a pointer to the core material
341   *         \li \b 0 if an error happened
342   *****************************************************************************/
343 
loadCoreMaterial(void * inputBuffer)344 CalCoreMaterialPtr CalLoader::loadCoreMaterial(void* inputBuffer)
345 {
346    //Create a new buffer data source and pass it on
347    CalBufferSource bufferSrc(inputBuffer);
348    return loadCoreMaterial(bufferSrc);
349 }
350 
351  /*****************************************************************************/
352 /** Loads a core mesh instance.
353   *
354   * This function loads a core mesh instance from a memory buffer.
355   *
356   * @param inputBuffer The memory buffer to load the core mesh instance from.
357   *                    This buffer should be initialized and ready to be
358   *                    read from.
359   *
360   * @return One of the following values:
361   *         \li a pointer to the core mesh
362   *         \li \b 0 if an error happened
363   *****************************************************************************/
364 
loadCoreMesh(void * inputBuffer)365 CalCoreMeshPtr CalLoader::loadCoreMesh(void* inputBuffer)
366 {
367    //Create a new buffer data source and pass it on
368    CalBufferSource bufferSrc(inputBuffer);
369    return loadCoreMesh(bufferSrc);
370 }
371 
372  /*****************************************************************************/
373 /** Loads a core skeleton instance.
374   *
375   * This function loads a core skeleton instance from a memory buffer.
376   *
377   * @param inputBuffer The memory buffer to load the core skeleton instance
378   *                    from. This buffer should be initialized and ready to
379   *                    be read from.
380   *
381   * @return One of the following values:
382   *         \li a pointer to the core skeleton
383   *         \li \b 0 if an error happened
384   *****************************************************************************/
385 
loadCoreSkeleton(void * inputBuffer)386 CalCoreSkeletonPtr CalLoader::loadCoreSkeleton(void* inputBuffer)
387 {
388    //Create a new buffer data source and pass it on
389    CalBufferSource bufferSrc(inputBuffer);
390    return loadCoreSkeleton(bufferSrc);
391 }
392 
393  /*****************************************************************************/
394 /** Loads a core animation instance.
395   *
396   * This function loads a core animation instance from a data source.
397   *
398   * @param dataSrc The data source to load the core animation instance from.
399   *
400   * @return One of the following values:
401   *         \li a pointer to the core animation
402   *         \li \b 0 if an error happened
403   *****************************************************************************/
404 
loadCoreAnimation(CalDataSource & dataSrc,CalCoreSkeleton * skel)405 CalCoreAnimationPtr CalLoader::loadCoreAnimation(CalDataSource& dataSrc, CalCoreSkeleton *skel)
406 {
407 
408   // check if this is a valid file
409   char magic[4];
410   if(!dataSrc.readBytes(&magic[0], 4) || (memcmp(&magic[0], Cal::ANIMATION_FILE_MAGIC, 4) != 0))
411   {
412     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__);
413     return 0;
414   }
415 
416   // check if the version is compatible with the library
417   int version;
418   if(!dataSrc.readInteger(version) || (version < Cal::EARLIEST_COMPATIBLE_FILE_VERSION) || (version > Cal::CURRENT_FILE_VERSION))
419   {
420     CalError::setLastError(CalError::INCOMPATIBLE_FILE_VERSION, __FILE__, __LINE__);
421     return 0;
422   }
423 
424   // allocate a new core animation instance
425   CalCoreAnimationPtr pCoreAnimation(new CalCoreAnimation);
426   if(!pCoreAnimation)
427   {
428     CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__);
429     return 0;
430   }
431 
432   // get the duration of the core animation
433   float duration;
434   if(!dataSrc.readFloat(duration))
435   {
436     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__);
437     return 0;
438   }
439 
440   // check for a valid duration
441   if(duration <= 0.0f)
442   {
443     CalError::setLastError(CalError::INVALID_ANIMATION_DURATION, __FILE__, __LINE__);
444     return 0;
445   }
446 
447   // set the duration in the core animation instance
448   pCoreAnimation->setDuration(duration);
449 
450   // read the number of tracks
451   int trackCount;
452   if(!dataSrc.readInteger(trackCount) || (trackCount <= 0))
453   {
454     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__);
455     return 0;
456   }
457 
458 	// read flags
459 	int flags = 0;
460 	if(version >= LIBRARY_VERSION) {
461 	  if(!dataSrc.readInteger(flags))
462 		{
463 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__);
464 			return 0;
465 		}
466 	}
467 
468   // load all core bones
469   int trackId;
470   for(trackId = 0; trackId < trackCount; ++trackId)
471   {
472     // load the core track
473     CalCoreTrack *pCoreTrack;
474     pCoreTrack = loadCoreTrack(dataSrc, skel, duration, flags);
475     if(pCoreTrack == 0)
476     {
477       CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__);
478       return 0;
479     }
480 
481     // add the core track to the core animation instance
482     pCoreAnimation->addCoreTrack(pCoreTrack);
483   }
484 
485   return pCoreAnimation;
486 }
487 
488  /*****************************************************************************/
489 /** Loads a core material instance.
490   *
491   * This function loads a core material instance from a data source.
492   *
493   * @param dataSrc The data source to load the core material instance from.
494   *
495   * @return One of the following values:
496   *         \li a pointer to the core material
497   *         \li \b 0 if an error happened
498   *****************************************************************************/
499 
loadCoreMaterial(CalDataSource & dataSrc)500 CalCoreMaterialPtr CalLoader::loadCoreMaterial(CalDataSource& dataSrc)
501 {
502 
503   // check if this is a valid file
504   char magic[4];
505   if(!dataSrc.readBytes(&magic[0], 4) || (memcmp(&magic[0], Cal::MATERIAL_FILE_MAGIC, 4) != 0))
506   {
507     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__);
508     return 0;
509   }
510 
511   // check if the version is compatible with the library
512   int version;
513   if(!dataSrc.readInteger(version) || (version < Cal::EARLIEST_COMPATIBLE_FILE_VERSION) || (version > Cal::CURRENT_FILE_VERSION))
514   {
515     CalError::setLastError(CalError::INCOMPATIBLE_FILE_VERSION, __FILE__, __LINE__);
516     return 0;
517   }
518 
519   // allocate a new core material instance
520   CalCoreMaterialPtr pCoreMaterial = new CalCoreMaterial();
521   if(!pCoreMaterial)
522   {
523     CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__);
524     return 0;
525   }
526 
527   // get the ambient color of the core material
528   CalCoreMaterial::Color ambientColor;
529   dataSrc.readBytes(&ambientColor, sizeof(ambientColor));
530 
531   // get the diffuse color of the core material
532   CalCoreMaterial::Color diffuseColor;
533   dataSrc.readBytes(&diffuseColor, sizeof(diffuseColor));
534 
535   // get the specular color of the core material
536   CalCoreMaterial::Color specularColor;
537   dataSrc.readBytes(&specularColor, sizeof(specularColor));
538 
539   // get the shininess factor of the core material
540   float shininess;
541   dataSrc.readFloat(shininess);
542 
543   // check if an error happened
544   if(!dataSrc.ok())
545   {
546     dataSrc.setError();
547     return 0;
548   }
549 
550   // set the colors and the shininess
551   pCoreMaterial->setAmbientColor(ambientColor);
552   pCoreMaterial->setDiffuseColor(diffuseColor);
553   pCoreMaterial->setSpecularColor(specularColor);
554   pCoreMaterial->setShininess(shininess);
555 
556   // read the number of maps
557   int mapCount;
558   if(!dataSrc.readInteger(mapCount) || (mapCount < 0))
559   {
560     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__);
561     return 0;
562   }
563 
564   // reserve memory for all the material data
565   if(!pCoreMaterial->reserve(mapCount))
566   {
567     CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__);
568     return 0;
569   }
570 
571   // load all maps
572   int mapId;
573   for(mapId = 0; mapId < mapCount; ++mapId)
574   {
575     CalCoreMaterial::Map map;
576 
577     // read the filename of the map
578     std::string strName;
579     dataSrc.readString(map.strFilename);
580 
581     // initialize the user data
582     map.userData = 0;
583 
584     // check if an error happened
585     if(!dataSrc.ok())
586     {
587       CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__);
588       return 0;
589     }
590 
591     // set map in the core material instance
592     pCoreMaterial->setMap(mapId, map);
593   }
594 
595   return pCoreMaterial;
596 }
597 
598  /*****************************************************************************/
599 /** Loads a core mesh instance.
600   *
601   * This function loads a core mesh instance from a data source.
602   *
603   * @param dataSrc The data source to load the core mesh instance from.
604   *
605   * @return One of the following values:
606   *         \li a pointer to the core mesh
607   *         \li \b 0 if an error happened
608   *****************************************************************************/
609 
loadCoreMesh(CalDataSource & dataSrc)610 CalCoreMeshPtr CalLoader::loadCoreMesh(CalDataSource& dataSrc)
611 {
612 
613   // check if this is a valid file
614   char magic[4];
615   if(!dataSrc.readBytes(&magic[0], 4) || (memcmp(&magic[0], Cal::MESH_FILE_MAGIC, 4) != 0))
616   {
617     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__);
618     return 0;
619   }
620 
621   // check if the version is compatible with the library
622   int version;
623   if(!dataSrc.readInteger(version) || (version < Cal::EARLIEST_COMPATIBLE_FILE_VERSION) || (version > Cal::CURRENT_FILE_VERSION))
624   {
625     CalError::setLastError(CalError::INCOMPATIBLE_FILE_VERSION, __FILE__, __LINE__);
626     return 0;
627   }
628 
629   // get the number of submeshes
630   int submeshCount;
631   if(!dataSrc.readInteger(submeshCount))
632   {
633     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__);
634     return 0;
635   }
636 
637   // allocate a new core mesh instance
638   CalCoreMeshPtr pCoreMesh = new CalCoreMesh();
639   if(!pCoreMesh)
640   {
641     CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__);
642     return 0;
643   }
644 
645   // load all core submeshes
646   for(int submeshId = 0; submeshId < submeshCount; ++submeshId)
647   {
648     // load the core submesh
649     CalCoreSubmesh *pCoreSubmesh = loadCoreSubmesh(dataSrc);
650     if(pCoreSubmesh == 0)
651     {
652       return 0;
653     }
654 
655     // add the core submesh to the core mesh instance
656     pCoreMesh->addCoreSubmesh(pCoreSubmesh);
657   }
658 
659   return pCoreMesh;
660 }
661 
662  /*****************************************************************************/
663 /** Loads a core skeleton instance.
664   *
665   * This function loads a core skeleton instance from a data source.
666   *
667   * @param dataSrc The data source to load the core skeleton instance from.
668   *
669   * @return One of the following values:
670   *         \li a pointer to the core skeleton
671   *         \li \b 0 if an error happened
672   *****************************************************************************/
673 
loadCoreSkeleton(CalDataSource & dataSrc)674 CalCoreSkeletonPtr CalLoader::loadCoreSkeleton(CalDataSource& dataSrc)
675 {
676 
677   // check if this is a valid file
678   char magic[4];
679   if(!dataSrc.readBytes(&magic[0], 4) || (memcmp(&magic[0], Cal::SKELETON_FILE_MAGIC, 4) != 0))
680   {
681     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__);
682     return 0;
683   }
684 
685   // check if the version is compatible with the library
686   int version;
687   if(!dataSrc.readInteger(version) || (version < Cal::EARLIEST_COMPATIBLE_FILE_VERSION) || (version > Cal::CURRENT_FILE_VERSION))
688   {
689     CalError::setLastError(CalError::INCOMPATIBLE_FILE_VERSION, __FILE__, __LINE__);
690     return 0;
691   }
692 
693   // read the number of bones
694   int boneCount;
695   if(!dataSrc.readInteger(boneCount) || (boneCount <= 0))
696   {
697     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__);
698     return 0;
699   }
700 
701   // allocate a new core skeleton instance
702   CalCoreSkeletonPtr pCoreSkeleton = new CalCoreSkeleton();
703   if(!pCoreSkeleton)
704   {
705     CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__);
706     return 0;
707   }
708 
709   // load all core bones
710   for(int boneId = 0; boneId < boneCount; ++boneId)
711   {
712     // load the core bone
713     CalCoreBone *pCoreBone = loadCoreBones(dataSrc);
714     if(pCoreBone == 0)
715     {
716       return 0;
717     }
718 
719     // set the core skeleton of the core bone instance
720     pCoreBone->setCoreSkeleton(pCoreSkeleton.get());
721 
722     // add the core bone to the core skeleton instance
723     pCoreSkeleton->addCoreBone(pCoreBone);
724 
725     // add a core skeleton mapping of the bone's name for quick reference later
726     pCoreSkeleton->mapCoreBoneName(boneId, pCoreBone->getName());
727 
728   }
729 
730   // calculate state of the core skeleton
731   pCoreSkeleton->calculateState();
732 
733   return pCoreSkeleton;
734 }
735 
736  /*****************************************************************************/
737 /** Loads a core bone instance.
738   *
739   * This function loads a core bone instance from a data source.
740   *
741   * @param dataSrc The data source to load the core bone instance from.
742   *
743   * @return One of the following values:
744   *         \li a pointer to the core bone
745   *         \li \b 0 if an error happened
746   *****************************************************************************/
747 
loadCoreBones(CalDataSource & dataSrc)748 CalCoreBone *CalLoader::loadCoreBones(CalDataSource& dataSrc)
749 {
750   if(!dataSrc.ok())
751   {
752     dataSrc.setError();
753     return 0;
754   }
755 
756   // read the name of the bone
757   std::string strName;
758   dataSrc.readString(strName);
759 
760   // get the translation of the bone
761   float tx, ty, tz;
762   dataSrc.readFloat(tx);
763   dataSrc.readFloat(ty);
764   dataSrc.readFloat(tz);
765 
766   // get the rotation of the bone
767   float rx, ry, rz, rw;
768   dataSrc.readFloat(rx);
769   dataSrc.readFloat(ry);
770   dataSrc.readFloat(rz);
771   dataSrc.readFloat(rw);
772 
773   // get the bone space translation of the bone
774   float txBoneSpace, tyBoneSpace, tzBoneSpace;
775   dataSrc.readFloat(txBoneSpace);
776   dataSrc.readFloat(tyBoneSpace);
777   dataSrc.readFloat(tzBoneSpace);
778 
779   // get the bone space rotation of the bone
780   float rxBoneSpace, ryBoneSpace, rzBoneSpace, rwBoneSpace;
781   dataSrc.readFloat(rxBoneSpace);
782   dataSrc.readFloat(ryBoneSpace);
783   dataSrc.readFloat(rzBoneSpace);
784   dataSrc.readFloat(rwBoneSpace);
785 
786   // get the parent bone id
787   int parentId;
788   dataSrc.readInteger(parentId);
789 
790   CalQuaternion rot(rx,ry,rz,rw);
791   CalQuaternion rotbs(rxBoneSpace, ryBoneSpace, rzBoneSpace, rwBoneSpace);
792   CalVector trans(tx,ty,tz);
793 
794   if (loadingMode & LOADER_ROTATE_X_AXIS)
795   {
796     if (parentId == -1) // only root bone necessary
797     {
798       // Root bone must have quaternion rotated
799       CalQuaternion x_axis_90(0.7071067811f,0.0f,0.0f,0.7071067811f);
800       rot *= x_axis_90;
801       // Root bone must have translation rotated also
802       trans *= x_axis_90;
803     }
804   }
805 
806 
807   // check if an error happened
808   if(!dataSrc.ok())
809   {
810     dataSrc.setError();
811     return 0;
812   }
813 
814   // allocate a new core bone instance
815   CalCoreBone *pCoreBone;
816   pCoreBone = new CalCoreBone(strName);
817   if(pCoreBone == 0)
818   {
819     CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__);
820     return 0;
821   }
822 
823   // set the parent of the bone
824   pCoreBone->setParentId(parentId);
825 
826   // set all attributes of the bone
827   pCoreBone->setTranslation(trans);
828   pCoreBone->setRotation(rot);
829   pCoreBone->setTranslationBoneSpace(CalVector(txBoneSpace, tyBoneSpace, tzBoneSpace));
830   pCoreBone->setRotationBoneSpace(rotbs);
831 
832   // read the number of children
833   int childCount;
834   if(!dataSrc.readInteger(childCount) || (childCount < 0))
835   {
836     delete pCoreBone;
837     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__);
838     return 0;
839   }
840 
841   // load all children ids
842   for(; childCount > 0; childCount--)
843   {
844     int childId;
845     if(!dataSrc.readInteger(childId) || (childId < 0))
846     {
847       delete pCoreBone;
848       CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__);
849       return 0;
850     }
851 
852     pCoreBone->addChildId(childId);
853   }
854 
855   return pCoreBone;
856 }
857 
858  /*****************************************************************************/
859 /** Loads a core keyframe instance.
860   *
861   * This function loads a core keyframe instance from a data source.
862   *
863   * @param dataSrc The data source to load the core keyframe instance from.
864   *
865   * @return One of the following values:
866   *         \li a pointer to the core keyframe
867   *         \li \b 0 if an error happened
868   *****************************************************************************/
869 
loadCoreKeyframe(CalDataSource & dataSrc)870 CalCoreKeyframe* CalLoader::loadCoreKeyframe(CalDataSource& dataSrc)
871 {
872   if(!dataSrc.ok())
873   {
874     dataSrc.setError();
875     return 0;
876   }
877 
878   // get the time of the keyframe
879   float time;
880   dataSrc.readFloat(time);
881 
882   // get the translation of the bone
883   float tx, ty, tz;
884   dataSrc.readFloat(tx);
885   dataSrc.readFloat(ty);
886   dataSrc.readFloat(tz);
887 
888   // get the rotation of the bone
889   float rx, ry, rz, rw;
890   dataSrc.readFloat(rx);
891   dataSrc.readFloat(ry);
892   dataSrc.readFloat(rz);
893   dataSrc.readFloat(rw);
894 
895   // check if an error happened
896   if(!dataSrc.ok())
897   {
898     dataSrc.setError();
899     return 0;
900   }
901 
902   // allocate a new core keyframe instance
903   CalCoreKeyframe *pCoreKeyframe = new CalCoreKeyframe();
904 
905   if(pCoreKeyframe == 0)
906   {
907     CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__);
908     return 0;
909   }
910 
911   // create the core keyframe instance
912   if(!pCoreKeyframe->create())
913   {
914     delete pCoreKeyframe;
915     return 0;
916   }
917   // set all attributes of the keyframe
918   pCoreKeyframe->setTime(time);
919   pCoreKeyframe->setTranslation(CalVector(tx, ty, tz));
920   pCoreKeyframe->setRotation(CalQuaternion(rx, ry, rz, rw));
921 
922   return pCoreKeyframe;
923 }
924 
925  /*****************************************************************************/
926 /** Loads a core compressed keyframe instance.
927   *
928   * This function loads a core compressed keyframe instance from a data source.
929   *
930   * @param dataSrc The data source to load the core compressed keyframe instance from.
931   *
932   * @return One of the following values:
933   *         \li a pointer to the core keyframe
934   *         \li \b 0 if an error happened
935   *****************************************************************************/
936 
loadCompressedCoreKeyframe(CalDataSource & dataSrc,const CalVector & trackMinPt,const CalVector & trackScale,float trackDuration)937 CalCoreKeyframe *CalLoader::loadCompressedCoreKeyframe(CalDataSource& dataSrc, const CalVector& trackMinPt, const CalVector& trackScale, float trackDuration)
938 {
939   if(!dataSrc.ok())
940   {
941     dataSrc.setError();
942     return 0;
943   }
944 
945   // get the time of the keyframe
946 	unsigned short itime;
947   dataSrc.readShort((short&)itime);
948 	float time = (itime / 65535.0f) * trackDuration;
949 
950   // get the translation of the bone
951   float tx, ty, tz;
952 
953 	unsigned pt;
954 	dataSrc.readInteger((int&)pt);
955 
956 	unsigned ptx = pt & 0x7ff;
957 	unsigned pty = (pt >> 11) & 0x7ff;
958 	unsigned ptz = pt >> 22;
959 
960 	tx = ptx * trackScale.x + trackMinPt.x;
961 	ty = pty * trackScale.y + trackMinPt.y;
962 	tz = ptz * trackScale.z + trackMinPt.z;
963 
964   // get the rotation of the bone
965 	short s0, s1, s2;
966 	dataSrc.readShort(s0);
967 	dataSrc.readShort(s1);
968 	dataSrc.readShort(s2);
969 	CalQuaternion quat;
970 	quat.decompress(s0, s1, s2);
971 
972   // check if an error happened
973   if(!dataSrc.ok())
974   {
975     dataSrc.setError();
976     return 0;
977   }
978 
979   // allocate a new core keyframe instance
980   CalCoreKeyframe *pCoreKeyframe = new CalCoreKeyframe();
981 
982   if(pCoreKeyframe == 0)
983   {
984     CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__);
985     return 0;
986   }
987 
988   // create the core keyframe instance
989   if(!pCoreKeyframe->create())
990   {
991     delete pCoreKeyframe;
992     return 0;
993   }
994   // set all attributes of the keyframe
995   pCoreKeyframe->setTime(time);
996   pCoreKeyframe->setTranslation(CalVector(tx, ty, tz));
997 	pCoreKeyframe->setRotation(quat);
998 
999   return pCoreKeyframe;
1000 }
1001 
1002  /*****************************************************************************/
1003 /** Loads a core submesh instance.
1004   *
1005   * This function loads a core submesh instance from a data source.
1006   *
1007   * @param dataSrc The data source to load the core submesh instance from.
1008   *
1009   * @return One of the following values:
1010   *         \li a pointer to the core submesh
1011   *         \li \b 0 if an error happened
1012   *****************************************************************************/
1013 
loadCoreSubmesh(CalDataSource & dataSrc)1014 CalCoreSubmesh *CalLoader::loadCoreSubmesh(CalDataSource& dataSrc)
1015 {
1016 	if(!dataSrc.ok())
1017 	{
1018 		dataSrc.setError();
1019 		return 0;
1020 	}
1021 
1022 	// get the material thread id of the submesh
1023 	int coreMaterialThreadId;
1024 	dataSrc.readInteger(coreMaterialThreadId);
1025 
1026 	// get the number of vertices, faces, level-of-details and springs
1027 	int vertexCount;
1028 	dataSrc.readInteger(vertexCount);
1029 
1030 	int faceCount;
1031 	dataSrc.readInteger(faceCount);
1032 
1033 	int lodCount;
1034 	dataSrc.readInteger(lodCount);
1035 
1036 	int springCount;
1037 	dataSrc.readInteger(springCount);
1038 
1039 	// get the number of texture coordinates per vertex
1040 	int textureCoordinateCount;
1041 	dataSrc.readInteger(textureCoordinateCount);
1042 
1043 	// check if an error happened
1044 	if(!dataSrc.ok())
1045 	{
1046 		dataSrc.setError();
1047 		return 0;
1048 	}
1049 
1050 	// allocate a new core submesh instance
1051 	CalCoreSubmesh *pCoreSubmesh;
1052 	pCoreSubmesh = new CalCoreSubmesh();
1053 	if(pCoreSubmesh == 0)
1054 	{
1055 		CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__);
1056 		return 0;
1057 	}
1058 
1059 	// set the LOD step count
1060 	pCoreSubmesh->setLodCount(lodCount);
1061 
1062 	// set the core material id
1063 	pCoreSubmesh->setCoreMaterialThreadId(coreMaterialThreadId);
1064 
1065 	// reserve memory for all the submesh data
1066 	if(!pCoreSubmesh->reserve(vertexCount, textureCoordinateCount, faceCount, springCount))
1067 	{
1068 		CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__);
1069 		delete pCoreSubmesh;
1070 		return 0;
1071 	}
1072 
1073 	// load the tangent space enable flags.
1074 	int textureCoordinateId;
1075 	for (textureCoordinateId = 0; textureCoordinateId < textureCoordinateCount; textureCoordinateId++)
1076 	{
1077 		pCoreSubmesh->enableTangents(textureCoordinateId, false);
1078 	}
1079 
1080 	// load all vertices and their influences
1081 	int vertexId;
1082 	for(vertexId = 0; vertexId < vertexCount; ++vertexId)
1083 	{
1084 		CalCoreSubmesh::Vertex vertex;
1085 
1086 		// load data of the vertex
1087 		dataSrc.readFloat(vertex.position.x);
1088 		dataSrc.readFloat(vertex.position.y);
1089 		dataSrc.readFloat(vertex.position.z);
1090 		dataSrc.readFloat(vertex.normal.x);
1091 		dataSrc.readFloat(vertex.normal.y);
1092 		dataSrc.readFloat(vertex.normal.z);
1093 		dataSrc.readInteger(vertex.collapseId);
1094 		dataSrc.readInteger(vertex.faceCollapseCount);
1095 
1096 		// check if an error happened
1097 		if(!dataSrc.ok())
1098 		{
1099 			dataSrc.setError();
1100 			delete pCoreSubmesh;
1101 			return 0;
1102 		}
1103 
1104 		// load all texture coordinates of the vertex
1105 		int textureCoordinateId;
1106 		for(textureCoordinateId = 0; textureCoordinateId < textureCoordinateCount; ++textureCoordinateId)
1107 		{
1108 			CalCoreSubmesh::TextureCoordinate textureCoordinate;
1109 
1110 			// load data of the influence
1111 			dataSrc.readFloat(textureCoordinate.u);
1112 			dataSrc.readFloat(textureCoordinate.v);
1113 
1114 			if (loadingMode & LOADER_INVERT_V_COORD)
1115 			{
1116 				textureCoordinate.v = 1.0f - textureCoordinate.v;
1117 			}
1118 
1119 			// check if an error happened
1120 			if(!dataSrc.ok())
1121 			{
1122 				dataSrc.setError();
1123 				delete pCoreSubmesh;
1124 				return 0;
1125 			}
1126 
1127 			// set texture coordinate in the core submesh instance
1128 			pCoreSubmesh->setTextureCoordinate(vertexId, textureCoordinateId, textureCoordinate);
1129 		}
1130 
1131 		// get the number of influences
1132 		int influenceCount;
1133 		if(!dataSrc.readInteger(influenceCount) || (influenceCount < 0))
1134 		{
1135 			dataSrc.setError();
1136 			delete pCoreSubmesh;
1137 			return 0;
1138 		}
1139 
1140 		// reserve memory for the influences in the vertex
1141 		vertex.vectorInfluence.reserve(influenceCount);
1142 		vertex.vectorInfluence.resize(influenceCount);
1143 
1144 		// load all influences of the vertex
1145 		int influenceId;
1146 		for(influenceId = 0; influenceId < influenceCount; ++influenceId)
1147 		{
1148 			// load data of the influence
1149 			dataSrc.readInteger(vertex.vectorInfluence[influenceId].boneId),
1150 			dataSrc.readFloat(vertex.vectorInfluence[influenceId].weight);
1151 
1152 			// check if an error happened
1153 			if(!dataSrc.ok())
1154 			{
1155 				dataSrc.setError();
1156 				delete pCoreSubmesh;
1157 				return 0;
1158 			}
1159 		}
1160 
1161 		// set vertex in the core submesh instance
1162 		pCoreSubmesh->setVertex(vertexId, vertex);
1163 
1164 		// load the physical property of the vertex if there are springs in the core submesh
1165 		if(springCount > 0)
1166 		{
1167 			CalCoreSubmesh::PhysicalProperty physicalProperty;
1168 
1169 			// load data of the physical property
1170 			dataSrc.readFloat(physicalProperty.weight);
1171 
1172 			// check if an error happened
1173 			if(!dataSrc.ok())
1174 			{
1175 				dataSrc.setError();
1176 				delete pCoreSubmesh;
1177 				return 0;
1178 			}
1179 
1180 			// set the physical property in the core submesh instance
1181 			pCoreSubmesh->setPhysicalProperty(vertexId, physicalProperty);
1182 		}
1183 	}
1184 
1185 	// load all springs
1186 	int springId;
1187 	for(springId = 0; springId < springCount; ++springId)
1188 	{
1189 		CalCoreSubmesh::Spring spring;
1190 
1191 		// load data of the spring
1192 		dataSrc.readInteger(spring.vertexId[0]);
1193 		dataSrc.readInteger(spring.vertexId[1]);
1194 		dataSrc.readFloat(spring.springCoefficient);
1195 		dataSrc.readFloat(spring.idleLength);
1196 
1197 		// check if an error happened
1198 		if(!dataSrc.ok())
1199 		{
1200 			dataSrc.setError();
1201 			delete pCoreSubmesh;
1202 			return 0;
1203 		}
1204 
1205 		// set spring in the core submesh instance
1206 		pCoreSubmesh->setSpring(springId, spring);
1207 	}
1208 
1209 
1210 	// load all faces
1211 	int faceId;
1212 	int justOnce = 0;
1213 	bool flipModel = false;
1214 	for(faceId = 0; faceId < faceCount; ++faceId)
1215 	{
1216 		CalCoreSubmesh::Face face;
1217 
1218 		// load data of the face
1219 
1220 		int tmp[4];
1221 		dataSrc.readInteger(tmp[0]);
1222 		dataSrc.readInteger(tmp[1]);
1223 		dataSrc.readInteger(tmp[2]);
1224 
1225 		if(sizeof(CalIndex)==2)
1226 		{
1227 			if(tmp[0]>65535 || tmp[1]>65535 || tmp[2]>65535)
1228 			{
1229 				CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__);
1230 				delete pCoreSubmesh;
1231 				return 0;
1232 			}
1233 		}
1234 		face.vertexId[0]=tmp[0];
1235 		face.vertexId[1]=tmp[1];
1236 		face.vertexId[2]=tmp[2];
1237 
1238 		// check if an error happened
1239 		if(!dataSrc.ok())
1240 		{
1241 			dataSrc.setError();
1242 			delete pCoreSubmesh;
1243 			return 0;
1244 		}
1245 
1246 		// check if left-handed coord system is used by the object
1247 		// can be done only once since the object has one system for all faces
1248 		if (justOnce==0)
1249 		{
1250 			// get vertexes of first face
1251 			std::vector<CalCoreSubmesh::Vertex>& vectorVertex = pCoreSubmesh->getVectorVertex();
1252 			CalCoreSubmesh::Vertex& v1 = vectorVertex[tmp[0]];
1253 			CalCoreSubmesh::Vertex& v2 = vectorVertex[tmp[1]];
1254 			CalCoreSubmesh::Vertex& v3 = vectorVertex[tmp[2]];
1255 
1256 			CalVector point1 = CalVector(v1.position.x, v1.position.y, v1.position.z);
1257 			CalVector point2 = CalVector(v2.position.x, v2.position.y, v2.position.z);
1258 			CalVector point3 = CalVector(v3.position.x, v3.position.y, v3.position.z);
1259 
1260 			// gets vectors (v1-v2) and (v3-v2)
1261 			CalVector vect1 = point1 - point2;
1262 			CalVector vect2 = point3 - point2;
1263 
1264 			// calculates normal of face
1265 			CalVector cross = vect1 % vect2;
1266 			CalVector faceNormal = cross / cross.length();
1267 
1268 			// compare the calculated normal with the normal of a vertex
1269 			CalVector maxNorm = v1.normal;
1270 
1271 			// if the two vectors point to the same direction then the poly needs flipping
1272 			// so if the dot product > 0 it needs flipping
1273 			if (faceNormal*maxNorm>0)
1274 				flipModel = true;
1275 
1276 			// flip the winding order if the loading flags request it
1277 			if (loadingMode & LOADER_FLIP_WINDING)
1278 				flipModel = !flipModel;
1279 
1280 			justOnce = 1;
1281 		}
1282 
1283 
1284 		// flip if needed
1285 		if (flipModel)
1286 		{
1287 			tmp[3] = face.vertexId[1];
1288 			face.vertexId[1]=face.vertexId[2];
1289 			face.vertexId[2]=tmp[3];
1290 		}
1291 
1292 		// set face in the core submesh instance
1293 		pCoreSubmesh->setFace(faceId, face);
1294 	}
1295 
1296 	return pCoreSubmesh;
1297 }
1298 
1299  /*****************************************************************************/
1300 /** Loads a core track instance.
1301   *
1302   * This function loads a core track instance from a data source.
1303   *
1304   * @param dataSrc The data source to load the core track instance from.
1305   *
1306   * @return One of the following values:
1307   *         \li a pointer to the core track
1308   *         \li \b 0 if an error happened
1309   *****************************************************************************/
1310 
loadCoreTrack(CalDataSource & dataSrc,CalCoreSkeleton * skel,float duration,int flags)1311 CalCoreTrack *CalLoader::loadCoreTrack(CalDataSource& dataSrc, CalCoreSkeleton *skel, float duration, int flags)
1312 {
1313   if(!dataSrc.ok())
1314   {
1315     dataSrc.setError();
1316     return 0;
1317   }
1318 
1319   // read the bone id
1320   int coreBoneId;
1321   if(!dataSrc.readInteger(coreBoneId) || (coreBoneId < 0))
1322   {
1323     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__);
1324     return 0;
1325   }
1326 
1327   // allocate a new core track instance
1328   CalCoreTrack *pCoreTrack;
1329   pCoreTrack = new CalCoreTrack();
1330   if(pCoreTrack == 0)
1331   {
1332     CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__);
1333     return 0;
1334   }
1335 
1336   // create the core track instance
1337   if(!pCoreTrack->create())
1338   {
1339     delete pCoreTrack;
1340     return 0;
1341   }
1342 
1343   // link the core track to the appropriate core bone instance
1344   pCoreTrack->setCoreBoneId(coreBoneId);
1345 
1346   // read the number of keyframes
1347   int keyframeCount;
1348   if(!dataSrc.readInteger(keyframeCount) || (keyframeCount <= 0))
1349   {
1350     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__);
1351     return 0;
1352   }
1353 
1354 	CalVector minpt, scale;
1355 	if(flags & 1)
1356 	{
1357 		dataSrc.readFloat(minpt.x);
1358 		dataSrc.readFloat(minpt.y);
1359 		dataSrc.readFloat(minpt.z);
1360 		dataSrc.readFloat(scale.x);
1361 		dataSrc.readFloat(scale.y);
1362 		dataSrc.readFloat(scale.z);
1363 	}
1364 
1365   // load all core keyframes
1366   int keyframeId;
1367   for(keyframeId = 0; keyframeId < keyframeCount; ++keyframeId)
1368   {
1369     // load the core keyframe
1370     CalCoreKeyframe *pCoreKeyframe;
1371 
1372 		if(flags & 1)
1373 		{
1374 			pCoreKeyframe = loadCompressedCoreKeyframe(dataSrc, minpt, scale, duration);
1375 		}
1376 		else
1377 		{
1378 			pCoreKeyframe = loadCoreKeyframe(dataSrc);
1379 		}
1380 
1381     if(pCoreKeyframe == 0)
1382     {
1383       pCoreTrack->destroy();
1384       delete pCoreTrack;
1385       return 0;
1386     }
1387     if(loadingMode & LOADER_ROTATE_X_AXIS)
1388     {
1389       // Check for anim rotation
1390       if (skel && skel->getCoreBone(coreBoneId)->getParentId() == -1)  // root bone
1391       {
1392         // rotate root bone quaternion
1393         CalQuaternion rot = pCoreKeyframe->getRotation();
1394         CalQuaternion x_axis_90(0.7071067811f,0.0f,0.0f,0.7071067811f);
1395         rot *= x_axis_90;
1396         pCoreKeyframe->setRotation(rot);
1397         // rotate root bone displacement
1398         CalVector vec = pCoreKeyframe->getTranslation();
1399 				vec *= x_axis_90;
1400         pCoreKeyframe->setTranslation(vec);
1401       }
1402     }
1403 
1404     // add the core keyframe to the core track instance
1405     pCoreTrack->addCoreKeyframe(pCoreKeyframe);
1406   }
1407 
1408   return pCoreTrack;
1409 }
1410 
1411 
1412  /*****************************************************************************/
1413 /** Loads a core skeleton instance from a XML file.
1414   *
1415   * This function loads a core skeleton instance from a XML file.
1416   *
1417   * @param strFilename The name of the file to load the core skeleton instance
1418   *                    from.
1419   *
1420   * @return One of the following values:
1421   *         \li a pointer to the core skeleton
1422   *         \li \b 0 if an error happened
1423   *****************************************************************************/
1424 
loadXmlCoreSkeleton(const std::string & strFilename)1425 CalCoreSkeletonPtr CalLoader::loadXmlCoreSkeleton(const std::string& strFilename)
1426 {
1427 	std::stringstream str;
1428 	TiXmlDocument doc(strFilename);
1429 	if(!doc.LoadFile())
1430 	{
1431 		CalError::setLastError(CalError::FILE_NOT_FOUND, __FILE__, __LINE__, strFilename);
1432 		return 0;
1433 	}
1434 
1435 	TiXmlNode* node;
1436 	TiXmlElement*skeleton = doc.FirstChildElement();
1437 	if(!skeleton)
1438 	{
1439 		CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1440 		return 0;
1441 	}
1442 
1443 	if(stricmp(skeleton->Value(),"HEADER")==0)
1444 	{
1445 		if(stricmp(skeleton->Attribute("MAGIC"),Cal::SKELETON_XMLFILE_MAGIC)!=0)
1446 		{
1447 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1448 			return 0;
1449 		}
1450 
1451 		if(atoi(skeleton->Attribute("VERSION")) < Cal::EARLIEST_COMPATIBLE_FILE_VERSION )
1452 		{
1453 			CalError::setLastError(CalError::INCOMPATIBLE_FILE_VERSION, __FILE__, __LINE__, strFilename);
1454 			return 0;
1455 		}
1456 
1457 		skeleton = skeleton->NextSiblingElement();
1458 	}
1459 
1460 	if(!skeleton || stricmp(skeleton->Value(),"SKELETON")!=0)
1461 	{
1462 		CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1463 		return 0;
1464 	}
1465 
1466 	if(skeleton->Attribute("MAGIC")!=NULL && stricmp(skeleton->Attribute("MAGIC"),Cal::SKELETON_XMLFILE_MAGIC)!=0)
1467 	{
1468 		CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1469 		return 0;
1470 	}
1471 
1472 	if(skeleton->Attribute("VERSION")!=NULL && atoi(skeleton->Attribute("VERSION")) < Cal::EARLIEST_COMPATIBLE_FILE_VERSION )
1473 	{
1474 		CalError::setLastError(CalError::INCOMPATIBLE_FILE_VERSION, __FILE__, __LINE__, strFilename);
1475 		return 0;
1476 	}
1477 
1478 
1479 	// allocate a new core skeleton instance
1480 	CalCoreSkeletonPtr pCoreSkeleton = new CalCoreSkeleton();
1481 	if(!pCoreSkeleton)
1482 	{
1483 		CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__);
1484 		return 0;
1485 	}
1486 
1487 	TiXmlElement* bone;
1488 	for( bone = skeleton->FirstChildElement();bone;bone = bone->NextSiblingElement() )
1489 	{
1490 		if(stricmp(bone->Value(),"BONE")!=0)
1491 		{
1492 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1493 			return 0;
1494 		}
1495 
1496 		std::string strName=bone->Attribute("NAME");
1497 
1498 
1499 		// get the translation of the bone
1500 
1501 		TiXmlElement* translation = bone->FirstChildElement();
1502 		if(!translation || stricmp( translation->Value(),"TRANSLATION")!=0)
1503 		{
1504 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1505 			return 0;
1506 		}
1507 
1508 		float tx, ty, tz;
1509 
1510 		node = translation->FirstChild();
1511 		if(!node)
1512 		{
1513 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1514 			return 0;
1515 		}
1516 		TiXmlText* translationdata = node->ToText();
1517 		if(!translationdata)
1518 		{
1519 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1520 			return 0;
1521 		}
1522 		str.clear();
1523 		str << translationdata->Value();
1524 		str >> tx >> ty >> tz;
1525 
1526 		// get the rotation of the bone
1527 
1528 		TiXmlElement* rotation = translation->NextSiblingElement();
1529 		if(!rotation || stricmp(rotation->Value(),"ROTATION")!=0)
1530 		{
1531 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1532 			return 0;
1533 		}
1534 
1535 		float rx, ry, rz, rw;
1536 
1537 		node = rotation->FirstChild();
1538 		if(!node)
1539 		{
1540 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1541 			return 0;
1542 		}
1543 		TiXmlText* rotationdata = node->ToText();
1544 		if(!rotationdata)
1545 		{
1546 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1547 			return 0;
1548 		}
1549 		str.clear();
1550 		str << rotationdata->Value();
1551 		str >> rx >> ry >> rz >> rw;
1552 
1553 		// get the bone space translation of the bone
1554 
1555 
1556 		TiXmlElement* translationBoneSpace = rotation->NextSiblingElement();
1557 		if(!rotation || stricmp(translationBoneSpace->Value(),"LOCALTRANSLATION")!=0)
1558 		{
1559 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1560 			return 0;
1561 		}
1562 
1563 		float txBoneSpace, tyBoneSpace, tzBoneSpace;
1564 
1565 		node = translationBoneSpace->FirstChild();
1566 		if(!node)
1567 		{
1568 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1569 			return 0;
1570 		}
1571 		TiXmlText* translationBoneSpacedata = node->ToText();
1572 		if(!translationBoneSpacedata)
1573 		{
1574 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1575 			return 0;
1576 		}
1577 		str.clear();
1578 		str << translationBoneSpacedata->Value();
1579 		str >> txBoneSpace >> tyBoneSpace >> tzBoneSpace;
1580 
1581 		// get the bone space rotation of the bone
1582 
1583 		TiXmlElement* rotationBoneSpace = translationBoneSpace->NextSiblingElement();
1584 		if(!rotationBoneSpace || stricmp(rotationBoneSpace->Value(),"LOCALROTATION")!=0)
1585 		{
1586 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1587 			return 0;
1588 		}
1589 
1590 		float rxBoneSpace, ryBoneSpace, rzBoneSpace, rwBoneSpace;
1591 
1592 		node = rotationBoneSpace->FirstChild();
1593 		if(!node)
1594 		{
1595 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1596 			return 0;
1597 		}
1598 		TiXmlText* rotationBoneSpacedata = node->ToText();
1599 		if(!rotationBoneSpacedata)
1600 		{
1601 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1602 			return 0;
1603 		}
1604 		str.clear();
1605 		str << rotationBoneSpacedata->Value();
1606 		str >> rxBoneSpace >> ryBoneSpace >> rzBoneSpace >> rwBoneSpace;
1607 
1608 		// get the parent bone id
1609 
1610 		TiXmlElement* parent = rotationBoneSpace->NextSiblingElement();
1611 		if(!parent ||stricmp(parent->Value(),"PARENTID")!=0)
1612 		{
1613 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1614 			return 0;
1615 		}
1616 
1617 
1618 		int parentId;
1619 
1620 		node = parent->FirstChild();
1621 		if(!node)
1622 		{
1623 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1624 			return 0;
1625 		}
1626 		TiXmlText* parentid = node->ToText();
1627 		if(!parentid)
1628 		{
1629 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1630 			return 0;
1631 		}
1632 		parentId = atoi(parentid->Value());
1633 
1634 		// allocate a new core bone instance
1635 		CalCoreBone *pCoreBone = new CalCoreBone(strName);
1636 		if(pCoreBone == 0)
1637 		{
1638 			CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__);
1639 			return 0;
1640 		}
1641 
1642 		// set the parent of the bone
1643 		pCoreBone->setParentId(parentId);
1644 
1645 		// set all attributes of the bone
1646 
1647 		CalVector trans = CalVector(tx, ty, tz);
1648 		CalQuaternion rot = CalQuaternion(rx, ry, rz, rw);
1649 
1650 		if (loadingMode & LOADER_ROTATE_X_AXIS)
1651 		{
1652 			if (parentId == -1) // only root bone necessary
1653 			{
1654 				// Root bone must have quaternion rotated
1655 				CalQuaternion x_axis_90(0.7071067811f,0.0f,0.0f,0.7071067811f);
1656 				rot *= x_axis_90;
1657 				// Root bone must have translation rotated also
1658 				trans *= x_axis_90;
1659 			}
1660 		}
1661 
1662 
1663 		pCoreBone->setTranslation(trans);
1664 		pCoreBone->setRotation(rot);
1665 		pCoreBone->setTranslationBoneSpace(CalVector(txBoneSpace, tyBoneSpace, tzBoneSpace));
1666 		pCoreBone->setRotationBoneSpace(CalQuaternion(rxBoneSpace, ryBoneSpace, rzBoneSpace, rwBoneSpace));
1667 
1668 
1669 		TiXmlElement* child;
1670 		for( child = parent->NextSiblingElement();child;child = child->NextSiblingElement() )
1671 		{
1672 			if(stricmp(child->Value(),"CHILDID")!=0)
1673 			{
1674 				CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1675 				delete pCoreBone;
1676 				return 0;
1677 			}
1678 
1679 			TiXmlNode *node= child->FirstChild();
1680 			if(!node)
1681 			{
1682 				CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1683 				delete pCoreBone;
1684 				return 0;
1685 			}
1686 			TiXmlText* childid = node->ToText();
1687 			if(!childid)
1688 			{
1689 				CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1690 				delete pCoreBone;
1691 				return 0;
1692 			}
1693 
1694 			int childId = atoi(childid->Value());
1695 
1696 			pCoreBone->addChildId(childId);
1697 		}
1698 
1699 		// set the core skeleton of the core bone instance
1700 		pCoreBone->setCoreSkeleton(pCoreSkeleton.get());
1701 
1702 		// add the core bone to the core skeleton instance
1703 		pCoreSkeleton->addCoreBone(pCoreBone);
1704 
1705 	}
1706 
1707 	doc.Clear();
1708 
1709 	pCoreSkeleton->calculateState();
1710 
1711 	return pCoreSkeleton;
1712 }
1713 
1714  /*****************************************************************************/
1715 /** Loads a core animation instance from a XML file.
1716   *
1717   * This function loads a core animation instance from a XML file.
1718   *
1719   * @param strFilename The name of the file to load the core animation instance
1720   *                    from.
1721   *
1722   * @return One of the following values:
1723   *         \li a pointer to the core animation
1724   *         \li \b 0 if an error happened
1725   *****************************************************************************/
1726 
loadXmlCoreAnimation(const std::string & strFilename,CalCoreSkeleton * skel)1727 CalCoreAnimationPtr CalLoader::loadXmlCoreAnimation(const std::string& strFilename, CalCoreSkeleton *skel)
1728 {
1729 	std::stringstream str;
1730 	TiXmlDocument doc(strFilename);
1731 	if(!doc.LoadFile())
1732 	{
1733 		CalError::setLastError(CalError::FILE_NOT_FOUND, __FILE__, __LINE__, strFilename);
1734 		return 0;
1735 	}
1736 
1737 	TiXmlNode* node;
1738 
1739 	TiXmlElement*animation = doc.FirstChildElement();
1740 	if(!animation)
1741 	{
1742 		CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1743 		return 0;
1744 	}
1745 
1746 	if(stricmp(animation->Value(),"HEADER")==0)
1747 	{
1748 		if(stricmp(animation->Attribute("MAGIC"),Cal::ANIMATION_XMLFILE_MAGIC)!=0)
1749 		{
1750 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1751 			return 0;
1752 		}
1753 
1754 		if(atoi(animation->Attribute("VERSION")) < Cal::EARLIEST_COMPATIBLE_FILE_VERSION )
1755 		{
1756 			CalError::setLastError(CalError::INCOMPATIBLE_FILE_VERSION, __FILE__, __LINE__, strFilename);
1757 			return 0;
1758 		}
1759 
1760 		animation = animation->NextSiblingElement();
1761 	}
1762 
1763 	if(!animation || stricmp(animation->Value(),"ANIMATION")!=0)
1764 	{
1765 		CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1766 		return 0;
1767 	}
1768 
1769 	if(animation->Attribute("MAGIC") !=NULL && stricmp(animation->Attribute("MAGIC"),Cal::ANIMATION_XMLFILE_MAGIC)!=0)
1770 	{
1771 		CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1772 		return 0;
1773 	}
1774 
1775 	if(animation->Attribute("VERSION")!=NULL && atoi(animation->Attribute("VERSION")) < Cal::EARLIEST_COMPATIBLE_FILE_VERSION )
1776 	{
1777 		CalError::setLastError(CalError::INCOMPATIBLE_FILE_VERSION, __FILE__, __LINE__, strFilename);
1778 		return 0;
1779 	}
1780 
1781 	int trackCount= atoi(animation->Attribute("NUMTRACKS"));
1782 	float duration= (float) atof(animation->Attribute("DURATION"));
1783 
1784 	// allocate a new core animation instance
1785 	CalCoreAnimation *pCoreAnimation;
1786 	pCoreAnimation = new CalCoreAnimation();
1787 	if(pCoreAnimation == 0)
1788 	{
1789 		CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__);
1790 		return 0;
1791 	}
1792 
1793 	// check for a valid duration
1794 	if(duration <= 0.0f)
1795 	{
1796 		CalError::setLastError(CalError::INVALID_ANIMATION_DURATION, __FILE__, __LINE__, strFilename);
1797 		return 0;
1798 	}
1799 
1800 	// set the duration in the core animation instance
1801 	pCoreAnimation->setDuration(duration);
1802 	TiXmlElement* track=animation->FirstChildElement();
1803 
1804 	// load all core bones
1805 	int trackId;
1806 	for(trackId = 0; trackId < trackCount; ++trackId)
1807 	{
1808 		if(!track || stricmp(track->Value(),"TRACK")!=0)
1809 		{
1810 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1811 			return 0;
1812 		}
1813 
1814 		CalCoreTrack *pCoreTrack;
1815 
1816 		pCoreTrack = new CalCoreTrack();
1817 		if(pCoreTrack == 0)
1818 		{
1819 			CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__);
1820 			return 0;
1821 		}
1822 
1823 		// create the core track instance
1824 		if(!pCoreTrack->create())
1825 		{
1826 			delete pCoreTrack;
1827 			return 0;
1828 		}
1829 
1830 		int coreBoneId = atoi(track->Attribute("BONEID"));
1831 
1832 		// link the core track to the appropriate core bone instance
1833 		pCoreTrack->setCoreBoneId(coreBoneId);
1834 
1835 		// read the number of keyframes
1836 		int keyframeCount= atoi(track->Attribute("NUMKEYFRAMES"));
1837 
1838 		if(keyframeCount <= 0)
1839 		{
1840 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1841 			return 0;
1842 		}
1843 
1844 		TiXmlElement* keyframe= track->FirstChildElement();
1845 
1846 		// load all core keyframes
1847 		int keyframeId;
1848 		for(keyframeId = 0; keyframeId < keyframeCount; ++keyframeId)
1849 		{
1850 			// load the core keyframe
1851 			if(!keyframe|| stricmp(keyframe->Value(),"KEYFRAME")!=0)
1852 			{
1853 				CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1854 				return 0;
1855 			}
1856 
1857 			float time= (float) atof(keyframe->Attribute("TIME"));
1858 
1859 			TiXmlElement* translation = keyframe->FirstChildElement();
1860 			if(!translation || stricmp(translation->Value(),"TRANSLATION")!=0)
1861 			{
1862 				CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1863 				return 0;
1864 			}
1865 
1866 			float tx, ty, tz;
1867 
1868 			node = translation->FirstChild();
1869 			if(!node)
1870 			{
1871 				CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1872 				return 0;
1873 			}
1874 
1875 			TiXmlText* translationdata = node->ToText();
1876 			if(!translationdata)
1877 			{
1878 				CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1879 				return 0;
1880 			}
1881 			str.clear();
1882 			str << translationdata->Value();
1883 			str >> tx >> ty >> tz;
1884 
1885 			TiXmlElement* rotation = translation->NextSiblingElement();
1886 			if(!rotation || stricmp(rotation->Value(),"ROTATION")!=0)
1887 			{
1888 				CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1889 				return 0;
1890 			}
1891 
1892 			float rx, ry, rz, rw;
1893 
1894 			node = rotation->FirstChild();
1895 			if(!node)
1896 			{
1897 				CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1898 				return 0;
1899 			}
1900 			TiXmlText* rotationdata = node->ToText();
1901 			if(!rotationdata)
1902 			{
1903 				CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1904 				return 0;
1905 			}
1906 			str.clear();
1907 			str << rotationdata->Value();
1908 			str >> rx >> ry >> rz >> rw;
1909 
1910 			// allocate a new core keyframe instance
1911 
1912 			CalCoreKeyframe *pCoreKeyframe;
1913 			pCoreKeyframe = new CalCoreKeyframe();
1914 			if(pCoreKeyframe == 0)
1915 			{
1916 				CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__);
1917 				return 0;
1918 			}
1919 
1920 			// create the core keyframe instance
1921 			if(!pCoreKeyframe->create())
1922 			{
1923 				return 0;
1924 			}
1925 			// set all attributes of the keyframe
1926 			pCoreKeyframe->setTime(time);
1927 			pCoreKeyframe->setTranslation(CalVector(tx, ty, tz));
1928 			pCoreKeyframe->setRotation(CalQuaternion(rx, ry, rz, rw));
1929 
1930 			if (loadingMode & LOADER_ROTATE_X_AXIS)
1931 			{
1932 				// Check for anim rotation
1933 				if (skel && skel->getCoreBone(coreBoneId)->getParentId() == -1)  // root bone
1934 				{
1935 					// rotate root bone quaternion
1936 					CalQuaternion rot = pCoreKeyframe->getRotation();
1937 					CalQuaternion x_axis_90(0.7071067811f,0.0f,0.0f,0.7071067811f);
1938 					rot *= x_axis_90;
1939 					pCoreKeyframe->setRotation(rot);
1940 					// rotate root bone displacement
1941 					CalVector trans = pCoreKeyframe->getTranslation();
1942 					trans *= x_axis_90;
1943 					pCoreKeyframe->setTranslation(trans);
1944 				}
1945 			}
1946 
1947 			// add the core keyframe to the core track instance
1948 			pCoreTrack->addCoreKeyframe(pCoreKeyframe);
1949 			keyframe = keyframe->NextSiblingElement();
1950 		}
1951 
1952 		pCoreAnimation->addCoreTrack(pCoreTrack);
1953 		track=track->NextSiblingElement();
1954 	}
1955 
1956 	// explicitly close the file
1957 	doc.Clear();
1958 
1959 	return pCoreAnimation;
1960 }
1961 
1962  /*****************************************************************************/
1963 /** Loads a core mesh instance from a Xml file.
1964   *
1965   * This function loads a core mesh instance from a Xml file.
1966   *
1967   * @param strFilename The name of the file to load the core mesh instance from.
1968   *
1969   * @return One of the following values:
1970   *         \li a pointer to the core mesh
1971   *         \li \b 0 if an error happened
1972   *****************************************************************************/
1973 
loadXmlCoreMesh(const std::string & strFilename)1974 CalCoreMeshPtr CalLoader::loadXmlCoreMesh(const std::string& strFilename)
1975 {
1976 	std::stringstream str;
1977 	TiXmlDocument doc(strFilename);
1978 	if(!doc.LoadFile())
1979 	{
1980 		CalError::setLastError(CalError::FILE_NOT_FOUND, __FILE__, __LINE__, strFilename);
1981 		return 0;
1982 	}
1983 
1984 	TiXmlNode* node;
1985 
1986 	TiXmlElement*mesh = doc.FirstChildElement();
1987 	if(!mesh)
1988 	{
1989 		CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1990 		return 0;
1991 	}
1992 
1993 	if(stricmp(mesh->Value(),"HEADER")==0)
1994 	{
1995 		if(stricmp(mesh->Attribute("MAGIC"),Cal::MESH_XMLFILE_MAGIC)!=0)
1996 		{
1997 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
1998 			return 0;
1999 		}
2000 
2001 		if(atoi(mesh->Attribute("VERSION")) < Cal::EARLIEST_COMPATIBLE_FILE_VERSION )
2002 		{
2003 			CalError::setLastError(CalError::INCOMPATIBLE_FILE_VERSION, __FILE__, __LINE__, strFilename);
2004 			return 0;
2005 		}
2006 
2007 		mesh = mesh->NextSiblingElement();
2008 	}
2009 	if(!mesh || stricmp(mesh->Value(),"MESH")!=0)
2010 	{
2011 		CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2012 		return 0;
2013 	}
2014 
2015 	if(mesh->Attribute("MAGIC")!=NULL && stricmp(mesh->Attribute("MAGIC"),Cal::MESH_XMLFILE_MAGIC)!=0)
2016 	{
2017 		CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2018 		return 0;
2019 	}
2020 
2021 	if(mesh->Attribute("VERSION")!=NULL && atoi(mesh->Attribute("VERSION")) < Cal::EARLIEST_COMPATIBLE_FILE_VERSION )
2022 	{
2023 		CalError::setLastError(CalError::INCOMPATIBLE_FILE_VERSION, __FILE__, __LINE__, strFilename);
2024 		return 0;
2025 	}
2026 
2027 	// get the number of submeshes
2028 	int submeshCount = atoi(mesh->Attribute("NUMSUBMESH"));
2029 
2030 	// allocate a new core mesh instance
2031 	CalCoreMeshPtr pCoreMesh = new CalCoreMesh;
2032 	if(!pCoreMesh)
2033 	{
2034 		CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__);
2035 		return 0;
2036 	}
2037 
2038 	TiXmlElement*submesh = mesh->FirstChildElement();
2039 
2040 	// load all core submeshes
2041 	int submeshId;
2042 	for(submeshId = 0; submeshId < submeshCount; ++submeshId)
2043 	{
2044 		if(!submesh || stricmp(submesh->Value(),"SUBMESH")!=0)
2045 		{
2046 			CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2047 			return 0;
2048 		}
2049 
2050 		// get the material thread id of the submesh
2051 		int coreMaterialThreadId = atoi(submesh->Attribute("MATERIAL"));
2052 
2053 		// get the number of vertices, faces, level-of-details and springs
2054 		int vertexCount = atoi(submesh->Attribute("NUMVERTICES"));
2055 
2056 		int faceCount = atoi(submesh->Attribute("NUMFACES"));
2057 
2058 		int lodCount = atoi(submesh->Attribute("NUMLODSTEPS"));
2059 
2060 		int springCount = atoi(submesh->Attribute("NUMSPRINGS"));
2061 
2062 		int textureCoordinateCount = atoi(submesh->Attribute("NUMTEXCOORDS"));
2063 
2064 		// allocate a new core submesh instance
2065 		CalCoreSubmesh *pCoreSubmesh = new CalCoreSubmesh();
2066 		if(pCoreSubmesh == 0)
2067 		{
2068 			CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__);
2069 			return 0;
2070 		}
2071 
2072 		// set the LOD step count
2073 		pCoreSubmesh->setLodCount(lodCount);
2074 
2075 		// set the core material id
2076 		pCoreSubmesh->setCoreMaterialThreadId(coreMaterialThreadId);
2077 
2078 		// reserve memory for all the submesh data
2079 		if(!pCoreSubmesh->reserve(vertexCount, textureCoordinateCount, faceCount, springCount))
2080 		{
2081 			CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__, strFilename);
2082 			delete pCoreSubmesh;
2083 			return 0;
2084 		}
2085 
2086 		TiXmlElement *vertex = submesh->FirstChildElement();
2087 
2088 		// load all vertices and their influences
2089 		int vertexId;
2090 		for(vertexId = 0; vertexId < vertexCount; ++vertexId)
2091 		{
2092 			if(!vertex || stricmp(vertex->Value(),"VERTEX")!=0)
2093 			{
2094 				delete pCoreSubmesh;
2095 				CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2096 				return 0;
2097 			}
2098 
2099 			CalCoreSubmesh::Vertex Vertex;
2100 
2101 			TiXmlElement *pos= vertex->FirstChildElement();
2102 			if(!pos || stricmp(pos->Value(),"POS")!=0)
2103 			{
2104 				delete pCoreSubmesh;
2105 				CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2106 				return 0;
2107 			}
2108 
2109 			node = pos->FirstChild();
2110 			if(!node)
2111 			{
2112 				delete pCoreSubmesh;
2113 				CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2114 				return 0;
2115 			}
2116 			TiXmlText* posdata = node->ToText();
2117 			if(!posdata)
2118 			{
2119 				delete pCoreSubmesh;
2120 				CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2121 				return 0;
2122 			}
2123 			str.clear();
2124 			str << posdata->Value();
2125 			str >> Vertex.position.x >> Vertex.position.y >> Vertex.position.z;
2126 
2127 			TiXmlElement *norm= pos->NextSiblingElement();
2128 			if(!norm||stricmp(norm->Value(),"NORM")!=0)
2129 			{
2130 				delete pCoreSubmesh;
2131 				CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2132 				return 0;
2133 			}
2134 
2135 			node = norm->FirstChild();
2136 			if(!norm)
2137 			{
2138 				delete pCoreSubmesh;
2139 				CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2140 				return 0;
2141 			}
2142 			TiXmlText* normdata = node->ToText();
2143 			if(!normdata)
2144 			{
2145 				delete pCoreSubmesh;
2146 				CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2147 				return 0;
2148 			}
2149 			str.clear();
2150 			str << normdata->Value();
2151 			str >> Vertex.normal.x >> Vertex.normal.y >> Vertex.normal.z;
2152 
2153 			TiXmlElement *collapse= norm->NextSiblingElement();
2154 			if(collapse && stricmp(collapse->Value(),"COLLAPSEID")==0)
2155 			{
2156 				node = collapse->FirstChild();
2157 				if(!node)
2158 				{
2159 					delete pCoreSubmesh;
2160 					CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2161 					return 0;
2162 				}
2163 				TiXmlText* collapseid = node->ToText();
2164 				if(!collapseid)
2165 				{
2166 					delete pCoreSubmesh;
2167 					CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2168 					return 0;
2169 				}
2170 				Vertex.collapseId = atoi(collapseid->Value());
2171 
2172 				TiXmlElement *collapseCount= collapse->NextSiblingElement();
2173 				if(!collapseCount|| stricmp(collapseCount->Value(),"COLLAPSECOUNT")!=0)
2174 				{
2175 					delete pCoreSubmesh;
2176 					CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2177 					return 0;
2178 				}
2179 
2180 				node = collapseCount->FirstChild();
2181 				if(!node)
2182 				{
2183 					delete pCoreSubmesh;
2184 					CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2185 					return 0;
2186 				}
2187 				TiXmlText* collapseCountdata = node->ToText();
2188 				if(!collapseCountdata)
2189 				{
2190 					delete pCoreSubmesh;
2191 					CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2192 					return 0;
2193 				}
2194 				Vertex.faceCollapseCount= atoi(collapseCountdata->Value());
2195 				collapse = collapseCount->NextSiblingElement();
2196 			}
2197 			else
2198 			{
2199 				Vertex.collapseId=-1;
2200 				Vertex.faceCollapseCount=0;
2201 			}
2202 
2203 
2204 			TiXmlElement *texcoord = collapse;
2205 
2206 			// load all texture coordinates of the vertex
2207 			int textureCoordinateId;
2208 			for(textureCoordinateId = 0; textureCoordinateId < textureCoordinateCount; ++textureCoordinateId)
2209 			{
2210 				CalCoreSubmesh::TextureCoordinate textureCoordinate;
2211 				// load data of the influence
2212 				if(!texcoord || stricmp(texcoord->Value(),"TEXCOORD")!=0)
2213 				{
2214 					delete pCoreSubmesh;
2215 					CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2216 					return 0;
2217 				}
2218 
2219 				node = texcoord->FirstChild();
2220 				if(!node)
2221 				{
2222 					delete pCoreSubmesh;
2223 					CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2224 					return 0;
2225 				}
2226 				TiXmlText* texcoorddata = node->ToText();
2227 				if(!texcoorddata)
2228 				{
2229 					delete pCoreSubmesh;
2230 					CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2231 					return 0;
2232 				}
2233 				str.clear();
2234 				str << texcoorddata->Value();
2235 				str >> textureCoordinate.u >> textureCoordinate.v;
2236 
2237 				if (loadingMode & LOADER_INVERT_V_COORD)
2238 				{
2239 					textureCoordinate.v = 1.0f - textureCoordinate.v;
2240 				}
2241 
2242 				// set texture coordinate in the core submesh instance
2243 				pCoreSubmesh->setTextureCoordinate(vertexId, textureCoordinateId, textureCoordinate);
2244 				texcoord = texcoord->NextSiblingElement();
2245 			}
2246 
2247 			// get the number of influences
2248 			int influenceCount= atoi(vertex->Attribute("NUMINFLUENCES"));
2249 
2250 			if(influenceCount < 0)
2251 			{
2252 				CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2253 				delete pCoreSubmesh;
2254 				return 0;
2255 			}
2256 
2257 			// reserve memory for the influences in the vertex
2258 			Vertex.vectorInfluence.reserve(influenceCount);
2259 			Vertex.vectorInfluence.resize(influenceCount);
2260 
2261 			TiXmlElement *influence = texcoord;
2262 
2263 			// load all influences of the vertex
2264 			int influenceId;
2265 			for(influenceId = 0; influenceId < influenceCount; ++influenceId)
2266 			{
2267 				if(!influence ||stricmp(influence->Value(),"INFLUENCE")!=0)
2268 				{
2269 					delete pCoreSubmesh;
2270 					CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2271 					return 0;
2272 				}
2273 
2274 				node = influence->FirstChild();
2275 				if(!node)
2276 				{
2277 					delete pCoreSubmesh;
2278 					CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2279 					return 0;
2280 				}
2281 				TiXmlText* influencedata = node->ToText();
2282 				if(!influencedata)
2283 				{
2284 					delete pCoreSubmesh;
2285 					CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2286 					return 0;
2287 				}
2288 
2289 				Vertex.vectorInfluence[influenceId].boneId = atoi(influence->Attribute("ID"));
2290 
2291 				Vertex.vectorInfluence[influenceId].weight = (float) atof(influencedata->Value());
2292 
2293 				influence=influence->NextSiblingElement();
2294 			}
2295 
2296 			// set vertex in the core submesh instance
2297 			pCoreSubmesh->setVertex(vertexId, Vertex);
2298 
2299 			TiXmlElement *physique = influence;
2300 
2301 
2302 
2303 			// load the physical property of the vertex if there are springs in the core submesh
2304 			if(springCount > 0)
2305 			{
2306 				CalCoreSubmesh::PhysicalProperty physicalProperty;
2307 
2308 				if(!physique || stricmp(physique->Value(),"PHYSIQUE")!=0)
2309 				{
2310 					delete pCoreSubmesh;
2311 					CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2312 					return 0;
2313 				}
2314 				node = physique->FirstChild();
2315 				if(!node)
2316 				{
2317 					delete pCoreSubmesh;
2318 					CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2319 					return 0;
2320 				}
2321 				TiXmlText* physiquedata = node->ToText();
2322 				if(!physiquedata)
2323 				{
2324 					delete pCoreSubmesh;
2325 					CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2326 					return 0;
2327 				}
2328 
2329 				physicalProperty.weight = (float) atof(physiquedata->Value());
2330 
2331 				// set the physical property in the core submesh instance
2332 				pCoreSubmesh->setPhysicalProperty(vertexId, physicalProperty);
2333 
2334 			}
2335 
2336 
2337 			vertex = vertex->NextSiblingElement();
2338 		}
2339 
2340 		TiXmlElement *spring= vertex;
2341 
2342 		// load all springs
2343 		int springId;
2344 		for(springId = 0; springId < springCount; ++springId)
2345 		{
2346 			CalCoreSubmesh::Spring Spring;
2347 			if(!spring ||stricmp(spring->Value(),"SPRING")!=0)
2348 			{
2349 				delete pCoreSubmesh;
2350 				CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2351 				return 0;
2352 			}
2353 			str.clear();
2354 			str << spring->Attribute("VERTEXID");
2355 			str >> Spring.vertexId[0] >> Spring.vertexId[1];
2356 			Spring.springCoefficient = (float) atof(spring->Attribute("COEF"));
2357 			Spring.idleLength = (float) atof(spring->Attribute("LENGTH"));
2358 
2359 			// set spring in the core submesh instance
2360 			pCoreSubmesh->setSpring(springId, Spring);
2361 			spring = spring->NextSiblingElement();
2362 		}
2363 
2364 		TiXmlElement *face = spring;
2365 
2366 		// load all faces
2367 		int faceId;
2368 		for(faceId = 0; faceId < faceCount; ++faceId)
2369 		{
2370 			CalCoreSubmesh::Face Face;
2371 
2372 			if(!face || stricmp(face->Value(),"FACE")!=0)
2373 			{
2374 				delete pCoreSubmesh;
2375 				CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2376 				return 0;
2377 			}
2378 
2379 			int tmp[3];
2380 
2381 			// load data of the face
2382 
2383 			str.clear();
2384 			str << face->Attribute("VERTEXID");
2385 			str >> tmp[0] >> tmp [1] >> tmp[2];
2386 
2387 			if(sizeof(CalIndex)==2)
2388 			{
2389 				if(tmp[0]>65535 || tmp[1]>65535 || tmp[2]>65535)
2390 				{
2391 					CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2392 					delete pCoreSubmesh;
2393 					return 0;
2394 				}
2395 			}
2396 			Face.vertexId[0]=tmp[0];
2397 			Face.vertexId[1]=tmp[1];
2398 			Face.vertexId[2]=tmp[2];
2399 
2400 			pCoreSubmesh->setFace(faceId, Face);
2401 
2402 			face=face->NextSiblingElement();
2403 		}
2404 		submesh=submesh->NextSiblingElement();
2405 
2406 		// add the core submesh to the core mesh instance
2407 		pCoreMesh->addCoreSubmesh(pCoreSubmesh);
2408 	}
2409 
2410 	// explicitly close the file
2411 	doc.Clear();
2412 	return pCoreMesh;
2413 }
2414 
2415  /*****************************************************************************/
2416 /** Loads a core material instance from a XML file.
2417   *
2418   * This function loads a core material instance from a XML file.
2419   *
2420   * @param strFilename The name of the file to load the core material instance
2421   *                    from.
2422   *
2423   * @return One of the following values:
2424   *         \li a pointer to the core material
2425   *         \li \b 0 if an error happened
2426   *****************************************************************************/
2427 
2428 
loadXmlCoreMaterial(const std::string & strFilename)2429 CalCoreMaterialPtr CalLoader::loadXmlCoreMaterial(const std::string& strFilename)
2430 {
2431   std::stringstream str;
2432   int r,g,b,a;
2433   TiXmlDocument doc(strFilename);
2434   if(!doc.LoadFile())
2435   {
2436     CalError::setLastError(CalError::FILE_NOT_FOUND, __FILE__, __LINE__, strFilename);
2437     return 0;
2438   }
2439 
2440   TiXmlNode* node;
2441 
2442   TiXmlElement*material = doc.FirstChildElement();
2443   if(!material)
2444   {
2445     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2446         return 0;
2447   }
2448 
2449   if(stricmp(material->Value(),"HEADER")==0)
2450   {
2451     if(stricmp(material->Attribute("MAGIC"),Cal::MATERIAL_XMLFILE_MAGIC)!=0)
2452   {
2453     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2454           return 0;
2455     }
2456 
2457     if(atoi(material->Attribute("VERSION")) < Cal::EARLIEST_COMPATIBLE_FILE_VERSION )
2458     {
2459     CalError::setLastError(CalError::INCOMPATIBLE_FILE_VERSION, __FILE__, __LINE__, strFilename);
2460           return 0;
2461     }
2462 
2463     material = material->NextSiblingElement();
2464   }
2465 
2466   if(!material||stricmp(material->Value(),"MATERIAL")!=0)
2467   {
2468     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2469       return 0;
2470   }
2471 
2472   if(material->Attribute("MAGIC")!=NULL && stricmp(material->Attribute("MAGIC"),Cal::MATERIAL_XMLFILE_MAGIC)!=0)
2473   {
2474     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2475         return 0;
2476   }
2477 
2478   if(material->Attribute("VERSION") != NULL && atoi(material->Attribute("VERSION")) < Cal::EARLIEST_COMPATIBLE_FILE_VERSION )
2479   {
2480     CalError::setLastError(CalError::INCOMPATIBLE_FILE_VERSION, __FILE__, __LINE__, strFilename);
2481         return 0;
2482   }
2483 
2484   CalCoreMaterialPtr pCoreMaterial = new CalCoreMaterial();
2485   if(!pCoreMaterial)
2486   {
2487     CalError::setLastError(CalError::MEMORY_ALLOCATION_FAILED, __FILE__, __LINE__);
2488     return 0;
2489   }
2490 
2491   TiXmlElement* ambient = material->FirstChildElement();
2492   if(!ambient ||stricmp(ambient->Value(),"AMBIENT")!=0)
2493   {
2494     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2495     return 0;
2496   }
2497 
2498   CalCoreMaterial::Color ambientColor;
2499   node = ambient->FirstChild();
2500   if(!node)
2501   {
2502     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2503     return 0;
2504   }
2505   TiXmlText* ambientdata = node->ToText();
2506   if(!ambientdata)
2507   {
2508     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2509     return 0;
2510   }
2511   str << ambientdata->Value();
2512   str >> r >> g >> b >> a;
2513   ambientColor.red = (unsigned char)r;
2514   ambientColor.green = (unsigned char)g;
2515   ambientColor.blue = (unsigned char)b;
2516   ambientColor.alpha = (unsigned char)a;
2517 
2518   TiXmlElement* diffuse = ambient->NextSiblingElement();
2519   if(!diffuse || stricmp(diffuse->Value(),"DIFFUSE")!=0)
2520   {
2521     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2522     return 0;
2523   }
2524 
2525   CalCoreMaterial::Color diffuseColor;
2526   node = diffuse->FirstChild();
2527   if(!node)
2528   {
2529     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2530     return 0;
2531   }
2532   TiXmlText* diffusedata = node->ToText();
2533   if(!diffusedata)
2534   {
2535     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2536     return 0;
2537   }
2538   str.clear();
2539   str << diffusedata->Value();
2540   str >> r >> g >> b >> a;
2541   diffuseColor.red = (unsigned char)r;
2542   diffuseColor.green = (unsigned char)g;
2543   diffuseColor.blue = (unsigned char)b;
2544   diffuseColor.alpha = (unsigned char)a;
2545 
2546 
2547   TiXmlElement* specular = diffuse->NextSiblingElement();
2548   if(!specular||stricmp(specular->Value(),"SPECULAR")!=0)
2549   {
2550     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2551     return 0;
2552   }
2553 
2554   CalCoreMaterial::Color specularColor;
2555   node = specular->FirstChild();
2556   if(!node)
2557   {
2558     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2559     return 0;
2560   }
2561   TiXmlText* speculardata = node->ToText();
2562   if(!speculardata)
2563   {
2564     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2565     return 0;
2566   }
2567   str.clear();
2568   str << speculardata->Value();
2569   str >> r >> g >> b >> a;
2570   specularColor.red = (unsigned char)r;
2571   specularColor.green = (unsigned char)g;
2572   specularColor.blue = (unsigned char)b;
2573   specularColor.alpha = (unsigned char)a;
2574 
2575   TiXmlElement* shininess = specular->NextSiblingElement();
2576   if(!shininess||stricmp(shininess->Value(),"SHININESS")!=0)
2577   {
2578     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2579     return 0;
2580   }
2581 
2582   float fshininess;
2583   node = shininess->FirstChild();
2584   if(!node)
2585   {
2586     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2587     return 0;
2588   }
2589   TiXmlText* shininessdata = node->ToText();
2590   if(!shininessdata)
2591   {
2592     CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2593     return 0;
2594   }
2595   fshininess = (float)atof(shininessdata->Value());
2596 
2597   // set the colors and the shininess
2598   pCoreMaterial->setAmbientColor(ambientColor);
2599   pCoreMaterial->setDiffuseColor(diffuseColor);
2600   pCoreMaterial->setSpecularColor(specularColor);
2601   pCoreMaterial->setShininess(fshininess);
2602 
2603   std::vector<std::string> MatFileName;
2604 
2605   TiXmlElement* map;
2606 
2607   for(map = shininess->NextSiblingElement();map;map = map->NextSiblingElement() )
2608   {
2609     if(!map||stricmp(map->Value(),"MAP")!=0)
2610     {
2611       CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2612       return 0;
2613     }
2614 
2615 
2616     node= map->FirstChild();
2617     if(!node)
2618     {
2619       CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2620       return 0;
2621     }
2622 
2623     TiXmlText* mapfile = node->ToText();
2624     if(!mapfile)
2625     {
2626       CalError::setLastError(CalError::INVALID_FILE_FORMAT, __FILE__, __LINE__, strFilename);
2627       return 0;
2628     }
2629 
2630     MatFileName.push_back(mapfile->Value());
2631   }
2632   pCoreMaterial->reserve(MatFileName.size());
2633 
2634   for(unsigned int mapId=0; mapId < MatFileName.size(); ++mapId)
2635   {
2636     CalCoreMaterial::Map Map;
2637     // initialize the user data
2638     Map.userData = 0;
2639 
2640     Map.strFilename= MatFileName[mapId];
2641 
2642     // set map in the core material instance
2643     pCoreMaterial->setMap(mapId, Map);
2644   }
2645 
2646   doc.Clear();
2647 
2648   return pCoreMaterial;
2649 }
2650 
2651 //****************************************************************************//
2652