SHARE
TWEET

Untitled

a guest Nov 19th, 2019 83 in 7 days
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include "BoundarySystem.h"
  2. #include "EntityManager.h"
  3.  
  4. BoundarySystem::BoundarySystem(EntityManager* manager)
  5.     :manager{ manager }
  6. {
  7. }
  8.  
  9. BoundarySystem::~BoundarySystem()
  10. {
  11. }
  12.  
  13. BoundarySystem* BoundarySystem::GetInstance(EntityManager* manager)
  14. {
  15.     static std::unique_ptr<BoundarySystem> boundarySystem(new BoundarySystem(manager));
  16.  
  17.     if (boundarySystem) {
  18.         return boundarySystem.get();
  19.     }
  20.     else {
  21.         return nullptr;
  22.     }
  23. }
  24.  
  25. void BoundarySystem::InitConstraintComponent(ConstraintComponent* thisComp)
  26. {
  27.     Entity* owner = manager->GetEntity(thisComp->GetOwnerID());
  28.     Entity* parent = manager->GetEntity(owner->GetParentEntityID());
  29.  
  30.     InitConstraintComponentPos(thisComp);
  31.  
  32.     //Clamp to parent Constraint rect
  33.     if (thisComp->clampToParent && parent->HasComponentType(ECType::ConstraintComponent)) {
  34.         auto* parentRect = manager->GetFirstComponentForType<ConstraintComponent>(parent);
  35.         ClampToFit(thisComp->rect, parentRect->rect);
  36.     }
  37. }
  38.  
  39. void BoundarySystem::InitConstraintComponentPos(ConstraintComponent* thisComp)
  40. {
  41.     auto& rect = thisComp->rect;
  42.     auto& pos = thisComp->pos;
  43.     float width = rect.right;
  44.     float height = rect.bottom;
  45.  
  46.     if (thisComp->posType == EPosType::absolute) {
  47.  
  48.         switch (thisComp->posAlign)
  49.         {
  50.         case EGizmoAlign::top_left:
  51.             MoveX(rect, pos.x);
  52.             MoveY(rect, pos.y);
  53.             break;
  54.         case EGizmoAlign::center:
  55.             MoveX(rect, pos.x - width / 2);
  56.             MoveY(rect, pos.y - height / 2);
  57.             break;
  58.         }
  59.     }
  60.     else
  61.     {
  62.         //make sure relative pos is in range 0-1, clamp if is not
  63.         if (pos.x > 1.f || pos.y > 1.f) {
  64.             float max = max(pos.x, pos.y);
  65.             if (pos.x > 0) pos.x /= max;
  66.             if (pos.y > 0) pos.y /= max;
  67.         }
  68.  
  69.         RECT client{};
  70.         GetWindowRect(RenderingSystem::GetInstance()->GetGfx()->GetHwnd(), &client);
  71.  
  72.         switch (thisComp->posAlign)
  73.         {
  74.         case EGizmoAlign::top_left:
  75.             MoveX(rect, pos.x * client.right);
  76.             MoveY(rect, pos.y * client.bottom);
  77.             break;
  78.         case EGizmoAlign::center:
  79.             MoveX(rect, (pos.x * client.right) - width / 2);
  80.             MoveY(rect, (pos.y * client.bottom) - height / 2);
  81.             break;
  82.         }
  83.     }
  84. }
  85.  
  86. void BoundarySystem::SnapRectCompToConstraint(Entity* entity)
  87. {
  88.     if (entity->HasComponentType(ECType::ConstraintComponent)
  89.         && entity->HasComponentType(ECType::RectComponent))
  90.     {
  91.         vector<uInt> rectIDs = entity->GetComponentsIDForType(ECType::RectComponent);
  92.         auto& rectComponentsVec = manager->GetComponentsVector<RectComponent>();
  93.         auto* constrComp = manager->GetFirstComponentForType<ConstraintComponent>(entity);
  94.         for (uInt i = 0; i < rectIDs.size(); i++) {
  95.             uInt ID = rectIDs[i];
  96.             if (rectComponentsVec[ID].snapToConstraint) {
  97.                 SnapRectCompToConstraint(&rectComponentsVec[ID], constrComp);
  98.             }
  99.         }
  100.     }
  101. }
  102.  
  103. void BoundarySystem::SnapRectCompToConstraint(RectComponent* rectComp, ConstraintComponent* constrComp)
  104. {
  105.     rectComp->rect = constrComp->rect;
  106. }
  107.  
  108. void BoundarySystem::AnchorTo(EEHandle thisHandle, EAnchor thisSide, EEHandle otherHandle, EAnchor otherSide)
  109. {
  110.     //ensure both have a ConstraintComponent
  111.     if (!manager->GetEntity(thisHandle)->HasComponentType(ECType::ConstraintComponent)
  112.         || !manager->GetEntity(otherHandle)->HasComponentType(ECType::ConstraintComponent))
  113.     {
  114.         return;
  115.     }
  116.  
  117.     //ensure both anchors are on the same axis or that both are "center"
  118.     if (otherSide != thisSide) {
  119.         if (otherSide != OppositeAnchorSide(thisSide))
  120.             return;
  121.     }
  122.  
  123.  
  124.     auto* thisComp = manager->GetFirstComponentForType<ConstraintComponent>(thisHandle);
  125.     auto* otherComp = manager->GetFirstComponentForType<ConstraintComponent>(otherHandle);
  126.  
  127.     //free thisComponent from previous anchors
  128.     switch (thisSide)
  129.     {
  130.     case EAnchor::left:
  131.     case EAnchor::right:
  132.         EraseAnchorsAndBridgeGap(thisComp, EAxis::horizontal);
  133.         break;
  134.     case EAnchor::top:
  135.     case EAnchor::bottom:
  136.         EraseAnchorsAndBridgeGap(thisComp, EAxis::vertical);
  137.         break;
  138.     }
  139.  
  140.     //Link new anchors
  141.     LinkAnchors(thisComp, thisSide, otherComp, otherSide);
  142.  
  143.     //move this Component to its anchor
  144.     float deltaMove{};
  145.     deltaMove = MoveConstraintComponent(thisComp, thisSide, otherComp, otherSide);
  146.  
  147.     //move linked components EXCEPT otherComp by the same ammount
  148.  
  149.  
  150.  
  151. }
  152.  
  153. void BoundarySystem::LinkAnchors(ConstraintComponent* thisComp, EAnchor thisSide, ConstraintComponent* otherComp, EAnchor otherSide)
  154. {
  155.     //if one is center, then both need to be.
  156.     if (thisSide == EAnchor::center || otherSide == EAnchor::center) {
  157.         if (thisSide != otherSide) {
  158.             return;
  159.         }
  160.     }
  161.  
  162.     auto& thisAnchors = thisComp->anchors;
  163.     auto& otherAnchors = otherComp->anchors;
  164.  
  165.     //if we insert thisComp between two elements, then we inherit the one previously linked to otherComp
  166.     if (otherAnchors.find(otherSide) != otherAnchors.end()) {
  167.         //if we anchor inside another component, example: this anchor is left and other anchor is left
  168.         //then we move the inherited component we are replacing to the right
  169.         auto inheritSide = (thisSide == otherSide) ? OppositeAnchorSide(otherSide) : otherSide;
  170.         thisAnchors[inheritSide] = otherAnchors[otherSide];
  171.     }
  172.     otherAnchors[otherSide].neighborHandle = manager->GetHandleFromID(thisComp->GetOwnerID());
  173.     otherAnchors[otherSide].neighborSide = thisSide;
  174.     //center is special, in case of center only the other component need to know about this.
  175.     //the other (bottom) component can move this, but this shouldn't know about the bottom one.
  176.     if (thisSide != EAnchor::center) {
  177.         thisAnchors[thisSide].neighborHandle = manager->GetHandleFromID(otherComp->GetOwnerID());
  178.         thisAnchors[thisSide].neighborSide = otherSide;
  179.     }
  180. }
  181.  
  182. void BoundarySystem::EraseAnchorsAndBridgeGap(ConstraintComponent* thisComp, EAxis axis)
  183. {
  184.     auto& anchors = thisComp->anchors;
  185.  
  186.     switch (axis)
  187.     {
  188.     case EAxis::horizontal:
  189.         if (anchors.find(EAnchor::left) != anchors.end()
  190.             && anchors.find(EAnchor::right) != anchors.end()
  191.             )
  192.         {
  193.             //bridge gap
  194.             auto& leftAnchors = manager->GetFirstComponentForType<ConstraintComponent>(anchors[EAnchor::left].neighborHandle)->anchors;
  195.             auto& rightAnchors = manager->GetFirstComponentForType<ConstraintComponent>(anchors[EAnchor::right].neighborHandle)->anchors;
  196.             leftAnchors[EAnchor::right] = anchors[EAnchor::right];
  197.             rightAnchors[EAnchor::left] = anchors[EAnchor::left];
  198.         }
  199.         anchors.erase(EAnchor::left);
  200.         anchors.erase(EAnchor::right);
  201.         break;
  202.     case EAxis::vertical:
  203.         //bridge gap
  204.         if (anchors.find(EAnchor::top) != anchors.end()
  205.             && anchors.find(EAnchor::bottom) != anchors.end()
  206.             )
  207.         {
  208.             auto& topAnchors = manager->GetFirstComponentForType<ConstraintComponent>(anchors[EAnchor::top].neighborHandle)->anchors;
  209.             auto& bottomAnchors = manager->GetFirstComponentForType<ConstraintComponent>(anchors[EAnchor::bottom].neighborHandle)->anchors;
  210.             topAnchors[EAnchor::bottom] = anchors[EAnchor::bottom];
  211.             bottomAnchors[EAnchor::top] = anchors[EAnchor::top];
  212.         }
  213.         anchors.erase(EAnchor::top);
  214.         anchors.erase(EAnchor::bottom);
  215.         break;
  216.     }
  217. }
  218.  
  219. float BoundarySystem::MoveConstraintComponent(ConstraintComponent* thisComp, EAnchor thisSide, const ConstraintComponent* otherComp, EAnchor otherSide)
  220. {
  221.     auto& rect = thisComp->rect;
  222.     auto otherRect = otherComp->rect;
  223.     float delta{};
  224.  
  225.     EResponse response{};
  226.  
  227.     switch (thisSide)
  228.     {
  229.     case EAnchor::left: response = thisComp->responseType.left; break;
  230.     case EAnchor::top: response = thisComp->responseType.top; break;
  231.     case EAnchor::right: response = thisComp->responseType.right; break;
  232.     case EAnchor::bottom: response = thisComp->responseType.bottom; break;
  233.     case EAnchor::center: response = EResponse::rigid; break;
  234.     }
  235.  
  236.  
  237.     //If response is rigid, should move 2 sides of the rect
  238.     //If response is flexible, should move only 1 side
  239.     switch (response)
  240.     {
  241.     case EResponse::rigid:
  242.         if (thisSide != EAnchor::center) {
  243.             float& rectSide = RectSideFromAnchor(rect, thisSide);
  244.             float& oppositeSide = RectSideFromAnchor(rect, OppositeAnchorSide(thisSide));
  245.             const auto& targetSide = RectSideFromAnchor(otherRect, otherSide);
  246.  
  247.             delta = targetSide - rectSide;
  248.             rectSide += delta;
  249.             oppositeSide += delta;
  250.  
  251.             UpdateConstraintPos(thisComp);
  252.         }
  253.         else
  254.         {
  255.             float targetW = GetWidth(otherRect);
  256.             float targetH = GetHeight(otherRect);
  257.             D2D_POINT_2F targetPos{ otherRect.left + targetW / 2,otherRect.top + targetH / 2 };
  258.             float halfThisW = GetWidth(rect)/2;
  259.             float halfThisH = GetHeight(rect)/2;
  260.            
  261.             rect.left = targetPos.x - halfThisW;
  262.             rect.right = targetPos.x + halfThisW;
  263.             rect.top = targetPos.y - halfThisH;
  264.             rect.bottom = targetPos.y + halfThisH;
  265.            
  266.             UpdateConstraintPos(thisComp);
  267.         }
  268.         break;
  269.  
  270.     case EResponse::flexible:
  271.         float& rectSide = RectSideFromAnchor(rect, thisSide);
  272.         const auto& targetSide = RectSideFromAnchor(otherRect, otherSide);
  273.         rectSide = targetSide;
  274.         UpdateConstraintPos(thisComp);
  275.         break;
  276.     }
  277.  
  278.     return delta;
  279. }
  280.  
  281. void BoundarySystem::UpdateConstraintPos(ConstraintComponent* comp)
  282. {
  283.  
  284.     const auto& rect = comp->rect;
  285.     auto& pos = comp->pos;
  286.     float width = rect.right - rect.left;
  287.     float height = rect.bottom - rect.top;
  288.  
  289.     switch (comp->posType)
  290.     {
  291.     case EPosType::absolute:
  292.     {
  293.         switch (comp->posAlign)
  294.         {
  295.         case EGizmoAlign::top_left:
  296.             pos.x = rect.left;
  297.             pos.y = rect.top;
  298.             break;
  299.         case EGizmoAlign::center:
  300.             pos.x = rect.left + width / 2;
  301.             pos.y = rect.top + height / 2;
  302.             break;
  303.         }
  304.     }
  305.     break;
  306.     case EPosType::relative:
  307.     {
  308.         RECT client{};
  309.         GetWindowRect(RenderingSystem::GetInstance()->GetGfx()->GetHwnd(), &client);
  310.  
  311.         switch (comp->posAlign)
  312.         {
  313.         case EGizmoAlign::top_left:
  314.             pos.x = rect.left / client.right;
  315.             pos.y = rect.top / client.bottom;
  316.             break;
  317.         case EGizmoAlign::center:
  318.             pos.x = (rect.left / client.right) + (width / client.right);
  319.             pos.y = (rect.top / client.bottom) + (height / client.bottom);
  320.             break;
  321.         }
  322.     }
  323.         break;
  324.     }
  325. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top