1 /* 2 ----------------------------------------------------------------------------- 3 This source file is part of OGRE 4 (Object-oriented Graphics Rendering Engine) 5 For the latest info, see http://www.ogre3d.org/ 6 7 Copyright (c) 2000-2013 Torus Knot Software Ltd 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 ----------------------------------------------------------------------------- 27 */ 28 #include "OgreStableHeaders.h" 29 30 #include "OgreSkeletonFileFormat.h" 31 #include "OgreSkeletonSerializer.h" 32 #include "OgreSkeleton.h" 33 #include "OgreAnimation.h" 34 #include "OgreAnimationTrack.h" 35 #include "OgreKeyFrame.h" 36 #include "OgreBone.h" 37 #include "OgreString.h" 38 #include "OgreDataStream.h" 39 #include "OgreLogManager.h" 40 41 42 43 44 namespace Ogre { 45 /// stream overhead = ID + size 46 const long SSTREAM_OVERHEAD_SIZE = sizeof(uint16) + sizeof(uint32); 47 const uint16 HEADER_STREAM_ID_EXT = 0x1000; 48 //--------------------------------------------------------------------- SkeletonSerializer()49 SkeletonSerializer::SkeletonSerializer() 50 { 51 // Version number 52 // NB changed to include bone names in 1.1 53 mVersion = "[Unknown]"; 54 } 55 //--------------------------------------------------------------------- ~SkeletonSerializer()56 SkeletonSerializer::~SkeletonSerializer() 57 { 58 } 59 60 //--------------------------------------------------------------------- exportSkeleton(const Skeleton * pSkeleton,const String & filename,SkeletonVersion ver,Endian endianMode)61 void SkeletonSerializer::exportSkeleton(const Skeleton* pSkeleton, 62 const String& filename, SkeletonVersion ver, Endian endianMode) 63 { 64 std::fstream *f = OGRE_NEW_T(std::fstream, MEMCATEGORY_GENERAL)(); 65 f->open(filename.c_str(), std::ios::binary | std::ios::out); 66 DataStreamPtr stream(OGRE_NEW FileStreamDataStream(f)); 67 68 exportSkeleton(pSkeleton, stream, ver, endianMode); 69 70 stream->close(); 71 } 72 //--------------------------------------------------------------------- exportSkeleton(const Skeleton * pSkeleton,DataStreamPtr stream,SkeletonVersion ver,Endian endianMode)73 void SkeletonSerializer::exportSkeleton(const Skeleton* pSkeleton, 74 DataStreamPtr stream, SkeletonVersion ver, Endian endianMode) 75 { 76 setWorkingVersion(ver); 77 // Decide on endian mode 78 determineEndianness(endianMode); 79 80 String msg; 81 mStream = stream; 82 if (!stream->isWriteable()) 83 { 84 OGRE_EXCEPT(Exception::ERR_CANNOT_WRITE_TO_FILE, 85 "Unable to write to stream " + stream->getName(), 86 "SkeletonSerializer::exportSkeleton"); 87 } 88 89 90 writeFileHeader(); 91 92 // Write main skeleton data 93 LogManager::getSingleton().logMessage("Exporting bones.."); 94 writeSkeleton(pSkeleton, ver); 95 LogManager::getSingleton().logMessage("Bones exported."); 96 97 // Write all animations 98 unsigned short numAnims = pSkeleton->getNumAnimations(); 99 LogManager::getSingleton().stream() 100 << "Exporting animations, count=" << numAnims; 101 for (unsigned short i = 0; i < numAnims; ++i) 102 { 103 Animation* pAnim = pSkeleton->getAnimation(i); 104 LogManager::getSingleton().stream() 105 << "Exporting animation: " << pAnim->getName(); 106 writeAnimation(pSkeleton, pAnim, ver); 107 LogManager::getSingleton().logMessage("Animation exported."); 108 109 } 110 111 // Write links 112 Skeleton::LinkedSkeletonAnimSourceIterator linkIt = 113 pSkeleton->getLinkedSkeletonAnimationSourceIterator(); 114 while(linkIt.hasMoreElements()) 115 { 116 const LinkedSkeletonAnimationSource& link = linkIt.getNext(); 117 writeSkeletonAnimationLink(pSkeleton, link); 118 } 119 120 } 121 //--------------------------------------------------------------------- importSkeleton(DataStreamPtr & stream,Skeleton * pSkel)122 void SkeletonSerializer::importSkeleton(DataStreamPtr& stream, Skeleton* pSkel) 123 { 124 // Determine endianness (must be the first thing we do!) 125 determineEndianness(stream); 126 127 // Check header 128 readFileHeader(stream); 129 130 while(!stream->eof()) 131 { 132 unsigned short streamID = readChunk(stream); 133 switch (streamID) 134 { 135 case SKELETON_BLENDMODE: 136 { 137 // Optional blend mode 138 uint16 blendMode; 139 readShorts(stream, &blendMode, 1); 140 pSkel->setBlendMode(static_cast<SkeletonAnimationBlendMode>(blendMode)); 141 break; 142 } 143 case SKELETON_BONE: 144 readBone(stream, pSkel); 145 break; 146 case SKELETON_BONE_PARENT: 147 readBoneParent(stream, pSkel); 148 break; 149 case SKELETON_ANIMATION: 150 readAnimation(stream, pSkel); 151 break; 152 case SKELETON_ANIMATION_LINK: 153 readSkeletonAnimationLink(stream, pSkel); 154 break; 155 } 156 } 157 158 // Assume bones are stored in the binding pose 159 pSkel->setBindingPose(); 160 161 162 } 163 164 //--------------------------------------------------------------------- setWorkingVersion(SkeletonVersion ver)165 void SkeletonSerializer::setWorkingVersion(SkeletonVersion ver) 166 { 167 if (ver == SKELETON_VERSION_1_0) 168 mVersion = "[Serializer_v1.10]"; 169 else mVersion = "[Serializer_v1.80]"; 170 } 171 //--------------------------------------------------------------------- writeSkeleton(const Skeleton * pSkel,SkeletonVersion ver)172 void SkeletonSerializer::writeSkeleton(const Skeleton* pSkel, SkeletonVersion ver) 173 { 174 // Write blend mode 175 if ((int)ver > (int)SKELETON_VERSION_1_0) 176 { 177 writeChunkHeader(SKELETON_BLENDMODE, SSTREAM_OVERHEAD_SIZE + sizeof(unsigned short)); 178 uint16 blendMode = static_cast<uint16>(pSkel->getBlendMode()); 179 writeShorts(&blendMode, 1); 180 } 181 182 // Write each bone 183 unsigned short numBones = pSkel->getNumBones(); 184 unsigned short i; 185 for (i = 0; i < numBones; ++i) 186 { 187 Bone* pBone = pSkel->getBone(i); 188 writeBone(pSkel, pBone); 189 } 190 // Write parents 191 for (i = 0; i < numBones; ++i) 192 { 193 Bone* pBone = pSkel->getBone(i); 194 unsigned short handle = pBone->getHandle(); 195 Bone* pParent = static_cast<Bone*>(pBone->getParent()); 196 if (pParent != NULL) 197 { 198 writeBoneParent(pSkel, handle, pParent->getHandle()); 199 } 200 } 201 } 202 //--------------------------------------------------------------------- writeBone(const Skeleton * pSkel,const Bone * pBone)203 void SkeletonSerializer::writeBone(const Skeleton* pSkel, const Bone* pBone) 204 { 205 writeChunkHeader(SKELETON_BONE, calcBoneSize(pSkel, pBone)); 206 207 unsigned short handle = pBone->getHandle(); 208 // char* name 209 writeString(pBone->getName()); 210 // unsigned short handle : handle of the bone, should be contiguous & start at 0 211 writeShorts(&handle, 1); 212 // Vector3 position : position of this bone relative to parent 213 writeObject(pBone->getPosition()); 214 // Quaternion orientation : orientation of this bone relative to parent 215 writeObject(pBone->getOrientation()); 216 // Vector3 scale : scale of this bone relative to parent 217 if (pBone->getScale() != Vector3::UNIT_SCALE) 218 { 219 writeObject(pBone->getScale()); 220 } 221 } 222 //--------------------------------------------------------------------- writeBoneParent(const Skeleton * pSkel,unsigned short boneId,unsigned short parentId)223 void SkeletonSerializer::writeBoneParent(const Skeleton* pSkel, 224 unsigned short boneId, unsigned short parentId) 225 { 226 writeChunkHeader(SKELETON_BONE_PARENT, calcBoneParentSize(pSkel)); 227 228 // unsigned short handle : child bone 229 writeShorts(&boneId, 1); 230 // unsigned short parentHandle : parent bone 231 writeShorts(&parentId, 1); 232 233 } 234 //--------------------------------------------------------------------- writeAnimation(const Skeleton * pSkel,const Animation * anim,SkeletonVersion ver)235 void SkeletonSerializer::writeAnimation(const Skeleton* pSkel, 236 const Animation* anim, SkeletonVersion ver) 237 { 238 writeChunkHeader(SKELETON_ANIMATION, calcAnimationSize(pSkel, anim)); 239 240 // char* name : Name of the animation 241 writeString(anim->getName()); 242 // float length : Length of the animation in seconds 243 float len = anim->getLength(); 244 writeFloats(&len, 1); 245 246 if ((int)ver > (int)SKELETON_VERSION_1_0) 247 { 248 if (anim->getUseBaseKeyFrame()) 249 { 250 size_t size = SSTREAM_OVERHEAD_SIZE; 251 // char* baseAnimationName (including terminator) 252 size += anim->getBaseKeyFrameAnimationName().length() + 1; 253 // float baseKeyFrameTime 254 size += sizeof(float); 255 256 writeChunkHeader(SKELETON_ANIMATION_BASEINFO, size); 257 258 // char* baseAnimationName (blank for self) 259 writeString(anim->getBaseKeyFrameAnimationName()); 260 261 // float baseKeyFrameTime 262 float t = (float)anim->getBaseKeyFrameTime(); 263 writeFloats(&t, 1); 264 } 265 } 266 267 // Write all tracks 268 Animation::NodeTrackIterator trackIt = anim->getNodeTrackIterator(); 269 while(trackIt.hasMoreElements()) 270 { 271 writeAnimationTrack(pSkel, trackIt.getNext()); 272 } 273 274 } 275 //--------------------------------------------------------------------- writeAnimationTrack(const Skeleton * pSkel,const NodeAnimationTrack * track)276 void SkeletonSerializer::writeAnimationTrack(const Skeleton* pSkel, 277 const NodeAnimationTrack* track) 278 { 279 writeChunkHeader(SKELETON_ANIMATION_TRACK, calcAnimationTrackSize(pSkel, track)); 280 281 // unsigned short boneIndex : Index of bone to apply to 282 Bone* bone = static_cast<Bone*>(track->getAssociatedNode()); 283 unsigned short boneid = bone->getHandle(); 284 writeShorts(&boneid, 1); 285 286 // Write all keyframes 287 for (unsigned short i = 0; i < track->getNumKeyFrames(); ++i) 288 { 289 writeKeyFrame(pSkel, track->getNodeKeyFrame(i)); 290 } 291 292 } 293 //--------------------------------------------------------------------- writeKeyFrame(const Skeleton * pSkel,const TransformKeyFrame * key)294 void SkeletonSerializer::writeKeyFrame(const Skeleton* pSkel, 295 const TransformKeyFrame* key) 296 { 297 298 writeChunkHeader(SKELETON_ANIMATION_TRACK_KEYFRAME, 299 calcKeyFrameSize(pSkel, key)); 300 301 // float time : The time position (seconds) 302 float time = key->getTime(); 303 writeFloats(&time, 1); 304 // Quaternion rotate : Rotation to apply at this keyframe 305 writeObject(key->getRotation()); 306 // Vector3 translate : Translation to apply at this keyframe 307 writeObject(key->getTranslate()); 308 // Vector3 scale : Scale to apply at this keyframe 309 if (key->getScale() != Vector3::UNIT_SCALE) 310 { 311 writeObject(key->getScale()); 312 } 313 } 314 //--------------------------------------------------------------------- calcBoneSize(const Skeleton * pSkel,const Bone * pBone)315 size_t SkeletonSerializer::calcBoneSize(const Skeleton* pSkel, 316 const Bone* pBone) 317 { 318 size_t size = SSTREAM_OVERHEAD_SIZE; 319 320 // handle 321 size += sizeof(unsigned short); 322 323 // position 324 size += sizeof(float) * 3; 325 326 // orientation 327 size += sizeof(float) * 4; 328 329 // scale 330 if (pBone->getScale() != Vector3::UNIT_SCALE) 331 { 332 size += sizeof(float) * 3; 333 } 334 335 return size; 336 } 337 //--------------------------------------------------------------------- calcBoneSizeWithoutScale(const Skeleton * pSkel,const Bone * pBone)338 size_t SkeletonSerializer::calcBoneSizeWithoutScale(const Skeleton* pSkel, 339 const Bone* pBone) 340 { 341 size_t size = SSTREAM_OVERHEAD_SIZE; 342 343 // handle 344 size += sizeof(unsigned short); 345 346 // position 347 size += sizeof(float) * 3; 348 349 // orientation 350 size += sizeof(float) * 4; 351 352 return size; 353 } 354 //--------------------------------------------------------------------- calcBoneParentSize(const Skeleton * pSkel)355 size_t SkeletonSerializer::calcBoneParentSize(const Skeleton* pSkel) 356 { 357 size_t size = SSTREAM_OVERHEAD_SIZE; 358 359 // handle 360 size += sizeof(unsigned short); 361 362 // parent handle 363 size += sizeof(unsigned short); 364 365 return size; 366 } 367 //--------------------------------------------------------------------- calcAnimationSize(const Skeleton * pSkel,const Animation * pAnim)368 size_t SkeletonSerializer::calcAnimationSize(const Skeleton* pSkel, 369 const Animation* pAnim) 370 { 371 size_t size = SSTREAM_OVERHEAD_SIZE; 372 373 // Name, including terminator 374 size += pAnim->getName().length() + 1; 375 // length 376 size += sizeof(float); 377 378 // Nested animation tracks 379 Animation::NodeTrackIterator trackIt = pAnim->getNodeTrackIterator(); 380 while(trackIt.hasMoreElements()) 381 { 382 size += calcAnimationTrackSize(pSkel, trackIt.getNext()); 383 } 384 385 return size; 386 } 387 //--------------------------------------------------------------------- calcAnimationTrackSize(const Skeleton * pSkel,const NodeAnimationTrack * pTrack)388 size_t SkeletonSerializer::calcAnimationTrackSize(const Skeleton* pSkel, 389 const NodeAnimationTrack* pTrack) 390 { 391 size_t size = SSTREAM_OVERHEAD_SIZE; 392 393 // unsigned short boneIndex : Index of bone to apply to 394 size += sizeof(unsigned short); 395 396 // Nested keyframes 397 for (unsigned short i = 0; i < pTrack->getNumKeyFrames(); ++i) 398 { 399 size += calcKeyFrameSize(pSkel, pTrack->getNodeKeyFrame(i)); 400 } 401 402 return size; 403 } 404 //--------------------------------------------------------------------- calcKeyFrameSize(const Skeleton * pSkel,const TransformKeyFrame * pKey)405 size_t SkeletonSerializer::calcKeyFrameSize(const Skeleton* pSkel, 406 const TransformKeyFrame* pKey) 407 { 408 size_t size = SSTREAM_OVERHEAD_SIZE; 409 410 // float time : The time position (seconds) 411 size += sizeof(float); 412 // Quaternion rotate : Rotation to apply at this keyframe 413 size += sizeof(float) * 4; 414 // Vector3 translate : Translation to apply at this keyframe 415 size += sizeof(float) * 3; 416 // Vector3 scale : Scale to apply at this keyframe 417 if (pKey->getScale() != Vector3::UNIT_SCALE) 418 { 419 size += sizeof(float) * 3; 420 } 421 422 return size; 423 } 424 //--------------------------------------------------------------------- calcKeyFrameSizeWithoutScale(const Skeleton * pSkel,const TransformKeyFrame * pKey)425 size_t SkeletonSerializer::calcKeyFrameSizeWithoutScale(const Skeleton* pSkel, 426 const TransformKeyFrame* pKey) 427 { 428 size_t size = SSTREAM_OVERHEAD_SIZE; 429 430 // float time : The time position (seconds) 431 size += sizeof(float); 432 // Quaternion rotate : Rotation to apply at this keyframe 433 size += sizeof(float) * 4; 434 // Vector3 translate : Translation to apply at this keyframe 435 size += sizeof(float) * 3; 436 437 return size; 438 } 439 //--------------------------------------------------------------------- readFileHeader(DataStreamPtr & stream)440 void SkeletonSerializer::readFileHeader(DataStreamPtr& stream) 441 { 442 unsigned short headerID; 443 444 // Read header ID 445 readShorts(stream, &headerID, 1); 446 447 if (headerID == HEADER_STREAM_ID_EXT) 448 { 449 // Read version 450 String ver = readString(stream); 451 if ((ver != "[Serializer_v1.10]") && 452 (ver != "[Serializer_v1.80]")) 453 { 454 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 455 "Invalid file: version incompatible, file reports " + String(ver), 456 "Serializer::readFileHeader"); 457 } 458 mVersion = ver; 459 } 460 else 461 { 462 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Invalid file: no header", 463 "Serializer::readFileHeader"); 464 } 465 } 466 //--------------------------------------------------------------------- readBone(DataStreamPtr & stream,Skeleton * pSkel)467 void SkeletonSerializer::readBone(DataStreamPtr& stream, Skeleton* pSkel) 468 { 469 // char* name 470 String name = readString(stream); 471 // unsigned short handle : handle of the bone, should be contiguous & start at 0 472 unsigned short handle; 473 readShorts(stream, &handle, 1); 474 475 // Create new bone 476 Bone* pBone = pSkel->createBone(name, handle); 477 478 // Vector3 position : position of this bone relative to parent 479 Vector3 pos; 480 readObject(stream, pos); 481 pBone->setPosition(pos); 482 // Quaternion orientation : orientation of this bone relative to parent 483 Quaternion q; 484 readObject(stream, q); 485 pBone->setOrientation(q); 486 // Do we have scale? 487 if (mCurrentstreamLen > calcBoneSizeWithoutScale(pSkel, pBone)) 488 { 489 Vector3 scale; 490 readObject(stream, scale); 491 pBone->setScale(scale); 492 } 493 } 494 //--------------------------------------------------------------------- readBoneParent(DataStreamPtr & stream,Skeleton * pSkel)495 void SkeletonSerializer::readBoneParent(DataStreamPtr& stream, Skeleton* pSkel) 496 { 497 // All bones have been created by this point 498 Bone *child, *parent; 499 unsigned short childHandle, parentHandle; 500 501 // unsigned short handle : child bone 502 readShorts(stream, &childHandle, 1); 503 // unsigned short parentHandle : parent bone 504 readShorts(stream, &parentHandle, 1); 505 506 // Find bones 507 parent = pSkel->getBone(parentHandle); 508 child = pSkel->getBone(childHandle); 509 510 // attach 511 parent->addChild(child); 512 513 } 514 //--------------------------------------------------------------------- readAnimation(DataStreamPtr & stream,Skeleton * pSkel)515 void SkeletonSerializer::readAnimation(DataStreamPtr& stream, Skeleton* pSkel) 516 { 517 // char* name : Name of the animation 518 String name; 519 name = readString(stream); 520 // float length : Length of the animation in seconds 521 float len; 522 readFloats(stream, &len, 1); 523 524 Animation *pAnim = pSkel->createAnimation(name, len); 525 526 // Read all tracks 527 if (!stream->eof()) 528 { 529 unsigned short streamID = readChunk(stream); 530 // Optional base info is possible 531 if (streamID == SKELETON_ANIMATION_BASEINFO) 532 { 533 // char baseAnimationName 534 String baseAnimName = readString(stream); 535 // float baseKeyFrameTime 536 float baseKeyTime; 537 readFloats(stream, &baseKeyTime, 1); 538 539 pAnim->setUseBaseKeyFrame(true, baseKeyTime, baseAnimName); 540 541 if (!stream->eof()) 542 { 543 // Get next stream 544 streamID = readChunk(stream); 545 } 546 } 547 548 while(streamID == SKELETON_ANIMATION_TRACK && !stream->eof()) 549 { 550 readAnimationTrack(stream, pAnim, pSkel); 551 552 if (!stream->eof()) 553 { 554 // Get next stream 555 streamID = readChunk(stream); 556 } 557 } 558 if (!stream->eof()) 559 { 560 // Backpedal back to start of this stream if we've found a non-track 561 stream->skip(-SSTREAM_OVERHEAD_SIZE); 562 } 563 564 } 565 566 567 568 } 569 //--------------------------------------------------------------------- readAnimationTrack(DataStreamPtr & stream,Animation * anim,Skeleton * pSkel)570 void SkeletonSerializer::readAnimationTrack(DataStreamPtr& stream, Animation* anim, 571 Skeleton* pSkel) 572 { 573 // unsigned short boneIndex : Index of bone to apply to 574 unsigned short boneHandle; 575 readShorts(stream, &boneHandle, 1); 576 577 // Find bone 578 Bone *targetBone = pSkel->getBone(boneHandle); 579 580 // Create track 581 NodeAnimationTrack* pTrack = anim->createNodeTrack(boneHandle, targetBone); 582 583 // Keep looking for nested keyframes 584 if (!stream->eof()) 585 { 586 unsigned short streamID = readChunk(stream); 587 while(streamID == SKELETON_ANIMATION_TRACK_KEYFRAME && !stream->eof()) 588 { 589 readKeyFrame(stream, pTrack, pSkel); 590 591 if (!stream->eof()) 592 { 593 // Get next stream 594 streamID = readChunk(stream); 595 } 596 } 597 if (!stream->eof()) 598 { 599 // Backpedal back to start of this stream if we've found a non-keyframe 600 stream->skip(-SSTREAM_OVERHEAD_SIZE); 601 } 602 603 } 604 605 606 } 607 //--------------------------------------------------------------------- readKeyFrame(DataStreamPtr & stream,NodeAnimationTrack * track,Skeleton * pSkel)608 void SkeletonSerializer::readKeyFrame(DataStreamPtr& stream, NodeAnimationTrack* track, 609 Skeleton* pSkel) 610 { 611 // float time : The time position (seconds) 612 float time; 613 readFloats(stream, &time, 1); 614 615 TransformKeyFrame *kf = track->createNodeKeyFrame(time); 616 617 // Quaternion rotate : Rotation to apply at this keyframe 618 Quaternion rot; 619 readObject(stream, rot); 620 kf->setRotation(rot); 621 // Vector3 translate : Translation to apply at this keyframe 622 Vector3 trans; 623 readObject(stream, trans); 624 kf->setTranslate(trans); 625 // Do we have scale? 626 if (mCurrentstreamLen > calcKeyFrameSizeWithoutScale(pSkel, kf)) 627 { 628 Vector3 scale; 629 readObject(stream, scale); 630 kf->setScale(scale); 631 } 632 } 633 //--------------------------------------------------------------------- writeSkeletonAnimationLink(const Skeleton * pSkel,const LinkedSkeletonAnimationSource & link)634 void SkeletonSerializer::writeSkeletonAnimationLink(const Skeleton* pSkel, 635 const LinkedSkeletonAnimationSource& link) 636 { 637 writeChunkHeader(SKELETON_ANIMATION_LINK, 638 calcSkeletonAnimationLinkSize(pSkel, link)); 639 640 // char* skeletonName 641 writeString(link.skeletonName); 642 // float scale 643 writeFloats(&(link.scale), 1); 644 645 } 646 //--------------------------------------------------------------------- calcSkeletonAnimationLinkSize(const Skeleton * pSkel,const LinkedSkeletonAnimationSource & link)647 size_t SkeletonSerializer::calcSkeletonAnimationLinkSize(const Skeleton* pSkel, 648 const LinkedSkeletonAnimationSource& link) 649 { 650 size_t size = SSTREAM_OVERHEAD_SIZE; 651 652 // char* skeletonName 653 size += link.skeletonName.length() + 1; 654 // float scale 655 size += sizeof(float); 656 657 return size; 658 659 } 660 //--------------------------------------------------------------------- readSkeletonAnimationLink(DataStreamPtr & stream,Skeleton * pSkel)661 void SkeletonSerializer::readSkeletonAnimationLink(DataStreamPtr& stream, 662 Skeleton* pSkel) 663 { 664 // char* skeletonName 665 String skelName = readString(stream); 666 // float scale 667 float scale; 668 readFloats(stream, &scale, 1); 669 670 pSkel->addLinkedSkeletonAnimationSource(skelName, scale); 671 672 } 673 674 675 676 } 677 678 679