@@ -658,43 +658,12 @@ bool RenderedTarget::touchingClones(const std::vector<libscratchcpp::Sprite *> &
658658
659659bool RenderedTarget::touchingColor (const Value &color) const
660660{
661- // https://github.com/scratchfoundation/scratch-render/blob/0a04c2fb165f5c20406ec34ab2ea5682ae45d6e0/src/RenderWebGL.js#L775-L841
662- if (!m_engine)
663- return false ;
664-
665- QRgb rgb = convertColor (color);
666-
667- std::vector<Target *> targets;
668- m_engine->getVisibleTargets (targets);
669-
670- QRectF myRect = touchingBounds ();
671- std::vector<IRenderedTarget *> candidates;
672- QRectF bounds = candidatesBounds (myRect, targets, candidates);
673-
674- if (colorMatches (rgb, qRgb (255 , 255 , 255 ))) {
675- // The color we're checking for is the background color which spans the entire stage
676- bounds = myRect;
677-
678- if (bounds.isEmpty ())
679- return false ;
680- } else if (candidates.empty ()) {
681- // If not checking for the background color, we can return early if there are no candidate drawables
682- return false ;
683- }
684-
685- // Loop through the points of the union
686- for (int y = bounds.top (); y <= bounds.bottom (); y++) {
687- for (int x = bounds.left (); x <= bounds.right (); x++) {
688- if (this ->containsScratchPoint (x, y)) {
689- QRgb pixelColor = sampleColor3b (x, y, candidates);
690-
691- if (colorMatches (rgb, pixelColor))
692- return true ;
693- }
694- }
695- }
661+ return touchingColor (color, false , Value ());
662+ }
696663
697- return false ;
664+ bool RenderedTarget::touchingColor (const Value &color, const Value &mask) const
665+ {
666+ return touchingColor (color, true , mask);
698667}
699668
700669void RenderedTarget::calculatePos ()
@@ -896,6 +865,70 @@ CpuTextureManager *RenderedTarget::textureManager() const
896865 return m_textureManager.get ();
897866}
898867
868+ bool RenderedTarget::touchingColor (const libscratchcpp::Value &color, bool hasMask, const libscratchcpp::Value &mask) const
869+ {
870+ // https://github.com/scratchfoundation/scratch-render/blob/0a04c2fb165f5c20406ec34ab2ea5682ae45d6e0/src/RenderWebGL.js#L775-L841
871+ if (!m_engine)
872+ return false ;
873+
874+ QRgb rgb = convertColor (color);
875+ QRgb mask3b;
876+ double ghostValue = 0 ;
877+
878+ if (hasMask) {
879+ // Ignore ghost effect when checking mask
880+ auto it = m_graphicEffects.find (ShaderManager::Effect::Ghost);
881+
882+ if (it != m_graphicEffects.cend ()) {
883+ ghostValue = it->second ;
884+ m_graphicEffects.erase (ShaderManager::Effect::Ghost);
885+ }
886+
887+ mask3b = convertColor (mask);
888+ }
889+
890+ std::vector<Target *> targets;
891+ m_engine->getVisibleTargets (targets);
892+
893+ QRectF myRect = touchingBounds ();
894+ std::vector<IRenderedTarget *> candidates;
895+ QRectF bounds = candidatesBounds (myRect, targets, candidates);
896+
897+ if (colorMatches (rgb, qRgb (255 , 255 , 255 ))) {
898+ // The color we're checking for is the background color which spans the entire stage
899+ bounds = myRect;
900+
901+ if (bounds.isEmpty ())
902+ return false ;
903+ } else if (candidates.empty ()) {
904+ // If not checking for the background color, we can return early if there are no candidate drawables
905+ return false ;
906+ }
907+
908+ // Loop through the points of the union
909+ for (int y = bounds.top (); y <= bounds.bottom (); y++) {
910+ for (int x = bounds.left (); x <= bounds.right (); x++) {
911+ if (hasMask ? maskMatches (colorAtScratchPoint (x, y), mask3b) : this ->containsScratchPoint (x, y)) {
912+ QRgb pixelColor = sampleColor3b (x, y, candidates);
913+
914+ if (colorMatches (rgb, pixelColor)) {
915+ // Restore ghost effect value
916+ if (hasMask && ghostValue != 0 )
917+ m_graphicEffects[ShaderManager::Effect::Ghost] = ghostValue;
918+
919+ return true ;
920+ }
921+ }
922+ }
923+ }
924+
925+ // Restore ghost effect value
926+ if (hasMask && ghostValue != 0 )
927+ m_graphicEffects[ShaderManager::Effect::Ghost] = ghostValue;
928+
929+ return false ;
930+ }
931+
899932QRectF RenderedTarget::touchingBounds () const
900933{
901934 // https://github.com/scratchfoundation/scratch-render/blob/0a04c2fb165f5c20406ec34ab2ea5682ae45d6e0/src/RenderWebGL.js#L1330-L1350
@@ -1051,7 +1084,13 @@ QRgb RenderedTarget::convertColor(const libscratchcpp::Value &color)
10511084bool RenderedTarget::colorMatches (QRgb a, QRgb b)
10521085{
10531086 // https://github.com/scratchfoundation/scratch-render/blob/0a04c2fb165f5c20406ec34ab2ea5682ae45d6e0/src/RenderWebGL.js#L77-L81
1054- return (qRed (a) & 0b11111000 ) == (qRed (b) & 0b11111000 ) && (qGreen (a) & 0b11111000 ) == (qGreen (b) & 0b11111000 ) && (qBlue (a) & 0b11110000 ) == (qBlue (b) & 0b11110000 );
1087+ return qAlpha (a) > 0 && (qRed (a) & 0b11111000 ) == (qRed (b) & 0b11111000 ) && (qGreen (a) & 0b11111000 ) == (qGreen (b) & 0b11111000 ) && (qBlue (a) & 0b11110000 ) == (qBlue (b) & 0b11110000 );
1088+ }
1089+
1090+ bool RenderedTarget::maskMatches (QRgb a, QRgb b)
1091+ {
1092+ // https://github.com/scratchfoundation/scratch-render/blob/0a04c2fb165f5c20406ec34ab2ea5682ae45d6e0/src/RenderWebGL.js#L59-L65
1093+ return (qRed (a) & 0b11111000 ) == (qRed (b) & 0b11111000 ) && (qGreen (a) & 0b11111000 ) == (qGreen (b) & 0b11111000 ) && (qBlue (a) & 0b11111000 ) == (qBlue (b) & 0b11111000 );
10551094}
10561095
10571096QRgb RenderedTarget::sampleColor3b (double x, double y, const std::vector<IRenderedTarget *> &targets) const
0 commit comments