2
0

Animation.cpp 4.5 KB

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