@@ -134,7 +134,7 @@ unsigned int PenBlocks::changePenHueBy(libscratchcpp::VirtualMachine *vm)
134134
135135 if (model) {
136136 const double colorChange = vm->getInput (0 , 1 )->toDouble () / 2 ;
137- setOrChangeColorParam (model-> penAttributes (), ColorParam::COLOR, colorChange, true );
137+ setOrChangeColorParam (ColorParam::COLOR, colorChange, model-> penState (), true , true );
138138 }
139139
140140 return 1 ;
@@ -147,7 +147,8 @@ unsigned int PenBlocks::setPenColorToColor(libscratchcpp::VirtualMachine *vm)
147147 if (model) {
148148 const Value *value = vm->getInput (0 , 1 );
149149 std::string stringValue;
150- PenAttributes &attributes = model->penAttributes ();
150+ PenState &penState = model->penState ();
151+ QColor newColor;
151152
152153 if (value->isString ())
153154 stringValue = value->toString ();
@@ -157,19 +158,24 @@ unsigned int PenBlocks::setPenColorToColor(libscratchcpp::VirtualMachine *vm)
157158
158159 if (stringValue.size () <= 7 ) // #RRGGBB
159160 {
160- attributes. color = QColor::fromString (stringValue);
161- valid = attributes. color .isValid ();
161+ newColor = QColor::fromString (stringValue);
162+ valid = newColor .isValid ();
162163 }
163164
164165 if (!valid)
165- attributes. color = QColor ( 0 , 0 , 0 ) ;
166+ newColor = Qt::black ;
166167
167168 } else {
168- attributes. color = QColor::fromRgba (static_cast <QRgb>(value->toLong ()));
169+ newColor = QColor::fromRgba (static_cast <QRgb>(value->toLong ()));
169170
170- if (attributes. color .alpha () == 0 )
171- attributes. color .setAlpha (255 );
171+ if (newColor .alpha () == 0 )
172+ newColor .setAlpha (255 );
172173 }
174+
175+ penState.setColor (newColor);
176+
177+ // Set the legacy "shade" value the same way Scratch 2 did.
178+ penState.shade = penState.brightness / 2 ;
173179 }
174180
175181 return 1 ;
@@ -187,22 +193,31 @@ SpriteModel *PenBlocks::getSpriteModel(libscratchcpp::VirtualMachine *vm)
187193 return model;
188194}
189195
190- void PenBlocks::setOrChangeColorParam (PenAttributes &penAttributes, ColorParam param, double value, bool change)
196+ void PenBlocks::setOrChangeColorParam (ColorParam param, double value, PenState &penState, bool change, bool legacy )
191197{
192- PenState penState;
193- penState.setColor (penAttributes.color );
194-
195198 switch (param) {
196199 case ColorParam::COLOR:
197200 penState.color = wrapClamp (value + (change ? penState.color : 0 ), 0 , 100 );
198201 break ;
199202 }
200203
201- const int h = std::round (std::fmod (penState.color * 360 / 100 , 360.0 ));
202- const int s = std::round (penState.saturation * 2.55 );
203- const int v = std::round (penState.brightness * 2.55 );
204- const int a = std::round ((100 - penState.transparency ) * 2.55 );
205- penAttributes.color = QColor::fromHsv (h, s, v, a);
204+ penState.updateColor ();
205+
206+ if (legacy) {
207+ // https://github.com/scratchfoundation/scratch-vm/blob/8dbcc1fc8f8d8c4f1e40629fe8a388149d6dfd1c/src/extensions/scratch3_pen/index.js#L750-L767
208+ // Create the new color in RGB using the scratch 2 "shade" model
209+ QColor rgb = penState.penAttributes .color .toRgb ();
210+ const double shade = (penState.shade > 100 ) ? 200 - penState.shade : penState.shade ;
211+
212+ if (shade < 50 )
213+ rgb = mixRgb (QColor (Qt::black), rgb, (10 + shade) / 60 );
214+ else
215+ rgb = mixRgb (rgb, QColor (Qt::white), (shade - 50 ) / 60 );
216+
217+ // Update the pen state according to new color
218+ const QColor hsv = rgb.toHsv ();
219+ penState.setColor (hsv);
220+ }
206221}
207222
208223double PenBlocks::wrapClamp (double n, double min, double max)
@@ -211,3 +226,15 @@ double PenBlocks::wrapClamp(double n, double min, double max)
211226 const double range = max - min + 1 ;
212227 return n - (std::floor ((n - min) / range) * range);
213228}
229+
230+ QColor PenBlocks::mixRgb (const QColor &rgb0, const QColor &rgb1, double fraction1)
231+ {
232+ // https://github.com/scratchfoundation/scratch-vm/blob/a4f095db5e03e072ba222fe721eeeb543c9b9c15/src/util/color.js#L192-L201
233+ if (fraction1 <= 0 )
234+ return rgb0;
235+ if (fraction1 >= 1 )
236+ return rgb1;
237+
238+ const double fraction0 = 1 - fraction1;
239+ return QColor ((fraction0 * rgb0.red ()) + (fraction1 * rgb1.red ()), (fraction0 * rgb0.green ()) + (fraction1 * rgb1.green ()), (fraction0 * rgb0.blue ()) + (fraction1 * rgb1.blue ()));
240+ }
0 commit comments