diff --git a/CMakeLists.txt b/CMakeLists.txt index 64781f7..e200f12 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.14) -project(scratchcpp-render VERSION 0.9.0 LANGUAGES CXX) +project(scratchcpp-render VERSION 0.10.0 LANGUAGES CXX) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOUIC ON) diff --git a/libscratchcpp b/libscratchcpp index 8ed5355..6c5fc94 160000 --- a/libscratchcpp +++ b/libscratchcpp @@ -1 +1 @@ -Subproject commit 8ed5355643f3b92cd672cda7673dba1b4105bbb1 +Subproject commit 6c5fc94c34ccc9b10cbfdd7a088201643c010518 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index af50238..aa7735d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -78,13 +78,6 @@ qt_add_qml_module(scratchcpp-render effecttransform.h ) -if (NOT LIBSCRATCHCPP_USE_LLVM) - target_sources(scratchcpp-render - PRIVATE - blocks/penblocks.cpp - blocks/penblocks.h) -endif() - list(APPEND QML_IMPORT_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) list(REMOVE_DUPLICATES QML_IMPORT_PATH) set(QML_IMPORT_PATH ${QML_IMPORT_PATH} CACHE STRING "" FORCE) diff --git a/src/ProjectPlayer.qml b/src/ProjectPlayer.qml index 87f8f7e..b458ed4 100644 --- a/src/ProjectPlayer.qml +++ b/src/ProjectPlayer.qml @@ -192,6 +192,16 @@ ProjectScene { scale: hqPen ? 1 : stageScale transformOrigin: Item.TopLeft visible: !priv.loading + + onWidthChanged: { + if (!hqPen) + refresh(); + } + + onHeightChanged: { + if (!hqPen) + refresh(); + } } Component { @@ -263,22 +273,25 @@ ProjectScene { } } - Repeater { - id: sprites - model: loader.sprites - delegate: renderedSprite - } + Item { + // Sprites are wrapped in Item to ensure monitors appear above them + Repeater { + id: sprites + model: loader.sprites + delegate: renderedSprite + } - Repeater { - id: clones - model: ListModel {} - delegate: renderedSprite - } + Repeater { + id: clones + model: ListModel {} + delegate: renderedSprite + } - Repeater { - id: textBubbles - model: loader.sprites - delegate: renderedTextBubble + Repeater { + id: textBubbles + model: loader.sprites + delegate: renderedTextBubble + } } SceneMouseArea { diff --git a/src/blocks/penblocks.cpp b/src/blocks/penblocks.cpp deleted file mode 100644 index 2d77b79..0000000 --- a/src/blocks/penblocks.cpp +++ /dev/null @@ -1,572 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later - -#include -#include -#include -#include - -#include "penblocks.h" -#include "penlayer.h" -#include "penstate.h" -#include "spritemodel.h" -#include "stagemodel.h" - -using namespace scratchcpprender; -using namespace libscratchcpp; - -// Pen size range: https://github.com/scratchfoundation/scratch-vm/blob/8dbcc1fc8f8d8c4f1e40629fe8a388149d6dfd1c/src/extensions/scratch3_pen/index.js#L100-L102 -static const double PEN_SIZE_MIN = 1; -static const double PEN_SIZE_MAX = 1200; - -static const double COLOR_PARAM_MIN = 0; -static const double COLOR_PARAM_MAX = 100; - -const std::unordered_map - PenBlocks::COLOR_PARAM_MAP = { { "color", ColorParam::COLOR }, { "saturation", ColorParam::SATURATION }, { "brightness", ColorParam::BRIGHTNESS }, { "transparency", ColorParam::TRANSPARENCY } }; - -std::string PenBlocks::name() const -{ - return "pen"; -} - -std::string PenBlocks::description() const -{ - return "Pen blocks"; -} - -Rgb PenBlocks::color() const -{ - return rgb(15, 189, 140); -} - -void PenBlocks::registerBlocks(IEngine *engine) -{ - // Blocks - engine->addCompileFunction(this, "pen_clear", &compileClear); - engine->addCompileFunction(this, "pen_stamp", &compileStamp); - engine->addCompileFunction(this, "pen_penDown", &compilePenDown); - engine->addCompileFunction(this, "pen_penUp", &compilePenUp); - engine->addCompileFunction(this, "pen_setPenColorToColor", &compileSetPenColorToColor); - engine->addCompileFunction(this, "pen_changePenColorParamBy", &compileChangePenColorParamBy); - engine->addCompileFunction(this, "pen_setPenColorParamTo", &compileSetPenColorParamTo); - engine->addCompileFunction(this, "pen_changePenSizeBy", &compileChangePenSizeBy); - engine->addCompileFunction(this, "pen_setPenSizeTo", &compileSetPenSizeTo); - engine->addCompileFunction(this, "pen_changePenShadeBy", &compileChangePenShadeBy); - engine->addCompileFunction(this, "pen_setPenShadeToNumber", &compileSetPenShadeToNumber); - engine->addCompileFunction(this, "pen_changePenHueBy", &compileChangePenHueBy); - engine->addCompileFunction(this, "pen_setPenHueToNumber", &compileSetPenHueToNumber); - - // Inputs - engine->addInput(this, "COLOR", COLOR); - engine->addInput(this, "COLOR_PARAM", COLOR_PARAM); - engine->addInput(this, "VALUE", VALUE); - engine->addInput(this, "SIZE", SIZE); - engine->addInput(this, "SHADE", SHADE); - engine->addInput(this, "HUE", HUE); -} - -void PenBlocks::compileClear(Compiler *compiler) -{ - compiler->addFunctionCall(&clear); -} - -void PenBlocks::compileStamp(Compiler *compiler) -{ - compiler->addFunctionCall(&stamp); -} - -void PenBlocks::compilePenDown(Compiler *compiler) -{ - compiler->addFunctionCall(&penDown); -} - -void PenBlocks::compilePenUp(Compiler *compiler) -{ - compiler->addFunctionCall(&penUp); -} - -void PenBlocks::compileSetPenColorToColor(libscratchcpp::Compiler *compiler) -{ - compiler->addInput(COLOR); - compiler->addFunctionCall(&setPenColorToColor); -} - -void PenBlocks::compileChangePenColorParamBy(libscratchcpp::Compiler *compiler) -{ - Input *input = compiler->input(COLOR_PARAM); - - if (input->pointsToDropdownMenu()) { - std::string value = input->selectedMenuItem(); - BlockFunc f = nullptr; - - if (value == "color") - f = &changePenColorBy; - else if (value == "saturation") - f = &changePenSaturationBy; - else if (value == "brightness") - f = &changePenBrightnessBy; - else if (value == "transparency") - f = &changePenTransparencyBy; - - if (f) { - compiler->addInput(VALUE); - compiler->addFunctionCall(f); - } - } else { - compiler->addInput(input); - compiler->addInput(VALUE); - compiler->addFunctionCall(&changePenColorParamBy); - } -} - -void PenBlocks::compileSetPenColorParamTo(Compiler *compiler) -{ - Input *input = compiler->input(COLOR_PARAM); - - if (input->pointsToDropdownMenu()) { - std::string value = input->selectedMenuItem(); - BlockFunc f = nullptr; - - if (value == "color") - f = &setPenColorTo; - else if (value == "saturation") - f = &setPenSaturationTo; - else if (value == "brightness") - f = &setPenBrightnessTo; - else if (value == "transparency") - f = &setPenTransparencyTo; - - if (f) { - compiler->addInput(VALUE); - compiler->addFunctionCall(f); - } - } else { - compiler->addInput(input); - compiler->addInput(VALUE); - compiler->addFunctionCall(&setPenColorParamTo); - } -} - -void PenBlocks::compileChangePenSizeBy(libscratchcpp::Compiler *compiler) -{ - compiler->addInput(SIZE); - compiler->addFunctionCall(&changePenSizeBy); -} - -void PenBlocks::compileSetPenSizeTo(libscratchcpp::Compiler *compiler) -{ - compiler->addInput(SIZE); - compiler->addFunctionCall(&setPenSizeTo); -} - -void PenBlocks::compileChangePenShadeBy(Compiler *compiler) -{ - compiler->addInput(SHADE); - compiler->addFunctionCall(&changePenShadeBy); -} - -void PenBlocks::compileSetPenShadeToNumber(libscratchcpp::Compiler *compiler) -{ - compiler->addInput(SHADE); - compiler->addFunctionCall(&setPenShadeToNumber); -} - -void PenBlocks::compileChangePenHueBy(libscratchcpp::Compiler *compiler) -{ - compiler->addInput(HUE); - compiler->addFunctionCall(&changePenHueBy); -} - -void PenBlocks::compileSetPenHueToNumber(libscratchcpp::Compiler *compiler) -{ - compiler->addInput(HUE); - compiler->addFunctionCall(&setPenHueToNumber); -} - -unsigned int PenBlocks::clear(VirtualMachine *vm) -{ - IPenLayer *penLayer = PenLayer::getProjectPenLayer(vm->engine()); - - if (penLayer) { - penLayer->clear(); - vm->engine()->requestRedraw(); - } - - return 0; -} - -unsigned int PenBlocks::stamp(libscratchcpp::VirtualMachine *vm) -{ - IPenLayer *penLayer = PenLayer::getProjectPenLayer(vm->engine()); - - if (penLayer) { - Target *target = vm->target(); - IRenderedTarget *renderedTarget = nullptr; - - if (target->isStage()) { - IStageHandler *iface = static_cast(target)->getInterface(); - renderedTarget = static_cast(iface)->renderedTarget(); - } else { - ISpriteHandler *iface = static_cast(target)->getInterface(); - renderedTarget = static_cast(iface)->renderedTarget(); - } - - penLayer->stamp(renderedTarget); - vm->engine()->requestRedraw(); - } - - return 0; -} - -unsigned int PenBlocks::penDown(VirtualMachine *vm) -{ - TargetModel *model = getTargetModel(vm); - - if (model) - model->setPenDown(true); - - return 0; -} - -unsigned int PenBlocks::penUp(libscratchcpp::VirtualMachine *vm) -{ - TargetModel *model = getTargetModel(vm); - - if (model) - model->setPenDown(false); - - return 0; -} - -unsigned int PenBlocks::changePenSizeBy(libscratchcpp::VirtualMachine *vm) -{ - TargetModel *model = getTargetModel(vm); - - if (model) - model->penAttributes().diameter = std::clamp(model->penAttributes().diameter + vm->getInput(0, 1)->toDouble(), PEN_SIZE_MIN, PEN_SIZE_MAX); - - return 1; -} - -unsigned int PenBlocks::setPenSizeTo(libscratchcpp::VirtualMachine *vm) -{ - TargetModel *model = getTargetModel(vm); - - if (model) - model->penAttributes().diameter = std::clamp(vm->getInput(0, 1)->toDouble(), PEN_SIZE_MIN, PEN_SIZE_MAX); - - return 1; -} - -unsigned int PenBlocks::changePenShadeBy(libscratchcpp::VirtualMachine *vm) -{ - TargetModel *model = getTargetModel(vm); - - if (model) { - PenState &penState = model->penState(); - setPenShade(penState.shade + vm->getInput(0, 1)->toDouble(), penState); - } - - return 1; -} - -unsigned int PenBlocks::setPenShadeToNumber(libscratchcpp::VirtualMachine *vm) -{ - TargetModel *model = getTargetModel(vm); - - if (model) - setPenShade(vm->getInput(0, 1)->toInt(), model->penState()); - - return 1; -} - -unsigned int PenBlocks::changePenHueBy(libscratchcpp::VirtualMachine *vm) -{ - TargetModel *model = getTargetModel(vm); - - if (model) { - PenState &penState = model->penState(); - const double colorChange = vm->getInput(0, 1)->toDouble() / 2; - setOrChangeColorParam(ColorParam::COLOR, colorChange, penState, true); - legacyUpdatePenColor(penState); - } - - return 1; -} - -unsigned int PenBlocks::setPenHueToNumber(libscratchcpp::VirtualMachine *vm) -{ - TargetModel *model = getTargetModel(vm); - - if (model) { - PenState &penState = model->penState(); - const double colorValue = vm->getInput(0, 1)->toDouble() / 2; - setOrChangeColorParam(ColorParam::COLOR, colorValue, penState, false); - penState.transparency = 0; - legacyUpdatePenColor(penState); - } - - return 1; -} - -unsigned int PenBlocks::setPenColorToColor(libscratchcpp::VirtualMachine *vm) -{ - TargetModel *model = getTargetModel(vm); - - if (model) { - const Value *value = vm->getInput(0, 1); - std::string stringValue; - PenState &penState = model->penState(); - QColor newColor; - - if (value->isString()) - stringValue = value->toString(); - - if (!stringValue.empty() && stringValue[0] == '#') { - bool valid = false; - - if (stringValue.size() <= 7) // #RRGGBB - { - newColor = QColor::fromString(stringValue); - valid = newColor.isValid(); - } - - if (!valid) - newColor = Qt::black; - - } else - newColor = QColor::fromRgba(static_cast(value->toLong())); - - QColor hsv = newColor.toHsv(); - penState.color = (hsv.hue() / 360.0) * 100; - penState.saturation = hsv.saturationF() * 100; - penState.brightness = hsv.valueF() * 100; - - if (newColor.alpha() > 0) - penState.transparency = 100 * (1 - newColor.alpha() / 255.0); - else - penState.transparency = 0; - - penState.updateColor(); - - // Set the legacy "shade" value the same way Scratch 2 did. - penState.shade = penState.brightness / 2; - } - - return 1; -} - -unsigned int PenBlocks::changePenColorParamBy(VirtualMachine *vm) -{ - TargetModel *model = getTargetModel(vm); - - if (model) { - const auto it = COLOR_PARAM_MAP.find(vm->getInput(0, 2)->toString()); - - if (it == COLOR_PARAM_MAP.cend()) - return 2; - - setOrChangeColorParam(it->second, vm->getInput(1, 2)->toDouble(), model->penState(), true); - } - - return 2; -} - -unsigned int PenBlocks::changePenColorBy(VirtualMachine *vm) -{ - TargetModel *model = getTargetModel(vm); - - if (model) - setOrChangeColorParam(ColorParam::COLOR, vm->getInput(0, 1)->toDouble(), model->penState(), true); - - return 1; -} - -unsigned int PenBlocks::changePenSaturationBy(VirtualMachine *vm) -{ - TargetModel *model = getTargetModel(vm); - - if (model) - setOrChangeColorParam(ColorParam::SATURATION, vm->getInput(0, 1)->toDouble(), model->penState(), true); - - return 1; -} - -unsigned int PenBlocks::changePenBrightnessBy(VirtualMachine *vm) -{ - TargetModel *model = getTargetModel(vm); - - if (model) - setOrChangeColorParam(ColorParam::BRIGHTNESS, vm->getInput(0, 1)->toDouble(), model->penState(), true); - - return 1; -} - -unsigned int PenBlocks::changePenTransparencyBy(VirtualMachine *vm) -{ - TargetModel *model = getTargetModel(vm); - - if (model) - setOrChangeColorParam(ColorParam::TRANSPARENCY, vm->getInput(0, 1)->toDouble(), model->penState(), true); - - return 1; -} - -unsigned int PenBlocks::setPenColorParamTo(VirtualMachine *vm) -{ - TargetModel *model = getTargetModel(vm); - - if (model) { - const auto it = COLOR_PARAM_MAP.find(vm->getInput(0, 2)->toString()); - - if (it == COLOR_PARAM_MAP.cend()) - return 2; - - setOrChangeColorParam(it->second, vm->getInput(1, 2)->toDouble(), model->penState(), false); - } - - return 2; -} - -unsigned int PenBlocks::setPenColorTo(VirtualMachine *vm) -{ - TargetModel *model = getTargetModel(vm); - - if (model) - setOrChangeColorParam(ColorParam::COLOR, vm->getInput(0, 1)->toDouble(), model->penState(), false); - - return 1; -} - -unsigned int PenBlocks::setPenSaturationTo(VirtualMachine *vm) -{ - TargetModel *model = getTargetModel(vm); - - if (model) - setOrChangeColorParam(ColorParam::SATURATION, vm->getInput(0, 1)->toDouble(), model->penState(), false); - - return 1; -} - -unsigned int PenBlocks::setPenBrightnessTo(VirtualMachine *vm) -{ - TargetModel *model = getTargetModel(vm); - - if (model) - setOrChangeColorParam(ColorParam::BRIGHTNESS, vm->getInput(0, 1)->toDouble(), model->penState(), false); - - return 1; -} - -unsigned int PenBlocks::setPenTransparencyTo(VirtualMachine *vm) -{ - TargetModel *model = getTargetModel(vm); - - if (model) - setOrChangeColorParam(ColorParam::TRANSPARENCY, vm->getInput(0, 1)->toDouble(), model->penState(), false); - - return 1; -} - -TargetModel *PenBlocks::getTargetModel(libscratchcpp::VirtualMachine *vm) -{ - Target *target = vm->target(); - - if (!target) - return nullptr; - - if (target->isStage()) { - Stage *stage = static_cast(target); - return static_cast(stage->getInterface()); - } else { - Sprite *sprite = static_cast(target); - return static_cast(sprite->getInterface()); - } -} - -void PenBlocks::setOrChangeColorParam(ColorParam param, double value, PenState &penState, bool change) -{ - switch (param) { - case ColorParam::COLOR: - penState.color = wrapClamp(value + (change ? penState.color : 0), 0, 100); - break; - - case ColorParam::SATURATION: - penState.saturation = std::clamp(value + (change ? penState.saturation : 0), COLOR_PARAM_MIN, COLOR_PARAM_MAX); - break; - - case ColorParam::BRIGHTNESS: - penState.brightness = std::clamp(value + (change ? penState.brightness : 0), COLOR_PARAM_MIN, COLOR_PARAM_MAX); - break; - - case ColorParam::TRANSPARENCY: - penState.transparency = std::clamp(value + (change ? penState.transparency : 0), COLOR_PARAM_MIN, COLOR_PARAM_MAX); - break; - - default: - assert(false); - return; - } - - penState.updateColor(); -} - -void PenBlocks::setPenShade(int shade, PenState &penState) -{ - // https://github.com/scratchfoundation/scratch-vm/blob/8dbcc1fc8f8d8c4f1e40629fe8a388149d6dfd1c/src/extensions/scratch3_pen/index.js#L718-L730 - // Wrap clamp the new shade value the way Scratch 2 did - shade = shade % 200; - - if (shade < 0) - shade += 200; - - // And store the shade that was used to compute this new color for later use - penState.shade = shade; - - legacyUpdatePenColor(penState); -} - -void PenBlocks::legacyUpdatePenColor(PenState &penState) -{ - // https://github.com/scratchfoundation/scratch-vm/blob/8dbcc1fc8f8d8c4f1e40629fe8a388149d6dfd1c/src/extensions/scratch3_pen/index.js#L750-L767 - // Create the new color in RGB using the scratch 2 "shade" model - QRgb rgb = QColor::fromHsvF(penState.color / 100, 1, 1).rgb(); - const double shade = (penState.shade > 100) ? 200 - penState.shade : penState.shade; - - if (shade < 50) - rgb = mixRgb(0, rgb, (10 + shade) / 60); - else - rgb = mixRgb(rgb, 0xFFFFFF, (shade - 50) / 60); - - // Update the pen state according to new color - QColor hsv = QColor::fromRgb(rgb).toHsv(); - penState.color = 100 * hsv.hueF(); - penState.saturation = 100 * hsv.saturationF(); - penState.brightness = 100 * hsv.valueF(); - - penState.updateColor(); -} - -double PenBlocks::wrapClamp(double n, double min, double max) -{ - // TODO: Move this to a separate class - const double range = max - min /*+ 1*/; - return n - (std::floor((n - min) / range) * range); -} - -QRgb PenBlocks::mixRgb(QRgb rgb0, QRgb rgb1, double fraction1) -{ - // https://github.com/scratchfoundation/scratch-vm/blob/a4f095db5e03e072ba222fe721eeeb543c9b9c15/src/util/color.js#L192-L201 - // https://github.com/scratchfoundation/scratch-flash/blob/2e4a402ceb205a042887f54b26eebe1c2e6da6c0/src/util/Color.as#L75-L89 - if (fraction1 <= 0) - return rgb0; - - if (fraction1 >= 1) - return rgb1; - - const double fraction0 = 1 - fraction1; - const int r = static_cast(((fraction0 * qRed(rgb0)) + (fraction1 * qRed(rgb1)))) & 255; - const int g = static_cast(((fraction0 * qGreen(rgb0)) + (fraction1 * qGreen(rgb1)))) & 255; - const int b = static_cast(((fraction0 * qBlue(rgb0)) + (fraction1 * qBlue(rgb1)))) & 255; - return qRgb(r, g, b); -} diff --git a/src/blocks/penblocks.h b/src/blocks/penblocks.h deleted file mode 100644 index 61e147b..0000000 --- a/src/blocks/penblocks.h +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-or-later - -#pragma once - -#include -#include - -namespace scratchcpprender -{ - -class TargetModel; -class PenState; - -class PenBlocks : public libscratchcpp::IExtension -{ - public: - enum Inputs - { - COLOR, - COLOR_PARAM, - VALUE, - SIZE, - SHADE, - HUE - }; - - std::string name() const override; - std::string description() const override; - libscratchcpp::Rgb color() const override; - - void registerBlocks(libscratchcpp::IEngine *engine) override; - - static void compileClear(libscratchcpp::Compiler *compiler); - static void compileStamp(libscratchcpp::Compiler *compiler); - static void compilePenDown(libscratchcpp::Compiler *compiler); - static void compilePenUp(libscratchcpp::Compiler *compiler); - static void compileSetPenColorToColor(libscratchcpp::Compiler *compiler); - static void compileChangePenColorParamBy(libscratchcpp::Compiler *compiler); - static void compileSetPenColorParamTo(libscratchcpp::Compiler *compiler); - static void compileChangePenSizeBy(libscratchcpp::Compiler *compiler); - static void compileSetPenSizeTo(libscratchcpp::Compiler *compiler); - static void compileChangePenShadeBy(libscratchcpp::Compiler *compiler); - static void compileSetPenShadeToNumber(libscratchcpp::Compiler *compiler); - static void compileChangePenHueBy(libscratchcpp::Compiler *compiler); - static void compileSetPenHueToNumber(libscratchcpp::Compiler *compiler); - - static unsigned int clear(libscratchcpp::VirtualMachine *vm); - static unsigned int stamp(libscratchcpp::VirtualMachine *vm); - static unsigned int penDown(libscratchcpp::VirtualMachine *vm); - static unsigned int penUp(libscratchcpp::VirtualMachine *vm); - static unsigned int setPenColorToColor(libscratchcpp::VirtualMachine *vm); - - static unsigned int changePenColorParamBy(libscratchcpp::VirtualMachine *vm); - static unsigned int changePenColorBy(libscratchcpp::VirtualMachine *vm); - static unsigned int changePenSaturationBy(libscratchcpp::VirtualMachine *vm); - static unsigned int changePenBrightnessBy(libscratchcpp::VirtualMachine *vm); - static unsigned int changePenTransparencyBy(libscratchcpp::VirtualMachine *vm); - - static unsigned int setPenColorParamTo(libscratchcpp::VirtualMachine *vm); - static unsigned int setPenColorTo(libscratchcpp::VirtualMachine *vm); - static unsigned int setPenSaturationTo(libscratchcpp::VirtualMachine *vm); - static unsigned int setPenBrightnessTo(libscratchcpp::VirtualMachine *vm); - static unsigned int setPenTransparencyTo(libscratchcpp::VirtualMachine *vm); - - static unsigned int changePenSizeBy(libscratchcpp::VirtualMachine *vm); - static unsigned int setPenSizeTo(libscratchcpp::VirtualMachine *vm); - static unsigned int changePenShadeBy(libscratchcpp::VirtualMachine *vm); - static unsigned int setPenShadeToNumber(libscratchcpp::VirtualMachine *vm); - static unsigned int changePenHueBy(libscratchcpp::VirtualMachine *vm); - static unsigned int setPenHueToNumber(libscratchcpp::VirtualMachine *vm); - - private: - enum class ColorParam - { - COLOR, - SATURATION, - BRIGHTNESS, - TRANSPARENCY - }; - - static TargetModel *getTargetModel(libscratchcpp::VirtualMachine *vm); - static void setOrChangeColorParam(ColorParam param, double value, PenState &penState, bool change); - static void setPenShade(int shade, PenState &penState); - static void legacyUpdatePenColor(PenState &penState); - static double wrapClamp(double n, double min, double max); - static QRgb mixRgb(QRgb rgb0, QRgb rgb1, double fraction1); - - static const std::unordered_map COLOR_PARAM_MAP; -}; - -} // namespace scratchcpprender diff --git a/src/listmonitormodel.cpp b/src/listmonitormodel.cpp index b88b3e9..5c09847 100644 --- a/src/listmonitormodel.cpp +++ b/src/listmonitormodel.cpp @@ -1,6 +1,6 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -#include +#include #include "listmonitormodel.h" #include "listmonitorlistmodel.h" @@ -18,13 +18,10 @@ ListMonitorModel::ListMonitorModel(libscratchcpp::IExtension *extension, QObject m_listModel = new ListMonitorListModel(this); } -void ListMonitorModel::onValueChanged(const libscratchcpp::VirtualMachine *vm) +void ListMonitorModel::onValueChanged(const libscratchcpp::Value &value) { - if (vm->registerCount() == 1) { - long index = vm->getInput(0, 1)->toLong(); - libscratchcpp::List *list = vm->lists()[index]; - m_listModel->setList(list, m_minIndex, m_maxIndex); - } + libscratchcpp::List *list = (libscratchcpp::List *)value.toPointer(); + m_listModel->setList(list, m_minIndex, m_maxIndex); } MonitorModel::Type ListMonitorModel::type() const diff --git a/src/listmonitormodel.h b/src/listmonitormodel.h index acda897..3452b7e 100644 --- a/src/listmonitormodel.h +++ b/src/listmonitormodel.h @@ -25,7 +25,7 @@ class ListMonitorModel : public MonitorModel ListMonitorModel(QObject *parent = nullptr); ListMonitorModel(libscratchcpp::IExtension *extension, QObject *parent = nullptr); - void onValueChanged(const libscratchcpp::VirtualMachine *vm) override; + void onValueChanged(const libscratchcpp::Value &value) override; Type type() const override; diff --git a/src/monitormodel.h b/src/monitormodel.h index 8ad7f73..bf1120b 100644 --- a/src/monitormodel.h +++ b/src/monitormodel.h @@ -47,7 +47,7 @@ class MonitorModel void init(libscratchcpp::Monitor *monitor) override final; - virtual void onValueChanged(const libscratchcpp::VirtualMachine *vm) override { } + virtual void onValueChanged(const libscratchcpp::Value &value) override { } void onVisibleChanged(bool visible) override final; void onXChanged(int x) override final; void onYChanged(int y) override final; diff --git a/src/penlayer.cpp b/src/penlayer.cpp index 7333517..b93cb30 100644 --- a/src/penlayer.cpp +++ b/src/penlayer.cpp @@ -68,9 +68,15 @@ void PenLayer::setEngine(libscratchcpp::IEngine *newEngine) m_engine = newEngine; - if (m_engine && QOpenGLContext::currentContext()) { + if (!m_glCtx) { + m_glCtx = QOpenGLContext::currentContext(); + + if (m_glCtx) + m_surface = m_glCtx->surface(); + } + + if (m_engine && m_glCtx) { m_projectPenLayers[m_engine] = this; - createFbo(); if (!m_painter) m_painter = std::make_unique(); @@ -80,6 +86,8 @@ void PenLayer::setEngine(libscratchcpp::IEngine *newEngine) m_glF->initializeOpenGLFunctions(); } + refresh(); + if (m_vao == 0) { // Set up VBO and VAO float vertices[] = { -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f }; @@ -124,8 +132,8 @@ void PenLayer::setHqPen(bool newHqPen) return; m_hqPen = newHqPen; - createFbo(); emit hqPenChanged(); + refresh(); } void scratchcpprender::PenLayer::clear() @@ -324,6 +332,41 @@ void PenLayer::stamp(IRenderedTarget *target) update(); } +void PenLayer::refresh() +{ + if (!m_glCtx || !m_surface || !m_engine || !m_glF) + return; + + QOpenGLContext *oldCtx = QOpenGLContext::currentContext(); + QSurface *oldSurface = oldCtx->surface(); + + if (oldCtx != m_glCtx) { + oldCtx->doneCurrent(); + m_glCtx->makeCurrent(m_surface); + } + + QOpenGLFramebufferObjectFormat fboFormat; + fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); + + QOpenGLFramebufferObject *newFbo = new QOpenGLFramebufferObject(width(), height(), fboFormat); + Q_ASSERT(newFbo->isValid()); + + if (m_fbo) { + m_glF->glDisable(GL_SCISSOR_TEST); + QOpenGLFramebufferObject::blitFramebuffer(newFbo, m_fbo.get()); + m_glF->glEnable(GL_SCISSOR_TEST); + } + + m_fbo.reset(newFbo); + m_texture = Texture(m_fbo->texture(), m_fbo->size()); + m_scale = width() / m_engine->stageWidth(); + + if (oldCtx != m_glCtx) { + m_glCtx->doneCurrent(); + oldCtx->makeCurrent(oldSurface); + } +} + QOpenGLFramebufferObject *PenLayer::framebufferObject() const { return m_fbo.get(); @@ -427,36 +470,21 @@ void PenLayer::addPenLayer(libscratchcpp::IEngine *engine, IPenLayer *penLayer) QNanoQuickItemPainter *PenLayer::createItemPainter() const { + m_glCtx = QOpenGLContext::currentContext(); + Q_ASSERT(m_glCtx); + m_surface = m_glCtx->surface(); + Q_ASSERT(m_surface); return new PenLayerPainter; } void PenLayer::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) { if (m_hqPen && newGeometry != oldGeometry) - createFbo(); + refresh(); QNanoQuickItem::geometryChange(newGeometry, oldGeometry); } -void PenLayer::createFbo() -{ - if (!QOpenGLContext::currentContext() || !m_engine) - return; - - QOpenGLFramebufferObjectFormat fboFormat; - fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); - - QOpenGLFramebufferObject *newFbo = new QOpenGLFramebufferObject(width(), height(), fboFormat); - Q_ASSERT(newFbo->isValid()); - - if (m_fbo) - QOpenGLFramebufferObject::blitFramebuffer(newFbo, m_fbo.get()); - - m_fbo.reset(newFbo); - m_texture = Texture(m_fbo->texture(), m_fbo->size()); - m_scale = width() / m_engine->stageWidth(); -} - void PenLayer::updateTexture() { if (!m_fbo) diff --git a/src/penlayer.h b/src/penlayer.h index d17eadc..53c614c 100644 --- a/src/penlayer.h +++ b/src/penlayer.h @@ -39,6 +39,8 @@ class PenLayer : public IPenLayer void drawLine(const PenAttributes &penAttributes, double x0, double y0, double x1, double y1) override; void stamp(IRenderedTarget *target) override; + Q_INVOKABLE void refresh(); + QOpenGLFramebufferObject *framebufferObject() const override; QRgb colorAtScratchPoint(double x, double y) const override; @@ -56,7 +58,6 @@ class PenLayer : public IPenLayer void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; private: - void createFbo(); void updateTexture(); static std::unordered_map m_projectPenLayers; @@ -65,6 +66,8 @@ class PenLayer : public IPenLayer libscratchcpp::IEngine *m_engine = nullptr; bool m_hqPen = false; std::unique_ptr m_fbo; + mutable QOpenGLContext *m_glCtx = nullptr; + mutable QSurface *m_surface = nullptr; double m_scale = 1; std::unique_ptr m_painter; std::unique_ptr m_glF; diff --git a/src/projectloader.cpp b/src/projectloader.cpp index 3126a5f..1453620 100644 --- a/src/projectloader.cpp +++ b/src/projectloader.cpp @@ -12,7 +12,7 @@ #include "valuemonitormodel.h" #include "listmonitormodel.h" #include "renderedtarget.h" -#include "blocks/penblocks.h" +// #include "blocks/penblocks.h" using namespace scratchcpprender; using namespace libscratchcpp; @@ -37,10 +37,8 @@ ProjectLoader::ProjectLoader(QObject *parent) : initTimer(); m_renderTimer.start(); -#ifndef USE_LLVM - // Register pen blocks - ScratchConfiguration::registerExtension(std::make_shared()); -#endif + // TODO: Register pen blocks + // ScratchConfiguration::registerExtension(std::make_shared()); } ProjectLoader::~ProjectLoader() @@ -210,6 +208,24 @@ void ProjectLoader::timerEvent(QTimerEvent *event) return; if (m_engine) { + QOpenGLContext *oldCtx = QOpenGLContext::currentContext(); + QSurface *oldSurface = nullptr; + + if (!m_glCtx) + m_glCtx = oldCtx; + + if (m_glCtx) { + if (!m_surface) + m_surface = m_glCtx->surface(); + + oldSurface = oldCtx->surface(); + + if (oldCtx != m_glCtx) { + oldCtx->doneCurrent(); + m_glCtx->makeCurrent(m_surface); + } + } + for (Monitor *monitor : m_unpositionedMonitors) monitor->autoPosition(m_engine->monitors()); @@ -230,6 +246,13 @@ void ProjectLoader::timerEvent(QTimerEvent *event) m_renderTimer.restart(); } else m_renderFpsCounter++; + + if (m_glCtx) { + if (oldCtx != m_glCtx) { + m_glCtx->doneCurrent(); + oldCtx->makeCurrent(oldSurface); + } + } } event->accept(); diff --git a/src/projectloader.h b/src/projectloader.h index 8ada11c..249be57 100644 --- a/src/projectloader.h +++ b/src/projectloader.h @@ -12,6 +12,9 @@ Q_MOC_INCLUDE("spritemodel.h"); Q_MOC_INCLUDE("monitormodel.h"); +class QSurface; +class QOpenGLContext; + namespace scratchcpprender { @@ -185,6 +188,8 @@ class ProjectLoader : public QObject std::atomic m_downloadedAssets = 0; std::atomic m_assetCount = 0; std::atomic m_stopLoading = false; + QOpenGLContext *m_glCtx = nullptr; + QSurface *m_surface = nullptr; }; } // namespace scratchcpprender diff --git a/src/valuemonitormodel.cpp b/src/valuemonitormodel.cpp index 78d8c90..0af3911 100644 --- a/src/valuemonitormodel.cpp +++ b/src/valuemonitormodel.cpp @@ -1,7 +1,7 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -#include #include +#include #include "valuemonitormodel.h" @@ -21,12 +21,10 @@ ValueMonitorModel::ValueMonitorModel(IExtension *extension, QObject *parent) : { } -void ValueMonitorModel::onValueChanged(const VirtualMachine *vm) +void ValueMonitorModel::onValueChanged(const libscratchcpp::Value &value) { - if (vm->registerCount() == 1) { - m_value = QString::fromStdString(vm->getInput(0, 1)->toString()); - emit valueChanged(); - } + m_value = QString::fromStdString(value.toString()); + emit valueChanged(); } MonitorModel::Type ValueMonitorModel::type() const diff --git a/src/valuemonitormodel.h b/src/valuemonitormodel.h index c256c74..79401b4 100644 --- a/src/valuemonitormodel.h +++ b/src/valuemonitormodel.h @@ -30,7 +30,7 @@ class ValueMonitorModel : public MonitorModel ValueMonitorModel(QObject *parent = nullptr); ValueMonitorModel(libscratchcpp::IExtension *extension, QObject *parent = nullptr); - void onValueChanged(const libscratchcpp::VirtualMachine *vm) override; + void onValueChanged(const libscratchcpp::Value &value) override; Type type() const override; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0159df6..f697644 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -36,7 +36,6 @@ add_subdirectory(penattributes) add_subdirectory(penstate) add_subdirectory(penlayer) add_subdirectory(penlayerpainter) -add_subdirectory(blocks) add_subdirectory(graphicseffect) add_subdirectory(shadermanager) add_subdirectory(textbubbleshape) diff --git a/test/blocks/CMakeLists.txt b/test/blocks/CMakeLists.txt deleted file mode 100644 index b3b8888..0000000 --- a/test/blocks/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -# 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 deleted file mode 100644 index 900ede2..0000000 --- a/test/blocks/pen_blocks_test.cpp +++ /dev/null @@ -1,1479 +0,0 @@ -#include -#include -#include -#include -#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: - void SetUp() override { m_extension = 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); - } - - void addObscuredInput(std::shared_ptr block, const std::string &name, PenBlocks::Inputs id, std::shared_ptr valueBlock) const - { - auto input = std::make_shared(name, Input::Type::ObscuredShadow); - input->setValueBlock(valueBlock); - input->setInputId(id); - block->addInput(input); - } - - std::shared_ptr addNullInput(std::shared_ptr block, const std::string &name, PenBlocks::Inputs id) const - { - auto input = std::make_shared(name, Input::Type::Shadow); - input->setInputId(id); - block->addInput(input); - - return input; - } - - void addDropdownInput(std::shared_ptr block, const std::string &name, PenBlocks::Inputs id, const std::string &selectedValue, std::shared_ptr valueBlock = nullptr) const - { - if (valueBlock) - addObscuredInput(block, name, id, valueBlock); - else { - auto input = addNullInput(block, name, id); - auto menu = std::make_shared(block->id() + "_menu", block->opcode() + "_menu"); - menu->setShadow(true); - input->setValueBlock(menu); - addDropdownField(menu, name, -1, selectedValue, -1); - } - } - - void addDropdownField(std::shared_ptr block, const std::string &name, int id, const std::string &value, int valueId) const - { - auto field = std::make_shared(name, value); - field->setFieldId(id); - field->setSpecialValueId(valueId); - block->addField(field); - } - - std::shared_ptr createNullBlock(const std::string &id) - { - std::shared_ptr block = std::make_shared(id, ""); - BlockComp func = [](Compiler *compiler) { compiler->addInstruction(vm::OP_NULL); }; - block->setCompileFunction(func); - - return block; - } - - std::unique_ptr m_extension; - EngineMock m_engineMock; -}; - -TEST_F(PenBlocksTest, Name) -{ - ASSERT_EQ(m_extension->name(), "pen"); -} - -TEST_F(PenBlocksTest, RegisterBlocks) -{ - // Blocks - EXPECT_CALL(m_engineMock, addCompileFunction(m_extension.get(), "pen_clear", &PenBlocks::compileClear)); - EXPECT_CALL(m_engineMock, addCompileFunction(m_extension.get(), "pen_stamp", &PenBlocks::compileStamp)); - EXPECT_CALL(m_engineMock, addCompileFunction(m_extension.get(), "pen_penDown", &PenBlocks::compilePenDown)); - EXPECT_CALL(m_engineMock, addCompileFunction(m_extension.get(), "pen_penUp", &PenBlocks::compilePenUp)); - EXPECT_CALL(m_engineMock, addCompileFunction(m_extension.get(), "pen_setPenColorToColor", &PenBlocks::compileSetPenColorToColor)); - EXPECT_CALL(m_engineMock, addCompileFunction(m_extension.get(), "pen_changePenColorParamBy", &PenBlocks::compileChangePenColorParamBy)); - EXPECT_CALL(m_engineMock, addCompileFunction(m_extension.get(), "pen_setPenColorParamTo", &PenBlocks::compileSetPenColorParamTo)); - EXPECT_CALL(m_engineMock, addCompileFunction(m_extension.get(), "pen_changePenSizeBy", &PenBlocks::compileChangePenSizeBy)); - EXPECT_CALL(m_engineMock, addCompileFunction(m_extension.get(), "pen_setPenSizeTo", &PenBlocks::compileSetPenSizeTo)); - EXPECT_CALL(m_engineMock, addCompileFunction(m_extension.get(), "pen_changePenShadeBy", &PenBlocks::compileChangePenShadeBy)); - EXPECT_CALL(m_engineMock, addCompileFunction(m_extension.get(), "pen_setPenShadeToNumber", &PenBlocks::compileSetPenShadeToNumber)); - EXPECT_CALL(m_engineMock, addCompileFunction(m_extension.get(), "pen_changePenHueBy", &PenBlocks::compileChangePenHueBy)); - EXPECT_CALL(m_engineMock, addCompileFunction(m_extension.get(), "pen_setPenHueToNumber", &PenBlocks::compileSetPenHueToNumber)); - - // Inputs - EXPECT_CALL(m_engineMock, addInput(m_extension.get(), "COLOR", PenBlocks::COLOR)); - EXPECT_CALL(m_engineMock, addInput(m_extension.get(), "COLOR_PARAM", PenBlocks::COLOR_PARAM)); - EXPECT_CALL(m_engineMock, addInput(m_extension.get(), "VALUE", PenBlocks::VALUE)); - EXPECT_CALL(m_engineMock, addInput(m_extension.get(), "SIZE", PenBlocks::SIZE)); - EXPECT_CALL(m_engineMock, addInput(m_extension.get(), "SHADE", PenBlocks::SHADE)); - EXPECT_CALL(m_engineMock, addInput(m_extension.get(), "HUE", PenBlocks::HUE)); - - m_extension->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, Stamp) -{ - Compiler compiler(&m_engineMock); - - auto block = std::make_shared("a", "pen_stamp"); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::stamp)).WillOnce(Return(2)); - compiler.init(); - compiler.setBlock(block); - PenBlocks::compileStamp(&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, StampImpl) -{ - static unsigned int bytecode[] = { vm::OP_START, vm::OP_EXEC, 0, vm::OP_HALT }; - static BlockFunc functions[] = { &PenBlocks::stamp }; - - PenLayerMock penLayer; - PenLayer::addPenLayer(&m_engineMock, &penLayer); - RenderedTargetMock renderedTarget; - - // Test sprite - libscratchcpp::Sprite sprite; - SpriteModel spriteModel; - sprite.setInterface(&spriteModel); - spriteModel.setRenderedTarget(&renderedTarget); - - VirtualMachine vm1(&sprite, &m_engineMock, nullptr); - vm1.setBytecode(bytecode); - vm1.setFunctions(functions); - - EXPECT_CALL(penLayer, stamp(&renderedTarget)); - EXPECT_CALL(m_engineMock, requestRedraw()); - vm1.run(); - - ASSERT_EQ(vm1.registerCount(), 0); - - // Test stage - libscratchcpp::Stage stage; - StageModel stageModel; - stage.setInterface(&stageModel); - stageModel.setRenderedTarget(&renderedTarget); - - VirtualMachine vm2(&stage, &m_engineMock, nullptr); - vm2.setBytecode(bytecode); - vm2.setFunctions(functions); - - EXPECT_CALL(penLayer, stamp(&renderedTarget)); - EXPECT_CALL(m_engineMock, requestRedraw()); - vm2.run(); - - ASSERT_EQ(vm2.registerCount(), 0); -} - -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); -} - -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 }; - - std::vector> models; - std::vector> targets; - - models.push_back(std::make_shared()); - targets.push_back(std::make_shared()); - static_cast(targets.back().get())->setInterface(static_cast(models.back().get())); - - models.push_back(std::make_shared()); - targets.push_back(std::make_shared()); - static_cast(targets.back().get())->setInterface(static_cast(models.back().get())); - - for (int i = 0; i < targets.size(); i++) { - auto target = targets[i]; - auto model = models[i]; - - VirtualMachine vm(target.get(), &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()); - } -} - -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 }; - - std::vector> models; - std::vector> targets; - - models.push_back(std::make_shared()); - targets.push_back(std::make_shared()); - static_cast(targets.back().get())->setInterface(static_cast(models.back().get())); - - models.push_back(std::make_shared()); - targets.push_back(std::make_shared()); - static_cast(targets.back().get())->setInterface(static_cast(models.back().get())); - - for (int i = 0; i < targets.size(); i++) { - auto target = targets[i]; - auto model = models[i]; - model->setPenDown(true); - - VirtualMachine vm(target.get(), &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()); - } -} - -TEST_F(PenBlocksTest, SetPenColorToColor) -{ - Compiler compiler(&m_engineMock); - - // set pen color to ("#AABBCC") - auto block1 = std::make_shared("a", "pen_setPenColorToColor"); - addValueInput(block1, "COLOR", PenBlocks::COLOR, "#AABBCC"); - - // set pen color to (null block) - auto block2 = std::make_shared("b", "pen_setPenColorToColor"); - addObscuredInput(block2, "COLOR", PenBlocks::COLOR, createNullBlock("c")); - - compiler.init(); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::setPenColorToColor)).WillOnce(Return(2)); - compiler.setBlock(block1); - PenBlocks::compileSetPenColorToColor(&compiler); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::setPenColorToColor)).WillOnce(Return(2)); - compiler.setBlock(block2); - PenBlocks::compileSetPenColorToColor(&compiler); - - compiler.end(); - - ASSERT_EQ(compiler.bytecode(), std::vector({ vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 2, vm::OP_NULL, vm::OP_EXEC, 2, vm::OP_HALT })); - ASSERT_EQ(compiler.constValues().size(), 1); - ASSERT_EQ(compiler.constValues()[0].toString(), "#AABBCC"); - ASSERT_TRUE(compiler.variables().empty()); - ASSERT_TRUE(compiler.lists().empty()); -} - -TEST_F(PenBlocksTest, SetPenColorToColorImpl) -{ - static unsigned int bytecode1[] = { vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode2[] = { vm::OP_START, vm::OP_CONST, 1, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode3[] = { vm::OP_START, vm::OP_CONST, 2, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode4[] = { vm::OP_START, vm::OP_CONST, 3, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode5[] = { vm::OP_START, vm::OP_CONST, 4, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode6[] = { vm::OP_START, vm::OP_CONST, 5, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode7[] = { vm::OP_START, vm::OP_CONST, 6, vm::OP_EXEC, 0, vm::OP_HALT }; - static BlockFunc functions[] = { &PenBlocks::setPenColorToColor }; - static Value constValues[] = { "#AABbCC", "#03F", "#FFGFFF", "#AABBCCDD", "FFFFFF", 1228097602, 255 }; - - std::vector> models; - std::vector> targets; - - models.push_back(std::make_shared()); - targets.push_back(std::make_shared()); - static_cast(targets.back().get())->setInterface(static_cast(models.back().get())); - - models.push_back(std::make_shared()); - targets.push_back(std::make_shared()); - static_cast(targets.back().get())->setInterface(static_cast(models.back().get())); - - for (int i = 0; i < targets.size(); i++) { - auto target = targets[i]; - auto model = models[i]; - - VirtualMachine vm(target.get(), &m_engineMock, nullptr); - vm.setBytecode(bytecode1); - vm.setFunctions(functions); - vm.setConstValues(constValues); - - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(210, 42, 204))); - - vm.reset(); - vm.setBytecode(bytecode2); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(228, 255, 255))); - - vm.reset(); - vm.setBytecode(bytecode3); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(359, 0, 0))); - - vm.reset(); - vm.setBytecode(bytecode4); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(359, 0, 0))); - - vm.reset(); - vm.setBytecode(bytecode5); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(359, 0, 0))); - - vm.reset(); - vm.setBytecode(bytecode6); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(162, 74, 72, 73))); - - vm.reset(); - vm.setBytecode(bytecode7); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(239, 255, 255))); - } -} - -TEST_F(PenBlocksTest, ChangePenColorParamBy) -{ - Compiler compiler(&m_engineMock); - - // change pen (color) by (34.6) - auto block1 = std::make_shared("a", "pen_changePenColorParamBy"); - addDropdownInput(block1, "COLOR_PARAM", PenBlocks::COLOR_PARAM, "color"); - addValueInput(block1, "VALUE", PenBlocks::VALUE, 34.6); - - // change pen (saturation) by (46.8) - auto block2 = std::make_shared("b", "pen_changePenColorParamBy"); - addDropdownInput(block2, "COLOR_PARAM", PenBlocks::COLOR_PARAM, "saturation"); - addValueInput(block2, "VALUE", PenBlocks::VALUE, 46.8); - - // change pen (brightness) by (0.45) - auto block3 = std::make_shared("c", "pen_changePenColorParamBy"); - addDropdownInput(block3, "COLOR_PARAM", PenBlocks::COLOR_PARAM, "brightness"); - addValueInput(block3, "VALUE", PenBlocks::VALUE, 0.45); - - // change pen (transparency) by (89.06) - auto block4 = std::make_shared("d", "pen_changePenColorParamBy"); - addDropdownInput(block4, "COLOR_PARAM", PenBlocks::COLOR_PARAM, "transparency"); - addValueInput(block4, "VALUE", PenBlocks::VALUE, 89.06); - - // change pen (invalid param) by (52.7) - auto block5 = std::make_shared("e", "pen_changePenColorParamBy"); - addDropdownInput(block5, "COLOR_PARAM", PenBlocks::COLOR_PARAM, "invalid param"); - addValueInput(block5, "VALUE", PenBlocks::VALUE, 52.7); - - // change pen (null block) by (35.2) - auto block6 = std::make_shared("f", "pen_changePenColorParamBy"); - addDropdownInput(block6, "COLOR_PARAM", PenBlocks::COLOR_PARAM, "", createNullBlock("g")); - addValueInput(block6, "VALUE", PenBlocks::VALUE, 35.2); - - compiler.init(); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::changePenColorBy)).WillOnce(Return(0)); - compiler.setBlock(block1); - PenBlocks::compileChangePenColorParamBy(&compiler); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::changePenSaturationBy)).WillOnce(Return(1)); - compiler.setBlock(block2); - PenBlocks::compileChangePenColorParamBy(&compiler); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::changePenBrightnessBy)).WillOnce(Return(2)); - compiler.setBlock(block3); - PenBlocks::compileChangePenColorParamBy(&compiler); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::changePenTransparencyBy)).WillOnce(Return(3)); - compiler.setBlock(block4); - PenBlocks::compileChangePenColorParamBy(&compiler); - - compiler.setBlock(block5); - PenBlocks::compileChangePenColorParamBy(&compiler); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::changePenColorParamBy)).WillOnce(Return(4)); - compiler.setBlock(block6); - PenBlocks::compileChangePenColorParamBy(&compiler); - - compiler.end(); - - ASSERT_EQ( - compiler.bytecode(), - std::vector( - { vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 0, vm::OP_CONST, 1, vm::OP_EXEC, 1, vm::OP_CONST, 2, vm::OP_EXEC, 2, vm::OP_CONST, 3, vm::OP_EXEC, 3, - vm::OP_NULL, vm::OP_CONST, 4, vm::OP_EXEC, 4, vm::OP_HALT })); - ASSERT_EQ(compiler.constValues(), std::vector({ 34.6, 46.8, 0.45, 89.06, 35.2 })); - ASSERT_TRUE(compiler.variables().empty()); - ASSERT_TRUE(compiler.lists().empty()); -} - -TEST_F(PenBlocksTest, ChangePenColorParamByImpl) -{ - static unsigned int bytecode1[] = { vm::OP_START, vm::OP_CONST, 0, vm::OP_CONST, 5, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode2[] = { vm::OP_START, vm::OP_CONST, 0, vm::OP_CONST, 6, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode3[] = { vm::OP_START, vm::OP_CONST, 1, vm::OP_CONST, 5, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode4[] = { vm::OP_START, vm::OP_CONST, 1, vm::OP_CONST, 6, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode5[] = { vm::OP_START, vm::OP_CONST, 2, vm::OP_CONST, 5, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode6[] = { vm::OP_START, vm::OP_CONST, 2, vm::OP_CONST, 6, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode7[] = { vm::OP_START, vm::OP_CONST, 3, vm::OP_CONST, 5, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode8[] = { vm::OP_START, vm::OP_CONST, 3, vm::OP_CONST, 6, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode9[] = { vm::OP_START, vm::OP_CONST, 4, vm::OP_CONST, 5, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode10[] = { vm::OP_START, vm::OP_CONST, 5, vm::OP_EXEC, 1, vm::OP_HALT }; - static unsigned int bytecode11[] = { vm::OP_START, vm::OP_CONST, 6, vm::OP_EXEC, 1, vm::OP_HALT }; - static unsigned int bytecode12[] = { vm::OP_START, vm::OP_CONST, 5, vm::OP_EXEC, 2, vm::OP_HALT }; - static unsigned int bytecode13[] = { vm::OP_START, vm::OP_CONST, 6, vm::OP_EXEC, 2, vm::OP_HALT }; - static unsigned int bytecode14[] = { vm::OP_START, vm::OP_CONST, 5, vm::OP_EXEC, 3, vm::OP_HALT }; - static unsigned int bytecode15[] = { vm::OP_START, vm::OP_CONST, 6, vm::OP_EXEC, 3, vm::OP_HALT }; - static unsigned int bytecode16[] = { vm::OP_START, vm::OP_CONST, 5, vm::OP_EXEC, 4, vm::OP_HALT }; - static unsigned int bytecode17[] = { vm::OP_START, vm::OP_CONST, 6, vm::OP_EXEC, 4, vm::OP_HALT }; - static BlockFunc - functions[] = { &PenBlocks::changePenColorParamBy, &PenBlocks::changePenColorBy, &PenBlocks::changePenSaturationBy, &PenBlocks::changePenBrightnessBy, &PenBlocks::changePenTransparencyBy }; - static Value constValues[] = { "color", "saturation", "brightness", "transparency", "invalid", 53.2, -120.8 }; - - std::vector> models; - std::vector> targets; - - models.push_back(std::make_shared()); - targets.push_back(std::make_shared()); - static_cast(targets.back().get())->setInterface(static_cast(models.back().get())); - - models.push_back(std::make_shared()); - targets.push_back(std::make_shared()); - static_cast(targets.back().get())->setInterface(static_cast(models.back().get())); - - for (int i = 0; i < targets.size(); i++) { - auto target = targets[i]; - auto model = models[i]; - model->penState().transparency = 100 * (1 - 150 / 255.0); - - VirtualMachine vm(target.get(), &m_engineMock, nullptr); - vm.setBytecode(bytecode1); - vm.setFunctions(functions); - vm.setConstValues(constValues); - - // color - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(71, 255, 255, 150))); - - vm.reset(); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(263, 255, 255, 150))); - - vm.reset(); - vm.setBytecode(bytecode2); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(188, 255, 255, 150))); - - // saturation - model->penState().saturation = 32.4; - vm.reset(); - vm.setBytecode(bytecode3); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(188, 218, 255, 150))); - - vm.reset(); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(188, 255, 255, 150))); - - vm.reset(); - vm.setBytecode(bytecode4); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(188, 0, 255, 150))); - - // brightness - model->penState().brightness = 12.5; - vm.reset(); - vm.setBytecode(bytecode5); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(188, 0, 167, 150))); - - vm.reset(); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(188, 0, 255, 150))); - - vm.reset(); - vm.setBytecode(bytecode6); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(188, 0, 0, 150))); - - // transparency - model->penState().transparency = 6.28; - vm.reset(); - vm.setBytecode(bytecode7); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(188, 0, 0, 103))); - - vm.reset(); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(188, 0, 0, 0))); - - vm.reset(); - vm.setBytecode(bytecode8); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(188, 0, 0, 255))); - - // invalid parameter - vm.reset(); - vm.setBytecode(bytecode9); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(188, 0, 0, 255))); - - // color (optimized) - model->penState() = PenState(); - model->penState().transparency = 100 * (1 - 150 / 255.0); - vm.reset(); - vm.setBytecode(bytecode10); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(71, 255, 255, 150))); - - vm.reset(); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(263, 255, 255, 150))); - - vm.reset(); - vm.setBytecode(bytecode11); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(188, 255, 255, 150))); - - // saturation (optimized) - model->penState().saturation = 32.4; - vm.reset(); - vm.setBytecode(bytecode12); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(188, 218, 255, 150))); - - vm.reset(); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(188, 255, 255, 150))); - - vm.reset(); - vm.setBytecode(bytecode13); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(188, 0, 255, 150))); - - // brightness (optimized) - model->penState().brightness = 12.5; - vm.reset(); - vm.setBytecode(bytecode14); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(188, 0, 167, 150))); - - vm.reset(); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(188, 0, 255, 150))); - - vm.reset(); - vm.setBytecode(bytecode15); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(188, 0, 0, 150))); - - // transparency (optimized) - model->penState().transparency = 6.28; - vm.reset(); - vm.setBytecode(bytecode16); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(188, 0, 0, 103))); - - vm.reset(); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(188, 0, 0, 0))); - - vm.reset(); - vm.setBytecode(bytecode17); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(188, 0, 0, 255))); - } -} - -TEST_F(PenBlocksTest, SetPenColorParamTo) -{ - Compiler compiler(&m_engineMock); - - // set pen (color) to (34.6) - auto block1 = std::make_shared("a", "pen_setPenColorParamTo"); - addDropdownInput(block1, "COLOR_PARAM", PenBlocks::COLOR_PARAM, "color"); - addValueInput(block1, "VALUE", PenBlocks::VALUE, 34.6); - - // set pen (saturation) to (46.8) - auto block2 = std::make_shared("b", "pen_setPenColorParamTo"); - addDropdownInput(block2, "COLOR_PARAM", PenBlocks::COLOR_PARAM, "saturation"); - addValueInput(block2, "VALUE", PenBlocks::VALUE, 46.8); - - // set pen (brightness) to (0.45) - auto block3 = std::make_shared("c", "pen_setPenColorParamTo"); - addDropdownInput(block3, "COLOR_PARAM", PenBlocks::COLOR_PARAM, "brightness"); - addValueInput(block3, "VALUE", PenBlocks::VALUE, 0.45); - - // set pen (transparency) to (89.06) - auto block4 = std::make_shared("d", "pen_setPenColorParamTo"); - addDropdownInput(block4, "COLOR_PARAM", PenBlocks::COLOR_PARAM, "transparency"); - addValueInput(block4, "VALUE", PenBlocks::VALUE, 89.06); - - // set pen (invalid param) to (52.7) - auto block5 = std::make_shared("e", "pen_setPenColorParamTo"); - addDropdownInput(block5, "COLOR_PARAM", PenBlocks::COLOR_PARAM, "invalid param"); - addValueInput(block5, "VALUE", PenBlocks::VALUE, 52.7); - - // set pen (null block) to (35.2) - auto block6 = std::make_shared("f", "pen_setPenColorParamTo"); - addDropdownInput(block6, "COLOR_PARAM", PenBlocks::COLOR_PARAM, "", createNullBlock("g")); - addValueInput(block6, "VALUE", PenBlocks::VALUE, 35.2); - - compiler.init(); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::setPenColorTo)).WillOnce(Return(0)); - compiler.setBlock(block1); - PenBlocks::compileSetPenColorParamTo(&compiler); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::setPenSaturationTo)).WillOnce(Return(1)); - compiler.setBlock(block2); - PenBlocks::compileSetPenColorParamTo(&compiler); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::setPenBrightnessTo)).WillOnce(Return(2)); - compiler.setBlock(block3); - PenBlocks::compileSetPenColorParamTo(&compiler); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::setPenTransparencyTo)).WillOnce(Return(3)); - compiler.setBlock(block4); - PenBlocks::compileSetPenColorParamTo(&compiler); - - compiler.setBlock(block5); - PenBlocks::compileSetPenColorParamTo(&compiler); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::setPenColorParamTo)).WillOnce(Return(4)); - compiler.setBlock(block6); - PenBlocks::compileSetPenColorParamTo(&compiler); - - compiler.end(); - - ASSERT_EQ( - compiler.bytecode(), - std::vector( - { vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 0, vm::OP_CONST, 1, vm::OP_EXEC, 1, vm::OP_CONST, 2, vm::OP_EXEC, 2, vm::OP_CONST, 3, vm::OP_EXEC, 3, - vm::OP_NULL, vm::OP_CONST, 4, vm::OP_EXEC, 4, vm::OP_HALT })); - ASSERT_EQ(compiler.constValues(), std::vector({ 34.6, 46.8, 0.45, 89.06, 35.2 })); - ASSERT_TRUE(compiler.variables().empty()); - ASSERT_TRUE(compiler.lists().empty()); -} - -TEST_F(PenBlocksTest, SetPenColorParamToImpl) -{ - static unsigned int bytecode1[] = { vm::OP_START, vm::OP_CONST, 0, vm::OP_CONST, 5, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode2[] = { vm::OP_START, vm::OP_CONST, 0, vm::OP_CONST, 6, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode3[] = { vm::OP_START, vm::OP_CONST, 0, vm::OP_CONST, 7, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode4[] = { vm::OP_START, vm::OP_CONST, 1, vm::OP_CONST, 5, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode5[] = { vm::OP_START, vm::OP_CONST, 1, vm::OP_CONST, 6, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode6[] = { vm::OP_START, vm::OP_CONST, 1, vm::OP_CONST, 7, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode7[] = { vm::OP_START, vm::OP_CONST, 2, vm::OP_CONST, 5, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode8[] = { vm::OP_START, vm::OP_CONST, 2, vm::OP_CONST, 6, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode9[] = { vm::OP_START, vm::OP_CONST, 2, vm::OP_CONST, 7, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode10[] = { vm::OP_START, vm::OP_CONST, 3, vm::OP_CONST, 5, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode11[] = { vm::OP_START, vm::OP_CONST, 3, vm::OP_CONST, 6, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode12[] = { vm::OP_START, vm::OP_CONST, 3, vm::OP_CONST, 7, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode13[] = { vm::OP_START, vm::OP_CONST, 4, vm::OP_CONST, 5, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode14[] = { vm::OP_START, vm::OP_CONST, 5, vm::OP_EXEC, 1, vm::OP_HALT }; - static unsigned int bytecode15[] = { vm::OP_START, vm::OP_CONST, 6, vm::OP_EXEC, 1, vm::OP_HALT }; - static unsigned int bytecode16[] = { vm::OP_START, vm::OP_CONST, 7, vm::OP_EXEC, 1, vm::OP_HALT }; - static unsigned int bytecode17[] = { vm::OP_START, vm::OP_CONST, 5, vm::OP_EXEC, 2, vm::OP_HALT }; - static unsigned int bytecode18[] = { vm::OP_START, vm::OP_CONST, 6, vm::OP_EXEC, 2, vm::OP_HALT }; - static unsigned int bytecode19[] = { vm::OP_START, vm::OP_CONST, 7, vm::OP_EXEC, 2, vm::OP_HALT }; - static unsigned int bytecode20[] = { vm::OP_START, vm::OP_CONST, 5, vm::OP_EXEC, 3, vm::OP_HALT }; - static unsigned int bytecode21[] = { vm::OP_START, vm::OP_CONST, 6, vm::OP_EXEC, 3, vm::OP_HALT }; - static unsigned int bytecode22[] = { vm::OP_START, vm::OP_CONST, 7, vm::OP_EXEC, 3, vm::OP_HALT }; - static unsigned int bytecode23[] = { vm::OP_START, vm::OP_CONST, 5, vm::OP_EXEC, 4, vm::OP_HALT }; - static unsigned int bytecode24[] = { vm::OP_START, vm::OP_CONST, 6, vm::OP_EXEC, 4, vm::OP_HALT }; - static unsigned int bytecode25[] = { vm::OP_START, vm::OP_CONST, 7, vm::OP_EXEC, 4, vm::OP_HALT }; - static BlockFunc functions[] = { &PenBlocks::setPenColorParamTo, &PenBlocks::setPenColorTo, &PenBlocks::setPenSaturationTo, &PenBlocks::setPenBrightnessTo, &PenBlocks::setPenTransparencyTo }; - static Value constValues[] = { "color", "saturation", "brightness", "transparency", "invalid", 53.2, -234.9, 287.1 }; - - std::vector> models; - std::vector> targets; - - models.push_back(std::make_shared()); - targets.push_back(std::make_shared()); - static_cast(targets.back().get())->setInterface(static_cast(models.back().get())); - - models.push_back(std::make_shared()); - targets.push_back(std::make_shared()); - static_cast(targets.back().get())->setInterface(static_cast(models.back().get())); - - for (int i = 0; i < targets.size(); i++) { - auto target = targets[i]; - auto model = models[i]; - model->penState().color = 78.6; - model->penState().transparency = 100 * (1 - 150 / 255.0); - - VirtualMachine vm(target.get(), &m_engineMock, nullptr); - vm.setBytecode(bytecode1); - vm.setFunctions(functions); - vm.setConstValues(constValues); - - // color - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(191, 255, 255, 150))); - - vm.reset(); - vm.setBytecode(bytecode2); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(234, 255, 255, 150))); - - vm.reset(); - vm.setBytecode(bytecode3); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(313, 255, 255, 150))); - - // saturation - model->penState().saturation = 32.4; - vm.reset(); - vm.setBytecode(bytecode4); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(313, 135, 255, 150))); - - vm.reset(); - vm.setBytecode(bytecode5); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(313, 0, 255, 150))); - - vm.reset(); - vm.setBytecode(bytecode6); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(313, 255, 255, 150))); - - // brightness - model->penState().brightness = 12.5; - vm.reset(); - vm.setBytecode(bytecode7); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(313, 255, 135, 150))); - - vm.reset(); - vm.setBytecode(bytecode8); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(313, 255, 0, 150))); - - vm.reset(); - vm.setBytecode(bytecode9); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(313, 255, 255, 150))); - - // transparency - model->penState().transparency = 12.5; - vm.reset(); - vm.setBytecode(bytecode10); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(313, 255, 255, 119))); - - vm.reset(); - vm.setBytecode(bytecode11); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(313, 255, 255, 255))); - - vm.reset(); - vm.setBytecode(bytecode12); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(313, 255, 255, 0))); - - // invalid parameter - vm.reset(); - vm.setBytecode(bytecode13); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(313, 255, 255, 0))); - - // color (optimized) - model->penState() = PenState(); - model->penState().color = 78.6; - model->penState().transparency = 100 * (1 - 150 / 255.0); - vm.reset(); - vm.setBytecode(bytecode14); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(191, 255, 255, 150))); - - vm.reset(); - vm.setBytecode(bytecode15); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(234, 255, 255, 150))); - - vm.reset(); - vm.setBytecode(bytecode16); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(313, 255, 255, 150))); - - // saturation (optimized) - model->penState().saturation = 32.4; - vm.reset(); - vm.setBytecode(bytecode17); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(313, 135, 255, 150))); - - vm.reset(); - vm.setBytecode(bytecode18); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(313, 0, 255, 150))); - - vm.reset(); - vm.setBytecode(bytecode19); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(313, 255, 255, 150))); - - // brightness (optimized) - model->penState().brightness = 12.5; - vm.reset(); - vm.setBytecode(bytecode20); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(313, 255, 135, 150))); - - vm.reset(); - vm.setBytecode(bytecode21); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(313, 255, 0, 150))); - - vm.reset(); - vm.setBytecode(bytecode22); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(313, 255, 255, 150))); - - // transparency (optimized) - model->penState().transparency = 12.5; - vm.reset(); - vm.setBytecode(bytecode23); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(313, 255, 255, 119))); - - vm.reset(); - vm.setBytecode(bytecode24); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(313, 255, 255, 255))); - - vm.reset(); - vm.setBytecode(bytecode25); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(313, 255, 255, 0))); - } -} - -TEST_F(PenBlocksTest, ChangePenSizeBy) -{ - Compiler compiler(&m_engineMock); - - // change pen size by (4.5) - auto block1 = std::make_shared("a", "pen_changePenSizeBy"); - addValueInput(block1, "SIZE", PenBlocks::SIZE, 4.5); - - // change pen size by (null block) - auto block2 = std::make_shared("b", "pen_changePenSizeBy"); - addObscuredInput(block2, "SIZE", PenBlocks::SIZE, createNullBlock("c")); - - compiler.init(); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::changePenSizeBy)).WillOnce(Return(2)); - compiler.setBlock(block1); - PenBlocks::compileChangePenSizeBy(&compiler); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::changePenSizeBy)).WillOnce(Return(2)); - compiler.setBlock(block2); - PenBlocks::compileChangePenSizeBy(&compiler); - - compiler.end(); - - ASSERT_EQ(compiler.bytecode(), std::vector({ vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 2, vm::OP_NULL, vm::OP_EXEC, 2, vm::OP_HALT })); - ASSERT_EQ(compiler.constValues().size(), 1); - ASSERT_EQ(compiler.constValues()[0].toDouble(), 4.5); - ASSERT_TRUE(compiler.variables().empty()); - ASSERT_TRUE(compiler.lists().empty()); -} - -TEST_F(PenBlocksTest, ChangePenSizeByImpl) -{ - static unsigned int bytecode1[] = { vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode2[] = { vm::OP_START, vm::OP_CONST, 1, vm::OP_EXEC, 0, vm::OP_HALT }; - static BlockFunc functions[] = { &PenBlocks::changePenSizeBy }; - static Value constValues[] = { 511.5, -650.08 }; - - std::vector> models; - std::vector> targets; - - models.push_back(std::make_shared()); - targets.push_back(std::make_shared()); - static_cast(targets.back().get())->setInterface(static_cast(models.back().get())); - - models.push_back(std::make_shared()); - targets.push_back(std::make_shared()); - static_cast(targets.back().get())->setInterface(static_cast(models.back().get())); - - for (int i = 0; i < targets.size(); i++) { - auto target = targets[i]; - auto model = models[i]; - - VirtualMachine vm(target.get(), &m_engineMock, nullptr); - vm.setBytecode(bytecode1); - vm.setFunctions(functions); - vm.setConstValues(constValues); - - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().diameter, 512.5); - - vm.reset(); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().diameter, 1024); - - vm.reset(); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().diameter, 1200); - - vm.reset(); - vm.setBytecode(bytecode2); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().diameter, 549.92); - - vm.reset(); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().diameter, 1); - } -} - -TEST_F(PenBlocksTest, SetPenSizeTo) -{ - Compiler compiler(&m_engineMock); - - // set pen size to (51.46) - auto block1 = std::make_shared("a", "pen_setPenSizeTo"); - addValueInput(block1, "SIZE", PenBlocks::SIZE, 51.46); - - // set pen size to (null block) - auto block2 = std::make_shared("b", "pen_setPenSizeTo"); - addObscuredInput(block2, "SIZE", PenBlocks::SIZE, createNullBlock("c")); - - compiler.init(); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::setPenSizeTo)).WillOnce(Return(2)); - compiler.setBlock(block1); - PenBlocks::compileSetPenSizeTo(&compiler); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::setPenSizeTo)).WillOnce(Return(2)); - compiler.setBlock(block2); - PenBlocks::compileSetPenSizeTo(&compiler); - - compiler.end(); - - ASSERT_EQ(compiler.bytecode(), std::vector({ vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 2, vm::OP_NULL, vm::OP_EXEC, 2, vm::OP_HALT })); - ASSERT_EQ(compiler.constValues().size(), 1); - ASSERT_EQ(compiler.constValues()[0].toDouble(), 51.46); - ASSERT_TRUE(compiler.variables().empty()); - ASSERT_TRUE(compiler.lists().empty()); -} - -TEST_F(PenBlocksTest, SetPenSizeToImpl) -{ - static unsigned int bytecode1[] = { vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode2[] = { vm::OP_START, vm::OP_CONST, 1, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode3[] = { vm::OP_START, vm::OP_CONST, 2, vm::OP_EXEC, 0, vm::OP_HALT }; - static BlockFunc functions[] = { &PenBlocks::setPenSizeTo }; - static Value constValues[] = { 511.5, -650.08, 1500 }; - - std::vector> models; - std::vector> targets; - - models.push_back(std::make_shared()); - targets.push_back(std::make_shared()); - static_cast(targets.back().get())->setInterface(static_cast(models.back().get())); - - models.push_back(std::make_shared()); - targets.push_back(std::make_shared()); - static_cast(targets.back().get())->setInterface(static_cast(models.back().get())); - - for (int i = 0; i < targets.size(); i++) { - auto target = targets[i]; - auto model = models[i]; - - VirtualMachine vm(target.get(), &m_engineMock, nullptr); - vm.setBytecode(bytecode1); - vm.setFunctions(functions); - vm.setConstValues(constValues); - - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().diameter, 511.5); - - vm.reset(); - vm.setBytecode(bytecode2); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().diameter, 1); - - vm.reset(); - vm.setBytecode(bytecode3); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().diameter, 1200); - } -} - -TEST_F(PenBlocksTest, ChangePenShadeBy) -{ - Compiler compiler(&m_engineMock); - - // change pen shade by (4.5) - auto block1 = std::make_shared("a", "pen_changePenShadeBy"); - addValueInput(block1, "SHADE", PenBlocks::SHADE, 4.5); - - // change pen shade by (null block) - auto block2 = std::make_shared("b", "pen_changePenShadeBy"); - addObscuredInput(block2, "SHADE", PenBlocks::SHADE, createNullBlock("c")); - - compiler.init(); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::changePenShadeBy)).WillOnce(Return(2)); - compiler.setBlock(block1); - PenBlocks::compileChangePenShadeBy(&compiler); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::changePenShadeBy)).WillOnce(Return(2)); - compiler.setBlock(block2); - PenBlocks::compileChangePenShadeBy(&compiler); - - compiler.end(); - - ASSERT_EQ(compiler.bytecode(), std::vector({ vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 2, vm::OP_NULL, vm::OP_EXEC, 2, vm::OP_HALT })); - ASSERT_EQ(compiler.constValues().size(), 1); - ASSERT_EQ(compiler.constValues()[0].toDouble(), 4.5); - ASSERT_TRUE(compiler.variables().empty()); - ASSERT_TRUE(compiler.lists().empty()); -} - -TEST_F(PenBlocksTest, ChangePenShadeByImpl) -{ - static unsigned int bytecode1[] = { vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode2[] = { vm::OP_START, vm::OP_CONST, 1, vm::OP_EXEC, 0, vm::OP_HALT }; - static BlockFunc functions[] = { &PenBlocks::changePenShadeBy }; - static Value constValues[] = { 134.09, -124.45 }; - - std::vector> models; - std::vector> targets; - - models.push_back(std::make_shared()); - targets.push_back(std::make_shared()); - static_cast(targets.back().get())->setInterface(static_cast(models.back().get())); - - models.push_back(std::make_shared()); - targets.push_back(std::make_shared()); - static_cast(targets.back().get())->setInterface(static_cast(models.back().get())); - - for (int i = 0; i < targets.size(); i++) { - auto target = targets[i]; - auto model = models[i]; - model->penState().transparency = 100 * (1 - 150 / 255.0); - - VirtualMachine vm(target.get(), &m_engineMock, nullptr); - vm.setBytecode(bytecode1); - vm.setFunctions(functions); - vm.setConstValues(constValues); - - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(240, 255, 110, 150))); - - vm.reset(); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(240, 119, 255, 150))); - - vm.reset(); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(240, 247, 255, 150))); - - vm.reset(); - vm.setBytecode(bytecode2); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(240, 162, 255, 150))); - - vm.reset(); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(240, 255, 55, 150))); - } -} - -TEST_F(PenBlocksTest, SetPenShadeToNumber) -{ - Compiler compiler(&m_engineMock); - - // set pen shade to (4.5) - auto block1 = std::make_shared("a", "pen_setPenShadeToNumber"); - addValueInput(block1, "SHADE", PenBlocks::SHADE, 4.5); - - // set pen shade to (null block) - auto block2 = std::make_shared("b", "pen_setPenShadeToNumber"); - addObscuredInput(block2, "SHADE", PenBlocks::SHADE, createNullBlock("c")); - - compiler.init(); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::setPenShadeToNumber)).WillOnce(Return(2)); - compiler.setBlock(block1); - PenBlocks::compileSetPenShadeToNumber(&compiler); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::setPenShadeToNumber)).WillOnce(Return(2)); - compiler.setBlock(block2); - PenBlocks::compileSetPenShadeToNumber(&compiler); - - compiler.end(); - - ASSERT_EQ(compiler.bytecode(), std::vector({ vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 2, vm::OP_NULL, vm::OP_EXEC, 2, vm::OP_HALT })); - ASSERT_EQ(compiler.constValues().size(), 1); - ASSERT_EQ(compiler.constValues()[0].toDouble(), 4.5); - ASSERT_TRUE(compiler.variables().empty()); - ASSERT_TRUE(compiler.lists().empty()); -} - -TEST_F(PenBlocksTest, SetPenShadeToNumberImpl) -{ - static unsigned int bytecode1[] = { vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode2[] = { vm::OP_START, vm::OP_CONST, 1, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode3[] = { vm::OP_START, vm::OP_CONST, 2, vm::OP_EXEC, 0, vm::OP_HALT }; - static BlockFunc functions[] = { &PenBlocks::setPenShadeToNumber }; - static Value constValues[] = { 125.7, -114.09, 489.4 }; - - std::vector> models; - std::vector> targets; - - models.push_back(std::make_shared()); - targets.push_back(std::make_shared()); - static_cast(targets.back().get())->setInterface(static_cast(models.back().get())); - - models.push_back(std::make_shared()); - targets.push_back(std::make_shared()); - static_cast(targets.back().get())->setInterface(static_cast(models.back().get())); - - for (int i = 0; i < targets.size(); i++) { - auto target = targets[i]; - auto model = models[i]; - model->penState().transparency = 100 * (1 - 150 / 255.0); - - VirtualMachine vm(target.get(), &m_engineMock, nullptr); - vm.setBytecode(bytecode1); - vm.setFunctions(functions); - vm.setConstValues(constValues); - - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(240, 148, 253, 150))); - - vm.reset(); - vm.setBytecode(bytecode2); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(240, 102, 255, 150))); - - vm.reset(); - vm.setBytecode(bytecode3); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(240, 89, 255, 150))); - } -} - -TEST_F(PenBlocksTest, ChangePenHueBy) -{ - Compiler compiler(&m_engineMock); - - // change pen hue by (4.5) - auto block1 = std::make_shared("a", "pen_changePenHueBy"); - addValueInput(block1, "HUE", PenBlocks::HUE, 4.5); - - // change pen hue by (null block) - auto block2 = std::make_shared("b", "pen_changePenHueBy"); - addObscuredInput(block2, "HUE", PenBlocks::HUE, createNullBlock("c")); - - compiler.init(); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::changePenHueBy)).WillOnce(Return(2)); - compiler.setBlock(block1); - PenBlocks::compileChangePenHueBy(&compiler); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::changePenHueBy)).WillOnce(Return(2)); - compiler.setBlock(block2); - PenBlocks::compileChangePenHueBy(&compiler); - - compiler.end(); - - ASSERT_EQ(compiler.bytecode(), std::vector({ vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 2, vm::OP_NULL, vm::OP_EXEC, 2, vm::OP_HALT })); - ASSERT_EQ(compiler.constValues().size(), 1); - ASSERT_EQ(compiler.constValues()[0].toDouble(), 4.5); - ASSERT_TRUE(compiler.variables().empty()); - ASSERT_TRUE(compiler.lists().empty()); -} - -TEST_F(PenBlocksTest, ChangePenHueByImpl) -{ - static unsigned int bytecode1[] = { vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode2[] = { vm::OP_START, vm::OP_CONST, 1, vm::OP_EXEC, 0, vm::OP_HALT }; - static BlockFunc functions[] = { &PenBlocks::changePenHueBy }; - static Value constValues[] = { 125.7, -114.09 }; - - std::vector> models; - std::vector> targets; - - models.push_back(std::make_shared()); - targets.push_back(std::make_shared()); - static_cast(targets.back().get())->setInterface(static_cast(models.back().get())); - - models.push_back(std::make_shared()); - targets.push_back(std::make_shared()); - static_cast(targets.back().get())->setInterface(static_cast(models.back().get())); - - for (int i = 0; i < targets.size(); i++) { - auto target = targets[i]; - auto model = models[i]; - model->penState().transparency = 100 * (1 - 150 / 255.0); - - VirtualMachine vm(target.get(), &m_engineMock, nullptr); - vm.setBytecode(bytecode1); - vm.setFunctions(functions); - vm.setConstValues(constValues); - - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(106, 255, 255, 150))); - - vm.reset(); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(332, 255, 255, 150))); - - vm.reset(); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(199, 255, 255, 150))); - - vm.reset(); - vm.setBytecode(bytecode2); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(353, 255, 255, 150))); - - vm.reset(); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(148, 255, 255, 150))); - } -} - -TEST_F(PenBlocksTest, SetPenHueToNumber) -{ - Compiler compiler(&m_engineMock); - - // set pen hue to (54.09) - auto block1 = std::make_shared("a", "pen_setPenHueToNumber"); - addValueInput(block1, "HUE", PenBlocks::HUE, 54.09); - - // set pen hue to (null block) - auto block2 = std::make_shared("b", "pen_setPenHueToNumber"); - addObscuredInput(block2, "HUE", PenBlocks::HUE, createNullBlock("c")); - - compiler.init(); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::setPenHueToNumber)).WillOnce(Return(2)); - compiler.setBlock(block1); - PenBlocks::compileSetPenHueToNumber(&compiler); - - EXPECT_CALL(m_engineMock, functionIndex(&PenBlocks::setPenHueToNumber)).WillOnce(Return(2)); - compiler.setBlock(block2); - PenBlocks::compileSetPenHueToNumber(&compiler); - - compiler.end(); - - ASSERT_EQ(compiler.bytecode(), std::vector({ vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 2, vm::OP_NULL, vm::OP_EXEC, 2, vm::OP_HALT })); - ASSERT_EQ(compiler.constValues().size(), 1); - ASSERT_EQ(compiler.constValues()[0].toDouble(), 54.09); - ASSERT_TRUE(compiler.variables().empty()); - ASSERT_TRUE(compiler.lists().empty()); -} - -TEST_F(PenBlocksTest, SetPenHueToNumberImpl) -{ - static unsigned int bytecode1[] = { vm::OP_START, vm::OP_CONST, 0, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode2[] = { vm::OP_START, vm::OP_CONST, 1, vm::OP_EXEC, 0, vm::OP_HALT }; - static unsigned int bytecode3[] = { vm::OP_START, vm::OP_CONST, 2, vm::OP_EXEC, 0, vm::OP_HALT }; - static BlockFunc functions[] = { &PenBlocks::setPenHueToNumber }; - static Value constValues[] = { 125.7, -114.09, 489.4 }; - - std::vector> models; - std::vector> targets; - - models.push_back(std::make_shared()); - targets.push_back(std::make_shared()); - static_cast(targets.back().get())->setInterface(static_cast(models.back().get())); - - models.push_back(std::make_shared()); - targets.push_back(std::make_shared()); - static_cast(targets.back().get())->setInterface(static_cast(models.back().get())); - - for (int i = 0; i < targets.size(); i++) { - auto target = targets[i]; - auto model = models[i]; - model->penState().transparency = 100 * (1 - 150 / 255.0); - - VirtualMachine vm(target.get(), &m_engineMock, nullptr); - vm.setBytecode(bytecode1); - vm.setFunctions(functions); - vm.setConstValues(constValues); - - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(226, 255, 255, 255))); - - vm.reset(); - vm.setBytecode(bytecode2); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(154, 255, 255, 255))); - - vm.reset(); - vm.setBytecode(bytecode3); - vm.run(); - ASSERT_EQ(vm.registerCount(), 0); - ASSERT_EQ(model->penAttributes().color, QNanoColor::fromQColor(QColor::fromHsv(160, 255, 255, 255))); - } -} diff --git a/test/lines.png b/test/lines.png index 245885e..5792818 100644 Binary files a/test/lines.png and b/test/lines.png differ diff --git a/test/lines_hq.png b/test/lines_hq.png index c78d1d3..2cdc7e7 100644 Binary files a/test/lines_hq.png and b/test/lines_hq.png differ diff --git a/test/mocks/enginemock.h b/test/mocks/enginemock.h index 5a9714e..8f63633 100644 --- a/test/mocks/enginemock.h +++ b/test/mocks/enginemock.h @@ -8,7 +8,7 @@ using namespace libscratchcpp; namespace scratchcpprender { -using ScriptMap = std::unordered_map, std::shared_ptr