Skip to content

Commit

Permalink
V4 uilayout scissorclipping fix (cocos2d#20415)
Browse files Browse the repository at this point in the history
* Fix for issue cocos2d#19890

* Updated with better fix from the V3 PR cocos2d#18651

* Formatting fix

* Fixed issue with incorrect type (double instead of float) when compiling on certain platforms.

* Another attempt to fix compilation issue
  • Loading branch information
rh101 authored and Xrysnow committed Jun 21, 2020
1 parent 4aad46e commit d81a985
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 47 deletions.
73 changes: 26 additions & 47 deletions cocos/ui/UILayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ THE SOFTWARE.
#include "base/CCEventFocus.h"
#include "base/CCStencilStateManager.h"
#include "editor-support/cocostudio/CocosStudioExtension.h"
#include <algorithm>


NS_CC_BEGIN
Expand Down Expand Up @@ -220,6 +221,9 @@ void Layout::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t par
return;
}

if (FLAGS_TRANSFORM_DIRTY & parentFlags || _transformUpdated || _contentSizeDirty)
_clippingRectDirty = true;

adaptRenderers();
doLayout();

Expand All @@ -239,7 +243,8 @@ void Layout::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t par
}
else
{
Widget::visit(renderer, parentTransform, parentFlags);
//no need to adapt render again
ProtectedNode::visit(renderer, parentTransform, parentFlags);
}
}

Expand Down Expand Up @@ -475,16 +480,20 @@ const Rect& Layout::getClippingRect()
{
if (_clippingRectDirty)
{
const Vec2 worldPos = convertToWorldSpace(Vec2::ZERO);
const AffineTransform t = getNodeToWorldAffineTransform();
const float scissorWidth = _contentSize.width * t.a;
const float scissorHeight = _contentSize.height * t.d;
const auto worldPos1 = convertToWorldSpace(Vec2::ZERO);
const auto worldPos2 = convertToWorldSpace(Vec2(_contentSize.width, _contentSize.height));

//Node can be flipped
const auto worldPos = Vec2(std::min(worldPos1.x, worldPos2.x), std::min(worldPos1.y, worldPos2.y));
const auto scissorWidth = std::fabs(worldPos2.x - worldPos1.x);
const auto scissorHeight = std::fabs(worldPos2.y - worldPos1.y);

Layout* parent = this;

while (parent)
{
parent = dynamic_cast<Layout*>(parent->getParent());
if(parent)
if (parent)
{
if (parent->isClippingEnabled())
{
Expand All @@ -493,49 +502,19 @@ const Rect& Layout::getClippingRect()
}
}
}

if (_clippingParent)
{
const Rect& parentClippingRect = _clippingParent->getClippingRect();
float finalX = worldPos.x;
float finalY = worldPos.y;
float finalWidth = scissorWidth;
float finalHeight = scissorHeight;

const float leftOffset = worldPos.x - parentClippingRect.origin.x;
if (leftOffset < 0.0f)
{
finalX = parentClippingRect.origin.x;
finalWidth += leftOffset;
}
const float rightOffset = (worldPos.x + scissorWidth) - (parentClippingRect.origin.x + parentClippingRect.size.width);
if (rightOffset > 0.0f)
{
finalWidth -= rightOffset;
}
const float topOffset = (worldPos.y + scissorHeight) - (parentClippingRect.origin.y + parentClippingRect.size.height);
if (topOffset > 0.0f)
{
finalHeight -= topOffset;
}
const float bottomOffset = worldPos.y - parentClippingRect.origin.y;
if (bottomOffset < 0.0f)
{
finalY = parentClippingRect.origin.y;
finalHeight += bottomOffset;
}
if (finalWidth < 0.0f)
{
finalWidth = 0.0f;
}
if (finalHeight < 0.0f)
{
finalHeight = 0.0f;
}
_clippingRect.origin.x = finalX;
_clippingRect.origin.y = finalY;
_clippingRect.size.width = finalWidth;
_clippingRect.size.height = finalHeight;
const auto& parentClippingRect = _clippingParent->getClippingRect();

_clippingRect.origin.x = std::max(parentClippingRect.origin.x, worldPos.x);
_clippingRect.origin.y = std::max(parentClippingRect.origin.y, worldPos.y);

const auto right = std::min(parentClippingRect.origin.x + parentClippingRect.size.width, worldPos.x + scissorWidth);
const auto top = std::min(parentClippingRect.origin.y + parentClippingRect.size.height, worldPos.y + scissorHeight);

_clippingRect.size.width = std::max(0.0f, right - _clippingRect.origin.x);
_clippingRect.size.height = std::max(0.0f, top - _clippingRect.origin.y);
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ UILayoutTests::UILayoutTests()
ADD_TEST_CASE(UILayoutComponent_Berth_Test);
ADD_TEST_CASE(UILayoutComponent_Berth_Stretch_Test);
ADD_TEST_CASE(UILayoutTest_Issue19890);
ADD_TEST_CASE(UILayout_Clipping_Test);
}

// UILayoutTest
Expand Down Expand Up @@ -1016,3 +1017,58 @@ bool UILayoutTest_Issue19890::init()

return true;
}

bool UILayout_Clipping_Test::init()
{
if (UIScene::init())
{
Size widgetSize = _widget->getContentSize();

// Add the alert
Text* alert = Text::create("Left & Right must look same", "fonts/Marker Felt.ttf", 30 );
alert->setColor(Color3B(159, 168, 176));
alert->setPosition(Vec2(widgetSize.width / 2.0f,
widgetSize.height / 2.0f - alert->getContentSize().height * 3.075f));

_uiLayer->addChild(alert);

Layout* layout1 = Layout::create();
layout1->setClippingEnabled(true);
layout1->setContentSize(Size(widgetSize.width/4, widgetSize.height/3));
layout1->setClippingType(cocos2d::ui::Layout::ClippingType::SCISSOR);
layout1->setPosition(Vec2(widgetSize.width / 4.0f, widgetSize.height / 2.0f ));
layout1->setAnchorPoint(Vec2(0.5, 0.5));
_uiLayer->addChild(layout1);

Layout* sublayout1 = Layout::create();
sublayout1->setClippingEnabled(true);
sublayout1->setBackGroundImage("cocosui/Hello.png");
sublayout1->setContentSize(Size(widgetSize.width/6, widgetSize.width/2));
sublayout1->setClippingType(cocos2d::ui::Layout::ClippingType::STENCIL);
sublayout1->setPosition(Vec2(widgetSize.width / 8.0f + widgetSize.width / 16.0f, widgetSize.height / 6.0f ));
sublayout1->setAnchorPoint(Vec2(0.5, 0.5));
sublayout1->runAction(RepeatForever::create(Sequence::createWithTwoActions(MoveBy::create(2, Vec2(-widgetSize.width/8, 0)), MoveBy::create(2, Vec2(widgetSize.width/8, 0)))));
layout1->addChild(sublayout1);

Layout* layout2 = Layout::create();
layout2->setClippingEnabled(true);
layout2->setContentSize(Size(widgetSize.width/4, widgetSize.height/3));
layout2->setClippingType(cocos2d::ui::Layout::ClippingType::SCISSOR);
layout2->setPosition(Vec2(widgetSize.width *3.0f / 4.0f, widgetSize.height / 2.0f ));
layout2->setAnchorPoint(Vec2(0.5, 0.5));
_uiLayer->addChild(layout2);

Layout* sublayout2 = Layout::create();
sublayout2->setClippingEnabled(true);
sublayout2->setBackGroundImage("cocosui/Hello.png");
sublayout2->setContentSize(Size(widgetSize.width/6, widgetSize.width/2));
sublayout2->setClippingType(cocos2d::ui::Layout::ClippingType::SCISSOR);
sublayout2->setPosition(Vec2(widgetSize.width / 8.0f + widgetSize.width / 16.0f, widgetSize.height / 6.0f ));
sublayout2->setAnchorPoint(Vec2(0.5, 0.5));
sublayout2->runAction(RepeatForever::create(Sequence::createWithTwoActions(MoveBy::create(2, Vec2(-widgetSize.width/8, 0)), MoveBy::create(2, Vec2(widgetSize.width/8, 0)))));
layout2->addChild(sublayout2);

return true;
}
return false;
}
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,12 @@ class UILayoutTest_Issue19890 : public UIScene
CREATE_FUNC(UILayoutTest_Issue19890);
};

class UILayout_Clipping_Test : public UILayoutComponentTest
{
public:
virtual bool init() override;

CREATE_FUNC(UILayout_Clipping_Test);
};

#endif /* defined(__TestCpp__UILayoutTest__) */

0 comments on commit d81a985

Please sign in to comment.