Skip to content

Commit 1959c79

Browse files
rh101minggo
authored andcommitted
V4 uilayout scissorclipping fix (#20415)
* Fix for issue #19890 * Updated with better fix from the V3 PR #18651 * Formatting fix * Fixed issue with incorrect type (double instead of float) when compiling on certain platforms. * Another attempt to fix compilation issue
1 parent e628a78 commit 1959c79

File tree

3 files changed

+90
-47
lines changed

3 files changed

+90
-47
lines changed

cocos/ui/UILayout.cpp

Lines changed: 26 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ THE SOFTWARE.
3636
#include "base/CCEventFocus.h"
3737
#include "base/CCStencilStateManager.h"
3838
#include "editor-support/cocostudio/CocosStudioExtension.h"
39+
#include <algorithm>
3940

4041

4142
NS_CC_BEGIN
@@ -220,6 +221,9 @@ void Layout::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t par
220221
return;
221222
}
222223

224+
if (FLAGS_TRANSFORM_DIRTY & parentFlags || _transformUpdated || _contentSizeDirty)
225+
_clippingRectDirty = true;
226+
223227
adaptRenderers();
224228
doLayout();
225229

@@ -239,7 +243,8 @@ void Layout::visit(Renderer *renderer, const Mat4 &parentTransform, uint32_t par
239243
}
240244
else
241245
{
242-
Widget::visit(renderer, parentTransform, parentFlags);
246+
//no need to adapt render again
247+
ProtectedNode::visit(renderer, parentTransform, parentFlags);
243248
}
244249
}
245250

@@ -475,16 +480,20 @@ const Rect& Layout::getClippingRect()
475480
{
476481
if (_clippingRectDirty)
477482
{
478-
const Vec2 worldPos = convertToWorldSpace(Vec2::ZERO);
479-
const AffineTransform t = getNodeToWorldAffineTransform();
480-
const float scissorWidth = _contentSize.width * t.a;
481-
const float scissorHeight = _contentSize.height * t.d;
483+
const auto worldPos1 = convertToWorldSpace(Vec2::ZERO);
484+
const auto worldPos2 = convertToWorldSpace(Vec2(_contentSize.width, _contentSize.height));
485+
486+
//Node can be flipped
487+
const auto worldPos = Vec2(std::min(worldPos1.x, worldPos2.x), std::min(worldPos1.y, worldPos2.y));
488+
const auto scissorWidth = std::fabs(worldPos2.x - worldPos1.x);
489+
const auto scissorHeight = std::fabs(worldPos2.y - worldPos1.y);
490+
482491
Layout* parent = this;
483492

484493
while (parent)
485494
{
486495
parent = dynamic_cast<Layout*>(parent->getParent());
487-
if(parent)
496+
if (parent)
488497
{
489498
if (parent->isClippingEnabled())
490499
{
@@ -493,49 +502,19 @@ const Rect& Layout::getClippingRect()
493502
}
494503
}
495504
}
496-
505+
497506
if (_clippingParent)
498507
{
499-
const Rect& parentClippingRect = _clippingParent->getClippingRect();
500-
float finalX = worldPos.x;
501-
float finalY = worldPos.y;
502-
float finalWidth = scissorWidth;
503-
float finalHeight = scissorHeight;
504-
505-
const float leftOffset = worldPos.x - parentClippingRect.origin.x;
506-
if (leftOffset < 0.0f)
507-
{
508-
finalX = parentClippingRect.origin.x;
509-
finalWidth += leftOffset;
510-
}
511-
const float rightOffset = (worldPos.x + scissorWidth) - (parentClippingRect.origin.x + parentClippingRect.size.width);
512-
if (rightOffset > 0.0f)
513-
{
514-
finalWidth -= rightOffset;
515-
}
516-
const float topOffset = (worldPos.y + scissorHeight) - (parentClippingRect.origin.y + parentClippingRect.size.height);
517-
if (topOffset > 0.0f)
518-
{
519-
finalHeight -= topOffset;
520-
}
521-
const float bottomOffset = worldPos.y - parentClippingRect.origin.y;
522-
if (bottomOffset < 0.0f)
523-
{
524-
finalY = parentClippingRect.origin.y;
525-
finalHeight += bottomOffset;
526-
}
527-
if (finalWidth < 0.0f)
528-
{
529-
finalWidth = 0.0f;
530-
}
531-
if (finalHeight < 0.0f)
532-
{
533-
finalHeight = 0.0f;
534-
}
535-
_clippingRect.origin.x = finalX;
536-
_clippingRect.origin.y = finalY;
537-
_clippingRect.size.width = finalWidth;
538-
_clippingRect.size.height = finalHeight;
508+
const auto& parentClippingRect = _clippingParent->getClippingRect();
509+
510+
_clippingRect.origin.x = std::max(parentClippingRect.origin.x, worldPos.x);
511+
_clippingRect.origin.y = std::max(parentClippingRect.origin.y, worldPos.y);
512+
513+
const auto right = std::min(parentClippingRect.origin.x + parentClippingRect.size.width, worldPos.x + scissorWidth);
514+
const auto top = std::min(parentClippingRect.origin.y + parentClippingRect.size.height, worldPos.y + scissorHeight);
515+
516+
_clippingRect.size.width = std::max(0.0f, right - _clippingRect.origin.x);
517+
_clippingRect.size.height = std::max(0.0f, top - _clippingRect.origin.y);
539518
}
540519
else
541520
{

tests/cpp-tests/Classes/UITest/CocoStudioGUITest/UILayoutTest/UILayoutTest.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ UILayoutTests::UILayoutTests()
4343
ADD_TEST_CASE(UILayoutComponent_Berth_Test);
4444
ADD_TEST_CASE(UILayoutComponent_Berth_Stretch_Test);
4545
ADD_TEST_CASE(UILayoutTest_Issue19890);
46+
ADD_TEST_CASE(UILayout_Clipping_Test);
4647
}
4748

4849
// UILayoutTest
@@ -1016,3 +1017,58 @@ bool UILayoutTest_Issue19890::init()
10161017

10171018
return true;
10181019
}
1020+
1021+
bool UILayout_Clipping_Test::init()
1022+
{
1023+
if (UIScene::init())
1024+
{
1025+
Size widgetSize = _widget->getContentSize();
1026+
1027+
// Add the alert
1028+
Text* alert = Text::create("Left & Right must look same", "fonts/Marker Felt.ttf", 30 );
1029+
alert->setColor(Color3B(159, 168, 176));
1030+
alert->setPosition(Vec2(widgetSize.width / 2.0f,
1031+
widgetSize.height / 2.0f - alert->getContentSize().height * 3.075f));
1032+
1033+
_uiLayer->addChild(alert);
1034+
1035+
Layout* layout1 = Layout::create();
1036+
layout1->setClippingEnabled(true);
1037+
layout1->setContentSize(Size(widgetSize.width/4, widgetSize.height/3));
1038+
layout1->setClippingType(cocos2d::ui::Layout::ClippingType::SCISSOR);
1039+
layout1->setPosition(Vec2(widgetSize.width / 4.0f, widgetSize.height / 2.0f ));
1040+
layout1->setAnchorPoint(Vec2(0.5, 0.5));
1041+
_uiLayer->addChild(layout1);
1042+
1043+
Layout* sublayout1 = Layout::create();
1044+
sublayout1->setClippingEnabled(true);
1045+
sublayout1->setBackGroundImage("cocosui/Hello.png");
1046+
sublayout1->setContentSize(Size(widgetSize.width/6, widgetSize.width/2));
1047+
sublayout1->setClippingType(cocos2d::ui::Layout::ClippingType::STENCIL);
1048+
sublayout1->setPosition(Vec2(widgetSize.width / 8.0f + widgetSize.width / 16.0f, widgetSize.height / 6.0f ));
1049+
sublayout1->setAnchorPoint(Vec2(0.5, 0.5));
1050+
sublayout1->runAction(RepeatForever::create(Sequence::createWithTwoActions(MoveBy::create(2, Vec2(-widgetSize.width/8, 0)), MoveBy::create(2, Vec2(widgetSize.width/8, 0)))));
1051+
layout1->addChild(sublayout1);
1052+
1053+
Layout* layout2 = Layout::create();
1054+
layout2->setClippingEnabled(true);
1055+
layout2->setContentSize(Size(widgetSize.width/4, widgetSize.height/3));
1056+
layout2->setClippingType(cocos2d::ui::Layout::ClippingType::SCISSOR);
1057+
layout2->setPosition(Vec2(widgetSize.width *3.0f / 4.0f, widgetSize.height / 2.0f ));
1058+
layout2->setAnchorPoint(Vec2(0.5, 0.5));
1059+
_uiLayer->addChild(layout2);
1060+
1061+
Layout* sublayout2 = Layout::create();
1062+
sublayout2->setClippingEnabled(true);
1063+
sublayout2->setBackGroundImage("cocosui/Hello.png");
1064+
sublayout2->setContentSize(Size(widgetSize.width/6, widgetSize.width/2));
1065+
sublayout2->setClippingType(cocos2d::ui::Layout::ClippingType::SCISSOR);
1066+
sublayout2->setPosition(Vec2(widgetSize.width / 8.0f + widgetSize.width / 16.0f, widgetSize.height / 6.0f ));
1067+
sublayout2->setAnchorPoint(Vec2(0.5, 0.5));
1068+
sublayout2->runAction(RepeatForever::create(Sequence::createWithTwoActions(MoveBy::create(2, Vec2(-widgetSize.width/8, 0)), MoveBy::create(2, Vec2(widgetSize.width/8, 0)))));
1069+
layout2->addChild(sublayout2);
1070+
1071+
return true;
1072+
}
1073+
return false;
1074+
}

tests/cpp-tests/Classes/UITest/CocoStudioGUITest/UILayoutTest/UILayoutTest.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,4 +170,12 @@ class UILayoutTest_Issue19890 : public UIScene
170170
CREATE_FUNC(UILayoutTest_Issue19890);
171171
};
172172

173+
class UILayout_Clipping_Test : public UILayoutComponentTest
174+
{
175+
public:
176+
virtual bool init() override;
177+
178+
CREATE_FUNC(UILayout_Clipping_Test);
179+
};
180+
173181
#endif /* defined(__TestCpp__UILayoutTest__) */

0 commit comments

Comments
 (0)