Skip to content

Commit

Permalink
Move effect transform + bounds check out of getLocalPosition
Browse files Browse the repository at this point in the history
This results in a tad bit of duplicated code, but considering that we
have 4 different code paths (colorAtNearest, colorAtLinear,
isTouchingNearest, and isTouchingLinear) for sampling a silhouette,
that's to be expected.

This more closely matches the GPU pipeline, in which color and position
calculations are more intertwined. This replaces the hacky fix in #424
with a solution that matches the GPU: instead of not transforming points
outside the skin bounds, just return transparency/false early.
  • Loading branch information
adroitwhiz committed Mar 15, 2021
1 parent 32d682c commit c823982
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 19 deletions.
24 changes: 12 additions & 12 deletions src/Drawable.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,6 @@ const getLocalPosition = (drawable, vec) => {
// TODO: Check if this can be removed after render pull 479 is merged
if (Math.abs(localPosition[0]) < FLOATING_POINT_ERROR_ALLOWANCE) localPosition[0] = 0;
if (Math.abs(localPosition[1]) < FLOATING_POINT_ERROR_ALLOWANCE) localPosition[1] = 0;
// Apply texture effect transform if the localPosition is within the drawable's space,
// and any effects are currently active.
if (drawable.enabledEffects !== 0 &&
(localPosition[0] >= 0 && localPosition[0] < 1) &&
(localPosition[1] >= 0 && localPosition[1] < 1)) {

EffectTransform.transformPoint(drawable, localPosition, localPosition);
}
return localPosition;
};

Expand Down Expand Up @@ -501,11 +493,17 @@ class Drawable {
}

_isTouchingNearest (vec) {
return this.skin.isTouchingNearest(getLocalPosition(this, vec));
const localPosition = getLocalPosition(this, vec);
if (!this.skin.pointInsideLogicalBounds(localPosition)) return false;
if (this.enabledEffects !== 0) EffectTransform.transformPoint(this, localPosition, localPosition);
return this.skin._silhouette.isTouchingNearest(localPosition);
}

_isTouchingLinear (vec) {
return this.skin.isTouchingLinear(getLocalPosition(this, vec));
const localPosition = getLocalPosition(this, vec);
if (!this.skin.pointInsideLogicalBounds(localPosition)) return false;
if (this.enabledEffects !== 0) EffectTransform.transformPoint(this, localPosition, localPosition);
return this.skin._silhouette.isTouchingLinear(localPosition);
}

/**
Expand Down Expand Up @@ -769,15 +767,17 @@ class Drawable {
*/
static sampleColor4b (vec, drawable, dst, effectMask) {
const localPosition = getLocalPosition(drawable, vec);
if (localPosition[0] < 0 || localPosition[1] < 0 ||
localPosition[0] > 1 || localPosition[1] > 1) {
if (!this.skin.pointInsideLogicalBounds(localPosition)) {
dst[0] = 0;
dst[1] = 0;
dst[2] = 0;
dst[3] = 0;
return dst;
}

// Apply texture effect transform if any effects are currently active.
if (drawable.enabledEffects !== 0) EffectTransform.transformPoint(drawable, localPosition, localPosition);

const textColor =
// commenting out to only use nearest for now
// drawable.skin.useNearest(drawable._scale, drawable) ?
Expand Down
7 changes: 2 additions & 5 deletions src/EffectTransform.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,15 +138,12 @@ class EffectTransform {
dst[1] = (dst[1] - skinUniforms.u_logicalBounds[1]) /
(skinUniforms.u_logicalBounds[3] - skinUniforms.u_logicalBounds[1]);

const pointInsideLogicalBounds = dst[0] >= 0 && dst[0] <= 1 && dst[1] >= 0 && dst[1] <= 1;

// Only apply mosaic and pixelate effects to points inside the "logical bounds".
if ((effects & ShaderManager.EFFECT_INFO.mosaic.mask) !== 0 && pointInsideLogicalBounds) {
if ((effects & ShaderManager.EFFECT_INFO.mosaic.mask) !== 0) {
// texcoord0 = fract(u_mosaic * texcoord0);
dst[0] = uniforms.u_mosaic * dst[0] % 1;
dst[1] = uniforms.u_mosaic * dst[1] % 1;
}
if ((effects & ShaderManager.EFFECT_INFO.pixelate.mask) !== 0 && pointInsideLogicalBounds) {
if ((effects & ShaderManager.EFFECT_INFO.pixelate.mask) !== 0) {
// vec2 pixelTexelSize = u_skinSize / u_pixelate;
const texelX = skinUniforms.u_skinSize[0] / uniforms.u_pixelate;
const texelY = skinUniforms.u_skinSize[1] / uniforms.u_pixelate;
Expand Down
4 changes: 2 additions & 2 deletions src/RenderWebGL.js
Original file line number Diff line number Diff line change
Expand Up @@ -1979,7 +1979,7 @@ class RenderWebGL extends EventEmitter {
for (; x < width; x++) {
_pixelPos[0] = x / width;
EffectTransform.transformPoint(drawable, _pixelPos, _effectPos);
if (drawable.skin.isTouchingLinear(_effectPos)) {
if (drawable.skin.pointInsideLogicalBounds(_pixelPos) && drawable.skin.isTouchingLinear(_effectPos)) {
currentPoint = [x, y];
break;
}
Expand Down Expand Up @@ -2016,7 +2016,7 @@ class RenderWebGL extends EventEmitter {
for (x = width - 1; x >= 0; x--) {
_pixelPos[0] = x / width;
EffectTransform.transformPoint(drawable, _pixelPos, _effectPos);
if (drawable.skin.isTouchingLinear(_effectPos)) {
if (drawable.skin.pointInsideLogicalBounds(_pixelPos) && drawable.skin.isTouchingLinear(_effectPos)) {
currentPoint = [x, y];
break;
}
Expand Down
13 changes: 13 additions & 0 deletions src/Skin.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,19 @@ class Skin extends EventEmitter {
this.emit(Skin.Events.WasAltered);
}

/**
* Is this (texture-space, in the range [0, 1]) point inside the skin's "logical bounds"?
* @param {twgl.v3} vec A texture coordinate.
* @return {boolean} True if the point is inside the skin's "logical bounds"
*/
pointInsideLogicalBounds (vec) {
const logicalBounds = this._uniforms.u_logicalBounds;
return vec[0] >= logicalBounds[0] &&
vec[0] <= logicalBounds[2] &&
vec[1] >= logicalBounds[1] &&
vec[1] <= logicalBounds[3];
}

/**
* Does this point touch an opaque or translucent point on this skin?
* Nearest Neighbor version
Expand Down

0 comments on commit c823982

Please sign in to comment.