Advertisement
Guest User

Untitled

a guest
Jun 17th, 2013
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.10 KB | None | 0 0
  1. #include "CharacterDisplayer.hpp"
  2.  
  3. Display::CharacterDisplayer::CharacterDisplayer(DisplayInterface& display) :
  4.     mDisplay(display),
  5.     mResources(mDisplay),
  6.     mCurrentAnimationElapsedTime(0)
  7. {
  8.  
  9. }
  10.  
  11. void Display::CharacterDisplayer::setCharacterResource(const std::string& name) {
  12.     // clearing everything
  13.     mBones.clear();
  14.     mSlots.clear();
  15.     mSkins.clear();
  16.     mAnimations.clear();
  17.     mCurrentAnimationElapsedTime = 0;
  18.  
  19.     // loading the YAML
  20.     mCharacterInfos = YAML::Load(ExternalResource(name));
  21.  
  22.     // filling bones list structure
  23.     for (auto& boneNode : mCharacterInfos[std::string("bones")]) {
  24.         auto& boneInfos = mBones[boneNode[std::string("name")].as<std::string>()];
  25.  
  26.         // filling parent if possible
  27.         {   auto& parentBoneNode = boneNode[std::string("parent")];
  28.             if (parentBoneNode.IsScalar())
  29.                 boneInfos.parentBone = parentBoneNode.as<std::string>();
  30.         }
  31.  
  32.         // filling default informations
  33.         {   boneInfos.defaultSetup.x = 0;
  34.             boneInfos.defaultSetup.y = 0;
  35.             boneInfos.defaultSetup.rotation = 0;
  36.             boneInfos.defaultSetup.scaleX = 1;
  37.             boneInfos.defaultSetup.scaleY = 1;
  38.  
  39.             auto& nodeX = boneNode[std::string("x")];
  40.             if (nodeX.IsScalar())
  41.                 boneInfos.defaultSetup.x = nodeX.as<float>();
  42.  
  43.             auto& nodeY = boneNode[std::string("y")];
  44.             if (nodeY.IsScalar())
  45.                 boneInfos.defaultSetup.y = nodeY.as<float>();
  46.  
  47.             auto& nodeRotation = boneNode[std::string("rotation")];
  48.             if (nodeRotation.IsScalar())
  49.                 boneInfos.defaultSetup.rotation = nodeRotation.as<float>() * 3.14159265f / 180.f;
  50.  
  51.             auto& nodeScaleX = boneNode[std::string("scaleX")];
  52.             if (nodeScaleX.IsScalar())
  53.                 boneInfos.defaultSetup.scaleX = nodeScaleX.as<float>();
  54.  
  55.             auto& nodeScaleY = boneNode[std::string("scaleY")];
  56.             if (nodeScaleY.IsScalar())
  57.                 boneInfos.defaultSetup.scaleY = nodeScaleY.as<float>();
  58.         }
  59.     }
  60.  
  61.     // filling slots list structure
  62.     for (auto& slotNode : mCharacterInfos[std::string("slots")]) {
  63.         auto& slotInfos = mSlots[slotNode[std::string("name")].as<std::string>()];
  64.  
  65.         // filling bone
  66.         slotInfos.bone = slotNode[std::string("bone")].as<std::string>();
  67.  
  68.         // filling attachment if possible
  69.         {   auto& attachmentBoneNode = slotNode[std::string("attachment")];
  70.             if (attachmentBoneNode.IsScalar())
  71.                 slotInfos.attributes.attachment = attachmentBoneNode.as<std::string>();
  72.         }
  73.     }
  74.  
  75.     // filling skins list structure
  76.     for (auto& skinNode : mCharacterInfos[std::string("skins")]) {
  77.         for (auto& skinSlotNode : skinNode.second) {
  78.             for (auto& attachementNode : skinSlotNode.second) {
  79.                 // creating new attachment
  80.                 auto& attachmentInfos = mSkins[skinNode.first.as<std::string>()][skinSlotNode.first.as<std::string>()][attachementNode.first.as<std::string>()];
  81.                
  82.                 // filling real name
  83.                 {   auto& nameNode = attachementNode.second[std::string("name")];
  84.                     if (nameNode.IsScalar())    attachmentInfos.textureName = nameNode.as<std::string>();
  85.                     else                        attachmentInfos.textureName = attachementNode.first.as<std::string>();
  86.                 }
  87.  
  88.                 // filling matrix
  89.                 {   float x = 0;
  90.                     float y = 0;
  91.                     float scaleX = 1;
  92.                     float scaleY = 1;
  93.                     float rotation = 0;
  94.                     float width = 1;
  95.                     float height = 1;
  96.  
  97.                     auto& nodeX = attachementNode.second[std::string("x")];
  98.                     if (nodeX.IsScalar())
  99.                         x = nodeX.as<float>();
  100.  
  101.                     auto& nodeY = attachementNode.second[std::string("y")];
  102.                     if (nodeY.IsScalar())
  103.                         y = nodeY.as<float>();
  104.  
  105.                     auto& nodeScaleX = attachementNode.second[std::string("scaleX")];
  106.                     if (nodeScaleX.IsScalar())
  107.                         scaleX = nodeScaleX.as<float>();
  108.  
  109.                     auto& nodeScaleY = attachementNode.second[std::string("scaleY")];
  110.                     if (nodeScaleY.IsScalar())
  111.                         scaleY = nodeScaleY.as<float>();
  112.  
  113.                     auto& nodeRotation = attachementNode.second[std::string("rotation")];
  114.                     if (nodeRotation.IsScalar())
  115.                         rotation = nodeRotation.as<float>() * 3.14159265f / 180.f;
  116.  
  117.                     auto& nodeWidth = attachementNode.second[std::string("width")];
  118.                     if (nodeWidth.IsScalar())
  119.                         width = nodeWidth.as<float>();
  120.  
  121.                     auto& nodeHeight = attachementNode.second[std::string("height")];
  122.                     if (nodeHeight.IsScalar())
  123.                         height = nodeHeight.as<float>();
  124.  
  125.                     attachmentInfos.matrixToSlot = attachmentInfos.matrixToSlot.buildIdentityMatrix();
  126.                     attachmentInfos.matrixToSlot(1, 1) = cos(rotation);
  127.                     attachmentInfos.matrixToSlot(2, 2) = attachmentInfos.matrixToSlot(1, 1);
  128.                     attachmentInfos.matrixToSlot(1, 2) = sin(rotation);
  129.                     attachmentInfos.matrixToSlot(2, 1) = -attachmentInfos.matrixToSlot(1, 2);
  130.                     attachmentInfos.matrixToSlot(1, 1) *= scaleX * width;
  131.                     attachmentInfos.matrixToSlot(1, 2) *= scaleX * width;
  132.                     attachmentInfos.matrixToSlot(2, 1) *= scaleY * height;
  133.                     attachmentInfos.matrixToSlot(2, 2) *= scaleY * height;
  134.                     attachmentInfos.matrixToSlot(4, 1) = x;
  135.                     attachmentInfos.matrixToSlot(4, 2) = y;
  136.                 }
  137.  
  138.                 // filling sprite displayer
  139.                 attachmentInfos.displayer = std::make_shared<SpriteDisplayer>(mDisplay);
  140.                 attachmentInfos.displayer->setTexture(mResources.loadTexture(attachmentInfos.textureName));
  141.                 attachmentInfos.displayer->setRectangleCoords(-0.5f, 0.5f, 0.5f, -0.5f);
  142.             }
  143.         }
  144.     }
  145.  
  146.     // filling animations list structure
  147.     for (auto& animationNode : mCharacterInfos[std::string("animations")]) {
  148.         auto& animationInfos = mAnimations[animationNode.first.as<std::string>()];
  149.         animationInfos.maxTime = 0;
  150.  
  151.         // dummy so that an animation is automatically selected
  152.         mCurrentAnimation = animationNode.first.as<std::string>();
  153.  
  154.         // building timelines for bones
  155.         for (auto& boneNode : animationNode.second[std::string("bones")]) {
  156.             auto& timelineInfos = animationInfos.bonesTimelines[boneNode.first.as<std::string>()];
  157.  
  158.             // enumerating elements in timeline
  159.             for (auto& timelineType : boneNode.second) {
  160.                 const auto type = timelineType.first.as<std::string>();
  161.                 BoneTimelineElement* previousElement = nullptr;
  162.  
  163.                 for (auto& timelineElement : timelineType.second) {
  164.                     std::unique_ptr<BoneTimelineElement> element(new BoneTimelineElement);
  165.                     element->time = timelineElement[std::string("time")].as<float>();
  166.                     element->next = nullptr;
  167.                     element->curveFunction = parseCurveFunction(timelineElement[std::string("curve")]);
  168.  
  169.                     // updating animation's max time
  170.                     if (animationInfos.maxTime < element->time)
  171.                         animationInfos.maxTime = element->time;
  172.  
  173.                     // building the "apply" function
  174.                     if (type == "translate") {
  175.                         float x = 0;
  176.                         float y = 0;
  177.  
  178.                         auto& nodeX = timelineElement[std::string("x")];
  179.                         if (nodeX.IsScalar())   x = nodeX.as<float>();
  180.                         auto& nodeY = timelineElement[std::string("y")];
  181.                         if (nodeY.IsScalar())   y = nodeY.as<float>();
  182.  
  183.                         element->apply = [=](BoneAttributes& attr) { attr.x = x; attr.y = y; };
  184.  
  185.                     } else if (type == "rotate") {
  186.                         float rotation = 0;
  187.  
  188.                         auto& nodeRotation = timelineElement[std::string("angle")];
  189.                         if (nodeRotation.IsScalar())    rotation = nodeRotation.as<float>() * 3.14159265f / 180.f;
  190.  
  191.                         element->apply = [=](BoneAttributes& attr) { attr.rotation = rotation; };
  192.  
  193.                     } else if (type == "scale") {
  194.                         float x = 0;
  195.                         float y = 0;
  196.  
  197.                         auto& nodeX = timelineElement[std::string("x")];
  198.                         if (nodeX.IsScalar())   x = nodeX.as<float>();
  199.                         auto& nodeY = timelineElement[std::string("y")];
  200.                         if (nodeY.IsScalar())   y = nodeY.as<float>();
  201.  
  202.                         element->apply = [=](BoneAttributes& attr) { attr.scaleX = x; attr.scaleY = y; };
  203.                     }
  204.  
  205.                     // inserting in list
  206.                     if (previousElement)
  207.                         previousElement->next = element.get();
  208.                     previousElement = element.get();
  209.                     timelineInfos.push_back(std::move(element));
  210.                 }
  211.             }
  212.         }
  213.        
  214.         // building timelines for slots
  215.         for (auto& slotNode : animationNode.second[std::string("slots")]) {
  216.             auto& timelineInfos = animationInfos.slotsTimelines[slotNode.first.as<std::string>()];
  217.  
  218.             // enumerating elements in timeline
  219.             for (auto& timelineType : slotNode.second) {
  220.                 const auto type = timelineType.first.as<std::string>();
  221.                 SlotTimelineElement* previousElement = nullptr;
  222.  
  223.                 for (auto& timelineElement : timelineType.second) {
  224.                     std::unique_ptr<SlotTimelineElement> element(new SlotTimelineElement);
  225.                     element->time = timelineElement[std::string("time")].as<float>();
  226.                     element->next = nullptr;
  227.                     element->curveFunction = parseCurveFunction(timelineElement[std::string("curve")]);
  228.  
  229.                     // updating animation's max time
  230.                     if (animationInfos.maxTime < element->time)
  231.                         animationInfos.maxTime = element->time;
  232.  
  233.                     // building the "apply" function
  234.                     if (type == "attachment") {
  235.                         const auto name = timelineElement[std::string("name")].as<std::string>();
  236.                         element->apply = [=](SlotAttributes& attr) { attr.attachment = name; };
  237.  
  238.                     } else if (type == "color") {
  239.                         // TODO:
  240.  
  241.                     }
  242.  
  243.                     // inserting in list
  244.                     if (previousElement)
  245.                         previousElement->next = element.get();
  246.                     previousElement = element.get();
  247.                     timelineInfos.push_back(std::move(element));
  248.                 }
  249.             }
  250.         }
  251.     }
  252.  
  253.     // setting default animation
  254.     mCurrentAnimation = "walk";
  255. }
  256.  
  257. void Display::CharacterDisplayer::draw(const Maths::Matrix<4>& matrix) const {
  258.     auto currentAnimation = &mAnimations.at(mCurrentAnimation);
  259.  
  260.     mCurrentAnimationElapsedTime += 1.f / 60.f;     // TODO:
  261.     if (mCurrentAnimationElapsedTime > currentAnimation->maxTime)
  262.         mCurrentAnimationElapsedTime -= currentAnimation->maxTime;
  263.  
  264.     // this variable will contain
  265.     std::unordered_map<std::string,Maths::Matrix<4>> bonesAttributes;
  266.  
  267.     // updating bones
  268.     for (auto& bone : mBones) {
  269.         // this variable will contain the final attributes for this bone
  270.         auto totalAttributes = bone.second.defaultSetup;
  271.  
  272.         //
  273.         {   const auto animationIter = currentAnimation->bonesTimelines.find(bone.first);
  274.             if (animationIter != currentAnimation->bonesTimelines.end()) {
  275.                 for (auto& timelineElement : currentAnimation->bonesTimelines.at(bone.first)) {
  276.                     if (timelineElement->time > mCurrentAnimationElapsedTime || (timelineElement->next && timelineElement->next->time <= mCurrentAnimationElapsedTime))
  277.                         continue;
  278.  
  279.                     // we have identified the current animation member
  280.                     BoneAttributes attributes;
  281.                     timelineElement->apply(attributes);
  282.  
  283.                     // handling interpolation
  284.                     if (timelineElement->next) {
  285.                         const auto interpolationPercentage = timelineElement->curveFunction((mCurrentAnimationElapsedTime - timelineElement->time) / (timelineElement->next->time - timelineElement->time));
  286.                
  287.                         BoneAttributes nextAttr;
  288.                         timelineElement->next->apply(nextAttr);
  289.                         attributes.x += interpolationPercentage * (nextAttr.x - attributes.x);
  290.                         attributes.y += interpolationPercentage * (nextAttr.y - attributes.y);
  291.                         attributes.rotation += interpolationPercentage * (nextAttr.rotation - attributes.rotation);
  292.                         attributes.scaleX += interpolationPercentage * (nextAttr.scaleX - attributes.scaleX);
  293.                         attributes.scaleY += interpolationPercentage * (nextAttr.scaleY - attributes.scaleY);
  294.                     }
  295.  
  296.                     // commit to totalAttributes
  297.                     totalAttributes.x += attributes.x;
  298.                     totalAttributes.y += attributes.y;
  299.                     totalAttributes.rotation += attributes.rotation;
  300.                     totalAttributes.scaleX *= attributes.scaleX;
  301.                     totalAttributes.scaleY *= attributes.scaleY;
  302.                 }
  303.             }
  304.         }
  305.  
  306.         // computing matrix
  307.         auto& matrix = bonesAttributes[bone.first];
  308.         matrix = matrix.buildIdentityMatrix();
  309.         matrix(4, 1) = totalAttributes.x;
  310.         matrix(4, 2) = totalAttributes.y;
  311.         matrix(1, 1) = cos(totalAttributes.rotation);
  312.         matrix(2, 2) = matrix(1, 1);
  313.         matrix(1, 2) = sin(totalAttributes.rotation);
  314.         matrix(2, 1) = -matrix(1, 2);
  315.         matrix(1, 1) *= totalAttributes.scaleX;
  316.         matrix(1, 2) *= totalAttributes.scaleX;
  317.         matrix(2, 1) *= totalAttributes.scaleY;
  318.         matrix(2, 2) *= totalAttributes.scaleY;
  319.  
  320.         // multiplying by parent matrix
  321.         if (!bone.second.parentBone.empty())
  322.             matrix *= bonesAttributes.at(bone.second.parentBone);
  323.     }
  324.  
  325.     // dezoom matrix
  326.     Maths::Matrix<4> dezoomMatrix = Maths::Matrix<4>::buildIdentityMatrix();
  327.     dezoomMatrix(1, 1) = 1.f / 500.f;
  328.     dezoomMatrix(2, 2) = 1.f / 500.f;
  329.  
  330.     // updating slots
  331.     for (auto& slot : mSlots) {
  332.         SlotAttributes currentAttributes = slot.second.attributes;
  333.  
  334.         //
  335.         {   const auto animationIter = currentAnimation->slotsTimelines.find(slot.first);
  336.             if (animationIter != currentAnimation->slotsTimelines.end()) {
  337.                 for (auto& timelineElement : currentAnimation->slotsTimelines.at(slot.first)) {
  338.                     if (timelineElement->time > mCurrentAnimationElapsedTime || (timelineElement->next && timelineElement->next->time <= mCurrentAnimationElapsedTime))
  339.                         continue;
  340.  
  341.                     // we have identified the current animation member
  342.                     timelineElement->apply(currentAttributes);
  343.                 }
  344.             }
  345.         }
  346.        
  347.         // drawing
  348.         if (!currentAttributes.attachment.empty()) {
  349.             auto& attachment = mSkins.at("default").at(slot.first).at(currentAttributes.attachment);
  350.             auto& boneMatrix = bonesAttributes.at(slot.second.bone);
  351.             attachment.displayer->draw(attachment.matrixToSlot * boneMatrix * dezoomMatrix);
  352.         }
  353.     }
  354. }
  355.  
  356. std::function<float (float)> Display::CharacterDisplayer::parseCurveFunction(const YAML::Node& curveNode) {
  357.     // if not defined, assume linear
  358.     if (!curveNode.IsDefined() || curveNode.IsNull())
  359.         return [](float x) { return x; };
  360.    
  361.     // checking keywords "linear" and "stepped"
  362.     if (curveNode.IsScalar()) {
  363.         if (curveNode.as<std::string>() == "linear")        return [](float x) -> float { return x; };
  364.         if (curveNode.as<std::string>() == "stepped")       return [](float) -> float { return 0.f; };
  365.     }
  366.  
  367.     // bézier curve
  368.     if (curveNode.IsSequence()) {
  369.         const auto cx1 = curveNode[0].as<float>();
  370.         const auto cy1 = curveNode[1].as<float>();
  371.         const auto cx2 = curveNode[2].as<float>();
  372.         const auto cy2 = curveNode[3].as<float>();
  373.  
  374.         return [=](float x) {
  375.             auto previousX = 0;
  376.             for (float t = 0; t <= 1; t += 0.01f) {
  377.                 const auto calculatedX = 3*cx1*t*(1-t)*(1-t) + 3*cx2*t*t*(1-t) + t*t*t;
  378.                 if (calculatedX < x)
  379.                     continue;
  380.                 const auto calculatedY = 3*cy1*t*(1-t)*(1-t) + 3*cy2*t*t*(1-t) + t*t*t;
  381.                 return calculatedY;
  382.             }
  383.  
  384.             // TODO: assert false or something
  385.             return x;
  386.         };
  387.     }
  388.  
  389.     throw "Unknown value for curve property";
  390. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement