| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- // ----------------------------------------------------------------
- // From Game Programming in C++ by Sanjay Madhav
- // Copyright (C) 2017 Sanjay Madhav. All rights reserved.
- //
- // Released under the BSD License
- // See LICENSE in root directory for full details.
- // ----------------------------------------------------------------
- #include "Skeleton.h"
- #include <rapidjson/document.h>
- #include <SDL/SDL_log.h>
- #include "MatrixPalette.h"
- #include "LevelLoader.h"
- bool Skeleton::Load(const std::string& fileName)
- {
- mFileName = fileName;
- rapidjson::Document doc;
- if (!LevelLoader::LoadJSON(fileName, doc))
- {
- SDL_Log("Failed to load skeleton %s", fileName.c_str());
- return false;
- }
- int ver = doc["version"].GetInt();
- // Check the metadata
- if (ver != 1)
- {
- SDL_Log("Skeleton %s unknown format", fileName.c_str());
- return false;
- }
- const rapidjson::Value& bonecount = doc["bonecount"];
- if (!bonecount.IsUint())
- {
- SDL_Log("Skeleton %s doesn't have a bone count.", fileName.c_str());
- return false;
- }
- size_t count = bonecount.GetUint();
- if (count > MAX_SKELETON_BONES)
- {
- SDL_Log("Skeleton %s exceeds maximum bone count.", fileName.c_str());
- return false;
- }
- mBones.reserve(count);
- const rapidjson::Value& bones = doc["bones"];
- if (!bones.IsArray())
- {
- SDL_Log("Skeleton %s doesn't have a bone array?", fileName.c_str());
- return false;
- }
- if (bones.Size() != count)
- {
- SDL_Log("Skeleton %s has a mismatch between the bone count and number of bones", fileName.c_str());
- return false;
- }
- Bone temp;
- for (rapidjson::SizeType i = 0; i < count; i++)
- {
- if (!bones[i].IsObject())
- {
- SDL_Log("Skeleton %s: Bone %d is invalid.", fileName.c_str(), i);
- return false;
- }
- const rapidjson::Value& name = bones[i]["name"];
- temp.mName = name.GetString();
- const rapidjson::Value& parent = bones[i]["parent"];
- temp.mParent = parent.GetInt();
- const rapidjson::Value& bindpose = bones[i]["bindpose"];
- if (!bindpose.IsObject())
- {
- SDL_Log("Skeleton %s: Bone %d is invalid.", fileName.c_str(), i);
- return false;
- }
- const rapidjson::Value& rot = bindpose["rot"];
- const rapidjson::Value& trans = bindpose["trans"];
- if (!rot.IsArray() || !trans.IsArray())
- {
- SDL_Log("Skeleton %s: Bone %d is invalid.", fileName.c_str(), i);
- return false;
- }
- temp.mLocalBindPose.mRotation.x = rot[0].GetDouble();
- temp.mLocalBindPose.mRotation.y = rot[1].GetDouble();
- temp.mLocalBindPose.mRotation.z = rot[2].GetDouble();
- temp.mLocalBindPose.mRotation.w = rot[3].GetDouble();
- temp.mLocalBindPose.mTranslation.x = trans[0].GetDouble();
- temp.mLocalBindPose.mTranslation.y = trans[1].GetDouble();
- temp.mLocalBindPose.mTranslation.z = trans[2].GetDouble();
- mBones.emplace_back(temp);
- }
- // Now that we have the bones
- ComputeGlobalInvBindPose();
- return true;
- }
- void Skeleton::ComputeGlobalInvBindPose()
- {
- // Resize to number of bones, which automatically fills identity
- mGlobalInvBindPoses.resize(GetNumBones());
-
- // Step 1: Compute global bind pose for each bone
-
- // The global bind pose for root is just the local bind pose
- mGlobalInvBindPoses[0] = mBones[0].mLocalBindPose.ToMatrix();
- // Each remaining bone's global bind pose is its local pose
- // multiplied by the parent's global bind pose
- for (size_t i = 1; i < mGlobalInvBindPoses.size(); i++)
- {
- Matrix4 localMat = mBones[i].mLocalBindPose.ToMatrix();
- mGlobalInvBindPoses[i] = localMat * mGlobalInvBindPoses[mBones[i].mParent];
- }
- // Step 2: Invert
- for (size_t i = 0; i < mGlobalInvBindPoses.size(); i++)
- {
- mGlobalInvBindPoses[i].Invert();
- }
- }
|