10
10
*/
11
11
let __SilhouetteUpdateCanvas ;
12
12
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
+
13
18
/**
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 .
16
21
* @private
17
22
* @param {Silhouette } silhouette - has data width and height
18
23
* @param {number } x - x
19
24
* @param {number } y - y
20
25
* @return {number } Alpha value for x/y position
21
26
*/
22
27
const 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
+
27
32
return data [ ( ( ( y * width ) + x ) * 4 ) + 3 ] ;
28
33
} ;
29
34
@@ -41,16 +46,16 @@ const __cornerWork = [
41
46
* Get the color from a given silhouette at an x/y local texture position.
42
47
* Multiply color values by alpha for proper blending.
43
48
* @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 ).
46
51
* @param {Uint8ClampedArray } dst A color 4b space.
47
52
* @return {Uint8ClampedArray } The dst vector.
48
53
*/
49
54
const 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
+
54
59
const offset = ( ( y * width ) + x ) * 4 ;
55
60
// premultiply alpha
56
61
const alpha = data [ offset + 3 ] / 255 ;
@@ -65,16 +70,16 @@ const getColor4b = ({_width: width, _height: height, _colorData: data}, x, y, ds
65
70
* Get the color from a given silhouette at an x/y local texture position.
66
71
* Do not multiply color values by alpha, as it has already been done.
67
72
* @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 ).
70
75
* @param {Uint8ClampedArray } dst A color 4b space.
71
76
* @return {Uint8ClampedArray } The dst vector.
72
77
*/
73
78
const 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
+
78
83
const offset = ( ( y * width ) + x ) * 4 ;
79
84
dst [ 0 ] = data [ offset ] ;
80
85
dst [ 1 ] = data [ offset + 1 ] ;
@@ -163,8 +168,8 @@ class Silhouette {
163
168
colorAtNearest ( vec , dst ) {
164
169
return this . _getColor (
165
170
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 ) ,
168
173
dst
169
174
) ;
170
175
}
@@ -177,8 +182,13 @@ class Silhouette {
177
182
* @returns {Uint8ClampedArray } dst
178
183
*/
179
184
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 ;
182
192
183
193
const x1D = x % 1 ;
184
194
const y1D = y % 1 ;
@@ -208,10 +218,17 @@ class Silhouette {
208
218
*/
209
219
isTouchingNearest ( vec ) {
210
220
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
+
211
228
return getPoint (
212
229
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 )
215
232
) > 0 ;
216
233
}
217
234
@@ -223,8 +240,15 @@ class Silhouette {
223
240
*/
224
241
isTouchingLinear ( vec ) {
225
242
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 ) ;
228
252
return getPoint ( this , x , y ) > 0 ||
229
253
getPoint ( this , x + 1 , y ) > 0 ||
230
254
getPoint ( this , x , y + 1 ) > 0 ||
0 commit comments