@@ -182,9 +182,23 @@ class RenderWebGL extends EventEmitter {
182
182
/** @type {function } */
183
183
this . _exitRegion = null ;
184
184
185
+ /** @type {object } */
186
+ this . _backgroundDrawRegionId = {
187
+ enter : ( ) => this . _enterDrawBackground ( ) ,
188
+ exit : ( ) => this . _exitDrawBackground ( )
189
+ } ;
190
+
185
191
/** @type {Array.<snapshotCallback> } */
186
192
this . _snapshotCallbacks = [ ] ;
187
193
194
+ /** @type {Array<number> }
195
+ * @readonly */
196
+ this . _backgroundColor4f = [ 0 , 0 , 0 , 0 ] ;
197
+
198
+ /** @type {Uint8ClampedArray }
199
+ * @readonly */
200
+ this . _backgroundColor3b = new Uint8ClampedArray ( 3 ) ;
201
+
188
202
this . _createGeometry ( ) ;
189
203
190
204
this . on ( RenderConstants . Events . NativeSizeChanged , this . onNativeSizeChanged ) ;
@@ -244,7 +258,12 @@ class RenderWebGL extends EventEmitter {
244
258
* @param {number } blue The blue component for the background.
245
259
*/
246
260
setBackgroundColor ( red , green , blue ) {
247
- this . _backgroundColor = [ red , green , blue , 1 ] ;
261
+ this . _backgroundColor4f = [ red , green , blue , 1 ] ;
262
+
263
+ this . _backgroundColor3b [ 0 ] = red * 255 ;
264
+ this . _backgroundColor3b [ 1 ] = green * 255 ;
265
+ this . _backgroundColor3b [ 2 ] = blue * 255 ;
266
+
248
267
}
249
268
250
269
/**
@@ -623,7 +642,7 @@ class RenderWebGL extends EventEmitter {
623
642
624
643
twgl . bindFramebufferInfo ( gl , null ) ;
625
644
gl . viewport ( 0 , 0 , gl . canvas . width , gl . canvas . height ) ;
626
- gl . clearColor . apply ( gl , this . _backgroundColor ) ;
645
+ gl . clearColor . apply ( gl , this . _backgroundColor4f ) ;
627
646
gl . clear ( gl . COLOR_BUFFER_BIT ) ;
628
647
629
648
this . _drawThese ( this . _drawList , ShaderManager . DRAW_MODE . default , this . _projection ) ;
@@ -739,12 +758,20 @@ class RenderWebGL extends EventEmitter {
739
758
*/
740
759
isTouchingColor ( drawableID , color3b , mask3b ) {
741
760
const candidates = this . _candidatesTouching ( drawableID , this . _visibleDrawList ) ;
742
- if ( candidates . length === 0 ) {
761
+
762
+ let bounds ;
763
+ if ( colorMatches ( color3b , this . _backgroundColor3b , 0 ) ) {
764
+ // If the color we're checking for is the background color, don't confine the check to
765
+ // candidate drawables' bounds--since the background spans the entire stage, we must check
766
+ // everything that lies inside the drawable.
767
+ bounds = this . _touchingBounds ( drawableID ) ;
768
+ } else if ( candidates . length === 0 ) {
769
+ // If not checking for the background color, we can return early if there are no candidate drawables.
743
770
return false ;
771
+ } else {
772
+ bounds = this . _candidatesBounds ( candidates ) ;
744
773
}
745
774
746
- const bounds = this . _candidatesBounds ( candidates ) ;
747
-
748
775
const maxPixelsForCPU = this . _getMaxPixelsForCPU ( ) ;
749
776
750
777
const debugCanvasContext = this . _debugCanvas && this . _debugCanvas . getContext ( '2d' ) ;
@@ -805,6 +832,19 @@ class RenderWebGL extends EventEmitter {
805
832
}
806
833
}
807
834
835
+ _enterDrawBackground ( ) {
836
+ const gl = this . gl ;
837
+ const currentShader = this . _shaderManager . getShader ( ShaderManager . DRAW_MODE . background , 0 ) ;
838
+ gl . disable ( gl . BLEND ) ;
839
+ gl . useProgram ( currentShader . program ) ;
840
+ twgl . setBuffersAndAttributes ( gl , currentShader , this . _bufferInfo ) ;
841
+ }
842
+
843
+ _exitDrawBackground ( ) {
844
+ const gl = this . gl ;
845
+ gl . enable ( gl . BLEND ) ;
846
+ }
847
+
808
848
_isTouchingColorGpuStart ( drawableID , candidateIDs , bounds , color3b , mask3b ) {
809
849
this . _doExitDrawRegion ( ) ;
810
850
@@ -816,15 +856,8 @@ class RenderWebGL extends EventEmitter {
816
856
gl . viewport ( 0 , 0 , bounds . width , bounds . height ) ;
817
857
const projection = twgl . m4 . ortho ( bounds . left , bounds . right , bounds . top , bounds . bottom , - 1 , 1 ) ;
818
858
819
- let fillBackgroundColor = this . _backgroundColor ;
820
-
821
- // When using masking such that the background fill color will showing through, ensure we don't
822
- // fill using the same color that we are trying to detect!
823
- if ( color3b [ 0 ] > 196 && color3b [ 1 ] > 196 && color3b [ 2 ] > 196 ) {
824
- fillBackgroundColor = [ 0 , 0 , 0 , 255 ] ;
825
- }
826
-
827
- gl . clearColor . apply ( gl , fillBackgroundColor ) ;
859
+ // Clear the query buffer to fully transparent. This will be the color of pixels that fail the stencil test.
860
+ gl . clearColor ( 0 , 0 , 0 , 0 ) ;
828
861
gl . clear ( gl . COLOR_BUFFER_BIT | gl . STENCIL_BUFFER_BIT ) ;
829
862
830
863
let extraUniforms ;
@@ -835,7 +868,11 @@ class RenderWebGL extends EventEmitter {
835
868
} ;
836
869
}
837
870
871
+ // TODO: figure out why this is all in a try block?
838
872
try {
873
+ // Using the stencil buffer, mask out the drawing to either the drawable's bounds
874
+ // or pixels of the drawable which match the mask color, depending on whether a mask color is given.
875
+ // Masked-out pixels will not be checked.
839
876
gl . enable ( gl . STENCIL_TEST ) ;
840
877
gl . stencilFunc ( gl . ALWAYS , 1 , 1 ) ;
841
878
gl . stencilOp ( gl . KEEP , gl . KEEP , gl . REPLACE ) ;
@@ -856,6 +893,18 @@ class RenderWebGL extends EventEmitter {
856
893
gl . stencilOp ( gl . KEEP , gl . KEEP , gl . KEEP ) ;
857
894
gl . colorMask ( true , true , true , true ) ;
858
895
896
+ // Draw the background as a quad. Drawing a background with gl.clear will not mask to the stenciled area.
897
+ this . enterDrawRegion ( this . _backgroundDrawRegionId ) ;
898
+
899
+ const uniforms = {
900
+ u_backgroundColor : this . _backgroundColor4f
901
+ } ;
902
+
903
+ const currentShader = this . _shaderManager . getShader ( ShaderManager . DRAW_MODE . background , 0 ) ;
904
+ twgl . setUniforms ( currentShader , uniforms ) ;
905
+ twgl . drawBufferInfo ( gl , this . _bufferInfo , gl . TRIANGLES ) ;
906
+
907
+ // Draw the candidate drawables on top of the background.
859
908
this . _drawThese ( candidateIDs , ShaderManager . DRAW_MODE . default , projection ,
860
909
{ idFilterFunc : testID => testID !== drawableID }
861
910
) ;
@@ -880,7 +929,8 @@ class RenderWebGL extends EventEmitter {
880
929
}
881
930
882
931
for ( let pixelBase = 0 ; pixelBase < pixels . length ; pixelBase += 4 ) {
883
- if ( colorMatches ( color3b , pixels , pixelBase ) ) {
932
+ // Transparent pixels are masked (either by the drawable's bounds or color mask).
933
+ if ( pixels [ pixelBase + 3 ] !== 0 && colorMatches ( color3b , pixels , pixelBase ) ) {
884
934
return true ;
885
935
}
886
936
}
@@ -1210,7 +1260,7 @@ class RenderWebGL extends EventEmitter {
1210
1260
gl . viewport ( 0 , 0 , bounds . width , bounds . height ) ;
1211
1261
const projection = twgl . m4 . ortho ( bounds . left , bounds . right , bounds . top , bounds . bottom , - 1 , 1 ) ;
1212
1262
1213
- gl . clearColor . apply ( gl , this . _backgroundColor ) ;
1263
+ gl . clearColor . apply ( gl , this . _backgroundColor4f ) ;
1214
1264
gl . clear ( gl . COLOR_BUFFER_BIT ) ;
1215
1265
this . _drawThese ( this . _drawList , ShaderManager . DRAW_MODE . default , projection ) ;
1216
1266
0 commit comments