2
0

Skeleton.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  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 "Skeleton.h"
  9. #include <fstream>
  10. #include <sstream>
  11. #include <rapidjson/document.h>
  12. #include <SDL/SDL_log.h>
  13. #include "MatrixPalette.h"
  14. bool Skeleton::Load(const std::string& fileName)
  15. {
  16. std::ifstream file(fileName);
  17. if (!file.is_open())
  18. {
  19. SDL_Log("File not found: Skeleton %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("Skeleton %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("Skeleton %s unknown format", fileName.c_str());
  38. return false;
  39. }
  40. const rapidjson::Value& bonecount = doc["bonecount"];
  41. if (!bonecount.IsUint())
  42. {
  43. SDL_Log("Skeleton %s doesn't have a bone count.", fileName.c_str());
  44. return false;
  45. }
  46. size_t count = bonecount.GetUint();
  47. if (count > MAX_SKELETON_BONES)
  48. {
  49. SDL_Log("Skeleton %s exceeds maximum bone count.", fileName.c_str());
  50. return false;
  51. }
  52. mBones.reserve(count);
  53. const rapidjson::Value& bones = doc["bones"];
  54. if (!bones.IsArray())
  55. {
  56. SDL_Log("Skeleton %s doesn't have a bone array?", fileName.c_str());
  57. return false;
  58. }
  59. if (bones.Size() != count)
  60. {
  61. SDL_Log("Skeleton %s has a mismatch between the bone count and number of bones", fileName.c_str());
  62. return false;
  63. }
  64. Bone temp;
  65. for (rapidjson::SizeType i = 0; i < count; i++)
  66. {
  67. if (!bones[i].IsObject())
  68. {
  69. SDL_Log("Skeleton %s: Bone %d is invalid.", fileName.c_str(), i);
  70. return false;
  71. }
  72. const rapidjson::Value& name = bones[i]["name"];
  73. temp.mName = name.GetString();
  74. const rapidjson::Value& parent = bones[i]["parent"];
  75. temp.mParent = parent.GetInt();
  76. const rapidjson::Value& bindpose = bones[i]["bindpose"];
  77. if (!bindpose.IsObject())
  78. {
  79. SDL_Log("Skeleton %s: Bone %d is invalid.", fileName.c_str(), i);
  80. return false;
  81. }
  82. const rapidjson::Value& rot = bindpose["rot"];
  83. const rapidjson::Value& trans = bindpose["trans"];
  84. if (!rot.IsArray() || !trans.IsArray())
  85. {
  86. SDL_Log("Skeleton %s: Bone %d is invalid.", fileName.c_str(), i);
  87. return false;
  88. }
  89. temp.mLocalBindPose.mRotation.x = rot[0].GetDouble();
  90. temp.mLocalBindPose.mRotation.y = rot[1].GetDouble();
  91. temp.mLocalBindPose.mRotation.z = rot[2].GetDouble();
  92. temp.mLocalBindPose.mRotation.w = rot[3].GetDouble();
  93. temp.mLocalBindPose.mTranslation.x = trans[0].GetDouble();
  94. temp.mLocalBindPose.mTranslation.y = trans[1].GetDouble();
  95. temp.mLocalBindPose.mTranslation.z = trans[2].GetDouble();
  96. mBones.emplace_back(temp);
  97. }
  98. // Now that we have the bones
  99. ComputeGlobalInvBindPose();
  100. return true;
  101. }
  102. void Skeleton::ComputeGlobalInvBindPose()
  103. {
  104. // Resize to number of bones, which automatically fills identity
  105. mGlobalInvBindPoses.resize(GetNumBones());
  106. // Step 1: Compute global bind pose for each bone
  107. // The global bind pose for root is just the local bind pose
  108. mGlobalInvBindPoses[0] = mBones[0].mLocalBindPose.ToMatrix();
  109. // Each remaining bone's global bind pose is its local pose
  110. // multiplied by the parent's global bind pose
  111. for (size_t i = 1; i < mGlobalInvBindPoses.size(); i++)
  112. {
  113. Matrix4 localMat = mBones[i].mLocalBindPose.ToMatrix();
  114. mGlobalInvBindPoses[i] = localMat * mGlobalInvBindPoses[mBones[i].mParent];
  115. }
  116. // Step 2: Invert
  117. for (size_t i = 0; i < mGlobalInvBindPoses.size(); i++)
  118. {
  119. mGlobalInvBindPoses[i].Invert();
  120. }
  121. }