diff --git a/include/scratchcpp/ispritehandler.h b/include/scratchcpp/ispritehandler.h index d8a61a68..e423f960 100644 --- a/include/scratchcpp/ispritehandler.h +++ b/include/scratchcpp/ispritehandler.h @@ -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 diff --git a/include/scratchcpp/istagehandler.h b/include/scratchcpp/istagehandler.h index b6cf7f50..b417ec32 100644 --- a/include/scratchcpp/istagehandler.h +++ b/include/scratchcpp/istagehandler.h @@ -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 diff --git a/include/scratchcpp/sprite.h b/include/scratchcpp/sprite.h index f2f7d517..e62f50c5 100644 --- a/include/scratchcpp/sprite.h +++ b/include/scratchcpp/sprite.h @@ -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; diff --git a/include/scratchcpp/stage.h b/include/scratchcpp/stage.h index 3a0df955..274c56ba 100644 --- a/include/scratchcpp/stage.h +++ b/include/scratchcpp/stage.h @@ -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; diff --git a/include/scratchcpp/target.h b/include/scratchcpp/target.h index 20d1a389..523b70b9 100644 --- a/include/scratchcpp/target.h +++ b/include/scratchcpp/target.h @@ -3,6 +3,7 @@ #pragma once #include +#include #include "drawable.h" #include "rect.h" @@ -12,7 +13,6 @@ namespace libscratchcpp { class Variable; -struct ValueData; class List; class Block; class Comment; @@ -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); diff --git a/include/scratchcpp/value.h b/include/scratchcpp/value.h index 96c781f3..7f0c6a54 100644 --- a/include/scratchcpp/value.h +++ b/include/scratchcpp/value.h @@ -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); } diff --git a/include/scratchcpp/value_functions.h b/include/scratchcpp/value_functions.h index 1542d2b9..2a8a2217 100644 --- a/include/scratchcpp/value_functions.h +++ b/include/scratchcpp/value_functions.h @@ -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); @@ -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); diff --git a/src/blocks/sensingblocks.cpp b/src/blocks/sensingblocks.cpp index a1ef1c55..af1349ed 100644 --- a/src/blocks/sensingblocks.cpp +++ b/src/blocks/sensingblocks.cpp @@ -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; } diff --git a/src/scratch/sprite.cpp b/src/scratch/sprite.cpp index 9ca3347a..b755ca26 100644 --- a/src/scratch/sprite.cpp +++ b/src/scratch/sprite.cpp @@ -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; @@ -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; diff --git a/src/scratch/stage.cpp b/src/scratch/stage.cpp index 3a755886..124e6ff8 100644 --- a/src/scratch/stage.cpp +++ b/src/scratch/stage.cpp @@ -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; @@ -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; diff --git a/src/scratch/target.cpp b/src/scratch/target.cpp index d1e4224f..4fc276aa 100644 --- a/src/scratch/target.cpp +++ b/src/scratch/target.cpp @@ -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; } diff --git a/src/scratch/value_functions.cpp b/src/scratch/value_functions.cpp index 0e157b65..7dced357 100644 --- a/src/scratch/value_functions.cpp +++ b/src/scratch/value_functions.cpp @@ -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) { diff --git a/test/blocks/sensing_blocks_test.cpp b/test/blocks/sensing_blocks_test.cpp index ecb5588c..e486f372 100644 --- a/test/blocks/sensing_blocks_test.cpp +++ b/test/blocks/sensing_blocks_test.cpp @@ -422,21 +422,21 @@ 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(); @@ -444,7 +444,7 @@ TEST_F(SensingBlocksTest, TouchingColorImpl) 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(); @@ -495,21 +495,21 @@ 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(); @@ -517,7 +517,7 @@ TEST_F(SensingBlocksTest, ColorIsTouchingColorImpl) 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(); diff --git a/test/mocks/spritehandlermock.h b/test/mocks/spritehandlermock.h index a3d2ab4b..4a9055c0 100644 --- a/test/mocks/spritehandlermock.h +++ b/test/mocks/spritehandlermock.h @@ -35,6 +35,6 @@ class SpriteHandlerMock : public ISpriteHandler MOCK_METHOD(bool, touchingClones, (const std::vector &), (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)); }; diff --git a/test/mocks/stagehandlermock.h b/test/mocks/stagehandlermock.h index 9e3892ed..1cc31205 100644 --- a/test/mocks/stagehandlermock.h +++ b/test/mocks/stagehandlermock.h @@ -26,6 +26,6 @@ class StageHandlerMock : public IStageHandler MOCK_METHOD(bool, touchingClones, (const std::vector &), (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)); }; diff --git a/test/mocks/targetmock.h b/test/mocks/targetmock.h index aca1c4c6..bfa62420 100644 --- a/test/mocks/targetmock.h +++ b/test/mocks/targetmock.h @@ -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)); diff --git a/test/scratch_classes/sprite_test.cpp b/test/scratch_classes/sprite_test.cpp index 572bd5f5..5749896a 100644 --- a/test/scratch_classes/sprite_test.cpp +++ b/test/scratch_classes/sprite_test.cpp @@ -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) diff --git a/test/scratch_classes/stage_test.cpp b/test/scratch_classes/stage_test.cpp index 53f0477d..bdf7c4c8 100644 --- a/test/scratch_classes/stage_test.cpp +++ b/test/scratch_classes/stage_test.cpp @@ -229,18 +229,19 @@ TEST(StageTest, TouchingColor) EXPECT_CALL(iface, init); stage.setInterface(&iface); - Value v1 = 4278228630, v2 = "#FF00FA"; - EXPECT_CALL(iface, touchingColor(v1)).WillOnce(Return(false)); - ASSERT_FALSE(stage.touchingColor(v1)); + Rgb c1 = Value(4278228630).toRgba(); + Rgb c2 = Value("#FF00FA").toRgba(); + EXPECT_CALL(iface, touchingColor(c1)).WillOnce(Return(false)); + ASSERT_FALSE(stage.touchingColor(c1)); - EXPECT_CALL(iface, touchingColor(v2)).WillOnce(Return(true)); - ASSERT_TRUE(stage.touchingColor(v2)); + EXPECT_CALL(iface, touchingColor(c2)).WillOnce(Return(true)); + ASSERT_TRUE(stage.touchingColor(c2)); - EXPECT_CALL(iface, touchingColor(v1, v2)).WillOnce(Return(false)); - ASSERT_FALSE(stage.touchingColor(v1, v2)); + EXPECT_CALL(iface, touchingColor(c1, c2)).WillOnce(Return(false)); + ASSERT_FALSE(stage.touchingColor(c1, c2)); - EXPECT_CALL(iface, touchingColor(v2, v1)).WillOnce(Return(true)); - ASSERT_TRUE(stage.touchingColor(v2, v1)); + EXPECT_CALL(iface, touchingColor(c2, c1)).WillOnce(Return(true)); + ASSERT_TRUE(stage.touchingColor(c2, c1)); } TEST(StageTest, GraphicsEffects) diff --git a/test/scratch_classes/target_test.cpp b/test/scratch_classes/target_test.cpp index 93ef3330..92596c01 100644 --- a/test/scratch_classes/target_test.cpp +++ b/test/scratch_classes/target_test.cpp @@ -759,9 +759,9 @@ TEST(TargetTest, TouchingEdge) TEST(TargetTest, TouchingColor) { Target target; - Value v; - ASSERT_FALSE(target.touchingColor(v)); - ASSERT_FALSE(target.touchingColor(v, v)); + Rgb c = 0; + ASSERT_FALSE(target.touchingColor(c)); + ASSERT_FALSE(target.touchingColor(c, c)); } TEST(TargetTest, GraphicsEffects) diff --git a/test/scratch_classes/value_test.cpp b/test/scratch_classes/value_test.cpp index 71e31bfd..76462ebe 100644 --- a/test/scratch_classes/value_test.cpp +++ b/test/scratch_classes/value_test.cpp @@ -1616,6 +1616,60 @@ TEST(ValueTest, ToString) free(s); } +TEST(ValueTest, ToRgba) +{ + Value v = "#ff0000"; + ASSERT_EQ(v.toRgba(), rgba(255, 0, 0, 255)); + + v = "#00ff00"; + ASSERT_EQ(v.toRgba(), rgba(0, 255, 0, 255)); + + v = "#0000ff"; + ASSERT_EQ(v.toRgba(), rgba(0, 0, 255, 255)); + + v = "#800000"; + ASSERT_EQ(v.toRgba(), rgba(128, 0, 0, 255)); + + v = "#008000"; + ASSERT_EQ(v.toRgba(), rgba(0, 128, 0, 255)); + + v = "#000080"; + ASSERT_EQ(v.toRgba(), rgba(0, 0, 128, 255)); + + v = "#FF0080FF"; + ASSERT_EQ(v.toRgba(), rgba(0, 0, 0, 255)); + + v = "#abc"; + ASSERT_EQ(v.toRgba(), rgba(170, 187, 204, 255)); + + v = "00ff00"; + ASSERT_EQ(v.toRgba(), 0); + + v = "123"; + ASSERT_EQ(v.toRgba(), 123); + + v = "#12345"; + ASSERT_EQ(v.toRgba(), rgba(0, 0, 0, 255)); + + v = ""; + ASSERT_EQ(v.toRgba(), rgba(0, 0, 0, 255)); + + v = "#gggggg"; + ASSERT_EQ(v.toRgba(), rgba(0, 0, 0, 255)); + + v = 2164195583; + ASSERT_EQ(v.toRgba(), 2164195583); + + v = 0; + ASSERT_EQ(v.toRgba(), 0); + + v = true; + ASSERT_EQ(v.toRgba(), 1); + + v = false; + ASSERT_EQ(v.toRgba(), 0); +} + TEST(ValueTest, AddFunction) { Value v = 50; @@ -3121,3 +3175,39 @@ TEST(ValueTest, StringToBool) ASSERT_TRUE(value_stringToBool("0b100112001")); ASSERT_TRUE(value_stringToBool("0b10011001.1")); } + +TEST(ValueTest, RedComponent) +{ + Rgb color = rgba(255, 100, 50, 255); + ASSERT_EQ(red(color), 255); +} + +TEST(ValueTest, GreenComponent) +{ + Rgb color = rgba(255, 100, 50, 255); + ASSERT_EQ(green(color), 100); +} + +TEST(ValueTest, BlueComponent) +{ + Rgb color = rgba(255, 100, 50, 255); + ASSERT_EQ(blue(color), 50); +} + +TEST(ValueTest, AlphaComponent) +{ + Rgb color = rgba(255, 100, 50, 128); + ASSERT_EQ(alpha(color), 128); +} + +TEST(ValueTest, RGB) +{ + Rgb color = rgb(255, 100, 50); + ASSERT_EQ(color, 0xFFFF6432); +} + +TEST(ValueTest, RGBA) +{ + Rgb color = rgba(255, 100, 50, 128); + ASSERT_EQ(color, 0x80FF6432); +}