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