Skip to content

Commit f17c444

Browse files
committed
Update touchingClones() to be closer to Scratch
* clamp bounds to the stage * snap bounds to int
1 parent e895cd3 commit f17c444

File tree

3 files changed

+120
-10
lines changed

3 files changed

+120
-10
lines changed

src/renderedtarget.cpp

+40-4
Original file line numberDiff line numberDiff line change
@@ -605,8 +605,11 @@ bool RenderedTarget::touchingClones(const std::vector<libscratchcpp::Sprite *> &
605605
{
606606
// https://github.com/scratchfoundation/scratch-render/blob/941562438fe3dd6e7d98d9387607d535dcd68d24/src/RenderWebGL.js#L967-L1002
607607
// TODO: Use Rect methods and do not use QRects
608-
Rect scratchRect = getFastBounds();
609-
const QRectF myRect(QPointF(scratchRect.left(), scratchRect.bottom()), QPointF(scratchRect.right(), scratchRect.top()));
608+
const QRectF myRect = touchingBounds();
609+
610+
if (myRect.isEmpty())
611+
return false;
612+
610613
QRectF united;
611614
std::vector<IRenderedTarget *> candidates;
612615

@@ -624,8 +627,9 @@ bool RenderedTarget::touchingClones(const std::vector<libscratchcpp::Sprite *> &
624627
// Calculate the intersection of the bounding rectangles
625628
IRenderedTarget *candidate = model->renderedTarget();
626629
Q_ASSERT(candidate);
627-
scratchRect = candidate->getFastBounds();
628-
QRectF rect(QPointF(scratchRect.left(), scratchRect.bottom()), QPointF(scratchRect.right(), scratchRect.top()));
630+
Rect scratchRect = candidate->getFastBounds();
631+
// TODO: Use Rect::snapToInt()
632+
QRect rect(QPoint(scratchRect.left(), scratchRect.bottom()), QPoint(scratchRect.right(), scratchRect.top()));
629633
QRectF intersected = myRect.intersected(rect);
630634

631635
// Add it to the union
@@ -791,6 +795,38 @@ CpuTextureManager *RenderedTarget::textureManager()
791795
return m_textureManager.get();
792796
}
793797

798+
QRectF RenderedTarget::touchingBounds() const
799+
{
800+
// https://github.com/scratchfoundation/scratch-render/blob/0a04c2fb165f5c20406ec34ab2ea5682ae45d6e0/src/RenderWebGL.js#L1330-L1350
801+
if (!m_engine)
802+
return QRectF();
803+
804+
Rect scratchBounds = getFastBounds();
805+
806+
// Limit queries to the stage size
807+
const double stageWidth = m_engine->stageWidth();
808+
const double stageHeight = m_engine->stageHeight();
809+
clampRect(scratchBounds, -stageWidth / 2, stageWidth / 2, -stageHeight / 2, stageHeight / 2);
810+
811+
// TODO: Use Rect::snapToInt()
812+
QRect bounds(QPoint(scratchBounds.left(), scratchBounds.bottom()), QPoint(scratchBounds.right(), scratchBounds.top()));
813+
return bounds;
814+
}
815+
816+
void RenderedTarget::clampRect(Rect &rect, double left, double right, double bottom, double top)
817+
{
818+
// TODO: Use Rect::clamp()
819+
rect.setLeft(std::max(rect.left(), left));
820+
rect.setRight(std::min(rect.right(), right));
821+
rect.setBottom(std::max(rect.bottom(), bottom));
822+
rect.setTop(std::min(rect.top(), top));
823+
824+
rect.setLeft(std::min(rect.left(), right));
825+
rect.setRight(std::max(rect.right(), left));
826+
rect.setBottom(std::min(rect.bottom(), top));
827+
rect.setTop(std::max(rect.top(), bottom));
828+
}
829+
794830
bool RenderedTarget::mirrorHorizontally() const
795831
{
796832
return m_mirrorHorizontally;

src/renderedtarget.h

+2
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ class RenderedTarget : public IRenderedTarget
122122
QPointF transformPoint(double scratchX, double scratchY, double originX, double originY, double sinRot, double cosRot) const;
123123
QPointF mapFromStageWithOriginPoint(const QPointF &scenePoint) const;
124124
CpuTextureManager *textureManager();
125+
QRectF touchingBounds() const;
126+
static void clampRect(libscratchcpp::Rect &rect, double left, double right, double bottom, double top);
125127

126128
libscratchcpp::IEngine *m_engine = nullptr;
127129
libscratchcpp::Costume *m_costume = nullptr;

test/renderedtarget/renderedtarget_test.cpp

+78-6
Original file line numberDiff line numberDiff line change
@@ -836,7 +836,7 @@ TEST_F(RenderedTargetTest, TouchingClones)
836836
target.setHeight(3);
837837

838838
EXPECT_CALL(target1, getFastBounds()).WillOnce(Return(Rect(2, 1, 6, -5)));
839-
EXPECT_CALL(target2, getFastBounds()).WillOnce(Return(Rect(-5, -1, 1.8, -8)));
839+
EXPECT_CALL(target2, getFastBounds()).WillOnce(Return(Rect(-5, -1, 1, -8)));
840840
EXPECT_CALL(target1, containsScratchPoint(1, -3)).WillOnce(Return(false));
841841
EXPECT_CALL(target2, containsScratchPoint(1, -3)).WillOnce(Return(false));
842842
EXPECT_CALL(target1, containsScratchPoint(2, -3)).WillOnce(Return(false));
@@ -856,30 +856,46 @@ TEST_F(RenderedTargetTest, TouchingClones)
856856
ASSERT_FALSE(target.touchingClones({ &clone1, &clone2 }));
857857

858858
EXPECT_CALL(target1, getFastBounds()).WillOnce(Return(Rect(2, 1, 6, -5)));
859-
EXPECT_CALL(target2, getFastBounds()).WillOnce(Return(Rect(-5, -1, 1.8, -8)));
859+
EXPECT_CALL(target2, getFastBounds()).WillOnce(Return(Rect(-5, -1, 1, -8)));
860860
EXPECT_CALL(target1, containsScratchPoint(1, -3)).WillOnce(Return(false));
861861
EXPECT_CALL(target2, containsScratchPoint(1, -3)).WillOnce(Return(false));
862862
EXPECT_CALL(target1, containsScratchPoint(2, -3)).WillOnce(Return(true));
863863
ASSERT_TRUE(target.touchingClones({ &clone1, &clone2 }));
864864

865865
EXPECT_CALL(target1, getFastBounds()).WillOnce(Return(Rect(5, 1, 6, -5)));
866-
EXPECT_CALL(target2, getFastBounds()).WillOnce(Return(Rect(-5, -1, 1.8, -8)));
866+
EXPECT_CALL(target2, getFastBounds()).WillOnce(Return(Rect(-5, -1, 2, -8)));
867867
EXPECT_CALL(target1, containsScratchPoint(1, -3)).WillOnce(Return(false));
868868
EXPECT_CALL(target2, containsScratchPoint(1, -3)).WillOnce(Return(false));
869+
EXPECT_CALL(target1, containsScratchPoint(2, -3)).WillOnce(Return(false));
870+
EXPECT_CALL(target2, containsScratchPoint(2, -3)).WillOnce(Return(false));
871+
EXPECT_CALL(target1, containsScratchPoint(3, -3)).WillOnce(Return(false));
872+
EXPECT_CALL(target2, containsScratchPoint(3, -3)).WillOnce(Return(false));
869873
EXPECT_CALL(target1, containsScratchPoint(1, -2)).WillOnce(Return(false));
870874
EXPECT_CALL(target2, containsScratchPoint(1, -2)).WillOnce(Return(false));
875+
EXPECT_CALL(target1, containsScratchPoint(3, -2)).WillOnce(Return(false));
876+
EXPECT_CALL(target2, containsScratchPoint(3, -2)).WillOnce(Return(false));
871877
EXPECT_CALL(target1, containsScratchPoint(1, -1)).WillOnce(Return(false));
872878
EXPECT_CALL(target2, containsScratchPoint(1, -1)).WillOnce(Return(false));
879+
EXPECT_CALL(target1, containsScratchPoint(2, -1)).WillOnce(Return(false));
880+
EXPECT_CALL(target2, containsScratchPoint(2, -1)).WillOnce(Return(false));
881+
EXPECT_CALL(target1, containsScratchPoint(3, -1)).WillOnce(Return(false));
882+
EXPECT_CALL(target2, containsScratchPoint(3, -1)).WillOnce(Return(false));
873883
ASSERT_FALSE(target.touchingClones({ &clone1, &clone2 }));
874884

875885
EXPECT_CALL(target1, getFastBounds()).WillOnce(Return(Rect(2, 1, 6, -5)));
876-
EXPECT_CALL(target2, getFastBounds()).WillOnce(Return(Rect(-5, -6.5, 1.8, -8)));
886+
EXPECT_CALL(target2, getFastBounds()).WillOnce(Return(Rect(-5, -6, 2, -8)));
887+
EXPECT_CALL(target1, containsScratchPoint(1, -3)).WillOnce(Return(false));
888+
EXPECT_CALL(target2, containsScratchPoint(1, -3)).WillOnce(Return(false));
877889
EXPECT_CALL(target1, containsScratchPoint(2, -3)).WillOnce(Return(false));
878890
EXPECT_CALL(target2, containsScratchPoint(2, -3)).WillOnce(Return(false));
879891
EXPECT_CALL(target1, containsScratchPoint(3, -3)).WillOnce(Return(false));
880892
EXPECT_CALL(target2, containsScratchPoint(3, -3)).WillOnce(Return(false));
893+
EXPECT_CALL(target1, containsScratchPoint(1, -2)).WillOnce(Return(false));
894+
EXPECT_CALL(target2, containsScratchPoint(1, -2)).WillOnce(Return(false));
881895
EXPECT_CALL(target1, containsScratchPoint(3, -2)).WillOnce(Return(false));
882896
EXPECT_CALL(target2, containsScratchPoint(3, -2)).WillOnce(Return(false));
897+
EXPECT_CALL(target1, containsScratchPoint(1, -1)).WillOnce(Return(false));
898+
EXPECT_CALL(target2, containsScratchPoint(1, -1)).WillOnce(Return(false));
883899
EXPECT_CALL(target1, containsScratchPoint(2, -1)).WillOnce(Return(false));
884900
EXPECT_CALL(target2, containsScratchPoint(2, -1)).WillOnce(Return(false));
885901
EXPECT_CALL(target1, containsScratchPoint(3, -1)).WillOnce(Return(false));
@@ -888,12 +904,68 @@ TEST_F(RenderedTargetTest, TouchingClones)
888904

889905
EXPECT_CALL(target1, getFastBounds()).WillOnce(Return(Rect(2, 1, 6, -5)));
890906
EXPECT_CALL(target2, getFastBounds()).WillOnce(Return(Rect(-5, -6.5, 1.8, -8)));
907+
EXPECT_CALL(target1, containsScratchPoint(1, -3)).WillOnce(Return(false));
908+
EXPECT_CALL(target2, containsScratchPoint(1, -3)).WillOnce(Return(false));
891909
EXPECT_CALL(target1, containsScratchPoint(2, -3)).WillOnce(Return(false));
892-
EXPECT_CALL(target2, containsScratchPoint(2, -3)).WillOnce(Return(true));
910+
EXPECT_CALL(target2, containsScratchPoint(2, -3)).WillOnce(Return(false));
911+
EXPECT_CALL(target1, containsScratchPoint(3, -3)).WillOnce(Return(false));
912+
EXPECT_CALL(target2, containsScratchPoint(3, -3)).WillOnce(Return(false));
913+
EXPECT_CALL(target1, containsScratchPoint(1, -2)).WillOnce(Return(false));
914+
EXPECT_CALL(target2, containsScratchPoint(1, -2)).WillOnce(Return(false));
915+
EXPECT_CALL(target1, containsScratchPoint(3, -2)).WillOnce(Return(false));
916+
EXPECT_CALL(target2, containsScratchPoint(3, -2)).WillOnce(Return(false));
917+
EXPECT_CALL(target1, containsScratchPoint(1, -1)).WillOnce(Return(false));
918+
EXPECT_CALL(target2, containsScratchPoint(1, -1)).WillOnce(Return(false));
919+
EXPECT_CALL(target1, containsScratchPoint(2, -1)).WillOnce(Return(false));
920+
EXPECT_CALL(target2, containsScratchPoint(2, -1)).WillOnce(Return(false));
921+
EXPECT_CALL(target1, containsScratchPoint(3, -1)).WillOnce(Return(false));
922+
EXPECT_CALL(target2, containsScratchPoint(3, -1)).WillOnce(Return(false));
923+
ASSERT_FALSE(target.touchingClones({ &clone1, &clone2 }));
924+
925+
EXPECT_CALL(target1, getFastBounds()).WillOnce(Return(Rect(2, 1, 6, -5)));
926+
EXPECT_CALL(target2, getFastBounds()).WillOnce(Return(Rect(-5, -6, 2, -8)));
927+
EXPECT_CALL(target1, containsScratchPoint(1, -3)).WillOnce(Return(false));
928+
EXPECT_CALL(target2, containsScratchPoint(1, -3)).WillOnce(Return(true));
893929
ASSERT_TRUE(target.touchingClones({ &clone1, &clone2 }));
894930

895931
EXPECT_CALL(target1, getFastBounds()).WillOnce(Return(Rect(5, 1, 6, -5)));
896-
EXPECT_CALL(target2, getFastBounds()).WillOnce(Return(Rect(-5, -6.5, 1.8, -8)));
932+
EXPECT_CALL(target2, getFastBounds()).WillOnce(Return(Rect(-5, -6, 2, -8)));
933+
EXPECT_CALL(target1, containsScratchPoint).Times(0);
934+
EXPECT_CALL(target2, containsScratchPoint).Times(0);
935+
ASSERT_FALSE(target.touchingClones({ &clone1, &clone2 }));
936+
937+
// Out of bounds: top left
938+
target.updateX(-300);
939+
target.updateY(200);
940+
EXPECT_CALL(target1, getFastBounds()).WillOnce(Return(Rect(2 - 300, 1 + 200, 6 - 300, -5 + 200)));
941+
EXPECT_CALL(target2, getFastBounds()).WillOnce(Return(Rect(-5 - 300, -6.5 + 200, 1.8 - 300, -8 + 200)));
942+
EXPECT_CALL(target1, containsScratchPoint).Times(0);
943+
EXPECT_CALL(target2, containsScratchPoint).Times(0);
944+
ASSERT_FALSE(target.touchingClones({ &clone1, &clone2 }));
945+
946+
// Out of bounds: top right
947+
target.updateX(300);
948+
target.updateY(200);
949+
EXPECT_CALL(target1, getFastBounds()).WillOnce(Return(Rect(2 + 300, 1 + 200, 6 + 300, -5 + 200)));
950+
EXPECT_CALL(target2, getFastBounds()).WillOnce(Return(Rect(-5 + 300, -6.5 + 200, 1.8 + 300, -8 + 200)));
951+
EXPECT_CALL(target1, containsScratchPoint).Times(0);
952+
EXPECT_CALL(target2, containsScratchPoint).Times(0);
953+
ASSERT_FALSE(target.touchingClones({ &clone1, &clone2 }));
954+
955+
// Out of bounds: bottom right
956+
target.updateX(300);
957+
target.updateY(-200);
958+
EXPECT_CALL(target1, getFastBounds()).WillOnce(Return(Rect(2 + 300, 1 - 200, 6 + 300, -5 - 200)));
959+
EXPECT_CALL(target2, getFastBounds()).WillOnce(Return(Rect(-5 + 300, -6.5 - 200, 1.8 + 300, -8 - 200)));
960+
EXPECT_CALL(target1, containsScratchPoint).Times(0);
961+
EXPECT_CALL(target2, containsScratchPoint).Times(0);
962+
ASSERT_FALSE(target.touchingClones({ &clone1, &clone2 }));
963+
964+
// Out of bounds: bottom left
965+
target.updateX(-300);
966+
target.updateY(-200);
967+
EXPECT_CALL(target1, getFastBounds()).WillOnce(Return(Rect(2 - 300, 1 - 200, 6 - 300, -5 - 200)));
968+
EXPECT_CALL(target2, getFastBounds()).WillOnce(Return(Rect(-5 - 300, -6.5 - 200, 1.8 - 300, -8 - 200)));
897969
EXPECT_CALL(target1, containsScratchPoint).Times(0);
898970
EXPECT_CALL(target2, containsScratchPoint).Times(0);
899971
ASSERT_FALSE(target.touchingClones({ &clone1, &clone2 }));

0 commit comments

Comments
 (0)