diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/src/core/display/TransformStatic.js b/src/core/display/TransformStatic.js index c0c2f33..1e8d0c6 100644 --- a/src/core/display/TransformStatic.js +++ b/src/core/display/TransformStatic.js @@ -47,12 +47,10 @@ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; this._localID = 0; this._currentLocalID = 0; @@ -69,16 +67,16 @@ } /** - * Called when skew changes + * Called when skew or rotation changes * * @private */ updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 this._localID ++; } @@ -93,15 +91,10 @@ if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -119,22 +112,15 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -147,6 +133,9 @@ if (this._parentID !== parentTransform._worldID) { // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -191,8 +180,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID ++; + this.updateSkew(); } } diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/src/core/display/TransformStatic.js b/src/core/display/TransformStatic.js index c0c2f33..1e8d0c6 100644 --- a/src/core/display/TransformStatic.js +++ b/src/core/display/TransformStatic.js @@ -47,12 +47,10 @@ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; this._localID = 0; this._currentLocalID = 0; @@ -69,16 +67,16 @@ } /** - * Called when skew changes + * Called when skew or rotation changes * * @private */ updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 this._localID ++; } @@ -93,15 +91,10 @@ if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -119,22 +112,15 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -147,6 +133,9 @@ if (this._parentID !== parentTransform._worldID) { // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -191,8 +180,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID ++; + this.updateSkew(); } } diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 9e65938..6f0a417 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -491,9 +491,10 @@ const startX = cx + (Math.cos(startAngle) * radius); const startY = cy + (Math.sin(startAngle) * radius); - const points = this.currentPath.shape.points; + // If the currentPath exists, take its points. Otherwise call `moveTo` to start a path. + let points = this.currentPath ? this.currentPath.shape.points : null; - if (this.currentPath) + if (points) { if (points[points.length - 2] !== startX || points[points.length - 1] !== startY) { @@ -503,6 +504,7 @@ else { this.moveTo(startX, startY); + points = this.currentPath.shape.points; } const theta = sweep / (segs * 2); @@ -691,6 +693,7 @@ this.lineWidth = 0; this.filling = false; + this.boundsDirty = -1; this.dirty++; this.clearDirty++; this.graphicsData.length = 0; diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/src/core/display/TransformStatic.js b/src/core/display/TransformStatic.js index c0c2f33..1e8d0c6 100644 --- a/src/core/display/TransformStatic.js +++ b/src/core/display/TransformStatic.js @@ -47,12 +47,10 @@ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; this._localID = 0; this._currentLocalID = 0; @@ -69,16 +67,16 @@ } /** - * Called when skew changes + * Called when skew or rotation changes * * @private */ updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 this._localID ++; } @@ -93,15 +91,10 @@ if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -119,22 +112,15 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -147,6 +133,9 @@ if (this._parentID !== parentTransform._worldID) { // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -191,8 +180,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID ++; + this.updateSkew(); } } diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 9e65938..6f0a417 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -491,9 +491,10 @@ const startX = cx + (Math.cos(startAngle) * radius); const startY = cy + (Math.sin(startAngle) * radius); - const points = this.currentPath.shape.points; + // If the currentPath exists, take its points. Otherwise call `moveTo` to start a path. + let points = this.currentPath ? this.currentPath.shape.points : null; - if (this.currentPath) + if (points) { if (points[points.length - 2] !== startX || points[points.length - 1] !== startY) { @@ -503,6 +504,7 @@ else { this.moveTo(startX, startY); + points = this.currentPath.shape.points; } const theta = sweep / (segs * 2); @@ -691,6 +693,7 @@ this.lineWidth = 0; this.filling = false; + this.boundsDirty = -1; this.dirty++; this.clearDirty++; this.graphicsData.length = 0; diff --git a/src/core/math/Matrix.js b/src/core/math/Matrix.js index e3341fe..0b77477 100644 --- a/src/core/math/Matrix.js +++ b/src/core/math/Matrix.js @@ -353,10 +353,10 @@ const c = this.c; const d = this.d; - const skewX = Math.atan2(-c, d); + const skewX = -Math.atan2(-c, d); const skewY = Math.atan2(b, a); - const delta = Math.abs(1 - (skewX / skewY)); + const delta = Math.abs(skewX + skewY); if (delta < 0.00001) { diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/src/core/display/TransformStatic.js b/src/core/display/TransformStatic.js index c0c2f33..1e8d0c6 100644 --- a/src/core/display/TransformStatic.js +++ b/src/core/display/TransformStatic.js @@ -47,12 +47,10 @@ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; this._localID = 0; this._currentLocalID = 0; @@ -69,16 +67,16 @@ } /** - * Called when skew changes + * Called when skew or rotation changes * * @private */ updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 this._localID ++; } @@ -93,15 +91,10 @@ if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -119,22 +112,15 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -147,6 +133,9 @@ if (this._parentID !== parentTransform._worldID) { // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -191,8 +180,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID ++; + this.updateSkew(); } } diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 9e65938..6f0a417 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -491,9 +491,10 @@ const startX = cx + (Math.cos(startAngle) * radius); const startY = cy + (Math.sin(startAngle) * radius); - const points = this.currentPath.shape.points; + // If the currentPath exists, take its points. Otherwise call `moveTo` to start a path. + let points = this.currentPath ? this.currentPath.shape.points : null; - if (this.currentPath) + if (points) { if (points[points.length - 2] !== startX || points[points.length - 1] !== startY) { @@ -503,6 +504,7 @@ else { this.moveTo(startX, startY); + points = this.currentPath.shape.points; } const theta = sweep / (segs * 2); @@ -691,6 +693,7 @@ this.lineWidth = 0; this.filling = false; + this.boundsDirty = -1; this.dirty++; this.clearDirty++; this.graphicsData.length = 0; diff --git a/src/core/math/Matrix.js b/src/core/math/Matrix.js index e3341fe..0b77477 100644 --- a/src/core/math/Matrix.js +++ b/src/core/math/Matrix.js @@ -353,10 +353,10 @@ const c = this.c; const d = this.d; - const skewX = Math.atan2(-c, d); + const skewX = -Math.atan2(-c, d); const skewY = Math.atan2(b, a); - const delta = Math.abs(1 - (skewX / skewY)); + const delta = Math.abs(skewX + skewY); if (delta < 0.00001) { diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js index afe4a89..c4f34be 100644 --- a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -2,7 +2,7 @@ * Creates a little colored canvas * * @ignore - * @param {number} color - The color to make the canvas + * @param {string} color - The color to make the canvas * @return {canvas} a small canvas element */ function createColoredCanvas(color) diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/src/core/display/TransformStatic.js b/src/core/display/TransformStatic.js index c0c2f33..1e8d0c6 100644 --- a/src/core/display/TransformStatic.js +++ b/src/core/display/TransformStatic.js @@ -47,12 +47,10 @@ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; this._localID = 0; this._currentLocalID = 0; @@ -69,16 +67,16 @@ } /** - * Called when skew changes + * Called when skew or rotation changes * * @private */ updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 this._localID ++; } @@ -93,15 +91,10 @@ if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -119,22 +112,15 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -147,6 +133,9 @@ if (this._parentID !== parentTransform._worldID) { // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -191,8 +180,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID ++; + this.updateSkew(); } } diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 9e65938..6f0a417 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -491,9 +491,10 @@ const startX = cx + (Math.cos(startAngle) * radius); const startY = cy + (Math.sin(startAngle) * radius); - const points = this.currentPath.shape.points; + // If the currentPath exists, take its points. Otherwise call `moveTo` to start a path. + let points = this.currentPath ? this.currentPath.shape.points : null; - if (this.currentPath) + if (points) { if (points[points.length - 2] !== startX || points[points.length - 1] !== startY) { @@ -503,6 +504,7 @@ else { this.moveTo(startX, startY); + points = this.currentPath.shape.points; } const theta = sweep / (segs * 2); @@ -691,6 +693,7 @@ this.lineWidth = 0; this.filling = false; + this.boundsDirty = -1; this.dirty++; this.clearDirty++; this.graphicsData.length = 0; diff --git a/src/core/math/Matrix.js b/src/core/math/Matrix.js index e3341fe..0b77477 100644 --- a/src/core/math/Matrix.js +++ b/src/core/math/Matrix.js @@ -353,10 +353,10 @@ const c = this.c; const d = this.d; - const skewX = Math.atan2(-c, d); + const skewX = -Math.atan2(-c, d); const skewY = Math.atan2(b, a); - const delta = Math.abs(1 - (skewX / skewY)); + const delta = Math.abs(skewX + skewY); if (delta < 0.00001) { diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js index afe4a89..c4f34be 100644 --- a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -2,7 +2,7 @@ * Creates a little colored canvas * * @ignore - * @param {number} color - The color to make the canvas + * @param {string} color - The color to make the canvas * @return {canvas} a small canvas element */ function createColoredCanvas(color) diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 3e58a00..025fef0 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -120,6 +120,15 @@ this._transformID = -1; this._textureID = -1; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'sprite' + */ + this.pluginName = 'sprite'; } /** @@ -282,8 +291,8 @@ { this.calculateVertices(); - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -294,7 +303,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.sprite.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/src/core/display/TransformStatic.js b/src/core/display/TransformStatic.js index c0c2f33..1e8d0c6 100644 --- a/src/core/display/TransformStatic.js +++ b/src/core/display/TransformStatic.js @@ -47,12 +47,10 @@ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; this._localID = 0; this._currentLocalID = 0; @@ -69,16 +67,16 @@ } /** - * Called when skew changes + * Called when skew or rotation changes * * @private */ updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 this._localID ++; } @@ -93,15 +91,10 @@ if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -119,22 +112,15 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -147,6 +133,9 @@ if (this._parentID !== parentTransform._worldID) { // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -191,8 +180,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID ++; + this.updateSkew(); } } diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 9e65938..6f0a417 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -491,9 +491,10 @@ const startX = cx + (Math.cos(startAngle) * radius); const startY = cy + (Math.sin(startAngle) * radius); - const points = this.currentPath.shape.points; + // If the currentPath exists, take its points. Otherwise call `moveTo` to start a path. + let points = this.currentPath ? this.currentPath.shape.points : null; - if (this.currentPath) + if (points) { if (points[points.length - 2] !== startX || points[points.length - 1] !== startY) { @@ -503,6 +504,7 @@ else { this.moveTo(startX, startY); + points = this.currentPath.shape.points; } const theta = sweep / (segs * 2); @@ -691,6 +693,7 @@ this.lineWidth = 0; this.filling = false; + this.boundsDirty = -1; this.dirty++; this.clearDirty++; this.graphicsData.length = 0; diff --git a/src/core/math/Matrix.js b/src/core/math/Matrix.js index e3341fe..0b77477 100644 --- a/src/core/math/Matrix.js +++ b/src/core/math/Matrix.js @@ -353,10 +353,10 @@ const c = this.c; const d = this.d; - const skewX = Math.atan2(-c, d); + const skewX = -Math.atan2(-c, d); const skewY = Math.atan2(b, a); - const delta = Math.abs(1 - (skewX / skewY)); + const delta = Math.abs(skewX + skewY); if (delta < 0.00001) { diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js index afe4a89..c4f34be 100644 --- a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -2,7 +2,7 @@ * Creates a little colored canvas * * @ignore - * @param {number} color - The color to make the canvas + * @param {string} color - The color to make the canvas * @return {canvas} a small canvas element */ function createColoredCanvas(color) diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 3e58a00..025fef0 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -120,6 +120,15 @@ this._transformID = -1; this._textureID = -1; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'sprite' + */ + this.pluginName = 'sprite'; } /** @@ -282,8 +291,8 @@ { this.calculateVertices(); - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -294,7 +303,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.sprite.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index 20d4a0a..faeb91c 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -97,7 +97,7 @@ { const clonedProperties = {}; - for (const key in this._defaults) + for (const key in defaultStyle) { clonedProperties[key] = this[key]; } @@ -110,7 +110,7 @@ */ reset() { - Object.assign(this, this._defaults); + Object.assign(this, defaultStyle); } get align() @@ -435,22 +435,43 @@ * @param {number|number[]} color * @return {string} The color as a string. */ -function getColor(color) +function getSingleColor(color) { if (typeof color === 'number') { return hex2string(color); } - else if (Array.isArray(color)) + else if ( typeof color === 'string' ) { - for (let i = 0; i < color.length; ++i) + if ( color.indexOf('0x') === 0 ) { - if (typeof color[i] === 'number') - { - color[i] = hex2string(color[i]); - } + color = color.replace('0x', '#'); } } return color; } + +/** + * Utility function to convert hexadecimal colors to strings, and simply return the color if it's a string. + * This version can also convert array of colors + * + * @param {number|number[]} color + * @return {string} The color as a string. + */ +function getColor(color) +{ + if (!Array.isArray(color)) + { + return getSingleColor(color); + } + else + { + for (let i = 0; i < color.length; ++i) + { + color[i] = getSingleColor(color[i]); + } + + return color; + } +} diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/src/core/display/TransformStatic.js b/src/core/display/TransformStatic.js index c0c2f33..1e8d0c6 100644 --- a/src/core/display/TransformStatic.js +++ b/src/core/display/TransformStatic.js @@ -47,12 +47,10 @@ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; this._localID = 0; this._currentLocalID = 0; @@ -69,16 +67,16 @@ } /** - * Called when skew changes + * Called when skew or rotation changes * * @private */ updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 this._localID ++; } @@ -93,15 +91,10 @@ if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -119,22 +112,15 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -147,6 +133,9 @@ if (this._parentID !== parentTransform._worldID) { // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -191,8 +180,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID ++; + this.updateSkew(); } } diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 9e65938..6f0a417 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -491,9 +491,10 @@ const startX = cx + (Math.cos(startAngle) * radius); const startY = cy + (Math.sin(startAngle) * radius); - const points = this.currentPath.shape.points; + // If the currentPath exists, take its points. Otherwise call `moveTo` to start a path. + let points = this.currentPath ? this.currentPath.shape.points : null; - if (this.currentPath) + if (points) { if (points[points.length - 2] !== startX || points[points.length - 1] !== startY) { @@ -503,6 +504,7 @@ else { this.moveTo(startX, startY); + points = this.currentPath.shape.points; } const theta = sweep / (segs * 2); @@ -691,6 +693,7 @@ this.lineWidth = 0; this.filling = false; + this.boundsDirty = -1; this.dirty++; this.clearDirty++; this.graphicsData.length = 0; diff --git a/src/core/math/Matrix.js b/src/core/math/Matrix.js index e3341fe..0b77477 100644 --- a/src/core/math/Matrix.js +++ b/src/core/math/Matrix.js @@ -353,10 +353,10 @@ const c = this.c; const d = this.d; - const skewX = Math.atan2(-c, d); + const skewX = -Math.atan2(-c, d); const skewY = Math.atan2(b, a); - const delta = Math.abs(1 - (skewX / skewY)); + const delta = Math.abs(skewX + skewY); if (delta < 0.00001) { diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js index afe4a89..c4f34be 100644 --- a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -2,7 +2,7 @@ * Creates a little colored canvas * * @ignore - * @param {number} color - The color to make the canvas + * @param {string} color - The color to make the canvas * @return {canvas} a small canvas element */ function createColoredCanvas(color) diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 3e58a00..025fef0 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -120,6 +120,15 @@ this._transformID = -1; this._textureID = -1; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'sprite' + */ + this.pluginName = 'sprite'; } /** @@ -282,8 +291,8 @@ { this.calculateVertices(); - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -294,7 +303,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.sprite.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index 20d4a0a..faeb91c 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -97,7 +97,7 @@ { const clonedProperties = {}; - for (const key in this._defaults) + for (const key in defaultStyle) { clonedProperties[key] = this[key]; } @@ -110,7 +110,7 @@ */ reset() { - Object.assign(this, this._defaults); + Object.assign(this, defaultStyle); } get align() @@ -435,22 +435,43 @@ * @param {number|number[]} color * @return {string} The color as a string. */ -function getColor(color) +function getSingleColor(color) { if (typeof color === 'number') { return hex2string(color); } - else if (Array.isArray(color)) + else if ( typeof color === 'string' ) { - for (let i = 0; i < color.length; ++i) + if ( color.indexOf('0x') === 0 ) { - if (typeof color[i] === 'number') - { - color[i] = hex2string(color[i]); - } + color = color.replace('0x', '#'); } } return color; } + +/** + * Utility function to convert hexadecimal colors to strings, and simply return the color if it's a string. + * This version can also convert array of colors + * + * @param {number|number[]} color + * @return {string} The color as a string. + */ +function getColor(color) +{ + if (!Array.isArray(color)) + { + return getSingleColor(color); + } + else + { + for (let i = 0; i < color.length; ++i) + { + color[i] = getSingleColor(color[i]); + } + + return color; + } +} diff --git a/src/core/utils/index.js b/src/core/utils/index.js index c82aaa4..2a7497b 100644 --- a/src/core/utils/index.js +++ b/src/core/utils/index.js @@ -103,9 +103,10 @@ * @memberof PIXI.utils * @function getResolutionOfUrl * @param {string} url - the image path + * @param {number} [defaultValue=1] - the defaultValue if no filename prefix is set. * @return {number} resolution / device pixel ratio of an asset */ -export function getResolutionOfUrl(url) +export function getResolutionOfUrl(url, defaultValue) { const resolution = settings.RETINA_PREFIX.exec(url); @@ -114,7 +115,7 @@ return parseFloat(resolution[1]); } - return 1; + return defaultValue !== undefined ? defaultValue : 1; } /** diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/src/core/display/TransformStatic.js b/src/core/display/TransformStatic.js index c0c2f33..1e8d0c6 100644 --- a/src/core/display/TransformStatic.js +++ b/src/core/display/TransformStatic.js @@ -47,12 +47,10 @@ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; this._localID = 0; this._currentLocalID = 0; @@ -69,16 +67,16 @@ } /** - * Called when skew changes + * Called when skew or rotation changes * * @private */ updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 this._localID ++; } @@ -93,15 +91,10 @@ if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -119,22 +112,15 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -147,6 +133,9 @@ if (this._parentID !== parentTransform._worldID) { // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -191,8 +180,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID ++; + this.updateSkew(); } } diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 9e65938..6f0a417 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -491,9 +491,10 @@ const startX = cx + (Math.cos(startAngle) * radius); const startY = cy + (Math.sin(startAngle) * radius); - const points = this.currentPath.shape.points; + // If the currentPath exists, take its points. Otherwise call `moveTo` to start a path. + let points = this.currentPath ? this.currentPath.shape.points : null; - if (this.currentPath) + if (points) { if (points[points.length - 2] !== startX || points[points.length - 1] !== startY) { @@ -503,6 +504,7 @@ else { this.moveTo(startX, startY); + points = this.currentPath.shape.points; } const theta = sweep / (segs * 2); @@ -691,6 +693,7 @@ this.lineWidth = 0; this.filling = false; + this.boundsDirty = -1; this.dirty++; this.clearDirty++; this.graphicsData.length = 0; diff --git a/src/core/math/Matrix.js b/src/core/math/Matrix.js index e3341fe..0b77477 100644 --- a/src/core/math/Matrix.js +++ b/src/core/math/Matrix.js @@ -353,10 +353,10 @@ const c = this.c; const d = this.d; - const skewX = Math.atan2(-c, d); + const skewX = -Math.atan2(-c, d); const skewY = Math.atan2(b, a); - const delta = Math.abs(1 - (skewX / skewY)); + const delta = Math.abs(skewX + skewY); if (delta < 0.00001) { diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js index afe4a89..c4f34be 100644 --- a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -2,7 +2,7 @@ * Creates a little colored canvas * * @ignore - * @param {number} color - The color to make the canvas + * @param {string} color - The color to make the canvas * @return {canvas} a small canvas element */ function createColoredCanvas(color) diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 3e58a00..025fef0 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -120,6 +120,15 @@ this._transformID = -1; this._textureID = -1; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'sprite' + */ + this.pluginName = 'sprite'; } /** @@ -282,8 +291,8 @@ { this.calculateVertices(); - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -294,7 +303,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.sprite.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index 20d4a0a..faeb91c 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -97,7 +97,7 @@ { const clonedProperties = {}; - for (const key in this._defaults) + for (const key in defaultStyle) { clonedProperties[key] = this[key]; } @@ -110,7 +110,7 @@ */ reset() { - Object.assign(this, this._defaults); + Object.assign(this, defaultStyle); } get align() @@ -435,22 +435,43 @@ * @param {number|number[]} color * @return {string} The color as a string. */ -function getColor(color) +function getSingleColor(color) { if (typeof color === 'number') { return hex2string(color); } - else if (Array.isArray(color)) + else if ( typeof color === 'string' ) { - for (let i = 0; i < color.length; ++i) + if ( color.indexOf('0x') === 0 ) { - if (typeof color[i] === 'number') - { - color[i] = hex2string(color[i]); - } + color = color.replace('0x', '#'); } } return color; } + +/** + * Utility function to convert hexadecimal colors to strings, and simply return the color if it's a string. + * This version can also convert array of colors + * + * @param {number|number[]} color + * @return {string} The color as a string. + */ +function getColor(color) +{ + if (!Array.isArray(color)) + { + return getSingleColor(color); + } + else + { + for (let i = 0; i < color.length; ++i) + { + color[i] = getSingleColor(color[i]); + } + + return color; + } +} diff --git a/src/core/utils/index.js b/src/core/utils/index.js index c82aaa4..2a7497b 100644 --- a/src/core/utils/index.js +++ b/src/core/utils/index.js @@ -103,9 +103,10 @@ * @memberof PIXI.utils * @function getResolutionOfUrl * @param {string} url - the image path + * @param {number} [defaultValue=1] - the defaultValue if no filename prefix is set. * @return {number} resolution / device pixel ratio of an asset */ -export function getResolutionOfUrl(url) +export function getResolutionOfUrl(url, defaultValue) { const resolution = settings.RETINA_PREFIX.exec(url); @@ -114,7 +115,7 @@ return parseFloat(resolution[1]); } - return 1; + return defaultValue !== undefined ? defaultValue : 1; } /** diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js index b9352e6..a8bcfba 100644 --- a/src/extras/TilingSprite.js +++ b/src/extras/TilingSprite.js @@ -61,6 +61,15 @@ * @member {PIXI.extras.TextureTransform} */ this.uvTransform = texture.transform || new TextureTransform(texture); + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' method. + * + * @member {string} + * @default 'tilingSprite' + */ + this.pluginName = 'tilingSprite'; } /** * Changes frame clamping in corresponding textureTransform, shortcut @@ -158,8 +167,8 @@ this.tileTransform.updateLocalTransform(); this.uvTransform.update(); - renderer.setObjectRenderer(renderer.plugins.tilingSprite); - renderer.plugins.tilingSprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/src/core/display/TransformStatic.js b/src/core/display/TransformStatic.js index c0c2f33..1e8d0c6 100644 --- a/src/core/display/TransformStatic.js +++ b/src/core/display/TransformStatic.js @@ -47,12 +47,10 @@ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; this._localID = 0; this._currentLocalID = 0; @@ -69,16 +67,16 @@ } /** - * Called when skew changes + * Called when skew or rotation changes * * @private */ updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 this._localID ++; } @@ -93,15 +91,10 @@ if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -119,22 +112,15 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -147,6 +133,9 @@ if (this._parentID !== parentTransform._worldID) { // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -191,8 +180,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID ++; + this.updateSkew(); } } diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 9e65938..6f0a417 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -491,9 +491,10 @@ const startX = cx + (Math.cos(startAngle) * radius); const startY = cy + (Math.sin(startAngle) * radius); - const points = this.currentPath.shape.points; + // If the currentPath exists, take its points. Otherwise call `moveTo` to start a path. + let points = this.currentPath ? this.currentPath.shape.points : null; - if (this.currentPath) + if (points) { if (points[points.length - 2] !== startX || points[points.length - 1] !== startY) { @@ -503,6 +504,7 @@ else { this.moveTo(startX, startY); + points = this.currentPath.shape.points; } const theta = sweep / (segs * 2); @@ -691,6 +693,7 @@ this.lineWidth = 0; this.filling = false; + this.boundsDirty = -1; this.dirty++; this.clearDirty++; this.graphicsData.length = 0; diff --git a/src/core/math/Matrix.js b/src/core/math/Matrix.js index e3341fe..0b77477 100644 --- a/src/core/math/Matrix.js +++ b/src/core/math/Matrix.js @@ -353,10 +353,10 @@ const c = this.c; const d = this.d; - const skewX = Math.atan2(-c, d); + const skewX = -Math.atan2(-c, d); const skewY = Math.atan2(b, a); - const delta = Math.abs(1 - (skewX / skewY)); + const delta = Math.abs(skewX + skewY); if (delta < 0.00001) { diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js index afe4a89..c4f34be 100644 --- a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -2,7 +2,7 @@ * Creates a little colored canvas * * @ignore - * @param {number} color - The color to make the canvas + * @param {string} color - The color to make the canvas * @return {canvas} a small canvas element */ function createColoredCanvas(color) diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 3e58a00..025fef0 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -120,6 +120,15 @@ this._transformID = -1; this._textureID = -1; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'sprite' + */ + this.pluginName = 'sprite'; } /** @@ -282,8 +291,8 @@ { this.calculateVertices(); - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -294,7 +303,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.sprite.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index 20d4a0a..faeb91c 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -97,7 +97,7 @@ { const clonedProperties = {}; - for (const key in this._defaults) + for (const key in defaultStyle) { clonedProperties[key] = this[key]; } @@ -110,7 +110,7 @@ */ reset() { - Object.assign(this, this._defaults); + Object.assign(this, defaultStyle); } get align() @@ -435,22 +435,43 @@ * @param {number|number[]} color * @return {string} The color as a string. */ -function getColor(color) +function getSingleColor(color) { if (typeof color === 'number') { return hex2string(color); } - else if (Array.isArray(color)) + else if ( typeof color === 'string' ) { - for (let i = 0; i < color.length; ++i) + if ( color.indexOf('0x') === 0 ) { - if (typeof color[i] === 'number') - { - color[i] = hex2string(color[i]); - } + color = color.replace('0x', '#'); } } return color; } + +/** + * Utility function to convert hexadecimal colors to strings, and simply return the color if it's a string. + * This version can also convert array of colors + * + * @param {number|number[]} color + * @return {string} The color as a string. + */ +function getColor(color) +{ + if (!Array.isArray(color)) + { + return getSingleColor(color); + } + else + { + for (let i = 0; i < color.length; ++i) + { + color[i] = getSingleColor(color[i]); + } + + return color; + } +} diff --git a/src/core/utils/index.js b/src/core/utils/index.js index c82aaa4..2a7497b 100644 --- a/src/core/utils/index.js +++ b/src/core/utils/index.js @@ -103,9 +103,10 @@ * @memberof PIXI.utils * @function getResolutionOfUrl * @param {string} url - the image path + * @param {number} [defaultValue=1] - the defaultValue if no filename prefix is set. * @return {number} resolution / device pixel ratio of an asset */ -export function getResolutionOfUrl(url) +export function getResolutionOfUrl(url, defaultValue) { const resolution = settings.RETINA_PREFIX.exec(url); @@ -114,7 +115,7 @@ return parseFloat(resolution[1]); } - return 1; + return defaultValue !== undefined ? defaultValue : 1; } /** diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js index b9352e6..a8bcfba 100644 --- a/src/extras/TilingSprite.js +++ b/src/extras/TilingSprite.js @@ -61,6 +61,15 @@ * @member {PIXI.extras.TextureTransform} */ this.uvTransform = texture.transform || new TextureTransform(texture); + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' method. + * + * @member {string} + * @default 'tilingSprite' + */ + this.pluginName = 'tilingSprite'; } /** * Changes frame clamping in corresponding textureTransform, shortcut @@ -158,8 +167,8 @@ this.tileTransform.updateLocalTransform(); this.uvTransform.update(); - renderer.setObjectRenderer(renderer.plugins.tilingSprite); - renderer.plugins.tilingSprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/filters/blur/BlurFilter.js b/src/filters/blur/BlurFilter.js index 5b3c3a9..8a05893 100644 --- a/src/filters/blur/BlurFilter.js +++ b/src/filters/blur/BlurFilter.js @@ -15,14 +15,15 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { super(); - this.blurXFilter = new BlurXFilter(); - this.blurYFilter = new BlurYFilter(); + this.blurXFilter = new BlurXFilter(strength, quality, resolution, kernelSize); + this.blurYFilter = new BlurYFilter(strength, quality, resolution, kernelSize); this.resolution = 1; this.padding = 0; diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/src/core/display/TransformStatic.js b/src/core/display/TransformStatic.js index c0c2f33..1e8d0c6 100644 --- a/src/core/display/TransformStatic.js +++ b/src/core/display/TransformStatic.js @@ -47,12 +47,10 @@ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; this._localID = 0; this._currentLocalID = 0; @@ -69,16 +67,16 @@ } /** - * Called when skew changes + * Called when skew or rotation changes * * @private */ updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 this._localID ++; } @@ -93,15 +91,10 @@ if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -119,22 +112,15 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -147,6 +133,9 @@ if (this._parentID !== parentTransform._worldID) { // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -191,8 +180,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID ++; + this.updateSkew(); } } diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 9e65938..6f0a417 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -491,9 +491,10 @@ const startX = cx + (Math.cos(startAngle) * radius); const startY = cy + (Math.sin(startAngle) * radius); - const points = this.currentPath.shape.points; + // If the currentPath exists, take its points. Otherwise call `moveTo` to start a path. + let points = this.currentPath ? this.currentPath.shape.points : null; - if (this.currentPath) + if (points) { if (points[points.length - 2] !== startX || points[points.length - 1] !== startY) { @@ -503,6 +504,7 @@ else { this.moveTo(startX, startY); + points = this.currentPath.shape.points; } const theta = sweep / (segs * 2); @@ -691,6 +693,7 @@ this.lineWidth = 0; this.filling = false; + this.boundsDirty = -1; this.dirty++; this.clearDirty++; this.graphicsData.length = 0; diff --git a/src/core/math/Matrix.js b/src/core/math/Matrix.js index e3341fe..0b77477 100644 --- a/src/core/math/Matrix.js +++ b/src/core/math/Matrix.js @@ -353,10 +353,10 @@ const c = this.c; const d = this.d; - const skewX = Math.atan2(-c, d); + const skewX = -Math.atan2(-c, d); const skewY = Math.atan2(b, a); - const delta = Math.abs(1 - (skewX / skewY)); + const delta = Math.abs(skewX + skewY); if (delta < 0.00001) { diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js index afe4a89..c4f34be 100644 --- a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -2,7 +2,7 @@ * Creates a little colored canvas * * @ignore - * @param {number} color - The color to make the canvas + * @param {string} color - The color to make the canvas * @return {canvas} a small canvas element */ function createColoredCanvas(color) diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 3e58a00..025fef0 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -120,6 +120,15 @@ this._transformID = -1; this._textureID = -1; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'sprite' + */ + this.pluginName = 'sprite'; } /** @@ -282,8 +291,8 @@ { this.calculateVertices(); - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -294,7 +303,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.sprite.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index 20d4a0a..faeb91c 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -97,7 +97,7 @@ { const clonedProperties = {}; - for (const key in this._defaults) + for (const key in defaultStyle) { clonedProperties[key] = this[key]; } @@ -110,7 +110,7 @@ */ reset() { - Object.assign(this, this._defaults); + Object.assign(this, defaultStyle); } get align() @@ -435,22 +435,43 @@ * @param {number|number[]} color * @return {string} The color as a string. */ -function getColor(color) +function getSingleColor(color) { if (typeof color === 'number') { return hex2string(color); } - else if (Array.isArray(color)) + else if ( typeof color === 'string' ) { - for (let i = 0; i < color.length; ++i) + if ( color.indexOf('0x') === 0 ) { - if (typeof color[i] === 'number') - { - color[i] = hex2string(color[i]); - } + color = color.replace('0x', '#'); } } return color; } + +/** + * Utility function to convert hexadecimal colors to strings, and simply return the color if it's a string. + * This version can also convert array of colors + * + * @param {number|number[]} color + * @return {string} The color as a string. + */ +function getColor(color) +{ + if (!Array.isArray(color)) + { + return getSingleColor(color); + } + else + { + for (let i = 0; i < color.length; ++i) + { + color[i] = getSingleColor(color[i]); + } + + return color; + } +} diff --git a/src/core/utils/index.js b/src/core/utils/index.js index c82aaa4..2a7497b 100644 --- a/src/core/utils/index.js +++ b/src/core/utils/index.js @@ -103,9 +103,10 @@ * @memberof PIXI.utils * @function getResolutionOfUrl * @param {string} url - the image path + * @param {number} [defaultValue=1] - the defaultValue if no filename prefix is set. * @return {number} resolution / device pixel ratio of an asset */ -export function getResolutionOfUrl(url) +export function getResolutionOfUrl(url, defaultValue) { const resolution = settings.RETINA_PREFIX.exec(url); @@ -114,7 +115,7 @@ return parseFloat(resolution[1]); } - return 1; + return defaultValue !== undefined ? defaultValue : 1; } /** diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js index b9352e6..a8bcfba 100644 --- a/src/extras/TilingSprite.js +++ b/src/extras/TilingSprite.js @@ -61,6 +61,15 @@ * @member {PIXI.extras.TextureTransform} */ this.uvTransform = texture.transform || new TextureTransform(texture); + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' method. + * + * @member {string} + * @default 'tilingSprite' + */ + this.pluginName = 'tilingSprite'; } /** * Changes frame clamping in corresponding textureTransform, shortcut @@ -158,8 +167,8 @@ this.tileTransform.updateLocalTransform(); this.uvTransform.update(); - renderer.setObjectRenderer(renderer.plugins.tilingSprite); - renderer.plugins.tilingSprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/filters/blur/BlurFilter.js b/src/filters/blur/BlurFilter.js index 5b3c3a9..8a05893 100644 --- a/src/filters/blur/BlurFilter.js +++ b/src/filters/blur/BlurFilter.js @@ -15,14 +15,15 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { super(); - this.blurXFilter = new BlurXFilter(); - this.blurYFilter = new BlurYFilter(); + this.blurXFilter = new BlurXFilter(strength, quality, resolution, kernelSize); + this.blurYFilter = new BlurYFilter(strength, quality, resolution, kernelSize); this.resolution = 1; this.padding = 0; diff --git a/src/filters/blur/BlurXFilter.js b/src/filters/blur/BlurXFilter.js index 24181b6..338096c 100644 --- a/src/filters/blur/BlurXFilter.js +++ b/src/filters/blur/BlurXFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, true); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, true); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/src/core/display/TransformStatic.js b/src/core/display/TransformStatic.js index c0c2f33..1e8d0c6 100644 --- a/src/core/display/TransformStatic.js +++ b/src/core/display/TransformStatic.js @@ -47,12 +47,10 @@ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; this._localID = 0; this._currentLocalID = 0; @@ -69,16 +67,16 @@ } /** - * Called when skew changes + * Called when skew or rotation changes * * @private */ updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 this._localID ++; } @@ -93,15 +91,10 @@ if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -119,22 +112,15 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -147,6 +133,9 @@ if (this._parentID !== parentTransform._worldID) { // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -191,8 +180,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID ++; + this.updateSkew(); } } diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 9e65938..6f0a417 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -491,9 +491,10 @@ const startX = cx + (Math.cos(startAngle) * radius); const startY = cy + (Math.sin(startAngle) * radius); - const points = this.currentPath.shape.points; + // If the currentPath exists, take its points. Otherwise call `moveTo` to start a path. + let points = this.currentPath ? this.currentPath.shape.points : null; - if (this.currentPath) + if (points) { if (points[points.length - 2] !== startX || points[points.length - 1] !== startY) { @@ -503,6 +504,7 @@ else { this.moveTo(startX, startY); + points = this.currentPath.shape.points; } const theta = sweep / (segs * 2); @@ -691,6 +693,7 @@ this.lineWidth = 0; this.filling = false; + this.boundsDirty = -1; this.dirty++; this.clearDirty++; this.graphicsData.length = 0; diff --git a/src/core/math/Matrix.js b/src/core/math/Matrix.js index e3341fe..0b77477 100644 --- a/src/core/math/Matrix.js +++ b/src/core/math/Matrix.js @@ -353,10 +353,10 @@ const c = this.c; const d = this.d; - const skewX = Math.atan2(-c, d); + const skewX = -Math.atan2(-c, d); const skewY = Math.atan2(b, a); - const delta = Math.abs(1 - (skewX / skewY)); + const delta = Math.abs(skewX + skewY); if (delta < 0.00001) { diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js index afe4a89..c4f34be 100644 --- a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -2,7 +2,7 @@ * Creates a little colored canvas * * @ignore - * @param {number} color - The color to make the canvas + * @param {string} color - The color to make the canvas * @return {canvas} a small canvas element */ function createColoredCanvas(color) diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 3e58a00..025fef0 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -120,6 +120,15 @@ this._transformID = -1; this._textureID = -1; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'sprite' + */ + this.pluginName = 'sprite'; } /** @@ -282,8 +291,8 @@ { this.calculateVertices(); - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -294,7 +303,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.sprite.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index 20d4a0a..faeb91c 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -97,7 +97,7 @@ { const clonedProperties = {}; - for (const key in this._defaults) + for (const key in defaultStyle) { clonedProperties[key] = this[key]; } @@ -110,7 +110,7 @@ */ reset() { - Object.assign(this, this._defaults); + Object.assign(this, defaultStyle); } get align() @@ -435,22 +435,43 @@ * @param {number|number[]} color * @return {string} The color as a string. */ -function getColor(color) +function getSingleColor(color) { if (typeof color === 'number') { return hex2string(color); } - else if (Array.isArray(color)) + else if ( typeof color === 'string' ) { - for (let i = 0; i < color.length; ++i) + if ( color.indexOf('0x') === 0 ) { - if (typeof color[i] === 'number') - { - color[i] = hex2string(color[i]); - } + color = color.replace('0x', '#'); } } return color; } + +/** + * Utility function to convert hexadecimal colors to strings, and simply return the color if it's a string. + * This version can also convert array of colors + * + * @param {number|number[]} color + * @return {string} The color as a string. + */ +function getColor(color) +{ + if (!Array.isArray(color)) + { + return getSingleColor(color); + } + else + { + for (let i = 0; i < color.length; ++i) + { + color[i] = getSingleColor(color[i]); + } + + return color; + } +} diff --git a/src/core/utils/index.js b/src/core/utils/index.js index c82aaa4..2a7497b 100644 --- a/src/core/utils/index.js +++ b/src/core/utils/index.js @@ -103,9 +103,10 @@ * @memberof PIXI.utils * @function getResolutionOfUrl * @param {string} url - the image path + * @param {number} [defaultValue=1] - the defaultValue if no filename prefix is set. * @return {number} resolution / device pixel ratio of an asset */ -export function getResolutionOfUrl(url) +export function getResolutionOfUrl(url, defaultValue) { const resolution = settings.RETINA_PREFIX.exec(url); @@ -114,7 +115,7 @@ return parseFloat(resolution[1]); } - return 1; + return defaultValue !== undefined ? defaultValue : 1; } /** diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js index b9352e6..a8bcfba 100644 --- a/src/extras/TilingSprite.js +++ b/src/extras/TilingSprite.js @@ -61,6 +61,15 @@ * @member {PIXI.extras.TextureTransform} */ this.uvTransform = texture.transform || new TextureTransform(texture); + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' method. + * + * @member {string} + * @default 'tilingSprite' + */ + this.pluginName = 'tilingSprite'; } /** * Changes frame clamping in corresponding textureTransform, shortcut @@ -158,8 +167,8 @@ this.tileTransform.updateLocalTransform(); this.uvTransform.update(); - renderer.setObjectRenderer(renderer.plugins.tilingSprite); - renderer.plugins.tilingSprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/filters/blur/BlurFilter.js b/src/filters/blur/BlurFilter.js index 5b3c3a9..8a05893 100644 --- a/src/filters/blur/BlurFilter.js +++ b/src/filters/blur/BlurFilter.js @@ -15,14 +15,15 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { super(); - this.blurXFilter = new BlurXFilter(); - this.blurYFilter = new BlurYFilter(); + this.blurXFilter = new BlurXFilter(strength, quality, resolution, kernelSize); + this.blurYFilter = new BlurYFilter(strength, quality, resolution, kernelSize); this.resolution = 1; this.padding = 0; diff --git a/src/filters/blur/BlurXFilter.js b/src/filters/blur/BlurXFilter.js index 24181b6..338096c 100644 --- a/src/filters/blur/BlurXFilter.js +++ b/src/filters/blur/BlurXFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, true); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, true); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/filters/blur/BlurYFilter.js b/src/filters/blur/BlurYFilter.js index 267728b..94cbf37 100644 --- a/src/filters/blur/BlurYFilter.js +++ b/src/filters/blur/BlurYFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, false); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, false); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/src/core/display/TransformStatic.js b/src/core/display/TransformStatic.js index c0c2f33..1e8d0c6 100644 --- a/src/core/display/TransformStatic.js +++ b/src/core/display/TransformStatic.js @@ -47,12 +47,10 @@ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; this._localID = 0; this._currentLocalID = 0; @@ -69,16 +67,16 @@ } /** - * Called when skew changes + * Called when skew or rotation changes * * @private */ updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 this._localID ++; } @@ -93,15 +91,10 @@ if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -119,22 +112,15 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -147,6 +133,9 @@ if (this._parentID !== parentTransform._worldID) { // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -191,8 +180,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID ++; + this.updateSkew(); } } diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 9e65938..6f0a417 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -491,9 +491,10 @@ const startX = cx + (Math.cos(startAngle) * radius); const startY = cy + (Math.sin(startAngle) * radius); - const points = this.currentPath.shape.points; + // If the currentPath exists, take its points. Otherwise call `moveTo` to start a path. + let points = this.currentPath ? this.currentPath.shape.points : null; - if (this.currentPath) + if (points) { if (points[points.length - 2] !== startX || points[points.length - 1] !== startY) { @@ -503,6 +504,7 @@ else { this.moveTo(startX, startY); + points = this.currentPath.shape.points; } const theta = sweep / (segs * 2); @@ -691,6 +693,7 @@ this.lineWidth = 0; this.filling = false; + this.boundsDirty = -1; this.dirty++; this.clearDirty++; this.graphicsData.length = 0; diff --git a/src/core/math/Matrix.js b/src/core/math/Matrix.js index e3341fe..0b77477 100644 --- a/src/core/math/Matrix.js +++ b/src/core/math/Matrix.js @@ -353,10 +353,10 @@ const c = this.c; const d = this.d; - const skewX = Math.atan2(-c, d); + const skewX = -Math.atan2(-c, d); const skewY = Math.atan2(b, a); - const delta = Math.abs(1 - (skewX / skewY)); + const delta = Math.abs(skewX + skewY); if (delta < 0.00001) { diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js index afe4a89..c4f34be 100644 --- a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -2,7 +2,7 @@ * Creates a little colored canvas * * @ignore - * @param {number} color - The color to make the canvas + * @param {string} color - The color to make the canvas * @return {canvas} a small canvas element */ function createColoredCanvas(color) diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 3e58a00..025fef0 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -120,6 +120,15 @@ this._transformID = -1; this._textureID = -1; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'sprite' + */ + this.pluginName = 'sprite'; } /** @@ -282,8 +291,8 @@ { this.calculateVertices(); - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -294,7 +303,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.sprite.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index 20d4a0a..faeb91c 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -97,7 +97,7 @@ { const clonedProperties = {}; - for (const key in this._defaults) + for (const key in defaultStyle) { clonedProperties[key] = this[key]; } @@ -110,7 +110,7 @@ */ reset() { - Object.assign(this, this._defaults); + Object.assign(this, defaultStyle); } get align() @@ -435,22 +435,43 @@ * @param {number|number[]} color * @return {string} The color as a string. */ -function getColor(color) +function getSingleColor(color) { if (typeof color === 'number') { return hex2string(color); } - else if (Array.isArray(color)) + else if ( typeof color === 'string' ) { - for (let i = 0; i < color.length; ++i) + if ( color.indexOf('0x') === 0 ) { - if (typeof color[i] === 'number') - { - color[i] = hex2string(color[i]); - } + color = color.replace('0x', '#'); } } return color; } + +/** + * Utility function to convert hexadecimal colors to strings, and simply return the color if it's a string. + * This version can also convert array of colors + * + * @param {number|number[]} color + * @return {string} The color as a string. + */ +function getColor(color) +{ + if (!Array.isArray(color)) + { + return getSingleColor(color); + } + else + { + for (let i = 0; i < color.length; ++i) + { + color[i] = getSingleColor(color[i]); + } + + return color; + } +} diff --git a/src/core/utils/index.js b/src/core/utils/index.js index c82aaa4..2a7497b 100644 --- a/src/core/utils/index.js +++ b/src/core/utils/index.js @@ -103,9 +103,10 @@ * @memberof PIXI.utils * @function getResolutionOfUrl * @param {string} url - the image path + * @param {number} [defaultValue=1] - the defaultValue if no filename prefix is set. * @return {number} resolution / device pixel ratio of an asset */ -export function getResolutionOfUrl(url) +export function getResolutionOfUrl(url, defaultValue) { const resolution = settings.RETINA_PREFIX.exec(url); @@ -114,7 +115,7 @@ return parseFloat(resolution[1]); } - return 1; + return defaultValue !== undefined ? defaultValue : 1; } /** diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js index b9352e6..a8bcfba 100644 --- a/src/extras/TilingSprite.js +++ b/src/extras/TilingSprite.js @@ -61,6 +61,15 @@ * @member {PIXI.extras.TextureTransform} */ this.uvTransform = texture.transform || new TextureTransform(texture); + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' method. + * + * @member {string} + * @default 'tilingSprite' + */ + this.pluginName = 'tilingSprite'; } /** * Changes frame clamping in corresponding textureTransform, shortcut @@ -158,8 +167,8 @@ this.tileTransform.updateLocalTransform(); this.uvTransform.update(); - renderer.setObjectRenderer(renderer.plugins.tilingSprite); - renderer.plugins.tilingSprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/filters/blur/BlurFilter.js b/src/filters/blur/BlurFilter.js index 5b3c3a9..8a05893 100644 --- a/src/filters/blur/BlurFilter.js +++ b/src/filters/blur/BlurFilter.js @@ -15,14 +15,15 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { super(); - this.blurXFilter = new BlurXFilter(); - this.blurYFilter = new BlurYFilter(); + this.blurXFilter = new BlurXFilter(strength, quality, resolution, kernelSize); + this.blurYFilter = new BlurYFilter(strength, quality, resolution, kernelSize); this.resolution = 1; this.padding = 0; diff --git a/src/filters/blur/BlurXFilter.js b/src/filters/blur/BlurXFilter.js index 24181b6..338096c 100644 --- a/src/filters/blur/BlurXFilter.js +++ b/src/filters/blur/BlurXFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, true); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, true); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/filters/blur/BlurYFilter.js b/src/filters/blur/BlurYFilter.js index 267728b..94cbf37 100644 --- a/src/filters/blur/BlurYFilter.js +++ b/src/filters/blur/BlurYFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, false); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, false); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/interaction/InteractionEvent.js b/src/interaction/InteractionEvent.js index 0342469..75b2966 100644 --- a/src/interaction/InteractionEvent.js +++ b/src/interaction/InteractionEvent.js @@ -12,14 +12,15 @@ constructor() { /** - * Which this event will continue propagating in the tree + * Whether this event will continue propagating in the tree * * @member {boolean} */ this.stopped = false; /** - * The object to which event is dispatched. + * The object which caused this event to be dispatched. + * For listener callback see {@link PIXI.interaction.InteractionEvent.currentTarget}. * * @member {PIXI.DisplayObject} */ diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/src/core/display/TransformStatic.js b/src/core/display/TransformStatic.js index c0c2f33..1e8d0c6 100644 --- a/src/core/display/TransformStatic.js +++ b/src/core/display/TransformStatic.js @@ -47,12 +47,10 @@ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; this._localID = 0; this._currentLocalID = 0; @@ -69,16 +67,16 @@ } /** - * Called when skew changes + * Called when skew or rotation changes * * @private */ updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 this._localID ++; } @@ -93,15 +91,10 @@ if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -119,22 +112,15 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -147,6 +133,9 @@ if (this._parentID !== parentTransform._worldID) { // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -191,8 +180,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID ++; + this.updateSkew(); } } diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 9e65938..6f0a417 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -491,9 +491,10 @@ const startX = cx + (Math.cos(startAngle) * radius); const startY = cy + (Math.sin(startAngle) * radius); - const points = this.currentPath.shape.points; + // If the currentPath exists, take its points. Otherwise call `moveTo` to start a path. + let points = this.currentPath ? this.currentPath.shape.points : null; - if (this.currentPath) + if (points) { if (points[points.length - 2] !== startX || points[points.length - 1] !== startY) { @@ -503,6 +504,7 @@ else { this.moveTo(startX, startY); + points = this.currentPath.shape.points; } const theta = sweep / (segs * 2); @@ -691,6 +693,7 @@ this.lineWidth = 0; this.filling = false; + this.boundsDirty = -1; this.dirty++; this.clearDirty++; this.graphicsData.length = 0; diff --git a/src/core/math/Matrix.js b/src/core/math/Matrix.js index e3341fe..0b77477 100644 --- a/src/core/math/Matrix.js +++ b/src/core/math/Matrix.js @@ -353,10 +353,10 @@ const c = this.c; const d = this.d; - const skewX = Math.atan2(-c, d); + const skewX = -Math.atan2(-c, d); const skewY = Math.atan2(b, a); - const delta = Math.abs(1 - (skewX / skewY)); + const delta = Math.abs(skewX + skewY); if (delta < 0.00001) { diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js index afe4a89..c4f34be 100644 --- a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -2,7 +2,7 @@ * Creates a little colored canvas * * @ignore - * @param {number} color - The color to make the canvas + * @param {string} color - The color to make the canvas * @return {canvas} a small canvas element */ function createColoredCanvas(color) diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 3e58a00..025fef0 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -120,6 +120,15 @@ this._transformID = -1; this._textureID = -1; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'sprite' + */ + this.pluginName = 'sprite'; } /** @@ -282,8 +291,8 @@ { this.calculateVertices(); - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -294,7 +303,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.sprite.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index 20d4a0a..faeb91c 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -97,7 +97,7 @@ { const clonedProperties = {}; - for (const key in this._defaults) + for (const key in defaultStyle) { clonedProperties[key] = this[key]; } @@ -110,7 +110,7 @@ */ reset() { - Object.assign(this, this._defaults); + Object.assign(this, defaultStyle); } get align() @@ -435,22 +435,43 @@ * @param {number|number[]} color * @return {string} The color as a string. */ -function getColor(color) +function getSingleColor(color) { if (typeof color === 'number') { return hex2string(color); } - else if (Array.isArray(color)) + else if ( typeof color === 'string' ) { - for (let i = 0; i < color.length; ++i) + if ( color.indexOf('0x') === 0 ) { - if (typeof color[i] === 'number') - { - color[i] = hex2string(color[i]); - } + color = color.replace('0x', '#'); } } return color; } + +/** + * Utility function to convert hexadecimal colors to strings, and simply return the color if it's a string. + * This version can also convert array of colors + * + * @param {number|number[]} color + * @return {string} The color as a string. + */ +function getColor(color) +{ + if (!Array.isArray(color)) + { + return getSingleColor(color); + } + else + { + for (let i = 0; i < color.length; ++i) + { + color[i] = getSingleColor(color[i]); + } + + return color; + } +} diff --git a/src/core/utils/index.js b/src/core/utils/index.js index c82aaa4..2a7497b 100644 --- a/src/core/utils/index.js +++ b/src/core/utils/index.js @@ -103,9 +103,10 @@ * @memberof PIXI.utils * @function getResolutionOfUrl * @param {string} url - the image path + * @param {number} [defaultValue=1] - the defaultValue if no filename prefix is set. * @return {number} resolution / device pixel ratio of an asset */ -export function getResolutionOfUrl(url) +export function getResolutionOfUrl(url, defaultValue) { const resolution = settings.RETINA_PREFIX.exec(url); @@ -114,7 +115,7 @@ return parseFloat(resolution[1]); } - return 1; + return defaultValue !== undefined ? defaultValue : 1; } /** diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js index b9352e6..a8bcfba 100644 --- a/src/extras/TilingSprite.js +++ b/src/extras/TilingSprite.js @@ -61,6 +61,15 @@ * @member {PIXI.extras.TextureTransform} */ this.uvTransform = texture.transform || new TextureTransform(texture); + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' method. + * + * @member {string} + * @default 'tilingSprite' + */ + this.pluginName = 'tilingSprite'; } /** * Changes frame clamping in corresponding textureTransform, shortcut @@ -158,8 +167,8 @@ this.tileTransform.updateLocalTransform(); this.uvTransform.update(); - renderer.setObjectRenderer(renderer.plugins.tilingSprite); - renderer.plugins.tilingSprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/filters/blur/BlurFilter.js b/src/filters/blur/BlurFilter.js index 5b3c3a9..8a05893 100644 --- a/src/filters/blur/BlurFilter.js +++ b/src/filters/blur/BlurFilter.js @@ -15,14 +15,15 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { super(); - this.blurXFilter = new BlurXFilter(); - this.blurYFilter = new BlurYFilter(); + this.blurXFilter = new BlurXFilter(strength, quality, resolution, kernelSize); + this.blurYFilter = new BlurYFilter(strength, quality, resolution, kernelSize); this.resolution = 1; this.padding = 0; diff --git a/src/filters/blur/BlurXFilter.js b/src/filters/blur/BlurXFilter.js index 24181b6..338096c 100644 --- a/src/filters/blur/BlurXFilter.js +++ b/src/filters/blur/BlurXFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, true); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, true); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/filters/blur/BlurYFilter.js b/src/filters/blur/BlurYFilter.js index 267728b..94cbf37 100644 --- a/src/filters/blur/BlurYFilter.js +++ b/src/filters/blur/BlurYFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, false); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, false); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/interaction/InteractionEvent.js b/src/interaction/InteractionEvent.js index 0342469..75b2966 100644 --- a/src/interaction/InteractionEvent.js +++ b/src/interaction/InteractionEvent.js @@ -12,14 +12,15 @@ constructor() { /** - * Which this event will continue propagating in the tree + * Whether this event will continue propagating in the tree * * @member {boolean} */ this.stopped = false; /** - * The object to which event is dispatched. + * The object which caused this event to be dispatched. + * For listener callback see {@link PIXI.interaction.InteractionEvent.currentTarget}. * * @member {PIXI.DisplayObject} */ diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js index 94df60e..05f6628 100644 --- a/src/interaction/InteractionManager.js +++ b/src/interaction/InteractionManager.js @@ -105,15 +105,16 @@ this.interactionDOMElement = null; /** - * This property determins if mousemove and touchmove events are fired only when the cursror + * This property determines if mousemove and touchmove events are fired only when the cursror * is over the object. * Setting to true will make things work more in line with how the DOM verison works. * Setting to false can make things easier for things like dragging * It is currently set to false as this is how pixi used to work. This will be set to true in * future versions of pixi. * - * @private - * @member {boolean} + * @member {boolean} moveWhenInside + * @memberof PIXI.interaction.InteractionManager# + * @default false */ this.moveWhenInside = false; @@ -735,8 +736,10 @@ rect = this.interactionDOMElement.getBoundingClientRect(); } - point.x = ((x - rect.left) * (this.interactionDOMElement.width / rect.width)) / this.resolution; - point.y = ((y - rect.top) * (this.interactionDOMElement.height / rect.height)) / this.resolution; + const resolutionMultiplier = navigator.isCocoonJS ? this.resolution : (1.0 / this.resolution); + + point.x = ((x - rect.left) * (this.interactionDOMElement.width / rect.width)) * resolutionMultiplier; + point.y = ((y - rect.top) * (this.interactionDOMElement.height / rect.height)) * resolutionMultiplier; } /** diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/src/core/display/TransformStatic.js b/src/core/display/TransformStatic.js index c0c2f33..1e8d0c6 100644 --- a/src/core/display/TransformStatic.js +++ b/src/core/display/TransformStatic.js @@ -47,12 +47,10 @@ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; this._localID = 0; this._currentLocalID = 0; @@ -69,16 +67,16 @@ } /** - * Called when skew changes + * Called when skew or rotation changes * * @private */ updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 this._localID ++; } @@ -93,15 +91,10 @@ if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -119,22 +112,15 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -147,6 +133,9 @@ if (this._parentID !== parentTransform._worldID) { // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -191,8 +180,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID ++; + this.updateSkew(); } } diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 9e65938..6f0a417 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -491,9 +491,10 @@ const startX = cx + (Math.cos(startAngle) * radius); const startY = cy + (Math.sin(startAngle) * radius); - const points = this.currentPath.shape.points; + // If the currentPath exists, take its points. Otherwise call `moveTo` to start a path. + let points = this.currentPath ? this.currentPath.shape.points : null; - if (this.currentPath) + if (points) { if (points[points.length - 2] !== startX || points[points.length - 1] !== startY) { @@ -503,6 +504,7 @@ else { this.moveTo(startX, startY); + points = this.currentPath.shape.points; } const theta = sweep / (segs * 2); @@ -691,6 +693,7 @@ this.lineWidth = 0; this.filling = false; + this.boundsDirty = -1; this.dirty++; this.clearDirty++; this.graphicsData.length = 0; diff --git a/src/core/math/Matrix.js b/src/core/math/Matrix.js index e3341fe..0b77477 100644 --- a/src/core/math/Matrix.js +++ b/src/core/math/Matrix.js @@ -353,10 +353,10 @@ const c = this.c; const d = this.d; - const skewX = Math.atan2(-c, d); + const skewX = -Math.atan2(-c, d); const skewY = Math.atan2(b, a); - const delta = Math.abs(1 - (skewX / skewY)); + const delta = Math.abs(skewX + skewY); if (delta < 0.00001) { diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js index afe4a89..c4f34be 100644 --- a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -2,7 +2,7 @@ * Creates a little colored canvas * * @ignore - * @param {number} color - The color to make the canvas + * @param {string} color - The color to make the canvas * @return {canvas} a small canvas element */ function createColoredCanvas(color) diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 3e58a00..025fef0 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -120,6 +120,15 @@ this._transformID = -1; this._textureID = -1; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'sprite' + */ + this.pluginName = 'sprite'; } /** @@ -282,8 +291,8 @@ { this.calculateVertices(); - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -294,7 +303,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.sprite.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index 20d4a0a..faeb91c 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -97,7 +97,7 @@ { const clonedProperties = {}; - for (const key in this._defaults) + for (const key in defaultStyle) { clonedProperties[key] = this[key]; } @@ -110,7 +110,7 @@ */ reset() { - Object.assign(this, this._defaults); + Object.assign(this, defaultStyle); } get align() @@ -435,22 +435,43 @@ * @param {number|number[]} color * @return {string} The color as a string. */ -function getColor(color) +function getSingleColor(color) { if (typeof color === 'number') { return hex2string(color); } - else if (Array.isArray(color)) + else if ( typeof color === 'string' ) { - for (let i = 0; i < color.length; ++i) + if ( color.indexOf('0x') === 0 ) { - if (typeof color[i] === 'number') - { - color[i] = hex2string(color[i]); - } + color = color.replace('0x', '#'); } } return color; } + +/** + * Utility function to convert hexadecimal colors to strings, and simply return the color if it's a string. + * This version can also convert array of colors + * + * @param {number|number[]} color + * @return {string} The color as a string. + */ +function getColor(color) +{ + if (!Array.isArray(color)) + { + return getSingleColor(color); + } + else + { + for (let i = 0; i < color.length; ++i) + { + color[i] = getSingleColor(color[i]); + } + + return color; + } +} diff --git a/src/core/utils/index.js b/src/core/utils/index.js index c82aaa4..2a7497b 100644 --- a/src/core/utils/index.js +++ b/src/core/utils/index.js @@ -103,9 +103,10 @@ * @memberof PIXI.utils * @function getResolutionOfUrl * @param {string} url - the image path + * @param {number} [defaultValue=1] - the defaultValue if no filename prefix is set. * @return {number} resolution / device pixel ratio of an asset */ -export function getResolutionOfUrl(url) +export function getResolutionOfUrl(url, defaultValue) { const resolution = settings.RETINA_PREFIX.exec(url); @@ -114,7 +115,7 @@ return parseFloat(resolution[1]); } - return 1; + return defaultValue !== undefined ? defaultValue : 1; } /** diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js index b9352e6..a8bcfba 100644 --- a/src/extras/TilingSprite.js +++ b/src/extras/TilingSprite.js @@ -61,6 +61,15 @@ * @member {PIXI.extras.TextureTransform} */ this.uvTransform = texture.transform || new TextureTransform(texture); + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' method. + * + * @member {string} + * @default 'tilingSprite' + */ + this.pluginName = 'tilingSprite'; } /** * Changes frame clamping in corresponding textureTransform, shortcut @@ -158,8 +167,8 @@ this.tileTransform.updateLocalTransform(); this.uvTransform.update(); - renderer.setObjectRenderer(renderer.plugins.tilingSprite); - renderer.plugins.tilingSprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/filters/blur/BlurFilter.js b/src/filters/blur/BlurFilter.js index 5b3c3a9..8a05893 100644 --- a/src/filters/blur/BlurFilter.js +++ b/src/filters/blur/BlurFilter.js @@ -15,14 +15,15 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { super(); - this.blurXFilter = new BlurXFilter(); - this.blurYFilter = new BlurYFilter(); + this.blurXFilter = new BlurXFilter(strength, quality, resolution, kernelSize); + this.blurYFilter = new BlurYFilter(strength, quality, resolution, kernelSize); this.resolution = 1; this.padding = 0; diff --git a/src/filters/blur/BlurXFilter.js b/src/filters/blur/BlurXFilter.js index 24181b6..338096c 100644 --- a/src/filters/blur/BlurXFilter.js +++ b/src/filters/blur/BlurXFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, true); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, true); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/filters/blur/BlurYFilter.js b/src/filters/blur/BlurYFilter.js index 267728b..94cbf37 100644 --- a/src/filters/blur/BlurYFilter.js +++ b/src/filters/blur/BlurYFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, false); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, false); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/interaction/InteractionEvent.js b/src/interaction/InteractionEvent.js index 0342469..75b2966 100644 --- a/src/interaction/InteractionEvent.js +++ b/src/interaction/InteractionEvent.js @@ -12,14 +12,15 @@ constructor() { /** - * Which this event will continue propagating in the tree + * Whether this event will continue propagating in the tree * * @member {boolean} */ this.stopped = false; /** - * The object to which event is dispatched. + * The object which caused this event to be dispatched. + * For listener callback see {@link PIXI.interaction.InteractionEvent.currentTarget}. * * @member {PIXI.DisplayObject} */ diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js index 94df60e..05f6628 100644 --- a/src/interaction/InteractionManager.js +++ b/src/interaction/InteractionManager.js @@ -105,15 +105,16 @@ this.interactionDOMElement = null; /** - * This property determins if mousemove and touchmove events are fired only when the cursror + * This property determines if mousemove and touchmove events are fired only when the cursror * is over the object. * Setting to true will make things work more in line with how the DOM verison works. * Setting to false can make things easier for things like dragging * It is currently set to false as this is how pixi used to work. This will be set to true in * future versions of pixi. * - * @private - * @member {boolean} + * @member {boolean} moveWhenInside + * @memberof PIXI.interaction.InteractionManager# + * @default false */ this.moveWhenInside = false; @@ -735,8 +736,10 @@ rect = this.interactionDOMElement.getBoundingClientRect(); } - point.x = ((x - rect.left) * (this.interactionDOMElement.width / rect.width)) / this.resolution; - point.y = ((y - rect.top) * (this.interactionDOMElement.height / rect.height)) / this.resolution; + const resolutionMultiplier = navigator.isCocoonJS ? this.resolution : (1.0 / this.resolution); + + point.x = ((x - rect.left) * (this.interactionDOMElement.width / rect.width)) * resolutionMultiplier; + point.y = ((y - rect.top) * (this.interactionDOMElement.height / rect.height)) * resolutionMultiplier; } /** diff --git a/src/loaders/loader.js b/src/loaders/loader.js index c086919..978aa2d 100644 --- a/src/loaders/loader.js +++ b/src/loaders/loader.js @@ -12,7 +12,9 @@ * //or * let loader = new PIXI.loaders.Loader(); // you can also create your own if you want * - * loader.add('bunny',"data/bunny.png"); + * loader.add('bunny', 'data/bunny.png'); + * loader.add('spaceship', 'assets/spritesheet.json'); + * loader.add('scoreFont', 'assets/score.fnt'); * * loader.once('complete',onAssetsLoaded); * diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/src/core/display/TransformStatic.js b/src/core/display/TransformStatic.js index c0c2f33..1e8d0c6 100644 --- a/src/core/display/TransformStatic.js +++ b/src/core/display/TransformStatic.js @@ -47,12 +47,10 @@ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; this._localID = 0; this._currentLocalID = 0; @@ -69,16 +67,16 @@ } /** - * Called when skew changes + * Called when skew or rotation changes * * @private */ updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 this._localID ++; } @@ -93,15 +91,10 @@ if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -119,22 +112,15 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -147,6 +133,9 @@ if (this._parentID !== parentTransform._worldID) { // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -191,8 +180,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID ++; + this.updateSkew(); } } diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 9e65938..6f0a417 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -491,9 +491,10 @@ const startX = cx + (Math.cos(startAngle) * radius); const startY = cy + (Math.sin(startAngle) * radius); - const points = this.currentPath.shape.points; + // If the currentPath exists, take its points. Otherwise call `moveTo` to start a path. + let points = this.currentPath ? this.currentPath.shape.points : null; - if (this.currentPath) + if (points) { if (points[points.length - 2] !== startX || points[points.length - 1] !== startY) { @@ -503,6 +504,7 @@ else { this.moveTo(startX, startY); + points = this.currentPath.shape.points; } const theta = sweep / (segs * 2); @@ -691,6 +693,7 @@ this.lineWidth = 0; this.filling = false; + this.boundsDirty = -1; this.dirty++; this.clearDirty++; this.graphicsData.length = 0; diff --git a/src/core/math/Matrix.js b/src/core/math/Matrix.js index e3341fe..0b77477 100644 --- a/src/core/math/Matrix.js +++ b/src/core/math/Matrix.js @@ -353,10 +353,10 @@ const c = this.c; const d = this.d; - const skewX = Math.atan2(-c, d); + const skewX = -Math.atan2(-c, d); const skewY = Math.atan2(b, a); - const delta = Math.abs(1 - (skewX / skewY)); + const delta = Math.abs(skewX + skewY); if (delta < 0.00001) { diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js index afe4a89..c4f34be 100644 --- a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -2,7 +2,7 @@ * Creates a little colored canvas * * @ignore - * @param {number} color - The color to make the canvas + * @param {string} color - The color to make the canvas * @return {canvas} a small canvas element */ function createColoredCanvas(color) diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 3e58a00..025fef0 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -120,6 +120,15 @@ this._transformID = -1; this._textureID = -1; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'sprite' + */ + this.pluginName = 'sprite'; } /** @@ -282,8 +291,8 @@ { this.calculateVertices(); - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -294,7 +303,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.sprite.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index 20d4a0a..faeb91c 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -97,7 +97,7 @@ { const clonedProperties = {}; - for (const key in this._defaults) + for (const key in defaultStyle) { clonedProperties[key] = this[key]; } @@ -110,7 +110,7 @@ */ reset() { - Object.assign(this, this._defaults); + Object.assign(this, defaultStyle); } get align() @@ -435,22 +435,43 @@ * @param {number|number[]} color * @return {string} The color as a string. */ -function getColor(color) +function getSingleColor(color) { if (typeof color === 'number') { return hex2string(color); } - else if (Array.isArray(color)) + else if ( typeof color === 'string' ) { - for (let i = 0; i < color.length; ++i) + if ( color.indexOf('0x') === 0 ) { - if (typeof color[i] === 'number') - { - color[i] = hex2string(color[i]); - } + color = color.replace('0x', '#'); } } return color; } + +/** + * Utility function to convert hexadecimal colors to strings, and simply return the color if it's a string. + * This version can also convert array of colors + * + * @param {number|number[]} color + * @return {string} The color as a string. + */ +function getColor(color) +{ + if (!Array.isArray(color)) + { + return getSingleColor(color); + } + else + { + for (let i = 0; i < color.length; ++i) + { + color[i] = getSingleColor(color[i]); + } + + return color; + } +} diff --git a/src/core/utils/index.js b/src/core/utils/index.js index c82aaa4..2a7497b 100644 --- a/src/core/utils/index.js +++ b/src/core/utils/index.js @@ -103,9 +103,10 @@ * @memberof PIXI.utils * @function getResolutionOfUrl * @param {string} url - the image path + * @param {number} [defaultValue=1] - the defaultValue if no filename prefix is set. * @return {number} resolution / device pixel ratio of an asset */ -export function getResolutionOfUrl(url) +export function getResolutionOfUrl(url, defaultValue) { const resolution = settings.RETINA_PREFIX.exec(url); @@ -114,7 +115,7 @@ return parseFloat(resolution[1]); } - return 1; + return defaultValue !== undefined ? defaultValue : 1; } /** diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js index b9352e6..a8bcfba 100644 --- a/src/extras/TilingSprite.js +++ b/src/extras/TilingSprite.js @@ -61,6 +61,15 @@ * @member {PIXI.extras.TextureTransform} */ this.uvTransform = texture.transform || new TextureTransform(texture); + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' method. + * + * @member {string} + * @default 'tilingSprite' + */ + this.pluginName = 'tilingSprite'; } /** * Changes frame clamping in corresponding textureTransform, shortcut @@ -158,8 +167,8 @@ this.tileTransform.updateLocalTransform(); this.uvTransform.update(); - renderer.setObjectRenderer(renderer.plugins.tilingSprite); - renderer.plugins.tilingSprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/filters/blur/BlurFilter.js b/src/filters/blur/BlurFilter.js index 5b3c3a9..8a05893 100644 --- a/src/filters/blur/BlurFilter.js +++ b/src/filters/blur/BlurFilter.js @@ -15,14 +15,15 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { super(); - this.blurXFilter = new BlurXFilter(); - this.blurYFilter = new BlurYFilter(); + this.blurXFilter = new BlurXFilter(strength, quality, resolution, kernelSize); + this.blurYFilter = new BlurYFilter(strength, quality, resolution, kernelSize); this.resolution = 1; this.padding = 0; diff --git a/src/filters/blur/BlurXFilter.js b/src/filters/blur/BlurXFilter.js index 24181b6..338096c 100644 --- a/src/filters/blur/BlurXFilter.js +++ b/src/filters/blur/BlurXFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, true); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, true); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/filters/blur/BlurYFilter.js b/src/filters/blur/BlurYFilter.js index 267728b..94cbf37 100644 --- a/src/filters/blur/BlurYFilter.js +++ b/src/filters/blur/BlurYFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, false); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, false); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/interaction/InteractionEvent.js b/src/interaction/InteractionEvent.js index 0342469..75b2966 100644 --- a/src/interaction/InteractionEvent.js +++ b/src/interaction/InteractionEvent.js @@ -12,14 +12,15 @@ constructor() { /** - * Which this event will continue propagating in the tree + * Whether this event will continue propagating in the tree * * @member {boolean} */ this.stopped = false; /** - * The object to which event is dispatched. + * The object which caused this event to be dispatched. + * For listener callback see {@link PIXI.interaction.InteractionEvent.currentTarget}. * * @member {PIXI.DisplayObject} */ diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js index 94df60e..05f6628 100644 --- a/src/interaction/InteractionManager.js +++ b/src/interaction/InteractionManager.js @@ -105,15 +105,16 @@ this.interactionDOMElement = null; /** - * This property determins if mousemove and touchmove events are fired only when the cursror + * This property determines if mousemove and touchmove events are fired only when the cursror * is over the object. * Setting to true will make things work more in line with how the DOM verison works. * Setting to false can make things easier for things like dragging * It is currently set to false as this is how pixi used to work. This will be set to true in * future versions of pixi. * - * @private - * @member {boolean} + * @member {boolean} moveWhenInside + * @memberof PIXI.interaction.InteractionManager# + * @default false */ this.moveWhenInside = false; @@ -735,8 +736,10 @@ rect = this.interactionDOMElement.getBoundingClientRect(); } - point.x = ((x - rect.left) * (this.interactionDOMElement.width / rect.width)) / this.resolution; - point.y = ((y - rect.top) * (this.interactionDOMElement.height / rect.height)) / this.resolution; + const resolutionMultiplier = navigator.isCocoonJS ? this.resolution : (1.0 / this.resolution); + + point.x = ((x - rect.left) * (this.interactionDOMElement.width / rect.width)) * resolutionMultiplier; + point.y = ((y - rect.top) * (this.interactionDOMElement.height / rect.height)) * resolutionMultiplier; } /** diff --git a/src/loaders/loader.js b/src/loaders/loader.js index c086919..978aa2d 100644 --- a/src/loaders/loader.js +++ b/src/loaders/loader.js @@ -12,7 +12,9 @@ * //or * let loader = new PIXI.loaders.Loader(); // you can also create your own if you want * - * loader.add('bunny',"data/bunny.png"); + * loader.add('bunny', 'data/bunny.png'); + * loader.add('spaceship', 'assets/spritesheet.json'); + * loader.add('scoreFont', 'assets/score.fnt'); * * loader.once('complete',onAssetsLoaded); * diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js index 2d637b1..2b30b1c 100644 --- a/src/loaders/spritesheetParser.js +++ b/src/loaders/spritesheetParser.js @@ -43,14 +43,22 @@ const frames = resource.data.frames; const frameKeys = Object.keys(frames); const baseTexture = res.texture.baseTexture; - let resolution = core.utils.getResolutionOfUrl(resource.url); const scale = resource.data.meta.scale; - // for now (to keep things compatible) resolution overrides scale - // Support scale field on spritesheet - if (resolution === 1 && scale !== undefined && scale !== 1) + // Use a defaultValue of `null` to check if a url-based resolution is set + let resolution = core.utils.getResolutionOfUrl(resource.url, null); + + // No resolution found via URL + if (resolution === null) { - baseTexture.resolution = resolution = scale; + // Use the scale value or default to 1 + resolution = scale !== undefined ? scale : 1; + } + + // For non-1 resolutions, update baseTexture + if (resolution !== 1) + { + baseTexture.resolution = resolution; baseTexture.update(); } diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/src/core/display/TransformStatic.js b/src/core/display/TransformStatic.js index c0c2f33..1e8d0c6 100644 --- a/src/core/display/TransformStatic.js +++ b/src/core/display/TransformStatic.js @@ -47,12 +47,10 @@ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; this._localID = 0; this._currentLocalID = 0; @@ -69,16 +67,16 @@ } /** - * Called when skew changes + * Called when skew or rotation changes * * @private */ updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 this._localID ++; } @@ -93,15 +91,10 @@ if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -119,22 +112,15 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -147,6 +133,9 @@ if (this._parentID !== parentTransform._worldID) { // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -191,8 +180,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID ++; + this.updateSkew(); } } diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 9e65938..6f0a417 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -491,9 +491,10 @@ const startX = cx + (Math.cos(startAngle) * radius); const startY = cy + (Math.sin(startAngle) * radius); - const points = this.currentPath.shape.points; + // If the currentPath exists, take its points. Otherwise call `moveTo` to start a path. + let points = this.currentPath ? this.currentPath.shape.points : null; - if (this.currentPath) + if (points) { if (points[points.length - 2] !== startX || points[points.length - 1] !== startY) { @@ -503,6 +504,7 @@ else { this.moveTo(startX, startY); + points = this.currentPath.shape.points; } const theta = sweep / (segs * 2); @@ -691,6 +693,7 @@ this.lineWidth = 0; this.filling = false; + this.boundsDirty = -1; this.dirty++; this.clearDirty++; this.graphicsData.length = 0; diff --git a/src/core/math/Matrix.js b/src/core/math/Matrix.js index e3341fe..0b77477 100644 --- a/src/core/math/Matrix.js +++ b/src/core/math/Matrix.js @@ -353,10 +353,10 @@ const c = this.c; const d = this.d; - const skewX = Math.atan2(-c, d); + const skewX = -Math.atan2(-c, d); const skewY = Math.atan2(b, a); - const delta = Math.abs(1 - (skewX / skewY)); + const delta = Math.abs(skewX + skewY); if (delta < 0.00001) { diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js index afe4a89..c4f34be 100644 --- a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -2,7 +2,7 @@ * Creates a little colored canvas * * @ignore - * @param {number} color - The color to make the canvas + * @param {string} color - The color to make the canvas * @return {canvas} a small canvas element */ function createColoredCanvas(color) diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 3e58a00..025fef0 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -120,6 +120,15 @@ this._transformID = -1; this._textureID = -1; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'sprite' + */ + this.pluginName = 'sprite'; } /** @@ -282,8 +291,8 @@ { this.calculateVertices(); - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -294,7 +303,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.sprite.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index 20d4a0a..faeb91c 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -97,7 +97,7 @@ { const clonedProperties = {}; - for (const key in this._defaults) + for (const key in defaultStyle) { clonedProperties[key] = this[key]; } @@ -110,7 +110,7 @@ */ reset() { - Object.assign(this, this._defaults); + Object.assign(this, defaultStyle); } get align() @@ -435,22 +435,43 @@ * @param {number|number[]} color * @return {string} The color as a string. */ -function getColor(color) +function getSingleColor(color) { if (typeof color === 'number') { return hex2string(color); } - else if (Array.isArray(color)) + else if ( typeof color === 'string' ) { - for (let i = 0; i < color.length; ++i) + if ( color.indexOf('0x') === 0 ) { - if (typeof color[i] === 'number') - { - color[i] = hex2string(color[i]); - } + color = color.replace('0x', '#'); } } return color; } + +/** + * Utility function to convert hexadecimal colors to strings, and simply return the color if it's a string. + * This version can also convert array of colors + * + * @param {number|number[]} color + * @return {string} The color as a string. + */ +function getColor(color) +{ + if (!Array.isArray(color)) + { + return getSingleColor(color); + } + else + { + for (let i = 0; i < color.length; ++i) + { + color[i] = getSingleColor(color[i]); + } + + return color; + } +} diff --git a/src/core/utils/index.js b/src/core/utils/index.js index c82aaa4..2a7497b 100644 --- a/src/core/utils/index.js +++ b/src/core/utils/index.js @@ -103,9 +103,10 @@ * @memberof PIXI.utils * @function getResolutionOfUrl * @param {string} url - the image path + * @param {number} [defaultValue=1] - the defaultValue if no filename prefix is set. * @return {number} resolution / device pixel ratio of an asset */ -export function getResolutionOfUrl(url) +export function getResolutionOfUrl(url, defaultValue) { const resolution = settings.RETINA_PREFIX.exec(url); @@ -114,7 +115,7 @@ return parseFloat(resolution[1]); } - return 1; + return defaultValue !== undefined ? defaultValue : 1; } /** diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js index b9352e6..a8bcfba 100644 --- a/src/extras/TilingSprite.js +++ b/src/extras/TilingSprite.js @@ -61,6 +61,15 @@ * @member {PIXI.extras.TextureTransform} */ this.uvTransform = texture.transform || new TextureTransform(texture); + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' method. + * + * @member {string} + * @default 'tilingSprite' + */ + this.pluginName = 'tilingSprite'; } /** * Changes frame clamping in corresponding textureTransform, shortcut @@ -158,8 +167,8 @@ this.tileTransform.updateLocalTransform(); this.uvTransform.update(); - renderer.setObjectRenderer(renderer.plugins.tilingSprite); - renderer.plugins.tilingSprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/filters/blur/BlurFilter.js b/src/filters/blur/BlurFilter.js index 5b3c3a9..8a05893 100644 --- a/src/filters/blur/BlurFilter.js +++ b/src/filters/blur/BlurFilter.js @@ -15,14 +15,15 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { super(); - this.blurXFilter = new BlurXFilter(); - this.blurYFilter = new BlurYFilter(); + this.blurXFilter = new BlurXFilter(strength, quality, resolution, kernelSize); + this.blurYFilter = new BlurYFilter(strength, quality, resolution, kernelSize); this.resolution = 1; this.padding = 0; diff --git a/src/filters/blur/BlurXFilter.js b/src/filters/blur/BlurXFilter.js index 24181b6..338096c 100644 --- a/src/filters/blur/BlurXFilter.js +++ b/src/filters/blur/BlurXFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, true); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, true); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/filters/blur/BlurYFilter.js b/src/filters/blur/BlurYFilter.js index 267728b..94cbf37 100644 --- a/src/filters/blur/BlurYFilter.js +++ b/src/filters/blur/BlurYFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, false); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, false); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/interaction/InteractionEvent.js b/src/interaction/InteractionEvent.js index 0342469..75b2966 100644 --- a/src/interaction/InteractionEvent.js +++ b/src/interaction/InteractionEvent.js @@ -12,14 +12,15 @@ constructor() { /** - * Which this event will continue propagating in the tree + * Whether this event will continue propagating in the tree * * @member {boolean} */ this.stopped = false; /** - * The object to which event is dispatched. + * The object which caused this event to be dispatched. + * For listener callback see {@link PIXI.interaction.InteractionEvent.currentTarget}. * * @member {PIXI.DisplayObject} */ diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js index 94df60e..05f6628 100644 --- a/src/interaction/InteractionManager.js +++ b/src/interaction/InteractionManager.js @@ -105,15 +105,16 @@ this.interactionDOMElement = null; /** - * This property determins if mousemove and touchmove events are fired only when the cursror + * This property determines if mousemove and touchmove events are fired only when the cursror * is over the object. * Setting to true will make things work more in line with how the DOM verison works. * Setting to false can make things easier for things like dragging * It is currently set to false as this is how pixi used to work. This will be set to true in * future versions of pixi. * - * @private - * @member {boolean} + * @member {boolean} moveWhenInside + * @memberof PIXI.interaction.InteractionManager# + * @default false */ this.moveWhenInside = false; @@ -735,8 +736,10 @@ rect = this.interactionDOMElement.getBoundingClientRect(); } - point.x = ((x - rect.left) * (this.interactionDOMElement.width / rect.width)) / this.resolution; - point.y = ((y - rect.top) * (this.interactionDOMElement.height / rect.height)) / this.resolution; + const resolutionMultiplier = navigator.isCocoonJS ? this.resolution : (1.0 / this.resolution); + + point.x = ((x - rect.left) * (this.interactionDOMElement.width / rect.width)) * resolutionMultiplier; + point.y = ((y - rect.top) * (this.interactionDOMElement.height / rect.height)) * resolutionMultiplier; } /** diff --git a/src/loaders/loader.js b/src/loaders/loader.js index c086919..978aa2d 100644 --- a/src/loaders/loader.js +++ b/src/loaders/loader.js @@ -12,7 +12,9 @@ * //or * let loader = new PIXI.loaders.Loader(); // you can also create your own if you want * - * loader.add('bunny',"data/bunny.png"); + * loader.add('bunny', 'data/bunny.png'); + * loader.add('spaceship', 'assets/spritesheet.json'); + * loader.add('scoreFont', 'assets/score.fnt'); * * loader.once('complete',onAssetsLoaded); * diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js index 2d637b1..2b30b1c 100644 --- a/src/loaders/spritesheetParser.js +++ b/src/loaders/spritesheetParser.js @@ -43,14 +43,22 @@ const frames = resource.data.frames; const frameKeys = Object.keys(frames); const baseTexture = res.texture.baseTexture; - let resolution = core.utils.getResolutionOfUrl(resource.url); const scale = resource.data.meta.scale; - // for now (to keep things compatible) resolution overrides scale - // Support scale field on spritesheet - if (resolution === 1 && scale !== undefined && scale !== 1) + // Use a defaultValue of `null` to check if a url-based resolution is set + let resolution = core.utils.getResolutionOfUrl(resource.url, null); + + // No resolution found via URL + if (resolution === null) { - baseTexture.resolution = resolution = scale; + // Use the scale value or default to 1 + resolution = scale !== undefined ? scale : 1; + } + + // For non-1 resolutions, update baseTexture + if (resolution !== 1) + { + baseTexture.resolution = resolution; baseTexture.update(); } diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 21e5a61..bbb0938 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -122,6 +122,15 @@ * @member {object} */ this._glDatas = {}; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'mesh' + */ + this.pluginName = 'mesh'; } /** @@ -132,8 +141,8 @@ */ _renderWebGL(renderer) { - renderer.setObjectRenderer(renderer.plugins.mesh); - renderer.plugins.mesh.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -144,7 +153,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.mesh.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/src/core/display/TransformStatic.js b/src/core/display/TransformStatic.js index c0c2f33..1e8d0c6 100644 --- a/src/core/display/TransformStatic.js +++ b/src/core/display/TransformStatic.js @@ -47,12 +47,10 @@ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; this._localID = 0; this._currentLocalID = 0; @@ -69,16 +67,16 @@ } /** - * Called when skew changes + * Called when skew or rotation changes * * @private */ updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 this._localID ++; } @@ -93,15 +91,10 @@ if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -119,22 +112,15 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -147,6 +133,9 @@ if (this._parentID !== parentTransform._worldID) { // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -191,8 +180,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID ++; + this.updateSkew(); } } diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 9e65938..6f0a417 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -491,9 +491,10 @@ const startX = cx + (Math.cos(startAngle) * radius); const startY = cy + (Math.sin(startAngle) * radius); - const points = this.currentPath.shape.points; + // If the currentPath exists, take its points. Otherwise call `moveTo` to start a path. + let points = this.currentPath ? this.currentPath.shape.points : null; - if (this.currentPath) + if (points) { if (points[points.length - 2] !== startX || points[points.length - 1] !== startY) { @@ -503,6 +504,7 @@ else { this.moveTo(startX, startY); + points = this.currentPath.shape.points; } const theta = sweep / (segs * 2); @@ -691,6 +693,7 @@ this.lineWidth = 0; this.filling = false; + this.boundsDirty = -1; this.dirty++; this.clearDirty++; this.graphicsData.length = 0; diff --git a/src/core/math/Matrix.js b/src/core/math/Matrix.js index e3341fe..0b77477 100644 --- a/src/core/math/Matrix.js +++ b/src/core/math/Matrix.js @@ -353,10 +353,10 @@ const c = this.c; const d = this.d; - const skewX = Math.atan2(-c, d); + const skewX = -Math.atan2(-c, d); const skewY = Math.atan2(b, a); - const delta = Math.abs(1 - (skewX / skewY)); + const delta = Math.abs(skewX + skewY); if (delta < 0.00001) { diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js index afe4a89..c4f34be 100644 --- a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -2,7 +2,7 @@ * Creates a little colored canvas * * @ignore - * @param {number} color - The color to make the canvas + * @param {string} color - The color to make the canvas * @return {canvas} a small canvas element */ function createColoredCanvas(color) diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 3e58a00..025fef0 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -120,6 +120,15 @@ this._transformID = -1; this._textureID = -1; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'sprite' + */ + this.pluginName = 'sprite'; } /** @@ -282,8 +291,8 @@ { this.calculateVertices(); - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -294,7 +303,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.sprite.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index 20d4a0a..faeb91c 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -97,7 +97,7 @@ { const clonedProperties = {}; - for (const key in this._defaults) + for (const key in defaultStyle) { clonedProperties[key] = this[key]; } @@ -110,7 +110,7 @@ */ reset() { - Object.assign(this, this._defaults); + Object.assign(this, defaultStyle); } get align() @@ -435,22 +435,43 @@ * @param {number|number[]} color * @return {string} The color as a string. */ -function getColor(color) +function getSingleColor(color) { if (typeof color === 'number') { return hex2string(color); } - else if (Array.isArray(color)) + else if ( typeof color === 'string' ) { - for (let i = 0; i < color.length; ++i) + if ( color.indexOf('0x') === 0 ) { - if (typeof color[i] === 'number') - { - color[i] = hex2string(color[i]); - } + color = color.replace('0x', '#'); } } return color; } + +/** + * Utility function to convert hexadecimal colors to strings, and simply return the color if it's a string. + * This version can also convert array of colors + * + * @param {number|number[]} color + * @return {string} The color as a string. + */ +function getColor(color) +{ + if (!Array.isArray(color)) + { + return getSingleColor(color); + } + else + { + for (let i = 0; i < color.length; ++i) + { + color[i] = getSingleColor(color[i]); + } + + return color; + } +} diff --git a/src/core/utils/index.js b/src/core/utils/index.js index c82aaa4..2a7497b 100644 --- a/src/core/utils/index.js +++ b/src/core/utils/index.js @@ -103,9 +103,10 @@ * @memberof PIXI.utils * @function getResolutionOfUrl * @param {string} url - the image path + * @param {number} [defaultValue=1] - the defaultValue if no filename prefix is set. * @return {number} resolution / device pixel ratio of an asset */ -export function getResolutionOfUrl(url) +export function getResolutionOfUrl(url, defaultValue) { const resolution = settings.RETINA_PREFIX.exec(url); @@ -114,7 +115,7 @@ return parseFloat(resolution[1]); } - return 1; + return defaultValue !== undefined ? defaultValue : 1; } /** diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js index b9352e6..a8bcfba 100644 --- a/src/extras/TilingSprite.js +++ b/src/extras/TilingSprite.js @@ -61,6 +61,15 @@ * @member {PIXI.extras.TextureTransform} */ this.uvTransform = texture.transform || new TextureTransform(texture); + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' method. + * + * @member {string} + * @default 'tilingSprite' + */ + this.pluginName = 'tilingSprite'; } /** * Changes frame clamping in corresponding textureTransform, shortcut @@ -158,8 +167,8 @@ this.tileTransform.updateLocalTransform(); this.uvTransform.update(); - renderer.setObjectRenderer(renderer.plugins.tilingSprite); - renderer.plugins.tilingSprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/filters/blur/BlurFilter.js b/src/filters/blur/BlurFilter.js index 5b3c3a9..8a05893 100644 --- a/src/filters/blur/BlurFilter.js +++ b/src/filters/blur/BlurFilter.js @@ -15,14 +15,15 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { super(); - this.blurXFilter = new BlurXFilter(); - this.blurYFilter = new BlurYFilter(); + this.blurXFilter = new BlurXFilter(strength, quality, resolution, kernelSize); + this.blurYFilter = new BlurYFilter(strength, quality, resolution, kernelSize); this.resolution = 1; this.padding = 0; diff --git a/src/filters/blur/BlurXFilter.js b/src/filters/blur/BlurXFilter.js index 24181b6..338096c 100644 --- a/src/filters/blur/BlurXFilter.js +++ b/src/filters/blur/BlurXFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, true); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, true); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/filters/blur/BlurYFilter.js b/src/filters/blur/BlurYFilter.js index 267728b..94cbf37 100644 --- a/src/filters/blur/BlurYFilter.js +++ b/src/filters/blur/BlurYFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, false); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, false); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/interaction/InteractionEvent.js b/src/interaction/InteractionEvent.js index 0342469..75b2966 100644 --- a/src/interaction/InteractionEvent.js +++ b/src/interaction/InteractionEvent.js @@ -12,14 +12,15 @@ constructor() { /** - * Which this event will continue propagating in the tree + * Whether this event will continue propagating in the tree * * @member {boolean} */ this.stopped = false; /** - * The object to which event is dispatched. + * The object which caused this event to be dispatched. + * For listener callback see {@link PIXI.interaction.InteractionEvent.currentTarget}. * * @member {PIXI.DisplayObject} */ diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js index 94df60e..05f6628 100644 --- a/src/interaction/InteractionManager.js +++ b/src/interaction/InteractionManager.js @@ -105,15 +105,16 @@ this.interactionDOMElement = null; /** - * This property determins if mousemove and touchmove events are fired only when the cursror + * This property determines if mousemove and touchmove events are fired only when the cursror * is over the object. * Setting to true will make things work more in line with how the DOM verison works. * Setting to false can make things easier for things like dragging * It is currently set to false as this is how pixi used to work. This will be set to true in * future versions of pixi. * - * @private - * @member {boolean} + * @member {boolean} moveWhenInside + * @memberof PIXI.interaction.InteractionManager# + * @default false */ this.moveWhenInside = false; @@ -735,8 +736,10 @@ rect = this.interactionDOMElement.getBoundingClientRect(); } - point.x = ((x - rect.left) * (this.interactionDOMElement.width / rect.width)) / this.resolution; - point.y = ((y - rect.top) * (this.interactionDOMElement.height / rect.height)) / this.resolution; + const resolutionMultiplier = navigator.isCocoonJS ? this.resolution : (1.0 / this.resolution); + + point.x = ((x - rect.left) * (this.interactionDOMElement.width / rect.width)) * resolutionMultiplier; + point.y = ((y - rect.top) * (this.interactionDOMElement.height / rect.height)) * resolutionMultiplier; } /** diff --git a/src/loaders/loader.js b/src/loaders/loader.js index c086919..978aa2d 100644 --- a/src/loaders/loader.js +++ b/src/loaders/loader.js @@ -12,7 +12,9 @@ * //or * let loader = new PIXI.loaders.Loader(); // you can also create your own if you want * - * loader.add('bunny',"data/bunny.png"); + * loader.add('bunny', 'data/bunny.png'); + * loader.add('spaceship', 'assets/spritesheet.json'); + * loader.add('scoreFont', 'assets/score.fnt'); * * loader.once('complete',onAssetsLoaded); * diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js index 2d637b1..2b30b1c 100644 --- a/src/loaders/spritesheetParser.js +++ b/src/loaders/spritesheetParser.js @@ -43,14 +43,22 @@ const frames = resource.data.frames; const frameKeys = Object.keys(frames); const baseTexture = res.texture.baseTexture; - let resolution = core.utils.getResolutionOfUrl(resource.url); const scale = resource.data.meta.scale; - // for now (to keep things compatible) resolution overrides scale - // Support scale field on spritesheet - if (resolution === 1 && scale !== undefined && scale !== 1) + // Use a defaultValue of `null` to check if a url-based resolution is set + let resolution = core.utils.getResolutionOfUrl(resource.url, null); + + // No resolution found via URL + if (resolution === null) { - baseTexture.resolution = resolution = scale; + // Use the scale value or default to 1 + resolution = scale !== undefined ? scale : 1; + } + + // For non-1 resolutions, update baseTexture + if (resolution !== 1) + { + baseTexture.resolution = resolution; baseTexture.update(); } diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 21e5a61..bbb0938 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -122,6 +122,15 @@ * @member {object} */ this._glDatas = {}; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'mesh' + */ + this.pluginName = 'mesh'; } /** @@ -132,8 +141,8 @@ */ _renderWebGL(renderer) { - renderer.setObjectRenderer(renderer.plugins.mesh); - renderer.plugins.mesh.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -144,7 +153,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.mesh.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/test/core/Ellipse.js b/test/core/Ellipse.js new file mode 100644 index 0000000..f2e8234 --- /dev/null +++ b/test/core/Ellipse.js @@ -0,0 +1,71 @@ +'use strict'; + +describe('PIXI.Ellipse', function () +{ + it('should create a new ellipse', function () + { + const ellipse1 = new PIXI.Ellipse(); + + expect(ellipse1.x).to.equal(0); + expect(ellipse1.y).to.equal(0); + expect(ellipse1.width).to.equal(0); + expect(ellipse1.height).to.equal(0); + + const ellipse2 = new PIXI.Ellipse(10, 10, 5, 5); + + expect(ellipse2.x).to.equal(10); + expect(ellipse2.y).to.equal(10); + expect(ellipse2.width).to.equal(5); + expect(ellipse2.height).to.equal(5); + }); + + it('should clone a new ellipse', function () + { + const ellipse1 = new PIXI.Ellipse(10, 10, 5, 5); + + expect(ellipse1.x).to.equal(10); + expect(ellipse1.y).to.equal(10); + expect(ellipse1.width).to.equal(5); + expect(ellipse1.height).to.equal(5); + + const ellipse2 = ellipse1.clone(); + + expect(ellipse2.x).to.equal(10); + expect(ellipse2.y).to.equal(10); + expect(ellipse2.width).to.equal(5); + expect(ellipse2.height).to.equal(5); + }); + + it('should check if point is within ellipse', function () + { + const ellipse1 = new PIXI.Ellipse(10, 10, 5, 5); + + expect(ellipse1.contains(10, 10)).to.be.true; + expect(ellipse1.contains(10, 15)).to.be.true; + expect(ellipse1.contains(15, 10)).to.be.true; + expect(ellipse1.contains(5, 10)).to.be.true; + expect(ellipse1.contains(15, 10)).to.be.true; + + expect(ellipse1.contains(6, 7)).to.be.true; + expect(ellipse1.contains(7, 6)).to.be.true; + expect(ellipse1.contains(7, 7)).to.be.true; + expect(ellipse1.contains(13, 14)).to.be.true; + expect(ellipse1.contains(14, 13)).to.be.true; + + expect(ellipse1.contains(14, 14)).to.be.false; + expect(ellipse1.contains(10, 16)).to.be.false; + expect(ellipse1.contains(11, 15)).to.be.false; + expect(ellipse1.contains(0, 0)).to.be.false; + }); + + it('should return framing rectangle', function () + { + const ellipse1 = new PIXI.Ellipse(10, 10, 5, 5); + const rect1 = ellipse1.getBounds(); + + expect(rect1.left).to.equal(5); + expect(rect1.top).to.equal(5); + expect(rect1.right).to.equal(10); + expect(rect1.bottom).to.equal(10); + }); +}); diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/src/core/display/TransformStatic.js b/src/core/display/TransformStatic.js index c0c2f33..1e8d0c6 100644 --- a/src/core/display/TransformStatic.js +++ b/src/core/display/TransformStatic.js @@ -47,12 +47,10 @@ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; this._localID = 0; this._currentLocalID = 0; @@ -69,16 +67,16 @@ } /** - * Called when skew changes + * Called when skew or rotation changes * * @private */ updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 this._localID ++; } @@ -93,15 +91,10 @@ if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -119,22 +112,15 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -147,6 +133,9 @@ if (this._parentID !== parentTransform._worldID) { // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -191,8 +180,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID ++; + this.updateSkew(); } } diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 9e65938..6f0a417 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -491,9 +491,10 @@ const startX = cx + (Math.cos(startAngle) * radius); const startY = cy + (Math.sin(startAngle) * radius); - const points = this.currentPath.shape.points; + // If the currentPath exists, take its points. Otherwise call `moveTo` to start a path. + let points = this.currentPath ? this.currentPath.shape.points : null; - if (this.currentPath) + if (points) { if (points[points.length - 2] !== startX || points[points.length - 1] !== startY) { @@ -503,6 +504,7 @@ else { this.moveTo(startX, startY); + points = this.currentPath.shape.points; } const theta = sweep / (segs * 2); @@ -691,6 +693,7 @@ this.lineWidth = 0; this.filling = false; + this.boundsDirty = -1; this.dirty++; this.clearDirty++; this.graphicsData.length = 0; diff --git a/src/core/math/Matrix.js b/src/core/math/Matrix.js index e3341fe..0b77477 100644 --- a/src/core/math/Matrix.js +++ b/src/core/math/Matrix.js @@ -353,10 +353,10 @@ const c = this.c; const d = this.d; - const skewX = Math.atan2(-c, d); + const skewX = -Math.atan2(-c, d); const skewY = Math.atan2(b, a); - const delta = Math.abs(1 - (skewX / skewY)); + const delta = Math.abs(skewX + skewY); if (delta < 0.00001) { diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js index afe4a89..c4f34be 100644 --- a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -2,7 +2,7 @@ * Creates a little colored canvas * * @ignore - * @param {number} color - The color to make the canvas + * @param {string} color - The color to make the canvas * @return {canvas} a small canvas element */ function createColoredCanvas(color) diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 3e58a00..025fef0 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -120,6 +120,15 @@ this._transformID = -1; this._textureID = -1; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'sprite' + */ + this.pluginName = 'sprite'; } /** @@ -282,8 +291,8 @@ { this.calculateVertices(); - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -294,7 +303,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.sprite.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index 20d4a0a..faeb91c 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -97,7 +97,7 @@ { const clonedProperties = {}; - for (const key in this._defaults) + for (const key in defaultStyle) { clonedProperties[key] = this[key]; } @@ -110,7 +110,7 @@ */ reset() { - Object.assign(this, this._defaults); + Object.assign(this, defaultStyle); } get align() @@ -435,22 +435,43 @@ * @param {number|number[]} color * @return {string} The color as a string. */ -function getColor(color) +function getSingleColor(color) { if (typeof color === 'number') { return hex2string(color); } - else if (Array.isArray(color)) + else if ( typeof color === 'string' ) { - for (let i = 0; i < color.length; ++i) + if ( color.indexOf('0x') === 0 ) { - if (typeof color[i] === 'number') - { - color[i] = hex2string(color[i]); - } + color = color.replace('0x', '#'); } } return color; } + +/** + * Utility function to convert hexadecimal colors to strings, and simply return the color if it's a string. + * This version can also convert array of colors + * + * @param {number|number[]} color + * @return {string} The color as a string. + */ +function getColor(color) +{ + if (!Array.isArray(color)) + { + return getSingleColor(color); + } + else + { + for (let i = 0; i < color.length; ++i) + { + color[i] = getSingleColor(color[i]); + } + + return color; + } +} diff --git a/src/core/utils/index.js b/src/core/utils/index.js index c82aaa4..2a7497b 100644 --- a/src/core/utils/index.js +++ b/src/core/utils/index.js @@ -103,9 +103,10 @@ * @memberof PIXI.utils * @function getResolutionOfUrl * @param {string} url - the image path + * @param {number} [defaultValue=1] - the defaultValue if no filename prefix is set. * @return {number} resolution / device pixel ratio of an asset */ -export function getResolutionOfUrl(url) +export function getResolutionOfUrl(url, defaultValue) { const resolution = settings.RETINA_PREFIX.exec(url); @@ -114,7 +115,7 @@ return parseFloat(resolution[1]); } - return 1; + return defaultValue !== undefined ? defaultValue : 1; } /** diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js index b9352e6..a8bcfba 100644 --- a/src/extras/TilingSprite.js +++ b/src/extras/TilingSprite.js @@ -61,6 +61,15 @@ * @member {PIXI.extras.TextureTransform} */ this.uvTransform = texture.transform || new TextureTransform(texture); + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' method. + * + * @member {string} + * @default 'tilingSprite' + */ + this.pluginName = 'tilingSprite'; } /** * Changes frame clamping in corresponding textureTransform, shortcut @@ -158,8 +167,8 @@ this.tileTransform.updateLocalTransform(); this.uvTransform.update(); - renderer.setObjectRenderer(renderer.plugins.tilingSprite); - renderer.plugins.tilingSprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/filters/blur/BlurFilter.js b/src/filters/blur/BlurFilter.js index 5b3c3a9..8a05893 100644 --- a/src/filters/blur/BlurFilter.js +++ b/src/filters/blur/BlurFilter.js @@ -15,14 +15,15 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { super(); - this.blurXFilter = new BlurXFilter(); - this.blurYFilter = new BlurYFilter(); + this.blurXFilter = new BlurXFilter(strength, quality, resolution, kernelSize); + this.blurYFilter = new BlurYFilter(strength, quality, resolution, kernelSize); this.resolution = 1; this.padding = 0; diff --git a/src/filters/blur/BlurXFilter.js b/src/filters/blur/BlurXFilter.js index 24181b6..338096c 100644 --- a/src/filters/blur/BlurXFilter.js +++ b/src/filters/blur/BlurXFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, true); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, true); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/filters/blur/BlurYFilter.js b/src/filters/blur/BlurYFilter.js index 267728b..94cbf37 100644 --- a/src/filters/blur/BlurYFilter.js +++ b/src/filters/blur/BlurYFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, false); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, false); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/interaction/InteractionEvent.js b/src/interaction/InteractionEvent.js index 0342469..75b2966 100644 --- a/src/interaction/InteractionEvent.js +++ b/src/interaction/InteractionEvent.js @@ -12,14 +12,15 @@ constructor() { /** - * Which this event will continue propagating in the tree + * Whether this event will continue propagating in the tree * * @member {boolean} */ this.stopped = false; /** - * The object to which event is dispatched. + * The object which caused this event to be dispatched. + * For listener callback see {@link PIXI.interaction.InteractionEvent.currentTarget}. * * @member {PIXI.DisplayObject} */ diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js index 94df60e..05f6628 100644 --- a/src/interaction/InteractionManager.js +++ b/src/interaction/InteractionManager.js @@ -105,15 +105,16 @@ this.interactionDOMElement = null; /** - * This property determins if mousemove and touchmove events are fired only when the cursror + * This property determines if mousemove and touchmove events are fired only when the cursror * is over the object. * Setting to true will make things work more in line with how the DOM verison works. * Setting to false can make things easier for things like dragging * It is currently set to false as this is how pixi used to work. This will be set to true in * future versions of pixi. * - * @private - * @member {boolean} + * @member {boolean} moveWhenInside + * @memberof PIXI.interaction.InteractionManager# + * @default false */ this.moveWhenInside = false; @@ -735,8 +736,10 @@ rect = this.interactionDOMElement.getBoundingClientRect(); } - point.x = ((x - rect.left) * (this.interactionDOMElement.width / rect.width)) / this.resolution; - point.y = ((y - rect.top) * (this.interactionDOMElement.height / rect.height)) / this.resolution; + const resolutionMultiplier = navigator.isCocoonJS ? this.resolution : (1.0 / this.resolution); + + point.x = ((x - rect.left) * (this.interactionDOMElement.width / rect.width)) * resolutionMultiplier; + point.y = ((y - rect.top) * (this.interactionDOMElement.height / rect.height)) * resolutionMultiplier; } /** diff --git a/src/loaders/loader.js b/src/loaders/loader.js index c086919..978aa2d 100644 --- a/src/loaders/loader.js +++ b/src/loaders/loader.js @@ -12,7 +12,9 @@ * //or * let loader = new PIXI.loaders.Loader(); // you can also create your own if you want * - * loader.add('bunny',"data/bunny.png"); + * loader.add('bunny', 'data/bunny.png'); + * loader.add('spaceship', 'assets/spritesheet.json'); + * loader.add('scoreFont', 'assets/score.fnt'); * * loader.once('complete',onAssetsLoaded); * diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js index 2d637b1..2b30b1c 100644 --- a/src/loaders/spritesheetParser.js +++ b/src/loaders/spritesheetParser.js @@ -43,14 +43,22 @@ const frames = resource.data.frames; const frameKeys = Object.keys(frames); const baseTexture = res.texture.baseTexture; - let resolution = core.utils.getResolutionOfUrl(resource.url); const scale = resource.data.meta.scale; - // for now (to keep things compatible) resolution overrides scale - // Support scale field on spritesheet - if (resolution === 1 && scale !== undefined && scale !== 1) + // Use a defaultValue of `null` to check if a url-based resolution is set + let resolution = core.utils.getResolutionOfUrl(resource.url, null); + + // No resolution found via URL + if (resolution === null) { - baseTexture.resolution = resolution = scale; + // Use the scale value or default to 1 + resolution = scale !== undefined ? scale : 1; + } + + // For non-1 resolutions, update baseTexture + if (resolution !== 1) + { + baseTexture.resolution = resolution; baseTexture.update(); } diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 21e5a61..bbb0938 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -122,6 +122,15 @@ * @member {object} */ this._glDatas = {}; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'mesh' + */ + this.pluginName = 'mesh'; } /** @@ -132,8 +141,8 @@ */ _renderWebGL(renderer) { - renderer.setObjectRenderer(renderer.plugins.mesh); - renderer.plugins.mesh.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -144,7 +153,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.mesh.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/test/core/Ellipse.js b/test/core/Ellipse.js new file mode 100644 index 0000000..f2e8234 --- /dev/null +++ b/test/core/Ellipse.js @@ -0,0 +1,71 @@ +'use strict'; + +describe('PIXI.Ellipse', function () +{ + it('should create a new ellipse', function () + { + const ellipse1 = new PIXI.Ellipse(); + + expect(ellipse1.x).to.equal(0); + expect(ellipse1.y).to.equal(0); + expect(ellipse1.width).to.equal(0); + expect(ellipse1.height).to.equal(0); + + const ellipse2 = new PIXI.Ellipse(10, 10, 5, 5); + + expect(ellipse2.x).to.equal(10); + expect(ellipse2.y).to.equal(10); + expect(ellipse2.width).to.equal(5); + expect(ellipse2.height).to.equal(5); + }); + + it('should clone a new ellipse', function () + { + const ellipse1 = new PIXI.Ellipse(10, 10, 5, 5); + + expect(ellipse1.x).to.equal(10); + expect(ellipse1.y).to.equal(10); + expect(ellipse1.width).to.equal(5); + expect(ellipse1.height).to.equal(5); + + const ellipse2 = ellipse1.clone(); + + expect(ellipse2.x).to.equal(10); + expect(ellipse2.y).to.equal(10); + expect(ellipse2.width).to.equal(5); + expect(ellipse2.height).to.equal(5); + }); + + it('should check if point is within ellipse', function () + { + const ellipse1 = new PIXI.Ellipse(10, 10, 5, 5); + + expect(ellipse1.contains(10, 10)).to.be.true; + expect(ellipse1.contains(10, 15)).to.be.true; + expect(ellipse1.contains(15, 10)).to.be.true; + expect(ellipse1.contains(5, 10)).to.be.true; + expect(ellipse1.contains(15, 10)).to.be.true; + + expect(ellipse1.contains(6, 7)).to.be.true; + expect(ellipse1.contains(7, 6)).to.be.true; + expect(ellipse1.contains(7, 7)).to.be.true; + expect(ellipse1.contains(13, 14)).to.be.true; + expect(ellipse1.contains(14, 13)).to.be.true; + + expect(ellipse1.contains(14, 14)).to.be.false; + expect(ellipse1.contains(10, 16)).to.be.false; + expect(ellipse1.contains(11, 15)).to.be.false; + expect(ellipse1.contains(0, 0)).to.be.false; + }); + + it('should return framing rectangle', function () + { + const ellipse1 = new PIXI.Ellipse(10, 10, 5, 5); + const rect1 = ellipse1.getBounds(); + + expect(rect1.left).to.equal(5); + expect(rect1.top).to.equal(5); + expect(rect1.right).to.equal(10); + expect(rect1.bottom).to.equal(10); + }); +}); diff --git a/test/core/Graphics.js b/test/core/Graphics.js index c7c7a45..0622cfc 100644 --- a/test/core/Graphics.js +++ b/test/core/Graphics.js @@ -128,4 +128,67 @@ expect(graphics.containsPoint(point)).to.be.false; }); }); + + describe('arc', () => + { + it('should draw an arc', () => + { + const graphics = new PIXI.Graphics(); + + expect(graphics.currentPath).to.be.null; + + expect(() => graphics.arc(100, 30, 20, 0, Math.PI)).to.not.throw(); + + expect(graphics.currentPath).to.be.not.null; + }); + + it('should not throw with other shapes', () => + { + // complex drawing #1: draw triangle, rounder rect and an arc (issue #3433) + const graphics = new PIXI.Graphics(); + + // set a fill and line style + graphics.beginFill(0xFF3300); + graphics.lineStyle(4, 0xffd900, 1); + + // draw a shape + graphics.moveTo(50, 50); + graphics.lineTo(250, 50); + graphics.lineTo(100, 100); + graphics.lineTo(50, 50); + graphics.endFill(); + + graphics.lineStyle(2, 0xFF00FF, 1); + graphics.beginFill(0xFF00BB, 0.25); + graphics.drawRoundedRect(150, 450, 300, 100, 15); + graphics.endFill(); + + graphics.beginFill(); + graphics.lineStyle(4, 0x00ff00, 1); + + expect(() => graphics.arc(300, 100, 20, 0, Math.PI)).to.not.throw(); + }); + + it('should do nothing when startAngle and endAngle are equal', () => + { + const graphics = new PIXI.Graphics(); + + expect(graphics.currentPath).to.be.null; + + graphics.arc(0, 0, 10, 0, 0); + + expect(graphics.currentPath).to.be.null; + }); + + it('should do nothing if sweep equals zero', () => + { + const graphics = new PIXI.Graphics(); + + expect(graphics.currentPath).to.be.null; + + graphics.arc(0, 0, 10, 10, 10); + + expect(graphics.currentPath).to.be.null; + }); + }); }); diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/src/core/display/TransformStatic.js b/src/core/display/TransformStatic.js index c0c2f33..1e8d0c6 100644 --- a/src/core/display/TransformStatic.js +++ b/src/core/display/TransformStatic.js @@ -47,12 +47,10 @@ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; this._localID = 0; this._currentLocalID = 0; @@ -69,16 +67,16 @@ } /** - * Called when skew changes + * Called when skew or rotation changes * * @private */ updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 this._localID ++; } @@ -93,15 +91,10 @@ if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -119,22 +112,15 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -147,6 +133,9 @@ if (this._parentID !== parentTransform._worldID) { // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -191,8 +180,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID ++; + this.updateSkew(); } } diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 9e65938..6f0a417 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -491,9 +491,10 @@ const startX = cx + (Math.cos(startAngle) * radius); const startY = cy + (Math.sin(startAngle) * radius); - const points = this.currentPath.shape.points; + // If the currentPath exists, take its points. Otherwise call `moveTo` to start a path. + let points = this.currentPath ? this.currentPath.shape.points : null; - if (this.currentPath) + if (points) { if (points[points.length - 2] !== startX || points[points.length - 1] !== startY) { @@ -503,6 +504,7 @@ else { this.moveTo(startX, startY); + points = this.currentPath.shape.points; } const theta = sweep / (segs * 2); @@ -691,6 +693,7 @@ this.lineWidth = 0; this.filling = false; + this.boundsDirty = -1; this.dirty++; this.clearDirty++; this.graphicsData.length = 0; diff --git a/src/core/math/Matrix.js b/src/core/math/Matrix.js index e3341fe..0b77477 100644 --- a/src/core/math/Matrix.js +++ b/src/core/math/Matrix.js @@ -353,10 +353,10 @@ const c = this.c; const d = this.d; - const skewX = Math.atan2(-c, d); + const skewX = -Math.atan2(-c, d); const skewY = Math.atan2(b, a); - const delta = Math.abs(1 - (skewX / skewY)); + const delta = Math.abs(skewX + skewY); if (delta < 0.00001) { diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js index afe4a89..c4f34be 100644 --- a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -2,7 +2,7 @@ * Creates a little colored canvas * * @ignore - * @param {number} color - The color to make the canvas + * @param {string} color - The color to make the canvas * @return {canvas} a small canvas element */ function createColoredCanvas(color) diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 3e58a00..025fef0 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -120,6 +120,15 @@ this._transformID = -1; this._textureID = -1; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'sprite' + */ + this.pluginName = 'sprite'; } /** @@ -282,8 +291,8 @@ { this.calculateVertices(); - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -294,7 +303,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.sprite.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index 20d4a0a..faeb91c 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -97,7 +97,7 @@ { const clonedProperties = {}; - for (const key in this._defaults) + for (const key in defaultStyle) { clonedProperties[key] = this[key]; } @@ -110,7 +110,7 @@ */ reset() { - Object.assign(this, this._defaults); + Object.assign(this, defaultStyle); } get align() @@ -435,22 +435,43 @@ * @param {number|number[]} color * @return {string} The color as a string. */ -function getColor(color) +function getSingleColor(color) { if (typeof color === 'number') { return hex2string(color); } - else if (Array.isArray(color)) + else if ( typeof color === 'string' ) { - for (let i = 0; i < color.length; ++i) + if ( color.indexOf('0x') === 0 ) { - if (typeof color[i] === 'number') - { - color[i] = hex2string(color[i]); - } + color = color.replace('0x', '#'); } } return color; } + +/** + * Utility function to convert hexadecimal colors to strings, and simply return the color if it's a string. + * This version can also convert array of colors + * + * @param {number|number[]} color + * @return {string} The color as a string. + */ +function getColor(color) +{ + if (!Array.isArray(color)) + { + return getSingleColor(color); + } + else + { + for (let i = 0; i < color.length; ++i) + { + color[i] = getSingleColor(color[i]); + } + + return color; + } +} diff --git a/src/core/utils/index.js b/src/core/utils/index.js index c82aaa4..2a7497b 100644 --- a/src/core/utils/index.js +++ b/src/core/utils/index.js @@ -103,9 +103,10 @@ * @memberof PIXI.utils * @function getResolutionOfUrl * @param {string} url - the image path + * @param {number} [defaultValue=1] - the defaultValue if no filename prefix is set. * @return {number} resolution / device pixel ratio of an asset */ -export function getResolutionOfUrl(url) +export function getResolutionOfUrl(url, defaultValue) { const resolution = settings.RETINA_PREFIX.exec(url); @@ -114,7 +115,7 @@ return parseFloat(resolution[1]); } - return 1; + return defaultValue !== undefined ? defaultValue : 1; } /** diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js index b9352e6..a8bcfba 100644 --- a/src/extras/TilingSprite.js +++ b/src/extras/TilingSprite.js @@ -61,6 +61,15 @@ * @member {PIXI.extras.TextureTransform} */ this.uvTransform = texture.transform || new TextureTransform(texture); + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' method. + * + * @member {string} + * @default 'tilingSprite' + */ + this.pluginName = 'tilingSprite'; } /** * Changes frame clamping in corresponding textureTransform, shortcut @@ -158,8 +167,8 @@ this.tileTransform.updateLocalTransform(); this.uvTransform.update(); - renderer.setObjectRenderer(renderer.plugins.tilingSprite); - renderer.plugins.tilingSprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/filters/blur/BlurFilter.js b/src/filters/blur/BlurFilter.js index 5b3c3a9..8a05893 100644 --- a/src/filters/blur/BlurFilter.js +++ b/src/filters/blur/BlurFilter.js @@ -15,14 +15,15 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { super(); - this.blurXFilter = new BlurXFilter(); - this.blurYFilter = new BlurYFilter(); + this.blurXFilter = new BlurXFilter(strength, quality, resolution, kernelSize); + this.blurYFilter = new BlurYFilter(strength, quality, resolution, kernelSize); this.resolution = 1; this.padding = 0; diff --git a/src/filters/blur/BlurXFilter.js b/src/filters/blur/BlurXFilter.js index 24181b6..338096c 100644 --- a/src/filters/blur/BlurXFilter.js +++ b/src/filters/blur/BlurXFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, true); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, true); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/filters/blur/BlurYFilter.js b/src/filters/blur/BlurYFilter.js index 267728b..94cbf37 100644 --- a/src/filters/blur/BlurYFilter.js +++ b/src/filters/blur/BlurYFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, false); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, false); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/interaction/InteractionEvent.js b/src/interaction/InteractionEvent.js index 0342469..75b2966 100644 --- a/src/interaction/InteractionEvent.js +++ b/src/interaction/InteractionEvent.js @@ -12,14 +12,15 @@ constructor() { /** - * Which this event will continue propagating in the tree + * Whether this event will continue propagating in the tree * * @member {boolean} */ this.stopped = false; /** - * The object to which event is dispatched. + * The object which caused this event to be dispatched. + * For listener callback see {@link PIXI.interaction.InteractionEvent.currentTarget}. * * @member {PIXI.DisplayObject} */ diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js index 94df60e..05f6628 100644 --- a/src/interaction/InteractionManager.js +++ b/src/interaction/InteractionManager.js @@ -105,15 +105,16 @@ this.interactionDOMElement = null; /** - * This property determins if mousemove and touchmove events are fired only when the cursror + * This property determines if mousemove and touchmove events are fired only when the cursror * is over the object. * Setting to true will make things work more in line with how the DOM verison works. * Setting to false can make things easier for things like dragging * It is currently set to false as this is how pixi used to work. This will be set to true in * future versions of pixi. * - * @private - * @member {boolean} + * @member {boolean} moveWhenInside + * @memberof PIXI.interaction.InteractionManager# + * @default false */ this.moveWhenInside = false; @@ -735,8 +736,10 @@ rect = this.interactionDOMElement.getBoundingClientRect(); } - point.x = ((x - rect.left) * (this.interactionDOMElement.width / rect.width)) / this.resolution; - point.y = ((y - rect.top) * (this.interactionDOMElement.height / rect.height)) / this.resolution; + const resolutionMultiplier = navigator.isCocoonJS ? this.resolution : (1.0 / this.resolution); + + point.x = ((x - rect.left) * (this.interactionDOMElement.width / rect.width)) * resolutionMultiplier; + point.y = ((y - rect.top) * (this.interactionDOMElement.height / rect.height)) * resolutionMultiplier; } /** diff --git a/src/loaders/loader.js b/src/loaders/loader.js index c086919..978aa2d 100644 --- a/src/loaders/loader.js +++ b/src/loaders/loader.js @@ -12,7 +12,9 @@ * //or * let loader = new PIXI.loaders.Loader(); // you can also create your own if you want * - * loader.add('bunny',"data/bunny.png"); + * loader.add('bunny', 'data/bunny.png'); + * loader.add('spaceship', 'assets/spritesheet.json'); + * loader.add('scoreFont', 'assets/score.fnt'); * * loader.once('complete',onAssetsLoaded); * diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js index 2d637b1..2b30b1c 100644 --- a/src/loaders/spritesheetParser.js +++ b/src/loaders/spritesheetParser.js @@ -43,14 +43,22 @@ const frames = resource.data.frames; const frameKeys = Object.keys(frames); const baseTexture = res.texture.baseTexture; - let resolution = core.utils.getResolutionOfUrl(resource.url); const scale = resource.data.meta.scale; - // for now (to keep things compatible) resolution overrides scale - // Support scale field on spritesheet - if (resolution === 1 && scale !== undefined && scale !== 1) + // Use a defaultValue of `null` to check if a url-based resolution is set + let resolution = core.utils.getResolutionOfUrl(resource.url, null); + + // No resolution found via URL + if (resolution === null) { - baseTexture.resolution = resolution = scale; + // Use the scale value or default to 1 + resolution = scale !== undefined ? scale : 1; + } + + // For non-1 resolutions, update baseTexture + if (resolution !== 1) + { + baseTexture.resolution = resolution; baseTexture.update(); } diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 21e5a61..bbb0938 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -122,6 +122,15 @@ * @member {object} */ this._glDatas = {}; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'mesh' + */ + this.pluginName = 'mesh'; } /** @@ -132,8 +141,8 @@ */ _renderWebGL(renderer) { - renderer.setObjectRenderer(renderer.plugins.mesh); - renderer.plugins.mesh.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -144,7 +153,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.mesh.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/test/core/Ellipse.js b/test/core/Ellipse.js new file mode 100644 index 0000000..f2e8234 --- /dev/null +++ b/test/core/Ellipse.js @@ -0,0 +1,71 @@ +'use strict'; + +describe('PIXI.Ellipse', function () +{ + it('should create a new ellipse', function () + { + const ellipse1 = new PIXI.Ellipse(); + + expect(ellipse1.x).to.equal(0); + expect(ellipse1.y).to.equal(0); + expect(ellipse1.width).to.equal(0); + expect(ellipse1.height).to.equal(0); + + const ellipse2 = new PIXI.Ellipse(10, 10, 5, 5); + + expect(ellipse2.x).to.equal(10); + expect(ellipse2.y).to.equal(10); + expect(ellipse2.width).to.equal(5); + expect(ellipse2.height).to.equal(5); + }); + + it('should clone a new ellipse', function () + { + const ellipse1 = new PIXI.Ellipse(10, 10, 5, 5); + + expect(ellipse1.x).to.equal(10); + expect(ellipse1.y).to.equal(10); + expect(ellipse1.width).to.equal(5); + expect(ellipse1.height).to.equal(5); + + const ellipse2 = ellipse1.clone(); + + expect(ellipse2.x).to.equal(10); + expect(ellipse2.y).to.equal(10); + expect(ellipse2.width).to.equal(5); + expect(ellipse2.height).to.equal(5); + }); + + it('should check if point is within ellipse', function () + { + const ellipse1 = new PIXI.Ellipse(10, 10, 5, 5); + + expect(ellipse1.contains(10, 10)).to.be.true; + expect(ellipse1.contains(10, 15)).to.be.true; + expect(ellipse1.contains(15, 10)).to.be.true; + expect(ellipse1.contains(5, 10)).to.be.true; + expect(ellipse1.contains(15, 10)).to.be.true; + + expect(ellipse1.contains(6, 7)).to.be.true; + expect(ellipse1.contains(7, 6)).to.be.true; + expect(ellipse1.contains(7, 7)).to.be.true; + expect(ellipse1.contains(13, 14)).to.be.true; + expect(ellipse1.contains(14, 13)).to.be.true; + + expect(ellipse1.contains(14, 14)).to.be.false; + expect(ellipse1.contains(10, 16)).to.be.false; + expect(ellipse1.contains(11, 15)).to.be.false; + expect(ellipse1.contains(0, 0)).to.be.false; + }); + + it('should return framing rectangle', function () + { + const ellipse1 = new PIXI.Ellipse(10, 10, 5, 5); + const rect1 = ellipse1.getBounds(); + + expect(rect1.left).to.equal(5); + expect(rect1.top).to.equal(5); + expect(rect1.right).to.equal(10); + expect(rect1.bottom).to.equal(10); + }); +}); diff --git a/test/core/Graphics.js b/test/core/Graphics.js index c7c7a45..0622cfc 100644 --- a/test/core/Graphics.js +++ b/test/core/Graphics.js @@ -128,4 +128,67 @@ expect(graphics.containsPoint(point)).to.be.false; }); }); + + describe('arc', () => + { + it('should draw an arc', () => + { + const graphics = new PIXI.Graphics(); + + expect(graphics.currentPath).to.be.null; + + expect(() => graphics.arc(100, 30, 20, 0, Math.PI)).to.not.throw(); + + expect(graphics.currentPath).to.be.not.null; + }); + + it('should not throw with other shapes', () => + { + // complex drawing #1: draw triangle, rounder rect and an arc (issue #3433) + const graphics = new PIXI.Graphics(); + + // set a fill and line style + graphics.beginFill(0xFF3300); + graphics.lineStyle(4, 0xffd900, 1); + + // draw a shape + graphics.moveTo(50, 50); + graphics.lineTo(250, 50); + graphics.lineTo(100, 100); + graphics.lineTo(50, 50); + graphics.endFill(); + + graphics.lineStyle(2, 0xFF00FF, 1); + graphics.beginFill(0xFF00BB, 0.25); + graphics.drawRoundedRect(150, 450, 300, 100, 15); + graphics.endFill(); + + graphics.beginFill(); + graphics.lineStyle(4, 0x00ff00, 1); + + expect(() => graphics.arc(300, 100, 20, 0, Math.PI)).to.not.throw(); + }); + + it('should do nothing when startAngle and endAngle are equal', () => + { + const graphics = new PIXI.Graphics(); + + expect(graphics.currentPath).to.be.null; + + graphics.arc(0, 0, 10, 0, 0); + + expect(graphics.currentPath).to.be.null; + }); + + it('should do nothing if sweep equals zero', () => + { + const graphics = new PIXI.Graphics(); + + expect(graphics.currentPath).to.be.null; + + graphics.arc(0, 0, 10, 10, 10); + + expect(graphics.currentPath).to.be.null; + }); + }); }); diff --git a/test/core/TextStyle.js b/test/core/TextStyle.js new file mode 100644 index 0000000..b5761ad --- /dev/null +++ b/test/core/TextStyle.js @@ -0,0 +1,26 @@ +'use strict'; + +describe('PIXI.TextStyle', function () +{ + it('reset reverts style to default', function () + { + const textStyle = new PIXI.TextStyle(); + const defaultFontSize = textStyle.fontSize; + + textStyle.fontSize = 1000; + + expect(textStyle.fontSize).to.equal(1000); + textStyle.reset(); + expect(textStyle.fontSize).to.equal(defaultFontSize); + }); + + it('should clone correctly', function () + { + const textStyle = new PIXI.TextStyle({ fontSize: 1000 }); + + const clonedTextStyle = textStyle.clone(); + + expect(textStyle.fontSize).to.equal(1000); + expect(clonedTextStyle.fontSize).to.equal(textStyle.fontSize); + }); +}); diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/src/core/display/TransformStatic.js b/src/core/display/TransformStatic.js index c0c2f33..1e8d0c6 100644 --- a/src/core/display/TransformStatic.js +++ b/src/core/display/TransformStatic.js @@ -47,12 +47,10 @@ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; this._localID = 0; this._currentLocalID = 0; @@ -69,16 +67,16 @@ } /** - * Called when skew changes + * Called when skew or rotation changes * * @private */ updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 this._localID ++; } @@ -93,15 +91,10 @@ if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -119,22 +112,15 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -147,6 +133,9 @@ if (this._parentID !== parentTransform._worldID) { // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -191,8 +180,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID ++; + this.updateSkew(); } } diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 9e65938..6f0a417 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -491,9 +491,10 @@ const startX = cx + (Math.cos(startAngle) * radius); const startY = cy + (Math.sin(startAngle) * radius); - const points = this.currentPath.shape.points; + // If the currentPath exists, take its points. Otherwise call `moveTo` to start a path. + let points = this.currentPath ? this.currentPath.shape.points : null; - if (this.currentPath) + if (points) { if (points[points.length - 2] !== startX || points[points.length - 1] !== startY) { @@ -503,6 +504,7 @@ else { this.moveTo(startX, startY); + points = this.currentPath.shape.points; } const theta = sweep / (segs * 2); @@ -691,6 +693,7 @@ this.lineWidth = 0; this.filling = false; + this.boundsDirty = -1; this.dirty++; this.clearDirty++; this.graphicsData.length = 0; diff --git a/src/core/math/Matrix.js b/src/core/math/Matrix.js index e3341fe..0b77477 100644 --- a/src/core/math/Matrix.js +++ b/src/core/math/Matrix.js @@ -353,10 +353,10 @@ const c = this.c; const d = this.d; - const skewX = Math.atan2(-c, d); + const skewX = -Math.atan2(-c, d); const skewY = Math.atan2(b, a); - const delta = Math.abs(1 - (skewX / skewY)); + const delta = Math.abs(skewX + skewY); if (delta < 0.00001) { diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js index afe4a89..c4f34be 100644 --- a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -2,7 +2,7 @@ * Creates a little colored canvas * * @ignore - * @param {number} color - The color to make the canvas + * @param {string} color - The color to make the canvas * @return {canvas} a small canvas element */ function createColoredCanvas(color) diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 3e58a00..025fef0 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -120,6 +120,15 @@ this._transformID = -1; this._textureID = -1; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'sprite' + */ + this.pluginName = 'sprite'; } /** @@ -282,8 +291,8 @@ { this.calculateVertices(); - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -294,7 +303,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.sprite.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index 20d4a0a..faeb91c 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -97,7 +97,7 @@ { const clonedProperties = {}; - for (const key in this._defaults) + for (const key in defaultStyle) { clonedProperties[key] = this[key]; } @@ -110,7 +110,7 @@ */ reset() { - Object.assign(this, this._defaults); + Object.assign(this, defaultStyle); } get align() @@ -435,22 +435,43 @@ * @param {number|number[]} color * @return {string} The color as a string. */ -function getColor(color) +function getSingleColor(color) { if (typeof color === 'number') { return hex2string(color); } - else if (Array.isArray(color)) + else if ( typeof color === 'string' ) { - for (let i = 0; i < color.length; ++i) + if ( color.indexOf('0x') === 0 ) { - if (typeof color[i] === 'number') - { - color[i] = hex2string(color[i]); - } + color = color.replace('0x', '#'); } } return color; } + +/** + * Utility function to convert hexadecimal colors to strings, and simply return the color if it's a string. + * This version can also convert array of colors + * + * @param {number|number[]} color + * @return {string} The color as a string. + */ +function getColor(color) +{ + if (!Array.isArray(color)) + { + return getSingleColor(color); + } + else + { + for (let i = 0; i < color.length; ++i) + { + color[i] = getSingleColor(color[i]); + } + + return color; + } +} diff --git a/src/core/utils/index.js b/src/core/utils/index.js index c82aaa4..2a7497b 100644 --- a/src/core/utils/index.js +++ b/src/core/utils/index.js @@ -103,9 +103,10 @@ * @memberof PIXI.utils * @function getResolutionOfUrl * @param {string} url - the image path + * @param {number} [defaultValue=1] - the defaultValue if no filename prefix is set. * @return {number} resolution / device pixel ratio of an asset */ -export function getResolutionOfUrl(url) +export function getResolutionOfUrl(url, defaultValue) { const resolution = settings.RETINA_PREFIX.exec(url); @@ -114,7 +115,7 @@ return parseFloat(resolution[1]); } - return 1; + return defaultValue !== undefined ? defaultValue : 1; } /** diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js index b9352e6..a8bcfba 100644 --- a/src/extras/TilingSprite.js +++ b/src/extras/TilingSprite.js @@ -61,6 +61,15 @@ * @member {PIXI.extras.TextureTransform} */ this.uvTransform = texture.transform || new TextureTransform(texture); + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' method. + * + * @member {string} + * @default 'tilingSprite' + */ + this.pluginName = 'tilingSprite'; } /** * Changes frame clamping in corresponding textureTransform, shortcut @@ -158,8 +167,8 @@ this.tileTransform.updateLocalTransform(); this.uvTransform.update(); - renderer.setObjectRenderer(renderer.plugins.tilingSprite); - renderer.plugins.tilingSprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/filters/blur/BlurFilter.js b/src/filters/blur/BlurFilter.js index 5b3c3a9..8a05893 100644 --- a/src/filters/blur/BlurFilter.js +++ b/src/filters/blur/BlurFilter.js @@ -15,14 +15,15 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { super(); - this.blurXFilter = new BlurXFilter(); - this.blurYFilter = new BlurYFilter(); + this.blurXFilter = new BlurXFilter(strength, quality, resolution, kernelSize); + this.blurYFilter = new BlurYFilter(strength, quality, resolution, kernelSize); this.resolution = 1; this.padding = 0; diff --git a/src/filters/blur/BlurXFilter.js b/src/filters/blur/BlurXFilter.js index 24181b6..338096c 100644 --- a/src/filters/blur/BlurXFilter.js +++ b/src/filters/blur/BlurXFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, true); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, true); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/filters/blur/BlurYFilter.js b/src/filters/blur/BlurYFilter.js index 267728b..94cbf37 100644 --- a/src/filters/blur/BlurYFilter.js +++ b/src/filters/blur/BlurYFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, false); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, false); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/interaction/InteractionEvent.js b/src/interaction/InteractionEvent.js index 0342469..75b2966 100644 --- a/src/interaction/InteractionEvent.js +++ b/src/interaction/InteractionEvent.js @@ -12,14 +12,15 @@ constructor() { /** - * Which this event will continue propagating in the tree + * Whether this event will continue propagating in the tree * * @member {boolean} */ this.stopped = false; /** - * The object to which event is dispatched. + * The object which caused this event to be dispatched. + * For listener callback see {@link PIXI.interaction.InteractionEvent.currentTarget}. * * @member {PIXI.DisplayObject} */ diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js index 94df60e..05f6628 100644 --- a/src/interaction/InteractionManager.js +++ b/src/interaction/InteractionManager.js @@ -105,15 +105,16 @@ this.interactionDOMElement = null; /** - * This property determins if mousemove and touchmove events are fired only when the cursror + * This property determines if mousemove and touchmove events are fired only when the cursror * is over the object. * Setting to true will make things work more in line with how the DOM verison works. * Setting to false can make things easier for things like dragging * It is currently set to false as this is how pixi used to work. This will be set to true in * future versions of pixi. * - * @private - * @member {boolean} + * @member {boolean} moveWhenInside + * @memberof PIXI.interaction.InteractionManager# + * @default false */ this.moveWhenInside = false; @@ -735,8 +736,10 @@ rect = this.interactionDOMElement.getBoundingClientRect(); } - point.x = ((x - rect.left) * (this.interactionDOMElement.width / rect.width)) / this.resolution; - point.y = ((y - rect.top) * (this.interactionDOMElement.height / rect.height)) / this.resolution; + const resolutionMultiplier = navigator.isCocoonJS ? this.resolution : (1.0 / this.resolution); + + point.x = ((x - rect.left) * (this.interactionDOMElement.width / rect.width)) * resolutionMultiplier; + point.y = ((y - rect.top) * (this.interactionDOMElement.height / rect.height)) * resolutionMultiplier; } /** diff --git a/src/loaders/loader.js b/src/loaders/loader.js index c086919..978aa2d 100644 --- a/src/loaders/loader.js +++ b/src/loaders/loader.js @@ -12,7 +12,9 @@ * //or * let loader = new PIXI.loaders.Loader(); // you can also create your own if you want * - * loader.add('bunny',"data/bunny.png"); + * loader.add('bunny', 'data/bunny.png'); + * loader.add('spaceship', 'assets/spritesheet.json'); + * loader.add('scoreFont', 'assets/score.fnt'); * * loader.once('complete',onAssetsLoaded); * diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js index 2d637b1..2b30b1c 100644 --- a/src/loaders/spritesheetParser.js +++ b/src/loaders/spritesheetParser.js @@ -43,14 +43,22 @@ const frames = resource.data.frames; const frameKeys = Object.keys(frames); const baseTexture = res.texture.baseTexture; - let resolution = core.utils.getResolutionOfUrl(resource.url); const scale = resource.data.meta.scale; - // for now (to keep things compatible) resolution overrides scale - // Support scale field on spritesheet - if (resolution === 1 && scale !== undefined && scale !== 1) + // Use a defaultValue of `null` to check if a url-based resolution is set + let resolution = core.utils.getResolutionOfUrl(resource.url, null); + + // No resolution found via URL + if (resolution === null) { - baseTexture.resolution = resolution = scale; + // Use the scale value or default to 1 + resolution = scale !== undefined ? scale : 1; + } + + // For non-1 resolutions, update baseTexture + if (resolution !== 1) + { + baseTexture.resolution = resolution; baseTexture.update(); } diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 21e5a61..bbb0938 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -122,6 +122,15 @@ * @member {object} */ this._glDatas = {}; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'mesh' + */ + this.pluginName = 'mesh'; } /** @@ -132,8 +141,8 @@ */ _renderWebGL(renderer) { - renderer.setObjectRenderer(renderer.plugins.mesh); - renderer.plugins.mesh.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -144,7 +153,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.mesh.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/test/core/Ellipse.js b/test/core/Ellipse.js new file mode 100644 index 0000000..f2e8234 --- /dev/null +++ b/test/core/Ellipse.js @@ -0,0 +1,71 @@ +'use strict'; + +describe('PIXI.Ellipse', function () +{ + it('should create a new ellipse', function () + { + const ellipse1 = new PIXI.Ellipse(); + + expect(ellipse1.x).to.equal(0); + expect(ellipse1.y).to.equal(0); + expect(ellipse1.width).to.equal(0); + expect(ellipse1.height).to.equal(0); + + const ellipse2 = new PIXI.Ellipse(10, 10, 5, 5); + + expect(ellipse2.x).to.equal(10); + expect(ellipse2.y).to.equal(10); + expect(ellipse2.width).to.equal(5); + expect(ellipse2.height).to.equal(5); + }); + + it('should clone a new ellipse', function () + { + const ellipse1 = new PIXI.Ellipse(10, 10, 5, 5); + + expect(ellipse1.x).to.equal(10); + expect(ellipse1.y).to.equal(10); + expect(ellipse1.width).to.equal(5); + expect(ellipse1.height).to.equal(5); + + const ellipse2 = ellipse1.clone(); + + expect(ellipse2.x).to.equal(10); + expect(ellipse2.y).to.equal(10); + expect(ellipse2.width).to.equal(5); + expect(ellipse2.height).to.equal(5); + }); + + it('should check if point is within ellipse', function () + { + const ellipse1 = new PIXI.Ellipse(10, 10, 5, 5); + + expect(ellipse1.contains(10, 10)).to.be.true; + expect(ellipse1.contains(10, 15)).to.be.true; + expect(ellipse1.contains(15, 10)).to.be.true; + expect(ellipse1.contains(5, 10)).to.be.true; + expect(ellipse1.contains(15, 10)).to.be.true; + + expect(ellipse1.contains(6, 7)).to.be.true; + expect(ellipse1.contains(7, 6)).to.be.true; + expect(ellipse1.contains(7, 7)).to.be.true; + expect(ellipse1.contains(13, 14)).to.be.true; + expect(ellipse1.contains(14, 13)).to.be.true; + + expect(ellipse1.contains(14, 14)).to.be.false; + expect(ellipse1.contains(10, 16)).to.be.false; + expect(ellipse1.contains(11, 15)).to.be.false; + expect(ellipse1.contains(0, 0)).to.be.false; + }); + + it('should return framing rectangle', function () + { + const ellipse1 = new PIXI.Ellipse(10, 10, 5, 5); + const rect1 = ellipse1.getBounds(); + + expect(rect1.left).to.equal(5); + expect(rect1.top).to.equal(5); + expect(rect1.right).to.equal(10); + expect(rect1.bottom).to.equal(10); + }); +}); diff --git a/test/core/Graphics.js b/test/core/Graphics.js index c7c7a45..0622cfc 100644 --- a/test/core/Graphics.js +++ b/test/core/Graphics.js @@ -128,4 +128,67 @@ expect(graphics.containsPoint(point)).to.be.false; }); }); + + describe('arc', () => + { + it('should draw an arc', () => + { + const graphics = new PIXI.Graphics(); + + expect(graphics.currentPath).to.be.null; + + expect(() => graphics.arc(100, 30, 20, 0, Math.PI)).to.not.throw(); + + expect(graphics.currentPath).to.be.not.null; + }); + + it('should not throw with other shapes', () => + { + // complex drawing #1: draw triangle, rounder rect and an arc (issue #3433) + const graphics = new PIXI.Graphics(); + + // set a fill and line style + graphics.beginFill(0xFF3300); + graphics.lineStyle(4, 0xffd900, 1); + + // draw a shape + graphics.moveTo(50, 50); + graphics.lineTo(250, 50); + graphics.lineTo(100, 100); + graphics.lineTo(50, 50); + graphics.endFill(); + + graphics.lineStyle(2, 0xFF00FF, 1); + graphics.beginFill(0xFF00BB, 0.25); + graphics.drawRoundedRect(150, 450, 300, 100, 15); + graphics.endFill(); + + graphics.beginFill(); + graphics.lineStyle(4, 0x00ff00, 1); + + expect(() => graphics.arc(300, 100, 20, 0, Math.PI)).to.not.throw(); + }); + + it('should do nothing when startAngle and endAngle are equal', () => + { + const graphics = new PIXI.Graphics(); + + expect(graphics.currentPath).to.be.null; + + graphics.arc(0, 0, 10, 0, 0); + + expect(graphics.currentPath).to.be.null; + }); + + it('should do nothing if sweep equals zero', () => + { + const graphics = new PIXI.Graphics(); + + expect(graphics.currentPath).to.be.null; + + graphics.arc(0, 0, 10, 10, 10); + + expect(graphics.currentPath).to.be.null; + }); + }); }); diff --git a/test/core/TextStyle.js b/test/core/TextStyle.js new file mode 100644 index 0000000..b5761ad --- /dev/null +++ b/test/core/TextStyle.js @@ -0,0 +1,26 @@ +'use strict'; + +describe('PIXI.TextStyle', function () +{ + it('reset reverts style to default', function () + { + const textStyle = new PIXI.TextStyle(); + const defaultFontSize = textStyle.fontSize; + + textStyle.fontSize = 1000; + + expect(textStyle.fontSize).to.equal(1000); + textStyle.reset(); + expect(textStyle.fontSize).to.equal(defaultFontSize); + }); + + it('should clone correctly', function () + { + const textStyle = new PIXI.TextStyle({ fontSize: 1000 }); + + const clonedTextStyle = textStyle.clone(); + + expect(textStyle.fontSize).to.equal(1000); + expect(clonedTextStyle.fontSize).to.equal(textStyle.fontSize); + }); +}); diff --git a/test/core/TransformStatic.js b/test/core/TransformStatic.js new file mode 100644 index 0000000..bb9607a --- /dev/null +++ b/test/core/TransformStatic.js @@ -0,0 +1,102 @@ +'use strict'; + +describe('PIXI.TransformStatic', () => +{ + describe('setFromMatrix', () => + { + it('should decompose negative scale into rotation', () => + { + const eps = 1e-3; + + const transform = new PIXI.TransformStatic(); + const parent = new PIXI.TransformStatic(); + const otherTransform = new PIXI.TransformStatic(); + + transform.position.set(20, 10); + transform.scale.set(-2, -3); + transform.rotation = Math.PI / 6; + transform.updateTransform(parent); + + otherTransform.setFromMatrix(transform.worldTransform); + + const position = otherTransform.position; + const scale = otherTransform.scale; + const skew = otherTransform.skew; + + expect(position.x).to.be.closeTo(20, eps); + expect(position.y).to.be.closeTo(10, eps); + expect(scale.x).to.be.closeTo(2, eps); + expect(scale.y).to.be.closeTo(3, eps); + expect(skew.x).to.equal(0); + expect(skew.y).to.equal(0); + expect(otherTransform.rotation).to.be.closeTo(-5 * Math.PI / 6, eps); + }); + + it('should decompose mirror into skew', () => + { + const eps = 1e-3; + + const transform = new PIXI.TransformStatic(); + const parent = new PIXI.TransformStatic(); + const otherTransform = new PIXI.TransformStatic(); + + transform.position.set(20, 10); + transform.scale.set(2, -3); + transform.rotation = Math.PI / 6; + transform.updateTransform(parent); + + otherTransform.setFromMatrix(transform.worldTransform); + + const position = otherTransform.position; + const scale = otherTransform.scale; + const skew = otherTransform.skew; + + expect(position.x).to.be.closeTo(20, eps); + expect(position.y).to.be.closeTo(10, eps); + expect(scale.x).to.be.closeTo(2, eps); + expect(scale.y).to.be.closeTo(3, eps); + expect(skew.x).to.be.closeTo(5 * Math.PI / 6, eps); + expect(skew.y).to.be.closeTo(Math.PI / 6, eps); + expect(otherTransform.rotation).to.equal(0); + }); + + it('should apply skew before scale, like in adobe animate and spine', () => + { + // this example looks the same in CSS and in pixi, made with pixi-animate by @bigtimebuddy + + const eps = 1e-3; + + const transform = new PIXI.TransformStatic(); + const parent = new PIXI.TransformStatic(); + const otherTransform = new PIXI.TransformStatic(); + + transform.position.set(387.8, 313.95); + transform.scale.set(0.572, 4.101); + transform.skew.set(-0.873, 0.175); + transform.updateTransform(parent); + + const mat = transform.worldTransform; + + expect(mat.a).to.be.closeTo(0.563, eps); + expect(mat.b).to.be.closeTo(0.100, eps); + expect(mat.c).to.be.closeTo(-3.142, eps); + expect(mat.d).to.be.closeTo(2.635, eps); + expect(mat.tx).to.be.closeTo(387.8, eps); + expect(mat.ty).to.be.closeTo(313.95, eps); + + otherTransform.setFromMatrix(transform.worldTransform); + + const position = otherTransform.position; + const scale = otherTransform.scale; + const skew = otherTransform.skew; + + expect(position.x).to.be.closeTo(387.8, eps); + expect(position.y).to.be.closeTo(313.95, eps); + expect(scale.x).to.be.closeTo(0.572, eps); + expect(scale.y).to.be.closeTo(4.101, eps); + expect(skew.x).to.be.closeTo(-0.873, eps); + expect(skew.y).to.be.closeTo(0.175, eps); + expect(otherTransform.rotation).to.be.equal(0); + }); + }); +}); diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/src/core/display/TransformStatic.js b/src/core/display/TransformStatic.js index c0c2f33..1e8d0c6 100644 --- a/src/core/display/TransformStatic.js +++ b/src/core/display/TransformStatic.js @@ -47,12 +47,10 @@ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; this._localID = 0; this._currentLocalID = 0; @@ -69,16 +67,16 @@ } /** - * Called when skew changes + * Called when skew or rotation changes * * @private */ updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 this._localID ++; } @@ -93,15 +91,10 @@ if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -119,22 +112,15 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -147,6 +133,9 @@ if (this._parentID !== parentTransform._worldID) { // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -191,8 +180,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID ++; + this.updateSkew(); } } diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 9e65938..6f0a417 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -491,9 +491,10 @@ const startX = cx + (Math.cos(startAngle) * radius); const startY = cy + (Math.sin(startAngle) * radius); - const points = this.currentPath.shape.points; + // If the currentPath exists, take its points. Otherwise call `moveTo` to start a path. + let points = this.currentPath ? this.currentPath.shape.points : null; - if (this.currentPath) + if (points) { if (points[points.length - 2] !== startX || points[points.length - 1] !== startY) { @@ -503,6 +504,7 @@ else { this.moveTo(startX, startY); + points = this.currentPath.shape.points; } const theta = sweep / (segs * 2); @@ -691,6 +693,7 @@ this.lineWidth = 0; this.filling = false; + this.boundsDirty = -1; this.dirty++; this.clearDirty++; this.graphicsData.length = 0; diff --git a/src/core/math/Matrix.js b/src/core/math/Matrix.js index e3341fe..0b77477 100644 --- a/src/core/math/Matrix.js +++ b/src/core/math/Matrix.js @@ -353,10 +353,10 @@ const c = this.c; const d = this.d; - const skewX = Math.atan2(-c, d); + const skewX = -Math.atan2(-c, d); const skewY = Math.atan2(b, a); - const delta = Math.abs(1 - (skewX / skewY)); + const delta = Math.abs(skewX + skewY); if (delta < 0.00001) { diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js index afe4a89..c4f34be 100644 --- a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -2,7 +2,7 @@ * Creates a little colored canvas * * @ignore - * @param {number} color - The color to make the canvas + * @param {string} color - The color to make the canvas * @return {canvas} a small canvas element */ function createColoredCanvas(color) diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 3e58a00..025fef0 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -120,6 +120,15 @@ this._transformID = -1; this._textureID = -1; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'sprite' + */ + this.pluginName = 'sprite'; } /** @@ -282,8 +291,8 @@ { this.calculateVertices(); - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -294,7 +303,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.sprite.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index 20d4a0a..faeb91c 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -97,7 +97,7 @@ { const clonedProperties = {}; - for (const key in this._defaults) + for (const key in defaultStyle) { clonedProperties[key] = this[key]; } @@ -110,7 +110,7 @@ */ reset() { - Object.assign(this, this._defaults); + Object.assign(this, defaultStyle); } get align() @@ -435,22 +435,43 @@ * @param {number|number[]} color * @return {string} The color as a string. */ -function getColor(color) +function getSingleColor(color) { if (typeof color === 'number') { return hex2string(color); } - else if (Array.isArray(color)) + else if ( typeof color === 'string' ) { - for (let i = 0; i < color.length; ++i) + if ( color.indexOf('0x') === 0 ) { - if (typeof color[i] === 'number') - { - color[i] = hex2string(color[i]); - } + color = color.replace('0x', '#'); } } return color; } + +/** + * Utility function to convert hexadecimal colors to strings, and simply return the color if it's a string. + * This version can also convert array of colors + * + * @param {number|number[]} color + * @return {string} The color as a string. + */ +function getColor(color) +{ + if (!Array.isArray(color)) + { + return getSingleColor(color); + } + else + { + for (let i = 0; i < color.length; ++i) + { + color[i] = getSingleColor(color[i]); + } + + return color; + } +} diff --git a/src/core/utils/index.js b/src/core/utils/index.js index c82aaa4..2a7497b 100644 --- a/src/core/utils/index.js +++ b/src/core/utils/index.js @@ -103,9 +103,10 @@ * @memberof PIXI.utils * @function getResolutionOfUrl * @param {string} url - the image path + * @param {number} [defaultValue=1] - the defaultValue if no filename prefix is set. * @return {number} resolution / device pixel ratio of an asset */ -export function getResolutionOfUrl(url) +export function getResolutionOfUrl(url, defaultValue) { const resolution = settings.RETINA_PREFIX.exec(url); @@ -114,7 +115,7 @@ return parseFloat(resolution[1]); } - return 1; + return defaultValue !== undefined ? defaultValue : 1; } /** diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js index b9352e6..a8bcfba 100644 --- a/src/extras/TilingSprite.js +++ b/src/extras/TilingSprite.js @@ -61,6 +61,15 @@ * @member {PIXI.extras.TextureTransform} */ this.uvTransform = texture.transform || new TextureTransform(texture); + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' method. + * + * @member {string} + * @default 'tilingSprite' + */ + this.pluginName = 'tilingSprite'; } /** * Changes frame clamping in corresponding textureTransform, shortcut @@ -158,8 +167,8 @@ this.tileTransform.updateLocalTransform(); this.uvTransform.update(); - renderer.setObjectRenderer(renderer.plugins.tilingSprite); - renderer.plugins.tilingSprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/filters/blur/BlurFilter.js b/src/filters/blur/BlurFilter.js index 5b3c3a9..8a05893 100644 --- a/src/filters/blur/BlurFilter.js +++ b/src/filters/blur/BlurFilter.js @@ -15,14 +15,15 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { super(); - this.blurXFilter = new BlurXFilter(); - this.blurYFilter = new BlurYFilter(); + this.blurXFilter = new BlurXFilter(strength, quality, resolution, kernelSize); + this.blurYFilter = new BlurYFilter(strength, quality, resolution, kernelSize); this.resolution = 1; this.padding = 0; diff --git a/src/filters/blur/BlurXFilter.js b/src/filters/blur/BlurXFilter.js index 24181b6..338096c 100644 --- a/src/filters/blur/BlurXFilter.js +++ b/src/filters/blur/BlurXFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, true); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, true); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/filters/blur/BlurYFilter.js b/src/filters/blur/BlurYFilter.js index 267728b..94cbf37 100644 --- a/src/filters/blur/BlurYFilter.js +++ b/src/filters/blur/BlurYFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, false); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, false); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/interaction/InteractionEvent.js b/src/interaction/InteractionEvent.js index 0342469..75b2966 100644 --- a/src/interaction/InteractionEvent.js +++ b/src/interaction/InteractionEvent.js @@ -12,14 +12,15 @@ constructor() { /** - * Which this event will continue propagating in the tree + * Whether this event will continue propagating in the tree * * @member {boolean} */ this.stopped = false; /** - * The object to which event is dispatched. + * The object which caused this event to be dispatched. + * For listener callback see {@link PIXI.interaction.InteractionEvent.currentTarget}. * * @member {PIXI.DisplayObject} */ diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js index 94df60e..05f6628 100644 --- a/src/interaction/InteractionManager.js +++ b/src/interaction/InteractionManager.js @@ -105,15 +105,16 @@ this.interactionDOMElement = null; /** - * This property determins if mousemove and touchmove events are fired only when the cursror + * This property determines if mousemove and touchmove events are fired only when the cursror * is over the object. * Setting to true will make things work more in line with how the DOM verison works. * Setting to false can make things easier for things like dragging * It is currently set to false as this is how pixi used to work. This will be set to true in * future versions of pixi. * - * @private - * @member {boolean} + * @member {boolean} moveWhenInside + * @memberof PIXI.interaction.InteractionManager# + * @default false */ this.moveWhenInside = false; @@ -735,8 +736,10 @@ rect = this.interactionDOMElement.getBoundingClientRect(); } - point.x = ((x - rect.left) * (this.interactionDOMElement.width / rect.width)) / this.resolution; - point.y = ((y - rect.top) * (this.interactionDOMElement.height / rect.height)) / this.resolution; + const resolutionMultiplier = navigator.isCocoonJS ? this.resolution : (1.0 / this.resolution); + + point.x = ((x - rect.left) * (this.interactionDOMElement.width / rect.width)) * resolutionMultiplier; + point.y = ((y - rect.top) * (this.interactionDOMElement.height / rect.height)) * resolutionMultiplier; } /** diff --git a/src/loaders/loader.js b/src/loaders/loader.js index c086919..978aa2d 100644 --- a/src/loaders/loader.js +++ b/src/loaders/loader.js @@ -12,7 +12,9 @@ * //or * let loader = new PIXI.loaders.Loader(); // you can also create your own if you want * - * loader.add('bunny',"data/bunny.png"); + * loader.add('bunny', 'data/bunny.png'); + * loader.add('spaceship', 'assets/spritesheet.json'); + * loader.add('scoreFont', 'assets/score.fnt'); * * loader.once('complete',onAssetsLoaded); * diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js index 2d637b1..2b30b1c 100644 --- a/src/loaders/spritesheetParser.js +++ b/src/loaders/spritesheetParser.js @@ -43,14 +43,22 @@ const frames = resource.data.frames; const frameKeys = Object.keys(frames); const baseTexture = res.texture.baseTexture; - let resolution = core.utils.getResolutionOfUrl(resource.url); const scale = resource.data.meta.scale; - // for now (to keep things compatible) resolution overrides scale - // Support scale field on spritesheet - if (resolution === 1 && scale !== undefined && scale !== 1) + // Use a defaultValue of `null` to check if a url-based resolution is set + let resolution = core.utils.getResolutionOfUrl(resource.url, null); + + // No resolution found via URL + if (resolution === null) { - baseTexture.resolution = resolution = scale; + // Use the scale value or default to 1 + resolution = scale !== undefined ? scale : 1; + } + + // For non-1 resolutions, update baseTexture + if (resolution !== 1) + { + baseTexture.resolution = resolution; baseTexture.update(); } diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 21e5a61..bbb0938 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -122,6 +122,15 @@ * @member {object} */ this._glDatas = {}; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'mesh' + */ + this.pluginName = 'mesh'; } /** @@ -132,8 +141,8 @@ */ _renderWebGL(renderer) { - renderer.setObjectRenderer(renderer.plugins.mesh); - renderer.plugins.mesh.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -144,7 +153,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.mesh.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/test/core/Ellipse.js b/test/core/Ellipse.js new file mode 100644 index 0000000..f2e8234 --- /dev/null +++ b/test/core/Ellipse.js @@ -0,0 +1,71 @@ +'use strict'; + +describe('PIXI.Ellipse', function () +{ + it('should create a new ellipse', function () + { + const ellipse1 = new PIXI.Ellipse(); + + expect(ellipse1.x).to.equal(0); + expect(ellipse1.y).to.equal(0); + expect(ellipse1.width).to.equal(0); + expect(ellipse1.height).to.equal(0); + + const ellipse2 = new PIXI.Ellipse(10, 10, 5, 5); + + expect(ellipse2.x).to.equal(10); + expect(ellipse2.y).to.equal(10); + expect(ellipse2.width).to.equal(5); + expect(ellipse2.height).to.equal(5); + }); + + it('should clone a new ellipse', function () + { + const ellipse1 = new PIXI.Ellipse(10, 10, 5, 5); + + expect(ellipse1.x).to.equal(10); + expect(ellipse1.y).to.equal(10); + expect(ellipse1.width).to.equal(5); + expect(ellipse1.height).to.equal(5); + + const ellipse2 = ellipse1.clone(); + + expect(ellipse2.x).to.equal(10); + expect(ellipse2.y).to.equal(10); + expect(ellipse2.width).to.equal(5); + expect(ellipse2.height).to.equal(5); + }); + + it('should check if point is within ellipse', function () + { + const ellipse1 = new PIXI.Ellipse(10, 10, 5, 5); + + expect(ellipse1.contains(10, 10)).to.be.true; + expect(ellipse1.contains(10, 15)).to.be.true; + expect(ellipse1.contains(15, 10)).to.be.true; + expect(ellipse1.contains(5, 10)).to.be.true; + expect(ellipse1.contains(15, 10)).to.be.true; + + expect(ellipse1.contains(6, 7)).to.be.true; + expect(ellipse1.contains(7, 6)).to.be.true; + expect(ellipse1.contains(7, 7)).to.be.true; + expect(ellipse1.contains(13, 14)).to.be.true; + expect(ellipse1.contains(14, 13)).to.be.true; + + expect(ellipse1.contains(14, 14)).to.be.false; + expect(ellipse1.contains(10, 16)).to.be.false; + expect(ellipse1.contains(11, 15)).to.be.false; + expect(ellipse1.contains(0, 0)).to.be.false; + }); + + it('should return framing rectangle', function () + { + const ellipse1 = new PIXI.Ellipse(10, 10, 5, 5); + const rect1 = ellipse1.getBounds(); + + expect(rect1.left).to.equal(5); + expect(rect1.top).to.equal(5); + expect(rect1.right).to.equal(10); + expect(rect1.bottom).to.equal(10); + }); +}); diff --git a/test/core/Graphics.js b/test/core/Graphics.js index c7c7a45..0622cfc 100644 --- a/test/core/Graphics.js +++ b/test/core/Graphics.js @@ -128,4 +128,67 @@ expect(graphics.containsPoint(point)).to.be.false; }); }); + + describe('arc', () => + { + it('should draw an arc', () => + { + const graphics = new PIXI.Graphics(); + + expect(graphics.currentPath).to.be.null; + + expect(() => graphics.arc(100, 30, 20, 0, Math.PI)).to.not.throw(); + + expect(graphics.currentPath).to.be.not.null; + }); + + it('should not throw with other shapes', () => + { + // complex drawing #1: draw triangle, rounder rect and an arc (issue #3433) + const graphics = new PIXI.Graphics(); + + // set a fill and line style + graphics.beginFill(0xFF3300); + graphics.lineStyle(4, 0xffd900, 1); + + // draw a shape + graphics.moveTo(50, 50); + graphics.lineTo(250, 50); + graphics.lineTo(100, 100); + graphics.lineTo(50, 50); + graphics.endFill(); + + graphics.lineStyle(2, 0xFF00FF, 1); + graphics.beginFill(0xFF00BB, 0.25); + graphics.drawRoundedRect(150, 450, 300, 100, 15); + graphics.endFill(); + + graphics.beginFill(); + graphics.lineStyle(4, 0x00ff00, 1); + + expect(() => graphics.arc(300, 100, 20, 0, Math.PI)).to.not.throw(); + }); + + it('should do nothing when startAngle and endAngle are equal', () => + { + const graphics = new PIXI.Graphics(); + + expect(graphics.currentPath).to.be.null; + + graphics.arc(0, 0, 10, 0, 0); + + expect(graphics.currentPath).to.be.null; + }); + + it('should do nothing if sweep equals zero', () => + { + const graphics = new PIXI.Graphics(); + + expect(graphics.currentPath).to.be.null; + + graphics.arc(0, 0, 10, 10, 10); + + expect(graphics.currentPath).to.be.null; + }); + }); }); diff --git a/test/core/TextStyle.js b/test/core/TextStyle.js new file mode 100644 index 0000000..b5761ad --- /dev/null +++ b/test/core/TextStyle.js @@ -0,0 +1,26 @@ +'use strict'; + +describe('PIXI.TextStyle', function () +{ + it('reset reverts style to default', function () + { + const textStyle = new PIXI.TextStyle(); + const defaultFontSize = textStyle.fontSize; + + textStyle.fontSize = 1000; + + expect(textStyle.fontSize).to.equal(1000); + textStyle.reset(); + expect(textStyle.fontSize).to.equal(defaultFontSize); + }); + + it('should clone correctly', function () + { + const textStyle = new PIXI.TextStyle({ fontSize: 1000 }); + + const clonedTextStyle = textStyle.clone(); + + expect(textStyle.fontSize).to.equal(1000); + expect(clonedTextStyle.fontSize).to.equal(textStyle.fontSize); + }); +}); diff --git a/test/core/TransformStatic.js b/test/core/TransformStatic.js new file mode 100644 index 0000000..bb9607a --- /dev/null +++ b/test/core/TransformStatic.js @@ -0,0 +1,102 @@ +'use strict'; + +describe('PIXI.TransformStatic', () => +{ + describe('setFromMatrix', () => + { + it('should decompose negative scale into rotation', () => + { + const eps = 1e-3; + + const transform = new PIXI.TransformStatic(); + const parent = new PIXI.TransformStatic(); + const otherTransform = new PIXI.TransformStatic(); + + transform.position.set(20, 10); + transform.scale.set(-2, -3); + transform.rotation = Math.PI / 6; + transform.updateTransform(parent); + + otherTransform.setFromMatrix(transform.worldTransform); + + const position = otherTransform.position; + const scale = otherTransform.scale; + const skew = otherTransform.skew; + + expect(position.x).to.be.closeTo(20, eps); + expect(position.y).to.be.closeTo(10, eps); + expect(scale.x).to.be.closeTo(2, eps); + expect(scale.y).to.be.closeTo(3, eps); + expect(skew.x).to.equal(0); + expect(skew.y).to.equal(0); + expect(otherTransform.rotation).to.be.closeTo(-5 * Math.PI / 6, eps); + }); + + it('should decompose mirror into skew', () => + { + const eps = 1e-3; + + const transform = new PIXI.TransformStatic(); + const parent = new PIXI.TransformStatic(); + const otherTransform = new PIXI.TransformStatic(); + + transform.position.set(20, 10); + transform.scale.set(2, -3); + transform.rotation = Math.PI / 6; + transform.updateTransform(parent); + + otherTransform.setFromMatrix(transform.worldTransform); + + const position = otherTransform.position; + const scale = otherTransform.scale; + const skew = otherTransform.skew; + + expect(position.x).to.be.closeTo(20, eps); + expect(position.y).to.be.closeTo(10, eps); + expect(scale.x).to.be.closeTo(2, eps); + expect(scale.y).to.be.closeTo(3, eps); + expect(skew.x).to.be.closeTo(5 * Math.PI / 6, eps); + expect(skew.y).to.be.closeTo(Math.PI / 6, eps); + expect(otherTransform.rotation).to.equal(0); + }); + + it('should apply skew before scale, like in adobe animate and spine', () => + { + // this example looks the same in CSS and in pixi, made with pixi-animate by @bigtimebuddy + + const eps = 1e-3; + + const transform = new PIXI.TransformStatic(); + const parent = new PIXI.TransformStatic(); + const otherTransform = new PIXI.TransformStatic(); + + transform.position.set(387.8, 313.95); + transform.scale.set(0.572, 4.101); + transform.skew.set(-0.873, 0.175); + transform.updateTransform(parent); + + const mat = transform.worldTransform; + + expect(mat.a).to.be.closeTo(0.563, eps); + expect(mat.b).to.be.closeTo(0.100, eps); + expect(mat.c).to.be.closeTo(-3.142, eps); + expect(mat.d).to.be.closeTo(2.635, eps); + expect(mat.tx).to.be.closeTo(387.8, eps); + expect(mat.ty).to.be.closeTo(313.95, eps); + + otherTransform.setFromMatrix(transform.worldTransform); + + const position = otherTransform.position; + const scale = otherTransform.scale; + const skew = otherTransform.skew; + + expect(position.x).to.be.closeTo(387.8, eps); + expect(position.y).to.be.closeTo(313.95, eps); + expect(scale.x).to.be.closeTo(0.572, eps); + expect(scale.y).to.be.closeTo(4.101, eps); + expect(skew.x).to.be.closeTo(-0.873, eps); + expect(skew.y).to.be.closeTo(0.175, eps); + expect(otherTransform.rotation).to.be.equal(0); + }); + }); +}); diff --git a/test/core/getLocalBounds.js b/test/core/getLocalBounds.js index 5835b9f..d160a56 100644 --- a/test/core/getLocalBounds.js +++ b/test/core/getLocalBounds.js @@ -38,9 +38,7 @@ const graphics = new PIXI.Graphics(); - graphics.beginFill(0xFF0000).drawCircle(0, 0, 10);// texture); - - graphics.scale.set(2); + graphics.beginFill(0xFF0000).drawCircle(0, 0, 10); parent.addChild(graphics); @@ -52,11 +50,73 @@ expect(bounds.height).to.equal(20); }); + it('should register correct local-bounds with Graphics after clear', function () + { + const parent = new PIXI.Container(); + + const graphics = new PIXI.Graphics(); + + graphics.beginFill(0xFF0000).drawRect(0, 0, 20, 20); + + parent.addChild(graphics); + + let bounds = graphics.getLocalBounds(); + + expect(bounds.x).to.equal(0); + expect(bounds.y).to.equal(0); + expect(bounds.width).to.equal(20); + expect(bounds.height).to.equal(20); + + graphics.clear(); + graphics.beginFill(0xFF, 1); + graphics.drawRect(0, 0, 10, 10); + graphics.endFill(); + + bounds = graphics.getLocalBounds(); + + expect(bounds.x).to.equal(0); + expect(bounds.y).to.equal(0); + expect(bounds.width).to.equal(10); + expect(bounds.height).to.equal(10); + }); + + it('should register correct local-bounds with Graphics after generateCanvasTexture and clear', function () + { + const parent = new PIXI.Container(); + + const graphics = new PIXI.Graphics(); + + graphics.beginFill(0xFF0000).drawRect(0, 0, 20, 20); + + parent.addChild(graphics); + + let bounds = graphics.getLocalBounds(); + + graphics.generateCanvasTexture(); + + expect(bounds.x).to.equal(0); + expect(bounds.y).to.equal(0); + expect(bounds.width).to.equal(20); + expect(bounds.height).to.equal(20); + + graphics.clear(); + graphics.beginFill(0xFF, 1); + graphics.drawRect(0, 0, 10, 10); + graphics.endFill(); + + bounds = graphics.getLocalBounds(); + + expect(bounds.x).to.equal(0); + expect(bounds.y).to.equal(0); + expect(bounds.width).to.equal(10); + expect(bounds.height).to.equal(10); + }); + it('should register correct local-bounds with an empty Container', function () { const parent = new PIXI.Container(); - const container = new PIXI.Container();// Graphics().beginFill(0xFF0000).drawCircle(0, 0, 10, 10);//texture); + const container = new PIXI.Container(); parent.addChild(container); @@ -72,9 +132,9 @@ { const parent = new PIXI.Container(); - const container = new PIXI.Container();// Graphics().beginFill(0xFF0000).drawCircle(0, 0, 10, 10);//texture); + const container = new PIXI.Container(); - const graphics = new PIXI.Graphics().beginFill(0xFF0000).drawRect(0, 0, 10, 10);// texture); + const graphics = new PIXI.Graphics().beginFill(0xFF0000).drawRect(0, 0, 10, 10); parent.addChild(container); container.addChild(graphics); diff --git a/package.json b/package.json index dae5f9a..844f742 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pixi.js", - "version": "4.2.3", + "version": "4.3.0", "description": "Pixi.js is a fast lightweight 2D library that works across all devices.", "author": "Mat Groves", "contributors": [ @@ -34,8 +34,11 @@ "lintfix": "npm run lint --fix", "prebuild": "npm run lint", "build": "npm run dist", + "predist": "rimraf dist/**", "dist": "pixify -d dist -n PIXI -o pixi -t babelify", + "prelib": "rimraf lib/**", "lib": "babel src --out-dir lib -s", + "predocs": "rimraf docs/**", "docs": "jsdoc -c scripts/jsdoc.conf.json -R README.md", "publish:patch": "npm version patch --no-git-tag-version && npm publish", "publish:minor": "npm version minor --no-git-tag-version && npm publish", diff --git a/src/core/display/Transform.js b/src/core/display/Transform.js index 8611925..35ed5e6 100644 --- a/src/core/display/Transform.js +++ b/src/core/display/Transform.js @@ -54,25 +54,23 @@ */ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; } /** - * Updates the skew values when the skew changes. + * Updates the skew values when the skew or rotation changes. * * @private */ updateSkew() { - this._cy = Math.cos(this.skew.y); - this._sy = Math.sin(this.skew.y); - this._nsx = Math.sin(this.skew.x); - this._cx = Math.cos(this.skew.x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 } /** @@ -81,15 +79,14 @@ updateLocalTransform() { const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; + + lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); + lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); } /** @@ -99,24 +96,20 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; - const a = this._cr * this.scale.x; - const b = this._sr * this.scale.x; - const c = -this._sr * this.scale.y; - const d = this._cr * this.scale.y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale.x; + lt.b = this._sx * this.scale.x; + lt.c = this._cy * this.scale.y; + lt.d = this._sy * this.scale.y; lt.tx = this.position.x - ((this.pivot.x * lt.a) + (this.pivot.y * lt.c)); lt.ty = this.position.y - ((this.pivot.x * lt.b) + (this.pivot.y * lt.d)); // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -156,7 +149,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); + this.updateSkew(); } } diff --git a/src/core/display/TransformStatic.js b/src/core/display/TransformStatic.js index c0c2f33..1e8d0c6 100644 --- a/src/core/display/TransformStatic.js +++ b/src/core/display/TransformStatic.js @@ -47,12 +47,10 @@ this._rotation = 0; - this._sr = Math.sin(0); - this._cr = Math.cos(0); - this._cy = Math.cos(0);// skewY); - this._sy = Math.sin(0);// skewY); - this._nsx = Math.sin(0);// skewX); - this._cx = Math.cos(0);// skewX); + this._cx = 1; // cos rotation + skewY; + this._sx = 0; // sin rotation + skewY; + this._cy = 0; // cos rotation + Math.PI/2 - skewX; + this._sy = 1; // sin rotation + Math.PI/2 - skewX; this._localID = 0; this._currentLocalID = 0; @@ -69,16 +67,16 @@ } /** - * Called when skew changes + * Called when skew or rotation changes * * @private */ updateSkew() { - this._cy = Math.cos(this.skew._y); - this._sy = Math.sin(this.skew._y); - this._nsx = Math.sin(this.skew._x); - this._cx = Math.cos(this.skew._x); + this._cx = Math.cos(this._rotation + this.skew._y); + this._sx = Math.sin(this._rotation + this.skew._y); + this._cy = -Math.sin(this._rotation - this.skew._x); // cos, added PI/2 + this._sy = Math.cos(this._rotation - this.skew._x); // sin, added PI/2 this._localID ++; } @@ -93,15 +91,10 @@ if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -119,22 +112,15 @@ */ updateTransform(parentTransform) { - const pt = parentTransform.worldTransform; - const wt = this.worldTransform; const lt = this.localTransform; if (this._localID !== this._currentLocalID) { // get the matrix values of the displayobject based on its transform properties.. - const a = this._cr * this.scale._x; - const b = this._sr * this.scale._x; - const c = -this._sr * this.scale._y; - const d = this._cr * this.scale._y; - - lt.a = (this._cy * a) + (this._sy * c); - lt.b = (this._cy * b) + (this._sy * d); - lt.c = (this._nsx * a) + (this._cx * c); - lt.d = (this._nsx * b) + (this._cx * d); + lt.a = this._cx * this.scale._x; + lt.b = this._sx * this.scale._x; + lt.c = this._cy * this.scale._y; + lt.d = this._sy * this.scale._y; lt.tx = this.position._x - ((this.pivot._x * lt.a) + (this.pivot._y * lt.c)); lt.ty = this.position._y - ((this.pivot._x * lt.b) + (this.pivot._y * lt.d)); @@ -147,6 +133,9 @@ if (this._parentID !== parentTransform._worldID) { // concat the parent matrix with the objects transform. + const pt = parentTransform.worldTransform; + const wt = this.worldTransform; + wt.a = (lt.a * pt.a) + (lt.b * pt.c); wt.b = (lt.a * pt.b) + (lt.b * pt.d); wt.c = (lt.c * pt.a) + (lt.d * pt.c); @@ -191,8 +180,6 @@ set rotation(value) { this._rotation = value; - this._sr = Math.sin(value); - this._cr = Math.cos(value); - this._localID ++; + this.updateSkew(); } } diff --git a/src/core/graphics/Graphics.js b/src/core/graphics/Graphics.js index 9e65938..6f0a417 100644 --- a/src/core/graphics/Graphics.js +++ b/src/core/graphics/Graphics.js @@ -491,9 +491,10 @@ const startX = cx + (Math.cos(startAngle) * radius); const startY = cy + (Math.sin(startAngle) * radius); - const points = this.currentPath.shape.points; + // If the currentPath exists, take its points. Otherwise call `moveTo` to start a path. + let points = this.currentPath ? this.currentPath.shape.points : null; - if (this.currentPath) + if (points) { if (points[points.length - 2] !== startX || points[points.length - 1] !== startY) { @@ -503,6 +504,7 @@ else { this.moveTo(startX, startY); + points = this.currentPath.shape.points; } const theta = sweep / (segs * 2); @@ -691,6 +693,7 @@ this.lineWidth = 0; this.filling = false; + this.boundsDirty = -1; this.dirty++; this.clearDirty++; this.graphicsData.length = 0; diff --git a/src/core/math/Matrix.js b/src/core/math/Matrix.js index e3341fe..0b77477 100644 --- a/src/core/math/Matrix.js +++ b/src/core/math/Matrix.js @@ -353,10 +353,10 @@ const c = this.c; const d = this.d; - const skewX = Math.atan2(-c, d); + const skewX = -Math.atan2(-c, d); const skewY = Math.atan2(b, a); - const delta = Math.abs(1 - (skewX / skewY)); + const delta = Math.abs(skewX + skewY); if (delta < 0.00001) { diff --git a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js index afe4a89..c4f34be 100644 --- a/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js +++ b/src/core/renderers/canvas/utils/canUseNewCanvasBlendModes.js @@ -2,7 +2,7 @@ * Creates a little colored canvas * * @ignore - * @param {number} color - The color to make the canvas + * @param {string} color - The color to make the canvas * @return {canvas} a small canvas element */ function createColoredCanvas(color) diff --git a/src/core/sprites/Sprite.js b/src/core/sprites/Sprite.js index 3e58a00..025fef0 100644 --- a/src/core/sprites/Sprite.js +++ b/src/core/sprites/Sprite.js @@ -120,6 +120,15 @@ this._transformID = -1; this._textureID = -1; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'sprite' + */ + this.pluginName = 'sprite'; } /** @@ -282,8 +291,8 @@ { this.calculateVertices(); - renderer.setObjectRenderer(renderer.plugins.sprite); - renderer.plugins.sprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -294,7 +303,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.sprite.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/core/text/TextStyle.js b/src/core/text/TextStyle.js index 20d4a0a..faeb91c 100644 --- a/src/core/text/TextStyle.js +++ b/src/core/text/TextStyle.js @@ -97,7 +97,7 @@ { const clonedProperties = {}; - for (const key in this._defaults) + for (const key in defaultStyle) { clonedProperties[key] = this[key]; } @@ -110,7 +110,7 @@ */ reset() { - Object.assign(this, this._defaults); + Object.assign(this, defaultStyle); } get align() @@ -435,22 +435,43 @@ * @param {number|number[]} color * @return {string} The color as a string. */ -function getColor(color) +function getSingleColor(color) { if (typeof color === 'number') { return hex2string(color); } - else if (Array.isArray(color)) + else if ( typeof color === 'string' ) { - for (let i = 0; i < color.length; ++i) + if ( color.indexOf('0x') === 0 ) { - if (typeof color[i] === 'number') - { - color[i] = hex2string(color[i]); - } + color = color.replace('0x', '#'); } } return color; } + +/** + * Utility function to convert hexadecimal colors to strings, and simply return the color if it's a string. + * This version can also convert array of colors + * + * @param {number|number[]} color + * @return {string} The color as a string. + */ +function getColor(color) +{ + if (!Array.isArray(color)) + { + return getSingleColor(color); + } + else + { + for (let i = 0; i < color.length; ++i) + { + color[i] = getSingleColor(color[i]); + } + + return color; + } +} diff --git a/src/core/utils/index.js b/src/core/utils/index.js index c82aaa4..2a7497b 100644 --- a/src/core/utils/index.js +++ b/src/core/utils/index.js @@ -103,9 +103,10 @@ * @memberof PIXI.utils * @function getResolutionOfUrl * @param {string} url - the image path + * @param {number} [defaultValue=1] - the defaultValue if no filename prefix is set. * @return {number} resolution / device pixel ratio of an asset */ -export function getResolutionOfUrl(url) +export function getResolutionOfUrl(url, defaultValue) { const resolution = settings.RETINA_PREFIX.exec(url); @@ -114,7 +115,7 @@ return parseFloat(resolution[1]); } - return 1; + return defaultValue !== undefined ? defaultValue : 1; } /** diff --git a/src/extras/TilingSprite.js b/src/extras/TilingSprite.js index b9352e6..a8bcfba 100644 --- a/src/extras/TilingSprite.js +++ b/src/extras/TilingSprite.js @@ -61,6 +61,15 @@ * @member {PIXI.extras.TextureTransform} */ this.uvTransform = texture.transform || new TextureTransform(texture); + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' method. + * + * @member {string} + * @default 'tilingSprite' + */ + this.pluginName = 'tilingSprite'; } /** * Changes frame clamping in corresponding textureTransform, shortcut @@ -158,8 +167,8 @@ this.tileTransform.updateLocalTransform(); this.uvTransform.update(); - renderer.setObjectRenderer(renderer.plugins.tilingSprite); - renderer.plugins.tilingSprite.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/src/filters/blur/BlurFilter.js b/src/filters/blur/BlurFilter.js index 5b3c3a9..8a05893 100644 --- a/src/filters/blur/BlurFilter.js +++ b/src/filters/blur/BlurFilter.js @@ -15,14 +15,15 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { super(); - this.blurXFilter = new BlurXFilter(); - this.blurYFilter = new BlurYFilter(); + this.blurXFilter = new BlurXFilter(strength, quality, resolution, kernelSize); + this.blurYFilter = new BlurYFilter(strength, quality, resolution, kernelSize); this.resolution = 1; this.padding = 0; diff --git a/src/filters/blur/BlurXFilter.js b/src/filters/blur/BlurXFilter.js index 24181b6..338096c 100644 --- a/src/filters/blur/BlurXFilter.js +++ b/src/filters/blur/BlurXFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, true); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, true); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/filters/blur/BlurYFilter.js b/src/filters/blur/BlurYFilter.js index 267728b..94cbf37 100644 --- a/src/filters/blur/BlurYFilter.js +++ b/src/filters/blur/BlurYFilter.js @@ -15,12 +15,14 @@ /** * @param {number} strength - The strength of the blur filter. * @param {number} quality - The quality of the blur filter. - * @param {number} resolution - The reoslution of the blur filter. + * @param {number} resolution - The resolution of the blur filter. + * @param {number} [kernelSize=5] - The kernelSize of the blur filter.Options: 5, 7, 9, 11, 13, 15. */ - constructor(strength, quality, resolution) + constructor(strength, quality, resolution, kernelSize) { - const vertSrc = generateBlurVertSource(5, false); - const fragSrc = generateBlurFragSource(5); + kernelSize = kernelSize || 5; + const vertSrc = generateBlurVertSource(kernelSize, false); + const fragSrc = generateBlurFragSource(kernelSize); super( // vertex shader diff --git a/src/interaction/InteractionEvent.js b/src/interaction/InteractionEvent.js index 0342469..75b2966 100644 --- a/src/interaction/InteractionEvent.js +++ b/src/interaction/InteractionEvent.js @@ -12,14 +12,15 @@ constructor() { /** - * Which this event will continue propagating in the tree + * Whether this event will continue propagating in the tree * * @member {boolean} */ this.stopped = false; /** - * The object to which event is dispatched. + * The object which caused this event to be dispatched. + * For listener callback see {@link PIXI.interaction.InteractionEvent.currentTarget}. * * @member {PIXI.DisplayObject} */ diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js index 94df60e..05f6628 100644 --- a/src/interaction/InteractionManager.js +++ b/src/interaction/InteractionManager.js @@ -105,15 +105,16 @@ this.interactionDOMElement = null; /** - * This property determins if mousemove and touchmove events are fired only when the cursror + * This property determines if mousemove and touchmove events are fired only when the cursror * is over the object. * Setting to true will make things work more in line with how the DOM verison works. * Setting to false can make things easier for things like dragging * It is currently set to false as this is how pixi used to work. This will be set to true in * future versions of pixi. * - * @private - * @member {boolean} + * @member {boolean} moveWhenInside + * @memberof PIXI.interaction.InteractionManager# + * @default false */ this.moveWhenInside = false; @@ -735,8 +736,10 @@ rect = this.interactionDOMElement.getBoundingClientRect(); } - point.x = ((x - rect.left) * (this.interactionDOMElement.width / rect.width)) / this.resolution; - point.y = ((y - rect.top) * (this.interactionDOMElement.height / rect.height)) / this.resolution; + const resolutionMultiplier = navigator.isCocoonJS ? this.resolution : (1.0 / this.resolution); + + point.x = ((x - rect.left) * (this.interactionDOMElement.width / rect.width)) * resolutionMultiplier; + point.y = ((y - rect.top) * (this.interactionDOMElement.height / rect.height)) * resolutionMultiplier; } /** diff --git a/src/loaders/loader.js b/src/loaders/loader.js index c086919..978aa2d 100644 --- a/src/loaders/loader.js +++ b/src/loaders/loader.js @@ -12,7 +12,9 @@ * //or * let loader = new PIXI.loaders.Loader(); // you can also create your own if you want * - * loader.add('bunny',"data/bunny.png"); + * loader.add('bunny', 'data/bunny.png'); + * loader.add('spaceship', 'assets/spritesheet.json'); + * loader.add('scoreFont', 'assets/score.fnt'); * * loader.once('complete',onAssetsLoaded); * diff --git a/src/loaders/spritesheetParser.js b/src/loaders/spritesheetParser.js index 2d637b1..2b30b1c 100644 --- a/src/loaders/spritesheetParser.js +++ b/src/loaders/spritesheetParser.js @@ -43,14 +43,22 @@ const frames = resource.data.frames; const frameKeys = Object.keys(frames); const baseTexture = res.texture.baseTexture; - let resolution = core.utils.getResolutionOfUrl(resource.url); const scale = resource.data.meta.scale; - // for now (to keep things compatible) resolution overrides scale - // Support scale field on spritesheet - if (resolution === 1 && scale !== undefined && scale !== 1) + // Use a defaultValue of `null` to check if a url-based resolution is set + let resolution = core.utils.getResolutionOfUrl(resource.url, null); + + // No resolution found via URL + if (resolution === null) { - baseTexture.resolution = resolution = scale; + // Use the scale value or default to 1 + resolution = scale !== undefined ? scale : 1; + } + + // For non-1 resolutions, update baseTexture + if (resolution !== 1) + { + baseTexture.resolution = resolution; baseTexture.update(); } diff --git a/src/mesh/Mesh.js b/src/mesh/Mesh.js index 21e5a61..bbb0938 100644 --- a/src/mesh/Mesh.js +++ b/src/mesh/Mesh.js @@ -122,6 +122,15 @@ * @member {object} */ this._glDatas = {}; + + /** + * Plugin that is responsible for rendering this element. + * Allows to customize the rendering process without overriding '_renderWebGL' & '_renderCanvas' methods. + * + * @member {string} + * @default 'mesh' + */ + this.pluginName = 'mesh'; } /** @@ -132,8 +141,8 @@ */ _renderWebGL(renderer) { - renderer.setObjectRenderer(renderer.plugins.mesh); - renderer.plugins.mesh.render(this); + renderer.setObjectRenderer(renderer.plugins[this.pluginName]); + renderer.plugins[this.pluginName].render(this); } /** @@ -144,7 +153,7 @@ */ _renderCanvas(renderer) { - renderer.plugins.mesh.render(this); + renderer.plugins[this.pluginName].render(this); } /** diff --git a/test/core/Ellipse.js b/test/core/Ellipse.js new file mode 100644 index 0000000..f2e8234 --- /dev/null +++ b/test/core/Ellipse.js @@ -0,0 +1,71 @@ +'use strict'; + +describe('PIXI.Ellipse', function () +{ + it('should create a new ellipse', function () + { + const ellipse1 = new PIXI.Ellipse(); + + expect(ellipse1.x).to.equal(0); + expect(ellipse1.y).to.equal(0); + expect(ellipse1.width).to.equal(0); + expect(ellipse1.height).to.equal(0); + + const ellipse2 = new PIXI.Ellipse(10, 10, 5, 5); + + expect(ellipse2.x).to.equal(10); + expect(ellipse2.y).to.equal(10); + expect(ellipse2.width).to.equal(5); + expect(ellipse2.height).to.equal(5); + }); + + it('should clone a new ellipse', function () + { + const ellipse1 = new PIXI.Ellipse(10, 10, 5, 5); + + expect(ellipse1.x).to.equal(10); + expect(ellipse1.y).to.equal(10); + expect(ellipse1.width).to.equal(5); + expect(ellipse1.height).to.equal(5); + + const ellipse2 = ellipse1.clone(); + + expect(ellipse2.x).to.equal(10); + expect(ellipse2.y).to.equal(10); + expect(ellipse2.width).to.equal(5); + expect(ellipse2.height).to.equal(5); + }); + + it('should check if point is within ellipse', function () + { + const ellipse1 = new PIXI.Ellipse(10, 10, 5, 5); + + expect(ellipse1.contains(10, 10)).to.be.true; + expect(ellipse1.contains(10, 15)).to.be.true; + expect(ellipse1.contains(15, 10)).to.be.true; + expect(ellipse1.contains(5, 10)).to.be.true; + expect(ellipse1.contains(15, 10)).to.be.true; + + expect(ellipse1.contains(6, 7)).to.be.true; + expect(ellipse1.contains(7, 6)).to.be.true; + expect(ellipse1.contains(7, 7)).to.be.true; + expect(ellipse1.contains(13, 14)).to.be.true; + expect(ellipse1.contains(14, 13)).to.be.true; + + expect(ellipse1.contains(14, 14)).to.be.false; + expect(ellipse1.contains(10, 16)).to.be.false; + expect(ellipse1.contains(11, 15)).to.be.false; + expect(ellipse1.contains(0, 0)).to.be.false; + }); + + it('should return framing rectangle', function () + { + const ellipse1 = new PIXI.Ellipse(10, 10, 5, 5); + const rect1 = ellipse1.getBounds(); + + expect(rect1.left).to.equal(5); + expect(rect1.top).to.equal(5); + expect(rect1.right).to.equal(10); + expect(rect1.bottom).to.equal(10); + }); +}); diff --git a/test/core/Graphics.js b/test/core/Graphics.js index c7c7a45..0622cfc 100644 --- a/test/core/Graphics.js +++ b/test/core/Graphics.js @@ -128,4 +128,67 @@ expect(graphics.containsPoint(point)).to.be.false; }); }); + + describe('arc', () => + { + it('should draw an arc', () => + { + const graphics = new PIXI.Graphics(); + + expect(graphics.currentPath).to.be.null; + + expect(() => graphics.arc(100, 30, 20, 0, Math.PI)).to.not.throw(); + + expect(graphics.currentPath).to.be.not.null; + }); + + it('should not throw with other shapes', () => + { + // complex drawing #1: draw triangle, rounder rect and an arc (issue #3433) + const graphics = new PIXI.Graphics(); + + // set a fill and line style + graphics.beginFill(0xFF3300); + graphics.lineStyle(4, 0xffd900, 1); + + // draw a shape + graphics.moveTo(50, 50); + graphics.lineTo(250, 50); + graphics.lineTo(100, 100); + graphics.lineTo(50, 50); + graphics.endFill(); + + graphics.lineStyle(2, 0xFF00FF, 1); + graphics.beginFill(0xFF00BB, 0.25); + graphics.drawRoundedRect(150, 450, 300, 100, 15); + graphics.endFill(); + + graphics.beginFill(); + graphics.lineStyle(4, 0x00ff00, 1); + + expect(() => graphics.arc(300, 100, 20, 0, Math.PI)).to.not.throw(); + }); + + it('should do nothing when startAngle and endAngle are equal', () => + { + const graphics = new PIXI.Graphics(); + + expect(graphics.currentPath).to.be.null; + + graphics.arc(0, 0, 10, 0, 0); + + expect(graphics.currentPath).to.be.null; + }); + + it('should do nothing if sweep equals zero', () => + { + const graphics = new PIXI.Graphics(); + + expect(graphics.currentPath).to.be.null; + + graphics.arc(0, 0, 10, 10, 10); + + expect(graphics.currentPath).to.be.null; + }); + }); }); diff --git a/test/core/TextStyle.js b/test/core/TextStyle.js new file mode 100644 index 0000000..b5761ad --- /dev/null +++ b/test/core/TextStyle.js @@ -0,0 +1,26 @@ +'use strict'; + +describe('PIXI.TextStyle', function () +{ + it('reset reverts style to default', function () + { + const textStyle = new PIXI.TextStyle(); + const defaultFontSize = textStyle.fontSize; + + textStyle.fontSize = 1000; + + expect(textStyle.fontSize).to.equal(1000); + textStyle.reset(); + expect(textStyle.fontSize).to.equal(defaultFontSize); + }); + + it('should clone correctly', function () + { + const textStyle = new PIXI.TextStyle({ fontSize: 1000 }); + + const clonedTextStyle = textStyle.clone(); + + expect(textStyle.fontSize).to.equal(1000); + expect(clonedTextStyle.fontSize).to.equal(textStyle.fontSize); + }); +}); diff --git a/test/core/TransformStatic.js b/test/core/TransformStatic.js new file mode 100644 index 0000000..bb9607a --- /dev/null +++ b/test/core/TransformStatic.js @@ -0,0 +1,102 @@ +'use strict'; + +describe('PIXI.TransformStatic', () => +{ + describe('setFromMatrix', () => + { + it('should decompose negative scale into rotation', () => + { + const eps = 1e-3; + + const transform = new PIXI.TransformStatic(); + const parent = new PIXI.TransformStatic(); + const otherTransform = new PIXI.TransformStatic(); + + transform.position.set(20, 10); + transform.scale.set(-2, -3); + transform.rotation = Math.PI / 6; + transform.updateTransform(parent); + + otherTransform.setFromMatrix(transform.worldTransform); + + const position = otherTransform.position; + const scale = otherTransform.scale; + const skew = otherTransform.skew; + + expect(position.x).to.be.closeTo(20, eps); + expect(position.y).to.be.closeTo(10, eps); + expect(scale.x).to.be.closeTo(2, eps); + expect(scale.y).to.be.closeTo(3, eps); + expect(skew.x).to.equal(0); + expect(skew.y).to.equal(0); + expect(otherTransform.rotation).to.be.closeTo(-5 * Math.PI / 6, eps); + }); + + it('should decompose mirror into skew', () => + { + const eps = 1e-3; + + const transform = new PIXI.TransformStatic(); + const parent = new PIXI.TransformStatic(); + const otherTransform = new PIXI.TransformStatic(); + + transform.position.set(20, 10); + transform.scale.set(2, -3); + transform.rotation = Math.PI / 6; + transform.updateTransform(parent); + + otherTransform.setFromMatrix(transform.worldTransform); + + const position = otherTransform.position; + const scale = otherTransform.scale; + const skew = otherTransform.skew; + + expect(position.x).to.be.closeTo(20, eps); + expect(position.y).to.be.closeTo(10, eps); + expect(scale.x).to.be.closeTo(2, eps); + expect(scale.y).to.be.closeTo(3, eps); + expect(skew.x).to.be.closeTo(5 * Math.PI / 6, eps); + expect(skew.y).to.be.closeTo(Math.PI / 6, eps); + expect(otherTransform.rotation).to.equal(0); + }); + + it('should apply skew before scale, like in adobe animate and spine', () => + { + // this example looks the same in CSS and in pixi, made with pixi-animate by @bigtimebuddy + + const eps = 1e-3; + + const transform = new PIXI.TransformStatic(); + const parent = new PIXI.TransformStatic(); + const otherTransform = new PIXI.TransformStatic(); + + transform.position.set(387.8, 313.95); + transform.scale.set(0.572, 4.101); + transform.skew.set(-0.873, 0.175); + transform.updateTransform(parent); + + const mat = transform.worldTransform; + + expect(mat.a).to.be.closeTo(0.563, eps); + expect(mat.b).to.be.closeTo(0.100, eps); + expect(mat.c).to.be.closeTo(-3.142, eps); + expect(mat.d).to.be.closeTo(2.635, eps); + expect(mat.tx).to.be.closeTo(387.8, eps); + expect(mat.ty).to.be.closeTo(313.95, eps); + + otherTransform.setFromMatrix(transform.worldTransform); + + const position = otherTransform.position; + const scale = otherTransform.scale; + const skew = otherTransform.skew; + + expect(position.x).to.be.closeTo(387.8, eps); + expect(position.y).to.be.closeTo(313.95, eps); + expect(scale.x).to.be.closeTo(0.572, eps); + expect(scale.y).to.be.closeTo(4.101, eps); + expect(skew.x).to.be.closeTo(-0.873, eps); + expect(skew.y).to.be.closeTo(0.175, eps); + expect(otherTransform.rotation).to.be.equal(0); + }); + }); +}); diff --git a/test/core/getLocalBounds.js b/test/core/getLocalBounds.js index 5835b9f..d160a56 100644 --- a/test/core/getLocalBounds.js +++ b/test/core/getLocalBounds.js @@ -38,9 +38,7 @@ const graphics = new PIXI.Graphics(); - graphics.beginFill(0xFF0000).drawCircle(0, 0, 10);// texture); - - graphics.scale.set(2); + graphics.beginFill(0xFF0000).drawCircle(0, 0, 10); parent.addChild(graphics); @@ -52,11 +50,73 @@ expect(bounds.height).to.equal(20); }); + it('should register correct local-bounds with Graphics after clear', function () + { + const parent = new PIXI.Container(); + + const graphics = new PIXI.Graphics(); + + graphics.beginFill(0xFF0000).drawRect(0, 0, 20, 20); + + parent.addChild(graphics); + + let bounds = graphics.getLocalBounds(); + + expect(bounds.x).to.equal(0); + expect(bounds.y).to.equal(0); + expect(bounds.width).to.equal(20); + expect(bounds.height).to.equal(20); + + graphics.clear(); + graphics.beginFill(0xFF, 1); + graphics.drawRect(0, 0, 10, 10); + graphics.endFill(); + + bounds = graphics.getLocalBounds(); + + expect(bounds.x).to.equal(0); + expect(bounds.y).to.equal(0); + expect(bounds.width).to.equal(10); + expect(bounds.height).to.equal(10); + }); + + it('should register correct local-bounds with Graphics after generateCanvasTexture and clear', function () + { + const parent = new PIXI.Container(); + + const graphics = new PIXI.Graphics(); + + graphics.beginFill(0xFF0000).drawRect(0, 0, 20, 20); + + parent.addChild(graphics); + + let bounds = graphics.getLocalBounds(); + + graphics.generateCanvasTexture(); + + expect(bounds.x).to.equal(0); + expect(bounds.y).to.equal(0); + expect(bounds.width).to.equal(20); + expect(bounds.height).to.equal(20); + + graphics.clear(); + graphics.beginFill(0xFF, 1); + graphics.drawRect(0, 0, 10, 10); + graphics.endFill(); + + bounds = graphics.getLocalBounds(); + + expect(bounds.x).to.equal(0); + expect(bounds.y).to.equal(0); + expect(bounds.width).to.equal(10); + expect(bounds.height).to.equal(10); + }); + it('should register correct local-bounds with an empty Container', function () { const parent = new PIXI.Container(); - const container = new PIXI.Container();// Graphics().beginFill(0xFF0000).drawCircle(0, 0, 10, 10);//texture); + const container = new PIXI.Container(); parent.addChild(container); @@ -72,9 +132,9 @@ { const parent = new PIXI.Container(); - const container = new PIXI.Container();// Graphics().beginFill(0xFF0000).drawCircle(0, 0, 10, 10);//texture); + const container = new PIXI.Container(); - const graphics = new PIXI.Graphics().beginFill(0xFF0000).drawRect(0, 0, 10, 10);// texture); + const graphics = new PIXI.Graphics().beginFill(0xFF0000).drawRect(0, 0, 10, 10); parent.addChild(container); container.addChild(graphics); diff --git a/test/core/index.js b/test/core/index.js index a060dde..405a557 100755 --- a/test/core/index.js +++ b/test/core/index.js @@ -1,11 +1,13 @@ 'use strict'; +require('./TransformStatic'); require('./Bounds'); require('./Container'); require('./DisplayObject'); require('./getLocalBounds'); require('./Sprite'); require('./TilingSprite'); +require('./TextStyle'); require('./Text'); require('./toGlobal'); require('./toLocal'); @@ -20,3 +22,4 @@ require('./Circle'); require('./Graphics'); require('./SpriteRenderer'); +require('./Ellipse');