Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions include/scratchcpp/ispritehandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,10 @@ class LIBSCRATCHCPP_EXPORT ISpriteHandler
virtual bool touchingPoint(double x, double y) const = 0;

/*! Used to check whether the sprite touches the given color. */
virtual bool touchingColor(const Value &color) const = 0;
virtual bool touchingColor(Rgb color) const = 0;

/*! Used to check whether the mask part of the sprite touches the given color. */
virtual bool touchingColor(const Value &color, const Value &mask) const = 0;
virtual bool touchingColor(Rgb color, Rgb mask) const = 0;
};

} // namespace libscratchcpp
4 changes: 2 additions & 2 deletions include/scratchcpp/istagehandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ class LIBSCRATCHCPP_EXPORT IStageHandler
virtual bool touchingPoint(double x, double y) const = 0;

/*! Used to check whether the stage touches the given color. */
virtual bool touchingColor(const Value &color) const = 0;
virtual bool touchingColor(Rgb color) const = 0;

/*! Used to check whether the mask part of the stage touches the given color. */
virtual bool touchingColor(const Value &color, const Value &mask) const = 0;
virtual bool touchingColor(Rgb color, Rgb mask) const = 0;
};

} // namespace libscratchcpp
4 changes: 2 additions & 2 deletions include/scratchcpp/sprite.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ class LIBSCRATCHCPP_EXPORT Sprite
void keepInFence(double newX, double newY, double *fencedX, double *fencedY) const;

bool touchingPoint(double x, double y) const override;
bool touchingColor(const Value &color) const override;
bool touchingColor(const Value &color, const Value &mask) const override;
bool touchingColor(Rgb color) const override;
bool touchingColor(Rgb color, Rgb mask) const override;

void setGraphicsEffectValue(IGraphicsEffect *effect, double value) override;

Expand Down
4 changes: 2 additions & 2 deletions include/scratchcpp/stage.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ class LIBSCRATCHCPP_EXPORT Stage : public Target
Rect fastBoundingRect() const override;

bool touchingPoint(double x, double y) const override;
bool touchingColor(const Value &color) const override;
bool touchingColor(const Value &color, const Value &mask) const override;
bool touchingColor(Rgb color) const override;
bool touchingColor(Rgb color, Rgb mask) const override;

void setGraphicsEffectValue(IGraphicsEffect *effect, double value) override;

Expand Down
6 changes: 3 additions & 3 deletions include/scratchcpp/target.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#pragma once

#include <vector>
#include <scratchcpp/value_functions.h>

#include "drawable.h"
#include "rect.h"
Expand All @@ -12,7 +13,6 @@ namespace libscratchcpp
{

class Variable;
struct ValueData;
class List;
class Block;
class Comment;
Expand Down Expand Up @@ -97,8 +97,8 @@ class LIBSCRATCHCPP_EXPORT Target : public Drawable
bool touchingSprite(Sprite *sprite) const;
virtual bool touchingPoint(double x, double y) const;
bool touchingEdge() const;
virtual bool touchingColor(const Value &color) const;
virtual bool touchingColor(const Value &color, const Value &mask) const;
virtual bool touchingColor(Rgb color) const;
virtual bool touchingColor(Rgb color, Rgb mask) const;

double graphicsEffectValue(IGraphicsEffect *effect) const;
virtual void setGraphicsEffectValue(IGraphicsEffect *effect, double value);
Expand Down
3 changes: 3 additions & 0 deletions include/scratchcpp/value.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ class LIBSCRATCHCPP_EXPORT Value
return ret;
}

/*! Converts the value to an RGBA quadruplet. */
Rgb toRgba() const { return value_toRgba(&m_data); }

/*! Adds the given value to the value. */
void add(const Value &v) { value_add(&m_data, &v.m_data, &m_data); }

Expand Down
40 changes: 40 additions & 0 deletions include/scratchcpp/value_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,45 @@
namespace libscratchcpp
{

/*! A typedef for unsigned int. Holds the RGBA values. */
using Rgb = unsigned int;

/*! Returns the red component of the quadruplet rgb. */
inline constexpr int red(Rgb rgb)
{
return ((rgb >> 16) & 0xff);
}

/*! Returns the green component of the quadruplet rgb. */
inline constexpr int green(Rgb rgb)
{
return ((rgb >> 8) & 0xff);
}

/*! Returns the blue component of the quadruplet rgb. */
inline constexpr int blue(Rgb rgb)
{
return (rgb & 0xff);
}

/*! Returns the alpha component of the quadruplet rgb. */
inline constexpr int alpha(Rgb rgb)
{
return rgb >> 24;
}

/*! Creates an RGB triplet from the given color components. */
inline constexpr Rgb rgb(int r, int g, int b)
{
return (0xffu << 24) | ((r & 0xffu) << 16) | ((g & 0xffu) << 8) | (b & 0xffu);
}

/*! Creates an RGBA quadruplet from the given color components. */
inline constexpr Rgb rgba(int r, int g, int b, int a)
{
return ((a & 0xffu) << 24) | ((r & 0xffu) << 16) | ((g & 0xffu) << 8) | (b & 0xffu);
}

extern "C"
{
LIBSCRATCHCPP_EXPORT void value_free(ValueData *v);
Expand Down Expand Up @@ -33,6 +72,7 @@ extern "C"
LIBSCRATCHCPP_EXPORT void value_toString(const ValueData *v, std::string *dst);
LIBSCRATCHCPP_EXPORT char *value_toCString(const ValueData *v);
LIBSCRATCHCPP_EXPORT void value_toUtf16(const ValueData *v, std::u16string *dst);
LIBSCRATCHCPP_EXPORT Rgb value_toRgba(const ValueData *v);

LIBSCRATCHCPP_EXPORT bool value_doubleIsInt(double v);

Expand Down
4 changes: 2 additions & 2 deletions src/blocks/sensingblocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -538,13 +538,13 @@ unsigned int SensingBlocks::touchingEdge(VirtualMachine *vm)

unsigned int SensingBlocks::touchingColor(VirtualMachine *vm)
{
vm->replaceReturnValue(vm->target()->touchingColor(*vm->getInput(0, 1)), 1);
vm->replaceReturnValue(vm->target()->touchingColor(vm->getInput(0, 1)->toRgba()), 1);
return 0;
}

unsigned int SensingBlocks::colorIsTouchingColor(VirtualMachine *vm)
{
vm->replaceReturnValue(vm->target()->touchingColor(*vm->getInput(0, 2), *vm->getInput(1, 2)), 2);
vm->replaceReturnValue(vm->target()->touchingColor(vm->getInput(0, 2)->toRgba(), vm->getInput(1, 2)->toRgba()), 2);
return 1;
}

Expand Down
4 changes: 2 additions & 2 deletions src/scratch/sprite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ bool Sprite::touchingPoint(double x, double y) const
}

/*! Overrides Target#touchingColor(). */
bool Sprite::touchingColor(const Value &color) const
bool Sprite::touchingColor(Rgb color) const
{
if (!impl->iface)
return false;
Expand All @@ -513,7 +513,7 @@ bool Sprite::touchingColor(const Value &color) const
}

/*! Overrides Target#touchingColor(). */
bool Sprite::touchingColor(const Value &color, const Value &mask) const
bool Sprite::touchingColor(Rgb color, Rgb mask) const
{
if (!impl->iface)
return false;
Expand Down
4 changes: 2 additions & 2 deletions src/scratch/stage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ bool Stage::touchingPoint(double x, double y) const
}

/*! Overrides Target#touchingColor(). */
bool Stage::touchingColor(const Value &color) const
bool Stage::touchingColor(Rgb color) const
{
if (!impl->iface)
return false;
Expand All @@ -195,7 +195,7 @@ bool Stage::touchingColor(const Value &color) const
}

/*! Overrides Target#touchingColor(). */
bool Stage::touchingColor(const Value &color, const Value &mask) const
bool Stage::touchingColor(Rgb color, Rgb mask) const
{
if (!impl->iface)
return false;
Expand Down
4 changes: 2 additions & 2 deletions src/scratch/target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -588,13 +588,13 @@ bool Target::touchingEdge() const
}

/*! Returns true if the Target is touching the given color (RGB triplet). */
bool Target::touchingColor(const Value &color) const
bool Target::touchingColor(Rgb color) const
{
return false;
}

/*! Returns true if the mask part of the Target is touching the given color (RGB triplet). */
bool Target::touchingColor(const Value &color, const Value &mask) const
bool Target::touchingColor(Rgb color, Rgb mask) const
{
return false;
}
Expand Down
57 changes: 57 additions & 0 deletions src/scratch/value_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,63 @@ extern "C"
dst->assign(utf8::utf8to16(s));
}

/*! Returns the RGBA quadruplet from the given color value. */
Rgb value_toRgba(const ValueData *v)
{
// https://github.com/scratchfoundation/scratch-vm/blob/112989da0e7306eeb405a5c52616e41c2164af24/src/util/cast.js#L92-L103
char *string = nullptr;
size_t stringLen = 0;

if (v->type == ValueType::Number)
return v->numberValue;
else if (v->type == ValueType::String) {
string = value_toCString(v);
stringLen = strlen(string);
} else if (v->type == ValueType::Bool)
return v->boolValue;

if (stringLen > 0 && string[0] == '#') {
// https://github.com/scratchfoundation/scratch-vm/blob/a4f095db5e03e072ba222fe721eeeb543c9b9c15/src/util/color.js#L60-L69
// (this implementation avoids regex)

// Handle shorthand hex (e.g., "abc" -> "aabbcc")
char expandedHex[7] = { 0 };
char *ptr;

if (stringLen == 4) {
expandedHex[0] = string[1];
expandedHex[1] = string[1];
expandedHex[2] = string[2];
expandedHex[3] = string[2];
expandedHex[4] = string[3];
expandedHex[5] = string[3];
ptr = expandedHex;
} else if (stringLen == 7)
ptr = string + 1; // skip '#'
else {
free(string);
return rgb(0, 0, 0);
}

// Convert hex components to integers
int r, g, b;

if (std::sscanf(ptr, "%2x%2x%2x", &r, &g, &b) == 3) {
free(string);
return rgb(r, g, b);
}

free(string);
} else if (stringLen > 0) {
const double ret = value_stringToDouble(string);
free(string);
return ret;
} else if (string)
free(string);

return rgb(0, 0, 0);
}

/*! Returns true if the given number represents a round integer. */
bool value_doubleIsInt(double v)
{
Expand Down
16 changes: 8 additions & 8 deletions test/blocks/sensing_blocks_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,29 +422,29 @@ TEST_F(SensingBlocksTest, TouchingColorImpl)
vm.setFunctions(functions);
vm.setConstValues(constValues);

EXPECT_CALL(target, touchingColor(constValues[0])).WillOnce(Return(false));
EXPECT_CALL(target, touchingColor(constValues[0].toRgba())).WillOnce(Return(false));
vm.setBytecode(bytecode1);
vm.run();

ASSERT_EQ(vm.registerCount(), 1);
ASSERT_FALSE(vm.getInput(0, 1)->toBool());

EXPECT_CALL(target, touchingColor(constValues[0])).WillOnce(Return(true));
EXPECT_CALL(target, touchingColor(constValues[0].toRgba())).WillOnce(Return(true));
vm.reset();
vm.run();

ASSERT_EQ(vm.registerCount(), 1);
ASSERT_TRUE(vm.getInput(0, 1)->toBool());

EXPECT_CALL(target, touchingColor(constValues[1])).WillOnce(Return(false));
EXPECT_CALL(target, touchingColor(constValues[1].toRgba())).WillOnce(Return(false));
vm.reset();
vm.setBytecode(bytecode2);
vm.run();

ASSERT_EQ(vm.registerCount(), 1);
ASSERT_FALSE(vm.getInput(0, 1)->toBool());

EXPECT_CALL(target, touchingColor(constValues[1])).WillOnce(Return(true));
EXPECT_CALL(target, touchingColor(constValues[1].toRgba())).WillOnce(Return(true));
vm.reset();
vm.run();

Expand Down Expand Up @@ -495,29 +495,29 @@ TEST_F(SensingBlocksTest, ColorIsTouchingColorImpl)
vm.setFunctions(functions);
vm.setConstValues(constValues);

EXPECT_CALL(target, touchingColor(constValues[0], constValues[1])).WillOnce(Return(false));
EXPECT_CALL(target, touchingColor(constValues[0].toRgba(), constValues[1].toRgba())).WillOnce(Return(false));
vm.setBytecode(bytecode1);
vm.run();

ASSERT_EQ(vm.registerCount(), 1);
ASSERT_FALSE(vm.getInput(0, 1)->toBool());

EXPECT_CALL(target, touchingColor(constValues[0], constValues[1])).WillOnce(Return(true));
EXPECT_CALL(target, touchingColor(constValues[0].toRgba(), constValues[1].toRgba())).WillOnce(Return(true));
vm.reset();
vm.run();

ASSERT_EQ(vm.registerCount(), 1);
ASSERT_TRUE(vm.getInput(0, 1)->toBool());

EXPECT_CALL(target, touchingColor(constValues[2], constValues[3])).WillOnce(Return(false));
EXPECT_CALL(target, touchingColor(constValues[2].toRgba(), constValues[3].toRgba())).WillOnce(Return(false));
vm.reset();
vm.setBytecode(bytecode2);
vm.run();

ASSERT_EQ(vm.registerCount(), 1);
ASSERT_FALSE(vm.getInput(0, 1)->toBool());

EXPECT_CALL(target, touchingColor(constValues[2], constValues[3])).WillOnce(Return(true));
EXPECT_CALL(target, touchingColor(constValues[2].toRgba(), constValues[3].toRgba())).WillOnce(Return(true));
vm.reset();
vm.run();

Expand Down
4 changes: 2 additions & 2 deletions test/mocks/spritehandlermock.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ class SpriteHandlerMock : public ISpriteHandler

MOCK_METHOD(bool, touchingClones, (const std::vector<Sprite *> &), (const, override));
MOCK_METHOD(bool, touchingPoint, (double, double), (const, override));
MOCK_METHOD(bool, touchingColor, (const Value &), (const, override));
MOCK_METHOD(bool, touchingColor, (const Value &, const Value &), (const, override));
MOCK_METHOD(bool, touchingColor, (Rgb), (const, override));
MOCK_METHOD(bool, touchingColor, (Rgb, Rgb), (const, override));
};
4 changes: 2 additions & 2 deletions test/mocks/stagehandlermock.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ class StageHandlerMock : public IStageHandler

MOCK_METHOD(bool, touchingClones, (const std::vector<Sprite *> &), (const, override));
MOCK_METHOD(bool, touchingPoint, (double, double), (const, override));
MOCK_METHOD(bool, touchingColor, (const Value &), (const, override));
MOCK_METHOD(bool, touchingColor, (const Value &, const Value &), (const, override));
MOCK_METHOD(bool, touchingColor, (Rgb), (const, override));
MOCK_METHOD(bool, touchingColor, (Rgb, Rgb), (const, override));
};
4 changes: 2 additions & 2 deletions test/mocks/targetmock.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ class TargetMock : public Target

MOCK_METHOD(bool, touchingPoint, (double, double), (const, override));

MOCK_METHOD(bool, touchingColor, (const Value &), (const, override));
MOCK_METHOD(bool, touchingColor, (const Value &, const Value &), (const, override));
MOCK_METHOD(bool, touchingColor, (Rgb), (const, override));
MOCK_METHOD(bool, touchingColor, (Rgb, Rgb), (const, override));

MOCK_METHOD(void, setGraphicsEffectValue, (IGraphicsEffect *, double), (override));
MOCK_METHOD(void, clearGraphicsEffects, (), (override));
Expand Down
19 changes: 10 additions & 9 deletions test/scratch_classes/sprite_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -834,18 +834,19 @@ TEST(SpriteTest, TouchingColor)
EXPECT_CALL(iface, init);
sprite.setInterface(&iface);

Value v1 = 4278228630, v2 = "#FF00FA";
EXPECT_CALL(iface, touchingColor(v1)).WillOnce(Return(false));
ASSERT_FALSE(sprite.touchingColor(v1));
Rgb c1 = Value(4278228630).toRgba();
Rgb c2 = Value("#FF00FA").toRgba();
EXPECT_CALL(iface, touchingColor(c1)).WillOnce(Return(false));
ASSERT_FALSE(sprite.touchingColor(c1));

EXPECT_CALL(iface, touchingColor(v2)).WillOnce(Return(true));
ASSERT_TRUE(sprite.touchingColor(v2));
EXPECT_CALL(iface, touchingColor(c2)).WillOnce(Return(true));
ASSERT_TRUE(sprite.touchingColor(c2));

EXPECT_CALL(iface, touchingColor(v1, v2)).WillOnce(Return(false));
ASSERT_FALSE(sprite.touchingColor(v1, v2));
EXPECT_CALL(iface, touchingColor(c1, c2)).WillOnce(Return(false));
ASSERT_FALSE(sprite.touchingColor(c1, c2));

EXPECT_CALL(iface, touchingColor(v2, v1)).WillOnce(Return(true));
ASSERT_TRUE(sprite.touchingColor(v2, v1));
EXPECT_CALL(iface, touchingColor(c2, c1)).WillOnce(Return(true));
ASSERT_TRUE(sprite.touchingColor(c2, c1));
}

TEST(SpriteTest, GraphicsEffects)
Expand Down
Loading
Loading