From 798ddfe5f2498939693fc3f70c65d3b9d5775389 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Mon, 22 Jan 2024 23:32:11 +0100 Subject: [PATCH 1/9] Add PenBlocks class --- src/CMakeLists.txt | 2 ++ src/blocks/penblocks.cpp | 15 ++++++++++++ src/blocks/penblocks.h | 22 +++++++++++++++++ test/CMakeLists.txt | 1 + test/blocks/CMakeLists.txt | 17 +++++++++++++ test/blocks/pen_blocks_test.cpp | 42 +++++++++++++++++++++++++++++++++ 6 files changed, 99 insertions(+) create mode 100644 src/blocks/penblocks.cpp create mode 100644 src/blocks/penblocks.h create mode 100644 test/blocks/CMakeLists.txt create mode 100644 test/blocks/pen_blocks_test.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d2b4c85..ce73e2b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -55,6 +55,8 @@ qt_add_qml_module(scratchcpp-render penlayerpainter.cpp penlayerpainter.h penattributes.h + blocks/penblocks.cpp + blocks/penblocks.h ) list(APPEND QML_IMPORT_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/src/blocks/penblocks.cpp b/src/blocks/penblocks.cpp new file mode 100644 index 0000000..355b8bb --- /dev/null +++ b/src/blocks/penblocks.cpp @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "penblocks.h" + +using namespace scratchcpprender; +using namespace libscratchcpp; + +std::string PenBlocks::name() const +{ + return "Pen"; +} + +void PenBlocks::registerBlocks(IEngine *engine) +{ +} diff --git a/src/blocks/penblocks.h b/src/blocks/penblocks.h new file mode 100644 index 0000000..5026add --- /dev/null +++ b/src/blocks/penblocks.h @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later + +#pragma once + +#include + +namespace scratchcpprender +{ + +class PenBlocks : public libscratchcpp::IBlockSection +{ + public: + enum Inputs + { + }; + + std::string name() const override; + + void registerBlocks(libscratchcpp::IEngine *engine) override; +}; + +} // namespace scratchcpprender diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0dbcc55..85eaac7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -34,3 +34,4 @@ add_subdirectory(skins) add_subdirectory(penattributes) add_subdirectory(penlayer) add_subdirectory(penlayerpainter) +add_subdirectory(blocks) diff --git a/test/blocks/CMakeLists.txt b/test/blocks/CMakeLists.txt new file mode 100644 index 0000000..b3b8888 --- /dev/null +++ b/test/blocks/CMakeLists.txt @@ -0,0 +1,17 @@ +# pen_blocks_test +add_executable( + pen_blocks_test + pen_blocks_test.cpp +) + +target_link_libraries( + pen_blocks_test + GTest::gtest_main + GTest::gmock_main + scratchcpp-render + scratchcpprender_mocks + ${QT_LIBS} +) + +add_test(pen_blocks_test) +gtest_discover_tests(pen_blocks_test) diff --git a/test/blocks/pen_blocks_test.cpp b/test/blocks/pen_blocks_test.cpp new file mode 100644 index 0000000..e39e4fc --- /dev/null +++ b/test/blocks/pen_blocks_test.cpp @@ -0,0 +1,42 @@ +#include +#include +#include +#include +#include + +#include "../common.h" + +using namespace scratchcpprender; +using namespace libscratchcpp; + +class PenBlocksTest : public testing::Test +{ + public: + void SetUp() override { m_section = std::make_unique(); } + + void addValueInput(std::shared_ptr block, const std::string &name, PenBlocks::Inputs id, const Value &value) const + { + auto input = std::make_shared(name, Input::Type::Shadow); + input->setPrimaryValue(value); + input->setInputId(id); + block->addInput(input); + } + + std::unique_ptr m_section; + EngineMock m_engineMock; +}; + +TEST_F(PenBlocksTest, Name) +{ + ASSERT_EQ(m_section->name(), "Pen"); +} + +TEST_F(PenBlocksTest, CategoryVisible) +{ + ASSERT_TRUE(m_section->categoryVisible()); +} + +TEST_F(PenBlocksTest, RegisterBlocks) +{ + m_section->registerBlocks(&m_engineMock); +} From 16050342fb0e82dc52f99837eec83041b25e598c Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Mon, 22 Jan 2024 23:50:29 +0100 Subject: [PATCH 2/9] Add PenExtension class --- src/CMakeLists.txt | 2 ++ src/blocks/penextension.cpp | 24 +++++++++++++++++++ src/blocks/penextension.h | 19 +++++++++++++++ test/blocks/CMakeLists.txt | 18 ++++++++++++++ test/blocks/penextension_test.cpp | 39 +++++++++++++++++++++++++++++++ 5 files changed, 102 insertions(+) create mode 100644 src/blocks/penextension.cpp create mode 100644 src/blocks/penextension.h create mode 100644 test/blocks/penextension_test.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ce73e2b..946a1f7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -55,6 +55,8 @@ qt_add_qml_module(scratchcpp-render penlayerpainter.cpp penlayerpainter.h penattributes.h + blocks/penextension.cpp + blocks/penextension.h blocks/penblocks.cpp blocks/penblocks.h ) diff --git a/src/blocks/penextension.cpp b/src/blocks/penextension.cpp new file mode 100644 index 0000000..1226d08 --- /dev/null +++ b/src/blocks/penextension.cpp @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include + +#include "penextension.h" +#include "penblocks.h" + +using namespace scratchcpprender; +using namespace libscratchcpp; + +std::string PenExtension::name() const +{ + return "pen"; +} + +std::string PenExtension::description() const +{ + return "Pen extension"; +} + +void PenExtension::registerSections(IEngine *engine) +{ + engine->registerSection(std::make_shared()); +} diff --git a/src/blocks/penextension.h b/src/blocks/penextension.h new file mode 100644 index 0000000..1e7363d --- /dev/null +++ b/src/blocks/penextension.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later + +#pragma once + +#include + +namespace scratchcpprender +{ + +class PenExtension : public libscratchcpp::IExtension +{ + public: + std::string name() const override; + std::string description() const override; + + void registerSections(libscratchcpp::IEngine *engine) override; +}; + +} // namespace scratchcpprender diff --git a/test/blocks/CMakeLists.txt b/test/blocks/CMakeLists.txt index b3b8888..6d6151d 100644 --- a/test/blocks/CMakeLists.txt +++ b/test/blocks/CMakeLists.txt @@ -15,3 +15,21 @@ target_link_libraries( add_test(pen_blocks_test) gtest_discover_tests(pen_blocks_test) + +# penextension_test +add_executable( + penextension_test + penextension_test.cpp +) + +target_link_libraries( + penextension_test + GTest::gtest_main + GTest::gmock_main + scratchcpp-render + scratchcpprender_mocks + ${QT_LIBS} +) + +add_test(penextension_test) +gtest_discover_tests(penextension_test) diff --git a/test/blocks/penextension_test.cpp b/test/blocks/penextension_test.cpp new file mode 100644 index 0000000..009a497 --- /dev/null +++ b/test/blocks/penextension_test.cpp @@ -0,0 +1,39 @@ +#include +#include +#include + +#include "../common.h" + +using namespace scratchcpprender; +using namespace libscratchcpp; + +using ::testing::WithArgs; +using ::testing::Invoke; +using ::testing::_; + +TEST(PenExtensionTest, Name) +{ + PenExtension ext; + ASSERT_EQ(ext.name(), "pen"); +} + +TEST(PenExtensionTest, Description) +{ + PenExtension ext; + ASSERT_EQ(ext.description(), "Pen extension"); +} + +TEST(PenExtensionTest, IncludeByDefault) +{ + PenExtension ext; + ASSERT_FALSE(ext.includeByDefault()); +} + +TEST(PenExtensionTest, RegisterSections) +{ + PenExtension ext; + EngineMock engine; + + EXPECT_CALL(engine, registerSection(_)).WillOnce(WithArgs<0>(Invoke([](std::shared_ptr section) { ASSERT_TRUE(dynamic_cast(section.get())); }))); + ext.registerSections(&engine); +} From 38955d4a548633963b04fa47295c84178cd9187a Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Mon, 22 Jan 2024 23:53:17 +0100 Subject: [PATCH 3/9] Register the pen extension --- src/projectloader.cpp | 5 +++++ test/projectloader/projectloader_test.cpp | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/projectloader.cpp b/src/projectloader.cpp index fe700ec..c9d9b96 100644 --- a/src/projectloader.cpp +++ b/src/projectloader.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -11,6 +12,7 @@ #include "valuemonitormodel.h" #include "listmonitormodel.h" #include "renderedtarget.h" +#include "blocks/penextension.h" using namespace scratchcpprender; using namespace libscratchcpp; @@ -31,6 +33,9 @@ ProjectLoader::ProjectLoader(QObject *parent) : }); initTimer(); + + // Register pen blocks + ScratchConfiguration::registerExtension(std::make_shared()); } ProjectLoader::~ProjectLoader() diff --git a/test/projectloader/projectloader_test.cpp b/test/projectloader/projectloader_test.cpp index 84adb5c..47420f6 100644 --- a/test/projectloader/projectloader_test.cpp +++ b/test/projectloader/projectloader_test.cpp @@ -1,8 +1,10 @@ #include +#include #include #include #include #include +#include #include #include @@ -62,6 +64,9 @@ TEST_F(ProjectLoaderTest, Constructors) ProjectLoader loader1; ProjectLoader loader2(&loader1); ASSERT_EQ(loader2.parent(), &loader1); + + // Pen extension should be registered + ASSERT_TRUE(dynamic_cast(ScratchConfiguration::getExtension("pen"))); } TEST_F(ProjectLoaderTest, Load) From a4de1d0ef2ef46db4e7f85f8c224ad4388d2f943 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Tue, 23 Jan 2024 00:00:33 +0100 Subject: [PATCH 4/9] Request redraw on pen operations --- src/spritemodel.cpp | 18 +++++++++++++----- test/target_models/spritemodel_test.cpp | 16 +++++++++++++++- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/spritemodel.cpp b/src/spritemodel.cpp index 95a0f8a..a443f99 100644 --- a/src/spritemodel.cpp +++ b/src/spritemodel.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "spritemodel.h" #include "renderedtarget.h" @@ -65,8 +66,13 @@ void SpriteModel::onYChanged(double y) void SpriteModel::onMoved(double oldX, double oldY, double newX, double newY) { - if (m_penDown && m_penLayer) + if (m_penDown && m_penLayer) { m_penLayer->drawLine(m_penAttributes, oldX, oldY, newX, newY); + libscratchcpp::IEngine *engine = m_sprite->engine(); + + if (engine) + engine->requestRedraw(); + } } void SpriteModel::onSizeChanged(double size) @@ -151,13 +157,15 @@ bool SpriteModel::penDown() const void SpriteModel::setPenDown(bool newPenDown) { - if (m_penDown == newPenDown) - return; - m_penDown = newPenDown; - if (m_penDown && m_penLayer && m_sprite) + if (m_penDown && m_penLayer && m_sprite) { m_penLayer->drawPoint(m_penAttributes, m_sprite->x(), m_sprite->y()); + libscratchcpp::IEngine *engine = m_sprite->engine(); + + if (engine) + engine->requestRedraw(); + } } SpriteModel *SpriteModel::cloneRoot() const diff --git a/test/target_models/spritemodel_test.cpp b/test/target_models/spritemodel_test.cpp index 819aa7e..7d932cd 100644 --- a/test/target_models/spritemodel_test.cpp +++ b/test/target_models/spritemodel_test.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "../common.h" @@ -149,17 +150,25 @@ TEST(SpriteModelTest, OnYChanged) TEST(SpriteModelTest, OnMoved) { SpriteModel model; + Sprite sprite; + EngineMock engine; + sprite.setEngine(&engine); + model.init(&sprite); PenLayerMock penLayer; model.setPenLayer(&penLayer); EXPECT_CALL(penLayer, drawLine).Times(0); + EXPECT_CALL(engine, requestRedraw).Times(0); model.onMoved(-15.6, 54.9, 159.04, -2.5); + EXPECT_CALL(penLayer, drawPoint); + EXPECT_CALL(engine, requestRedraw); model.setPenDown(true); PenAttributes &attr = model.penAttributes(); EXPECT_CALL(penLayer, drawLine(_, -15.6, 54.9, 159.04, -2.5)).WillOnce(WithArgs<0>(Invoke([&attr](const PenAttributes &attrArg) { ASSERT_EQ(&attr, &attrArg); }))); + EXPECT_CALL(engine, requestRedraw()); model.onMoved(-15.6, 54.9, 159.04, -2.5); } @@ -253,8 +262,10 @@ TEST(SpriteModelTest, PenDown) { SpriteModel model; Sprite sprite; + EngineMock engine; sprite.setX(24.6); sprite.setY(-48.8); + sprite.setEngine(&engine); model.init(&sprite); ASSERT_FALSE(model.penDown()); @@ -264,14 +275,17 @@ TEST(SpriteModelTest, PenDown) PenAttributes &attr = model.penAttributes(); EXPECT_CALL(penLayer, drawPoint(_, 24.6, -48.8)).WillOnce(WithArgs<0>(Invoke([&attr](const PenAttributes &attrArg) { ASSERT_EQ(&attr, &attrArg); }))); + EXPECT_CALL(engine, requestRedraw()); model.setPenDown(true); ASSERT_TRUE(model.penDown()); - EXPECT_CALL(penLayer, drawPoint).Times(0); + EXPECT_CALL(penLayer, drawPoint(_, 24.6, -48.8)); + EXPECT_CALL(engine, requestRedraw()); model.setPenDown(true); ASSERT_TRUE(model.penDown()); EXPECT_CALL(penLayer, drawPoint).Times(0); + EXPECT_CALL(engine, requestRedraw).Times(0); model.setPenDown(false); ASSERT_FALSE(model.penDown()); } From de4e9384df8448e7606fb77ef03f5425ba40eaf0 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Tue, 23 Jan 2024 00:09:52 +0100 Subject: [PATCH 5/9] PenLayer: Allow setting engine without OpenGL context --- src/penlayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/penlayer.cpp b/src/penlayer.cpp index 0c559e7..09f7938 100644 --- a/src/penlayer.cpp +++ b/src/penlayer.cpp @@ -47,7 +47,7 @@ void PenLayer::setEngine(libscratchcpp::IEngine *newEngine) m_engine = newEngine; - if (m_engine) { + if (m_engine && QOpenGLContext::currentContext()) { m_projectPenLayers[m_engine] = this; m_fbo = std::make_unique(m_engine->stageWidth(), m_engine->stageHeight(), m_fboFormat); Q_ASSERT(m_fbo->isValid()); From 0484ed3a7e4da3d9c033288524033ed3c6917ef8 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Tue, 23 Jan 2024 00:13:13 +0100 Subject: [PATCH 6/9] Add addPenLayer() method to PenLayer --- src/penlayer.cpp | 5 +++++ src/penlayer.h | 1 + test/penlayer/penlayer_test.cpp | 22 +++++++++++++--------- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/penlayer.cpp b/src/penlayer.cpp index 09f7938..2809806 100644 --- a/src/penlayer.cpp +++ b/src/penlayer.cpp @@ -134,6 +134,11 @@ IPenLayer *PenLayer::getProjectPenLayer(libscratchcpp::IEngine *engine) return nullptr; } +void PenLayer::addPenLayer(libscratchcpp::IEngine *engine, IPenLayer *penLayer) +{ + m_projectPenLayers[engine] = penLayer; +} + QNanoQuickItemPainter *PenLayer::createItemPainter() const { return new PenLayerPainter; diff --git a/src/penlayer.h b/src/penlayer.h index fc88ae2..7a98a0b 100644 --- a/src/penlayer.h +++ b/src/penlayer.h @@ -34,6 +34,7 @@ class PenLayer : public IPenLayer QOpenGLFramebufferObject *framebufferObject() const override; static IPenLayer *getProjectPenLayer(libscratchcpp::IEngine *engine); + static void addPenLayer(libscratchcpp::IEngine *engine, IPenLayer *penLayer); // for tests signals: void engineChanged(); diff --git a/test/penlayer/penlayer_test.cpp b/test/penlayer/penlayer_test.cpp index 90beb67..539a7e8 100644 --- a/test/penlayer/penlayer_test.cpp +++ b/test/penlayer/penlayer_test.cpp @@ -99,27 +99,31 @@ TEST_F(PenLayerTest, FramebufferObject) TEST_F(PenLayerTest, GetProjectPenLayer) { PenLayer penLayer; - ASSERT_EQ(penLayer.getProjectPenLayer(nullptr), nullptr); + ASSERT_EQ(PenLayer::getProjectPenLayer(nullptr), nullptr); EngineMock engine1, engine2; - ASSERT_EQ(penLayer.getProjectPenLayer(&engine1), nullptr); - ASSERT_EQ(penLayer.getProjectPenLayer(&engine2), nullptr); + ASSERT_EQ(PenLayer::getProjectPenLayer(&engine1), nullptr); + ASSERT_EQ(PenLayer::getProjectPenLayer(&engine2), nullptr); EXPECT_CALL(engine1, stageWidth()).WillOnce(Return(1)); EXPECT_CALL(engine1, stageHeight()).WillOnce(Return(1)); penLayer.setEngine(&engine1); - ASSERT_EQ(penLayer.getProjectPenLayer(&engine1), &penLayer); - ASSERT_EQ(penLayer.getProjectPenLayer(&engine2), nullptr); + ASSERT_EQ(PenLayer::getProjectPenLayer(&engine1), &penLayer); + ASSERT_EQ(PenLayer::getProjectPenLayer(&engine2), nullptr); EXPECT_CALL(engine2, stageWidth()).WillOnce(Return(1)); EXPECT_CALL(engine2, stageHeight()).WillOnce(Return(1)); penLayer.setEngine(&engine2); - ASSERT_EQ(penLayer.getProjectPenLayer(&engine1), nullptr); - ASSERT_EQ(penLayer.getProjectPenLayer(&engine2), &penLayer); + ASSERT_EQ(PenLayer::getProjectPenLayer(&engine1), nullptr); + ASSERT_EQ(PenLayer::getProjectPenLayer(&engine2), &penLayer); penLayer.setEngine(nullptr); - ASSERT_EQ(penLayer.getProjectPenLayer(&engine1), nullptr); - ASSERT_EQ(penLayer.getProjectPenLayer(&engine2), nullptr); + ASSERT_EQ(PenLayer::getProjectPenLayer(&engine1), nullptr); + ASSERT_EQ(PenLayer::getProjectPenLayer(&engine2), nullptr); + + PenLayer::addPenLayer(&engine1, &penLayer); + ASSERT_EQ(PenLayer::getProjectPenLayer(&engine1), &penLayer); + ASSERT_EQ(PenLayer::getProjectPenLayer(&engine2), nullptr); } TEST_F(PenLayerTest, Clear) From 004182775200ec15b5686108a88004a077a93872 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Tue, 23 Jan 2024 00:17:08 +0100 Subject: [PATCH 7/9] Implement pen_clear block --- src/blocks/penblocks.cpp | 24 ++++++++++++++++++ src/blocks/penblocks.h | 4 +++ test/blocks/pen_blocks_test.cpp | 44 +++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) diff --git a/src/blocks/penblocks.cpp b/src/blocks/penblocks.cpp index 355b8bb..a8be37f 100644 --- a/src/blocks/penblocks.cpp +++ b/src/blocks/penblocks.cpp @@ -1,6 +1,11 @@ // SPDX-License-Identifier: LGPL-3.0-or-later +#include +#include + #include "penblocks.h" +#include "penlayer.h" +#include "spritemodel.h" using namespace scratchcpprender; using namespace libscratchcpp; @@ -12,4 +17,23 @@ std::string PenBlocks::name() const void PenBlocks::registerBlocks(IEngine *engine) { + // Blocks + engine->addCompileFunction(this, "pen_clear", &compileClear); +} + +void PenBlocks::compileClear(Compiler *compiler) +{ + compiler->addFunctionCall(&clear); +} + +unsigned int PenBlocks::clear(VirtualMachine *vm) +{ + IPenLayer *penLayer = PenLayer::getProjectPenLayer(vm->engine()); + + if (penLayer) { + penLayer->clear(); + vm->engine()->requestRedraw(); + } + + return 0; } diff --git a/src/blocks/penblocks.h b/src/blocks/penblocks.h index 5026add..62c8438 100644 --- a/src/blocks/penblocks.h +++ b/src/blocks/penblocks.h @@ -17,6 +17,10 @@ class PenBlocks : public libscratchcpp::IBlockSection std::string name() const override; void registerBlocks(libscratchcpp::IEngine *engine) override; + + static void compileClear(libscratchcpp::Compiler *compiler); + + static unsigned int clear(libscratchcpp::VirtualMachine *vm); }; } // namespace scratchcpprender diff --git a/test/blocks/pen_blocks_test.cpp b/test/blocks/pen_blocks_test.cpp index e39e4fc..82f9e37 100644 --- a/test/blocks/pen_blocks_test.cpp +++ b/test/blocks/pen_blocks_test.cpp @@ -1,14 +1,18 @@ #include #include #include +#include #include #include +#include #include "../common.h" using namespace scratchcpprender; using namespace libscratchcpp; +using ::testing::Return; + class PenBlocksTest : public testing::Test { public: @@ -38,5 +42,45 @@ TEST_F(PenBlocksTest, CategoryVisible) TEST_F(PenBlocksTest, RegisterBlocks) { + // Blocks + EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "pen_clear", &PenBlocks::compileClear)); + m_section->registerBlocks(&m_engineMock); } + +TEST_F(PenBlocksTest, Clear) +{ + Compiler compiler(&m_engineMock); + + auto block = std::make_shared("a", "pen_clear"); + + EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::clear)).WillOnce(Return(2)); + compiler.init(); + compiler.setBlock(block); + PenBlocks::compileClear(&compiler); + compiler.end(); + + ASSERT_EQ(compiler.bytecode(), std::vector({ vm::OP_START, vm::OP_EXEC, 2, vm::OP_HALT })); + ASSERT_TRUE(compiler.constValues().empty()); + ASSERT_TRUE(compiler.variables().empty()); + ASSERT_TRUE(compiler.lists().empty()); +} + +TEST_F(PenBlocksTest, ClearImpl) +{ + static unsigned int bytecode[] = { vm::OP_START, vm::OP_EXEC, 0, vm::OP_HALT }; + static BlockFunc functions[] = { &PenBlocks::clear }; + + PenLayerMock penLayer; + PenLayer::addPenLayer(&m_engineMock, &penLayer); + + VirtualMachine vm(nullptr, &m_engineMock, nullptr); + vm.setBytecode(bytecode); + vm.setFunctions(functions); + + EXPECT_CALL(penLayer, clear()); + EXPECT_CALL(m_engineMock, requestRedraw()); + vm.run(); + + ASSERT_EQ(vm.registerCount(), 0); +} From acd44228a17a82ba8788964c7a87c2f27edb7010 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Tue, 23 Jan 2024 00:28:04 +0100 Subject: [PATCH 8/9] Implement pen_penDown block --- src/blocks/penblocks.cpp | 23 ++++++++++++++++++ src/blocks/penblocks.h | 2 ++ test/blocks/pen_blocks_test.cpp | 43 +++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/src/blocks/penblocks.cpp b/src/blocks/penblocks.cpp index a8be37f..ab44b1f 100644 --- a/src/blocks/penblocks.cpp +++ b/src/blocks/penblocks.cpp @@ -19,6 +19,7 @@ void PenBlocks::registerBlocks(IEngine *engine) { // Blocks engine->addCompileFunction(this, "pen_clear", &compileClear); + engine->addCompileFunction(this, "pen_penDown", &compilePenDown); } void PenBlocks::compileClear(Compiler *compiler) @@ -26,6 +27,11 @@ void PenBlocks::compileClear(Compiler *compiler) compiler->addFunctionCall(&clear); } +void PenBlocks::compilePenDown(Compiler *compiler) +{ + compiler->addFunctionCall(&penDown); +} + unsigned int PenBlocks::clear(VirtualMachine *vm) { IPenLayer *penLayer = PenLayer::getProjectPenLayer(vm->engine()); @@ -37,3 +43,20 @@ unsigned int PenBlocks::clear(VirtualMachine *vm) return 0; } + +unsigned int PenBlocks::penDown(VirtualMachine *vm) +{ + Target *target = vm->target(); + + if (!target || target->isStage()) + return 0; + + Sprite *sprite = static_cast(target); + SpriteModel *model = static_cast(sprite->getInterface()); + + if (model) + model->setPenDown(true); + + return 0; +} + diff --git a/src/blocks/penblocks.h b/src/blocks/penblocks.h index 62c8438..6d2f367 100644 --- a/src/blocks/penblocks.h +++ b/src/blocks/penblocks.h @@ -19,8 +19,10 @@ class PenBlocks : public libscratchcpp::IBlockSection void registerBlocks(libscratchcpp::IEngine *engine) override; static void compileClear(libscratchcpp::Compiler *compiler); + static void compilePenDown(libscratchcpp::Compiler *compiler); static unsigned int clear(libscratchcpp::VirtualMachine *vm); + static unsigned int penDown(libscratchcpp::VirtualMachine *vm); }; } // namespace scratchcpprender diff --git a/test/blocks/pen_blocks_test.cpp b/test/blocks/pen_blocks_test.cpp index 82f9e37..1320065 100644 --- a/test/blocks/pen_blocks_test.cpp +++ b/test/blocks/pen_blocks_test.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +45,7 @@ TEST_F(PenBlocksTest, RegisterBlocks) { // Blocks EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "pen_clear", &PenBlocks::compileClear)); + EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "pen_penDown", &PenBlocks::compilePenDown)); m_section->registerBlocks(&m_engineMock); } @@ -84,3 +86,44 @@ TEST_F(PenBlocksTest, ClearImpl) ASSERT_EQ(vm.registerCount(), 0); } + +TEST_F(PenBlocksTest, PenDown) +{ + Compiler compiler(&m_engineMock); + + auto block = std::make_shared("a", "pen_penDown"); + + EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::penDown)).WillOnce(Return(2)); + compiler.init(); + compiler.setBlock(block); + PenBlocks::compilePenDown(&compiler); + compiler.end(); + + ASSERT_EQ(compiler.bytecode(), std::vector({ vm::OP_START, vm::OP_EXEC, 2, vm::OP_HALT })); + ASSERT_TRUE(compiler.constValues().empty()); + ASSERT_TRUE(compiler.variables().empty()); + ASSERT_TRUE(compiler.lists().empty()); +} + +TEST_F(PenBlocksTest, PenDownImpl) +{ + static unsigned int bytecode[] = { vm::OP_START, vm::OP_EXEC, 0, vm::OP_HALT }; + static BlockFunc functions[] = { &PenBlocks::penDown }; + + SpriteModel model; + Sprite sprite; + sprite.setInterface(&model); + + VirtualMachine vm(&sprite, &m_engineMock, nullptr); + vm.setBytecode(bytecode); + vm.setFunctions(functions); + + vm.run(); + ASSERT_EQ(vm.registerCount(), 0); + ASSERT_TRUE(model.penDown()); + + vm.reset(); + vm.run(); + ASSERT_EQ(vm.registerCount(), 0); + ASSERT_TRUE(model.penDown()); +} From d53d1ef9189730cf8b08f146323d635d6122fb24 Mon Sep 17 00:00:00 2001 From: adazem009 <68537469+adazem009@users.noreply.github.com> Date: Tue, 23 Jan 2024 00:30:07 +0100 Subject: [PATCH 9/9] Implement pen_penUp block --- src/blocks/penblocks.cpp | 21 ++++++++++++++++ src/blocks/penblocks.h | 2 ++ test/blocks/pen_blocks_test.cpp | 43 +++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/src/blocks/penblocks.cpp b/src/blocks/penblocks.cpp index ab44b1f..e314b7d 100644 --- a/src/blocks/penblocks.cpp +++ b/src/blocks/penblocks.cpp @@ -20,6 +20,7 @@ void PenBlocks::registerBlocks(IEngine *engine) // Blocks engine->addCompileFunction(this, "pen_clear", &compileClear); engine->addCompileFunction(this, "pen_penDown", &compilePenDown); + engine->addCompileFunction(this, "pen_penUp", &compilePenUp); } void PenBlocks::compileClear(Compiler *compiler) @@ -32,6 +33,11 @@ void PenBlocks::compilePenDown(Compiler *compiler) compiler->addFunctionCall(&penDown); } +void PenBlocks::compilePenUp(Compiler *compiler) +{ + compiler->addFunctionCall(&penUp); +} + unsigned int PenBlocks::clear(VirtualMachine *vm) { IPenLayer *penLayer = PenLayer::getProjectPenLayer(vm->engine()); @@ -60,3 +66,18 @@ unsigned int PenBlocks::penDown(VirtualMachine *vm) return 0; } +unsigned int PenBlocks::penUp(libscratchcpp::VirtualMachine *vm) +{ + Target *target = vm->target(); + + if (!target || target->isStage()) + return 0; + + Sprite *sprite = static_cast(target); + SpriteModel *model = static_cast(sprite->getInterface()); + + if (model) + model->setPenDown(false); + + return 0; +} diff --git a/src/blocks/penblocks.h b/src/blocks/penblocks.h index 6d2f367..7da4ba1 100644 --- a/src/blocks/penblocks.h +++ b/src/blocks/penblocks.h @@ -20,9 +20,11 @@ class PenBlocks : public libscratchcpp::IBlockSection static void compileClear(libscratchcpp::Compiler *compiler); static void compilePenDown(libscratchcpp::Compiler *compiler); + static void compilePenUp(libscratchcpp::Compiler *compiler); static unsigned int clear(libscratchcpp::VirtualMachine *vm); static unsigned int penDown(libscratchcpp::VirtualMachine *vm); + static unsigned int penUp(libscratchcpp::VirtualMachine *vm); }; } // namespace scratchcpprender diff --git a/test/blocks/pen_blocks_test.cpp b/test/blocks/pen_blocks_test.cpp index 1320065..e6d9f66 100644 --- a/test/blocks/pen_blocks_test.cpp +++ b/test/blocks/pen_blocks_test.cpp @@ -46,6 +46,7 @@ TEST_F(PenBlocksTest, RegisterBlocks) // Blocks EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "pen_clear", &PenBlocks::compileClear)); EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "pen_penDown", &PenBlocks::compilePenDown)); + EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "pen_penUp", &PenBlocks::compilePenUp)); m_section->registerBlocks(&m_engineMock); } @@ -127,3 +128,45 @@ TEST_F(PenBlocksTest, PenDownImpl) ASSERT_EQ(vm.registerCount(), 0); ASSERT_TRUE(model.penDown()); } + +TEST_F(PenBlocksTest, PenUp) +{ + Compiler compiler(&m_engineMock); + + auto block = std::make_shared("a", "pen_penUp"); + + EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::penUp)).WillOnce(Return(2)); + compiler.init(); + compiler.setBlock(block); + PenBlocks::compilePenUp(&compiler); + compiler.end(); + + ASSERT_EQ(compiler.bytecode(), std::vector({ vm::OP_START, vm::OP_EXEC, 2, vm::OP_HALT })); + ASSERT_TRUE(compiler.constValues().empty()); + ASSERT_TRUE(compiler.variables().empty()); + ASSERT_TRUE(compiler.lists().empty()); +} + +TEST_F(PenBlocksTest, PenUpImpl) +{ + static unsigned int bytecode[] = { vm::OP_START, vm::OP_EXEC, 0, vm::OP_HALT }; + static BlockFunc functions[] = { &PenBlocks::penUp }; + + SpriteModel model; + model.setPenDown(true); + Sprite sprite; + sprite.setInterface(&model); + + VirtualMachine vm(&sprite, &m_engineMock, nullptr); + vm.setBytecode(bytecode); + vm.setFunctions(functions); + + vm.run(); + ASSERT_EQ(vm.registerCount(), 0); + ASSERT_FALSE(model.penDown()); + + vm.reset(); + vm.run(); + ASSERT_EQ(vm.registerCount(), 0); + ASSERT_FALSE(model.penDown()); +}