Skip to content

Commit d78c6b4

Browse files
committed
Add getFastBounds() method to RenderedTarget
1 parent affa08f commit d78c6b4

File tree

5 files changed

+108
-0
lines changed

5 files changed

+108
-0
lines changed

src/irenderedtarget.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class IRenderedTarget : public QNanoQuickItem
7171

7272
virtual libscratchcpp::Rect getBounds() const = 0;
7373
virtual QRectF getBoundsForBubble() const = 0;
74+
virtual libscratchcpp::Rect getFastBounds() const = 0;
7475

7576
virtual QPointF mapFromScene(const QPointF &point) const = 0;
7677

src/renderedtarget.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,39 @@ QRectF RenderedTarget::getBoundsForBubble() const
383383
return QRectF(QPointF(rect.left(), rect.top()), QPointF(rect.right(), rect.bottom()));
384384
}
385385

386+
Rect RenderedTarget::getFastBounds() const
387+
{
388+
if (!m_costume || !m_skin || !m_texture.isValid())
389+
return Rect(m_x, m_y, m_x, m_y);
390+
391+
const double scale = this->scale();
392+
const double width = this->width() / m_stageScale;
393+
const double height = this->height() / m_stageScale;
394+
const double originX = m_costume->rotationCenterX() * m_size / scale / m_costume->bitmapResolution() - width / 2;
395+
const double originY = -m_costume->rotationCenterY() * m_size / scale / m_costume->bitmapResolution() + height / 2;
396+
const double rot = -rotation() * pi / 180;
397+
398+
QPointF topLeft = transformPoint(-width / 2, height / 2, originX, originY, rot);
399+
QPointF topRight = transformPoint(width / 2, height / 2, originX, originY, rot);
400+
QPointF bottomRight = transformPoint(width / 2, -height / 2, originX, originY, rot);
401+
QPointF bottomLeft = transformPoint(-width / 2, -height / 2, originX, originY, rot);
402+
403+
if (m_mirrorHorizontally) {
404+
topLeft.setX(-topLeft.x());
405+
topRight.setX(-topRight.x());
406+
bottomRight.setX(-bottomRight.x());
407+
bottomLeft.setX(-bottomLeft.x());
408+
}
409+
const auto xList = { topLeft.x(), topRight.x(), bottomRight.x(), bottomLeft.x() };
410+
const auto yList = { topLeft.y(), topRight.y(), bottomRight.y(), bottomLeft.y() };
411+
const double minX = std::min(xList);
412+
const double maxX = std::max(xList);
413+
const double minY = std::min(yList);
414+
const double maxY = std::max(yList);
415+
416+
return Rect(minX * scale + m_x, maxY * scale + m_y, maxX * scale + m_x, minY * scale + m_y);
417+
}
418+
386419
QPointF RenderedTarget::mapFromScene(const QPointF &point) const
387420
{
388421
return QNanoQuickItem::mapFromScene(point);

src/renderedtarget.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class RenderedTarget : public IRenderedTarget
7676

7777
libscratchcpp::Rect getBounds() const override;
7878
Q_INVOKABLE QRectF getBoundsForBubble() const override;
79+
libscratchcpp::Rect getFastBounds() const override;
7980

8081
QPointF mapFromScene(const QPointF &point) const override;
8182

test/mocks/renderedtargetmock.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class RenderedTargetMock : public IRenderedTarget
5656
MOCK_METHOD(QPointF, mapFromScene, (const QPointF &), (const, override));
5757

5858
MOCK_METHOD(libscratchcpp::Rect, getBounds, (), (const, override));
59+
MOCK_METHOD(libscratchcpp::Rect, getFastBounds, (), (const, override));
5960
MOCK_METHOD(QRectF, getBoundsForBubble, (), (const, override));
6061

6162
MOCK_METHOD(bool, mirrorHorizontally, (), (const, override));

test/renderedtarget/renderedtarget_test.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,3 +740,75 @@ TEST_F(RenderedTargetTest, GetBounds)
740740

741741
context.doneCurrent();
742742
}
743+
744+
TEST_F(RenderedTargetTest, GetFastBounds)
745+
{
746+
QOpenGLContext context;
747+
QOffscreenSurface surface;
748+
createContextAndSurface(&context, &surface);
749+
QOpenGLExtraFunctions glF(&context);
750+
glF.initializeOpenGLFunctions();
751+
RenderedTarget target;
752+
753+
Sprite sprite;
754+
sprite.setX(75.64);
755+
sprite.setY(-120.3);
756+
sprite.setDirection(-46.37);
757+
sprite.setSize(67.98);
758+
SpriteModel spriteModel;
759+
sprite.setInterface(&spriteModel);
760+
target.setSpriteModel(&spriteModel);
761+
EngineMock engine;
762+
target.setEngine(&engine);
763+
auto costume = std::make_shared<Costume>("", "", "png");
764+
std::string costumeData = readFileStr("image.png");
765+
costume->setData(costumeData.size(), static_cast<void *>(costumeData.data()));
766+
costume->setRotationCenterX(-15);
767+
costume->setRotationCenterY(48);
768+
costume->setBitmapResolution(3.25);
769+
sprite.addCostume(costume);
770+
771+
EXPECT_CALL(engine, stageWidth()).WillOnce(Return(480));
772+
EXPECT_CALL(engine, stageHeight()).WillOnce(Return(360));
773+
target.loadCostumes();
774+
target.updateCostume(costume.get());
775+
target.beforeRedraw();
776+
777+
Rect bounds = target.getFastBounds();
778+
ASSERT_EQ(std::round(bounds.left() * 100) / 100, 65.84);
779+
ASSERT_EQ(std::round(bounds.top() * 100) / 100, -123.92);
780+
ASSERT_EQ(std::round(bounds.right() * 100) / 100, 67.31);
781+
ASSERT_EQ(std::round(bounds.bottom() * 100) / 100, -125.4);
782+
783+
EXPECT_CALL(engine, stageWidth()).WillOnce(Return(480));
784+
EXPECT_CALL(engine, stageHeight()).WillOnce(Return(360));
785+
target.updateRotationStyle(Sprite::RotationStyle::LeftRight);
786+
787+
bounds = target.getFastBounds();
788+
ASSERT_EQ(std::round(bounds.left() * 100) / 100, 71.67);
789+
ASSERT_EQ(std::round(bounds.top() * 100) / 100, -110.26);
790+
ASSERT_EQ(std::round(bounds.right() * 100) / 100, 72.5);
791+
ASSERT_EQ(std::round(bounds.bottom() * 100) / 100, -111.51);
792+
793+
EXPECT_CALL(engine, stageWidth()).WillOnce(Return(480));
794+
EXPECT_CALL(engine, stageHeight()).WillOnce(Return(360));
795+
target.setStageScale(20.75);
796+
797+
bounds = target.getFastBounds();
798+
ASSERT_EQ(std::round(bounds.left() * 100) / 100, 71.67);
799+
ASSERT_EQ(std::round(bounds.top() * 100) / 100, -110.26);
800+
ASSERT_EQ(std::round(bounds.right() * 100) / 100, 72.5);
801+
ASSERT_EQ(std::round(bounds.bottom() * 100) / 100, -111.51);
802+
803+
EXPECT_CALL(engine, stageWidth()).WillOnce(Return(480));
804+
EXPECT_CALL(engine, stageHeight()).WillOnce(Return(360));
805+
target.updateSize(9780.6);
806+
807+
bounds = target.getFastBounds();
808+
ASSERT_EQ(std::round(bounds.left() * 100) / 100, -496.15);
809+
ASSERT_EQ(std::round(bounds.top() * 100) / 100, 1324.22);
810+
ASSERT_EQ(std::round(bounds.right() * 100) / 100, -375.77);
811+
ASSERT_EQ(std::round(bounds.bottom() * 100) / 100, 1443.65);
812+
813+
context.doneCurrent();
814+
}

0 commit comments

Comments
 (0)