2
0

Animation.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. // ----------------------------------------------------------------
  2. // From Game Programming in C++ by Sanjay Madhav
  3. // Copyright (C) 2017 Sanjay Madhav. All rights reserved.
  4. //
  5. // Released under the BSD License
  6. // See LICENSE in root directory for full details.
  7. // ----------------------------------------------------------------
  8. #include "Animation.h"
  9. #include "Skeleton.h"
  10. #include <rapidjson/document.h>
  11. #include <SDL/SDL_log.h>
  12. #include "LevelLoader.h"
  13. bool Animation::Load(const std::string& fileName)
  14. {
  15. mFileName = fileName;
  16. rapidjson::Document doc;
  17. if (!LevelLoader::LoadJSON(fileName, doc))
  18. {
  19. SDL_Log("Failed to load animation %s", fileName.c_str());
  20. return false;
  21. }
  22. int ver = doc["version"].GetInt();
  23. // Check the metadata
  24. if (ver != 1)
  25. {
  26. SDL_Log("Animation %s unknown format", fileName.c_str());
  27. return false;
  28. }
  29. const rapidjson::Value& sequence = doc["sequence"];
  30. if (!sequence.IsObject())
  31. {
  32. SDL_Log("Animation %s doesn't have a sequence.", fileName.c_str());
  33. return false;
  34. }
  35. const rapidjson::Value& frames = sequence["frames"];
  36. const rapidjson::Value& length = sequence["length"];
  37. const rapidjson::Value& bonecount = sequence["bonecount"];
  38. if (!frames.IsUint() || !length.IsDouble() || !bonecount.IsUint())
  39. {
  40. SDL_Log("Sequence %s has invalid frames, length, or bone count.", fileName.c_str());
  41. return false;
  42. }
  43. mNumFrames = frames.GetUint();
  44. mDuration = length.GetDouble();
  45. mNumBones = bonecount.GetUint();
  46. mFrameDuration = mDuration / (mNumFrames - 1);
  47. mTracks.resize(mNumBones);
  48. const rapidjson::Value& tracks = sequence["tracks"];
  49. if (!tracks.IsArray())
  50. {
  51. SDL_Log("Sequence %s missing a tracks array.", fileName.c_str());
  52. return false;
  53. }
  54. for (rapidjson::SizeType i = 0; i < tracks.Size(); i++)
  55. {
  56. if (!tracks[i].IsObject())
  57. {
  58. SDL_Log("Animation %s: Track element %d is invalid.", fileName.c_str(), i);
  59. return false;
  60. }
  61. size_t boneIndex = tracks[i]["bone"].GetUint();
  62. const rapidjson::Value& transforms = tracks[i]["transforms"];
  63. if (!transforms.IsArray())
  64. {
  65. SDL_Log("Animation %s: Track element %d is missing transforms.", fileName.c_str(), i);
  66. return false;
  67. }
  68. BoneTransform temp;
  69. if (transforms.Size() < mNumFrames)
  70. {
  71. SDL_Log("Animation %s: Track element %d has fewer frames than expected.", fileName.c_str(), i);
  72. return false;
  73. }
  74. for (rapidjson::SizeType j = 0; j < transforms.Size(); j++)
  75. {
  76. const rapidjson::Value& rot = transforms[j]["rot"];
  77. const rapidjson::Value& trans = transforms[j]["trans"];
  78. if (!rot.IsArray() || !trans.IsArray())
  79. {
  80. SDL_Log("Skeleton %s: Bone %d is invalid.", fileName.c_str(), i);
  81. return false;
  82. }
  83. temp.mRotation.x = rot[0].GetDouble();
  84. temp.mRotation.y = rot[1].GetDouble();
  85. temp.mRotation.z = rot[2].GetDouble();
  86. temp.mRotation.w = rot[3].GetDouble();
  87. temp.mTranslation.x = trans[0].GetDouble();
  88. temp.mTranslation.y = trans[1].GetDouble();
  89. temp.mTranslation.z = trans[2].GetDouble();
  90. mTracks[boneIndex].emplace_back(temp);
  91. }
  92. }
  93. return true;
  94. }
  95. void Animation::GetGlobalPoseAtTime(std::vector<Matrix4>& outPoses, const Skeleton* inSkeleton, float inTime) const
  96. {
  97. if (outPoses.size() != mNumBones)
  98. {
  99. outPoses.resize(mNumBones);
  100. }
  101. // Figure out the current frame index and next frame
  102. // (This assumes inTime is bounded by [0, AnimDuration]
  103. size_t frame = static_cast<size_t>(inTime / mFrameDuration);
  104. size_t nextFrame = frame + 1;
  105. // Calculate fractional value between frame and next frame
  106. float pct = inTime / mFrameDuration - frame;
  107. // Setup the pose for the root
  108. if (mTracks[0].size() > 0)
  109. {
  110. // Interpolate between the current frame's pose and the next frame
  111. BoneTransform interp = BoneTransform::Interpolate(mTracks[0][frame],
  112. mTracks[0][nextFrame], pct);
  113. outPoses[0] = interp.ToMatrix();
  114. }
  115. else
  116. {
  117. outPoses[0] = Matrix4::Identity;
  118. }
  119. const std::vector<Skeleton::Bone>& bones = inSkeleton->GetBones();
  120. // Now setup the poses for the rest
  121. for (size_t bone = 1; bone < mNumBones; bone++)
  122. {
  123. Matrix4 localMat; // (Defaults to identity)
  124. if (mTracks[bone].size() > 0)
  125. {
  126. BoneTransform interp = BoneTransform::Interpolate(mTracks[bone][frame],
  127. mTracks[bone][nextFrame], pct);
  128. localMat = interp.ToMatrix();
  129. }
  130. outPoses[bone] = localMat * outPoses[bones[bone].mParent];
  131. }
  132. }