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 bounds, 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
@@ -41,16 +46,16 @@ const __cornerWork = [
4146 * Get the color from a given silhouette at an x/y local texture position.
4247 * Multiply color values by alpha for proper blending.
4348 * @param {Silhouette } The silhouette to sample.
44- * @param {number } x X position of texture (0-1 ).
45- * @param {number } y Y position of texture (0-1 ).
49+ * @param {number } x X position of texture [0, width ).
50+ * @param {number } y Y position of texture [0, height ).
4651 * @param {Uint8ClampedArray } dst A color 4b space.
4752 * @return {Uint8ClampedArray } The dst vector.
4853 */
4954const getColor4b = ( { _width : width , _height : height , _colorData : data } , x , y , dst ) => {
50- // 0 if outside bounds, otherwise read from data .
51- if ( x >= width || y >= height || x < 0 || y < 0 ) {
52- return dst . fill ( 0 ) ;
53- }
55+ // Clamp coords to edge, matching GL_CLAMP_TO_EDGE .
56+ x = intMax ( 0 , intMin ( x , width - 1 ) ) ;
57+ y = intMax ( 0 , intMin ( y , height - 1 ) ) ;
58+
5459 const offset = ( ( y * width ) + x ) * 4 ;
5560 // premultiply alpha
5661 const alpha = data [ offset + 3 ] / 255 ;
@@ -65,16 +70,16 @@ const getColor4b = ({_width: width, _height: height, _colorData: data}, x, y, ds
6570 * Get the color from a given silhouette at an x/y local texture position.
6671 * Do not multiply color values by alpha, as it has already been done.
6772 * @param {Silhouette } The silhouette to sample.
68- * @param {number } x X position of texture (0-1 ).
69- * @param {number } y Y position of texture (0-1 ).
73+ * @param {number } x X position of texture [0, width ).
74+ * @param {number } y Y position of texture [0, height ).
7075 * @param {Uint8ClampedArray } dst A color 4b space.
7176 * @return {Uint8ClampedArray } The dst vector.
7277 */
7378const getPremultipliedColor4b = ( { _width : width , _height : height , _colorData : data } , x , y , dst ) => {
74- // 0 if outside bounds, otherwise read from data .
75- if ( x >= width || y >= height || x < 0 || y < 0 ) {
76- return dst . fill ( 0 ) ;
77- }
79+ // Clamp coords to edge, matching GL_CLAMP_TO_EDGE .
80+ x = intMax ( 0 , intMin ( x , width - 1 ) ) ;
81+ y = intMax ( 0 , intMin ( y , height - 1 ) ) ;
82+
7883 const offset = ( ( y * width ) + x ) * 4 ;
7984 dst [ 0 ] = data [ offset ] ;
8085 dst [ 1 ] = data [ offset + 1 ] ;
@@ -163,8 +168,8 @@ class Silhouette {
163168 colorAtNearest ( vec , dst ) {
164169 return this . _getColor (
165170 this ,
166- Math . floor ( vec [ 0 ] * ( this . _width - 1 ) ) ,
167- Math . floor ( vec [ 1 ] * ( this . _height - 1 ) ) ,
171+ Math . floor ( vec [ 0 ] * this . _width ) ,
172+ Math . floor ( vec [ 1 ] * this . _height ) ,
168173 dst
169174 ) ;
170175 }
@@ -177,8 +182,13 @@ class Silhouette {
177182 * @returns {Uint8ClampedArray } dst
178183 */
179184 colorAtLinear ( vec , dst ) {
180- const x = vec [ 0 ] * ( this . _width - 1 ) ;
181- const y = vec [ 1 ] * ( this . _height - 1 ) ;
185+ // In texture space, pixel centers are at integer coords. Here, the *corners* are at integers.
186+ // We cannot skip the "add 0.5 in Drawable.getLocalPosition -> subtract 0.5 here" roundtrip
187+ // because the two spaces are different--we add 0.5 in Drawable.getLocalPosition in "Scratch space"
188+ // (-240,240 & -180,180), but subtract 0.5 in silhouette space (0, width or height).
189+ // See https://web.archive.org/web/20190125211252/http://hacksoflife.blogspot.com/2009/12/texture-coordinate-system-for-opengl.html
190+ const x = ( vec [ 0 ] * ( this . _width ) ) - 0.5 ;
191+ const y = ( vec [ 1 ] * ( this . _height ) ) - 0.5 ;
182192
183193 const x1D = x % 1 ;
184194 const y1D = y % 1 ;
@@ -208,10 +218,17 @@ class Silhouette {
208218 */
209219 isTouchingNearest ( vec ) {
210220 if ( ! this . _colorData ) return ;
221+
222+ // Never touching if the coord falls outside the texture space.
223+ if ( vec [ 0 ] < 0 || vec [ 0 ] > 1 ||
224+ vec [ 1 ] < 0 || vec [ 1 ] > 1 ) {
225+ return false ;
226+ }
227+
211228 return getPoint (
212229 this ,
213- Math . floor ( vec [ 0 ] * ( this . _width - 1 ) ) ,
214- Math . floor ( vec [ 1 ] * ( this . _height - 1 ) )
230+ Math . floor ( vec [ 0 ] * this . _width ) ,
231+ Math . floor ( vec [ 1 ] * this . _height )
215232 ) > 0 ;
216233 }
217234
@@ -223,8 +240,15 @@ class Silhouette {
223240 */
224241 isTouchingLinear ( vec ) {
225242 if ( ! this . _colorData ) return ;
226- const x = Math . floor ( vec [ 0 ] * ( this . _width - 1 ) ) ;
227- const y = Math . floor ( vec [ 1 ] * ( this . _height - 1 ) ) ;
243+
244+ // Never touching if the coord falls outside the texture space.
245+ if ( vec [ 0 ] < 0 || vec [ 0 ] > 1 ||
246+ vec [ 1 ] < 0 || vec [ 1 ] > 1 ) {
247+ return false ;
248+ }
249+
250+ const x = Math . floor ( ( vec [ 0 ] * this . _width ) - 0.5 ) ;
251+ const y = Math . floor ( ( vec [ 1 ] * this . _height ) - 0.5 ) ;
228252 return getPoint ( this , x , y ) > 0 ||
229253 getPoint ( this , x + 1 , y ) > 0 ||
230254 getPoint ( this , x , y + 1 ) > 0 ||
0 commit comments