diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/extras/BitmapText.js b/src/extras/BitmapText.js
index 0592b54..96d9f44 100644
--- a/src/extras/BitmapText.js
+++ b/src/extras/BitmapText.js
@@ -1,5 +1,6 @@
import * as core from '../core';
import ObservablePoint from '../core/math/ObservablePoint';
+import { getResolutionOfUrl } from '../core/utils';
import settings from '../core/settings';
/**
@@ -510,7 +511,8 @@
const data = {};
const info = xml.getElementsByTagName('info')[0];
const common = xml.getElementsByTagName('common')[0];
- const res = texture.baseTexture.resolution || settings.RESOLUTION;
+ const fileName = xml.getElementsByTagName('page')[0].getAttribute('file');
+ const res = getResolutionOfUrl(fileName, settings.RESOLUTION);
data.font = info.getAttribute('face');
data.size = parseInt(info.getAttribute('size'), 10);
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/extras/BitmapText.js b/src/extras/BitmapText.js
index 0592b54..96d9f44 100644
--- a/src/extras/BitmapText.js
+++ b/src/extras/BitmapText.js
@@ -1,5 +1,6 @@
import * as core from '../core';
import ObservablePoint from '../core/math/ObservablePoint';
+import { getResolutionOfUrl } from '../core/utils';
import settings from '../core/settings';
/**
@@ -510,7 +511,8 @@
const data = {};
const info = xml.getElementsByTagName('info')[0];
const common = xml.getElementsByTagName('common')[0];
- const res = texture.baseTexture.resolution || settings.RESOLUTION;
+ const fileName = xml.getElementsByTagName('page')[0].getAttribute('file');
+ const res = getResolutionOfUrl(fileName, settings.RESOLUTION);
data.font = info.getAttribute('face');
data.size = parseInt(info.getAttribute('size'), 10);
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
deleted file mode 100644
index 16536d2..0000000
--- a/src/extras/TextureTransform.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import { default as Matrix } from '../core/math/Matrix';
-
-const tempMat = new Matrix();
-
-/**
- * class controls uv transform and frame clamp for texture
- *
- * @class
- * @memberof PIXI.extras
- */
-export default class TextureTransform
-{
- /**
- *
- * @param {PIXI.Texture} texture observed texture
- * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
- * @constructor
- */
- constructor(texture, clampMargin)
- {
- this._texture = texture;
-
- this.mapCoord = new Matrix();
-
- this.uClampFrame = new Float32Array(4);
-
- this.uClampOffset = new Float32Array(2);
-
- this._lastTextureID = -1;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
- *
- * @default 0
- * @member {number}
- */
- this.clampOffset = 0;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
- *
- * @default 0.5
- * @member {number}
- */
- this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
- }
-
- /**
- * texture property
- * @member {PIXI.Texture}
- */
- get texture()
- {
- return this._texture;
- }
-
- set texture(value) // eslint-disable-line require-jsdoc
- {
- this._texture = value;
- this._lastTextureID = -1;
- }
-
- /**
- * Multiplies uvs array to transform
- * @param {Float32Array} uvs mesh uvs
- * @param {Float32Array} [out=uvs] output
- * @returns {Float32Array} output
- */
- multiplyUvs(uvs, out)
- {
- if (out === undefined)
- {
- out = uvs;
- }
-
- const mat = this.mapCoord;
-
- for (let i = 0; i < uvs.length; i += 2)
- {
- const x = uvs[i];
- const y = uvs[i + 1];
-
- out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
- out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
- }
-
- return out;
- }
-
- /**
- * updates matrices if texture was changed
- * @param {boolean} forceUpdate if true, matrices will be updated any case
- * @returns {boolean} whether or not it was updated
- */
- update(forceUpdate)
- {
- const tex = this._texture;
-
- if (!tex || !tex.valid)
- {
- return false;
- }
-
- if (!forceUpdate
- && this._lastTextureID === tex._updateID)
- {
- return false;
- }
-
- this._lastTextureID = tex._updateID;
-
- const uvs = tex._uvs;
-
- this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
-
- const orig = tex.orig;
- const trim = tex.trim;
-
- if (trim)
- {
- tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
- -trim.x / trim.width, -trim.y / trim.height);
- this.mapCoord.append(tempMat);
- }
-
- const texBase = tex.baseTexture;
- const frame = this.uClampFrame;
- const margin = this.clampMargin / texBase.resolution;
- const offset = this.clampOffset;
-
- frame[0] = (tex._frame.x + margin + offset) / texBase.width;
- frame[1] = (tex._frame.y + margin + offset) / texBase.height;
- frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
- frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
- this.uClampOffset[0] = offset / texBase.realWidth;
- this.uClampOffset[1] = offset / texBase.realHeight;
-
- return true;
- }
-}
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/extras/BitmapText.js b/src/extras/BitmapText.js
index 0592b54..96d9f44 100644
--- a/src/extras/BitmapText.js
+++ b/src/extras/BitmapText.js
@@ -1,5 +1,6 @@
import * as core from '../core';
import ObservablePoint from '../core/math/ObservablePoint';
+import { getResolutionOfUrl } from '../core/utils';
import settings from '../core/settings';
/**
@@ -510,7 +511,8 @@
const data = {};
const info = xml.getElementsByTagName('info')[0];
const common = xml.getElementsByTagName('common')[0];
- const res = texture.baseTexture.resolution || settings.RESOLUTION;
+ const fileName = xml.getElementsByTagName('page')[0].getAttribute('file');
+ const res = getResolutionOfUrl(fileName, settings.RESOLUTION);
data.font = info.getAttribute('face');
data.size = parseInt(info.getAttribute('size'), 10);
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
deleted file mode 100644
index 16536d2..0000000
--- a/src/extras/TextureTransform.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import { default as Matrix } from '../core/math/Matrix';
-
-const tempMat = new Matrix();
-
-/**
- * class controls uv transform and frame clamp for texture
- *
- * @class
- * @memberof PIXI.extras
- */
-export default class TextureTransform
-{
- /**
- *
- * @param {PIXI.Texture} texture observed texture
- * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
- * @constructor
- */
- constructor(texture, clampMargin)
- {
- this._texture = texture;
-
- this.mapCoord = new Matrix();
-
- this.uClampFrame = new Float32Array(4);
-
- this.uClampOffset = new Float32Array(2);
-
- this._lastTextureID = -1;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
- *
- * @default 0
- * @member {number}
- */
- this.clampOffset = 0;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
- *
- * @default 0.5
- * @member {number}
- */
- this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
- }
-
- /**
- * texture property
- * @member {PIXI.Texture}
- */
- get texture()
- {
- return this._texture;
- }
-
- set texture(value) // eslint-disable-line require-jsdoc
- {
- this._texture = value;
- this._lastTextureID = -1;
- }
-
- /**
- * Multiplies uvs array to transform
- * @param {Float32Array} uvs mesh uvs
- * @param {Float32Array} [out=uvs] output
- * @returns {Float32Array} output
- */
- multiplyUvs(uvs, out)
- {
- if (out === undefined)
- {
- out = uvs;
- }
-
- const mat = this.mapCoord;
-
- for (let i = 0; i < uvs.length; i += 2)
- {
- const x = uvs[i];
- const y = uvs[i + 1];
-
- out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
- out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
- }
-
- return out;
- }
-
- /**
- * updates matrices if texture was changed
- * @param {boolean} forceUpdate if true, matrices will be updated any case
- * @returns {boolean} whether or not it was updated
- */
- update(forceUpdate)
- {
- const tex = this._texture;
-
- if (!tex || !tex.valid)
- {
- return false;
- }
-
- if (!forceUpdate
- && this._lastTextureID === tex._updateID)
- {
- return false;
- }
-
- this._lastTextureID = tex._updateID;
-
- const uvs = tex._uvs;
-
- this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
-
- const orig = tex.orig;
- const trim = tex.trim;
-
- if (trim)
- {
- tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
- -trim.x / trim.width, -trim.y / trim.height);
- this.mapCoord.append(tempMat);
- }
-
- const texBase = tex.baseTexture;
- const frame = this.uClampFrame;
- const margin = this.clampMargin / texBase.resolution;
- const offset = this.clampOffset;
-
- frame[0] = (tex._frame.x + margin + offset) / texBase.width;
- frame[1] = (tex._frame.y + margin + offset) / texBase.height;
- frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
- frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
- this.uClampOffset[0] = offset / texBase.realWidth;
- this.uClampOffset[1] = offset / texBase.realHeight;
-
- return true;
- }
-}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 736b207..84c0841 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -1,6 +1,5 @@
import * as core from '../core';
import CanvasTinter from '../core/sprites/canvas/CanvasTinter';
-import { default as TextureTransform } from './TextureTransform';
const tempPoint = new core.Point();
@@ -58,9 +57,9 @@
/**
* transform that is applied to UV to get the texture coords
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
*/
- this.uvTransform = texture.transform || new TextureTransform(texture);
+ this.uvTransform = texture.transform || new core.TextureMatrix(texture);
/**
* Plugin that is responsible for rendering this element.
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/extras/BitmapText.js b/src/extras/BitmapText.js
index 0592b54..96d9f44 100644
--- a/src/extras/BitmapText.js
+++ b/src/extras/BitmapText.js
@@ -1,5 +1,6 @@
import * as core from '../core';
import ObservablePoint from '../core/math/ObservablePoint';
+import { getResolutionOfUrl } from '../core/utils';
import settings from '../core/settings';
/**
@@ -510,7 +511,8 @@
const data = {};
const info = xml.getElementsByTagName('info')[0];
const common = xml.getElementsByTagName('common')[0];
- const res = texture.baseTexture.resolution || settings.RESOLUTION;
+ const fileName = xml.getElementsByTagName('page')[0].getAttribute('file');
+ const res = getResolutionOfUrl(fileName, settings.RESOLUTION);
data.font = info.getAttribute('face');
data.size = parseInt(info.getAttribute('size'), 10);
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
deleted file mode 100644
index 16536d2..0000000
--- a/src/extras/TextureTransform.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import { default as Matrix } from '../core/math/Matrix';
-
-const tempMat = new Matrix();
-
-/**
- * class controls uv transform and frame clamp for texture
- *
- * @class
- * @memberof PIXI.extras
- */
-export default class TextureTransform
-{
- /**
- *
- * @param {PIXI.Texture} texture observed texture
- * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
- * @constructor
- */
- constructor(texture, clampMargin)
- {
- this._texture = texture;
-
- this.mapCoord = new Matrix();
-
- this.uClampFrame = new Float32Array(4);
-
- this.uClampOffset = new Float32Array(2);
-
- this._lastTextureID = -1;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
- *
- * @default 0
- * @member {number}
- */
- this.clampOffset = 0;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
- *
- * @default 0.5
- * @member {number}
- */
- this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
- }
-
- /**
- * texture property
- * @member {PIXI.Texture}
- */
- get texture()
- {
- return this._texture;
- }
-
- set texture(value) // eslint-disable-line require-jsdoc
- {
- this._texture = value;
- this._lastTextureID = -1;
- }
-
- /**
- * Multiplies uvs array to transform
- * @param {Float32Array} uvs mesh uvs
- * @param {Float32Array} [out=uvs] output
- * @returns {Float32Array} output
- */
- multiplyUvs(uvs, out)
- {
- if (out === undefined)
- {
- out = uvs;
- }
-
- const mat = this.mapCoord;
-
- for (let i = 0; i < uvs.length; i += 2)
- {
- const x = uvs[i];
- const y = uvs[i + 1];
-
- out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
- out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
- }
-
- return out;
- }
-
- /**
- * updates matrices if texture was changed
- * @param {boolean} forceUpdate if true, matrices will be updated any case
- * @returns {boolean} whether or not it was updated
- */
- update(forceUpdate)
- {
- const tex = this._texture;
-
- if (!tex || !tex.valid)
- {
- return false;
- }
-
- if (!forceUpdate
- && this._lastTextureID === tex._updateID)
- {
- return false;
- }
-
- this._lastTextureID = tex._updateID;
-
- const uvs = tex._uvs;
-
- this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
-
- const orig = tex.orig;
- const trim = tex.trim;
-
- if (trim)
- {
- tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
- -trim.x / trim.width, -trim.y / trim.height);
- this.mapCoord.append(tempMat);
- }
-
- const texBase = tex.baseTexture;
- const frame = this.uClampFrame;
- const margin = this.clampMargin / texBase.resolution;
- const offset = this.clampOffset;
-
- frame[0] = (tex._frame.x + margin + offset) / texBase.width;
- frame[1] = (tex._frame.y + margin + offset) / texBase.height;
- frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
- frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
- this.uClampOffset[0] = offset / texBase.realWidth;
- this.uClampOffset[1] = offset / texBase.realHeight;
-
- return true;
- }
-}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 736b207..84c0841 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -1,6 +1,5 @@
import * as core from '../core';
import CanvasTinter from '../core/sprites/canvas/CanvasTinter';
-import { default as TextureTransform } from './TextureTransform';
const tempPoint = new core.Point();
@@ -58,9 +57,9 @@
/**
* transform that is applied to UV to get the texture coords
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
*/
- this.uvTransform = texture.transform || new TextureTransform(texture);
+ this.uvTransform = texture.transform || new core.TextureMatrix(texture);
/**
* Plugin that is responsible for rendering this element.
diff --git a/src/extras/index.js b/src/extras/index.js
index 5b98cb1..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -3,7 +3,6 @@
* @namespace PIXI.extras
*/
export { default as AnimatedSprite } from './AnimatedSprite';
-export { default as TextureTransform } from './TextureTransform';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
export { default as BitmapText } from './BitmapText';
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/extras/BitmapText.js b/src/extras/BitmapText.js
index 0592b54..96d9f44 100644
--- a/src/extras/BitmapText.js
+++ b/src/extras/BitmapText.js
@@ -1,5 +1,6 @@
import * as core from '../core';
import ObservablePoint from '../core/math/ObservablePoint';
+import { getResolutionOfUrl } from '../core/utils';
import settings from '../core/settings';
/**
@@ -510,7 +511,8 @@
const data = {};
const info = xml.getElementsByTagName('info')[0];
const common = xml.getElementsByTagName('common')[0];
- const res = texture.baseTexture.resolution || settings.RESOLUTION;
+ const fileName = xml.getElementsByTagName('page')[0].getAttribute('file');
+ const res = getResolutionOfUrl(fileName, settings.RESOLUTION);
data.font = info.getAttribute('face');
data.size = parseInt(info.getAttribute('size'), 10);
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
deleted file mode 100644
index 16536d2..0000000
--- a/src/extras/TextureTransform.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import { default as Matrix } from '../core/math/Matrix';
-
-const tempMat = new Matrix();
-
-/**
- * class controls uv transform and frame clamp for texture
- *
- * @class
- * @memberof PIXI.extras
- */
-export default class TextureTransform
-{
- /**
- *
- * @param {PIXI.Texture} texture observed texture
- * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
- * @constructor
- */
- constructor(texture, clampMargin)
- {
- this._texture = texture;
-
- this.mapCoord = new Matrix();
-
- this.uClampFrame = new Float32Array(4);
-
- this.uClampOffset = new Float32Array(2);
-
- this._lastTextureID = -1;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
- *
- * @default 0
- * @member {number}
- */
- this.clampOffset = 0;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
- *
- * @default 0.5
- * @member {number}
- */
- this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
- }
-
- /**
- * texture property
- * @member {PIXI.Texture}
- */
- get texture()
- {
- return this._texture;
- }
-
- set texture(value) // eslint-disable-line require-jsdoc
- {
- this._texture = value;
- this._lastTextureID = -1;
- }
-
- /**
- * Multiplies uvs array to transform
- * @param {Float32Array} uvs mesh uvs
- * @param {Float32Array} [out=uvs] output
- * @returns {Float32Array} output
- */
- multiplyUvs(uvs, out)
- {
- if (out === undefined)
- {
- out = uvs;
- }
-
- const mat = this.mapCoord;
-
- for (let i = 0; i < uvs.length; i += 2)
- {
- const x = uvs[i];
- const y = uvs[i + 1];
-
- out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
- out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
- }
-
- return out;
- }
-
- /**
- * updates matrices if texture was changed
- * @param {boolean} forceUpdate if true, matrices will be updated any case
- * @returns {boolean} whether or not it was updated
- */
- update(forceUpdate)
- {
- const tex = this._texture;
-
- if (!tex || !tex.valid)
- {
- return false;
- }
-
- if (!forceUpdate
- && this._lastTextureID === tex._updateID)
- {
- return false;
- }
-
- this._lastTextureID = tex._updateID;
-
- const uvs = tex._uvs;
-
- this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
-
- const orig = tex.orig;
- const trim = tex.trim;
-
- if (trim)
- {
- tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
- -trim.x / trim.width, -trim.y / trim.height);
- this.mapCoord.append(tempMat);
- }
-
- const texBase = tex.baseTexture;
- const frame = this.uClampFrame;
- const margin = this.clampMargin / texBase.resolution;
- const offset = this.clampOffset;
-
- frame[0] = (tex._frame.x + margin + offset) / texBase.width;
- frame[1] = (tex._frame.y + margin + offset) / texBase.height;
- frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
- frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
- this.uClampOffset[0] = offset / texBase.realWidth;
- this.uClampOffset[1] = offset / texBase.realHeight;
-
- return true;
- }
-}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 736b207..84c0841 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -1,6 +1,5 @@
import * as core from '../core';
import CanvasTinter from '../core/sprites/canvas/CanvasTinter';
-import { default as TextureTransform } from './TextureTransform';
const tempPoint = new core.Point();
@@ -58,9 +57,9 @@
/**
* transform that is applied to UV to get the texture coords
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
*/
- this.uvTransform = texture.transform || new TextureTransform(texture);
+ this.uvTransform = texture.transform || new core.TextureMatrix(texture);
/**
* Plugin that is responsible for rendering this element.
diff --git a/src/extras/index.js b/src/extras/index.js
index 5b98cb1..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -3,7 +3,6 @@
* @namespace PIXI.extras
*/
export { default as AnimatedSprite } from './AnimatedSprite';
-export { default as TextureTransform } from './TextureTransform';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
export { default as BitmapText } from './BitmapText';
diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js
new file mode 100644
index 0000000..c2824ed
--- /dev/null
+++ b/src/filters/alpha/AlphaFilter.js
@@ -0,0 +1,55 @@
+import * as core from '../../core';
+import { readFileSync } from 'fs';
+import { join } from 'path';
+
+/**
+ * Simplest filter - applies alpha
+ *
+ * Use this instead of Container's alpha property to avoid visual layering of individual elements.
+ * AlphaFilter applies alpha evenly across the entire display object and any opaque elements it contains.
+ * If elements are not opaque, they will blend with each other anyway.
+ *
+ * Very handy if you want to use common features of all filters:
+ *
+ * 1. Assign a blendMode to this filter, blend all elements inside display object with background.
+ *
+ * 2. To use clipping in display coordinates, assign a filterArea to the same container that has this filter.
+ *
+ * @class
+ * @extends PIXI.Filter
+ * @memberof PIXI.filters
+ */
+export default class AlphaFilter extends core.Filter
+{
+ /**
+ *
+ */
+ constructor()
+ {
+ super(
+ // vertex shader
+ readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
+ // fragment shader
+ readFileSync(join(__dirname, './alpha.frag'), 'utf8')
+ );
+
+ this.alpha = 1.0;
+ this.glShaderKey = 'alpha';
+ }
+
+ /**
+ * Coefficient for alpha multiplication
+ *
+ * @member {number}
+ * @default 1
+ */
+ get alpha()
+ {
+ return this.uniforms.uAlpha;
+ }
+
+ set alpha(value) // eslint-disable-line require-jsdoc
+ {
+ this.uniforms.uAlpha = value;
+ }
+}
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/extras/BitmapText.js b/src/extras/BitmapText.js
index 0592b54..96d9f44 100644
--- a/src/extras/BitmapText.js
+++ b/src/extras/BitmapText.js
@@ -1,5 +1,6 @@
import * as core from '../core';
import ObservablePoint from '../core/math/ObservablePoint';
+import { getResolutionOfUrl } from '../core/utils';
import settings from '../core/settings';
/**
@@ -510,7 +511,8 @@
const data = {};
const info = xml.getElementsByTagName('info')[0];
const common = xml.getElementsByTagName('common')[0];
- const res = texture.baseTexture.resolution || settings.RESOLUTION;
+ const fileName = xml.getElementsByTagName('page')[0].getAttribute('file');
+ const res = getResolutionOfUrl(fileName, settings.RESOLUTION);
data.font = info.getAttribute('face');
data.size = parseInt(info.getAttribute('size'), 10);
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
deleted file mode 100644
index 16536d2..0000000
--- a/src/extras/TextureTransform.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import { default as Matrix } from '../core/math/Matrix';
-
-const tempMat = new Matrix();
-
-/**
- * class controls uv transform and frame clamp for texture
- *
- * @class
- * @memberof PIXI.extras
- */
-export default class TextureTransform
-{
- /**
- *
- * @param {PIXI.Texture} texture observed texture
- * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
- * @constructor
- */
- constructor(texture, clampMargin)
- {
- this._texture = texture;
-
- this.mapCoord = new Matrix();
-
- this.uClampFrame = new Float32Array(4);
-
- this.uClampOffset = new Float32Array(2);
-
- this._lastTextureID = -1;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
- *
- * @default 0
- * @member {number}
- */
- this.clampOffset = 0;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
- *
- * @default 0.5
- * @member {number}
- */
- this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
- }
-
- /**
- * texture property
- * @member {PIXI.Texture}
- */
- get texture()
- {
- return this._texture;
- }
-
- set texture(value) // eslint-disable-line require-jsdoc
- {
- this._texture = value;
- this._lastTextureID = -1;
- }
-
- /**
- * Multiplies uvs array to transform
- * @param {Float32Array} uvs mesh uvs
- * @param {Float32Array} [out=uvs] output
- * @returns {Float32Array} output
- */
- multiplyUvs(uvs, out)
- {
- if (out === undefined)
- {
- out = uvs;
- }
-
- const mat = this.mapCoord;
-
- for (let i = 0; i < uvs.length; i += 2)
- {
- const x = uvs[i];
- const y = uvs[i + 1];
-
- out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
- out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
- }
-
- return out;
- }
-
- /**
- * updates matrices if texture was changed
- * @param {boolean} forceUpdate if true, matrices will be updated any case
- * @returns {boolean} whether or not it was updated
- */
- update(forceUpdate)
- {
- const tex = this._texture;
-
- if (!tex || !tex.valid)
- {
- return false;
- }
-
- if (!forceUpdate
- && this._lastTextureID === tex._updateID)
- {
- return false;
- }
-
- this._lastTextureID = tex._updateID;
-
- const uvs = tex._uvs;
-
- this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
-
- const orig = tex.orig;
- const trim = tex.trim;
-
- if (trim)
- {
- tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
- -trim.x / trim.width, -trim.y / trim.height);
- this.mapCoord.append(tempMat);
- }
-
- const texBase = tex.baseTexture;
- const frame = this.uClampFrame;
- const margin = this.clampMargin / texBase.resolution;
- const offset = this.clampOffset;
-
- frame[0] = (tex._frame.x + margin + offset) / texBase.width;
- frame[1] = (tex._frame.y + margin + offset) / texBase.height;
- frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
- frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
- this.uClampOffset[0] = offset / texBase.realWidth;
- this.uClampOffset[1] = offset / texBase.realHeight;
-
- return true;
- }
-}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 736b207..84c0841 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -1,6 +1,5 @@
import * as core from '../core';
import CanvasTinter from '../core/sprites/canvas/CanvasTinter';
-import { default as TextureTransform } from './TextureTransform';
const tempPoint = new core.Point();
@@ -58,9 +57,9 @@
/**
* transform that is applied to UV to get the texture coords
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
*/
- this.uvTransform = texture.transform || new TextureTransform(texture);
+ this.uvTransform = texture.transform || new core.TextureMatrix(texture);
/**
* Plugin that is responsible for rendering this element.
diff --git a/src/extras/index.js b/src/extras/index.js
index 5b98cb1..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -3,7 +3,6 @@
* @namespace PIXI.extras
*/
export { default as AnimatedSprite } from './AnimatedSprite';
-export { default as TextureTransform } from './TextureTransform';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
export { default as BitmapText } from './BitmapText';
diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js
new file mode 100644
index 0000000..c2824ed
--- /dev/null
+++ b/src/filters/alpha/AlphaFilter.js
@@ -0,0 +1,55 @@
+import * as core from '../../core';
+import { readFileSync } from 'fs';
+import { join } from 'path';
+
+/**
+ * Simplest filter - applies alpha
+ *
+ * Use this instead of Container's alpha property to avoid visual layering of individual elements.
+ * AlphaFilter applies alpha evenly across the entire display object and any opaque elements it contains.
+ * If elements are not opaque, they will blend with each other anyway.
+ *
+ * Very handy if you want to use common features of all filters:
+ *
+ * 1. Assign a blendMode to this filter, blend all elements inside display object with background.
+ *
+ * 2. To use clipping in display coordinates, assign a filterArea to the same container that has this filter.
+ *
+ * @class
+ * @extends PIXI.Filter
+ * @memberof PIXI.filters
+ */
+export default class AlphaFilter extends core.Filter
+{
+ /**
+ *
+ */
+ constructor()
+ {
+ super(
+ // vertex shader
+ readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
+ // fragment shader
+ readFileSync(join(__dirname, './alpha.frag'), 'utf8')
+ );
+
+ this.alpha = 1.0;
+ this.glShaderKey = 'alpha';
+ }
+
+ /**
+ * Coefficient for alpha multiplication
+ *
+ * @member {number}
+ * @default 1
+ */
+ get alpha()
+ {
+ return this.uniforms.uAlpha;
+ }
+
+ set alpha(value) // eslint-disable-line require-jsdoc
+ {
+ this.uniforms.uAlpha = value;
+ }
+}
diff --git a/src/filters/alpha/alpha.frag b/src/filters/alpha/alpha.frag
new file mode 100644
index 0000000..6db588c
--- /dev/null
+++ b/src/filters/alpha/alpha.frag
@@ -0,0 +1,9 @@
+varying vec2 vTextureCoord;
+
+uniform sampler2D uSampler;
+uniform float uAlpha;
+
+void main(void)
+{
+ gl_FragColor = texture2D(uSampler, vTextureCoord) * uAlpha;
+}
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/extras/BitmapText.js b/src/extras/BitmapText.js
index 0592b54..96d9f44 100644
--- a/src/extras/BitmapText.js
+++ b/src/extras/BitmapText.js
@@ -1,5 +1,6 @@
import * as core from '../core';
import ObservablePoint from '../core/math/ObservablePoint';
+import { getResolutionOfUrl } from '../core/utils';
import settings from '../core/settings';
/**
@@ -510,7 +511,8 @@
const data = {};
const info = xml.getElementsByTagName('info')[0];
const common = xml.getElementsByTagName('common')[0];
- const res = texture.baseTexture.resolution || settings.RESOLUTION;
+ const fileName = xml.getElementsByTagName('page')[0].getAttribute('file');
+ const res = getResolutionOfUrl(fileName, settings.RESOLUTION);
data.font = info.getAttribute('face');
data.size = parseInt(info.getAttribute('size'), 10);
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
deleted file mode 100644
index 16536d2..0000000
--- a/src/extras/TextureTransform.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import { default as Matrix } from '../core/math/Matrix';
-
-const tempMat = new Matrix();
-
-/**
- * class controls uv transform and frame clamp for texture
- *
- * @class
- * @memberof PIXI.extras
- */
-export default class TextureTransform
-{
- /**
- *
- * @param {PIXI.Texture} texture observed texture
- * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
- * @constructor
- */
- constructor(texture, clampMargin)
- {
- this._texture = texture;
-
- this.mapCoord = new Matrix();
-
- this.uClampFrame = new Float32Array(4);
-
- this.uClampOffset = new Float32Array(2);
-
- this._lastTextureID = -1;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
- *
- * @default 0
- * @member {number}
- */
- this.clampOffset = 0;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
- *
- * @default 0.5
- * @member {number}
- */
- this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
- }
-
- /**
- * texture property
- * @member {PIXI.Texture}
- */
- get texture()
- {
- return this._texture;
- }
-
- set texture(value) // eslint-disable-line require-jsdoc
- {
- this._texture = value;
- this._lastTextureID = -1;
- }
-
- /**
- * Multiplies uvs array to transform
- * @param {Float32Array} uvs mesh uvs
- * @param {Float32Array} [out=uvs] output
- * @returns {Float32Array} output
- */
- multiplyUvs(uvs, out)
- {
- if (out === undefined)
- {
- out = uvs;
- }
-
- const mat = this.mapCoord;
-
- for (let i = 0; i < uvs.length; i += 2)
- {
- const x = uvs[i];
- const y = uvs[i + 1];
-
- out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
- out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
- }
-
- return out;
- }
-
- /**
- * updates matrices if texture was changed
- * @param {boolean} forceUpdate if true, matrices will be updated any case
- * @returns {boolean} whether or not it was updated
- */
- update(forceUpdate)
- {
- const tex = this._texture;
-
- if (!tex || !tex.valid)
- {
- return false;
- }
-
- if (!forceUpdate
- && this._lastTextureID === tex._updateID)
- {
- return false;
- }
-
- this._lastTextureID = tex._updateID;
-
- const uvs = tex._uvs;
-
- this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
-
- const orig = tex.orig;
- const trim = tex.trim;
-
- if (trim)
- {
- tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
- -trim.x / trim.width, -trim.y / trim.height);
- this.mapCoord.append(tempMat);
- }
-
- const texBase = tex.baseTexture;
- const frame = this.uClampFrame;
- const margin = this.clampMargin / texBase.resolution;
- const offset = this.clampOffset;
-
- frame[0] = (tex._frame.x + margin + offset) / texBase.width;
- frame[1] = (tex._frame.y + margin + offset) / texBase.height;
- frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
- frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
- this.uClampOffset[0] = offset / texBase.realWidth;
- this.uClampOffset[1] = offset / texBase.realHeight;
-
- return true;
- }
-}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 736b207..84c0841 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -1,6 +1,5 @@
import * as core from '../core';
import CanvasTinter from '../core/sprites/canvas/CanvasTinter';
-import { default as TextureTransform } from './TextureTransform';
const tempPoint = new core.Point();
@@ -58,9 +57,9 @@
/**
* transform that is applied to UV to get the texture coords
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
*/
- this.uvTransform = texture.transform || new TextureTransform(texture);
+ this.uvTransform = texture.transform || new core.TextureMatrix(texture);
/**
* Plugin that is responsible for rendering this element.
diff --git a/src/extras/index.js b/src/extras/index.js
index 5b98cb1..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -3,7 +3,6 @@
* @namespace PIXI.extras
*/
export { default as AnimatedSprite } from './AnimatedSprite';
-export { default as TextureTransform } from './TextureTransform';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
export { default as BitmapText } from './BitmapText';
diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js
new file mode 100644
index 0000000..c2824ed
--- /dev/null
+++ b/src/filters/alpha/AlphaFilter.js
@@ -0,0 +1,55 @@
+import * as core from '../../core';
+import { readFileSync } from 'fs';
+import { join } from 'path';
+
+/**
+ * Simplest filter - applies alpha
+ *
+ * Use this instead of Container's alpha property to avoid visual layering of individual elements.
+ * AlphaFilter applies alpha evenly across the entire display object and any opaque elements it contains.
+ * If elements are not opaque, they will blend with each other anyway.
+ *
+ * Very handy if you want to use common features of all filters:
+ *
+ * 1. Assign a blendMode to this filter, blend all elements inside display object with background.
+ *
+ * 2. To use clipping in display coordinates, assign a filterArea to the same container that has this filter.
+ *
+ * @class
+ * @extends PIXI.Filter
+ * @memberof PIXI.filters
+ */
+export default class AlphaFilter extends core.Filter
+{
+ /**
+ *
+ */
+ constructor()
+ {
+ super(
+ // vertex shader
+ readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
+ // fragment shader
+ readFileSync(join(__dirname, './alpha.frag'), 'utf8')
+ );
+
+ this.alpha = 1.0;
+ this.glShaderKey = 'alpha';
+ }
+
+ /**
+ * Coefficient for alpha multiplication
+ *
+ * @member {number}
+ * @default 1
+ */
+ get alpha()
+ {
+ return this.uniforms.uAlpha;
+ }
+
+ set alpha(value) // eslint-disable-line require-jsdoc
+ {
+ this.uniforms.uAlpha = value;
+ }
+}
diff --git a/src/filters/alpha/alpha.frag b/src/filters/alpha/alpha.frag
new file mode 100644
index 0000000..6db588c
--- /dev/null
+++ b/src/filters/alpha/alpha.frag
@@ -0,0 +1,9 @@
+varying vec2 vTextureCoord;
+
+uniform sampler2D uSampler;
+uniform float uAlpha;
+
+void main(void)
+{
+ gl_FragColor = texture2D(uSampler, vTextureCoord) * uAlpha;
+}
diff --git a/src/filters/index.js b/src/filters/index.js
index 7ceb50a..dca47ab 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -25,4 +25,4 @@
export { default as BlurXFilter } from './blur/BlurXFilter';
export { default as BlurYFilter } from './blur/BlurYFilter';
export { default as ColorMatrixFilter } from './colormatrix/ColorMatrixFilter';
-export { default as VoidFilter } from './void/VoidFilter';
+export { default as AlphaFilter } from './alpha/AlphaFilter';
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/extras/BitmapText.js b/src/extras/BitmapText.js
index 0592b54..96d9f44 100644
--- a/src/extras/BitmapText.js
+++ b/src/extras/BitmapText.js
@@ -1,5 +1,6 @@
import * as core from '../core';
import ObservablePoint from '../core/math/ObservablePoint';
+import { getResolutionOfUrl } from '../core/utils';
import settings from '../core/settings';
/**
@@ -510,7 +511,8 @@
const data = {};
const info = xml.getElementsByTagName('info')[0];
const common = xml.getElementsByTagName('common')[0];
- const res = texture.baseTexture.resolution || settings.RESOLUTION;
+ const fileName = xml.getElementsByTagName('page')[0].getAttribute('file');
+ const res = getResolutionOfUrl(fileName, settings.RESOLUTION);
data.font = info.getAttribute('face');
data.size = parseInt(info.getAttribute('size'), 10);
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
deleted file mode 100644
index 16536d2..0000000
--- a/src/extras/TextureTransform.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import { default as Matrix } from '../core/math/Matrix';
-
-const tempMat = new Matrix();
-
-/**
- * class controls uv transform and frame clamp for texture
- *
- * @class
- * @memberof PIXI.extras
- */
-export default class TextureTransform
-{
- /**
- *
- * @param {PIXI.Texture} texture observed texture
- * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
- * @constructor
- */
- constructor(texture, clampMargin)
- {
- this._texture = texture;
-
- this.mapCoord = new Matrix();
-
- this.uClampFrame = new Float32Array(4);
-
- this.uClampOffset = new Float32Array(2);
-
- this._lastTextureID = -1;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
- *
- * @default 0
- * @member {number}
- */
- this.clampOffset = 0;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
- *
- * @default 0.5
- * @member {number}
- */
- this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
- }
-
- /**
- * texture property
- * @member {PIXI.Texture}
- */
- get texture()
- {
- return this._texture;
- }
-
- set texture(value) // eslint-disable-line require-jsdoc
- {
- this._texture = value;
- this._lastTextureID = -1;
- }
-
- /**
- * Multiplies uvs array to transform
- * @param {Float32Array} uvs mesh uvs
- * @param {Float32Array} [out=uvs] output
- * @returns {Float32Array} output
- */
- multiplyUvs(uvs, out)
- {
- if (out === undefined)
- {
- out = uvs;
- }
-
- const mat = this.mapCoord;
-
- for (let i = 0; i < uvs.length; i += 2)
- {
- const x = uvs[i];
- const y = uvs[i + 1];
-
- out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
- out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
- }
-
- return out;
- }
-
- /**
- * updates matrices if texture was changed
- * @param {boolean} forceUpdate if true, matrices will be updated any case
- * @returns {boolean} whether or not it was updated
- */
- update(forceUpdate)
- {
- const tex = this._texture;
-
- if (!tex || !tex.valid)
- {
- return false;
- }
-
- if (!forceUpdate
- && this._lastTextureID === tex._updateID)
- {
- return false;
- }
-
- this._lastTextureID = tex._updateID;
-
- const uvs = tex._uvs;
-
- this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
-
- const orig = tex.orig;
- const trim = tex.trim;
-
- if (trim)
- {
- tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
- -trim.x / trim.width, -trim.y / trim.height);
- this.mapCoord.append(tempMat);
- }
-
- const texBase = tex.baseTexture;
- const frame = this.uClampFrame;
- const margin = this.clampMargin / texBase.resolution;
- const offset = this.clampOffset;
-
- frame[0] = (tex._frame.x + margin + offset) / texBase.width;
- frame[1] = (tex._frame.y + margin + offset) / texBase.height;
- frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
- frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
- this.uClampOffset[0] = offset / texBase.realWidth;
- this.uClampOffset[1] = offset / texBase.realHeight;
-
- return true;
- }
-}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 736b207..84c0841 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -1,6 +1,5 @@
import * as core from '../core';
import CanvasTinter from '../core/sprites/canvas/CanvasTinter';
-import { default as TextureTransform } from './TextureTransform';
const tempPoint = new core.Point();
@@ -58,9 +57,9 @@
/**
* transform that is applied to UV to get the texture coords
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
*/
- this.uvTransform = texture.transform || new TextureTransform(texture);
+ this.uvTransform = texture.transform || new core.TextureMatrix(texture);
/**
* Plugin that is responsible for rendering this element.
diff --git a/src/extras/index.js b/src/extras/index.js
index 5b98cb1..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -3,7 +3,6 @@
* @namespace PIXI.extras
*/
export { default as AnimatedSprite } from './AnimatedSprite';
-export { default as TextureTransform } from './TextureTransform';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
export { default as BitmapText } from './BitmapText';
diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js
new file mode 100644
index 0000000..c2824ed
--- /dev/null
+++ b/src/filters/alpha/AlphaFilter.js
@@ -0,0 +1,55 @@
+import * as core from '../../core';
+import { readFileSync } from 'fs';
+import { join } from 'path';
+
+/**
+ * Simplest filter - applies alpha
+ *
+ * Use this instead of Container's alpha property to avoid visual layering of individual elements.
+ * AlphaFilter applies alpha evenly across the entire display object and any opaque elements it contains.
+ * If elements are not opaque, they will blend with each other anyway.
+ *
+ * Very handy if you want to use common features of all filters:
+ *
+ * 1. Assign a blendMode to this filter, blend all elements inside display object with background.
+ *
+ * 2. To use clipping in display coordinates, assign a filterArea to the same container that has this filter.
+ *
+ * @class
+ * @extends PIXI.Filter
+ * @memberof PIXI.filters
+ */
+export default class AlphaFilter extends core.Filter
+{
+ /**
+ *
+ */
+ constructor()
+ {
+ super(
+ // vertex shader
+ readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
+ // fragment shader
+ readFileSync(join(__dirname, './alpha.frag'), 'utf8')
+ );
+
+ this.alpha = 1.0;
+ this.glShaderKey = 'alpha';
+ }
+
+ /**
+ * Coefficient for alpha multiplication
+ *
+ * @member {number}
+ * @default 1
+ */
+ get alpha()
+ {
+ return this.uniforms.uAlpha;
+ }
+
+ set alpha(value) // eslint-disable-line require-jsdoc
+ {
+ this.uniforms.uAlpha = value;
+ }
+}
diff --git a/src/filters/alpha/alpha.frag b/src/filters/alpha/alpha.frag
new file mode 100644
index 0000000..6db588c
--- /dev/null
+++ b/src/filters/alpha/alpha.frag
@@ -0,0 +1,9 @@
+varying vec2 vTextureCoord;
+
+uniform sampler2D uSampler;
+uniform float uAlpha;
+
+void main(void)
+{
+ gl_FragColor = texture2D(uSampler, vTextureCoord) * uAlpha;
+}
diff --git a/src/filters/index.js b/src/filters/index.js
index 7ceb50a..dca47ab 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -25,4 +25,4 @@
export { default as BlurXFilter } from './blur/BlurXFilter';
export { default as BlurYFilter } from './blur/BlurYFilter';
export { default as ColorMatrixFilter } from './colormatrix/ColorMatrixFilter';
-export { default as VoidFilter } from './void/VoidFilter';
+export { default as AlphaFilter } from './alpha/AlphaFilter';
diff --git a/src/filters/void/VoidFilter.js b/src/filters/void/VoidFilter.js
deleted file mode 100644
index b4361ac..0000000
--- a/src/filters/void/VoidFilter.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as core from '../../core';
-import { readFileSync } from 'fs';
-import { join } from 'path';
-
-/**
- * Does nothing. Very handy.
- *
- * @class
- * @extends PIXI.Filter
- * @memberof PIXI.filters
- */
-export default class VoidFilter extends core.Filter
-{
- /**
- *
- */
- constructor()
- {
- super(
- // vertex shader
- readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
- // fragment shader
- readFileSync(join(__dirname, './void.frag'), 'utf8')
- );
-
- this.glShaderKey = 'void';
- }
-}
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/extras/BitmapText.js b/src/extras/BitmapText.js
index 0592b54..96d9f44 100644
--- a/src/extras/BitmapText.js
+++ b/src/extras/BitmapText.js
@@ -1,5 +1,6 @@
import * as core from '../core';
import ObservablePoint from '../core/math/ObservablePoint';
+import { getResolutionOfUrl } from '../core/utils';
import settings from '../core/settings';
/**
@@ -510,7 +511,8 @@
const data = {};
const info = xml.getElementsByTagName('info')[0];
const common = xml.getElementsByTagName('common')[0];
- const res = texture.baseTexture.resolution || settings.RESOLUTION;
+ const fileName = xml.getElementsByTagName('page')[0].getAttribute('file');
+ const res = getResolutionOfUrl(fileName, settings.RESOLUTION);
data.font = info.getAttribute('face');
data.size = parseInt(info.getAttribute('size'), 10);
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
deleted file mode 100644
index 16536d2..0000000
--- a/src/extras/TextureTransform.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import { default as Matrix } from '../core/math/Matrix';
-
-const tempMat = new Matrix();
-
-/**
- * class controls uv transform and frame clamp for texture
- *
- * @class
- * @memberof PIXI.extras
- */
-export default class TextureTransform
-{
- /**
- *
- * @param {PIXI.Texture} texture observed texture
- * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
- * @constructor
- */
- constructor(texture, clampMargin)
- {
- this._texture = texture;
-
- this.mapCoord = new Matrix();
-
- this.uClampFrame = new Float32Array(4);
-
- this.uClampOffset = new Float32Array(2);
-
- this._lastTextureID = -1;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
- *
- * @default 0
- * @member {number}
- */
- this.clampOffset = 0;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
- *
- * @default 0.5
- * @member {number}
- */
- this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
- }
-
- /**
- * texture property
- * @member {PIXI.Texture}
- */
- get texture()
- {
- return this._texture;
- }
-
- set texture(value) // eslint-disable-line require-jsdoc
- {
- this._texture = value;
- this._lastTextureID = -1;
- }
-
- /**
- * Multiplies uvs array to transform
- * @param {Float32Array} uvs mesh uvs
- * @param {Float32Array} [out=uvs] output
- * @returns {Float32Array} output
- */
- multiplyUvs(uvs, out)
- {
- if (out === undefined)
- {
- out = uvs;
- }
-
- const mat = this.mapCoord;
-
- for (let i = 0; i < uvs.length; i += 2)
- {
- const x = uvs[i];
- const y = uvs[i + 1];
-
- out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
- out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
- }
-
- return out;
- }
-
- /**
- * updates matrices if texture was changed
- * @param {boolean} forceUpdate if true, matrices will be updated any case
- * @returns {boolean} whether or not it was updated
- */
- update(forceUpdate)
- {
- const tex = this._texture;
-
- if (!tex || !tex.valid)
- {
- return false;
- }
-
- if (!forceUpdate
- && this._lastTextureID === tex._updateID)
- {
- return false;
- }
-
- this._lastTextureID = tex._updateID;
-
- const uvs = tex._uvs;
-
- this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
-
- const orig = tex.orig;
- const trim = tex.trim;
-
- if (trim)
- {
- tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
- -trim.x / trim.width, -trim.y / trim.height);
- this.mapCoord.append(tempMat);
- }
-
- const texBase = tex.baseTexture;
- const frame = this.uClampFrame;
- const margin = this.clampMargin / texBase.resolution;
- const offset = this.clampOffset;
-
- frame[0] = (tex._frame.x + margin + offset) / texBase.width;
- frame[1] = (tex._frame.y + margin + offset) / texBase.height;
- frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
- frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
- this.uClampOffset[0] = offset / texBase.realWidth;
- this.uClampOffset[1] = offset / texBase.realHeight;
-
- return true;
- }
-}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 736b207..84c0841 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -1,6 +1,5 @@
import * as core from '../core';
import CanvasTinter from '../core/sprites/canvas/CanvasTinter';
-import { default as TextureTransform } from './TextureTransform';
const tempPoint = new core.Point();
@@ -58,9 +57,9 @@
/**
* transform that is applied to UV to get the texture coords
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
*/
- this.uvTransform = texture.transform || new TextureTransform(texture);
+ this.uvTransform = texture.transform || new core.TextureMatrix(texture);
/**
* Plugin that is responsible for rendering this element.
diff --git a/src/extras/index.js b/src/extras/index.js
index 5b98cb1..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -3,7 +3,6 @@
* @namespace PIXI.extras
*/
export { default as AnimatedSprite } from './AnimatedSprite';
-export { default as TextureTransform } from './TextureTransform';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
export { default as BitmapText } from './BitmapText';
diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js
new file mode 100644
index 0000000..c2824ed
--- /dev/null
+++ b/src/filters/alpha/AlphaFilter.js
@@ -0,0 +1,55 @@
+import * as core from '../../core';
+import { readFileSync } from 'fs';
+import { join } from 'path';
+
+/**
+ * Simplest filter - applies alpha
+ *
+ * Use this instead of Container's alpha property to avoid visual layering of individual elements.
+ * AlphaFilter applies alpha evenly across the entire display object and any opaque elements it contains.
+ * If elements are not opaque, they will blend with each other anyway.
+ *
+ * Very handy if you want to use common features of all filters:
+ *
+ * 1. Assign a blendMode to this filter, blend all elements inside display object with background.
+ *
+ * 2. To use clipping in display coordinates, assign a filterArea to the same container that has this filter.
+ *
+ * @class
+ * @extends PIXI.Filter
+ * @memberof PIXI.filters
+ */
+export default class AlphaFilter extends core.Filter
+{
+ /**
+ *
+ */
+ constructor()
+ {
+ super(
+ // vertex shader
+ readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
+ // fragment shader
+ readFileSync(join(__dirname, './alpha.frag'), 'utf8')
+ );
+
+ this.alpha = 1.0;
+ this.glShaderKey = 'alpha';
+ }
+
+ /**
+ * Coefficient for alpha multiplication
+ *
+ * @member {number}
+ * @default 1
+ */
+ get alpha()
+ {
+ return this.uniforms.uAlpha;
+ }
+
+ set alpha(value) // eslint-disable-line require-jsdoc
+ {
+ this.uniforms.uAlpha = value;
+ }
+}
diff --git a/src/filters/alpha/alpha.frag b/src/filters/alpha/alpha.frag
new file mode 100644
index 0000000..6db588c
--- /dev/null
+++ b/src/filters/alpha/alpha.frag
@@ -0,0 +1,9 @@
+varying vec2 vTextureCoord;
+
+uniform sampler2D uSampler;
+uniform float uAlpha;
+
+void main(void)
+{
+ gl_FragColor = texture2D(uSampler, vTextureCoord) * uAlpha;
+}
diff --git a/src/filters/index.js b/src/filters/index.js
index 7ceb50a..dca47ab 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -25,4 +25,4 @@
export { default as BlurXFilter } from './blur/BlurXFilter';
export { default as BlurYFilter } from './blur/BlurYFilter';
export { default as ColorMatrixFilter } from './colormatrix/ColorMatrixFilter';
-export { default as VoidFilter } from './void/VoidFilter';
+export { default as AlphaFilter } from './alpha/AlphaFilter';
diff --git a/src/filters/void/VoidFilter.js b/src/filters/void/VoidFilter.js
deleted file mode 100644
index b4361ac..0000000
--- a/src/filters/void/VoidFilter.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as core from '../../core';
-import { readFileSync } from 'fs';
-import { join } from 'path';
-
-/**
- * Does nothing. Very handy.
- *
- * @class
- * @extends PIXI.Filter
- * @memberof PIXI.filters
- */
-export default class VoidFilter extends core.Filter
-{
- /**
- *
- */
- constructor()
- {
- super(
- // vertex shader
- readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
- // fragment shader
- readFileSync(join(__dirname, './void.frag'), 'utf8')
- );
-
- this.glShaderKey = 'void';
- }
-}
diff --git a/src/filters/void/void.frag b/src/filters/void/void.frag
deleted file mode 100644
index 99168fb..0000000
--- a/src/filters/void/void.frag
+++ /dev/null
@@ -1,8 +0,0 @@
-varying vec2 vTextureCoord;
-
-uniform sampler2D uSampler;
-
-void main(void)
-{
- gl_FragColor = texture2D(uSampler, vTextureCoord);
-}
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/extras/BitmapText.js b/src/extras/BitmapText.js
index 0592b54..96d9f44 100644
--- a/src/extras/BitmapText.js
+++ b/src/extras/BitmapText.js
@@ -1,5 +1,6 @@
import * as core from '../core';
import ObservablePoint from '../core/math/ObservablePoint';
+import { getResolutionOfUrl } from '../core/utils';
import settings from '../core/settings';
/**
@@ -510,7 +511,8 @@
const data = {};
const info = xml.getElementsByTagName('info')[0];
const common = xml.getElementsByTagName('common')[0];
- const res = texture.baseTexture.resolution || settings.RESOLUTION;
+ const fileName = xml.getElementsByTagName('page')[0].getAttribute('file');
+ const res = getResolutionOfUrl(fileName, settings.RESOLUTION);
data.font = info.getAttribute('face');
data.size = parseInt(info.getAttribute('size'), 10);
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
deleted file mode 100644
index 16536d2..0000000
--- a/src/extras/TextureTransform.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import { default as Matrix } from '../core/math/Matrix';
-
-const tempMat = new Matrix();
-
-/**
- * class controls uv transform and frame clamp for texture
- *
- * @class
- * @memberof PIXI.extras
- */
-export default class TextureTransform
-{
- /**
- *
- * @param {PIXI.Texture} texture observed texture
- * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
- * @constructor
- */
- constructor(texture, clampMargin)
- {
- this._texture = texture;
-
- this.mapCoord = new Matrix();
-
- this.uClampFrame = new Float32Array(4);
-
- this.uClampOffset = new Float32Array(2);
-
- this._lastTextureID = -1;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
- *
- * @default 0
- * @member {number}
- */
- this.clampOffset = 0;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
- *
- * @default 0.5
- * @member {number}
- */
- this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
- }
-
- /**
- * texture property
- * @member {PIXI.Texture}
- */
- get texture()
- {
- return this._texture;
- }
-
- set texture(value) // eslint-disable-line require-jsdoc
- {
- this._texture = value;
- this._lastTextureID = -1;
- }
-
- /**
- * Multiplies uvs array to transform
- * @param {Float32Array} uvs mesh uvs
- * @param {Float32Array} [out=uvs] output
- * @returns {Float32Array} output
- */
- multiplyUvs(uvs, out)
- {
- if (out === undefined)
- {
- out = uvs;
- }
-
- const mat = this.mapCoord;
-
- for (let i = 0; i < uvs.length; i += 2)
- {
- const x = uvs[i];
- const y = uvs[i + 1];
-
- out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
- out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
- }
-
- return out;
- }
-
- /**
- * updates matrices if texture was changed
- * @param {boolean} forceUpdate if true, matrices will be updated any case
- * @returns {boolean} whether or not it was updated
- */
- update(forceUpdate)
- {
- const tex = this._texture;
-
- if (!tex || !tex.valid)
- {
- return false;
- }
-
- if (!forceUpdate
- && this._lastTextureID === tex._updateID)
- {
- return false;
- }
-
- this._lastTextureID = tex._updateID;
-
- const uvs = tex._uvs;
-
- this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
-
- const orig = tex.orig;
- const trim = tex.trim;
-
- if (trim)
- {
- tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
- -trim.x / trim.width, -trim.y / trim.height);
- this.mapCoord.append(tempMat);
- }
-
- const texBase = tex.baseTexture;
- const frame = this.uClampFrame;
- const margin = this.clampMargin / texBase.resolution;
- const offset = this.clampOffset;
-
- frame[0] = (tex._frame.x + margin + offset) / texBase.width;
- frame[1] = (tex._frame.y + margin + offset) / texBase.height;
- frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
- frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
- this.uClampOffset[0] = offset / texBase.realWidth;
- this.uClampOffset[1] = offset / texBase.realHeight;
-
- return true;
- }
-}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 736b207..84c0841 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -1,6 +1,5 @@
import * as core from '../core';
import CanvasTinter from '../core/sprites/canvas/CanvasTinter';
-import { default as TextureTransform } from './TextureTransform';
const tempPoint = new core.Point();
@@ -58,9 +57,9 @@
/**
* transform that is applied to UV to get the texture coords
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
*/
- this.uvTransform = texture.transform || new TextureTransform(texture);
+ this.uvTransform = texture.transform || new core.TextureMatrix(texture);
/**
* Plugin that is responsible for rendering this element.
diff --git a/src/extras/index.js b/src/extras/index.js
index 5b98cb1..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -3,7 +3,6 @@
* @namespace PIXI.extras
*/
export { default as AnimatedSprite } from './AnimatedSprite';
-export { default as TextureTransform } from './TextureTransform';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
export { default as BitmapText } from './BitmapText';
diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js
new file mode 100644
index 0000000..c2824ed
--- /dev/null
+++ b/src/filters/alpha/AlphaFilter.js
@@ -0,0 +1,55 @@
+import * as core from '../../core';
+import { readFileSync } from 'fs';
+import { join } from 'path';
+
+/**
+ * Simplest filter - applies alpha
+ *
+ * Use this instead of Container's alpha property to avoid visual layering of individual elements.
+ * AlphaFilter applies alpha evenly across the entire display object and any opaque elements it contains.
+ * If elements are not opaque, they will blend with each other anyway.
+ *
+ * Very handy if you want to use common features of all filters:
+ *
+ * 1. Assign a blendMode to this filter, blend all elements inside display object with background.
+ *
+ * 2. To use clipping in display coordinates, assign a filterArea to the same container that has this filter.
+ *
+ * @class
+ * @extends PIXI.Filter
+ * @memberof PIXI.filters
+ */
+export default class AlphaFilter extends core.Filter
+{
+ /**
+ *
+ */
+ constructor()
+ {
+ super(
+ // vertex shader
+ readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
+ // fragment shader
+ readFileSync(join(__dirname, './alpha.frag'), 'utf8')
+ );
+
+ this.alpha = 1.0;
+ this.glShaderKey = 'alpha';
+ }
+
+ /**
+ * Coefficient for alpha multiplication
+ *
+ * @member {number}
+ * @default 1
+ */
+ get alpha()
+ {
+ return this.uniforms.uAlpha;
+ }
+
+ set alpha(value) // eslint-disable-line require-jsdoc
+ {
+ this.uniforms.uAlpha = value;
+ }
+}
diff --git a/src/filters/alpha/alpha.frag b/src/filters/alpha/alpha.frag
new file mode 100644
index 0000000..6db588c
--- /dev/null
+++ b/src/filters/alpha/alpha.frag
@@ -0,0 +1,9 @@
+varying vec2 vTextureCoord;
+
+uniform sampler2D uSampler;
+uniform float uAlpha;
+
+void main(void)
+{
+ gl_FragColor = texture2D(uSampler, vTextureCoord) * uAlpha;
+}
diff --git a/src/filters/index.js b/src/filters/index.js
index 7ceb50a..dca47ab 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -25,4 +25,4 @@
export { default as BlurXFilter } from './blur/BlurXFilter';
export { default as BlurYFilter } from './blur/BlurYFilter';
export { default as ColorMatrixFilter } from './colormatrix/ColorMatrixFilter';
-export { default as VoidFilter } from './void/VoidFilter';
+export { default as AlphaFilter } from './alpha/AlphaFilter';
diff --git a/src/filters/void/VoidFilter.js b/src/filters/void/VoidFilter.js
deleted file mode 100644
index b4361ac..0000000
--- a/src/filters/void/VoidFilter.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as core from '../../core';
-import { readFileSync } from 'fs';
-import { join } from 'path';
-
-/**
- * Does nothing. Very handy.
- *
- * @class
- * @extends PIXI.Filter
- * @memberof PIXI.filters
- */
-export default class VoidFilter extends core.Filter
-{
- /**
- *
- */
- constructor()
- {
- super(
- // vertex shader
- readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
- // fragment shader
- readFileSync(join(__dirname, './void.frag'), 'utf8')
- );
-
- this.glShaderKey = 'void';
- }
-}
diff --git a/src/filters/void/void.frag b/src/filters/void/void.frag
deleted file mode 100644
index 99168fb..0000000
--- a/src/filters/void/void.frag
+++ /dev/null
@@ -1,8 +0,0 @@
-varying vec2 vTextureCoord;
-
-uniform sampler2D uSampler;
-
-void main(void)
-{
- gl_FragColor = texture2D(uSampler, vTextureCoord);
-}
diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js
index d866f03..7006a3e 100644
--- a/src/mesh/Mesh.js
+++ b/src/mesh/Mesh.js
@@ -1,5 +1,5 @@
import * as core from '../core';
-import { default as TextureTransform } from '../extras/TextureTransform';
+import Texture from '../core/textures/Texture';
const tempPoint = new core.Point();
const tempPolygon = new core.Polygon();
@@ -27,9 +27,10 @@
* The texture of the Mesh
*
* @member {PIXI.Texture}
+ * @default PIXI.Texture.EMPTY
* @private
*/
- this._texture = texture;
+ this._texture = texture || Texture.EMPTY;
/**
* The Uvs of the Mesh
@@ -129,10 +130,10 @@
* its updated independently from texture uvTransform
* updates of uvs are tied to that thing
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
* @private
*/
- this._uvTransform = new TextureTransform(texture);
+ this._uvTransform = new core.TextureMatrix(this._texture);
/**
* whether or not upload uvTransform to shader
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/extras/BitmapText.js b/src/extras/BitmapText.js
index 0592b54..96d9f44 100644
--- a/src/extras/BitmapText.js
+++ b/src/extras/BitmapText.js
@@ -1,5 +1,6 @@
import * as core from '../core';
import ObservablePoint from '../core/math/ObservablePoint';
+import { getResolutionOfUrl } from '../core/utils';
import settings from '../core/settings';
/**
@@ -510,7 +511,8 @@
const data = {};
const info = xml.getElementsByTagName('info')[0];
const common = xml.getElementsByTagName('common')[0];
- const res = texture.baseTexture.resolution || settings.RESOLUTION;
+ const fileName = xml.getElementsByTagName('page')[0].getAttribute('file');
+ const res = getResolutionOfUrl(fileName, settings.RESOLUTION);
data.font = info.getAttribute('face');
data.size = parseInt(info.getAttribute('size'), 10);
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
deleted file mode 100644
index 16536d2..0000000
--- a/src/extras/TextureTransform.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import { default as Matrix } from '../core/math/Matrix';
-
-const tempMat = new Matrix();
-
-/**
- * class controls uv transform and frame clamp for texture
- *
- * @class
- * @memberof PIXI.extras
- */
-export default class TextureTransform
-{
- /**
- *
- * @param {PIXI.Texture} texture observed texture
- * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
- * @constructor
- */
- constructor(texture, clampMargin)
- {
- this._texture = texture;
-
- this.mapCoord = new Matrix();
-
- this.uClampFrame = new Float32Array(4);
-
- this.uClampOffset = new Float32Array(2);
-
- this._lastTextureID = -1;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
- *
- * @default 0
- * @member {number}
- */
- this.clampOffset = 0;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
- *
- * @default 0.5
- * @member {number}
- */
- this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
- }
-
- /**
- * texture property
- * @member {PIXI.Texture}
- */
- get texture()
- {
- return this._texture;
- }
-
- set texture(value) // eslint-disable-line require-jsdoc
- {
- this._texture = value;
- this._lastTextureID = -1;
- }
-
- /**
- * Multiplies uvs array to transform
- * @param {Float32Array} uvs mesh uvs
- * @param {Float32Array} [out=uvs] output
- * @returns {Float32Array} output
- */
- multiplyUvs(uvs, out)
- {
- if (out === undefined)
- {
- out = uvs;
- }
-
- const mat = this.mapCoord;
-
- for (let i = 0; i < uvs.length; i += 2)
- {
- const x = uvs[i];
- const y = uvs[i + 1];
-
- out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
- out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
- }
-
- return out;
- }
-
- /**
- * updates matrices if texture was changed
- * @param {boolean} forceUpdate if true, matrices will be updated any case
- * @returns {boolean} whether or not it was updated
- */
- update(forceUpdate)
- {
- const tex = this._texture;
-
- if (!tex || !tex.valid)
- {
- return false;
- }
-
- if (!forceUpdate
- && this._lastTextureID === tex._updateID)
- {
- return false;
- }
-
- this._lastTextureID = tex._updateID;
-
- const uvs = tex._uvs;
-
- this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
-
- const orig = tex.orig;
- const trim = tex.trim;
-
- if (trim)
- {
- tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
- -trim.x / trim.width, -trim.y / trim.height);
- this.mapCoord.append(tempMat);
- }
-
- const texBase = tex.baseTexture;
- const frame = this.uClampFrame;
- const margin = this.clampMargin / texBase.resolution;
- const offset = this.clampOffset;
-
- frame[0] = (tex._frame.x + margin + offset) / texBase.width;
- frame[1] = (tex._frame.y + margin + offset) / texBase.height;
- frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
- frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
- this.uClampOffset[0] = offset / texBase.realWidth;
- this.uClampOffset[1] = offset / texBase.realHeight;
-
- return true;
- }
-}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 736b207..84c0841 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -1,6 +1,5 @@
import * as core from '../core';
import CanvasTinter from '../core/sprites/canvas/CanvasTinter';
-import { default as TextureTransform } from './TextureTransform';
const tempPoint = new core.Point();
@@ -58,9 +57,9 @@
/**
* transform that is applied to UV to get the texture coords
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
*/
- this.uvTransform = texture.transform || new TextureTransform(texture);
+ this.uvTransform = texture.transform || new core.TextureMatrix(texture);
/**
* Plugin that is responsible for rendering this element.
diff --git a/src/extras/index.js b/src/extras/index.js
index 5b98cb1..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -3,7 +3,6 @@
* @namespace PIXI.extras
*/
export { default as AnimatedSprite } from './AnimatedSprite';
-export { default as TextureTransform } from './TextureTransform';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
export { default as BitmapText } from './BitmapText';
diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js
new file mode 100644
index 0000000..c2824ed
--- /dev/null
+++ b/src/filters/alpha/AlphaFilter.js
@@ -0,0 +1,55 @@
+import * as core from '../../core';
+import { readFileSync } from 'fs';
+import { join } from 'path';
+
+/**
+ * Simplest filter - applies alpha
+ *
+ * Use this instead of Container's alpha property to avoid visual layering of individual elements.
+ * AlphaFilter applies alpha evenly across the entire display object and any opaque elements it contains.
+ * If elements are not opaque, they will blend with each other anyway.
+ *
+ * Very handy if you want to use common features of all filters:
+ *
+ * 1. Assign a blendMode to this filter, blend all elements inside display object with background.
+ *
+ * 2. To use clipping in display coordinates, assign a filterArea to the same container that has this filter.
+ *
+ * @class
+ * @extends PIXI.Filter
+ * @memberof PIXI.filters
+ */
+export default class AlphaFilter extends core.Filter
+{
+ /**
+ *
+ */
+ constructor()
+ {
+ super(
+ // vertex shader
+ readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
+ // fragment shader
+ readFileSync(join(__dirname, './alpha.frag'), 'utf8')
+ );
+
+ this.alpha = 1.0;
+ this.glShaderKey = 'alpha';
+ }
+
+ /**
+ * Coefficient for alpha multiplication
+ *
+ * @member {number}
+ * @default 1
+ */
+ get alpha()
+ {
+ return this.uniforms.uAlpha;
+ }
+
+ set alpha(value) // eslint-disable-line require-jsdoc
+ {
+ this.uniforms.uAlpha = value;
+ }
+}
diff --git a/src/filters/alpha/alpha.frag b/src/filters/alpha/alpha.frag
new file mode 100644
index 0000000..6db588c
--- /dev/null
+++ b/src/filters/alpha/alpha.frag
@@ -0,0 +1,9 @@
+varying vec2 vTextureCoord;
+
+uniform sampler2D uSampler;
+uniform float uAlpha;
+
+void main(void)
+{
+ gl_FragColor = texture2D(uSampler, vTextureCoord) * uAlpha;
+}
diff --git a/src/filters/index.js b/src/filters/index.js
index 7ceb50a..dca47ab 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -25,4 +25,4 @@
export { default as BlurXFilter } from './blur/BlurXFilter';
export { default as BlurYFilter } from './blur/BlurYFilter';
export { default as ColorMatrixFilter } from './colormatrix/ColorMatrixFilter';
-export { default as VoidFilter } from './void/VoidFilter';
+export { default as AlphaFilter } from './alpha/AlphaFilter';
diff --git a/src/filters/void/VoidFilter.js b/src/filters/void/VoidFilter.js
deleted file mode 100644
index b4361ac..0000000
--- a/src/filters/void/VoidFilter.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as core from '../../core';
-import { readFileSync } from 'fs';
-import { join } from 'path';
-
-/**
- * Does nothing. Very handy.
- *
- * @class
- * @extends PIXI.Filter
- * @memberof PIXI.filters
- */
-export default class VoidFilter extends core.Filter
-{
- /**
- *
- */
- constructor()
- {
- super(
- // vertex shader
- readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
- // fragment shader
- readFileSync(join(__dirname, './void.frag'), 'utf8')
- );
-
- this.glShaderKey = 'void';
- }
-}
diff --git a/src/filters/void/void.frag b/src/filters/void/void.frag
deleted file mode 100644
index 99168fb..0000000
--- a/src/filters/void/void.frag
+++ /dev/null
@@ -1,8 +0,0 @@
-varying vec2 vTextureCoord;
-
-uniform sampler2D uSampler;
-
-void main(void)
-{
- gl_FragColor = texture2D(uSampler, vTextureCoord);
-}
diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js
index d866f03..7006a3e 100644
--- a/src/mesh/Mesh.js
+++ b/src/mesh/Mesh.js
@@ -1,5 +1,5 @@
import * as core from '../core';
-import { default as TextureTransform } from '../extras/TextureTransform';
+import Texture from '../core/textures/Texture';
const tempPoint = new core.Point();
const tempPolygon = new core.Polygon();
@@ -27,9 +27,10 @@
* The texture of the Mesh
*
* @member {PIXI.Texture}
+ * @default PIXI.Texture.EMPTY
* @private
*/
- this._texture = texture;
+ this._texture = texture || Texture.EMPTY;
/**
* The Uvs of the Mesh
@@ -129,10 +130,10 @@
* its updated independently from texture uvTransform
* updates of uvs are tied to that thing
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
* @private
*/
- this._uvTransform = new TextureTransform(texture);
+ this._uvTransform = new core.TextureMatrix(this._texture);
/**
* whether or not upload uvTransform to shader
diff --git a/src/mesh/NineSlicePlane.js b/src/mesh/NineSlicePlane.js
index 61ba5ee..f0d7575 100644
--- a/src/mesh/NineSlicePlane.js
+++ b/src/mesh/NineSlicePlane.js
@@ -172,8 +172,8 @@
const base = this._texture.baseTexture;
const textureSource = base.source;
- const w = base.width;
- const h = base.height;
+ const w = base.width * base.resolution;
+ const h = base.height * base.resolution;
this.drawSegment(context, textureSource, w, h, 0, 1, 10, 11);
this.drawSegment(context, textureSource, w, h, 2, 3, 12, 13);
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/extras/BitmapText.js b/src/extras/BitmapText.js
index 0592b54..96d9f44 100644
--- a/src/extras/BitmapText.js
+++ b/src/extras/BitmapText.js
@@ -1,5 +1,6 @@
import * as core from '../core';
import ObservablePoint from '../core/math/ObservablePoint';
+import { getResolutionOfUrl } from '../core/utils';
import settings from '../core/settings';
/**
@@ -510,7 +511,8 @@
const data = {};
const info = xml.getElementsByTagName('info')[0];
const common = xml.getElementsByTagName('common')[0];
- const res = texture.baseTexture.resolution || settings.RESOLUTION;
+ const fileName = xml.getElementsByTagName('page')[0].getAttribute('file');
+ const res = getResolutionOfUrl(fileName, settings.RESOLUTION);
data.font = info.getAttribute('face');
data.size = parseInt(info.getAttribute('size'), 10);
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
deleted file mode 100644
index 16536d2..0000000
--- a/src/extras/TextureTransform.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import { default as Matrix } from '../core/math/Matrix';
-
-const tempMat = new Matrix();
-
-/**
- * class controls uv transform and frame clamp for texture
- *
- * @class
- * @memberof PIXI.extras
- */
-export default class TextureTransform
-{
- /**
- *
- * @param {PIXI.Texture} texture observed texture
- * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
- * @constructor
- */
- constructor(texture, clampMargin)
- {
- this._texture = texture;
-
- this.mapCoord = new Matrix();
-
- this.uClampFrame = new Float32Array(4);
-
- this.uClampOffset = new Float32Array(2);
-
- this._lastTextureID = -1;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
- *
- * @default 0
- * @member {number}
- */
- this.clampOffset = 0;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
- *
- * @default 0.5
- * @member {number}
- */
- this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
- }
-
- /**
- * texture property
- * @member {PIXI.Texture}
- */
- get texture()
- {
- return this._texture;
- }
-
- set texture(value) // eslint-disable-line require-jsdoc
- {
- this._texture = value;
- this._lastTextureID = -1;
- }
-
- /**
- * Multiplies uvs array to transform
- * @param {Float32Array} uvs mesh uvs
- * @param {Float32Array} [out=uvs] output
- * @returns {Float32Array} output
- */
- multiplyUvs(uvs, out)
- {
- if (out === undefined)
- {
- out = uvs;
- }
-
- const mat = this.mapCoord;
-
- for (let i = 0; i < uvs.length; i += 2)
- {
- const x = uvs[i];
- const y = uvs[i + 1];
-
- out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
- out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
- }
-
- return out;
- }
-
- /**
- * updates matrices if texture was changed
- * @param {boolean} forceUpdate if true, matrices will be updated any case
- * @returns {boolean} whether or not it was updated
- */
- update(forceUpdate)
- {
- const tex = this._texture;
-
- if (!tex || !tex.valid)
- {
- return false;
- }
-
- if (!forceUpdate
- && this._lastTextureID === tex._updateID)
- {
- return false;
- }
-
- this._lastTextureID = tex._updateID;
-
- const uvs = tex._uvs;
-
- this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
-
- const orig = tex.orig;
- const trim = tex.trim;
-
- if (trim)
- {
- tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
- -trim.x / trim.width, -trim.y / trim.height);
- this.mapCoord.append(tempMat);
- }
-
- const texBase = tex.baseTexture;
- const frame = this.uClampFrame;
- const margin = this.clampMargin / texBase.resolution;
- const offset = this.clampOffset;
-
- frame[0] = (tex._frame.x + margin + offset) / texBase.width;
- frame[1] = (tex._frame.y + margin + offset) / texBase.height;
- frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
- frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
- this.uClampOffset[0] = offset / texBase.realWidth;
- this.uClampOffset[1] = offset / texBase.realHeight;
-
- return true;
- }
-}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 736b207..84c0841 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -1,6 +1,5 @@
import * as core from '../core';
import CanvasTinter from '../core/sprites/canvas/CanvasTinter';
-import { default as TextureTransform } from './TextureTransform';
const tempPoint = new core.Point();
@@ -58,9 +57,9 @@
/**
* transform that is applied to UV to get the texture coords
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
*/
- this.uvTransform = texture.transform || new TextureTransform(texture);
+ this.uvTransform = texture.transform || new core.TextureMatrix(texture);
/**
* Plugin that is responsible for rendering this element.
diff --git a/src/extras/index.js b/src/extras/index.js
index 5b98cb1..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -3,7 +3,6 @@
* @namespace PIXI.extras
*/
export { default as AnimatedSprite } from './AnimatedSprite';
-export { default as TextureTransform } from './TextureTransform';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
export { default as BitmapText } from './BitmapText';
diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js
new file mode 100644
index 0000000..c2824ed
--- /dev/null
+++ b/src/filters/alpha/AlphaFilter.js
@@ -0,0 +1,55 @@
+import * as core from '../../core';
+import { readFileSync } from 'fs';
+import { join } from 'path';
+
+/**
+ * Simplest filter - applies alpha
+ *
+ * Use this instead of Container's alpha property to avoid visual layering of individual elements.
+ * AlphaFilter applies alpha evenly across the entire display object and any opaque elements it contains.
+ * If elements are not opaque, they will blend with each other anyway.
+ *
+ * Very handy if you want to use common features of all filters:
+ *
+ * 1. Assign a blendMode to this filter, blend all elements inside display object with background.
+ *
+ * 2. To use clipping in display coordinates, assign a filterArea to the same container that has this filter.
+ *
+ * @class
+ * @extends PIXI.Filter
+ * @memberof PIXI.filters
+ */
+export default class AlphaFilter extends core.Filter
+{
+ /**
+ *
+ */
+ constructor()
+ {
+ super(
+ // vertex shader
+ readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
+ // fragment shader
+ readFileSync(join(__dirname, './alpha.frag'), 'utf8')
+ );
+
+ this.alpha = 1.0;
+ this.glShaderKey = 'alpha';
+ }
+
+ /**
+ * Coefficient for alpha multiplication
+ *
+ * @member {number}
+ * @default 1
+ */
+ get alpha()
+ {
+ return this.uniforms.uAlpha;
+ }
+
+ set alpha(value) // eslint-disable-line require-jsdoc
+ {
+ this.uniforms.uAlpha = value;
+ }
+}
diff --git a/src/filters/alpha/alpha.frag b/src/filters/alpha/alpha.frag
new file mode 100644
index 0000000..6db588c
--- /dev/null
+++ b/src/filters/alpha/alpha.frag
@@ -0,0 +1,9 @@
+varying vec2 vTextureCoord;
+
+uniform sampler2D uSampler;
+uniform float uAlpha;
+
+void main(void)
+{
+ gl_FragColor = texture2D(uSampler, vTextureCoord) * uAlpha;
+}
diff --git a/src/filters/index.js b/src/filters/index.js
index 7ceb50a..dca47ab 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -25,4 +25,4 @@
export { default as BlurXFilter } from './blur/BlurXFilter';
export { default as BlurYFilter } from './blur/BlurYFilter';
export { default as ColorMatrixFilter } from './colormatrix/ColorMatrixFilter';
-export { default as VoidFilter } from './void/VoidFilter';
+export { default as AlphaFilter } from './alpha/AlphaFilter';
diff --git a/src/filters/void/VoidFilter.js b/src/filters/void/VoidFilter.js
deleted file mode 100644
index b4361ac..0000000
--- a/src/filters/void/VoidFilter.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as core from '../../core';
-import { readFileSync } from 'fs';
-import { join } from 'path';
-
-/**
- * Does nothing. Very handy.
- *
- * @class
- * @extends PIXI.Filter
- * @memberof PIXI.filters
- */
-export default class VoidFilter extends core.Filter
-{
- /**
- *
- */
- constructor()
- {
- super(
- // vertex shader
- readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
- // fragment shader
- readFileSync(join(__dirname, './void.frag'), 'utf8')
- );
-
- this.glShaderKey = 'void';
- }
-}
diff --git a/src/filters/void/void.frag b/src/filters/void/void.frag
deleted file mode 100644
index 99168fb..0000000
--- a/src/filters/void/void.frag
+++ /dev/null
@@ -1,8 +0,0 @@
-varying vec2 vTextureCoord;
-
-uniform sampler2D uSampler;
-
-void main(void)
-{
- gl_FragColor = texture2D(uSampler, vTextureCoord);
-}
diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js
index d866f03..7006a3e 100644
--- a/src/mesh/Mesh.js
+++ b/src/mesh/Mesh.js
@@ -1,5 +1,5 @@
import * as core from '../core';
-import { default as TextureTransform } from '../extras/TextureTransform';
+import Texture from '../core/textures/Texture';
const tempPoint = new core.Point();
const tempPolygon = new core.Polygon();
@@ -27,9 +27,10 @@
* The texture of the Mesh
*
* @member {PIXI.Texture}
+ * @default PIXI.Texture.EMPTY
* @private
*/
- this._texture = texture;
+ this._texture = texture || Texture.EMPTY;
/**
* The Uvs of the Mesh
@@ -129,10 +130,10 @@
* its updated independently from texture uvTransform
* updates of uvs are tied to that thing
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
* @private
*/
- this._uvTransform = new TextureTransform(texture);
+ this._uvTransform = new core.TextureMatrix(this._texture);
/**
* whether or not upload uvTransform to shader
diff --git a/src/mesh/NineSlicePlane.js b/src/mesh/NineSlicePlane.js
index 61ba5ee..f0d7575 100644
--- a/src/mesh/NineSlicePlane.js
+++ b/src/mesh/NineSlicePlane.js
@@ -172,8 +172,8 @@
const base = this._texture.baseTexture;
const textureSource = base.source;
- const w = base.width;
- const h = base.height;
+ const w = base.width * base.resolution;
+ const h = base.height * base.resolution;
this.drawSegment(context, textureSource, w, h, 0, 1, 10, 11);
this.drawSegment(context, textureSource, w, h, 2, 3, 12, 13);
diff --git a/src/mesh/Plane.js b/src/mesh/Plane.js
index 4dd2398..2aa60f9 100644
--- a/src/mesh/Plane.js
+++ b/src/mesh/Plane.js
@@ -94,6 +94,8 @@
this.uvs = new Float32Array(uvs);
this.colors = new Float32Array(colors);
this.indices = new Uint16Array(indices);
+
+ this.dirty++;
this.indexDirty++;
this.multiplyUvs();
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/extras/BitmapText.js b/src/extras/BitmapText.js
index 0592b54..96d9f44 100644
--- a/src/extras/BitmapText.js
+++ b/src/extras/BitmapText.js
@@ -1,5 +1,6 @@
import * as core from '../core';
import ObservablePoint from '../core/math/ObservablePoint';
+import { getResolutionOfUrl } from '../core/utils';
import settings from '../core/settings';
/**
@@ -510,7 +511,8 @@
const data = {};
const info = xml.getElementsByTagName('info')[0];
const common = xml.getElementsByTagName('common')[0];
- const res = texture.baseTexture.resolution || settings.RESOLUTION;
+ const fileName = xml.getElementsByTagName('page')[0].getAttribute('file');
+ const res = getResolutionOfUrl(fileName, settings.RESOLUTION);
data.font = info.getAttribute('face');
data.size = parseInt(info.getAttribute('size'), 10);
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
deleted file mode 100644
index 16536d2..0000000
--- a/src/extras/TextureTransform.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import { default as Matrix } from '../core/math/Matrix';
-
-const tempMat = new Matrix();
-
-/**
- * class controls uv transform and frame clamp for texture
- *
- * @class
- * @memberof PIXI.extras
- */
-export default class TextureTransform
-{
- /**
- *
- * @param {PIXI.Texture} texture observed texture
- * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
- * @constructor
- */
- constructor(texture, clampMargin)
- {
- this._texture = texture;
-
- this.mapCoord = new Matrix();
-
- this.uClampFrame = new Float32Array(4);
-
- this.uClampOffset = new Float32Array(2);
-
- this._lastTextureID = -1;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
- *
- * @default 0
- * @member {number}
- */
- this.clampOffset = 0;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
- *
- * @default 0.5
- * @member {number}
- */
- this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
- }
-
- /**
- * texture property
- * @member {PIXI.Texture}
- */
- get texture()
- {
- return this._texture;
- }
-
- set texture(value) // eslint-disable-line require-jsdoc
- {
- this._texture = value;
- this._lastTextureID = -1;
- }
-
- /**
- * Multiplies uvs array to transform
- * @param {Float32Array} uvs mesh uvs
- * @param {Float32Array} [out=uvs] output
- * @returns {Float32Array} output
- */
- multiplyUvs(uvs, out)
- {
- if (out === undefined)
- {
- out = uvs;
- }
-
- const mat = this.mapCoord;
-
- for (let i = 0; i < uvs.length; i += 2)
- {
- const x = uvs[i];
- const y = uvs[i + 1];
-
- out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
- out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
- }
-
- return out;
- }
-
- /**
- * updates matrices if texture was changed
- * @param {boolean} forceUpdate if true, matrices will be updated any case
- * @returns {boolean} whether or not it was updated
- */
- update(forceUpdate)
- {
- const tex = this._texture;
-
- if (!tex || !tex.valid)
- {
- return false;
- }
-
- if (!forceUpdate
- && this._lastTextureID === tex._updateID)
- {
- return false;
- }
-
- this._lastTextureID = tex._updateID;
-
- const uvs = tex._uvs;
-
- this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
-
- const orig = tex.orig;
- const trim = tex.trim;
-
- if (trim)
- {
- tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
- -trim.x / trim.width, -trim.y / trim.height);
- this.mapCoord.append(tempMat);
- }
-
- const texBase = tex.baseTexture;
- const frame = this.uClampFrame;
- const margin = this.clampMargin / texBase.resolution;
- const offset = this.clampOffset;
-
- frame[0] = (tex._frame.x + margin + offset) / texBase.width;
- frame[1] = (tex._frame.y + margin + offset) / texBase.height;
- frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
- frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
- this.uClampOffset[0] = offset / texBase.realWidth;
- this.uClampOffset[1] = offset / texBase.realHeight;
-
- return true;
- }
-}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 736b207..84c0841 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -1,6 +1,5 @@
import * as core from '../core';
import CanvasTinter from '../core/sprites/canvas/CanvasTinter';
-import { default as TextureTransform } from './TextureTransform';
const tempPoint = new core.Point();
@@ -58,9 +57,9 @@
/**
* transform that is applied to UV to get the texture coords
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
*/
- this.uvTransform = texture.transform || new TextureTransform(texture);
+ this.uvTransform = texture.transform || new core.TextureMatrix(texture);
/**
* Plugin that is responsible for rendering this element.
diff --git a/src/extras/index.js b/src/extras/index.js
index 5b98cb1..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -3,7 +3,6 @@
* @namespace PIXI.extras
*/
export { default as AnimatedSprite } from './AnimatedSprite';
-export { default as TextureTransform } from './TextureTransform';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
export { default as BitmapText } from './BitmapText';
diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js
new file mode 100644
index 0000000..c2824ed
--- /dev/null
+++ b/src/filters/alpha/AlphaFilter.js
@@ -0,0 +1,55 @@
+import * as core from '../../core';
+import { readFileSync } from 'fs';
+import { join } from 'path';
+
+/**
+ * Simplest filter - applies alpha
+ *
+ * Use this instead of Container's alpha property to avoid visual layering of individual elements.
+ * AlphaFilter applies alpha evenly across the entire display object and any opaque elements it contains.
+ * If elements are not opaque, they will blend with each other anyway.
+ *
+ * Very handy if you want to use common features of all filters:
+ *
+ * 1. Assign a blendMode to this filter, blend all elements inside display object with background.
+ *
+ * 2. To use clipping in display coordinates, assign a filterArea to the same container that has this filter.
+ *
+ * @class
+ * @extends PIXI.Filter
+ * @memberof PIXI.filters
+ */
+export default class AlphaFilter extends core.Filter
+{
+ /**
+ *
+ */
+ constructor()
+ {
+ super(
+ // vertex shader
+ readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
+ // fragment shader
+ readFileSync(join(__dirname, './alpha.frag'), 'utf8')
+ );
+
+ this.alpha = 1.0;
+ this.glShaderKey = 'alpha';
+ }
+
+ /**
+ * Coefficient for alpha multiplication
+ *
+ * @member {number}
+ * @default 1
+ */
+ get alpha()
+ {
+ return this.uniforms.uAlpha;
+ }
+
+ set alpha(value) // eslint-disable-line require-jsdoc
+ {
+ this.uniforms.uAlpha = value;
+ }
+}
diff --git a/src/filters/alpha/alpha.frag b/src/filters/alpha/alpha.frag
new file mode 100644
index 0000000..6db588c
--- /dev/null
+++ b/src/filters/alpha/alpha.frag
@@ -0,0 +1,9 @@
+varying vec2 vTextureCoord;
+
+uniform sampler2D uSampler;
+uniform float uAlpha;
+
+void main(void)
+{
+ gl_FragColor = texture2D(uSampler, vTextureCoord) * uAlpha;
+}
diff --git a/src/filters/index.js b/src/filters/index.js
index 7ceb50a..dca47ab 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -25,4 +25,4 @@
export { default as BlurXFilter } from './blur/BlurXFilter';
export { default as BlurYFilter } from './blur/BlurYFilter';
export { default as ColorMatrixFilter } from './colormatrix/ColorMatrixFilter';
-export { default as VoidFilter } from './void/VoidFilter';
+export { default as AlphaFilter } from './alpha/AlphaFilter';
diff --git a/src/filters/void/VoidFilter.js b/src/filters/void/VoidFilter.js
deleted file mode 100644
index b4361ac..0000000
--- a/src/filters/void/VoidFilter.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as core from '../../core';
-import { readFileSync } from 'fs';
-import { join } from 'path';
-
-/**
- * Does nothing. Very handy.
- *
- * @class
- * @extends PIXI.Filter
- * @memberof PIXI.filters
- */
-export default class VoidFilter extends core.Filter
-{
- /**
- *
- */
- constructor()
- {
- super(
- // vertex shader
- readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
- // fragment shader
- readFileSync(join(__dirname, './void.frag'), 'utf8')
- );
-
- this.glShaderKey = 'void';
- }
-}
diff --git a/src/filters/void/void.frag b/src/filters/void/void.frag
deleted file mode 100644
index 99168fb..0000000
--- a/src/filters/void/void.frag
+++ /dev/null
@@ -1,8 +0,0 @@
-varying vec2 vTextureCoord;
-
-uniform sampler2D uSampler;
-
-void main(void)
-{
- gl_FragColor = texture2D(uSampler, vTextureCoord);
-}
diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js
index d866f03..7006a3e 100644
--- a/src/mesh/Mesh.js
+++ b/src/mesh/Mesh.js
@@ -1,5 +1,5 @@
import * as core from '../core';
-import { default as TextureTransform } from '../extras/TextureTransform';
+import Texture from '../core/textures/Texture';
const tempPoint = new core.Point();
const tempPolygon = new core.Polygon();
@@ -27,9 +27,10 @@
* The texture of the Mesh
*
* @member {PIXI.Texture}
+ * @default PIXI.Texture.EMPTY
* @private
*/
- this._texture = texture;
+ this._texture = texture || Texture.EMPTY;
/**
* The Uvs of the Mesh
@@ -129,10 +130,10 @@
* its updated independently from texture uvTransform
* updates of uvs are tied to that thing
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
* @private
*/
- this._uvTransform = new TextureTransform(texture);
+ this._uvTransform = new core.TextureMatrix(this._texture);
/**
* whether or not upload uvTransform to shader
diff --git a/src/mesh/NineSlicePlane.js b/src/mesh/NineSlicePlane.js
index 61ba5ee..f0d7575 100644
--- a/src/mesh/NineSlicePlane.js
+++ b/src/mesh/NineSlicePlane.js
@@ -172,8 +172,8 @@
const base = this._texture.baseTexture;
const textureSource = base.source;
- const w = base.width;
- const h = base.height;
+ const w = base.width * base.resolution;
+ const h = base.height * base.resolution;
this.drawSegment(context, textureSource, w, h, 0, 1, 10, 11);
this.drawSegment(context, textureSource, w, h, 2, 3, 12, 13);
diff --git a/src/mesh/Plane.js b/src/mesh/Plane.js
index 4dd2398..2aa60f9 100644
--- a/src/mesh/Plane.js
+++ b/src/mesh/Plane.js
@@ -94,6 +94,8 @@
this.uvs = new Float32Array(uvs);
this.colors = new Float32Array(colors);
this.indices = new Uint16Array(indices);
+
+ this.dirty++;
this.indexDirty++;
this.multiplyUvs();
diff --git a/test/interaction/InteractionManager.js b/test/interaction/InteractionManager.js
index 3f84d6a..136640e 100644
--- a/test/interaction/InteractionManager.js
+++ b/test/interaction/InteractionManager.js
@@ -279,13 +279,48 @@
removeSpy.restore();
});
- it('should add and remove pointer events to element', function ()
+ it('should add and remove pointer events to element seven times when touch events are supported', function ()
{
const manager = new PIXI.interaction.InteractionManager(sinon.stub());
const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
manager.interactionDOMElement = element;
manager.supportsPointerEvents = true;
+ manager.supportsTouchEvents = true;
+
+ manager.addEvents();
+
+ expect(element.addEventListener).to.have.been.callCount(7);
+ expect(element.addEventListener).to.have.been.calledWith('pointerdown');
+ expect(element.addEventListener).to.have.been.calledWith('pointerleave');
+ expect(element.addEventListener).to.have.been.calledWith('pointerover');
+
+ expect(element.addEventListener).to.have.been.calledWith('touchstart');
+ expect(element.addEventListener).to.have.been.calledWith('touchcancel');
+ expect(element.addEventListener).to.have.been.calledWith('touchend');
+ expect(element.addEventListener).to.have.been.calledWith('touchmove');
+
+ manager.removeEvents();
+
+ expect(element.removeEventListener).to.have.been.callCount(7);
+ expect(element.removeEventListener).to.have.been.calledWith('pointerdown');
+ expect(element.removeEventListener).to.have.been.calledWith('pointerleave');
+ expect(element.removeEventListener).to.have.been.calledWith('pointerover');
+
+ expect(element.removeEventListener).to.have.been.calledWith('touchstart');
+ expect(element.removeEventListener).to.have.been.calledWith('touchcancel');
+ expect(element.removeEventListener).to.have.been.calledWith('touchend');
+ expect(element.removeEventListener).to.have.been.calledWith('touchmove');
+ });
+
+ it('should add and remove pointer events to element three times when touch events are not supported', function ()
+ {
+ const manager = new PIXI.interaction.InteractionManager(sinon.stub());
+ const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
+
+ manager.interactionDOMElement = element;
+ manager.supportsPointerEvents = true;
+ manager.supportsTouchEvents = false;
manager.addEvents();
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/extras/BitmapText.js b/src/extras/BitmapText.js
index 0592b54..96d9f44 100644
--- a/src/extras/BitmapText.js
+++ b/src/extras/BitmapText.js
@@ -1,5 +1,6 @@
import * as core from '../core';
import ObservablePoint from '../core/math/ObservablePoint';
+import { getResolutionOfUrl } from '../core/utils';
import settings from '../core/settings';
/**
@@ -510,7 +511,8 @@
const data = {};
const info = xml.getElementsByTagName('info')[0];
const common = xml.getElementsByTagName('common')[0];
- const res = texture.baseTexture.resolution || settings.RESOLUTION;
+ const fileName = xml.getElementsByTagName('page')[0].getAttribute('file');
+ const res = getResolutionOfUrl(fileName, settings.RESOLUTION);
data.font = info.getAttribute('face');
data.size = parseInt(info.getAttribute('size'), 10);
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
deleted file mode 100644
index 16536d2..0000000
--- a/src/extras/TextureTransform.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import { default as Matrix } from '../core/math/Matrix';
-
-const tempMat = new Matrix();
-
-/**
- * class controls uv transform and frame clamp for texture
- *
- * @class
- * @memberof PIXI.extras
- */
-export default class TextureTransform
-{
- /**
- *
- * @param {PIXI.Texture} texture observed texture
- * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
- * @constructor
- */
- constructor(texture, clampMargin)
- {
- this._texture = texture;
-
- this.mapCoord = new Matrix();
-
- this.uClampFrame = new Float32Array(4);
-
- this.uClampOffset = new Float32Array(2);
-
- this._lastTextureID = -1;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
- *
- * @default 0
- * @member {number}
- */
- this.clampOffset = 0;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
- *
- * @default 0.5
- * @member {number}
- */
- this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
- }
-
- /**
- * texture property
- * @member {PIXI.Texture}
- */
- get texture()
- {
- return this._texture;
- }
-
- set texture(value) // eslint-disable-line require-jsdoc
- {
- this._texture = value;
- this._lastTextureID = -1;
- }
-
- /**
- * Multiplies uvs array to transform
- * @param {Float32Array} uvs mesh uvs
- * @param {Float32Array} [out=uvs] output
- * @returns {Float32Array} output
- */
- multiplyUvs(uvs, out)
- {
- if (out === undefined)
- {
- out = uvs;
- }
-
- const mat = this.mapCoord;
-
- for (let i = 0; i < uvs.length; i += 2)
- {
- const x = uvs[i];
- const y = uvs[i + 1];
-
- out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
- out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
- }
-
- return out;
- }
-
- /**
- * updates matrices if texture was changed
- * @param {boolean} forceUpdate if true, matrices will be updated any case
- * @returns {boolean} whether or not it was updated
- */
- update(forceUpdate)
- {
- const tex = this._texture;
-
- if (!tex || !tex.valid)
- {
- return false;
- }
-
- if (!forceUpdate
- && this._lastTextureID === tex._updateID)
- {
- return false;
- }
-
- this._lastTextureID = tex._updateID;
-
- const uvs = tex._uvs;
-
- this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
-
- const orig = tex.orig;
- const trim = tex.trim;
-
- if (trim)
- {
- tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
- -trim.x / trim.width, -trim.y / trim.height);
- this.mapCoord.append(tempMat);
- }
-
- const texBase = tex.baseTexture;
- const frame = this.uClampFrame;
- const margin = this.clampMargin / texBase.resolution;
- const offset = this.clampOffset;
-
- frame[0] = (tex._frame.x + margin + offset) / texBase.width;
- frame[1] = (tex._frame.y + margin + offset) / texBase.height;
- frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
- frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
- this.uClampOffset[0] = offset / texBase.realWidth;
- this.uClampOffset[1] = offset / texBase.realHeight;
-
- return true;
- }
-}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 736b207..84c0841 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -1,6 +1,5 @@
import * as core from '../core';
import CanvasTinter from '../core/sprites/canvas/CanvasTinter';
-import { default as TextureTransform } from './TextureTransform';
const tempPoint = new core.Point();
@@ -58,9 +57,9 @@
/**
* transform that is applied to UV to get the texture coords
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
*/
- this.uvTransform = texture.transform || new TextureTransform(texture);
+ this.uvTransform = texture.transform || new core.TextureMatrix(texture);
/**
* Plugin that is responsible for rendering this element.
diff --git a/src/extras/index.js b/src/extras/index.js
index 5b98cb1..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -3,7 +3,6 @@
* @namespace PIXI.extras
*/
export { default as AnimatedSprite } from './AnimatedSprite';
-export { default as TextureTransform } from './TextureTransform';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
export { default as BitmapText } from './BitmapText';
diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js
new file mode 100644
index 0000000..c2824ed
--- /dev/null
+++ b/src/filters/alpha/AlphaFilter.js
@@ -0,0 +1,55 @@
+import * as core from '../../core';
+import { readFileSync } from 'fs';
+import { join } from 'path';
+
+/**
+ * Simplest filter - applies alpha
+ *
+ * Use this instead of Container's alpha property to avoid visual layering of individual elements.
+ * AlphaFilter applies alpha evenly across the entire display object and any opaque elements it contains.
+ * If elements are not opaque, they will blend with each other anyway.
+ *
+ * Very handy if you want to use common features of all filters:
+ *
+ * 1. Assign a blendMode to this filter, blend all elements inside display object with background.
+ *
+ * 2. To use clipping in display coordinates, assign a filterArea to the same container that has this filter.
+ *
+ * @class
+ * @extends PIXI.Filter
+ * @memberof PIXI.filters
+ */
+export default class AlphaFilter extends core.Filter
+{
+ /**
+ *
+ */
+ constructor()
+ {
+ super(
+ // vertex shader
+ readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
+ // fragment shader
+ readFileSync(join(__dirname, './alpha.frag'), 'utf8')
+ );
+
+ this.alpha = 1.0;
+ this.glShaderKey = 'alpha';
+ }
+
+ /**
+ * Coefficient for alpha multiplication
+ *
+ * @member {number}
+ * @default 1
+ */
+ get alpha()
+ {
+ return this.uniforms.uAlpha;
+ }
+
+ set alpha(value) // eslint-disable-line require-jsdoc
+ {
+ this.uniforms.uAlpha = value;
+ }
+}
diff --git a/src/filters/alpha/alpha.frag b/src/filters/alpha/alpha.frag
new file mode 100644
index 0000000..6db588c
--- /dev/null
+++ b/src/filters/alpha/alpha.frag
@@ -0,0 +1,9 @@
+varying vec2 vTextureCoord;
+
+uniform sampler2D uSampler;
+uniform float uAlpha;
+
+void main(void)
+{
+ gl_FragColor = texture2D(uSampler, vTextureCoord) * uAlpha;
+}
diff --git a/src/filters/index.js b/src/filters/index.js
index 7ceb50a..dca47ab 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -25,4 +25,4 @@
export { default as BlurXFilter } from './blur/BlurXFilter';
export { default as BlurYFilter } from './blur/BlurYFilter';
export { default as ColorMatrixFilter } from './colormatrix/ColorMatrixFilter';
-export { default as VoidFilter } from './void/VoidFilter';
+export { default as AlphaFilter } from './alpha/AlphaFilter';
diff --git a/src/filters/void/VoidFilter.js b/src/filters/void/VoidFilter.js
deleted file mode 100644
index b4361ac..0000000
--- a/src/filters/void/VoidFilter.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as core from '../../core';
-import { readFileSync } from 'fs';
-import { join } from 'path';
-
-/**
- * Does nothing. Very handy.
- *
- * @class
- * @extends PIXI.Filter
- * @memberof PIXI.filters
- */
-export default class VoidFilter extends core.Filter
-{
- /**
- *
- */
- constructor()
- {
- super(
- // vertex shader
- readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
- // fragment shader
- readFileSync(join(__dirname, './void.frag'), 'utf8')
- );
-
- this.glShaderKey = 'void';
- }
-}
diff --git a/src/filters/void/void.frag b/src/filters/void/void.frag
deleted file mode 100644
index 99168fb..0000000
--- a/src/filters/void/void.frag
+++ /dev/null
@@ -1,8 +0,0 @@
-varying vec2 vTextureCoord;
-
-uniform sampler2D uSampler;
-
-void main(void)
-{
- gl_FragColor = texture2D(uSampler, vTextureCoord);
-}
diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js
index d866f03..7006a3e 100644
--- a/src/mesh/Mesh.js
+++ b/src/mesh/Mesh.js
@@ -1,5 +1,5 @@
import * as core from '../core';
-import { default as TextureTransform } from '../extras/TextureTransform';
+import Texture from '../core/textures/Texture';
const tempPoint = new core.Point();
const tempPolygon = new core.Polygon();
@@ -27,9 +27,10 @@
* The texture of the Mesh
*
* @member {PIXI.Texture}
+ * @default PIXI.Texture.EMPTY
* @private
*/
- this._texture = texture;
+ this._texture = texture || Texture.EMPTY;
/**
* The Uvs of the Mesh
@@ -129,10 +130,10 @@
* its updated independently from texture uvTransform
* updates of uvs are tied to that thing
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
* @private
*/
- this._uvTransform = new TextureTransform(texture);
+ this._uvTransform = new core.TextureMatrix(this._texture);
/**
* whether or not upload uvTransform to shader
diff --git a/src/mesh/NineSlicePlane.js b/src/mesh/NineSlicePlane.js
index 61ba5ee..f0d7575 100644
--- a/src/mesh/NineSlicePlane.js
+++ b/src/mesh/NineSlicePlane.js
@@ -172,8 +172,8 @@
const base = this._texture.baseTexture;
const textureSource = base.source;
- const w = base.width;
- const h = base.height;
+ const w = base.width * base.resolution;
+ const h = base.height * base.resolution;
this.drawSegment(context, textureSource, w, h, 0, 1, 10, 11);
this.drawSegment(context, textureSource, w, h, 2, 3, 12, 13);
diff --git a/src/mesh/Plane.js b/src/mesh/Plane.js
index 4dd2398..2aa60f9 100644
--- a/src/mesh/Plane.js
+++ b/src/mesh/Plane.js
@@ -94,6 +94,8 @@
this.uvs = new Float32Array(uvs);
this.colors = new Float32Array(colors);
this.indices = new Uint16Array(indices);
+
+ this.dirty++;
this.indexDirty++;
this.multiplyUvs();
diff --git a/test/interaction/InteractionManager.js b/test/interaction/InteractionManager.js
index 3f84d6a..136640e 100644
--- a/test/interaction/InteractionManager.js
+++ b/test/interaction/InteractionManager.js
@@ -279,13 +279,48 @@
removeSpy.restore();
});
- it('should add and remove pointer events to element', function ()
+ it('should add and remove pointer events to element seven times when touch events are supported', function ()
{
const manager = new PIXI.interaction.InteractionManager(sinon.stub());
const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
manager.interactionDOMElement = element;
manager.supportsPointerEvents = true;
+ manager.supportsTouchEvents = true;
+
+ manager.addEvents();
+
+ expect(element.addEventListener).to.have.been.callCount(7);
+ expect(element.addEventListener).to.have.been.calledWith('pointerdown');
+ expect(element.addEventListener).to.have.been.calledWith('pointerleave');
+ expect(element.addEventListener).to.have.been.calledWith('pointerover');
+
+ expect(element.addEventListener).to.have.been.calledWith('touchstart');
+ expect(element.addEventListener).to.have.been.calledWith('touchcancel');
+ expect(element.addEventListener).to.have.been.calledWith('touchend');
+ expect(element.addEventListener).to.have.been.calledWith('touchmove');
+
+ manager.removeEvents();
+
+ expect(element.removeEventListener).to.have.been.callCount(7);
+ expect(element.removeEventListener).to.have.been.calledWith('pointerdown');
+ expect(element.removeEventListener).to.have.been.calledWith('pointerleave');
+ expect(element.removeEventListener).to.have.been.calledWith('pointerover');
+
+ expect(element.removeEventListener).to.have.been.calledWith('touchstart');
+ expect(element.removeEventListener).to.have.been.calledWith('touchcancel');
+ expect(element.removeEventListener).to.have.been.calledWith('touchend');
+ expect(element.removeEventListener).to.have.been.calledWith('touchmove');
+ });
+
+ it('should add and remove pointer events to element three times when touch events are not supported', function ()
+ {
+ const manager = new PIXI.interaction.InteractionManager(sinon.stub());
+ const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
+
+ manager.interactionDOMElement = element;
+ manager.supportsPointerEvents = true;
+ manager.supportsTouchEvents = false;
manager.addEvents();
diff --git a/test/loaders/bitmapFontParser.js b/test/loaders/bitmapFontParser.js
index 7c77343..70703fc 100644
--- a/test/loaders/bitmapFontParser.js
+++ b/test/loaders/bitmapFontParser.js
@@ -1,7 +1,81 @@
'use strict';
+const path = require('path');
+const fs = require('fs');
+
describe('PIXI.loaders.bitmapFontParser', function ()
{
+ afterEach(function ()
+ {
+ for (var font in PIXI.extras.BitmapText.fonts)
+ {
+ delete PIXI.extras.BitmapText.fonts[font];
+ }
+ for (var baseTexture in PIXI.utils.BaseTextureCache)
+ {
+ delete PIXI.utils.BaseTextureCache[baseTexture];
+ }
+ for (var texture in PIXI.utils.TextureCache)
+ {
+ delete PIXI.utils.TextureCache[texture];
+ }
+ });
+
+ before(function (done)
+ {
+ const resolveURL = (url) => path.resolve(this.resources, url);
+
+ this.resources = path.join(__dirname, 'resources');
+ this.fontXML = null;
+ this.fontScaledXML = null;
+ this.fontImage = null;
+ this.fontScaledImage = null;
+ this.atlasImage = null;
+ this.atlasScaledImage = null;
+ this.atlasJSON = require(resolveURL('atlas.json')); // eslint-disable-line global-require
+ this.atlasScaledJSON = require(resolveURL('atlas@0.5x.json')); // eslint-disable-line global-require
+
+ const loadXML = (url) => new Promise((resolve) =>
+ fs.readFile(resolveURL(url), 'utf8', (err, data) =>
+ {
+ expect(err).to.be.null;
+ resolve((new window.DOMParser()).parseFromString(data, 'text/xml'));
+ }));
+
+ const loadImage = (url) => new Promise((resolve) =>
+ {
+ const image = new Image();
+
+ image.onload = () => resolve(image);
+ image.src = resolveURL(url);
+ });
+
+ Promise.all([
+ loadXML('font.fnt'),
+ loadXML('font@0.5x.fnt'),
+ loadImage('font.png'),
+ loadImage('font@0.5x.png'),
+ loadImage('atlas.png'),
+ loadImage('atlas@0.5x.png'),
+ ]).then(([
+ fontXML,
+ fontScaledXML,
+ fontImage,
+ fontScaledImage,
+ atlasImage,
+ atlasScaledImage,
+ ]) =>
+ {
+ this.fontXML = fontXML;
+ this.fontScaledXML = fontScaledXML;
+ this.fontImage = fontImage;
+ this.fontScaledImage = fontScaledImage;
+ this.atlasImage = atlasImage;
+ this.atlasScaledImage = atlasScaledImage;
+ done();
+ });
+ });
+
it('should exist and return a function', function ()
{
expect(PIXI.loaders.bitmapFontParser).to.be.a('function');
@@ -33,6 +107,206 @@
// TODO: Test the texture cache code path.
// TODO: Test the loading texture code path.
// TODO: Test data-url code paths.
+
+ it('should properly register bitmap font', function (done)
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture(this.fontImage, null, 1));
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, texture);
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charA.texture.frame.x).to.equal(2);
+ expect(charA.texture.frame.y).to.equal(2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charB.texture.frame.x).to.equal(2);
+ expect(charB.texture.frame.y).to.equal(24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charC.texture.frame.x).to.equal(23);
+ expect(charC.texture.frame.y).to.equal(2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charD.texture.frame.x).to.equal(19);
+ expect(charD.texture.frame.y).to.equal(24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+
+ it('should properly register SCALED bitmap font', function (done)
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture(this.fontScaledImage, null, 0.5));
+ const font = PIXI.extras.BitmapText.registerFont(this.fontScaledXML, texture);
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charA.texture.frame.x).to.equal(4); // 2 / 0.5
+ expect(charA.texture.frame.y).to.equal(4); // 2 / 0.5
+ expect(charA.texture.frame.width).to.equal(38); // 19 / 0.5
+ expect(charA.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charB.texture.frame.x).to.equal(4); // 2 / 0.5
+ expect(charB.texture.frame.y).to.equal(48); // 24 / 0.5
+ expect(charB.texture.frame.width).to.equal(30); // 15 / 0.5
+ expect(charB.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charC.texture.frame.x).to.equal(46); // 23 / 0.5
+ expect(charC.texture.frame.y).to.equal(4); // 2 / 0.5
+ expect(charC.texture.frame.width).to.equal(36); // 18 / 0.5
+ expect(charC.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charD.texture.frame.x).to.equal(38); // 19 / 0.5
+ expect(charD.texture.frame.y).to.equal(48); // 24 / 0.5
+ expect(charD.texture.frame.width).to.equal(34); // 17 / 0.5
+ expect(charD.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+
+ it('should properly register bitmap font NESTED into spritesheet', function (done)
+ {
+ const baseTexture = new PIXI.BaseTexture(this.atlasImage, null, 1);
+ const spritesheet = new PIXI.Spritesheet(baseTexture, this.atlasJSON);
+
+ spritesheet.parse(() =>
+ {
+ const fontTexture = PIXI.Texture.fromFrame('resources/font.png');
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, fontTexture);
+ const fontX = 158; // bare value from spritesheet frame
+ const fontY = 2; // bare value from spritesheet frame
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charA.texture.frame.x).to.equal(fontX + 2);
+ expect(charA.texture.frame.y).to.equal(fontY + 2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charB.texture.frame.x).to.equal(fontX + 2);
+ expect(charB.texture.frame.y).to.equal(fontY + 24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charC.texture.frame.x).to.equal(fontX + 23);
+ expect(charC.texture.frame.y).to.equal(fontY + 2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charD.texture.frame.x).to.equal(fontX + 19);
+ expect(charD.texture.frame.y).to.equal(fontY + 24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+ });
+
+ it('should properly register bitmap font NESTED into SCALED spritesheet', function (done)
+ {
+ const baseTexture = new PIXI.BaseTexture(this.atlasScaledImage, null, 1);
+ const spritesheet = new PIXI.Spritesheet(baseTexture, this.atlasScaledJSON);
+
+ spritesheet.parse(() =>
+ {
+ const fontTexture = PIXI.Texture.fromFrame('resources/font.png');
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, fontTexture);
+ const fontX = 158; // bare value from spritesheet frame
+ const fontY = 2; // bare value from spritesheet frame
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charA.texture.frame.x).to.equal(fontX + 2);
+ expect(charA.texture.frame.y).to.equal(fontY + 2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charB.texture.frame.x).to.equal(fontX + 2);
+ expect(charB.texture.frame.y).to.equal(fontY + 24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charC.texture.frame.x).to.equal(fontX + 23);
+ expect(charC.texture.frame.y).to.equal(fontY + 2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charD.texture.frame.x).to.equal(fontX + 19);
+ expect(charD.texture.frame.y).to.equal(fontY + 24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+ });
});
describe('PIXI.loaders.parseBitmapFontData', function ()
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/extras/BitmapText.js b/src/extras/BitmapText.js
index 0592b54..96d9f44 100644
--- a/src/extras/BitmapText.js
+++ b/src/extras/BitmapText.js
@@ -1,5 +1,6 @@
import * as core from '../core';
import ObservablePoint from '../core/math/ObservablePoint';
+import { getResolutionOfUrl } from '../core/utils';
import settings from '../core/settings';
/**
@@ -510,7 +511,8 @@
const data = {};
const info = xml.getElementsByTagName('info')[0];
const common = xml.getElementsByTagName('common')[0];
- const res = texture.baseTexture.resolution || settings.RESOLUTION;
+ const fileName = xml.getElementsByTagName('page')[0].getAttribute('file');
+ const res = getResolutionOfUrl(fileName, settings.RESOLUTION);
data.font = info.getAttribute('face');
data.size = parseInt(info.getAttribute('size'), 10);
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
deleted file mode 100644
index 16536d2..0000000
--- a/src/extras/TextureTransform.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import { default as Matrix } from '../core/math/Matrix';
-
-const tempMat = new Matrix();
-
-/**
- * class controls uv transform and frame clamp for texture
- *
- * @class
- * @memberof PIXI.extras
- */
-export default class TextureTransform
-{
- /**
- *
- * @param {PIXI.Texture} texture observed texture
- * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
- * @constructor
- */
- constructor(texture, clampMargin)
- {
- this._texture = texture;
-
- this.mapCoord = new Matrix();
-
- this.uClampFrame = new Float32Array(4);
-
- this.uClampOffset = new Float32Array(2);
-
- this._lastTextureID = -1;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
- *
- * @default 0
- * @member {number}
- */
- this.clampOffset = 0;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
- *
- * @default 0.5
- * @member {number}
- */
- this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
- }
-
- /**
- * texture property
- * @member {PIXI.Texture}
- */
- get texture()
- {
- return this._texture;
- }
-
- set texture(value) // eslint-disable-line require-jsdoc
- {
- this._texture = value;
- this._lastTextureID = -1;
- }
-
- /**
- * Multiplies uvs array to transform
- * @param {Float32Array} uvs mesh uvs
- * @param {Float32Array} [out=uvs] output
- * @returns {Float32Array} output
- */
- multiplyUvs(uvs, out)
- {
- if (out === undefined)
- {
- out = uvs;
- }
-
- const mat = this.mapCoord;
-
- for (let i = 0; i < uvs.length; i += 2)
- {
- const x = uvs[i];
- const y = uvs[i + 1];
-
- out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
- out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
- }
-
- return out;
- }
-
- /**
- * updates matrices if texture was changed
- * @param {boolean} forceUpdate if true, matrices will be updated any case
- * @returns {boolean} whether or not it was updated
- */
- update(forceUpdate)
- {
- const tex = this._texture;
-
- if (!tex || !tex.valid)
- {
- return false;
- }
-
- if (!forceUpdate
- && this._lastTextureID === tex._updateID)
- {
- return false;
- }
-
- this._lastTextureID = tex._updateID;
-
- const uvs = tex._uvs;
-
- this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
-
- const orig = tex.orig;
- const trim = tex.trim;
-
- if (trim)
- {
- tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
- -trim.x / trim.width, -trim.y / trim.height);
- this.mapCoord.append(tempMat);
- }
-
- const texBase = tex.baseTexture;
- const frame = this.uClampFrame;
- const margin = this.clampMargin / texBase.resolution;
- const offset = this.clampOffset;
-
- frame[0] = (tex._frame.x + margin + offset) / texBase.width;
- frame[1] = (tex._frame.y + margin + offset) / texBase.height;
- frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
- frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
- this.uClampOffset[0] = offset / texBase.realWidth;
- this.uClampOffset[1] = offset / texBase.realHeight;
-
- return true;
- }
-}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 736b207..84c0841 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -1,6 +1,5 @@
import * as core from '../core';
import CanvasTinter from '../core/sprites/canvas/CanvasTinter';
-import { default as TextureTransform } from './TextureTransform';
const tempPoint = new core.Point();
@@ -58,9 +57,9 @@
/**
* transform that is applied to UV to get the texture coords
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
*/
- this.uvTransform = texture.transform || new TextureTransform(texture);
+ this.uvTransform = texture.transform || new core.TextureMatrix(texture);
/**
* Plugin that is responsible for rendering this element.
diff --git a/src/extras/index.js b/src/extras/index.js
index 5b98cb1..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -3,7 +3,6 @@
* @namespace PIXI.extras
*/
export { default as AnimatedSprite } from './AnimatedSprite';
-export { default as TextureTransform } from './TextureTransform';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
export { default as BitmapText } from './BitmapText';
diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js
new file mode 100644
index 0000000..c2824ed
--- /dev/null
+++ b/src/filters/alpha/AlphaFilter.js
@@ -0,0 +1,55 @@
+import * as core from '../../core';
+import { readFileSync } from 'fs';
+import { join } from 'path';
+
+/**
+ * Simplest filter - applies alpha
+ *
+ * Use this instead of Container's alpha property to avoid visual layering of individual elements.
+ * AlphaFilter applies alpha evenly across the entire display object and any opaque elements it contains.
+ * If elements are not opaque, they will blend with each other anyway.
+ *
+ * Very handy if you want to use common features of all filters:
+ *
+ * 1. Assign a blendMode to this filter, blend all elements inside display object with background.
+ *
+ * 2. To use clipping in display coordinates, assign a filterArea to the same container that has this filter.
+ *
+ * @class
+ * @extends PIXI.Filter
+ * @memberof PIXI.filters
+ */
+export default class AlphaFilter extends core.Filter
+{
+ /**
+ *
+ */
+ constructor()
+ {
+ super(
+ // vertex shader
+ readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
+ // fragment shader
+ readFileSync(join(__dirname, './alpha.frag'), 'utf8')
+ );
+
+ this.alpha = 1.0;
+ this.glShaderKey = 'alpha';
+ }
+
+ /**
+ * Coefficient for alpha multiplication
+ *
+ * @member {number}
+ * @default 1
+ */
+ get alpha()
+ {
+ return this.uniforms.uAlpha;
+ }
+
+ set alpha(value) // eslint-disable-line require-jsdoc
+ {
+ this.uniforms.uAlpha = value;
+ }
+}
diff --git a/src/filters/alpha/alpha.frag b/src/filters/alpha/alpha.frag
new file mode 100644
index 0000000..6db588c
--- /dev/null
+++ b/src/filters/alpha/alpha.frag
@@ -0,0 +1,9 @@
+varying vec2 vTextureCoord;
+
+uniform sampler2D uSampler;
+uniform float uAlpha;
+
+void main(void)
+{
+ gl_FragColor = texture2D(uSampler, vTextureCoord) * uAlpha;
+}
diff --git a/src/filters/index.js b/src/filters/index.js
index 7ceb50a..dca47ab 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -25,4 +25,4 @@
export { default as BlurXFilter } from './blur/BlurXFilter';
export { default as BlurYFilter } from './blur/BlurYFilter';
export { default as ColorMatrixFilter } from './colormatrix/ColorMatrixFilter';
-export { default as VoidFilter } from './void/VoidFilter';
+export { default as AlphaFilter } from './alpha/AlphaFilter';
diff --git a/src/filters/void/VoidFilter.js b/src/filters/void/VoidFilter.js
deleted file mode 100644
index b4361ac..0000000
--- a/src/filters/void/VoidFilter.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as core from '../../core';
-import { readFileSync } from 'fs';
-import { join } from 'path';
-
-/**
- * Does nothing. Very handy.
- *
- * @class
- * @extends PIXI.Filter
- * @memberof PIXI.filters
- */
-export default class VoidFilter extends core.Filter
-{
- /**
- *
- */
- constructor()
- {
- super(
- // vertex shader
- readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
- // fragment shader
- readFileSync(join(__dirname, './void.frag'), 'utf8')
- );
-
- this.glShaderKey = 'void';
- }
-}
diff --git a/src/filters/void/void.frag b/src/filters/void/void.frag
deleted file mode 100644
index 99168fb..0000000
--- a/src/filters/void/void.frag
+++ /dev/null
@@ -1,8 +0,0 @@
-varying vec2 vTextureCoord;
-
-uniform sampler2D uSampler;
-
-void main(void)
-{
- gl_FragColor = texture2D(uSampler, vTextureCoord);
-}
diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js
index d866f03..7006a3e 100644
--- a/src/mesh/Mesh.js
+++ b/src/mesh/Mesh.js
@@ -1,5 +1,5 @@
import * as core from '../core';
-import { default as TextureTransform } from '../extras/TextureTransform';
+import Texture from '../core/textures/Texture';
const tempPoint = new core.Point();
const tempPolygon = new core.Polygon();
@@ -27,9 +27,10 @@
* The texture of the Mesh
*
* @member {PIXI.Texture}
+ * @default PIXI.Texture.EMPTY
* @private
*/
- this._texture = texture;
+ this._texture = texture || Texture.EMPTY;
/**
* The Uvs of the Mesh
@@ -129,10 +130,10 @@
* its updated independently from texture uvTransform
* updates of uvs are tied to that thing
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
* @private
*/
- this._uvTransform = new TextureTransform(texture);
+ this._uvTransform = new core.TextureMatrix(this._texture);
/**
* whether or not upload uvTransform to shader
diff --git a/src/mesh/NineSlicePlane.js b/src/mesh/NineSlicePlane.js
index 61ba5ee..f0d7575 100644
--- a/src/mesh/NineSlicePlane.js
+++ b/src/mesh/NineSlicePlane.js
@@ -172,8 +172,8 @@
const base = this._texture.baseTexture;
const textureSource = base.source;
- const w = base.width;
- const h = base.height;
+ const w = base.width * base.resolution;
+ const h = base.height * base.resolution;
this.drawSegment(context, textureSource, w, h, 0, 1, 10, 11);
this.drawSegment(context, textureSource, w, h, 2, 3, 12, 13);
diff --git a/src/mesh/Plane.js b/src/mesh/Plane.js
index 4dd2398..2aa60f9 100644
--- a/src/mesh/Plane.js
+++ b/src/mesh/Plane.js
@@ -94,6 +94,8 @@
this.uvs = new Float32Array(uvs);
this.colors = new Float32Array(colors);
this.indices = new Uint16Array(indices);
+
+ this.dirty++;
this.indexDirty++;
this.multiplyUvs();
diff --git a/test/interaction/InteractionManager.js b/test/interaction/InteractionManager.js
index 3f84d6a..136640e 100644
--- a/test/interaction/InteractionManager.js
+++ b/test/interaction/InteractionManager.js
@@ -279,13 +279,48 @@
removeSpy.restore();
});
- it('should add and remove pointer events to element', function ()
+ it('should add and remove pointer events to element seven times when touch events are supported', function ()
{
const manager = new PIXI.interaction.InteractionManager(sinon.stub());
const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
manager.interactionDOMElement = element;
manager.supportsPointerEvents = true;
+ manager.supportsTouchEvents = true;
+
+ manager.addEvents();
+
+ expect(element.addEventListener).to.have.been.callCount(7);
+ expect(element.addEventListener).to.have.been.calledWith('pointerdown');
+ expect(element.addEventListener).to.have.been.calledWith('pointerleave');
+ expect(element.addEventListener).to.have.been.calledWith('pointerover');
+
+ expect(element.addEventListener).to.have.been.calledWith('touchstart');
+ expect(element.addEventListener).to.have.been.calledWith('touchcancel');
+ expect(element.addEventListener).to.have.been.calledWith('touchend');
+ expect(element.addEventListener).to.have.been.calledWith('touchmove');
+
+ manager.removeEvents();
+
+ expect(element.removeEventListener).to.have.been.callCount(7);
+ expect(element.removeEventListener).to.have.been.calledWith('pointerdown');
+ expect(element.removeEventListener).to.have.been.calledWith('pointerleave');
+ expect(element.removeEventListener).to.have.been.calledWith('pointerover');
+
+ expect(element.removeEventListener).to.have.been.calledWith('touchstart');
+ expect(element.removeEventListener).to.have.been.calledWith('touchcancel');
+ expect(element.removeEventListener).to.have.been.calledWith('touchend');
+ expect(element.removeEventListener).to.have.been.calledWith('touchmove');
+ });
+
+ it('should add and remove pointer events to element three times when touch events are not supported', function ()
+ {
+ const manager = new PIXI.interaction.InteractionManager(sinon.stub());
+ const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
+
+ manager.interactionDOMElement = element;
+ manager.supportsPointerEvents = true;
+ manager.supportsTouchEvents = false;
manager.addEvents();
diff --git a/test/loaders/bitmapFontParser.js b/test/loaders/bitmapFontParser.js
index 7c77343..70703fc 100644
--- a/test/loaders/bitmapFontParser.js
+++ b/test/loaders/bitmapFontParser.js
@@ -1,7 +1,81 @@
'use strict';
+const path = require('path');
+const fs = require('fs');
+
describe('PIXI.loaders.bitmapFontParser', function ()
{
+ afterEach(function ()
+ {
+ for (var font in PIXI.extras.BitmapText.fonts)
+ {
+ delete PIXI.extras.BitmapText.fonts[font];
+ }
+ for (var baseTexture in PIXI.utils.BaseTextureCache)
+ {
+ delete PIXI.utils.BaseTextureCache[baseTexture];
+ }
+ for (var texture in PIXI.utils.TextureCache)
+ {
+ delete PIXI.utils.TextureCache[texture];
+ }
+ });
+
+ before(function (done)
+ {
+ const resolveURL = (url) => path.resolve(this.resources, url);
+
+ this.resources = path.join(__dirname, 'resources');
+ this.fontXML = null;
+ this.fontScaledXML = null;
+ this.fontImage = null;
+ this.fontScaledImage = null;
+ this.atlasImage = null;
+ this.atlasScaledImage = null;
+ this.atlasJSON = require(resolveURL('atlas.json')); // eslint-disable-line global-require
+ this.atlasScaledJSON = require(resolveURL('atlas@0.5x.json')); // eslint-disable-line global-require
+
+ const loadXML = (url) => new Promise((resolve) =>
+ fs.readFile(resolveURL(url), 'utf8', (err, data) =>
+ {
+ expect(err).to.be.null;
+ resolve((new window.DOMParser()).parseFromString(data, 'text/xml'));
+ }));
+
+ const loadImage = (url) => new Promise((resolve) =>
+ {
+ const image = new Image();
+
+ image.onload = () => resolve(image);
+ image.src = resolveURL(url);
+ });
+
+ Promise.all([
+ loadXML('font.fnt'),
+ loadXML('font@0.5x.fnt'),
+ loadImage('font.png'),
+ loadImage('font@0.5x.png'),
+ loadImage('atlas.png'),
+ loadImage('atlas@0.5x.png'),
+ ]).then(([
+ fontXML,
+ fontScaledXML,
+ fontImage,
+ fontScaledImage,
+ atlasImage,
+ atlasScaledImage,
+ ]) =>
+ {
+ this.fontXML = fontXML;
+ this.fontScaledXML = fontScaledXML;
+ this.fontImage = fontImage;
+ this.fontScaledImage = fontScaledImage;
+ this.atlasImage = atlasImage;
+ this.atlasScaledImage = atlasScaledImage;
+ done();
+ });
+ });
+
it('should exist and return a function', function ()
{
expect(PIXI.loaders.bitmapFontParser).to.be.a('function');
@@ -33,6 +107,206 @@
// TODO: Test the texture cache code path.
// TODO: Test the loading texture code path.
// TODO: Test data-url code paths.
+
+ it('should properly register bitmap font', function (done)
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture(this.fontImage, null, 1));
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, texture);
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charA.texture.frame.x).to.equal(2);
+ expect(charA.texture.frame.y).to.equal(2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charB.texture.frame.x).to.equal(2);
+ expect(charB.texture.frame.y).to.equal(24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charC.texture.frame.x).to.equal(23);
+ expect(charC.texture.frame.y).to.equal(2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charD.texture.frame.x).to.equal(19);
+ expect(charD.texture.frame.y).to.equal(24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+
+ it('should properly register SCALED bitmap font', function (done)
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture(this.fontScaledImage, null, 0.5));
+ const font = PIXI.extras.BitmapText.registerFont(this.fontScaledXML, texture);
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charA.texture.frame.x).to.equal(4); // 2 / 0.5
+ expect(charA.texture.frame.y).to.equal(4); // 2 / 0.5
+ expect(charA.texture.frame.width).to.equal(38); // 19 / 0.5
+ expect(charA.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charB.texture.frame.x).to.equal(4); // 2 / 0.5
+ expect(charB.texture.frame.y).to.equal(48); // 24 / 0.5
+ expect(charB.texture.frame.width).to.equal(30); // 15 / 0.5
+ expect(charB.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charC.texture.frame.x).to.equal(46); // 23 / 0.5
+ expect(charC.texture.frame.y).to.equal(4); // 2 / 0.5
+ expect(charC.texture.frame.width).to.equal(36); // 18 / 0.5
+ expect(charC.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charD.texture.frame.x).to.equal(38); // 19 / 0.5
+ expect(charD.texture.frame.y).to.equal(48); // 24 / 0.5
+ expect(charD.texture.frame.width).to.equal(34); // 17 / 0.5
+ expect(charD.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+
+ it('should properly register bitmap font NESTED into spritesheet', function (done)
+ {
+ const baseTexture = new PIXI.BaseTexture(this.atlasImage, null, 1);
+ const spritesheet = new PIXI.Spritesheet(baseTexture, this.atlasJSON);
+
+ spritesheet.parse(() =>
+ {
+ const fontTexture = PIXI.Texture.fromFrame('resources/font.png');
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, fontTexture);
+ const fontX = 158; // bare value from spritesheet frame
+ const fontY = 2; // bare value from spritesheet frame
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charA.texture.frame.x).to.equal(fontX + 2);
+ expect(charA.texture.frame.y).to.equal(fontY + 2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charB.texture.frame.x).to.equal(fontX + 2);
+ expect(charB.texture.frame.y).to.equal(fontY + 24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charC.texture.frame.x).to.equal(fontX + 23);
+ expect(charC.texture.frame.y).to.equal(fontY + 2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charD.texture.frame.x).to.equal(fontX + 19);
+ expect(charD.texture.frame.y).to.equal(fontY + 24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+ });
+
+ it('should properly register bitmap font NESTED into SCALED spritesheet', function (done)
+ {
+ const baseTexture = new PIXI.BaseTexture(this.atlasScaledImage, null, 1);
+ const spritesheet = new PIXI.Spritesheet(baseTexture, this.atlasScaledJSON);
+
+ spritesheet.parse(() =>
+ {
+ const fontTexture = PIXI.Texture.fromFrame('resources/font.png');
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, fontTexture);
+ const fontX = 158; // bare value from spritesheet frame
+ const fontY = 2; // bare value from spritesheet frame
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charA.texture.frame.x).to.equal(fontX + 2);
+ expect(charA.texture.frame.y).to.equal(fontY + 2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charB.texture.frame.x).to.equal(fontX + 2);
+ expect(charB.texture.frame.y).to.equal(fontY + 24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charC.texture.frame.x).to.equal(fontX + 23);
+ expect(charC.texture.frame.y).to.equal(fontY + 2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charD.texture.frame.x).to.equal(fontX + 19);
+ expect(charD.texture.frame.y).to.equal(fontY + 24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+ });
});
describe('PIXI.loaders.parseBitmapFontData', function ()
diff --git a/test/loaders/resources/atlas.json b/test/loaders/resources/atlas.json
new file mode 100644
index 0000000..86e65a5
--- /dev/null
+++ b/test/loaders/resources/atlas.json
@@ -0,0 +1,25 @@
+{
+ "meta": {
+ "image": "atlas.png",
+ "size": {"w":256,"h":256},
+ "scale": "1"
+ },
+ "frames": {
+ "resources/test.png":
+ {
+ "frame": {"x":2,"y":2,"w":152,"h":188},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":74,"y":36,"w":152,"h":188},
+ "sourceSize": {"w":300,"h":225}
+ },
+ "resources/font.png":
+ {
+ "frame": {"x":158,"y":2,"w":40,"h":42},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":2,"y":2,"w":40,"h":42},
+ "sourceSize": {"w":43,"h":46}
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/extras/BitmapText.js b/src/extras/BitmapText.js
index 0592b54..96d9f44 100644
--- a/src/extras/BitmapText.js
+++ b/src/extras/BitmapText.js
@@ -1,5 +1,6 @@
import * as core from '../core';
import ObservablePoint from '../core/math/ObservablePoint';
+import { getResolutionOfUrl } from '../core/utils';
import settings from '../core/settings';
/**
@@ -510,7 +511,8 @@
const data = {};
const info = xml.getElementsByTagName('info')[0];
const common = xml.getElementsByTagName('common')[0];
- const res = texture.baseTexture.resolution || settings.RESOLUTION;
+ const fileName = xml.getElementsByTagName('page')[0].getAttribute('file');
+ const res = getResolutionOfUrl(fileName, settings.RESOLUTION);
data.font = info.getAttribute('face');
data.size = parseInt(info.getAttribute('size'), 10);
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
deleted file mode 100644
index 16536d2..0000000
--- a/src/extras/TextureTransform.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import { default as Matrix } from '../core/math/Matrix';
-
-const tempMat = new Matrix();
-
-/**
- * class controls uv transform and frame clamp for texture
- *
- * @class
- * @memberof PIXI.extras
- */
-export default class TextureTransform
-{
- /**
- *
- * @param {PIXI.Texture} texture observed texture
- * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
- * @constructor
- */
- constructor(texture, clampMargin)
- {
- this._texture = texture;
-
- this.mapCoord = new Matrix();
-
- this.uClampFrame = new Float32Array(4);
-
- this.uClampOffset = new Float32Array(2);
-
- this._lastTextureID = -1;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
- *
- * @default 0
- * @member {number}
- */
- this.clampOffset = 0;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
- *
- * @default 0.5
- * @member {number}
- */
- this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
- }
-
- /**
- * texture property
- * @member {PIXI.Texture}
- */
- get texture()
- {
- return this._texture;
- }
-
- set texture(value) // eslint-disable-line require-jsdoc
- {
- this._texture = value;
- this._lastTextureID = -1;
- }
-
- /**
- * Multiplies uvs array to transform
- * @param {Float32Array} uvs mesh uvs
- * @param {Float32Array} [out=uvs] output
- * @returns {Float32Array} output
- */
- multiplyUvs(uvs, out)
- {
- if (out === undefined)
- {
- out = uvs;
- }
-
- const mat = this.mapCoord;
-
- for (let i = 0; i < uvs.length; i += 2)
- {
- const x = uvs[i];
- const y = uvs[i + 1];
-
- out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
- out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
- }
-
- return out;
- }
-
- /**
- * updates matrices if texture was changed
- * @param {boolean} forceUpdate if true, matrices will be updated any case
- * @returns {boolean} whether or not it was updated
- */
- update(forceUpdate)
- {
- const tex = this._texture;
-
- if (!tex || !tex.valid)
- {
- return false;
- }
-
- if (!forceUpdate
- && this._lastTextureID === tex._updateID)
- {
- return false;
- }
-
- this._lastTextureID = tex._updateID;
-
- const uvs = tex._uvs;
-
- this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
-
- const orig = tex.orig;
- const trim = tex.trim;
-
- if (trim)
- {
- tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
- -trim.x / trim.width, -trim.y / trim.height);
- this.mapCoord.append(tempMat);
- }
-
- const texBase = tex.baseTexture;
- const frame = this.uClampFrame;
- const margin = this.clampMargin / texBase.resolution;
- const offset = this.clampOffset;
-
- frame[0] = (tex._frame.x + margin + offset) / texBase.width;
- frame[1] = (tex._frame.y + margin + offset) / texBase.height;
- frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
- frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
- this.uClampOffset[0] = offset / texBase.realWidth;
- this.uClampOffset[1] = offset / texBase.realHeight;
-
- return true;
- }
-}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 736b207..84c0841 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -1,6 +1,5 @@
import * as core from '../core';
import CanvasTinter from '../core/sprites/canvas/CanvasTinter';
-import { default as TextureTransform } from './TextureTransform';
const tempPoint = new core.Point();
@@ -58,9 +57,9 @@
/**
* transform that is applied to UV to get the texture coords
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
*/
- this.uvTransform = texture.transform || new TextureTransform(texture);
+ this.uvTransform = texture.transform || new core.TextureMatrix(texture);
/**
* Plugin that is responsible for rendering this element.
diff --git a/src/extras/index.js b/src/extras/index.js
index 5b98cb1..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -3,7 +3,6 @@
* @namespace PIXI.extras
*/
export { default as AnimatedSprite } from './AnimatedSprite';
-export { default as TextureTransform } from './TextureTransform';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
export { default as BitmapText } from './BitmapText';
diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js
new file mode 100644
index 0000000..c2824ed
--- /dev/null
+++ b/src/filters/alpha/AlphaFilter.js
@@ -0,0 +1,55 @@
+import * as core from '../../core';
+import { readFileSync } from 'fs';
+import { join } from 'path';
+
+/**
+ * Simplest filter - applies alpha
+ *
+ * Use this instead of Container's alpha property to avoid visual layering of individual elements.
+ * AlphaFilter applies alpha evenly across the entire display object and any opaque elements it contains.
+ * If elements are not opaque, they will blend with each other anyway.
+ *
+ * Very handy if you want to use common features of all filters:
+ *
+ * 1. Assign a blendMode to this filter, blend all elements inside display object with background.
+ *
+ * 2. To use clipping in display coordinates, assign a filterArea to the same container that has this filter.
+ *
+ * @class
+ * @extends PIXI.Filter
+ * @memberof PIXI.filters
+ */
+export default class AlphaFilter extends core.Filter
+{
+ /**
+ *
+ */
+ constructor()
+ {
+ super(
+ // vertex shader
+ readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
+ // fragment shader
+ readFileSync(join(__dirname, './alpha.frag'), 'utf8')
+ );
+
+ this.alpha = 1.0;
+ this.glShaderKey = 'alpha';
+ }
+
+ /**
+ * Coefficient for alpha multiplication
+ *
+ * @member {number}
+ * @default 1
+ */
+ get alpha()
+ {
+ return this.uniforms.uAlpha;
+ }
+
+ set alpha(value) // eslint-disable-line require-jsdoc
+ {
+ this.uniforms.uAlpha = value;
+ }
+}
diff --git a/src/filters/alpha/alpha.frag b/src/filters/alpha/alpha.frag
new file mode 100644
index 0000000..6db588c
--- /dev/null
+++ b/src/filters/alpha/alpha.frag
@@ -0,0 +1,9 @@
+varying vec2 vTextureCoord;
+
+uniform sampler2D uSampler;
+uniform float uAlpha;
+
+void main(void)
+{
+ gl_FragColor = texture2D(uSampler, vTextureCoord) * uAlpha;
+}
diff --git a/src/filters/index.js b/src/filters/index.js
index 7ceb50a..dca47ab 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -25,4 +25,4 @@
export { default as BlurXFilter } from './blur/BlurXFilter';
export { default as BlurYFilter } from './blur/BlurYFilter';
export { default as ColorMatrixFilter } from './colormatrix/ColorMatrixFilter';
-export { default as VoidFilter } from './void/VoidFilter';
+export { default as AlphaFilter } from './alpha/AlphaFilter';
diff --git a/src/filters/void/VoidFilter.js b/src/filters/void/VoidFilter.js
deleted file mode 100644
index b4361ac..0000000
--- a/src/filters/void/VoidFilter.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as core from '../../core';
-import { readFileSync } from 'fs';
-import { join } from 'path';
-
-/**
- * Does nothing. Very handy.
- *
- * @class
- * @extends PIXI.Filter
- * @memberof PIXI.filters
- */
-export default class VoidFilter extends core.Filter
-{
- /**
- *
- */
- constructor()
- {
- super(
- // vertex shader
- readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
- // fragment shader
- readFileSync(join(__dirname, './void.frag'), 'utf8')
- );
-
- this.glShaderKey = 'void';
- }
-}
diff --git a/src/filters/void/void.frag b/src/filters/void/void.frag
deleted file mode 100644
index 99168fb..0000000
--- a/src/filters/void/void.frag
+++ /dev/null
@@ -1,8 +0,0 @@
-varying vec2 vTextureCoord;
-
-uniform sampler2D uSampler;
-
-void main(void)
-{
- gl_FragColor = texture2D(uSampler, vTextureCoord);
-}
diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js
index d866f03..7006a3e 100644
--- a/src/mesh/Mesh.js
+++ b/src/mesh/Mesh.js
@@ -1,5 +1,5 @@
import * as core from '../core';
-import { default as TextureTransform } from '../extras/TextureTransform';
+import Texture from '../core/textures/Texture';
const tempPoint = new core.Point();
const tempPolygon = new core.Polygon();
@@ -27,9 +27,10 @@
* The texture of the Mesh
*
* @member {PIXI.Texture}
+ * @default PIXI.Texture.EMPTY
* @private
*/
- this._texture = texture;
+ this._texture = texture || Texture.EMPTY;
/**
* The Uvs of the Mesh
@@ -129,10 +130,10 @@
* its updated independently from texture uvTransform
* updates of uvs are tied to that thing
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
* @private
*/
- this._uvTransform = new TextureTransform(texture);
+ this._uvTransform = new core.TextureMatrix(this._texture);
/**
* whether or not upload uvTransform to shader
diff --git a/src/mesh/NineSlicePlane.js b/src/mesh/NineSlicePlane.js
index 61ba5ee..f0d7575 100644
--- a/src/mesh/NineSlicePlane.js
+++ b/src/mesh/NineSlicePlane.js
@@ -172,8 +172,8 @@
const base = this._texture.baseTexture;
const textureSource = base.source;
- const w = base.width;
- const h = base.height;
+ const w = base.width * base.resolution;
+ const h = base.height * base.resolution;
this.drawSegment(context, textureSource, w, h, 0, 1, 10, 11);
this.drawSegment(context, textureSource, w, h, 2, 3, 12, 13);
diff --git a/src/mesh/Plane.js b/src/mesh/Plane.js
index 4dd2398..2aa60f9 100644
--- a/src/mesh/Plane.js
+++ b/src/mesh/Plane.js
@@ -94,6 +94,8 @@
this.uvs = new Float32Array(uvs);
this.colors = new Float32Array(colors);
this.indices = new Uint16Array(indices);
+
+ this.dirty++;
this.indexDirty++;
this.multiplyUvs();
diff --git a/test/interaction/InteractionManager.js b/test/interaction/InteractionManager.js
index 3f84d6a..136640e 100644
--- a/test/interaction/InteractionManager.js
+++ b/test/interaction/InteractionManager.js
@@ -279,13 +279,48 @@
removeSpy.restore();
});
- it('should add and remove pointer events to element', function ()
+ it('should add and remove pointer events to element seven times when touch events are supported', function ()
{
const manager = new PIXI.interaction.InteractionManager(sinon.stub());
const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
manager.interactionDOMElement = element;
manager.supportsPointerEvents = true;
+ manager.supportsTouchEvents = true;
+
+ manager.addEvents();
+
+ expect(element.addEventListener).to.have.been.callCount(7);
+ expect(element.addEventListener).to.have.been.calledWith('pointerdown');
+ expect(element.addEventListener).to.have.been.calledWith('pointerleave');
+ expect(element.addEventListener).to.have.been.calledWith('pointerover');
+
+ expect(element.addEventListener).to.have.been.calledWith('touchstart');
+ expect(element.addEventListener).to.have.been.calledWith('touchcancel');
+ expect(element.addEventListener).to.have.been.calledWith('touchend');
+ expect(element.addEventListener).to.have.been.calledWith('touchmove');
+
+ manager.removeEvents();
+
+ expect(element.removeEventListener).to.have.been.callCount(7);
+ expect(element.removeEventListener).to.have.been.calledWith('pointerdown');
+ expect(element.removeEventListener).to.have.been.calledWith('pointerleave');
+ expect(element.removeEventListener).to.have.been.calledWith('pointerover');
+
+ expect(element.removeEventListener).to.have.been.calledWith('touchstart');
+ expect(element.removeEventListener).to.have.been.calledWith('touchcancel');
+ expect(element.removeEventListener).to.have.been.calledWith('touchend');
+ expect(element.removeEventListener).to.have.been.calledWith('touchmove');
+ });
+
+ it('should add and remove pointer events to element three times when touch events are not supported', function ()
+ {
+ const manager = new PIXI.interaction.InteractionManager(sinon.stub());
+ const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
+
+ manager.interactionDOMElement = element;
+ manager.supportsPointerEvents = true;
+ manager.supportsTouchEvents = false;
manager.addEvents();
diff --git a/test/loaders/bitmapFontParser.js b/test/loaders/bitmapFontParser.js
index 7c77343..70703fc 100644
--- a/test/loaders/bitmapFontParser.js
+++ b/test/loaders/bitmapFontParser.js
@@ -1,7 +1,81 @@
'use strict';
+const path = require('path');
+const fs = require('fs');
+
describe('PIXI.loaders.bitmapFontParser', function ()
{
+ afterEach(function ()
+ {
+ for (var font in PIXI.extras.BitmapText.fonts)
+ {
+ delete PIXI.extras.BitmapText.fonts[font];
+ }
+ for (var baseTexture in PIXI.utils.BaseTextureCache)
+ {
+ delete PIXI.utils.BaseTextureCache[baseTexture];
+ }
+ for (var texture in PIXI.utils.TextureCache)
+ {
+ delete PIXI.utils.TextureCache[texture];
+ }
+ });
+
+ before(function (done)
+ {
+ const resolveURL = (url) => path.resolve(this.resources, url);
+
+ this.resources = path.join(__dirname, 'resources');
+ this.fontXML = null;
+ this.fontScaledXML = null;
+ this.fontImage = null;
+ this.fontScaledImage = null;
+ this.atlasImage = null;
+ this.atlasScaledImage = null;
+ this.atlasJSON = require(resolveURL('atlas.json')); // eslint-disable-line global-require
+ this.atlasScaledJSON = require(resolveURL('atlas@0.5x.json')); // eslint-disable-line global-require
+
+ const loadXML = (url) => new Promise((resolve) =>
+ fs.readFile(resolveURL(url), 'utf8', (err, data) =>
+ {
+ expect(err).to.be.null;
+ resolve((new window.DOMParser()).parseFromString(data, 'text/xml'));
+ }));
+
+ const loadImage = (url) => new Promise((resolve) =>
+ {
+ const image = new Image();
+
+ image.onload = () => resolve(image);
+ image.src = resolveURL(url);
+ });
+
+ Promise.all([
+ loadXML('font.fnt'),
+ loadXML('font@0.5x.fnt'),
+ loadImage('font.png'),
+ loadImage('font@0.5x.png'),
+ loadImage('atlas.png'),
+ loadImage('atlas@0.5x.png'),
+ ]).then(([
+ fontXML,
+ fontScaledXML,
+ fontImage,
+ fontScaledImage,
+ atlasImage,
+ atlasScaledImage,
+ ]) =>
+ {
+ this.fontXML = fontXML;
+ this.fontScaledXML = fontScaledXML;
+ this.fontImage = fontImage;
+ this.fontScaledImage = fontScaledImage;
+ this.atlasImage = atlasImage;
+ this.atlasScaledImage = atlasScaledImage;
+ done();
+ });
+ });
+
it('should exist and return a function', function ()
{
expect(PIXI.loaders.bitmapFontParser).to.be.a('function');
@@ -33,6 +107,206 @@
// TODO: Test the texture cache code path.
// TODO: Test the loading texture code path.
// TODO: Test data-url code paths.
+
+ it('should properly register bitmap font', function (done)
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture(this.fontImage, null, 1));
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, texture);
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charA.texture.frame.x).to.equal(2);
+ expect(charA.texture.frame.y).to.equal(2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charB.texture.frame.x).to.equal(2);
+ expect(charB.texture.frame.y).to.equal(24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charC.texture.frame.x).to.equal(23);
+ expect(charC.texture.frame.y).to.equal(2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charD.texture.frame.x).to.equal(19);
+ expect(charD.texture.frame.y).to.equal(24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+
+ it('should properly register SCALED bitmap font', function (done)
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture(this.fontScaledImage, null, 0.5));
+ const font = PIXI.extras.BitmapText.registerFont(this.fontScaledXML, texture);
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charA.texture.frame.x).to.equal(4); // 2 / 0.5
+ expect(charA.texture.frame.y).to.equal(4); // 2 / 0.5
+ expect(charA.texture.frame.width).to.equal(38); // 19 / 0.5
+ expect(charA.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charB.texture.frame.x).to.equal(4); // 2 / 0.5
+ expect(charB.texture.frame.y).to.equal(48); // 24 / 0.5
+ expect(charB.texture.frame.width).to.equal(30); // 15 / 0.5
+ expect(charB.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charC.texture.frame.x).to.equal(46); // 23 / 0.5
+ expect(charC.texture.frame.y).to.equal(4); // 2 / 0.5
+ expect(charC.texture.frame.width).to.equal(36); // 18 / 0.5
+ expect(charC.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charD.texture.frame.x).to.equal(38); // 19 / 0.5
+ expect(charD.texture.frame.y).to.equal(48); // 24 / 0.5
+ expect(charD.texture.frame.width).to.equal(34); // 17 / 0.5
+ expect(charD.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+
+ it('should properly register bitmap font NESTED into spritesheet', function (done)
+ {
+ const baseTexture = new PIXI.BaseTexture(this.atlasImage, null, 1);
+ const spritesheet = new PIXI.Spritesheet(baseTexture, this.atlasJSON);
+
+ spritesheet.parse(() =>
+ {
+ const fontTexture = PIXI.Texture.fromFrame('resources/font.png');
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, fontTexture);
+ const fontX = 158; // bare value from spritesheet frame
+ const fontY = 2; // bare value from spritesheet frame
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charA.texture.frame.x).to.equal(fontX + 2);
+ expect(charA.texture.frame.y).to.equal(fontY + 2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charB.texture.frame.x).to.equal(fontX + 2);
+ expect(charB.texture.frame.y).to.equal(fontY + 24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charC.texture.frame.x).to.equal(fontX + 23);
+ expect(charC.texture.frame.y).to.equal(fontY + 2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charD.texture.frame.x).to.equal(fontX + 19);
+ expect(charD.texture.frame.y).to.equal(fontY + 24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+ });
+
+ it('should properly register bitmap font NESTED into SCALED spritesheet', function (done)
+ {
+ const baseTexture = new PIXI.BaseTexture(this.atlasScaledImage, null, 1);
+ const spritesheet = new PIXI.Spritesheet(baseTexture, this.atlasScaledJSON);
+
+ spritesheet.parse(() =>
+ {
+ const fontTexture = PIXI.Texture.fromFrame('resources/font.png');
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, fontTexture);
+ const fontX = 158; // bare value from spritesheet frame
+ const fontY = 2; // bare value from spritesheet frame
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charA.texture.frame.x).to.equal(fontX + 2);
+ expect(charA.texture.frame.y).to.equal(fontY + 2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charB.texture.frame.x).to.equal(fontX + 2);
+ expect(charB.texture.frame.y).to.equal(fontY + 24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charC.texture.frame.x).to.equal(fontX + 23);
+ expect(charC.texture.frame.y).to.equal(fontY + 2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charD.texture.frame.x).to.equal(fontX + 19);
+ expect(charD.texture.frame.y).to.equal(fontY + 24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+ });
});
describe('PIXI.loaders.parseBitmapFontData', function ()
diff --git a/test/loaders/resources/atlas.json b/test/loaders/resources/atlas.json
new file mode 100644
index 0000000..86e65a5
--- /dev/null
+++ b/test/loaders/resources/atlas.json
@@ -0,0 +1,25 @@
+{
+ "meta": {
+ "image": "atlas.png",
+ "size": {"w":256,"h":256},
+ "scale": "1"
+ },
+ "frames": {
+ "resources/test.png":
+ {
+ "frame": {"x":2,"y":2,"w":152,"h":188},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":74,"y":36,"w":152,"h":188},
+ "sourceSize": {"w":300,"h":225}
+ },
+ "resources/font.png":
+ {
+ "frame": {"x":158,"y":2,"w":40,"h":42},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":2,"y":2,"w":40,"h":42},
+ "sourceSize": {"w":43,"h":46}
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/loaders/resources/atlas.png b/test/loaders/resources/atlas.png
new file mode 100644
index 0000000..d5e7892
--- /dev/null
+++ b/test/loaders/resources/atlas.png
Binary files differ
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/extras/BitmapText.js b/src/extras/BitmapText.js
index 0592b54..96d9f44 100644
--- a/src/extras/BitmapText.js
+++ b/src/extras/BitmapText.js
@@ -1,5 +1,6 @@
import * as core from '../core';
import ObservablePoint from '../core/math/ObservablePoint';
+import { getResolutionOfUrl } from '../core/utils';
import settings from '../core/settings';
/**
@@ -510,7 +511,8 @@
const data = {};
const info = xml.getElementsByTagName('info')[0];
const common = xml.getElementsByTagName('common')[0];
- const res = texture.baseTexture.resolution || settings.RESOLUTION;
+ const fileName = xml.getElementsByTagName('page')[0].getAttribute('file');
+ const res = getResolutionOfUrl(fileName, settings.RESOLUTION);
data.font = info.getAttribute('face');
data.size = parseInt(info.getAttribute('size'), 10);
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
deleted file mode 100644
index 16536d2..0000000
--- a/src/extras/TextureTransform.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import { default as Matrix } from '../core/math/Matrix';
-
-const tempMat = new Matrix();
-
-/**
- * class controls uv transform and frame clamp for texture
- *
- * @class
- * @memberof PIXI.extras
- */
-export default class TextureTransform
-{
- /**
- *
- * @param {PIXI.Texture} texture observed texture
- * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
- * @constructor
- */
- constructor(texture, clampMargin)
- {
- this._texture = texture;
-
- this.mapCoord = new Matrix();
-
- this.uClampFrame = new Float32Array(4);
-
- this.uClampOffset = new Float32Array(2);
-
- this._lastTextureID = -1;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
- *
- * @default 0
- * @member {number}
- */
- this.clampOffset = 0;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
- *
- * @default 0.5
- * @member {number}
- */
- this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
- }
-
- /**
- * texture property
- * @member {PIXI.Texture}
- */
- get texture()
- {
- return this._texture;
- }
-
- set texture(value) // eslint-disable-line require-jsdoc
- {
- this._texture = value;
- this._lastTextureID = -1;
- }
-
- /**
- * Multiplies uvs array to transform
- * @param {Float32Array} uvs mesh uvs
- * @param {Float32Array} [out=uvs] output
- * @returns {Float32Array} output
- */
- multiplyUvs(uvs, out)
- {
- if (out === undefined)
- {
- out = uvs;
- }
-
- const mat = this.mapCoord;
-
- for (let i = 0; i < uvs.length; i += 2)
- {
- const x = uvs[i];
- const y = uvs[i + 1];
-
- out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
- out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
- }
-
- return out;
- }
-
- /**
- * updates matrices if texture was changed
- * @param {boolean} forceUpdate if true, matrices will be updated any case
- * @returns {boolean} whether or not it was updated
- */
- update(forceUpdate)
- {
- const tex = this._texture;
-
- if (!tex || !tex.valid)
- {
- return false;
- }
-
- if (!forceUpdate
- && this._lastTextureID === tex._updateID)
- {
- return false;
- }
-
- this._lastTextureID = tex._updateID;
-
- const uvs = tex._uvs;
-
- this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
-
- const orig = tex.orig;
- const trim = tex.trim;
-
- if (trim)
- {
- tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
- -trim.x / trim.width, -trim.y / trim.height);
- this.mapCoord.append(tempMat);
- }
-
- const texBase = tex.baseTexture;
- const frame = this.uClampFrame;
- const margin = this.clampMargin / texBase.resolution;
- const offset = this.clampOffset;
-
- frame[0] = (tex._frame.x + margin + offset) / texBase.width;
- frame[1] = (tex._frame.y + margin + offset) / texBase.height;
- frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
- frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
- this.uClampOffset[0] = offset / texBase.realWidth;
- this.uClampOffset[1] = offset / texBase.realHeight;
-
- return true;
- }
-}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 736b207..84c0841 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -1,6 +1,5 @@
import * as core from '../core';
import CanvasTinter from '../core/sprites/canvas/CanvasTinter';
-import { default as TextureTransform } from './TextureTransform';
const tempPoint = new core.Point();
@@ -58,9 +57,9 @@
/**
* transform that is applied to UV to get the texture coords
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
*/
- this.uvTransform = texture.transform || new TextureTransform(texture);
+ this.uvTransform = texture.transform || new core.TextureMatrix(texture);
/**
* Plugin that is responsible for rendering this element.
diff --git a/src/extras/index.js b/src/extras/index.js
index 5b98cb1..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -3,7 +3,6 @@
* @namespace PIXI.extras
*/
export { default as AnimatedSprite } from './AnimatedSprite';
-export { default as TextureTransform } from './TextureTransform';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
export { default as BitmapText } from './BitmapText';
diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js
new file mode 100644
index 0000000..c2824ed
--- /dev/null
+++ b/src/filters/alpha/AlphaFilter.js
@@ -0,0 +1,55 @@
+import * as core from '../../core';
+import { readFileSync } from 'fs';
+import { join } from 'path';
+
+/**
+ * Simplest filter - applies alpha
+ *
+ * Use this instead of Container's alpha property to avoid visual layering of individual elements.
+ * AlphaFilter applies alpha evenly across the entire display object and any opaque elements it contains.
+ * If elements are not opaque, they will blend with each other anyway.
+ *
+ * Very handy if you want to use common features of all filters:
+ *
+ * 1. Assign a blendMode to this filter, blend all elements inside display object with background.
+ *
+ * 2. To use clipping in display coordinates, assign a filterArea to the same container that has this filter.
+ *
+ * @class
+ * @extends PIXI.Filter
+ * @memberof PIXI.filters
+ */
+export default class AlphaFilter extends core.Filter
+{
+ /**
+ *
+ */
+ constructor()
+ {
+ super(
+ // vertex shader
+ readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
+ // fragment shader
+ readFileSync(join(__dirname, './alpha.frag'), 'utf8')
+ );
+
+ this.alpha = 1.0;
+ this.glShaderKey = 'alpha';
+ }
+
+ /**
+ * Coefficient for alpha multiplication
+ *
+ * @member {number}
+ * @default 1
+ */
+ get alpha()
+ {
+ return this.uniforms.uAlpha;
+ }
+
+ set alpha(value) // eslint-disable-line require-jsdoc
+ {
+ this.uniforms.uAlpha = value;
+ }
+}
diff --git a/src/filters/alpha/alpha.frag b/src/filters/alpha/alpha.frag
new file mode 100644
index 0000000..6db588c
--- /dev/null
+++ b/src/filters/alpha/alpha.frag
@@ -0,0 +1,9 @@
+varying vec2 vTextureCoord;
+
+uniform sampler2D uSampler;
+uniform float uAlpha;
+
+void main(void)
+{
+ gl_FragColor = texture2D(uSampler, vTextureCoord) * uAlpha;
+}
diff --git a/src/filters/index.js b/src/filters/index.js
index 7ceb50a..dca47ab 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -25,4 +25,4 @@
export { default as BlurXFilter } from './blur/BlurXFilter';
export { default as BlurYFilter } from './blur/BlurYFilter';
export { default as ColorMatrixFilter } from './colormatrix/ColorMatrixFilter';
-export { default as VoidFilter } from './void/VoidFilter';
+export { default as AlphaFilter } from './alpha/AlphaFilter';
diff --git a/src/filters/void/VoidFilter.js b/src/filters/void/VoidFilter.js
deleted file mode 100644
index b4361ac..0000000
--- a/src/filters/void/VoidFilter.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as core from '../../core';
-import { readFileSync } from 'fs';
-import { join } from 'path';
-
-/**
- * Does nothing. Very handy.
- *
- * @class
- * @extends PIXI.Filter
- * @memberof PIXI.filters
- */
-export default class VoidFilter extends core.Filter
-{
- /**
- *
- */
- constructor()
- {
- super(
- // vertex shader
- readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
- // fragment shader
- readFileSync(join(__dirname, './void.frag'), 'utf8')
- );
-
- this.glShaderKey = 'void';
- }
-}
diff --git a/src/filters/void/void.frag b/src/filters/void/void.frag
deleted file mode 100644
index 99168fb..0000000
--- a/src/filters/void/void.frag
+++ /dev/null
@@ -1,8 +0,0 @@
-varying vec2 vTextureCoord;
-
-uniform sampler2D uSampler;
-
-void main(void)
-{
- gl_FragColor = texture2D(uSampler, vTextureCoord);
-}
diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js
index d866f03..7006a3e 100644
--- a/src/mesh/Mesh.js
+++ b/src/mesh/Mesh.js
@@ -1,5 +1,5 @@
import * as core from '../core';
-import { default as TextureTransform } from '../extras/TextureTransform';
+import Texture from '../core/textures/Texture';
const tempPoint = new core.Point();
const tempPolygon = new core.Polygon();
@@ -27,9 +27,10 @@
* The texture of the Mesh
*
* @member {PIXI.Texture}
+ * @default PIXI.Texture.EMPTY
* @private
*/
- this._texture = texture;
+ this._texture = texture || Texture.EMPTY;
/**
* The Uvs of the Mesh
@@ -129,10 +130,10 @@
* its updated independently from texture uvTransform
* updates of uvs are tied to that thing
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
* @private
*/
- this._uvTransform = new TextureTransform(texture);
+ this._uvTransform = new core.TextureMatrix(this._texture);
/**
* whether or not upload uvTransform to shader
diff --git a/src/mesh/NineSlicePlane.js b/src/mesh/NineSlicePlane.js
index 61ba5ee..f0d7575 100644
--- a/src/mesh/NineSlicePlane.js
+++ b/src/mesh/NineSlicePlane.js
@@ -172,8 +172,8 @@
const base = this._texture.baseTexture;
const textureSource = base.source;
- const w = base.width;
- const h = base.height;
+ const w = base.width * base.resolution;
+ const h = base.height * base.resolution;
this.drawSegment(context, textureSource, w, h, 0, 1, 10, 11);
this.drawSegment(context, textureSource, w, h, 2, 3, 12, 13);
diff --git a/src/mesh/Plane.js b/src/mesh/Plane.js
index 4dd2398..2aa60f9 100644
--- a/src/mesh/Plane.js
+++ b/src/mesh/Plane.js
@@ -94,6 +94,8 @@
this.uvs = new Float32Array(uvs);
this.colors = new Float32Array(colors);
this.indices = new Uint16Array(indices);
+
+ this.dirty++;
this.indexDirty++;
this.multiplyUvs();
diff --git a/test/interaction/InteractionManager.js b/test/interaction/InteractionManager.js
index 3f84d6a..136640e 100644
--- a/test/interaction/InteractionManager.js
+++ b/test/interaction/InteractionManager.js
@@ -279,13 +279,48 @@
removeSpy.restore();
});
- it('should add and remove pointer events to element', function ()
+ it('should add and remove pointer events to element seven times when touch events are supported', function ()
{
const manager = new PIXI.interaction.InteractionManager(sinon.stub());
const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
manager.interactionDOMElement = element;
manager.supportsPointerEvents = true;
+ manager.supportsTouchEvents = true;
+
+ manager.addEvents();
+
+ expect(element.addEventListener).to.have.been.callCount(7);
+ expect(element.addEventListener).to.have.been.calledWith('pointerdown');
+ expect(element.addEventListener).to.have.been.calledWith('pointerleave');
+ expect(element.addEventListener).to.have.been.calledWith('pointerover');
+
+ expect(element.addEventListener).to.have.been.calledWith('touchstart');
+ expect(element.addEventListener).to.have.been.calledWith('touchcancel');
+ expect(element.addEventListener).to.have.been.calledWith('touchend');
+ expect(element.addEventListener).to.have.been.calledWith('touchmove');
+
+ manager.removeEvents();
+
+ expect(element.removeEventListener).to.have.been.callCount(7);
+ expect(element.removeEventListener).to.have.been.calledWith('pointerdown');
+ expect(element.removeEventListener).to.have.been.calledWith('pointerleave');
+ expect(element.removeEventListener).to.have.been.calledWith('pointerover');
+
+ expect(element.removeEventListener).to.have.been.calledWith('touchstart');
+ expect(element.removeEventListener).to.have.been.calledWith('touchcancel');
+ expect(element.removeEventListener).to.have.been.calledWith('touchend');
+ expect(element.removeEventListener).to.have.been.calledWith('touchmove');
+ });
+
+ it('should add and remove pointer events to element three times when touch events are not supported', function ()
+ {
+ const manager = new PIXI.interaction.InteractionManager(sinon.stub());
+ const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
+
+ manager.interactionDOMElement = element;
+ manager.supportsPointerEvents = true;
+ manager.supportsTouchEvents = false;
manager.addEvents();
diff --git a/test/loaders/bitmapFontParser.js b/test/loaders/bitmapFontParser.js
index 7c77343..70703fc 100644
--- a/test/loaders/bitmapFontParser.js
+++ b/test/loaders/bitmapFontParser.js
@@ -1,7 +1,81 @@
'use strict';
+const path = require('path');
+const fs = require('fs');
+
describe('PIXI.loaders.bitmapFontParser', function ()
{
+ afterEach(function ()
+ {
+ for (var font in PIXI.extras.BitmapText.fonts)
+ {
+ delete PIXI.extras.BitmapText.fonts[font];
+ }
+ for (var baseTexture in PIXI.utils.BaseTextureCache)
+ {
+ delete PIXI.utils.BaseTextureCache[baseTexture];
+ }
+ for (var texture in PIXI.utils.TextureCache)
+ {
+ delete PIXI.utils.TextureCache[texture];
+ }
+ });
+
+ before(function (done)
+ {
+ const resolveURL = (url) => path.resolve(this.resources, url);
+
+ this.resources = path.join(__dirname, 'resources');
+ this.fontXML = null;
+ this.fontScaledXML = null;
+ this.fontImage = null;
+ this.fontScaledImage = null;
+ this.atlasImage = null;
+ this.atlasScaledImage = null;
+ this.atlasJSON = require(resolveURL('atlas.json')); // eslint-disable-line global-require
+ this.atlasScaledJSON = require(resolveURL('atlas@0.5x.json')); // eslint-disable-line global-require
+
+ const loadXML = (url) => new Promise((resolve) =>
+ fs.readFile(resolveURL(url), 'utf8', (err, data) =>
+ {
+ expect(err).to.be.null;
+ resolve((new window.DOMParser()).parseFromString(data, 'text/xml'));
+ }));
+
+ const loadImage = (url) => new Promise((resolve) =>
+ {
+ const image = new Image();
+
+ image.onload = () => resolve(image);
+ image.src = resolveURL(url);
+ });
+
+ Promise.all([
+ loadXML('font.fnt'),
+ loadXML('font@0.5x.fnt'),
+ loadImage('font.png'),
+ loadImage('font@0.5x.png'),
+ loadImage('atlas.png'),
+ loadImage('atlas@0.5x.png'),
+ ]).then(([
+ fontXML,
+ fontScaledXML,
+ fontImage,
+ fontScaledImage,
+ atlasImage,
+ atlasScaledImage,
+ ]) =>
+ {
+ this.fontXML = fontXML;
+ this.fontScaledXML = fontScaledXML;
+ this.fontImage = fontImage;
+ this.fontScaledImage = fontScaledImage;
+ this.atlasImage = atlasImage;
+ this.atlasScaledImage = atlasScaledImage;
+ done();
+ });
+ });
+
it('should exist and return a function', function ()
{
expect(PIXI.loaders.bitmapFontParser).to.be.a('function');
@@ -33,6 +107,206 @@
// TODO: Test the texture cache code path.
// TODO: Test the loading texture code path.
// TODO: Test data-url code paths.
+
+ it('should properly register bitmap font', function (done)
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture(this.fontImage, null, 1));
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, texture);
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charA.texture.frame.x).to.equal(2);
+ expect(charA.texture.frame.y).to.equal(2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charB.texture.frame.x).to.equal(2);
+ expect(charB.texture.frame.y).to.equal(24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charC.texture.frame.x).to.equal(23);
+ expect(charC.texture.frame.y).to.equal(2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charD.texture.frame.x).to.equal(19);
+ expect(charD.texture.frame.y).to.equal(24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+
+ it('should properly register SCALED bitmap font', function (done)
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture(this.fontScaledImage, null, 0.5));
+ const font = PIXI.extras.BitmapText.registerFont(this.fontScaledXML, texture);
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charA.texture.frame.x).to.equal(4); // 2 / 0.5
+ expect(charA.texture.frame.y).to.equal(4); // 2 / 0.5
+ expect(charA.texture.frame.width).to.equal(38); // 19 / 0.5
+ expect(charA.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charB.texture.frame.x).to.equal(4); // 2 / 0.5
+ expect(charB.texture.frame.y).to.equal(48); // 24 / 0.5
+ expect(charB.texture.frame.width).to.equal(30); // 15 / 0.5
+ expect(charB.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charC.texture.frame.x).to.equal(46); // 23 / 0.5
+ expect(charC.texture.frame.y).to.equal(4); // 2 / 0.5
+ expect(charC.texture.frame.width).to.equal(36); // 18 / 0.5
+ expect(charC.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charD.texture.frame.x).to.equal(38); // 19 / 0.5
+ expect(charD.texture.frame.y).to.equal(48); // 24 / 0.5
+ expect(charD.texture.frame.width).to.equal(34); // 17 / 0.5
+ expect(charD.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+
+ it('should properly register bitmap font NESTED into spritesheet', function (done)
+ {
+ const baseTexture = new PIXI.BaseTexture(this.atlasImage, null, 1);
+ const spritesheet = new PIXI.Spritesheet(baseTexture, this.atlasJSON);
+
+ spritesheet.parse(() =>
+ {
+ const fontTexture = PIXI.Texture.fromFrame('resources/font.png');
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, fontTexture);
+ const fontX = 158; // bare value from spritesheet frame
+ const fontY = 2; // bare value from spritesheet frame
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charA.texture.frame.x).to.equal(fontX + 2);
+ expect(charA.texture.frame.y).to.equal(fontY + 2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charB.texture.frame.x).to.equal(fontX + 2);
+ expect(charB.texture.frame.y).to.equal(fontY + 24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charC.texture.frame.x).to.equal(fontX + 23);
+ expect(charC.texture.frame.y).to.equal(fontY + 2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charD.texture.frame.x).to.equal(fontX + 19);
+ expect(charD.texture.frame.y).to.equal(fontY + 24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+ });
+
+ it('should properly register bitmap font NESTED into SCALED spritesheet', function (done)
+ {
+ const baseTexture = new PIXI.BaseTexture(this.atlasScaledImage, null, 1);
+ const spritesheet = new PIXI.Spritesheet(baseTexture, this.atlasScaledJSON);
+
+ spritesheet.parse(() =>
+ {
+ const fontTexture = PIXI.Texture.fromFrame('resources/font.png');
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, fontTexture);
+ const fontX = 158; // bare value from spritesheet frame
+ const fontY = 2; // bare value from spritesheet frame
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charA.texture.frame.x).to.equal(fontX + 2);
+ expect(charA.texture.frame.y).to.equal(fontY + 2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charB.texture.frame.x).to.equal(fontX + 2);
+ expect(charB.texture.frame.y).to.equal(fontY + 24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charC.texture.frame.x).to.equal(fontX + 23);
+ expect(charC.texture.frame.y).to.equal(fontY + 2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charD.texture.frame.x).to.equal(fontX + 19);
+ expect(charD.texture.frame.y).to.equal(fontY + 24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+ });
});
describe('PIXI.loaders.parseBitmapFontData', function ()
diff --git a/test/loaders/resources/atlas.json b/test/loaders/resources/atlas.json
new file mode 100644
index 0000000..86e65a5
--- /dev/null
+++ b/test/loaders/resources/atlas.json
@@ -0,0 +1,25 @@
+{
+ "meta": {
+ "image": "atlas.png",
+ "size": {"w":256,"h":256},
+ "scale": "1"
+ },
+ "frames": {
+ "resources/test.png":
+ {
+ "frame": {"x":2,"y":2,"w":152,"h":188},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":74,"y":36,"w":152,"h":188},
+ "sourceSize": {"w":300,"h":225}
+ },
+ "resources/font.png":
+ {
+ "frame": {"x":158,"y":2,"w":40,"h":42},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":2,"y":2,"w":40,"h":42},
+ "sourceSize": {"w":43,"h":46}
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/loaders/resources/atlas.png b/test/loaders/resources/atlas.png
new file mode 100644
index 0000000..d5e7892
--- /dev/null
+++ b/test/loaders/resources/atlas.png
Binary files differ
diff --git a/test/loaders/resources/atlas@0.5x.json b/test/loaders/resources/atlas@0.5x.json
new file mode 100644
index 0000000..ae990a1
--- /dev/null
+++ b/test/loaders/resources/atlas@0.5x.json
@@ -0,0 +1,25 @@
+{
+ "meta": {
+ "image": "atlas@0.5x.png",
+ "size": {"w":256,"h":256},
+ "scale": "1"
+ },
+ "frames": {
+ "resources/test.png":
+ {
+ "frame": {"x":2,"y":2,"w":152,"h":188},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":74,"y":36,"w":152,"h":188},
+ "sourceSize": {"w":300,"h":225}
+ },
+ "resources/font.png":
+ {
+ "frame": {"x":158,"y":2,"w":40,"h":42},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":2,"y":2,"w":40,"h":42},
+ "sourceSize": {"w":43,"h":46}
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/extras/BitmapText.js b/src/extras/BitmapText.js
index 0592b54..96d9f44 100644
--- a/src/extras/BitmapText.js
+++ b/src/extras/BitmapText.js
@@ -1,5 +1,6 @@
import * as core from '../core';
import ObservablePoint from '../core/math/ObservablePoint';
+import { getResolutionOfUrl } from '../core/utils';
import settings from '../core/settings';
/**
@@ -510,7 +511,8 @@
const data = {};
const info = xml.getElementsByTagName('info')[0];
const common = xml.getElementsByTagName('common')[0];
- const res = texture.baseTexture.resolution || settings.RESOLUTION;
+ const fileName = xml.getElementsByTagName('page')[0].getAttribute('file');
+ const res = getResolutionOfUrl(fileName, settings.RESOLUTION);
data.font = info.getAttribute('face');
data.size = parseInt(info.getAttribute('size'), 10);
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
deleted file mode 100644
index 16536d2..0000000
--- a/src/extras/TextureTransform.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import { default as Matrix } from '../core/math/Matrix';
-
-const tempMat = new Matrix();
-
-/**
- * class controls uv transform and frame clamp for texture
- *
- * @class
- * @memberof PIXI.extras
- */
-export default class TextureTransform
-{
- /**
- *
- * @param {PIXI.Texture} texture observed texture
- * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
- * @constructor
- */
- constructor(texture, clampMargin)
- {
- this._texture = texture;
-
- this.mapCoord = new Matrix();
-
- this.uClampFrame = new Float32Array(4);
-
- this.uClampOffset = new Float32Array(2);
-
- this._lastTextureID = -1;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
- *
- * @default 0
- * @member {number}
- */
- this.clampOffset = 0;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
- *
- * @default 0.5
- * @member {number}
- */
- this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
- }
-
- /**
- * texture property
- * @member {PIXI.Texture}
- */
- get texture()
- {
- return this._texture;
- }
-
- set texture(value) // eslint-disable-line require-jsdoc
- {
- this._texture = value;
- this._lastTextureID = -1;
- }
-
- /**
- * Multiplies uvs array to transform
- * @param {Float32Array} uvs mesh uvs
- * @param {Float32Array} [out=uvs] output
- * @returns {Float32Array} output
- */
- multiplyUvs(uvs, out)
- {
- if (out === undefined)
- {
- out = uvs;
- }
-
- const mat = this.mapCoord;
-
- for (let i = 0; i < uvs.length; i += 2)
- {
- const x = uvs[i];
- const y = uvs[i + 1];
-
- out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
- out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
- }
-
- return out;
- }
-
- /**
- * updates matrices if texture was changed
- * @param {boolean} forceUpdate if true, matrices will be updated any case
- * @returns {boolean} whether or not it was updated
- */
- update(forceUpdate)
- {
- const tex = this._texture;
-
- if (!tex || !tex.valid)
- {
- return false;
- }
-
- if (!forceUpdate
- && this._lastTextureID === tex._updateID)
- {
- return false;
- }
-
- this._lastTextureID = tex._updateID;
-
- const uvs = tex._uvs;
-
- this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
-
- const orig = tex.orig;
- const trim = tex.trim;
-
- if (trim)
- {
- tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
- -trim.x / trim.width, -trim.y / trim.height);
- this.mapCoord.append(tempMat);
- }
-
- const texBase = tex.baseTexture;
- const frame = this.uClampFrame;
- const margin = this.clampMargin / texBase.resolution;
- const offset = this.clampOffset;
-
- frame[0] = (tex._frame.x + margin + offset) / texBase.width;
- frame[1] = (tex._frame.y + margin + offset) / texBase.height;
- frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
- frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
- this.uClampOffset[0] = offset / texBase.realWidth;
- this.uClampOffset[1] = offset / texBase.realHeight;
-
- return true;
- }
-}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 736b207..84c0841 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -1,6 +1,5 @@
import * as core from '../core';
import CanvasTinter from '../core/sprites/canvas/CanvasTinter';
-import { default as TextureTransform } from './TextureTransform';
const tempPoint = new core.Point();
@@ -58,9 +57,9 @@
/**
* transform that is applied to UV to get the texture coords
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
*/
- this.uvTransform = texture.transform || new TextureTransform(texture);
+ this.uvTransform = texture.transform || new core.TextureMatrix(texture);
/**
* Plugin that is responsible for rendering this element.
diff --git a/src/extras/index.js b/src/extras/index.js
index 5b98cb1..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -3,7 +3,6 @@
* @namespace PIXI.extras
*/
export { default as AnimatedSprite } from './AnimatedSprite';
-export { default as TextureTransform } from './TextureTransform';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
export { default as BitmapText } from './BitmapText';
diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js
new file mode 100644
index 0000000..c2824ed
--- /dev/null
+++ b/src/filters/alpha/AlphaFilter.js
@@ -0,0 +1,55 @@
+import * as core from '../../core';
+import { readFileSync } from 'fs';
+import { join } from 'path';
+
+/**
+ * Simplest filter - applies alpha
+ *
+ * Use this instead of Container's alpha property to avoid visual layering of individual elements.
+ * AlphaFilter applies alpha evenly across the entire display object and any opaque elements it contains.
+ * If elements are not opaque, they will blend with each other anyway.
+ *
+ * Very handy if you want to use common features of all filters:
+ *
+ * 1. Assign a blendMode to this filter, blend all elements inside display object with background.
+ *
+ * 2. To use clipping in display coordinates, assign a filterArea to the same container that has this filter.
+ *
+ * @class
+ * @extends PIXI.Filter
+ * @memberof PIXI.filters
+ */
+export default class AlphaFilter extends core.Filter
+{
+ /**
+ *
+ */
+ constructor()
+ {
+ super(
+ // vertex shader
+ readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
+ // fragment shader
+ readFileSync(join(__dirname, './alpha.frag'), 'utf8')
+ );
+
+ this.alpha = 1.0;
+ this.glShaderKey = 'alpha';
+ }
+
+ /**
+ * Coefficient for alpha multiplication
+ *
+ * @member {number}
+ * @default 1
+ */
+ get alpha()
+ {
+ return this.uniforms.uAlpha;
+ }
+
+ set alpha(value) // eslint-disable-line require-jsdoc
+ {
+ this.uniforms.uAlpha = value;
+ }
+}
diff --git a/src/filters/alpha/alpha.frag b/src/filters/alpha/alpha.frag
new file mode 100644
index 0000000..6db588c
--- /dev/null
+++ b/src/filters/alpha/alpha.frag
@@ -0,0 +1,9 @@
+varying vec2 vTextureCoord;
+
+uniform sampler2D uSampler;
+uniform float uAlpha;
+
+void main(void)
+{
+ gl_FragColor = texture2D(uSampler, vTextureCoord) * uAlpha;
+}
diff --git a/src/filters/index.js b/src/filters/index.js
index 7ceb50a..dca47ab 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -25,4 +25,4 @@
export { default as BlurXFilter } from './blur/BlurXFilter';
export { default as BlurYFilter } from './blur/BlurYFilter';
export { default as ColorMatrixFilter } from './colormatrix/ColorMatrixFilter';
-export { default as VoidFilter } from './void/VoidFilter';
+export { default as AlphaFilter } from './alpha/AlphaFilter';
diff --git a/src/filters/void/VoidFilter.js b/src/filters/void/VoidFilter.js
deleted file mode 100644
index b4361ac..0000000
--- a/src/filters/void/VoidFilter.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as core from '../../core';
-import { readFileSync } from 'fs';
-import { join } from 'path';
-
-/**
- * Does nothing. Very handy.
- *
- * @class
- * @extends PIXI.Filter
- * @memberof PIXI.filters
- */
-export default class VoidFilter extends core.Filter
-{
- /**
- *
- */
- constructor()
- {
- super(
- // vertex shader
- readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
- // fragment shader
- readFileSync(join(__dirname, './void.frag'), 'utf8')
- );
-
- this.glShaderKey = 'void';
- }
-}
diff --git a/src/filters/void/void.frag b/src/filters/void/void.frag
deleted file mode 100644
index 99168fb..0000000
--- a/src/filters/void/void.frag
+++ /dev/null
@@ -1,8 +0,0 @@
-varying vec2 vTextureCoord;
-
-uniform sampler2D uSampler;
-
-void main(void)
-{
- gl_FragColor = texture2D(uSampler, vTextureCoord);
-}
diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js
index d866f03..7006a3e 100644
--- a/src/mesh/Mesh.js
+++ b/src/mesh/Mesh.js
@@ -1,5 +1,5 @@
import * as core from '../core';
-import { default as TextureTransform } from '../extras/TextureTransform';
+import Texture from '../core/textures/Texture';
const tempPoint = new core.Point();
const tempPolygon = new core.Polygon();
@@ -27,9 +27,10 @@
* The texture of the Mesh
*
* @member {PIXI.Texture}
+ * @default PIXI.Texture.EMPTY
* @private
*/
- this._texture = texture;
+ this._texture = texture || Texture.EMPTY;
/**
* The Uvs of the Mesh
@@ -129,10 +130,10 @@
* its updated independently from texture uvTransform
* updates of uvs are tied to that thing
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
* @private
*/
- this._uvTransform = new TextureTransform(texture);
+ this._uvTransform = new core.TextureMatrix(this._texture);
/**
* whether or not upload uvTransform to shader
diff --git a/src/mesh/NineSlicePlane.js b/src/mesh/NineSlicePlane.js
index 61ba5ee..f0d7575 100644
--- a/src/mesh/NineSlicePlane.js
+++ b/src/mesh/NineSlicePlane.js
@@ -172,8 +172,8 @@
const base = this._texture.baseTexture;
const textureSource = base.source;
- const w = base.width;
- const h = base.height;
+ const w = base.width * base.resolution;
+ const h = base.height * base.resolution;
this.drawSegment(context, textureSource, w, h, 0, 1, 10, 11);
this.drawSegment(context, textureSource, w, h, 2, 3, 12, 13);
diff --git a/src/mesh/Plane.js b/src/mesh/Plane.js
index 4dd2398..2aa60f9 100644
--- a/src/mesh/Plane.js
+++ b/src/mesh/Plane.js
@@ -94,6 +94,8 @@
this.uvs = new Float32Array(uvs);
this.colors = new Float32Array(colors);
this.indices = new Uint16Array(indices);
+
+ this.dirty++;
this.indexDirty++;
this.multiplyUvs();
diff --git a/test/interaction/InteractionManager.js b/test/interaction/InteractionManager.js
index 3f84d6a..136640e 100644
--- a/test/interaction/InteractionManager.js
+++ b/test/interaction/InteractionManager.js
@@ -279,13 +279,48 @@
removeSpy.restore();
});
- it('should add and remove pointer events to element', function ()
+ it('should add and remove pointer events to element seven times when touch events are supported', function ()
{
const manager = new PIXI.interaction.InteractionManager(sinon.stub());
const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
manager.interactionDOMElement = element;
manager.supportsPointerEvents = true;
+ manager.supportsTouchEvents = true;
+
+ manager.addEvents();
+
+ expect(element.addEventListener).to.have.been.callCount(7);
+ expect(element.addEventListener).to.have.been.calledWith('pointerdown');
+ expect(element.addEventListener).to.have.been.calledWith('pointerleave');
+ expect(element.addEventListener).to.have.been.calledWith('pointerover');
+
+ expect(element.addEventListener).to.have.been.calledWith('touchstart');
+ expect(element.addEventListener).to.have.been.calledWith('touchcancel');
+ expect(element.addEventListener).to.have.been.calledWith('touchend');
+ expect(element.addEventListener).to.have.been.calledWith('touchmove');
+
+ manager.removeEvents();
+
+ expect(element.removeEventListener).to.have.been.callCount(7);
+ expect(element.removeEventListener).to.have.been.calledWith('pointerdown');
+ expect(element.removeEventListener).to.have.been.calledWith('pointerleave');
+ expect(element.removeEventListener).to.have.been.calledWith('pointerover');
+
+ expect(element.removeEventListener).to.have.been.calledWith('touchstart');
+ expect(element.removeEventListener).to.have.been.calledWith('touchcancel');
+ expect(element.removeEventListener).to.have.been.calledWith('touchend');
+ expect(element.removeEventListener).to.have.been.calledWith('touchmove');
+ });
+
+ it('should add and remove pointer events to element three times when touch events are not supported', function ()
+ {
+ const manager = new PIXI.interaction.InteractionManager(sinon.stub());
+ const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
+
+ manager.interactionDOMElement = element;
+ manager.supportsPointerEvents = true;
+ manager.supportsTouchEvents = false;
manager.addEvents();
diff --git a/test/loaders/bitmapFontParser.js b/test/loaders/bitmapFontParser.js
index 7c77343..70703fc 100644
--- a/test/loaders/bitmapFontParser.js
+++ b/test/loaders/bitmapFontParser.js
@@ -1,7 +1,81 @@
'use strict';
+const path = require('path');
+const fs = require('fs');
+
describe('PIXI.loaders.bitmapFontParser', function ()
{
+ afterEach(function ()
+ {
+ for (var font in PIXI.extras.BitmapText.fonts)
+ {
+ delete PIXI.extras.BitmapText.fonts[font];
+ }
+ for (var baseTexture in PIXI.utils.BaseTextureCache)
+ {
+ delete PIXI.utils.BaseTextureCache[baseTexture];
+ }
+ for (var texture in PIXI.utils.TextureCache)
+ {
+ delete PIXI.utils.TextureCache[texture];
+ }
+ });
+
+ before(function (done)
+ {
+ const resolveURL = (url) => path.resolve(this.resources, url);
+
+ this.resources = path.join(__dirname, 'resources');
+ this.fontXML = null;
+ this.fontScaledXML = null;
+ this.fontImage = null;
+ this.fontScaledImage = null;
+ this.atlasImage = null;
+ this.atlasScaledImage = null;
+ this.atlasJSON = require(resolveURL('atlas.json')); // eslint-disable-line global-require
+ this.atlasScaledJSON = require(resolveURL('atlas@0.5x.json')); // eslint-disable-line global-require
+
+ const loadXML = (url) => new Promise((resolve) =>
+ fs.readFile(resolveURL(url), 'utf8', (err, data) =>
+ {
+ expect(err).to.be.null;
+ resolve((new window.DOMParser()).parseFromString(data, 'text/xml'));
+ }));
+
+ const loadImage = (url) => new Promise((resolve) =>
+ {
+ const image = new Image();
+
+ image.onload = () => resolve(image);
+ image.src = resolveURL(url);
+ });
+
+ Promise.all([
+ loadXML('font.fnt'),
+ loadXML('font@0.5x.fnt'),
+ loadImage('font.png'),
+ loadImage('font@0.5x.png'),
+ loadImage('atlas.png'),
+ loadImage('atlas@0.5x.png'),
+ ]).then(([
+ fontXML,
+ fontScaledXML,
+ fontImage,
+ fontScaledImage,
+ atlasImage,
+ atlasScaledImage,
+ ]) =>
+ {
+ this.fontXML = fontXML;
+ this.fontScaledXML = fontScaledXML;
+ this.fontImage = fontImage;
+ this.fontScaledImage = fontScaledImage;
+ this.atlasImage = atlasImage;
+ this.atlasScaledImage = atlasScaledImage;
+ done();
+ });
+ });
+
it('should exist and return a function', function ()
{
expect(PIXI.loaders.bitmapFontParser).to.be.a('function');
@@ -33,6 +107,206 @@
// TODO: Test the texture cache code path.
// TODO: Test the loading texture code path.
// TODO: Test data-url code paths.
+
+ it('should properly register bitmap font', function (done)
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture(this.fontImage, null, 1));
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, texture);
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charA.texture.frame.x).to.equal(2);
+ expect(charA.texture.frame.y).to.equal(2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charB.texture.frame.x).to.equal(2);
+ expect(charB.texture.frame.y).to.equal(24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charC.texture.frame.x).to.equal(23);
+ expect(charC.texture.frame.y).to.equal(2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charD.texture.frame.x).to.equal(19);
+ expect(charD.texture.frame.y).to.equal(24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+
+ it('should properly register SCALED bitmap font', function (done)
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture(this.fontScaledImage, null, 0.5));
+ const font = PIXI.extras.BitmapText.registerFont(this.fontScaledXML, texture);
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charA.texture.frame.x).to.equal(4); // 2 / 0.5
+ expect(charA.texture.frame.y).to.equal(4); // 2 / 0.5
+ expect(charA.texture.frame.width).to.equal(38); // 19 / 0.5
+ expect(charA.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charB.texture.frame.x).to.equal(4); // 2 / 0.5
+ expect(charB.texture.frame.y).to.equal(48); // 24 / 0.5
+ expect(charB.texture.frame.width).to.equal(30); // 15 / 0.5
+ expect(charB.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charC.texture.frame.x).to.equal(46); // 23 / 0.5
+ expect(charC.texture.frame.y).to.equal(4); // 2 / 0.5
+ expect(charC.texture.frame.width).to.equal(36); // 18 / 0.5
+ expect(charC.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charD.texture.frame.x).to.equal(38); // 19 / 0.5
+ expect(charD.texture.frame.y).to.equal(48); // 24 / 0.5
+ expect(charD.texture.frame.width).to.equal(34); // 17 / 0.5
+ expect(charD.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+
+ it('should properly register bitmap font NESTED into spritesheet', function (done)
+ {
+ const baseTexture = new PIXI.BaseTexture(this.atlasImage, null, 1);
+ const spritesheet = new PIXI.Spritesheet(baseTexture, this.atlasJSON);
+
+ spritesheet.parse(() =>
+ {
+ const fontTexture = PIXI.Texture.fromFrame('resources/font.png');
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, fontTexture);
+ const fontX = 158; // bare value from spritesheet frame
+ const fontY = 2; // bare value from spritesheet frame
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charA.texture.frame.x).to.equal(fontX + 2);
+ expect(charA.texture.frame.y).to.equal(fontY + 2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charB.texture.frame.x).to.equal(fontX + 2);
+ expect(charB.texture.frame.y).to.equal(fontY + 24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charC.texture.frame.x).to.equal(fontX + 23);
+ expect(charC.texture.frame.y).to.equal(fontY + 2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charD.texture.frame.x).to.equal(fontX + 19);
+ expect(charD.texture.frame.y).to.equal(fontY + 24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+ });
+
+ it('should properly register bitmap font NESTED into SCALED spritesheet', function (done)
+ {
+ const baseTexture = new PIXI.BaseTexture(this.atlasScaledImage, null, 1);
+ const spritesheet = new PIXI.Spritesheet(baseTexture, this.atlasScaledJSON);
+
+ spritesheet.parse(() =>
+ {
+ const fontTexture = PIXI.Texture.fromFrame('resources/font.png');
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, fontTexture);
+ const fontX = 158; // bare value from spritesheet frame
+ const fontY = 2; // bare value from spritesheet frame
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charA.texture.frame.x).to.equal(fontX + 2);
+ expect(charA.texture.frame.y).to.equal(fontY + 2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charB.texture.frame.x).to.equal(fontX + 2);
+ expect(charB.texture.frame.y).to.equal(fontY + 24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charC.texture.frame.x).to.equal(fontX + 23);
+ expect(charC.texture.frame.y).to.equal(fontY + 2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charD.texture.frame.x).to.equal(fontX + 19);
+ expect(charD.texture.frame.y).to.equal(fontY + 24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+ });
});
describe('PIXI.loaders.parseBitmapFontData', function ()
diff --git a/test/loaders/resources/atlas.json b/test/loaders/resources/atlas.json
new file mode 100644
index 0000000..86e65a5
--- /dev/null
+++ b/test/loaders/resources/atlas.json
@@ -0,0 +1,25 @@
+{
+ "meta": {
+ "image": "atlas.png",
+ "size": {"w":256,"h":256},
+ "scale": "1"
+ },
+ "frames": {
+ "resources/test.png":
+ {
+ "frame": {"x":2,"y":2,"w":152,"h":188},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":74,"y":36,"w":152,"h":188},
+ "sourceSize": {"w":300,"h":225}
+ },
+ "resources/font.png":
+ {
+ "frame": {"x":158,"y":2,"w":40,"h":42},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":2,"y":2,"w":40,"h":42},
+ "sourceSize": {"w":43,"h":46}
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/loaders/resources/atlas.png b/test/loaders/resources/atlas.png
new file mode 100644
index 0000000..d5e7892
--- /dev/null
+++ b/test/loaders/resources/atlas.png
Binary files differ
diff --git a/test/loaders/resources/atlas@0.5x.json b/test/loaders/resources/atlas@0.5x.json
new file mode 100644
index 0000000..ae990a1
--- /dev/null
+++ b/test/loaders/resources/atlas@0.5x.json
@@ -0,0 +1,25 @@
+{
+ "meta": {
+ "image": "atlas@0.5x.png",
+ "size": {"w":256,"h":256},
+ "scale": "1"
+ },
+ "frames": {
+ "resources/test.png":
+ {
+ "frame": {"x":2,"y":2,"w":152,"h":188},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":74,"y":36,"w":152,"h":188},
+ "sourceSize": {"w":300,"h":225}
+ },
+ "resources/font.png":
+ {
+ "frame": {"x":158,"y":2,"w":40,"h":42},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":2,"y":2,"w":40,"h":42},
+ "sourceSize": {"w":43,"h":46}
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/loaders/resources/atlas@0.5x.png b/test/loaders/resources/atlas@0.5x.png
new file mode 100644
index 0000000..d5e7892
--- /dev/null
+++ b/test/loaders/resources/atlas@0.5x.png
Binary files differ
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/extras/BitmapText.js b/src/extras/BitmapText.js
index 0592b54..96d9f44 100644
--- a/src/extras/BitmapText.js
+++ b/src/extras/BitmapText.js
@@ -1,5 +1,6 @@
import * as core from '../core';
import ObservablePoint from '../core/math/ObservablePoint';
+import { getResolutionOfUrl } from '../core/utils';
import settings from '../core/settings';
/**
@@ -510,7 +511,8 @@
const data = {};
const info = xml.getElementsByTagName('info')[0];
const common = xml.getElementsByTagName('common')[0];
- const res = texture.baseTexture.resolution || settings.RESOLUTION;
+ const fileName = xml.getElementsByTagName('page')[0].getAttribute('file');
+ const res = getResolutionOfUrl(fileName, settings.RESOLUTION);
data.font = info.getAttribute('face');
data.size = parseInt(info.getAttribute('size'), 10);
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
deleted file mode 100644
index 16536d2..0000000
--- a/src/extras/TextureTransform.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import { default as Matrix } from '../core/math/Matrix';
-
-const tempMat = new Matrix();
-
-/**
- * class controls uv transform and frame clamp for texture
- *
- * @class
- * @memberof PIXI.extras
- */
-export default class TextureTransform
-{
- /**
- *
- * @param {PIXI.Texture} texture observed texture
- * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
- * @constructor
- */
- constructor(texture, clampMargin)
- {
- this._texture = texture;
-
- this.mapCoord = new Matrix();
-
- this.uClampFrame = new Float32Array(4);
-
- this.uClampOffset = new Float32Array(2);
-
- this._lastTextureID = -1;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
- *
- * @default 0
- * @member {number}
- */
- this.clampOffset = 0;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
- *
- * @default 0.5
- * @member {number}
- */
- this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
- }
-
- /**
- * texture property
- * @member {PIXI.Texture}
- */
- get texture()
- {
- return this._texture;
- }
-
- set texture(value) // eslint-disable-line require-jsdoc
- {
- this._texture = value;
- this._lastTextureID = -1;
- }
-
- /**
- * Multiplies uvs array to transform
- * @param {Float32Array} uvs mesh uvs
- * @param {Float32Array} [out=uvs] output
- * @returns {Float32Array} output
- */
- multiplyUvs(uvs, out)
- {
- if (out === undefined)
- {
- out = uvs;
- }
-
- const mat = this.mapCoord;
-
- for (let i = 0; i < uvs.length; i += 2)
- {
- const x = uvs[i];
- const y = uvs[i + 1];
-
- out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
- out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
- }
-
- return out;
- }
-
- /**
- * updates matrices if texture was changed
- * @param {boolean} forceUpdate if true, matrices will be updated any case
- * @returns {boolean} whether or not it was updated
- */
- update(forceUpdate)
- {
- const tex = this._texture;
-
- if (!tex || !tex.valid)
- {
- return false;
- }
-
- if (!forceUpdate
- && this._lastTextureID === tex._updateID)
- {
- return false;
- }
-
- this._lastTextureID = tex._updateID;
-
- const uvs = tex._uvs;
-
- this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
-
- const orig = tex.orig;
- const trim = tex.trim;
-
- if (trim)
- {
- tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
- -trim.x / trim.width, -trim.y / trim.height);
- this.mapCoord.append(tempMat);
- }
-
- const texBase = tex.baseTexture;
- const frame = this.uClampFrame;
- const margin = this.clampMargin / texBase.resolution;
- const offset = this.clampOffset;
-
- frame[0] = (tex._frame.x + margin + offset) / texBase.width;
- frame[1] = (tex._frame.y + margin + offset) / texBase.height;
- frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
- frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
- this.uClampOffset[0] = offset / texBase.realWidth;
- this.uClampOffset[1] = offset / texBase.realHeight;
-
- return true;
- }
-}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 736b207..84c0841 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -1,6 +1,5 @@
import * as core from '../core';
import CanvasTinter from '../core/sprites/canvas/CanvasTinter';
-import { default as TextureTransform } from './TextureTransform';
const tempPoint = new core.Point();
@@ -58,9 +57,9 @@
/**
* transform that is applied to UV to get the texture coords
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
*/
- this.uvTransform = texture.transform || new TextureTransform(texture);
+ this.uvTransform = texture.transform || new core.TextureMatrix(texture);
/**
* Plugin that is responsible for rendering this element.
diff --git a/src/extras/index.js b/src/extras/index.js
index 5b98cb1..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -3,7 +3,6 @@
* @namespace PIXI.extras
*/
export { default as AnimatedSprite } from './AnimatedSprite';
-export { default as TextureTransform } from './TextureTransform';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
export { default as BitmapText } from './BitmapText';
diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js
new file mode 100644
index 0000000..c2824ed
--- /dev/null
+++ b/src/filters/alpha/AlphaFilter.js
@@ -0,0 +1,55 @@
+import * as core from '../../core';
+import { readFileSync } from 'fs';
+import { join } from 'path';
+
+/**
+ * Simplest filter - applies alpha
+ *
+ * Use this instead of Container's alpha property to avoid visual layering of individual elements.
+ * AlphaFilter applies alpha evenly across the entire display object and any opaque elements it contains.
+ * If elements are not opaque, they will blend with each other anyway.
+ *
+ * Very handy if you want to use common features of all filters:
+ *
+ * 1. Assign a blendMode to this filter, blend all elements inside display object with background.
+ *
+ * 2. To use clipping in display coordinates, assign a filterArea to the same container that has this filter.
+ *
+ * @class
+ * @extends PIXI.Filter
+ * @memberof PIXI.filters
+ */
+export default class AlphaFilter extends core.Filter
+{
+ /**
+ *
+ */
+ constructor()
+ {
+ super(
+ // vertex shader
+ readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
+ // fragment shader
+ readFileSync(join(__dirname, './alpha.frag'), 'utf8')
+ );
+
+ this.alpha = 1.0;
+ this.glShaderKey = 'alpha';
+ }
+
+ /**
+ * Coefficient for alpha multiplication
+ *
+ * @member {number}
+ * @default 1
+ */
+ get alpha()
+ {
+ return this.uniforms.uAlpha;
+ }
+
+ set alpha(value) // eslint-disable-line require-jsdoc
+ {
+ this.uniforms.uAlpha = value;
+ }
+}
diff --git a/src/filters/alpha/alpha.frag b/src/filters/alpha/alpha.frag
new file mode 100644
index 0000000..6db588c
--- /dev/null
+++ b/src/filters/alpha/alpha.frag
@@ -0,0 +1,9 @@
+varying vec2 vTextureCoord;
+
+uniform sampler2D uSampler;
+uniform float uAlpha;
+
+void main(void)
+{
+ gl_FragColor = texture2D(uSampler, vTextureCoord) * uAlpha;
+}
diff --git a/src/filters/index.js b/src/filters/index.js
index 7ceb50a..dca47ab 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -25,4 +25,4 @@
export { default as BlurXFilter } from './blur/BlurXFilter';
export { default as BlurYFilter } from './blur/BlurYFilter';
export { default as ColorMatrixFilter } from './colormatrix/ColorMatrixFilter';
-export { default as VoidFilter } from './void/VoidFilter';
+export { default as AlphaFilter } from './alpha/AlphaFilter';
diff --git a/src/filters/void/VoidFilter.js b/src/filters/void/VoidFilter.js
deleted file mode 100644
index b4361ac..0000000
--- a/src/filters/void/VoidFilter.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as core from '../../core';
-import { readFileSync } from 'fs';
-import { join } from 'path';
-
-/**
- * Does nothing. Very handy.
- *
- * @class
- * @extends PIXI.Filter
- * @memberof PIXI.filters
- */
-export default class VoidFilter extends core.Filter
-{
- /**
- *
- */
- constructor()
- {
- super(
- // vertex shader
- readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
- // fragment shader
- readFileSync(join(__dirname, './void.frag'), 'utf8')
- );
-
- this.glShaderKey = 'void';
- }
-}
diff --git a/src/filters/void/void.frag b/src/filters/void/void.frag
deleted file mode 100644
index 99168fb..0000000
--- a/src/filters/void/void.frag
+++ /dev/null
@@ -1,8 +0,0 @@
-varying vec2 vTextureCoord;
-
-uniform sampler2D uSampler;
-
-void main(void)
-{
- gl_FragColor = texture2D(uSampler, vTextureCoord);
-}
diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js
index d866f03..7006a3e 100644
--- a/src/mesh/Mesh.js
+++ b/src/mesh/Mesh.js
@@ -1,5 +1,5 @@
import * as core from '../core';
-import { default as TextureTransform } from '../extras/TextureTransform';
+import Texture from '../core/textures/Texture';
const tempPoint = new core.Point();
const tempPolygon = new core.Polygon();
@@ -27,9 +27,10 @@
* The texture of the Mesh
*
* @member {PIXI.Texture}
+ * @default PIXI.Texture.EMPTY
* @private
*/
- this._texture = texture;
+ this._texture = texture || Texture.EMPTY;
/**
* The Uvs of the Mesh
@@ -129,10 +130,10 @@
* its updated independently from texture uvTransform
* updates of uvs are tied to that thing
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
* @private
*/
- this._uvTransform = new TextureTransform(texture);
+ this._uvTransform = new core.TextureMatrix(this._texture);
/**
* whether or not upload uvTransform to shader
diff --git a/src/mesh/NineSlicePlane.js b/src/mesh/NineSlicePlane.js
index 61ba5ee..f0d7575 100644
--- a/src/mesh/NineSlicePlane.js
+++ b/src/mesh/NineSlicePlane.js
@@ -172,8 +172,8 @@
const base = this._texture.baseTexture;
const textureSource = base.source;
- const w = base.width;
- const h = base.height;
+ const w = base.width * base.resolution;
+ const h = base.height * base.resolution;
this.drawSegment(context, textureSource, w, h, 0, 1, 10, 11);
this.drawSegment(context, textureSource, w, h, 2, 3, 12, 13);
diff --git a/src/mesh/Plane.js b/src/mesh/Plane.js
index 4dd2398..2aa60f9 100644
--- a/src/mesh/Plane.js
+++ b/src/mesh/Plane.js
@@ -94,6 +94,8 @@
this.uvs = new Float32Array(uvs);
this.colors = new Float32Array(colors);
this.indices = new Uint16Array(indices);
+
+ this.dirty++;
this.indexDirty++;
this.multiplyUvs();
diff --git a/test/interaction/InteractionManager.js b/test/interaction/InteractionManager.js
index 3f84d6a..136640e 100644
--- a/test/interaction/InteractionManager.js
+++ b/test/interaction/InteractionManager.js
@@ -279,13 +279,48 @@
removeSpy.restore();
});
- it('should add and remove pointer events to element', function ()
+ it('should add and remove pointer events to element seven times when touch events are supported', function ()
{
const manager = new PIXI.interaction.InteractionManager(sinon.stub());
const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
manager.interactionDOMElement = element;
manager.supportsPointerEvents = true;
+ manager.supportsTouchEvents = true;
+
+ manager.addEvents();
+
+ expect(element.addEventListener).to.have.been.callCount(7);
+ expect(element.addEventListener).to.have.been.calledWith('pointerdown');
+ expect(element.addEventListener).to.have.been.calledWith('pointerleave');
+ expect(element.addEventListener).to.have.been.calledWith('pointerover');
+
+ expect(element.addEventListener).to.have.been.calledWith('touchstart');
+ expect(element.addEventListener).to.have.been.calledWith('touchcancel');
+ expect(element.addEventListener).to.have.been.calledWith('touchend');
+ expect(element.addEventListener).to.have.been.calledWith('touchmove');
+
+ manager.removeEvents();
+
+ expect(element.removeEventListener).to.have.been.callCount(7);
+ expect(element.removeEventListener).to.have.been.calledWith('pointerdown');
+ expect(element.removeEventListener).to.have.been.calledWith('pointerleave');
+ expect(element.removeEventListener).to.have.been.calledWith('pointerover');
+
+ expect(element.removeEventListener).to.have.been.calledWith('touchstart');
+ expect(element.removeEventListener).to.have.been.calledWith('touchcancel');
+ expect(element.removeEventListener).to.have.been.calledWith('touchend');
+ expect(element.removeEventListener).to.have.been.calledWith('touchmove');
+ });
+
+ it('should add and remove pointer events to element three times when touch events are not supported', function ()
+ {
+ const manager = new PIXI.interaction.InteractionManager(sinon.stub());
+ const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
+
+ manager.interactionDOMElement = element;
+ manager.supportsPointerEvents = true;
+ manager.supportsTouchEvents = false;
manager.addEvents();
diff --git a/test/loaders/bitmapFontParser.js b/test/loaders/bitmapFontParser.js
index 7c77343..70703fc 100644
--- a/test/loaders/bitmapFontParser.js
+++ b/test/loaders/bitmapFontParser.js
@@ -1,7 +1,81 @@
'use strict';
+const path = require('path');
+const fs = require('fs');
+
describe('PIXI.loaders.bitmapFontParser', function ()
{
+ afterEach(function ()
+ {
+ for (var font in PIXI.extras.BitmapText.fonts)
+ {
+ delete PIXI.extras.BitmapText.fonts[font];
+ }
+ for (var baseTexture in PIXI.utils.BaseTextureCache)
+ {
+ delete PIXI.utils.BaseTextureCache[baseTexture];
+ }
+ for (var texture in PIXI.utils.TextureCache)
+ {
+ delete PIXI.utils.TextureCache[texture];
+ }
+ });
+
+ before(function (done)
+ {
+ const resolveURL = (url) => path.resolve(this.resources, url);
+
+ this.resources = path.join(__dirname, 'resources');
+ this.fontXML = null;
+ this.fontScaledXML = null;
+ this.fontImage = null;
+ this.fontScaledImage = null;
+ this.atlasImage = null;
+ this.atlasScaledImage = null;
+ this.atlasJSON = require(resolveURL('atlas.json')); // eslint-disable-line global-require
+ this.atlasScaledJSON = require(resolveURL('atlas@0.5x.json')); // eslint-disable-line global-require
+
+ const loadXML = (url) => new Promise((resolve) =>
+ fs.readFile(resolveURL(url), 'utf8', (err, data) =>
+ {
+ expect(err).to.be.null;
+ resolve((new window.DOMParser()).parseFromString(data, 'text/xml'));
+ }));
+
+ const loadImage = (url) => new Promise((resolve) =>
+ {
+ const image = new Image();
+
+ image.onload = () => resolve(image);
+ image.src = resolveURL(url);
+ });
+
+ Promise.all([
+ loadXML('font.fnt'),
+ loadXML('font@0.5x.fnt'),
+ loadImage('font.png'),
+ loadImage('font@0.5x.png'),
+ loadImage('atlas.png'),
+ loadImage('atlas@0.5x.png'),
+ ]).then(([
+ fontXML,
+ fontScaledXML,
+ fontImage,
+ fontScaledImage,
+ atlasImage,
+ atlasScaledImage,
+ ]) =>
+ {
+ this.fontXML = fontXML;
+ this.fontScaledXML = fontScaledXML;
+ this.fontImage = fontImage;
+ this.fontScaledImage = fontScaledImage;
+ this.atlasImage = atlasImage;
+ this.atlasScaledImage = atlasScaledImage;
+ done();
+ });
+ });
+
it('should exist and return a function', function ()
{
expect(PIXI.loaders.bitmapFontParser).to.be.a('function');
@@ -33,6 +107,206 @@
// TODO: Test the texture cache code path.
// TODO: Test the loading texture code path.
// TODO: Test data-url code paths.
+
+ it('should properly register bitmap font', function (done)
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture(this.fontImage, null, 1));
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, texture);
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charA.texture.frame.x).to.equal(2);
+ expect(charA.texture.frame.y).to.equal(2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charB.texture.frame.x).to.equal(2);
+ expect(charB.texture.frame.y).to.equal(24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charC.texture.frame.x).to.equal(23);
+ expect(charC.texture.frame.y).to.equal(2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charD.texture.frame.x).to.equal(19);
+ expect(charD.texture.frame.y).to.equal(24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+
+ it('should properly register SCALED bitmap font', function (done)
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture(this.fontScaledImage, null, 0.5));
+ const font = PIXI.extras.BitmapText.registerFont(this.fontScaledXML, texture);
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charA.texture.frame.x).to.equal(4); // 2 / 0.5
+ expect(charA.texture.frame.y).to.equal(4); // 2 / 0.5
+ expect(charA.texture.frame.width).to.equal(38); // 19 / 0.5
+ expect(charA.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charB.texture.frame.x).to.equal(4); // 2 / 0.5
+ expect(charB.texture.frame.y).to.equal(48); // 24 / 0.5
+ expect(charB.texture.frame.width).to.equal(30); // 15 / 0.5
+ expect(charB.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charC.texture.frame.x).to.equal(46); // 23 / 0.5
+ expect(charC.texture.frame.y).to.equal(4); // 2 / 0.5
+ expect(charC.texture.frame.width).to.equal(36); // 18 / 0.5
+ expect(charC.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charD.texture.frame.x).to.equal(38); // 19 / 0.5
+ expect(charD.texture.frame.y).to.equal(48); // 24 / 0.5
+ expect(charD.texture.frame.width).to.equal(34); // 17 / 0.5
+ expect(charD.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+
+ it('should properly register bitmap font NESTED into spritesheet', function (done)
+ {
+ const baseTexture = new PIXI.BaseTexture(this.atlasImage, null, 1);
+ const spritesheet = new PIXI.Spritesheet(baseTexture, this.atlasJSON);
+
+ spritesheet.parse(() =>
+ {
+ const fontTexture = PIXI.Texture.fromFrame('resources/font.png');
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, fontTexture);
+ const fontX = 158; // bare value from spritesheet frame
+ const fontY = 2; // bare value from spritesheet frame
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charA.texture.frame.x).to.equal(fontX + 2);
+ expect(charA.texture.frame.y).to.equal(fontY + 2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charB.texture.frame.x).to.equal(fontX + 2);
+ expect(charB.texture.frame.y).to.equal(fontY + 24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charC.texture.frame.x).to.equal(fontX + 23);
+ expect(charC.texture.frame.y).to.equal(fontY + 2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charD.texture.frame.x).to.equal(fontX + 19);
+ expect(charD.texture.frame.y).to.equal(fontY + 24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+ });
+
+ it('should properly register bitmap font NESTED into SCALED spritesheet', function (done)
+ {
+ const baseTexture = new PIXI.BaseTexture(this.atlasScaledImage, null, 1);
+ const spritesheet = new PIXI.Spritesheet(baseTexture, this.atlasScaledJSON);
+
+ spritesheet.parse(() =>
+ {
+ const fontTexture = PIXI.Texture.fromFrame('resources/font.png');
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, fontTexture);
+ const fontX = 158; // bare value from spritesheet frame
+ const fontY = 2; // bare value from spritesheet frame
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charA.texture.frame.x).to.equal(fontX + 2);
+ expect(charA.texture.frame.y).to.equal(fontY + 2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charB.texture.frame.x).to.equal(fontX + 2);
+ expect(charB.texture.frame.y).to.equal(fontY + 24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charC.texture.frame.x).to.equal(fontX + 23);
+ expect(charC.texture.frame.y).to.equal(fontY + 2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charD.texture.frame.x).to.equal(fontX + 19);
+ expect(charD.texture.frame.y).to.equal(fontY + 24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+ });
});
describe('PIXI.loaders.parseBitmapFontData', function ()
diff --git a/test/loaders/resources/atlas.json b/test/loaders/resources/atlas.json
new file mode 100644
index 0000000..86e65a5
--- /dev/null
+++ b/test/loaders/resources/atlas.json
@@ -0,0 +1,25 @@
+{
+ "meta": {
+ "image": "atlas.png",
+ "size": {"w":256,"h":256},
+ "scale": "1"
+ },
+ "frames": {
+ "resources/test.png":
+ {
+ "frame": {"x":2,"y":2,"w":152,"h":188},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":74,"y":36,"w":152,"h":188},
+ "sourceSize": {"w":300,"h":225}
+ },
+ "resources/font.png":
+ {
+ "frame": {"x":158,"y":2,"w":40,"h":42},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":2,"y":2,"w":40,"h":42},
+ "sourceSize": {"w":43,"h":46}
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/loaders/resources/atlas.png b/test/loaders/resources/atlas.png
new file mode 100644
index 0000000..d5e7892
--- /dev/null
+++ b/test/loaders/resources/atlas.png
Binary files differ
diff --git a/test/loaders/resources/atlas@0.5x.json b/test/loaders/resources/atlas@0.5x.json
new file mode 100644
index 0000000..ae990a1
--- /dev/null
+++ b/test/loaders/resources/atlas@0.5x.json
@@ -0,0 +1,25 @@
+{
+ "meta": {
+ "image": "atlas@0.5x.png",
+ "size": {"w":256,"h":256},
+ "scale": "1"
+ },
+ "frames": {
+ "resources/test.png":
+ {
+ "frame": {"x":2,"y":2,"w":152,"h":188},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":74,"y":36,"w":152,"h":188},
+ "sourceSize": {"w":300,"h":225}
+ },
+ "resources/font.png":
+ {
+ "frame": {"x":158,"y":2,"w":40,"h":42},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":2,"y":2,"w":40,"h":42},
+ "sourceSize": {"w":43,"h":46}
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/loaders/resources/atlas@0.5x.png b/test/loaders/resources/atlas@0.5x.png
new file mode 100644
index 0000000..d5e7892
--- /dev/null
+++ b/test/loaders/resources/atlas@0.5x.png
Binary files differ
diff --git a/test/loaders/resources/font.fnt b/test/loaders/resources/font.fnt
new file mode 100644
index 0000000..56e1060
--- /dev/null
+++ b/test/loaders/resources/font.fnt
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/extras/BitmapText.js b/src/extras/BitmapText.js
index 0592b54..96d9f44 100644
--- a/src/extras/BitmapText.js
+++ b/src/extras/BitmapText.js
@@ -1,5 +1,6 @@
import * as core from '../core';
import ObservablePoint from '../core/math/ObservablePoint';
+import { getResolutionOfUrl } from '../core/utils';
import settings from '../core/settings';
/**
@@ -510,7 +511,8 @@
const data = {};
const info = xml.getElementsByTagName('info')[0];
const common = xml.getElementsByTagName('common')[0];
- const res = texture.baseTexture.resolution || settings.RESOLUTION;
+ const fileName = xml.getElementsByTagName('page')[0].getAttribute('file');
+ const res = getResolutionOfUrl(fileName, settings.RESOLUTION);
data.font = info.getAttribute('face');
data.size = parseInt(info.getAttribute('size'), 10);
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
deleted file mode 100644
index 16536d2..0000000
--- a/src/extras/TextureTransform.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import { default as Matrix } from '../core/math/Matrix';
-
-const tempMat = new Matrix();
-
-/**
- * class controls uv transform and frame clamp for texture
- *
- * @class
- * @memberof PIXI.extras
- */
-export default class TextureTransform
-{
- /**
- *
- * @param {PIXI.Texture} texture observed texture
- * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
- * @constructor
- */
- constructor(texture, clampMargin)
- {
- this._texture = texture;
-
- this.mapCoord = new Matrix();
-
- this.uClampFrame = new Float32Array(4);
-
- this.uClampOffset = new Float32Array(2);
-
- this._lastTextureID = -1;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
- *
- * @default 0
- * @member {number}
- */
- this.clampOffset = 0;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
- *
- * @default 0.5
- * @member {number}
- */
- this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
- }
-
- /**
- * texture property
- * @member {PIXI.Texture}
- */
- get texture()
- {
- return this._texture;
- }
-
- set texture(value) // eslint-disable-line require-jsdoc
- {
- this._texture = value;
- this._lastTextureID = -1;
- }
-
- /**
- * Multiplies uvs array to transform
- * @param {Float32Array} uvs mesh uvs
- * @param {Float32Array} [out=uvs] output
- * @returns {Float32Array} output
- */
- multiplyUvs(uvs, out)
- {
- if (out === undefined)
- {
- out = uvs;
- }
-
- const mat = this.mapCoord;
-
- for (let i = 0; i < uvs.length; i += 2)
- {
- const x = uvs[i];
- const y = uvs[i + 1];
-
- out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
- out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
- }
-
- return out;
- }
-
- /**
- * updates matrices if texture was changed
- * @param {boolean} forceUpdate if true, matrices will be updated any case
- * @returns {boolean} whether or not it was updated
- */
- update(forceUpdate)
- {
- const tex = this._texture;
-
- if (!tex || !tex.valid)
- {
- return false;
- }
-
- if (!forceUpdate
- && this._lastTextureID === tex._updateID)
- {
- return false;
- }
-
- this._lastTextureID = tex._updateID;
-
- const uvs = tex._uvs;
-
- this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
-
- const orig = tex.orig;
- const trim = tex.trim;
-
- if (trim)
- {
- tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
- -trim.x / trim.width, -trim.y / trim.height);
- this.mapCoord.append(tempMat);
- }
-
- const texBase = tex.baseTexture;
- const frame = this.uClampFrame;
- const margin = this.clampMargin / texBase.resolution;
- const offset = this.clampOffset;
-
- frame[0] = (tex._frame.x + margin + offset) / texBase.width;
- frame[1] = (tex._frame.y + margin + offset) / texBase.height;
- frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
- frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
- this.uClampOffset[0] = offset / texBase.realWidth;
- this.uClampOffset[1] = offset / texBase.realHeight;
-
- return true;
- }
-}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 736b207..84c0841 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -1,6 +1,5 @@
import * as core from '../core';
import CanvasTinter from '../core/sprites/canvas/CanvasTinter';
-import { default as TextureTransform } from './TextureTransform';
const tempPoint = new core.Point();
@@ -58,9 +57,9 @@
/**
* transform that is applied to UV to get the texture coords
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
*/
- this.uvTransform = texture.transform || new TextureTransform(texture);
+ this.uvTransform = texture.transform || new core.TextureMatrix(texture);
/**
* Plugin that is responsible for rendering this element.
diff --git a/src/extras/index.js b/src/extras/index.js
index 5b98cb1..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -3,7 +3,6 @@
* @namespace PIXI.extras
*/
export { default as AnimatedSprite } from './AnimatedSprite';
-export { default as TextureTransform } from './TextureTransform';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
export { default as BitmapText } from './BitmapText';
diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js
new file mode 100644
index 0000000..c2824ed
--- /dev/null
+++ b/src/filters/alpha/AlphaFilter.js
@@ -0,0 +1,55 @@
+import * as core from '../../core';
+import { readFileSync } from 'fs';
+import { join } from 'path';
+
+/**
+ * Simplest filter - applies alpha
+ *
+ * Use this instead of Container's alpha property to avoid visual layering of individual elements.
+ * AlphaFilter applies alpha evenly across the entire display object and any opaque elements it contains.
+ * If elements are not opaque, they will blend with each other anyway.
+ *
+ * Very handy if you want to use common features of all filters:
+ *
+ * 1. Assign a blendMode to this filter, blend all elements inside display object with background.
+ *
+ * 2. To use clipping in display coordinates, assign a filterArea to the same container that has this filter.
+ *
+ * @class
+ * @extends PIXI.Filter
+ * @memberof PIXI.filters
+ */
+export default class AlphaFilter extends core.Filter
+{
+ /**
+ *
+ */
+ constructor()
+ {
+ super(
+ // vertex shader
+ readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
+ // fragment shader
+ readFileSync(join(__dirname, './alpha.frag'), 'utf8')
+ );
+
+ this.alpha = 1.0;
+ this.glShaderKey = 'alpha';
+ }
+
+ /**
+ * Coefficient for alpha multiplication
+ *
+ * @member {number}
+ * @default 1
+ */
+ get alpha()
+ {
+ return this.uniforms.uAlpha;
+ }
+
+ set alpha(value) // eslint-disable-line require-jsdoc
+ {
+ this.uniforms.uAlpha = value;
+ }
+}
diff --git a/src/filters/alpha/alpha.frag b/src/filters/alpha/alpha.frag
new file mode 100644
index 0000000..6db588c
--- /dev/null
+++ b/src/filters/alpha/alpha.frag
@@ -0,0 +1,9 @@
+varying vec2 vTextureCoord;
+
+uniform sampler2D uSampler;
+uniform float uAlpha;
+
+void main(void)
+{
+ gl_FragColor = texture2D(uSampler, vTextureCoord) * uAlpha;
+}
diff --git a/src/filters/index.js b/src/filters/index.js
index 7ceb50a..dca47ab 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -25,4 +25,4 @@
export { default as BlurXFilter } from './blur/BlurXFilter';
export { default as BlurYFilter } from './blur/BlurYFilter';
export { default as ColorMatrixFilter } from './colormatrix/ColorMatrixFilter';
-export { default as VoidFilter } from './void/VoidFilter';
+export { default as AlphaFilter } from './alpha/AlphaFilter';
diff --git a/src/filters/void/VoidFilter.js b/src/filters/void/VoidFilter.js
deleted file mode 100644
index b4361ac..0000000
--- a/src/filters/void/VoidFilter.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as core from '../../core';
-import { readFileSync } from 'fs';
-import { join } from 'path';
-
-/**
- * Does nothing. Very handy.
- *
- * @class
- * @extends PIXI.Filter
- * @memberof PIXI.filters
- */
-export default class VoidFilter extends core.Filter
-{
- /**
- *
- */
- constructor()
- {
- super(
- // vertex shader
- readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
- // fragment shader
- readFileSync(join(__dirname, './void.frag'), 'utf8')
- );
-
- this.glShaderKey = 'void';
- }
-}
diff --git a/src/filters/void/void.frag b/src/filters/void/void.frag
deleted file mode 100644
index 99168fb..0000000
--- a/src/filters/void/void.frag
+++ /dev/null
@@ -1,8 +0,0 @@
-varying vec2 vTextureCoord;
-
-uniform sampler2D uSampler;
-
-void main(void)
-{
- gl_FragColor = texture2D(uSampler, vTextureCoord);
-}
diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js
index d866f03..7006a3e 100644
--- a/src/mesh/Mesh.js
+++ b/src/mesh/Mesh.js
@@ -1,5 +1,5 @@
import * as core from '../core';
-import { default as TextureTransform } from '../extras/TextureTransform';
+import Texture from '../core/textures/Texture';
const tempPoint = new core.Point();
const tempPolygon = new core.Polygon();
@@ -27,9 +27,10 @@
* The texture of the Mesh
*
* @member {PIXI.Texture}
+ * @default PIXI.Texture.EMPTY
* @private
*/
- this._texture = texture;
+ this._texture = texture || Texture.EMPTY;
/**
* The Uvs of the Mesh
@@ -129,10 +130,10 @@
* its updated independently from texture uvTransform
* updates of uvs are tied to that thing
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
* @private
*/
- this._uvTransform = new TextureTransform(texture);
+ this._uvTransform = new core.TextureMatrix(this._texture);
/**
* whether or not upload uvTransform to shader
diff --git a/src/mesh/NineSlicePlane.js b/src/mesh/NineSlicePlane.js
index 61ba5ee..f0d7575 100644
--- a/src/mesh/NineSlicePlane.js
+++ b/src/mesh/NineSlicePlane.js
@@ -172,8 +172,8 @@
const base = this._texture.baseTexture;
const textureSource = base.source;
- const w = base.width;
- const h = base.height;
+ const w = base.width * base.resolution;
+ const h = base.height * base.resolution;
this.drawSegment(context, textureSource, w, h, 0, 1, 10, 11);
this.drawSegment(context, textureSource, w, h, 2, 3, 12, 13);
diff --git a/src/mesh/Plane.js b/src/mesh/Plane.js
index 4dd2398..2aa60f9 100644
--- a/src/mesh/Plane.js
+++ b/src/mesh/Plane.js
@@ -94,6 +94,8 @@
this.uvs = new Float32Array(uvs);
this.colors = new Float32Array(colors);
this.indices = new Uint16Array(indices);
+
+ this.dirty++;
this.indexDirty++;
this.multiplyUvs();
diff --git a/test/interaction/InteractionManager.js b/test/interaction/InteractionManager.js
index 3f84d6a..136640e 100644
--- a/test/interaction/InteractionManager.js
+++ b/test/interaction/InteractionManager.js
@@ -279,13 +279,48 @@
removeSpy.restore();
});
- it('should add and remove pointer events to element', function ()
+ it('should add and remove pointer events to element seven times when touch events are supported', function ()
{
const manager = new PIXI.interaction.InteractionManager(sinon.stub());
const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
manager.interactionDOMElement = element;
manager.supportsPointerEvents = true;
+ manager.supportsTouchEvents = true;
+
+ manager.addEvents();
+
+ expect(element.addEventListener).to.have.been.callCount(7);
+ expect(element.addEventListener).to.have.been.calledWith('pointerdown');
+ expect(element.addEventListener).to.have.been.calledWith('pointerleave');
+ expect(element.addEventListener).to.have.been.calledWith('pointerover');
+
+ expect(element.addEventListener).to.have.been.calledWith('touchstart');
+ expect(element.addEventListener).to.have.been.calledWith('touchcancel');
+ expect(element.addEventListener).to.have.been.calledWith('touchend');
+ expect(element.addEventListener).to.have.been.calledWith('touchmove');
+
+ manager.removeEvents();
+
+ expect(element.removeEventListener).to.have.been.callCount(7);
+ expect(element.removeEventListener).to.have.been.calledWith('pointerdown');
+ expect(element.removeEventListener).to.have.been.calledWith('pointerleave');
+ expect(element.removeEventListener).to.have.been.calledWith('pointerover');
+
+ expect(element.removeEventListener).to.have.been.calledWith('touchstart');
+ expect(element.removeEventListener).to.have.been.calledWith('touchcancel');
+ expect(element.removeEventListener).to.have.been.calledWith('touchend');
+ expect(element.removeEventListener).to.have.been.calledWith('touchmove');
+ });
+
+ it('should add and remove pointer events to element three times when touch events are not supported', function ()
+ {
+ const manager = new PIXI.interaction.InteractionManager(sinon.stub());
+ const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
+
+ manager.interactionDOMElement = element;
+ manager.supportsPointerEvents = true;
+ manager.supportsTouchEvents = false;
manager.addEvents();
diff --git a/test/loaders/bitmapFontParser.js b/test/loaders/bitmapFontParser.js
index 7c77343..70703fc 100644
--- a/test/loaders/bitmapFontParser.js
+++ b/test/loaders/bitmapFontParser.js
@@ -1,7 +1,81 @@
'use strict';
+const path = require('path');
+const fs = require('fs');
+
describe('PIXI.loaders.bitmapFontParser', function ()
{
+ afterEach(function ()
+ {
+ for (var font in PIXI.extras.BitmapText.fonts)
+ {
+ delete PIXI.extras.BitmapText.fonts[font];
+ }
+ for (var baseTexture in PIXI.utils.BaseTextureCache)
+ {
+ delete PIXI.utils.BaseTextureCache[baseTexture];
+ }
+ for (var texture in PIXI.utils.TextureCache)
+ {
+ delete PIXI.utils.TextureCache[texture];
+ }
+ });
+
+ before(function (done)
+ {
+ const resolveURL = (url) => path.resolve(this.resources, url);
+
+ this.resources = path.join(__dirname, 'resources');
+ this.fontXML = null;
+ this.fontScaledXML = null;
+ this.fontImage = null;
+ this.fontScaledImage = null;
+ this.atlasImage = null;
+ this.atlasScaledImage = null;
+ this.atlasJSON = require(resolveURL('atlas.json')); // eslint-disable-line global-require
+ this.atlasScaledJSON = require(resolveURL('atlas@0.5x.json')); // eslint-disable-line global-require
+
+ const loadXML = (url) => new Promise((resolve) =>
+ fs.readFile(resolveURL(url), 'utf8', (err, data) =>
+ {
+ expect(err).to.be.null;
+ resolve((new window.DOMParser()).parseFromString(data, 'text/xml'));
+ }));
+
+ const loadImage = (url) => new Promise((resolve) =>
+ {
+ const image = new Image();
+
+ image.onload = () => resolve(image);
+ image.src = resolveURL(url);
+ });
+
+ Promise.all([
+ loadXML('font.fnt'),
+ loadXML('font@0.5x.fnt'),
+ loadImage('font.png'),
+ loadImage('font@0.5x.png'),
+ loadImage('atlas.png'),
+ loadImage('atlas@0.5x.png'),
+ ]).then(([
+ fontXML,
+ fontScaledXML,
+ fontImage,
+ fontScaledImage,
+ atlasImage,
+ atlasScaledImage,
+ ]) =>
+ {
+ this.fontXML = fontXML;
+ this.fontScaledXML = fontScaledXML;
+ this.fontImage = fontImage;
+ this.fontScaledImage = fontScaledImage;
+ this.atlasImage = atlasImage;
+ this.atlasScaledImage = atlasScaledImage;
+ done();
+ });
+ });
+
it('should exist and return a function', function ()
{
expect(PIXI.loaders.bitmapFontParser).to.be.a('function');
@@ -33,6 +107,206 @@
// TODO: Test the texture cache code path.
// TODO: Test the loading texture code path.
// TODO: Test data-url code paths.
+
+ it('should properly register bitmap font', function (done)
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture(this.fontImage, null, 1));
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, texture);
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charA.texture.frame.x).to.equal(2);
+ expect(charA.texture.frame.y).to.equal(2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charB.texture.frame.x).to.equal(2);
+ expect(charB.texture.frame.y).to.equal(24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charC.texture.frame.x).to.equal(23);
+ expect(charC.texture.frame.y).to.equal(2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charD.texture.frame.x).to.equal(19);
+ expect(charD.texture.frame.y).to.equal(24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+
+ it('should properly register SCALED bitmap font', function (done)
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture(this.fontScaledImage, null, 0.5));
+ const font = PIXI.extras.BitmapText.registerFont(this.fontScaledXML, texture);
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charA.texture.frame.x).to.equal(4); // 2 / 0.5
+ expect(charA.texture.frame.y).to.equal(4); // 2 / 0.5
+ expect(charA.texture.frame.width).to.equal(38); // 19 / 0.5
+ expect(charA.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charB.texture.frame.x).to.equal(4); // 2 / 0.5
+ expect(charB.texture.frame.y).to.equal(48); // 24 / 0.5
+ expect(charB.texture.frame.width).to.equal(30); // 15 / 0.5
+ expect(charB.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charC.texture.frame.x).to.equal(46); // 23 / 0.5
+ expect(charC.texture.frame.y).to.equal(4); // 2 / 0.5
+ expect(charC.texture.frame.width).to.equal(36); // 18 / 0.5
+ expect(charC.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charD.texture.frame.x).to.equal(38); // 19 / 0.5
+ expect(charD.texture.frame.y).to.equal(48); // 24 / 0.5
+ expect(charD.texture.frame.width).to.equal(34); // 17 / 0.5
+ expect(charD.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+
+ it('should properly register bitmap font NESTED into spritesheet', function (done)
+ {
+ const baseTexture = new PIXI.BaseTexture(this.atlasImage, null, 1);
+ const spritesheet = new PIXI.Spritesheet(baseTexture, this.atlasJSON);
+
+ spritesheet.parse(() =>
+ {
+ const fontTexture = PIXI.Texture.fromFrame('resources/font.png');
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, fontTexture);
+ const fontX = 158; // bare value from spritesheet frame
+ const fontY = 2; // bare value from spritesheet frame
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charA.texture.frame.x).to.equal(fontX + 2);
+ expect(charA.texture.frame.y).to.equal(fontY + 2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charB.texture.frame.x).to.equal(fontX + 2);
+ expect(charB.texture.frame.y).to.equal(fontY + 24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charC.texture.frame.x).to.equal(fontX + 23);
+ expect(charC.texture.frame.y).to.equal(fontY + 2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charD.texture.frame.x).to.equal(fontX + 19);
+ expect(charD.texture.frame.y).to.equal(fontY + 24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+ });
+
+ it('should properly register bitmap font NESTED into SCALED spritesheet', function (done)
+ {
+ const baseTexture = new PIXI.BaseTexture(this.atlasScaledImage, null, 1);
+ const spritesheet = new PIXI.Spritesheet(baseTexture, this.atlasScaledJSON);
+
+ spritesheet.parse(() =>
+ {
+ const fontTexture = PIXI.Texture.fromFrame('resources/font.png');
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, fontTexture);
+ const fontX = 158; // bare value from spritesheet frame
+ const fontY = 2; // bare value from spritesheet frame
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charA.texture.frame.x).to.equal(fontX + 2);
+ expect(charA.texture.frame.y).to.equal(fontY + 2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charB.texture.frame.x).to.equal(fontX + 2);
+ expect(charB.texture.frame.y).to.equal(fontY + 24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charC.texture.frame.x).to.equal(fontX + 23);
+ expect(charC.texture.frame.y).to.equal(fontY + 2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charD.texture.frame.x).to.equal(fontX + 19);
+ expect(charD.texture.frame.y).to.equal(fontY + 24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+ });
});
describe('PIXI.loaders.parseBitmapFontData', function ()
diff --git a/test/loaders/resources/atlas.json b/test/loaders/resources/atlas.json
new file mode 100644
index 0000000..86e65a5
--- /dev/null
+++ b/test/loaders/resources/atlas.json
@@ -0,0 +1,25 @@
+{
+ "meta": {
+ "image": "atlas.png",
+ "size": {"w":256,"h":256},
+ "scale": "1"
+ },
+ "frames": {
+ "resources/test.png":
+ {
+ "frame": {"x":2,"y":2,"w":152,"h":188},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":74,"y":36,"w":152,"h":188},
+ "sourceSize": {"w":300,"h":225}
+ },
+ "resources/font.png":
+ {
+ "frame": {"x":158,"y":2,"w":40,"h":42},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":2,"y":2,"w":40,"h":42},
+ "sourceSize": {"w":43,"h":46}
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/loaders/resources/atlas.png b/test/loaders/resources/atlas.png
new file mode 100644
index 0000000..d5e7892
--- /dev/null
+++ b/test/loaders/resources/atlas.png
Binary files differ
diff --git a/test/loaders/resources/atlas@0.5x.json b/test/loaders/resources/atlas@0.5x.json
new file mode 100644
index 0000000..ae990a1
--- /dev/null
+++ b/test/loaders/resources/atlas@0.5x.json
@@ -0,0 +1,25 @@
+{
+ "meta": {
+ "image": "atlas@0.5x.png",
+ "size": {"w":256,"h":256},
+ "scale": "1"
+ },
+ "frames": {
+ "resources/test.png":
+ {
+ "frame": {"x":2,"y":2,"w":152,"h":188},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":74,"y":36,"w":152,"h":188},
+ "sourceSize": {"w":300,"h":225}
+ },
+ "resources/font.png":
+ {
+ "frame": {"x":158,"y":2,"w":40,"h":42},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":2,"y":2,"w":40,"h":42},
+ "sourceSize": {"w":43,"h":46}
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/loaders/resources/atlas@0.5x.png b/test/loaders/resources/atlas@0.5x.png
new file mode 100644
index 0000000..d5e7892
--- /dev/null
+++ b/test/loaders/resources/atlas@0.5x.png
Binary files differ
diff --git a/test/loaders/resources/font.fnt b/test/loaders/resources/font.fnt
new file mode 100644
index 0000000..56e1060
--- /dev/null
+++ b/test/loaders/resources/font.fnt
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/loaders/resources/font.png b/test/loaders/resources/font.png
new file mode 100644
index 0000000..cf772e9
--- /dev/null
+++ b/test/loaders/resources/font.png
Binary files differ
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/extras/BitmapText.js b/src/extras/BitmapText.js
index 0592b54..96d9f44 100644
--- a/src/extras/BitmapText.js
+++ b/src/extras/BitmapText.js
@@ -1,5 +1,6 @@
import * as core from '../core';
import ObservablePoint from '../core/math/ObservablePoint';
+import { getResolutionOfUrl } from '../core/utils';
import settings from '../core/settings';
/**
@@ -510,7 +511,8 @@
const data = {};
const info = xml.getElementsByTagName('info')[0];
const common = xml.getElementsByTagName('common')[0];
- const res = texture.baseTexture.resolution || settings.RESOLUTION;
+ const fileName = xml.getElementsByTagName('page')[0].getAttribute('file');
+ const res = getResolutionOfUrl(fileName, settings.RESOLUTION);
data.font = info.getAttribute('face');
data.size = parseInt(info.getAttribute('size'), 10);
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
deleted file mode 100644
index 16536d2..0000000
--- a/src/extras/TextureTransform.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import { default as Matrix } from '../core/math/Matrix';
-
-const tempMat = new Matrix();
-
-/**
- * class controls uv transform and frame clamp for texture
- *
- * @class
- * @memberof PIXI.extras
- */
-export default class TextureTransform
-{
- /**
- *
- * @param {PIXI.Texture} texture observed texture
- * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
- * @constructor
- */
- constructor(texture, clampMargin)
- {
- this._texture = texture;
-
- this.mapCoord = new Matrix();
-
- this.uClampFrame = new Float32Array(4);
-
- this.uClampOffset = new Float32Array(2);
-
- this._lastTextureID = -1;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
- *
- * @default 0
- * @member {number}
- */
- this.clampOffset = 0;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
- *
- * @default 0.5
- * @member {number}
- */
- this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
- }
-
- /**
- * texture property
- * @member {PIXI.Texture}
- */
- get texture()
- {
- return this._texture;
- }
-
- set texture(value) // eslint-disable-line require-jsdoc
- {
- this._texture = value;
- this._lastTextureID = -1;
- }
-
- /**
- * Multiplies uvs array to transform
- * @param {Float32Array} uvs mesh uvs
- * @param {Float32Array} [out=uvs] output
- * @returns {Float32Array} output
- */
- multiplyUvs(uvs, out)
- {
- if (out === undefined)
- {
- out = uvs;
- }
-
- const mat = this.mapCoord;
-
- for (let i = 0; i < uvs.length; i += 2)
- {
- const x = uvs[i];
- const y = uvs[i + 1];
-
- out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
- out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
- }
-
- return out;
- }
-
- /**
- * updates matrices if texture was changed
- * @param {boolean} forceUpdate if true, matrices will be updated any case
- * @returns {boolean} whether or not it was updated
- */
- update(forceUpdate)
- {
- const tex = this._texture;
-
- if (!tex || !tex.valid)
- {
- return false;
- }
-
- if (!forceUpdate
- && this._lastTextureID === tex._updateID)
- {
- return false;
- }
-
- this._lastTextureID = tex._updateID;
-
- const uvs = tex._uvs;
-
- this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
-
- const orig = tex.orig;
- const trim = tex.trim;
-
- if (trim)
- {
- tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
- -trim.x / trim.width, -trim.y / trim.height);
- this.mapCoord.append(tempMat);
- }
-
- const texBase = tex.baseTexture;
- const frame = this.uClampFrame;
- const margin = this.clampMargin / texBase.resolution;
- const offset = this.clampOffset;
-
- frame[0] = (tex._frame.x + margin + offset) / texBase.width;
- frame[1] = (tex._frame.y + margin + offset) / texBase.height;
- frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
- frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
- this.uClampOffset[0] = offset / texBase.realWidth;
- this.uClampOffset[1] = offset / texBase.realHeight;
-
- return true;
- }
-}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 736b207..84c0841 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -1,6 +1,5 @@
import * as core from '../core';
import CanvasTinter from '../core/sprites/canvas/CanvasTinter';
-import { default as TextureTransform } from './TextureTransform';
const tempPoint = new core.Point();
@@ -58,9 +57,9 @@
/**
* transform that is applied to UV to get the texture coords
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
*/
- this.uvTransform = texture.transform || new TextureTransform(texture);
+ this.uvTransform = texture.transform || new core.TextureMatrix(texture);
/**
* Plugin that is responsible for rendering this element.
diff --git a/src/extras/index.js b/src/extras/index.js
index 5b98cb1..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -3,7 +3,6 @@
* @namespace PIXI.extras
*/
export { default as AnimatedSprite } from './AnimatedSprite';
-export { default as TextureTransform } from './TextureTransform';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
export { default as BitmapText } from './BitmapText';
diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js
new file mode 100644
index 0000000..c2824ed
--- /dev/null
+++ b/src/filters/alpha/AlphaFilter.js
@@ -0,0 +1,55 @@
+import * as core from '../../core';
+import { readFileSync } from 'fs';
+import { join } from 'path';
+
+/**
+ * Simplest filter - applies alpha
+ *
+ * Use this instead of Container's alpha property to avoid visual layering of individual elements.
+ * AlphaFilter applies alpha evenly across the entire display object and any opaque elements it contains.
+ * If elements are not opaque, they will blend with each other anyway.
+ *
+ * Very handy if you want to use common features of all filters:
+ *
+ * 1. Assign a blendMode to this filter, blend all elements inside display object with background.
+ *
+ * 2. To use clipping in display coordinates, assign a filterArea to the same container that has this filter.
+ *
+ * @class
+ * @extends PIXI.Filter
+ * @memberof PIXI.filters
+ */
+export default class AlphaFilter extends core.Filter
+{
+ /**
+ *
+ */
+ constructor()
+ {
+ super(
+ // vertex shader
+ readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
+ // fragment shader
+ readFileSync(join(__dirname, './alpha.frag'), 'utf8')
+ );
+
+ this.alpha = 1.0;
+ this.glShaderKey = 'alpha';
+ }
+
+ /**
+ * Coefficient for alpha multiplication
+ *
+ * @member {number}
+ * @default 1
+ */
+ get alpha()
+ {
+ return this.uniforms.uAlpha;
+ }
+
+ set alpha(value) // eslint-disable-line require-jsdoc
+ {
+ this.uniforms.uAlpha = value;
+ }
+}
diff --git a/src/filters/alpha/alpha.frag b/src/filters/alpha/alpha.frag
new file mode 100644
index 0000000..6db588c
--- /dev/null
+++ b/src/filters/alpha/alpha.frag
@@ -0,0 +1,9 @@
+varying vec2 vTextureCoord;
+
+uniform sampler2D uSampler;
+uniform float uAlpha;
+
+void main(void)
+{
+ gl_FragColor = texture2D(uSampler, vTextureCoord) * uAlpha;
+}
diff --git a/src/filters/index.js b/src/filters/index.js
index 7ceb50a..dca47ab 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -25,4 +25,4 @@
export { default as BlurXFilter } from './blur/BlurXFilter';
export { default as BlurYFilter } from './blur/BlurYFilter';
export { default as ColorMatrixFilter } from './colormatrix/ColorMatrixFilter';
-export { default as VoidFilter } from './void/VoidFilter';
+export { default as AlphaFilter } from './alpha/AlphaFilter';
diff --git a/src/filters/void/VoidFilter.js b/src/filters/void/VoidFilter.js
deleted file mode 100644
index b4361ac..0000000
--- a/src/filters/void/VoidFilter.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as core from '../../core';
-import { readFileSync } from 'fs';
-import { join } from 'path';
-
-/**
- * Does nothing. Very handy.
- *
- * @class
- * @extends PIXI.Filter
- * @memberof PIXI.filters
- */
-export default class VoidFilter extends core.Filter
-{
- /**
- *
- */
- constructor()
- {
- super(
- // vertex shader
- readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
- // fragment shader
- readFileSync(join(__dirname, './void.frag'), 'utf8')
- );
-
- this.glShaderKey = 'void';
- }
-}
diff --git a/src/filters/void/void.frag b/src/filters/void/void.frag
deleted file mode 100644
index 99168fb..0000000
--- a/src/filters/void/void.frag
+++ /dev/null
@@ -1,8 +0,0 @@
-varying vec2 vTextureCoord;
-
-uniform sampler2D uSampler;
-
-void main(void)
-{
- gl_FragColor = texture2D(uSampler, vTextureCoord);
-}
diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js
index d866f03..7006a3e 100644
--- a/src/mesh/Mesh.js
+++ b/src/mesh/Mesh.js
@@ -1,5 +1,5 @@
import * as core from '../core';
-import { default as TextureTransform } from '../extras/TextureTransform';
+import Texture from '../core/textures/Texture';
const tempPoint = new core.Point();
const tempPolygon = new core.Polygon();
@@ -27,9 +27,10 @@
* The texture of the Mesh
*
* @member {PIXI.Texture}
+ * @default PIXI.Texture.EMPTY
* @private
*/
- this._texture = texture;
+ this._texture = texture || Texture.EMPTY;
/**
* The Uvs of the Mesh
@@ -129,10 +130,10 @@
* its updated independently from texture uvTransform
* updates of uvs are tied to that thing
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
* @private
*/
- this._uvTransform = new TextureTransform(texture);
+ this._uvTransform = new core.TextureMatrix(this._texture);
/**
* whether or not upload uvTransform to shader
diff --git a/src/mesh/NineSlicePlane.js b/src/mesh/NineSlicePlane.js
index 61ba5ee..f0d7575 100644
--- a/src/mesh/NineSlicePlane.js
+++ b/src/mesh/NineSlicePlane.js
@@ -172,8 +172,8 @@
const base = this._texture.baseTexture;
const textureSource = base.source;
- const w = base.width;
- const h = base.height;
+ const w = base.width * base.resolution;
+ const h = base.height * base.resolution;
this.drawSegment(context, textureSource, w, h, 0, 1, 10, 11);
this.drawSegment(context, textureSource, w, h, 2, 3, 12, 13);
diff --git a/src/mesh/Plane.js b/src/mesh/Plane.js
index 4dd2398..2aa60f9 100644
--- a/src/mesh/Plane.js
+++ b/src/mesh/Plane.js
@@ -94,6 +94,8 @@
this.uvs = new Float32Array(uvs);
this.colors = new Float32Array(colors);
this.indices = new Uint16Array(indices);
+
+ this.dirty++;
this.indexDirty++;
this.multiplyUvs();
diff --git a/test/interaction/InteractionManager.js b/test/interaction/InteractionManager.js
index 3f84d6a..136640e 100644
--- a/test/interaction/InteractionManager.js
+++ b/test/interaction/InteractionManager.js
@@ -279,13 +279,48 @@
removeSpy.restore();
});
- it('should add and remove pointer events to element', function ()
+ it('should add and remove pointer events to element seven times when touch events are supported', function ()
{
const manager = new PIXI.interaction.InteractionManager(sinon.stub());
const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
manager.interactionDOMElement = element;
manager.supportsPointerEvents = true;
+ manager.supportsTouchEvents = true;
+
+ manager.addEvents();
+
+ expect(element.addEventListener).to.have.been.callCount(7);
+ expect(element.addEventListener).to.have.been.calledWith('pointerdown');
+ expect(element.addEventListener).to.have.been.calledWith('pointerleave');
+ expect(element.addEventListener).to.have.been.calledWith('pointerover');
+
+ expect(element.addEventListener).to.have.been.calledWith('touchstart');
+ expect(element.addEventListener).to.have.been.calledWith('touchcancel');
+ expect(element.addEventListener).to.have.been.calledWith('touchend');
+ expect(element.addEventListener).to.have.been.calledWith('touchmove');
+
+ manager.removeEvents();
+
+ expect(element.removeEventListener).to.have.been.callCount(7);
+ expect(element.removeEventListener).to.have.been.calledWith('pointerdown');
+ expect(element.removeEventListener).to.have.been.calledWith('pointerleave');
+ expect(element.removeEventListener).to.have.been.calledWith('pointerover');
+
+ expect(element.removeEventListener).to.have.been.calledWith('touchstart');
+ expect(element.removeEventListener).to.have.been.calledWith('touchcancel');
+ expect(element.removeEventListener).to.have.been.calledWith('touchend');
+ expect(element.removeEventListener).to.have.been.calledWith('touchmove');
+ });
+
+ it('should add and remove pointer events to element three times when touch events are not supported', function ()
+ {
+ const manager = new PIXI.interaction.InteractionManager(sinon.stub());
+ const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
+
+ manager.interactionDOMElement = element;
+ manager.supportsPointerEvents = true;
+ manager.supportsTouchEvents = false;
manager.addEvents();
diff --git a/test/loaders/bitmapFontParser.js b/test/loaders/bitmapFontParser.js
index 7c77343..70703fc 100644
--- a/test/loaders/bitmapFontParser.js
+++ b/test/loaders/bitmapFontParser.js
@@ -1,7 +1,81 @@
'use strict';
+const path = require('path');
+const fs = require('fs');
+
describe('PIXI.loaders.bitmapFontParser', function ()
{
+ afterEach(function ()
+ {
+ for (var font in PIXI.extras.BitmapText.fonts)
+ {
+ delete PIXI.extras.BitmapText.fonts[font];
+ }
+ for (var baseTexture in PIXI.utils.BaseTextureCache)
+ {
+ delete PIXI.utils.BaseTextureCache[baseTexture];
+ }
+ for (var texture in PIXI.utils.TextureCache)
+ {
+ delete PIXI.utils.TextureCache[texture];
+ }
+ });
+
+ before(function (done)
+ {
+ const resolveURL = (url) => path.resolve(this.resources, url);
+
+ this.resources = path.join(__dirname, 'resources');
+ this.fontXML = null;
+ this.fontScaledXML = null;
+ this.fontImage = null;
+ this.fontScaledImage = null;
+ this.atlasImage = null;
+ this.atlasScaledImage = null;
+ this.atlasJSON = require(resolveURL('atlas.json')); // eslint-disable-line global-require
+ this.atlasScaledJSON = require(resolveURL('atlas@0.5x.json')); // eslint-disable-line global-require
+
+ const loadXML = (url) => new Promise((resolve) =>
+ fs.readFile(resolveURL(url), 'utf8', (err, data) =>
+ {
+ expect(err).to.be.null;
+ resolve((new window.DOMParser()).parseFromString(data, 'text/xml'));
+ }));
+
+ const loadImage = (url) => new Promise((resolve) =>
+ {
+ const image = new Image();
+
+ image.onload = () => resolve(image);
+ image.src = resolveURL(url);
+ });
+
+ Promise.all([
+ loadXML('font.fnt'),
+ loadXML('font@0.5x.fnt'),
+ loadImage('font.png'),
+ loadImage('font@0.5x.png'),
+ loadImage('atlas.png'),
+ loadImage('atlas@0.5x.png'),
+ ]).then(([
+ fontXML,
+ fontScaledXML,
+ fontImage,
+ fontScaledImage,
+ atlasImage,
+ atlasScaledImage,
+ ]) =>
+ {
+ this.fontXML = fontXML;
+ this.fontScaledXML = fontScaledXML;
+ this.fontImage = fontImage;
+ this.fontScaledImage = fontScaledImage;
+ this.atlasImage = atlasImage;
+ this.atlasScaledImage = atlasScaledImage;
+ done();
+ });
+ });
+
it('should exist and return a function', function ()
{
expect(PIXI.loaders.bitmapFontParser).to.be.a('function');
@@ -33,6 +107,206 @@
// TODO: Test the texture cache code path.
// TODO: Test the loading texture code path.
// TODO: Test data-url code paths.
+
+ it('should properly register bitmap font', function (done)
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture(this.fontImage, null, 1));
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, texture);
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charA.texture.frame.x).to.equal(2);
+ expect(charA.texture.frame.y).to.equal(2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charB.texture.frame.x).to.equal(2);
+ expect(charB.texture.frame.y).to.equal(24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charC.texture.frame.x).to.equal(23);
+ expect(charC.texture.frame.y).to.equal(2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charD.texture.frame.x).to.equal(19);
+ expect(charD.texture.frame.y).to.equal(24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+
+ it('should properly register SCALED bitmap font', function (done)
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture(this.fontScaledImage, null, 0.5));
+ const font = PIXI.extras.BitmapText.registerFont(this.fontScaledXML, texture);
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charA.texture.frame.x).to.equal(4); // 2 / 0.5
+ expect(charA.texture.frame.y).to.equal(4); // 2 / 0.5
+ expect(charA.texture.frame.width).to.equal(38); // 19 / 0.5
+ expect(charA.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charB.texture.frame.x).to.equal(4); // 2 / 0.5
+ expect(charB.texture.frame.y).to.equal(48); // 24 / 0.5
+ expect(charB.texture.frame.width).to.equal(30); // 15 / 0.5
+ expect(charB.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charC.texture.frame.x).to.equal(46); // 23 / 0.5
+ expect(charC.texture.frame.y).to.equal(4); // 2 / 0.5
+ expect(charC.texture.frame.width).to.equal(36); // 18 / 0.5
+ expect(charC.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charD.texture.frame.x).to.equal(38); // 19 / 0.5
+ expect(charD.texture.frame.y).to.equal(48); // 24 / 0.5
+ expect(charD.texture.frame.width).to.equal(34); // 17 / 0.5
+ expect(charD.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+
+ it('should properly register bitmap font NESTED into spritesheet', function (done)
+ {
+ const baseTexture = new PIXI.BaseTexture(this.atlasImage, null, 1);
+ const spritesheet = new PIXI.Spritesheet(baseTexture, this.atlasJSON);
+
+ spritesheet.parse(() =>
+ {
+ const fontTexture = PIXI.Texture.fromFrame('resources/font.png');
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, fontTexture);
+ const fontX = 158; // bare value from spritesheet frame
+ const fontY = 2; // bare value from spritesheet frame
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charA.texture.frame.x).to.equal(fontX + 2);
+ expect(charA.texture.frame.y).to.equal(fontY + 2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charB.texture.frame.x).to.equal(fontX + 2);
+ expect(charB.texture.frame.y).to.equal(fontY + 24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charC.texture.frame.x).to.equal(fontX + 23);
+ expect(charC.texture.frame.y).to.equal(fontY + 2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charD.texture.frame.x).to.equal(fontX + 19);
+ expect(charD.texture.frame.y).to.equal(fontY + 24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+ });
+
+ it('should properly register bitmap font NESTED into SCALED spritesheet', function (done)
+ {
+ const baseTexture = new PIXI.BaseTexture(this.atlasScaledImage, null, 1);
+ const spritesheet = new PIXI.Spritesheet(baseTexture, this.atlasScaledJSON);
+
+ spritesheet.parse(() =>
+ {
+ const fontTexture = PIXI.Texture.fromFrame('resources/font.png');
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, fontTexture);
+ const fontX = 158; // bare value from spritesheet frame
+ const fontY = 2; // bare value from spritesheet frame
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charA.texture.frame.x).to.equal(fontX + 2);
+ expect(charA.texture.frame.y).to.equal(fontY + 2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charB.texture.frame.x).to.equal(fontX + 2);
+ expect(charB.texture.frame.y).to.equal(fontY + 24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charC.texture.frame.x).to.equal(fontX + 23);
+ expect(charC.texture.frame.y).to.equal(fontY + 2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charD.texture.frame.x).to.equal(fontX + 19);
+ expect(charD.texture.frame.y).to.equal(fontY + 24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+ });
});
describe('PIXI.loaders.parseBitmapFontData', function ()
diff --git a/test/loaders/resources/atlas.json b/test/loaders/resources/atlas.json
new file mode 100644
index 0000000..86e65a5
--- /dev/null
+++ b/test/loaders/resources/atlas.json
@@ -0,0 +1,25 @@
+{
+ "meta": {
+ "image": "atlas.png",
+ "size": {"w":256,"h":256},
+ "scale": "1"
+ },
+ "frames": {
+ "resources/test.png":
+ {
+ "frame": {"x":2,"y":2,"w":152,"h":188},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":74,"y":36,"w":152,"h":188},
+ "sourceSize": {"w":300,"h":225}
+ },
+ "resources/font.png":
+ {
+ "frame": {"x":158,"y":2,"w":40,"h":42},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":2,"y":2,"w":40,"h":42},
+ "sourceSize": {"w":43,"h":46}
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/loaders/resources/atlas.png b/test/loaders/resources/atlas.png
new file mode 100644
index 0000000..d5e7892
--- /dev/null
+++ b/test/loaders/resources/atlas.png
Binary files differ
diff --git a/test/loaders/resources/atlas@0.5x.json b/test/loaders/resources/atlas@0.5x.json
new file mode 100644
index 0000000..ae990a1
--- /dev/null
+++ b/test/loaders/resources/atlas@0.5x.json
@@ -0,0 +1,25 @@
+{
+ "meta": {
+ "image": "atlas@0.5x.png",
+ "size": {"w":256,"h":256},
+ "scale": "1"
+ },
+ "frames": {
+ "resources/test.png":
+ {
+ "frame": {"x":2,"y":2,"w":152,"h":188},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":74,"y":36,"w":152,"h":188},
+ "sourceSize": {"w":300,"h":225}
+ },
+ "resources/font.png":
+ {
+ "frame": {"x":158,"y":2,"w":40,"h":42},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":2,"y":2,"w":40,"h":42},
+ "sourceSize": {"w":43,"h":46}
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/loaders/resources/atlas@0.5x.png b/test/loaders/resources/atlas@0.5x.png
new file mode 100644
index 0000000..d5e7892
--- /dev/null
+++ b/test/loaders/resources/atlas@0.5x.png
Binary files differ
diff --git a/test/loaders/resources/font.fnt b/test/loaders/resources/font.fnt
new file mode 100644
index 0000000..56e1060
--- /dev/null
+++ b/test/loaders/resources/font.fnt
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/loaders/resources/font.png b/test/loaders/resources/font.png
new file mode 100644
index 0000000..cf772e9
--- /dev/null
+++ b/test/loaders/resources/font.png
Binary files differ
diff --git a/test/loaders/resources/font@0.5x.fnt b/test/loaders/resources/font@0.5x.fnt
new file mode 100644
index 0000000..6c247c7
--- /dev/null
+++ b/test/loaders/resources/font@0.5x.fnt
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/core/index.js b/src/core/index.js
index 3265dfb..1a92622 100644
--- a/src/core/index.js
+++ b/src/core/index.js
@@ -33,6 +33,7 @@
export { default as CanvasGraphicsRenderer } from './graphics/canvas/CanvasGraphicsRenderer';
export { default as Spritesheet } from './textures/Spritesheet';
export { default as Texture } from './textures/Texture';
+export { default as TextureMatrix } from './textures/TextureMatrix';
export { default as BaseTexture } from './textures/BaseTexture';
export { default as RenderTexture } from './textures/RenderTexture';
export { default as BaseRenderTexture } from './textures/BaseRenderTexture';
diff --git a/src/core/math/GroupD8.js b/src/core/math/GroupD8.js
index 50c2f31..e6a09e7 100644
--- a/src/core/math/GroupD8.js
+++ b/src/core/math/GroupD8.js
@@ -111,13 +111,14 @@
rotate180: (rotation) => rotation ^ 4,
/**
- * I dont know why sometimes width and heights needs to be swapped. We'll fix it later.
+ * Direction of main vector can be horizontal, vertical or diagonal.
+ * Some objects work with vertical directions different.
*
* @memberof PIXI.GroupD8
* @param {number} rotation - The number to check.
- * @returns {boolean} Whether or not the width/height should be swapped.
+ * @returns {boolean} Whether or not the direction is vertical
*/
- isSwapWidthHeight: (rotation) => (rotation & 3) === 2,
+ isVertical: (rotation) => (rotation & 3) === 2,
/**
* @memberof PIXI.GroupD8
diff --git a/src/core/renderers/canvas/CanvasRenderer.js b/src/core/renderers/canvas/CanvasRenderer.js
index 4dcd773..8c4789c 100644
--- a/src/core/renderers/canvas/CanvasRenderer.js
+++ b/src/core/renderers/canvas/CanvasRenderer.js
@@ -199,6 +199,7 @@
// displayObject.hitArea = //TODO add a temp hit area
}
+ context.save();
context.setTransform(1, 0, 0, 1, 0, 0);
context.globalAlpha = 1;
this._activeBlendMode = BLEND_MODES.NORMAL;
@@ -235,6 +236,8 @@
displayObject.renderCanvas(this);
this.context = tempContext;
+ context.restore();
+
this.resolution = rootResolution;
this.emit('postrender');
diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js
index e63d2b0..3f432a1 100644
--- a/src/core/renderers/webgl/WebGLRenderer.js
+++ b/src/core/renderers/webgl/WebGLRenderer.js
@@ -662,8 +662,14 @@
this.setObjectRenderer(this.emptyRenderer);
this._activeShader = null;
+ this._activeVao = null;
this._activeRenderTarget = this.rootRenderTarget;
+ for (let i = 0; i < this.boundTextures.length; i++)
+ {
+ this.boundTextures[i] = this.emptyTextures[i];
+ }
+
// bind the main frame buffer (the screen);
this.rootRenderTarget.activate();
diff --git a/src/core/renderers/webgl/filters/filterTransforms.js b/src/core/renderers/webgl/filters/filterTransforms.js
index f955a9d..2d08dbc 100644
--- a/src/core/renderers/webgl/filters/filterTransforms.js
+++ b/src/core/renderers/webgl/filters/filterTransforms.js
@@ -40,13 +40,13 @@
// this will map the filter coord so that a texture can be used based on the transform of a sprite
export function calculateSpriteMatrix(outputMatrix, filterArea, textureSize, sprite)
{
- const texture = sprite._texture.baseTexture;
+ const orig = sprite._texture.orig;
const mappedMatrix = outputMatrix.set(textureSize.width, 0, 0, textureSize.height, filterArea.x, filterArea.y);
const worldTransform = sprite.worldTransform.copy(Matrix.TEMP_MATRIX);
worldTransform.invert();
mappedMatrix.prepend(worldTransform);
- mappedMatrix.scale(1.0 / texture.width, 1.0 / texture.height);
+ mappedMatrix.scale(1.0 / orig.width, 1.0 / orig.height);
mappedMatrix.translate(sprite.anchor.x, sprite.anchor.y);
return mappedMatrix;
diff --git a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
index 1e86c68..e5fd49c 100644
--- a/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
+++ b/src/core/renderers/webgl/filters/spriteMask/SpriteMaskFilter.js
@@ -2,6 +2,7 @@
import { Matrix } from '../../../../math';
import { readFileSync } from 'fs';
import { join } from 'path';
+import { default as TextureMatrix } from '../../../../textures/TextureMatrix';
/**
* The SpriteMaskFilter class
@@ -40,10 +41,25 @@
apply(filterManager, input, output)
{
const maskSprite = this.maskSprite;
+ const tex = this.maskSprite.texture;
- this.uniforms.mask = maskSprite._texture;
- this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite);
+ if (!tex.valid)
+ {
+ return;
+ }
+ if (!tex.transform)
+ {
+ // margin = 0.0, let it bleed a bit, shader code becomes easier
+ // assuming that atlas textures were made with 1-pixel padding
+ tex.transform = new TextureMatrix(tex, 0.0);
+ }
+ tex.transform.update();
+
+ this.uniforms.mask = tex;
+ this.uniforms.otherMatrix = filterManager.calculateSpriteMatrix(this.maskMatrix, maskSprite)
+ .prepend(tex.transform.mapCoord);
this.uniforms.alpha = maskSprite.worldAlpha;
+ this.uniforms.maskClamp = tex.transform.uClampFrame;
filterManager.applyFilter(this, input, output);
}
diff --git a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
index 4a419a1..0e4aef8 100644
--- a/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
+++ b/src/core/renderers/webgl/filters/spriteMask/spriteMaskFilter.frag
@@ -2,16 +2,18 @@
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
-uniform float alpha;
uniform sampler2D mask;
+uniform float alpha;
+uniform vec4 maskClamp;
void main(void)
{
- // check clip! this will stop the mask bleeding out from the edges
- vec2 text = abs( vMaskCoord - 0.5 );
- text = step(0.5, text);
+ float clip = step(3.5,
+ step(maskClamp.x, vMaskCoord.x) +
+ step(maskClamp.y, vMaskCoord.y) +
+ step(vMaskCoord.x, maskClamp.z) +
+ step(vMaskCoord.y, maskClamp.w));
- float clip = 1.0 - max(text.y, text.x);
vec4 original = texture2D(uSampler, vTextureCoord);
vec4 masky = texture2D(mask, vMaskCoord);
diff --git a/src/core/textures/BaseRenderTexture.js b/src/core/textures/BaseRenderTexture.js
index 0b13c90..2c74de1 100644
--- a/src/core/textures/BaseRenderTexture.js
+++ b/src/core/textures/BaseRenderTexture.js
@@ -54,8 +54,8 @@
this.resolution = resolution || settings.RESOLUTION;
- this.width = width;
- this.height = height;
+ this.width = Math.ceil(width);
+ this.height = Math.ceil(height);
this.realWidth = this.width * this.resolution;
this.realHeight = this.height * this.resolution;
@@ -95,6 +95,9 @@
*/
resize(width, height)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
if (width === this.width && height === this.height)
{
return;
diff --git a/src/core/textures/RenderTexture.js b/src/core/textures/RenderTexture.js
index 31d264e..4fe047f 100644
--- a/src/core/textures/RenderTexture.js
+++ b/src/core/textures/RenderTexture.js
@@ -97,6 +97,9 @@
*/
resize(width, height, doNotResizeBaseTexture)
{
+ width = Math.ceil(width);
+ height = Math.ceil(height);
+
// TODO - could be not required..
this.valid = (width > 0 && height > 0);
diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js
index 75eb069..c63af99 100644
--- a/src/core/textures/Texture.js
+++ b/src/core/textures/Texture.js
@@ -80,6 +80,7 @@
/**
* This is the trimmed area of original texture, before it was put in atlas
+ * Please call `_updateUvs()` after you change coordinates of `trim` manually.
*
* @member {PIXI.Rectangle}
*/
@@ -153,8 +154,10 @@
this._updateID = 0;
/**
- * Extra field for extra plugins. May contain clamp settings and some matrices
- * @type {Object}
+ * Contains data for uvs. May contain clamp settings and some matrices.
+ * Its a bit heavy, so by default that object is not created.
+ * @type {PIXI.TextureMatrix}
+ * @default null
*/
this.transform = null;
@@ -266,9 +269,7 @@
}
/**
- * Updates the internal WebGL UV cache.
- *
- * @protected
+ * Updates the internal WebGL UV cache. Use it after you change `frame` or `trim` of the texture.
*/
_updateUvs()
{
@@ -538,6 +539,7 @@
/**
* The frame specifies the region of the base texture that this texture uses.
+ * Please call `_updateUvs()` after you change coordinates of `frame` manually.
*
* @member {PIXI.Rectangle}
*/
diff --git a/src/core/textures/TextureMatrix.js b/src/core/textures/TextureMatrix.js
new file mode 100644
index 0000000..f0b9c12
--- /dev/null
+++ b/src/core/textures/TextureMatrix.js
@@ -0,0 +1,149 @@
+import { default as Matrix } from '../math/Matrix';
+
+const tempMat = new Matrix();
+
+/**
+ * Class controls uv transform and frame clamp for texture
+ * Can be used in Texture "transform" field, or separately, you can use different clamp settings on the same texture.
+ * If you want to add support for texture region of certain feature or filter, that's what you're looking for.
+ *
+ * @see PIXI.Texture
+ * @see PIXI.mesh.Mesh
+ * @see PIXI.extras.TilingSprite
+ * @class
+ * @memberof PIXI
+ */
+export default class TextureMatrix
+{
+ /**
+ *
+ * @param {PIXI.Texture} texture observed texture
+ * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
+ * @constructor
+ */
+ constructor(texture, clampMargin)
+ {
+ this._texture = texture;
+
+ this.mapCoord = new Matrix();
+
+ this.uClampFrame = new Float32Array(4);
+
+ this.uClampOffset = new Float32Array(2);
+
+ this._lastTextureID = -1;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
+ *
+ * @default 0
+ * @member {number}
+ */
+ this.clampOffset = 0;
+
+ /**
+ * Changes frame clamping
+ * Works with TilingSprite and Mesh
+ * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
+ *
+ * @default 0.5
+ * @member {number}
+ */
+ this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
+ }
+
+ /**
+ * texture property
+ * @member {PIXI.Texture}
+ */
+ get texture()
+ {
+ return this._texture;
+ }
+
+ set texture(value) // eslint-disable-line require-jsdoc
+ {
+ this._texture = value;
+ this._lastTextureID = -1;
+ }
+
+ /**
+ * Multiplies uvs array to transform
+ * @param {Float32Array} uvs mesh uvs
+ * @param {Float32Array} [out=uvs] output
+ * @returns {Float32Array} output
+ */
+ multiplyUvs(uvs, out)
+ {
+ if (out === undefined)
+ {
+ out = uvs;
+ }
+
+ const mat = this.mapCoord;
+
+ for (let i = 0; i < uvs.length; i += 2)
+ {
+ const x = uvs[i];
+ const y = uvs[i + 1];
+
+ out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
+ out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
+ }
+
+ return out;
+ }
+
+ /**
+ * updates matrices if texture was changed
+ * @param {boolean} forceUpdate if true, matrices will be updated any case
+ * @returns {boolean} whether or not it was updated
+ */
+ update(forceUpdate)
+ {
+ const tex = this._texture;
+
+ if (!tex || !tex.valid)
+ {
+ return false;
+ }
+
+ if (!forceUpdate
+ && this._lastTextureID === tex._updateID)
+ {
+ return false;
+ }
+
+ this._lastTextureID = tex._updateID;
+
+ const uvs = tex._uvs;
+
+ this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
+
+ const orig = tex.orig;
+ const trim = tex.trim;
+
+ if (trim)
+ {
+ tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
+ -trim.x / trim.width, -trim.y / trim.height);
+ this.mapCoord.append(tempMat);
+ }
+
+ const texBase = tex.baseTexture;
+ const frame = this.uClampFrame;
+ const margin = this.clampMargin / texBase.resolution;
+ const offset = this.clampOffset;
+
+ frame[0] = (tex._frame.x + margin + offset) / texBase.width;
+ frame[1] = (tex._frame.y + margin + offset) / texBase.height;
+ frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
+ frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
+ this.uClampOffset[0] = offset / texBase.realWidth;
+ this.uClampOffset[1] = offset / texBase.realHeight;
+
+ return true;
+ }
+}
diff --git a/src/core/textures/VideoBaseTexture.js b/src/core/textures/VideoBaseTexture.js
index f819313..86f0873 100644
--- a/src/core/textures/VideoBaseTexture.js
+++ b/src/core/textures/VideoBaseTexture.js
@@ -2,6 +2,7 @@
import { uid, BaseTextureCache } from '../utils';
import { shared } from '../ticker';
import { UPDATE_PRIORITY } from '../const';
+import determineCrossOrigin from '../utils/determineCrossOrigin';
/**
* A texture of a [playing] Video.
@@ -236,15 +237,27 @@
* @param {string} [videoSrc.mime] - The mimetype of the video (e.g. 'video/mp4'). If not specified
* the url's extension will be used as the second part of the mime type.
* @param {number} scaleMode - See {@link PIXI.SCALE_MODES} for possible values
+ * @param {boolean} [crossorigin=(auto)] - Should use anonymous CORS? Defaults to true if the URL is not a data-URI.
* @return {PIXI.VideoBaseTexture} Newly created VideoBaseTexture
*/
- static fromUrl(videoSrc, scaleMode)
+ static fromUrl(videoSrc, scaleMode, crossorigin)
{
const video = document.createElement('video');
video.setAttribute('webkit-playsinline', '');
video.setAttribute('playsinline', '');
+ const url = Array.isArray(videoSrc) ? (videoSrc[0].src || videoSrc[0]) : (videoSrc.src || videoSrc);
+
+ if (crossorigin === undefined && url.indexOf('data:') !== 0)
+ {
+ video.crossOrigin = determineCrossOrigin(url);
+ }
+ else if (crossorigin)
+ {
+ video.crossOrigin = typeof crossorigin === 'string' ? crossorigin : 'anonymous';
+ }
+
// array of objects or strings
if (Array.isArray(videoSrc))
{
@@ -256,7 +269,7 @@
// single object or string
else
{
- video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime));
+ video.appendChild(createSource(url, videoSrc.mime));
}
video.load();
diff --git a/src/deprecation.js b/src/deprecation.js
index a7e943f..dab6e70 100644
--- a/src/deprecation.js
+++ b/src/deprecation.js
@@ -586,6 +586,28 @@
});
}
+ if (extras)
+ {
+ Object.defineProperties(extras, {
+ /**
+ * @class
+ * @name TextureTransform
+ * @memberof PIXI.extras
+ * @see PIXI.TextureMatrix
+ * @deprecated since version 4.6.0
+ */
+ TextureTransform: {
+ get()
+ {
+ warn('The TextureTransform class has been renamed to TextureMatrix, '
+ + 'please use PIXI.TextureMatrix from now on.');
+
+ return core.TextureMatrix;
+ },
+ },
+ });
+ }
+
core.DisplayObject.prototype.generateTexture = function generateTexture(renderer, scaleMode, resolution)
{
warn('generateTexture has moved to the renderer, please use renderer.generateTexture(displayObject)');
@@ -601,6 +623,21 @@
return this.generateCanvasTexture(scaleMode, resolution);
};
+ /**
+ * @method
+ * @name PIXI.GroupD8.isSwapWidthHeight
+ * @see PIXI.GroupD8.isVertical
+ * @param {number} rotation - The number to check.
+ * @returns {boolean} Whether or not the direction is vertical
+ * @deprecated since version 4.6.0
+ */
+ core.GroupD8.isSwapWidthHeight = function isSwapWidthHeight(rotation)
+ {
+ warn('GroupD8.isSwapWidthHeight was renamed to GroupD8.isVertical');
+
+ return core.GroupD8.isVertical(rotation);
+ };
+
core.RenderTexture.prototype.render = function render(displayObject, matrix, clear, updateTransform)
{
this.legacyRenderer.render(displayObject, this, clear, matrix, !updateTransform);
@@ -946,6 +983,22 @@
return core.SpriteMaskFilter;
},
},
+
+ /**
+ * @class
+ * @private
+ * @name PIXI.filters.VoidFilter
+ * @see PIXI.filters.AlphaFilter
+ * @deprecated since version 4.5.7
+ */
+ VoidFilter: {
+ get()
+ {
+ warn('VoidFilter has been renamed to AlphaFilter, please use PIXI.filters.AlphaFilter');
+
+ return filters.AlphaFilter;
+ },
+ },
});
/**
diff --git a/src/extras/BitmapText.js b/src/extras/BitmapText.js
index 0592b54..96d9f44 100644
--- a/src/extras/BitmapText.js
+++ b/src/extras/BitmapText.js
@@ -1,5 +1,6 @@
import * as core from '../core';
import ObservablePoint from '../core/math/ObservablePoint';
+import { getResolutionOfUrl } from '../core/utils';
import settings from '../core/settings';
/**
@@ -510,7 +511,8 @@
const data = {};
const info = xml.getElementsByTagName('info')[0];
const common = xml.getElementsByTagName('common')[0];
- const res = texture.baseTexture.resolution || settings.RESOLUTION;
+ const fileName = xml.getElementsByTagName('page')[0].getAttribute('file');
+ const res = getResolutionOfUrl(fileName, settings.RESOLUTION);
data.font = info.getAttribute('face');
data.size = parseInt(info.getAttribute('size'), 10);
diff --git a/src/extras/TextureTransform.js b/src/extras/TextureTransform.js
deleted file mode 100644
index 16536d2..0000000
--- a/src/extras/TextureTransform.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import { default as Matrix } from '../core/math/Matrix';
-
-const tempMat = new Matrix();
-
-/**
- * class controls uv transform and frame clamp for texture
- *
- * @class
- * @memberof PIXI.extras
- */
-export default class TextureTransform
-{
- /**
- *
- * @param {PIXI.Texture} texture observed texture
- * @param {number} [clampMargin] Changes frame clamping, 0.5 by default. Use -0.5 for extra border.
- * @constructor
- */
- constructor(texture, clampMargin)
- {
- this._texture = texture;
-
- this.mapCoord = new Matrix();
-
- this.uClampFrame = new Float32Array(4);
-
- this.uClampOffset = new Float32Array(2);
-
- this._lastTextureID = -1;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to 1.5 if you texture has repeated right and bottom lines, that leads to smoother borders
- *
- * @default 0
- * @member {number}
- */
- this.clampOffset = 0;
-
- /**
- * Changes frame clamping
- * Works with TilingSprite and Mesh
- * Change to -0.5 to add a pixel to the edge, recommended for transparent trimmed textures in atlas
- *
- * @default 0.5
- * @member {number}
- */
- this.clampMargin = (typeof clampMargin === 'undefined') ? 0.5 : clampMargin;
- }
-
- /**
- * texture property
- * @member {PIXI.Texture}
- */
- get texture()
- {
- return this._texture;
- }
-
- set texture(value) // eslint-disable-line require-jsdoc
- {
- this._texture = value;
- this._lastTextureID = -1;
- }
-
- /**
- * Multiplies uvs array to transform
- * @param {Float32Array} uvs mesh uvs
- * @param {Float32Array} [out=uvs] output
- * @returns {Float32Array} output
- */
- multiplyUvs(uvs, out)
- {
- if (out === undefined)
- {
- out = uvs;
- }
-
- const mat = this.mapCoord;
-
- for (let i = 0; i < uvs.length; i += 2)
- {
- const x = uvs[i];
- const y = uvs[i + 1];
-
- out[i] = (x * mat.a) + (y * mat.c) + mat.tx;
- out[i + 1] = (x * mat.b) + (y * mat.d) + mat.ty;
- }
-
- return out;
- }
-
- /**
- * updates matrices if texture was changed
- * @param {boolean} forceUpdate if true, matrices will be updated any case
- * @returns {boolean} whether or not it was updated
- */
- update(forceUpdate)
- {
- const tex = this._texture;
-
- if (!tex || !tex.valid)
- {
- return false;
- }
-
- if (!forceUpdate
- && this._lastTextureID === tex._updateID)
- {
- return false;
- }
-
- this._lastTextureID = tex._updateID;
-
- const uvs = tex._uvs;
-
- this.mapCoord.set(uvs.x1 - uvs.x0, uvs.y1 - uvs.y0, uvs.x3 - uvs.x0, uvs.y3 - uvs.y0, uvs.x0, uvs.y0);
-
- const orig = tex.orig;
- const trim = tex.trim;
-
- if (trim)
- {
- tempMat.set(orig.width / trim.width, 0, 0, orig.height / trim.height,
- -trim.x / trim.width, -trim.y / trim.height);
- this.mapCoord.append(tempMat);
- }
-
- const texBase = tex.baseTexture;
- const frame = this.uClampFrame;
- const margin = this.clampMargin / texBase.resolution;
- const offset = this.clampOffset;
-
- frame[0] = (tex._frame.x + margin + offset) / texBase.width;
- frame[1] = (tex._frame.y + margin + offset) / texBase.height;
- frame[2] = (tex._frame.x + tex._frame.width - margin + offset) / texBase.width;
- frame[3] = (tex._frame.y + tex._frame.height - margin + offset) / texBase.height;
- this.uClampOffset[0] = offset / texBase.realWidth;
- this.uClampOffset[1] = offset / texBase.realHeight;
-
- return true;
- }
-}
diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js
index 736b207..84c0841 100644
--- a/src/extras/TilingSprite.js
+++ b/src/extras/TilingSprite.js
@@ -1,6 +1,5 @@
import * as core from '../core';
import CanvasTinter from '../core/sprites/canvas/CanvasTinter';
-import { default as TextureTransform } from './TextureTransform';
const tempPoint = new core.Point();
@@ -58,9 +57,9 @@
/**
* transform that is applied to UV to get the texture coords
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
*/
- this.uvTransform = texture.transform || new TextureTransform(texture);
+ this.uvTransform = texture.transform || new core.TextureMatrix(texture);
/**
* Plugin that is responsible for rendering this element.
diff --git a/src/extras/index.js b/src/extras/index.js
index 5b98cb1..a34d7ec 100644
--- a/src/extras/index.js
+++ b/src/extras/index.js
@@ -3,7 +3,6 @@
* @namespace PIXI.extras
*/
export { default as AnimatedSprite } from './AnimatedSprite';
-export { default as TextureTransform } from './TextureTransform';
export { default as TilingSprite } from './TilingSprite';
export { default as TilingSpriteRenderer } from './webgl/TilingSpriteRenderer';
export { default as BitmapText } from './BitmapText';
diff --git a/src/filters/alpha/AlphaFilter.js b/src/filters/alpha/AlphaFilter.js
new file mode 100644
index 0000000..c2824ed
--- /dev/null
+++ b/src/filters/alpha/AlphaFilter.js
@@ -0,0 +1,55 @@
+import * as core from '../../core';
+import { readFileSync } from 'fs';
+import { join } from 'path';
+
+/**
+ * Simplest filter - applies alpha
+ *
+ * Use this instead of Container's alpha property to avoid visual layering of individual elements.
+ * AlphaFilter applies alpha evenly across the entire display object and any opaque elements it contains.
+ * If elements are not opaque, they will blend with each other anyway.
+ *
+ * Very handy if you want to use common features of all filters:
+ *
+ * 1. Assign a blendMode to this filter, blend all elements inside display object with background.
+ *
+ * 2. To use clipping in display coordinates, assign a filterArea to the same container that has this filter.
+ *
+ * @class
+ * @extends PIXI.Filter
+ * @memberof PIXI.filters
+ */
+export default class AlphaFilter extends core.Filter
+{
+ /**
+ *
+ */
+ constructor()
+ {
+ super(
+ // vertex shader
+ readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
+ // fragment shader
+ readFileSync(join(__dirname, './alpha.frag'), 'utf8')
+ );
+
+ this.alpha = 1.0;
+ this.glShaderKey = 'alpha';
+ }
+
+ /**
+ * Coefficient for alpha multiplication
+ *
+ * @member {number}
+ * @default 1
+ */
+ get alpha()
+ {
+ return this.uniforms.uAlpha;
+ }
+
+ set alpha(value) // eslint-disable-line require-jsdoc
+ {
+ this.uniforms.uAlpha = value;
+ }
+}
diff --git a/src/filters/alpha/alpha.frag b/src/filters/alpha/alpha.frag
new file mode 100644
index 0000000..6db588c
--- /dev/null
+++ b/src/filters/alpha/alpha.frag
@@ -0,0 +1,9 @@
+varying vec2 vTextureCoord;
+
+uniform sampler2D uSampler;
+uniform float uAlpha;
+
+void main(void)
+{
+ gl_FragColor = texture2D(uSampler, vTextureCoord) * uAlpha;
+}
diff --git a/src/filters/index.js b/src/filters/index.js
index 7ceb50a..dca47ab 100644
--- a/src/filters/index.js
+++ b/src/filters/index.js
@@ -25,4 +25,4 @@
export { default as BlurXFilter } from './blur/BlurXFilter';
export { default as BlurYFilter } from './blur/BlurYFilter';
export { default as ColorMatrixFilter } from './colormatrix/ColorMatrixFilter';
-export { default as VoidFilter } from './void/VoidFilter';
+export { default as AlphaFilter } from './alpha/AlphaFilter';
diff --git a/src/filters/void/VoidFilter.js b/src/filters/void/VoidFilter.js
deleted file mode 100644
index b4361ac..0000000
--- a/src/filters/void/VoidFilter.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as core from '../../core';
-import { readFileSync } from 'fs';
-import { join } from 'path';
-
-/**
- * Does nothing. Very handy.
- *
- * @class
- * @extends PIXI.Filter
- * @memberof PIXI.filters
- */
-export default class VoidFilter extends core.Filter
-{
- /**
- *
- */
- constructor()
- {
- super(
- // vertex shader
- readFileSync(join(__dirname, '../fragments/default.vert'), 'utf8'),
- // fragment shader
- readFileSync(join(__dirname, './void.frag'), 'utf8')
- );
-
- this.glShaderKey = 'void';
- }
-}
diff --git a/src/filters/void/void.frag b/src/filters/void/void.frag
deleted file mode 100644
index 99168fb..0000000
--- a/src/filters/void/void.frag
+++ /dev/null
@@ -1,8 +0,0 @@
-varying vec2 vTextureCoord;
-
-uniform sampler2D uSampler;
-
-void main(void)
-{
- gl_FragColor = texture2D(uSampler, vTextureCoord);
-}
diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js
index d866f03..7006a3e 100644
--- a/src/mesh/Mesh.js
+++ b/src/mesh/Mesh.js
@@ -1,5 +1,5 @@
import * as core from '../core';
-import { default as TextureTransform } from '../extras/TextureTransform';
+import Texture from '../core/textures/Texture';
const tempPoint = new core.Point();
const tempPolygon = new core.Polygon();
@@ -27,9 +27,10 @@
* The texture of the Mesh
*
* @member {PIXI.Texture}
+ * @default PIXI.Texture.EMPTY
* @private
*/
- this._texture = texture;
+ this._texture = texture || Texture.EMPTY;
/**
* The Uvs of the Mesh
@@ -129,10 +130,10 @@
* its updated independently from texture uvTransform
* updates of uvs are tied to that thing
*
- * @member {PIXI.extras.TextureTransform}
+ * @member {PIXI.TextureMatrix}
* @private
*/
- this._uvTransform = new TextureTransform(texture);
+ this._uvTransform = new core.TextureMatrix(this._texture);
/**
* whether or not upload uvTransform to shader
diff --git a/src/mesh/NineSlicePlane.js b/src/mesh/NineSlicePlane.js
index 61ba5ee..f0d7575 100644
--- a/src/mesh/NineSlicePlane.js
+++ b/src/mesh/NineSlicePlane.js
@@ -172,8 +172,8 @@
const base = this._texture.baseTexture;
const textureSource = base.source;
- const w = base.width;
- const h = base.height;
+ const w = base.width * base.resolution;
+ const h = base.height * base.resolution;
this.drawSegment(context, textureSource, w, h, 0, 1, 10, 11);
this.drawSegment(context, textureSource, w, h, 2, 3, 12, 13);
diff --git a/src/mesh/Plane.js b/src/mesh/Plane.js
index 4dd2398..2aa60f9 100644
--- a/src/mesh/Plane.js
+++ b/src/mesh/Plane.js
@@ -94,6 +94,8 @@
this.uvs = new Float32Array(uvs);
this.colors = new Float32Array(colors);
this.indices = new Uint16Array(indices);
+
+ this.dirty++;
this.indexDirty++;
this.multiplyUvs();
diff --git a/test/interaction/InteractionManager.js b/test/interaction/InteractionManager.js
index 3f84d6a..136640e 100644
--- a/test/interaction/InteractionManager.js
+++ b/test/interaction/InteractionManager.js
@@ -279,13 +279,48 @@
removeSpy.restore();
});
- it('should add and remove pointer events to element', function ()
+ it('should add and remove pointer events to element seven times when touch events are supported', function ()
{
const manager = new PIXI.interaction.InteractionManager(sinon.stub());
const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
manager.interactionDOMElement = element;
manager.supportsPointerEvents = true;
+ manager.supportsTouchEvents = true;
+
+ manager.addEvents();
+
+ expect(element.addEventListener).to.have.been.callCount(7);
+ expect(element.addEventListener).to.have.been.calledWith('pointerdown');
+ expect(element.addEventListener).to.have.been.calledWith('pointerleave');
+ expect(element.addEventListener).to.have.been.calledWith('pointerover');
+
+ expect(element.addEventListener).to.have.been.calledWith('touchstart');
+ expect(element.addEventListener).to.have.been.calledWith('touchcancel');
+ expect(element.addEventListener).to.have.been.calledWith('touchend');
+ expect(element.addEventListener).to.have.been.calledWith('touchmove');
+
+ manager.removeEvents();
+
+ expect(element.removeEventListener).to.have.been.callCount(7);
+ expect(element.removeEventListener).to.have.been.calledWith('pointerdown');
+ expect(element.removeEventListener).to.have.been.calledWith('pointerleave');
+ expect(element.removeEventListener).to.have.been.calledWith('pointerover');
+
+ expect(element.removeEventListener).to.have.been.calledWith('touchstart');
+ expect(element.removeEventListener).to.have.been.calledWith('touchcancel');
+ expect(element.removeEventListener).to.have.been.calledWith('touchend');
+ expect(element.removeEventListener).to.have.been.calledWith('touchmove');
+ });
+
+ it('should add and remove pointer events to element three times when touch events are not supported', function ()
+ {
+ const manager = new PIXI.interaction.InteractionManager(sinon.stub());
+ const element = { style: {}, addEventListener: sinon.stub(), removeEventListener: sinon.stub() };
+
+ manager.interactionDOMElement = element;
+ manager.supportsPointerEvents = true;
+ manager.supportsTouchEvents = false;
manager.addEvents();
diff --git a/test/loaders/bitmapFontParser.js b/test/loaders/bitmapFontParser.js
index 7c77343..70703fc 100644
--- a/test/loaders/bitmapFontParser.js
+++ b/test/loaders/bitmapFontParser.js
@@ -1,7 +1,81 @@
'use strict';
+const path = require('path');
+const fs = require('fs');
+
describe('PIXI.loaders.bitmapFontParser', function ()
{
+ afterEach(function ()
+ {
+ for (var font in PIXI.extras.BitmapText.fonts)
+ {
+ delete PIXI.extras.BitmapText.fonts[font];
+ }
+ for (var baseTexture in PIXI.utils.BaseTextureCache)
+ {
+ delete PIXI.utils.BaseTextureCache[baseTexture];
+ }
+ for (var texture in PIXI.utils.TextureCache)
+ {
+ delete PIXI.utils.TextureCache[texture];
+ }
+ });
+
+ before(function (done)
+ {
+ const resolveURL = (url) => path.resolve(this.resources, url);
+
+ this.resources = path.join(__dirname, 'resources');
+ this.fontXML = null;
+ this.fontScaledXML = null;
+ this.fontImage = null;
+ this.fontScaledImage = null;
+ this.atlasImage = null;
+ this.atlasScaledImage = null;
+ this.atlasJSON = require(resolveURL('atlas.json')); // eslint-disable-line global-require
+ this.atlasScaledJSON = require(resolveURL('atlas@0.5x.json')); // eslint-disable-line global-require
+
+ const loadXML = (url) => new Promise((resolve) =>
+ fs.readFile(resolveURL(url), 'utf8', (err, data) =>
+ {
+ expect(err).to.be.null;
+ resolve((new window.DOMParser()).parseFromString(data, 'text/xml'));
+ }));
+
+ const loadImage = (url) => new Promise((resolve) =>
+ {
+ const image = new Image();
+
+ image.onload = () => resolve(image);
+ image.src = resolveURL(url);
+ });
+
+ Promise.all([
+ loadXML('font.fnt'),
+ loadXML('font@0.5x.fnt'),
+ loadImage('font.png'),
+ loadImage('font@0.5x.png'),
+ loadImage('atlas.png'),
+ loadImage('atlas@0.5x.png'),
+ ]).then(([
+ fontXML,
+ fontScaledXML,
+ fontImage,
+ fontScaledImage,
+ atlasImage,
+ atlasScaledImage,
+ ]) =>
+ {
+ this.fontXML = fontXML;
+ this.fontScaledXML = fontScaledXML;
+ this.fontImage = fontImage;
+ this.fontScaledImage = fontScaledImage;
+ this.atlasImage = atlasImage;
+ this.atlasScaledImage = atlasScaledImage;
+ done();
+ });
+ });
+
it('should exist and return a function', function ()
{
expect(PIXI.loaders.bitmapFontParser).to.be.a('function');
@@ -33,6 +107,206 @@
// TODO: Test the texture cache code path.
// TODO: Test the loading texture code path.
// TODO: Test data-url code paths.
+
+ it('should properly register bitmap font', function (done)
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture(this.fontImage, null, 1));
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, texture);
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charA.texture.frame.x).to.equal(2);
+ expect(charA.texture.frame.y).to.equal(2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charB.texture.frame.x).to.equal(2);
+ expect(charB.texture.frame.y).to.equal(24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charC.texture.frame.x).to.equal(23);
+ expect(charC.texture.frame.y).to.equal(2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.fontImage);
+ expect(charD.texture.frame.x).to.equal(19);
+ expect(charD.texture.frame.y).to.equal(24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+
+ it('should properly register SCALED bitmap font', function (done)
+ {
+ const texture = new PIXI.Texture(new PIXI.BaseTexture(this.fontScaledImage, null, 0.5));
+ const font = PIXI.extras.BitmapText.registerFont(this.fontScaledXML, texture);
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charA.texture.frame.x).to.equal(4); // 2 / 0.5
+ expect(charA.texture.frame.y).to.equal(4); // 2 / 0.5
+ expect(charA.texture.frame.width).to.equal(38); // 19 / 0.5
+ expect(charA.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charB.texture.frame.x).to.equal(4); // 2 / 0.5
+ expect(charB.texture.frame.y).to.equal(48); // 24 / 0.5
+ expect(charB.texture.frame.width).to.equal(30); // 15 / 0.5
+ expect(charB.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charC.texture.frame.x).to.equal(46); // 23 / 0.5
+ expect(charC.texture.frame.y).to.equal(4); // 2 / 0.5
+ expect(charC.texture.frame.width).to.equal(36); // 18 / 0.5
+ expect(charC.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.fontScaledImage);
+ expect(charD.texture.frame.x).to.equal(38); // 19 / 0.5
+ expect(charD.texture.frame.y).to.equal(48); // 24 / 0.5
+ expect(charD.texture.frame.width).to.equal(34); // 17 / 0.5
+ expect(charD.texture.frame.height).to.equal(40); // 20 / 0.5
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+
+ it('should properly register bitmap font NESTED into spritesheet', function (done)
+ {
+ const baseTexture = new PIXI.BaseTexture(this.atlasImage, null, 1);
+ const spritesheet = new PIXI.Spritesheet(baseTexture, this.atlasJSON);
+
+ spritesheet.parse(() =>
+ {
+ const fontTexture = PIXI.Texture.fromFrame('resources/font.png');
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, fontTexture);
+ const fontX = 158; // bare value from spritesheet frame
+ const fontY = 2; // bare value from spritesheet frame
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charA.texture.frame.x).to.equal(fontX + 2);
+ expect(charA.texture.frame.y).to.equal(fontY + 2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charB.texture.frame.x).to.equal(fontX + 2);
+ expect(charB.texture.frame.y).to.equal(fontY + 24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charC.texture.frame.x).to.equal(fontX + 23);
+ expect(charC.texture.frame.y).to.equal(fontY + 2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.atlasImage);
+ expect(charD.texture.frame.x).to.equal(fontX + 19);
+ expect(charD.texture.frame.y).to.equal(fontY + 24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+ });
+
+ it('should properly register bitmap font NESTED into SCALED spritesheet', function (done)
+ {
+ const baseTexture = new PIXI.BaseTexture(this.atlasScaledImage, null, 1);
+ const spritesheet = new PIXI.Spritesheet(baseTexture, this.atlasScaledJSON);
+
+ spritesheet.parse(() =>
+ {
+ const fontTexture = PIXI.Texture.fromFrame('resources/font.png');
+ const font = PIXI.extras.BitmapText.registerFont(this.fontXML, fontTexture);
+ const fontX = 158; // bare value from spritesheet frame
+ const fontY = 2; // bare value from spritesheet frame
+
+ expect(font).to.be.an.object;
+ expect(PIXI.extras.BitmapText.fonts.font).to.equal(font);
+ expect(font).to.have.property('chars');
+ const charA = font.chars['A'.charCodeAt(0) || 65];
+
+ expect(charA).to.exist;
+ expect(charA.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charA.texture.frame.x).to.equal(fontX + 2);
+ expect(charA.texture.frame.y).to.equal(fontY + 2);
+ expect(charA.texture.frame.width).to.equal(19);
+ expect(charA.texture.frame.height).to.equal(20);
+ const charB = font.chars['B'.charCodeAt(0) || 66];
+
+ expect(charB).to.exist;
+ expect(charB.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charB.texture.frame.x).to.equal(fontX + 2);
+ expect(charB.texture.frame.y).to.equal(fontY + 24);
+ expect(charB.texture.frame.width).to.equal(15);
+ expect(charB.texture.frame.height).to.equal(20);
+ const charC = font.chars['C'.charCodeAt(0) || 67];
+
+ expect(charC).to.exist;
+ expect(charC.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charC.texture.frame.x).to.equal(fontX + 23);
+ expect(charC.texture.frame.y).to.equal(fontY + 2);
+ expect(charC.texture.frame.width).to.equal(18);
+ expect(charC.texture.frame.height).to.equal(20);
+ const charD = font.chars['D'.charCodeAt(0) || 68];
+
+ expect(charD).to.exist;
+ expect(charD.texture.baseTexture.source).to.equal(this.atlasScaledImage);
+ expect(charD.texture.frame.x).to.equal(fontX + 19);
+ expect(charD.texture.frame.y).to.equal(fontY + 24);
+ expect(charD.texture.frame.width).to.equal(17);
+ expect(charD.texture.frame.height).to.equal(20);
+ const charE = font.chars['E'.charCodeAt(0) || 69];
+
+ expect(charE).to.be.undefined;
+ done();
+ });
+ });
});
describe('PIXI.loaders.parseBitmapFontData', function ()
diff --git a/test/loaders/resources/atlas.json b/test/loaders/resources/atlas.json
new file mode 100644
index 0000000..86e65a5
--- /dev/null
+++ b/test/loaders/resources/atlas.json
@@ -0,0 +1,25 @@
+{
+ "meta": {
+ "image": "atlas.png",
+ "size": {"w":256,"h":256},
+ "scale": "1"
+ },
+ "frames": {
+ "resources/test.png":
+ {
+ "frame": {"x":2,"y":2,"w":152,"h":188},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":74,"y":36,"w":152,"h":188},
+ "sourceSize": {"w":300,"h":225}
+ },
+ "resources/font.png":
+ {
+ "frame": {"x":158,"y":2,"w":40,"h":42},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":2,"y":2,"w":40,"h":42},
+ "sourceSize": {"w":43,"h":46}
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/loaders/resources/atlas.png b/test/loaders/resources/atlas.png
new file mode 100644
index 0000000..d5e7892
--- /dev/null
+++ b/test/loaders/resources/atlas.png
Binary files differ
diff --git a/test/loaders/resources/atlas@0.5x.json b/test/loaders/resources/atlas@0.5x.json
new file mode 100644
index 0000000..ae990a1
--- /dev/null
+++ b/test/loaders/resources/atlas@0.5x.json
@@ -0,0 +1,25 @@
+{
+ "meta": {
+ "image": "atlas@0.5x.png",
+ "size": {"w":256,"h":256},
+ "scale": "1"
+ },
+ "frames": {
+ "resources/test.png":
+ {
+ "frame": {"x":2,"y":2,"w":152,"h":188},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":74,"y":36,"w":152,"h":188},
+ "sourceSize": {"w":300,"h":225}
+ },
+ "resources/font.png":
+ {
+ "frame": {"x":158,"y":2,"w":40,"h":42},
+ "rotated": false,
+ "trimmed": true,
+ "spriteSourceSize": {"x":2,"y":2,"w":40,"h":42},
+ "sourceSize": {"w":43,"h":46}
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/loaders/resources/atlas@0.5x.png b/test/loaders/resources/atlas@0.5x.png
new file mode 100644
index 0000000..d5e7892
--- /dev/null
+++ b/test/loaders/resources/atlas@0.5x.png
Binary files differ
diff --git a/test/loaders/resources/font.fnt b/test/loaders/resources/font.fnt
new file mode 100644
index 0000000..56e1060
--- /dev/null
+++ b/test/loaders/resources/font.fnt
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/loaders/resources/font.png b/test/loaders/resources/font.png
new file mode 100644
index 0000000..cf772e9
--- /dev/null
+++ b/test/loaders/resources/font.png
Binary files differ
diff --git a/test/loaders/resources/font@0.5x.fnt b/test/loaders/resources/font@0.5x.fnt
new file mode 100644
index 0000000..6c247c7
--- /dev/null
+++ b/test/loaders/resources/font@0.5x.fnt
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test/loaders/resources/font@0.5x.png b/test/loaders/resources/font@0.5x.png
new file mode 100644
index 0000000..cf772e9
--- /dev/null
+++ b/test/loaders/resources/font@0.5x.png
Binary files differ