1010 */
1111let __SilhouetteUpdateCanvas ;
1212
13+ // Optimized Math.min and Math.max for integers;
14+ // taken from https://web.archive.org/web/20190716181049/http://guihaire.com/code/?p=549
15+ const intMin = ( i , j ) => j ^ ( ( i ^ j ) & ( ( i - j ) >> 31 ) ) ;
16+ const intMax = ( i , j ) => i ^ ( ( i ^ j ) & ( ( i - j ) >> 31 ) ) ;
17+
1318/**
14- * Internal helper function (in hopes that compiler can inline). Get a pixel
15- * from silhouette data, or 0 if outside it's bounds .
19+ * Internal helper function (in hopes that compiler can inline). Get a pixel's alpha
20+ * from silhouette data, matching texture sampling rules .
1621 * @private
1722 * @param {Silhouette } silhouette - has data width and height
1823 * @param {number } x - x
1924 * @param {number } y - y
2025 * @return {number } Alpha value for x/y position
2126 */
2227const getPoint = ( { _width : width , _height : height , _colorData : data } , x , y ) => {
23- // 0 if outside bouds, otherwise read from data .
24- if ( x >= width || y >= height || x < 0 || y < 0 ) {
25- return 0 ;
26- }
28+ // Clamp coords to edge, matching GL_CLAMP_TO_EDGE .
29+ x = intMax ( 0 , intMin ( x , width - 1 ) ) ;
30+ y = intMax ( 0 , intMin ( y , height - 1 ) ) ;
31+
2732 return data [ ( ( ( y * width ) + x ) * 4 ) + 3 ] ;
2833} ;
2934
@@ -40,16 +45,16 @@ const __cornerWork = [
4045/**
4146 * Get the color from a given silhouette at an x/y local texture position.
4247 * @param {Silhouette } The silhouette to sample.
43- * @param {number } x X position of texture (0-1 ).
44- * @param {number } y Y position of texture (0-1 ).
48+ * @param {number } x X position of texture [0, width ).
49+ * @param {number } y Y position of texture [0, height ).
4550 * @param {Uint8ClampedArray } dst A color 4b space.
4651 * @return {Uint8ClampedArray } The dst vector.
4752 */
4853const getColor4b = ( { _width : width , _height : height , _colorData : data } , x , y , dst ) => {
49- // 0 if outside bouds, otherwise read from data .
50- if ( x >= width || y >= height || x < 0 || y < 0 ) {
51- return dst . fill ( 0 ) ;
52- }
54+ // Clamp coords to edge, matching GL_CLAMP_TO_EDGE .
55+ x = intMax ( 0 , intMin ( x , width - 1 ) ) ;
56+ y = intMax ( 0 , intMin ( y , height - 1 ) ) ;
57+
5358 const offset = ( ( y * width ) + x ) * 4 ;
5459 dst [ 0 ] = data [ offset ] ;
5560 dst [ 1 ] = data [ offset + 1 ] ;
@@ -126,8 +131,8 @@ class Silhouette {
126131 colorAtNearest ( vec , dst ) {
127132 return getColor4b (
128133 this ,
129- Math . floor ( vec [ 0 ] * ( this . _width - 1 ) ) ,
130- Math . floor ( vec [ 1 ] * ( this . _height - 1 ) ) ,
134+ Math . floor ( vec [ 0 ] * this . _width ) ,
135+ Math . floor ( vec [ 1 ] * this . _height ) ,
131136 dst
132137 ) ;
133138 }
@@ -140,8 +145,13 @@ class Silhouette {
140145 * @returns {Uint8ClampedArray } dst
141146 */
142147 colorAtLinear ( vec , dst ) {
143- const x = vec [ 0 ] * ( this . _width - 1 ) ;
144- const y = vec [ 1 ] * ( this . _height - 1 ) ;
148+ // In texture space, pixel centers are at integer coords. Here, the *corners* are at integers.
149+ // We cannot skip the "add 0.5 in Drawable.getLocalPosition -> subtract 0.5 here" roundtrip
150+ // because the two spaces are different--we add 0.5 in Drawable.getLocalPosition in "Scratch space"
151+ // (-240,240 & -180,180), but subtract 0.5 in silhouette space (0, width or height).
152+ // See https://web.archive.org/web/20190125211252/http://hacksoflife.blogspot.com/2009/12/texture-coordinate-system-for-opengl.html
153+ const x = ( vec [ 0 ] * ( this . _width ) ) - 0.5 ;
154+ const y = ( vec [ 1 ] * ( this . _height ) ) - 0.5 ;
145155
146156 const x1D = x % 1 ;
147157 const y1D = y % 1 ;
@@ -171,10 +181,17 @@ class Silhouette {
171181 */
172182 isTouchingNearest ( vec ) {
173183 if ( ! this . _colorData ) return ;
184+
185+ // Never touching if the coord falls outside the texture space.
186+ if ( vec [ 0 ] < 0 || vec [ 0 ] > 1 ||
187+ vec [ 1 ] < 0 || vec [ 1 ] > 1 ) {
188+ return false ;
189+ }
190+
174191 return getPoint (
175192 this ,
176- Math . floor ( vec [ 0 ] * ( this . _width - 1 ) ) ,
177- Math . floor ( vec [ 1 ] * ( this . _height - 1 ) )
193+ Math . floor ( vec [ 0 ] * this . _width ) ,
194+ Math . floor ( vec [ 1 ] * this . _height )
178195 ) > 0 ;
179196 }
180197
@@ -186,8 +203,15 @@ class Silhouette {
186203 */
187204 isTouchingLinear ( vec ) {
188205 if ( ! this . _colorData ) return ;
189- const x = Math . floor ( vec [ 0 ] * ( this . _width - 1 ) ) ;
190- const y = Math . floor ( vec [ 1 ] * ( this . _height - 1 ) ) ;
206+
207+ // Never touching if the coord falls outside the texture space.
208+ if ( vec [ 0 ] < 0 || vec [ 0 ] > 1 ||
209+ vec [ 1 ] < 0 || vec [ 1 ] > 1 ) {
210+ return ;
211+ }
212+
213+ const x = Math . floor ( ( vec [ 0 ] * this . _width ) - 0.5 ) ;
214+ const y = Math . floor ( ( vec [ 1 ] * this . _height ) - 0.5 ) ;
191215 return getPoint ( this , x , y ) > 0 ||
192216 getPoint ( this , x + 1 , y ) > 0 ||
193217 getPoint ( this , x , y + 1 ) > 0 ||
0 commit comments