Skip to content

Commit bd7b539

Browse files
authored
Merge pull request #370 from scratchcpp/refactor_graphics_effect_api
Refactor graphics effect API
2 parents 8a9cf36 + 1cc2e97 commit bd7b539

25 files changed

+195
-218
lines changed

docs/Graphics effects.md

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,10 @@
11
\page graphicsEffects Graphics effects
22

3-
libscratchcpp provides API for implementing custom graphics effects.
4-
No effects are currently included with libscratchcpp, but that is planned to change.
3+
libscratchcpp provides API for adding custom graphics effects.
4+
No effects are included with libscratchcpp and must be implemented by the project player.
55

6-
In case you've implemented some of the effects yourself, feel free to make pull requests!
7-
These are the issues (tasks) for the default graphics effects:
8-
9-
- Color: https://github.com/scratchcpp/libscratchcpp/issues/283
10-
- Fisheye: https://github.com/scratchcpp/libscratchcpp/issues/284
11-
- Whirl: https://github.com/scratchcpp/libscratchcpp/issues/285
12-
- Pixelate: https://github.com/scratchcpp/libscratchcpp/issues/286
13-
- Mosaic: https://github.com/scratchcpp/libscratchcpp/issues/287
14-
- Brightness: https://github.com/scratchcpp/libscratchcpp/issues/288
15-
- Ghost: https://github.com/scratchcpp/libscratchcpp/issues/289
16-
17-
# Implementing a graphics effect
18-
To implement a graphics effect that libscratchcpp doesn't support,
6+
# Adding a custom graphics effect
7+
To add a graphics effect that libscratchcpp doesn't support,
198
subclass \link libscratchcpp::IGraphicsEffect IGraphicsEffect \endlink
209
and override all of the methods.
2110

@@ -27,12 +16,14 @@ using namespace libscratchcpp;
2716
The `name()` method should return the name of the effect which is
2817
used by the set and change effect blocks, for example `ghost` or `fisheye`.
2918

30-
The `apply()` method is used to apply the effect on a bitmap. The bitmap
31-
can be accessed using the `bitmap` parameter and is writable.
32-
3319
# Registering the graphics effect
3420
To register the graphics effect, use \link libscratchcpp::ScratchConfiguration::registerGraphicsEffect() ScratchConfiguration::registerGraphicsEffect() \endlink.
3521

3622
```cpp
3723
libscratchcpp::ScratchConfiguration::registerGraphicsEffect(std::make_shared<MyGraphicsEffect>());
3824
```
25+
26+
# Why should effects be registered?
27+
Effects in Scratch are usually identified by their name (`ghost`, `brightness`, etc.), but this isn't effective
28+
when it comes to running projects. Those "names" are therefore replaced by \link libscratchcpp::IGraphicsEffect IGraphicsEffect \endlink
29+
pointers which makes working with effects faster.

include/scratchcpp/costume.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ namespace libscratchcpp
1111
{
1212

1313
class Broadcast;
14-
class IGraphicsEffect;
1514
class CostumePrivate;
1615

1716
/*! \brief The Costume class represents a Scratch costume. */
@@ -41,11 +40,6 @@ class LIBSCRATCHCPP_EXPORT Costume : public Asset
4140

4241
Rgb **bitmap() const;
4342

44-
double graphicsEffectValue(IGraphicsEffect *effect) const;
45-
void setGraphicsEffectValue(IGraphicsEffect *effect, double value);
46-
47-
void clearGraphicsEffects();
48-
4943
Broadcast *broadcast();
5044

5145
protected:

include/scratchcpp/igraphicseffect.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,14 @@
99
namespace libscratchcpp
1010
{
1111

12-
/*! \brief The IGraphicsEffects class is an interface for implementing custom graphics effects. */
12+
/*! \brief The IGraphicsEffects class is an interface for custom graphics effects. */
1313
class LIBSCRATCHCPP_EXPORT IGraphicsEffect
1414
{
1515
public:
1616
virtual ~IGraphicsEffect() { }
1717

1818
/*! Returns the name of the graphics effect. */
1919
virtual std::string name() const = 0;
20-
21-
/*! Applies the effect on the given bitmap. */
22-
virtual void apply(Rgb **bitmap, unsigned int width, unsigned int height, double value) const = 0;
2320
};
2421

2522
} // namespace libscratchcpp

include/scratchcpp/ispritehandler.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ class LIBSCRATCHCPP_EXPORT ISpriteHandler
4141
/*! Called when the rotation style changes. */
4242
virtual void onRotationStyleChanged(Sprite::RotationStyle rotationStyle) = 0;
4343

44+
/*!
45+
* Called when the value of the given graphics effect changes.
46+
* \note This method isn't called when all effects are cleared, use onGraphicsEffectsCleared() for this.
47+
*/
48+
virtual void onGraphicsEffectChanged(IGraphicsEffect *effect, double value) = 0;
49+
50+
/*! Called when all graphics effects are cleared. */
51+
virtual void onGraphicsEffectsCleared() = 0;
52+
4453
/*!
4554
* Used to get the bounding rectangle of the sprite.
4655
* \note The rectangle must be relative to the stage, so make sure to use the sprite's coordinates.

include/scratchcpp/istagehandler.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ class LIBSCRATCHCPP_EXPORT IStageHandler
2828

2929
/*! Called when the video transparency changes. */
3030
virtual void onVideoTransparencyChanged(int videoTransparency) = 0;
31+
32+
/*!
33+
* Called when the value of the given graphics effect changes.
34+
* \note This method isn't called when all effects are cleared, use onGraphicsEffectsCleared() for this.
35+
*/
36+
virtual void onGraphicsEffectChanged(IGraphicsEffect *effect, double value) = 0;
37+
38+
/*! Called when all graphics effects are cleared. */
39+
virtual void onGraphicsEffectsCleared() = 0;
3140
};
3241

3342
} // namespace libscratchcpp

include/scratchcpp/sprite.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,9 @@ class LIBSCRATCHCPP_EXPORT Sprite : public Target
6767
Rect boundingRect() const;
6868
void keepInFence(double newX, double newY, double *fencedX, double *fencedY) const;
6969

70-
double graphicsEffectValue(IGraphicsEffect *effect) const;
71-
void setGraphicsEffectValue(IGraphicsEffect *effect, double value);
70+
void setGraphicsEffectValue(IGraphicsEffect *effect, double value) override;
7271

73-
void clearGraphicsEffects();
72+
void clearGraphicsEffects() override;
7473

7574
private:
7675
Target *dataSource() const override;

include/scratchcpp/stage.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ class LIBSCRATCHCPP_EXPORT Stage : public Target
4747
const std::string &textToSpeechLanguage() const;
4848
void setTextToSpeechLanguage(const std::string &newTextToSpeechLanguage);
4949

50+
void setGraphicsEffectValue(IGraphicsEffect *effect, double value) override;
51+
52+
void clearGraphicsEffects() override;
53+
5054
private:
5155
spimpl::unique_impl_ptr<StagePrivate> impl;
5256
};

include/scratchcpp/target.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class Block;
1717
class Comment;
1818
class Costume;
1919
class Sound;
20+
class IGraphicsEffect;
2021
class TargetPrivate;
2122

2223
/*! \brief The Target class is the Stage or a Sprite. */
@@ -77,6 +78,11 @@ class LIBSCRATCHCPP_EXPORT Target
7778
double volume() const;
7879
void setVolume(double newVolume);
7980

81+
double graphicsEffectValue(IGraphicsEffect *effect) const;
82+
virtual void setGraphicsEffectValue(IGraphicsEffect *effect, double value);
83+
84+
virtual void clearGraphicsEffects();
85+
8086
IEngine *engine() const;
8187
void setEngine(IEngine *engine);
8288

src/scratch/costume.cpp

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -107,42 +107,6 @@ Rgb **Costume::bitmap() const
107107
return impl->bitmap;
108108
}
109109

110-
/*! Returns the value of the given graphics effect. */
111-
double Costume::graphicsEffectValue(IGraphicsEffect *effect) const
112-
{
113-
auto it = impl->graphicsEffects.find(effect);
114-
115-
if (it == impl->graphicsEffects.cend())
116-
return 0;
117-
else
118-
return it->second;
119-
}
120-
121-
/*! Sets the value of the given graphics effect (this is automatically set by the sprite). */
122-
void Costume::setGraphicsEffectValue(IGraphicsEffect *effect, double value)
123-
{
124-
auto it = impl->graphicsEffects.find(effect);
125-
bool update = ((it == impl->graphicsEffects.cend()) || (it->second != value));
126-
127-
if (value == 0)
128-
impl->graphicsEffects.erase(effect);
129-
else
130-
impl->graphicsEffects[effect] = value;
131-
132-
if (update)
133-
impl->updateImage();
134-
}
135-
136-
/*! Clears all graphics effects (this is automatically called by the sprite). */
137-
void Costume::clearGraphicsEffects()
138-
{
139-
bool update = !impl->graphicsEffects.empty();
140-
impl->graphicsEffects.clear();
141-
142-
if (update)
143-
impl->updateImage();
144-
}
145-
146110
/*!
147111
* Returns the Broadcast linked with this costume.
148112
* \note This is used by the "switch backdrop to and wait" block.

src/scratch/costume_p.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// SPDX-License-Identifier: Apache-2.0
22

3-
#include <scratchcpp/igraphicseffect.h>
4-
53
#include "costume_p.h"
64

75
using namespace libscratchcpp;
@@ -45,9 +43,6 @@ void CostumePrivate::updateImage()
4543
for (unsigned int j = 0; j < scaledWidth; j++)
4644
bitmap[i][j] = image->colorAt(mirrorHorizontally ? (scaledWidth - 1 - j) : j, i, actualScale);
4745
}
48-
49-
for (const auto &[effect, value] : graphicsEffects)
50-
effect->apply(bitmap, scaledWidth, scaledHeight, value);
5146
}
5247

5348
void CostumePrivate::freeImage()

src/scratch/costume_p.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
namespace libscratchcpp
1010
{
1111

12-
class IGraphicsEffect;
13-
1412
struct CostumePrivate
1513
{
1614
CostumePrivate();
@@ -31,7 +29,6 @@ struct CostumePrivate
3129
double oldScale = 1;
3230
double scale = 1;
3331
bool mirrorHorizontally = false;
34-
std::unordered_map<IGraphicsEffect *, double> graphicsEffects;
3532
Broadcast broadcast;
3633
};
3734

src/scratch/sprite.cpp

Lines changed: 10 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -233,9 +233,6 @@ void Sprite::setCostumeIndex(int newCostumeIndex)
233233
if (costume) {
234234
costume->setScale(impl->size / 100);
235235
costume->setMirrorHorizontally(impl->rotationStyle == RotationStyle::LeftRight);
236-
237-
for (const auto &[effect, value] : impl->graphicsEffects)
238-
costume->setGraphicsEffectValue(effect, value);
239236
}
240237

241238
if (impl->visible) {
@@ -403,51 +400,36 @@ void Sprite::keepInFence(double newX, double newY, double *fencedX, double *fenc
403400
*fencedY = newY + dy;
404401
}
405402

406-
/*! Returns the value of the given graphics effect. */
407-
double Sprite::graphicsEffectValue(IGraphicsEffect *effect) const
408-
{
409-
auto it = impl->graphicsEffects.find(effect);
410-
411-
if (it == impl->graphicsEffects.cend())
412-
return 0;
413-
else
414-
return it->second;
415-
}
416-
417-
/*! Sets the value of the given graphics effect. */
403+
/*! Overrides Target#setGraphicsEffectValue(). */
418404
void Sprite::setGraphicsEffectValue(IGraphicsEffect *effect, double value)
419405
{
420-
impl->graphicsEffects[effect] = value;
421-
422-
auto costume = currentCostume();
423-
424-
if (costume)
425-
costume->setGraphicsEffectValue(effect, value);
406+
Target::setGraphicsEffectValue(effect, value);
426407

427408
if (impl->visible) {
428409
IEngine *eng = engine();
429410

430411
if (eng)
431412
eng->requestRedraw();
432413
}
414+
415+
if (impl->iface)
416+
impl->iface->onGraphicsEffectChanged(effect, value);
433417
}
434418

435-
/*! Sets the value of all graphics effects to 0 (clears them). */
419+
/*! Overrides Target#clearGraphicsEffects(). */
436420
void Sprite::clearGraphicsEffects()
437421
{
438-
impl->graphicsEffects.clear();
439-
440-
auto costume = currentCostume();
441-
442-
if (costume)
443-
costume->clearGraphicsEffects();
422+
Target::clearGraphicsEffects();
444423

445424
if (impl->visible) {
446425
IEngine *eng = engine();
447426

448427
if (eng)
449428
eng->requestRedraw();
450429
}
430+
431+
if (impl->iface)
432+
impl->iface->onGraphicsEffectsCleared();
451433
}
452434

453435
Target *Sprite::dataSource() const

src/scratch/sprite_p.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ struct SpritePrivate
3131
double direction = 90;
3232
bool draggable = false;
3333
Sprite::RotationStyle rotationStyle = Sprite::RotationStyle::AllAround;
34-
std::unordered_map<IGraphicsEffect *, double> graphicsEffects;
3534
};
3635

3736
} // namespace libscratchcpp

src/scratch/stage.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <scratchcpp/stage.h>
44
#include <scratchcpp/istagehandler.h>
5+
#include <scratchcpp/iengine.h>
56
#include <cassert>
67

78
#include "stage_p.h"
@@ -123,3 +124,29 @@ void Stage::setTextToSpeechLanguage(const std::string &newTextToSpeechLanguage)
123124
{
124125
impl->textToSpeechLanguage = newTextToSpeechLanguage;
125126
}
127+
128+
/*! Overrides Target#setGraphicsEffectValue(). */
129+
void Stage::setGraphicsEffectValue(IGraphicsEffect *effect, double value)
130+
{
131+
Target::setGraphicsEffectValue(effect, value);
132+
IEngine *eng = engine();
133+
134+
if (eng)
135+
eng->requestRedraw();
136+
137+
if (impl->iface)
138+
impl->iface->onGraphicsEffectChanged(effect, value);
139+
}
140+
141+
/*! Overrides Target#clearGraphicsEffects(). */
142+
void Stage::clearGraphicsEffects()
143+
{
144+
Target::clearGraphicsEffects();
145+
IEngine *eng = engine();
146+
147+
if (eng)
148+
eng->requestRedraw();
149+
150+
if (impl->iface)
151+
impl->iface->onGraphicsEffectsCleared();
152+
}

src/scratch/target.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,29 @@ void Target::setVolume(double newVolume)
409409
impl->volume = newVolume;
410410
}
411411

412+
/*! Returns the value of the given graphics effect. */
413+
double Target::graphicsEffectValue(IGraphicsEffect *effect) const
414+
{
415+
auto it = impl->graphicsEffects.find(effect);
416+
417+
if (it == impl->graphicsEffects.cend())
418+
return 0;
419+
else
420+
return it->second;
421+
}
422+
423+
/*! Sets the value of the given graphics effect. */
424+
void Target::setGraphicsEffectValue(IGraphicsEffect *effect, double value)
425+
{
426+
impl->graphicsEffects[effect] = value;
427+
}
428+
429+
/*! Sets the value of all graphics effects to 0 (clears them). */
430+
void Target::clearGraphicsEffects()
431+
{
432+
impl->graphicsEffects.clear();
433+
}
434+
412435
/*! Returns the engine. */
413436
IEngine *Target::engine() const
414437
{

0 commit comments

Comments
 (0)